mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 08:12:00 +02:00
140 lines
3.5 KiB
JavaScript
140 lines
3.5 KiB
JavaScript
![]() |
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,
|
||
|
};
|