Spaces:
Runtime error
Runtime error
require('dotenv').config(); | |
const { z } = require('zod'); | |
const fs = require('fs'); | |
const yaml = require('js-yaml'); | |
const path = require('path'); | |
const { DynamicStructuredTool } = require('langchain/tools'); | |
const { createOpenAPIChain } = require('langchain/chains'); | |
const SUFFIX = 'Prioritize using responses for subsequent requests to better fulfill the query.'; | |
const AuthBearer = z | |
.object({ | |
type: z.string().includes('service_http'), | |
authorization_type: z.string().includes('bearer'), | |
verification_tokens: z.object({ | |
openai: z.string(), | |
}), | |
}) | |
.catch(() => false); | |
const AuthDefinition = z | |
.object({ | |
type: z.string(), | |
authorization_type: z.string(), | |
verification_tokens: z.object({ | |
openai: z.string(), | |
}), | |
}) | |
.catch(() => false); | |
async function readSpecFile(filePath) { | |
try { | |
const fileContents = await fs.promises.readFile(filePath, 'utf8'); | |
if (path.extname(filePath) === '.json') { | |
return JSON.parse(fileContents); | |
} | |
return yaml.load(fileContents); | |
} catch (e) { | |
console.error(e); | |
return false; | |
} | |
} | |
async function getSpec(url) { | |
const RegularUrl = z | |
.string() | |
.url() | |
.catch(() => false); | |
if (RegularUrl.parse(url) && path.extname(url) === '.json') { | |
const response = await fetch(url); | |
return await response.json(); | |
} | |
const ValidSpecPath = z | |
.string() | |
.url() | |
.catch(async () => { | |
const spec = path.join(__dirname, '..', '.well-known', 'openapi', url); | |
if (!fs.existsSync(spec)) { | |
return false; | |
} | |
return await readSpecFile(spec); | |
}); | |
return ValidSpecPath.parse(url); | |
} | |
async function createOpenAPIPlugin({ data, llm, user, message, verbose = false }) { | |
let spec; | |
try { | |
spec = await getSpec(data.api.url, verbose); | |
} catch (error) { | |
verbose && console.debug('getSpec error', error); | |
return null; | |
} | |
if (!spec) { | |
verbose && console.debug('No spec found'); | |
return null; | |
} | |
const headers = {}; | |
const { auth, description_for_model } = data; | |
if (auth && AuthDefinition.parse(auth)) { | |
verbose && console.debug('auth detected', auth); | |
const { openai } = auth.verification_tokens; | |
if (AuthBearer.parse(auth)) { | |
headers.authorization = `Bearer ${openai}`; | |
verbose && console.debug('added auth bearer', headers); | |
} | |
} | |
return new DynamicStructuredTool({ | |
name: data.name_for_model, | |
description: `${data.description_for_human} ${SUFFIX}`, | |
schema: z.object({ | |
query: z | |
.string() | |
.describe( | |
'For the query, be specific in a conversational manner. It will be interpreted by a human.', | |
), | |
}), | |
func: async () => { | |
const chainOptions = { | |
llm, | |
verbose, | |
}; | |
if (data.headers && data.headers['librechat_user_id']) { | |
verbose && console.debug('id detected', headers); | |
headers[data.headers['librechat_user_id']] = user; | |
} | |
if (Object.keys(headers).length > 0) { | |
verbose && console.debug('headers detected', headers); | |
chainOptions.headers = headers; | |
} | |
if (data.params) { | |
verbose && console.debug('params detected', data.params); | |
chainOptions.params = data.params; | |
} | |
const chain = await createOpenAPIChain(spec, chainOptions); | |
const result = await chain.run( | |
`${message}\n\n||>Instructions: ${description_for_model}\n${SUFFIX}`, | |
); | |
console.log('api chain run result', result); | |
return result; | |
}, | |
}); | |
} | |
module.exports = { | |
getSpec, | |
readSpecFile, | |
createOpenAPIPlugin, | |
}; | |