mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-18 09:20:15 +01:00
105 lines
2.7 KiB
JavaScript
105 lines
2.7 KiB
JavaScript
|
|
const fs = require('fs');
|
||
|
|
const path = require('path');
|
||
|
|
const { z } = require('zod');
|
||
|
|
const { createOpenAPIPlugin } = require('../dynamic/OpenAPIPlugin');
|
||
|
|
|
||
|
|
// The minimum Manifest definition
|
||
|
|
const ManifestDefinition = z.object({
|
||
|
|
schema_version: z.string().optional(),
|
||
|
|
name_for_human: z.string(),
|
||
|
|
name_for_model: z.string(),
|
||
|
|
description_for_human: z.string(),
|
||
|
|
description_for_model: z.string(),
|
||
|
|
auth: z.object({}).optional(),
|
||
|
|
api: z.object({
|
||
|
|
// Spec URL or can be the filename of the OpenAPI spec yaml file,
|
||
|
|
// located in api\app\clients\tools\.well-known\openapi
|
||
|
|
url: z.string(),
|
||
|
|
type: z.string().optional(),
|
||
|
|
is_user_authenticated: z.boolean().nullable().optional(),
|
||
|
|
has_user_authentication: z.boolean().nullable().optional(),
|
||
|
|
}),
|
||
|
|
// use to override any params that the LLM will consistently get wrong
|
||
|
|
params: z.object({}).optional(),
|
||
|
|
logo_url: z.string().optional(),
|
||
|
|
contact_email: z.string().optional(),
|
||
|
|
legal_info_url: z.string().optional(),
|
||
|
|
});
|
||
|
|
|
||
|
|
function validateJson(json, verbose = true) {
|
||
|
|
try {
|
||
|
|
return ManifestDefinition.parse(json);
|
||
|
|
} catch (error) {
|
||
|
|
if (verbose) {
|
||
|
|
console.debug('validateJson error', error);
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// omit the LLM to return the well known jsons as objects
|
||
|
|
async function loadSpecs({ llm, user, message, map = false, verbose = false }) {
|
||
|
|
const directoryPath = path.join(__dirname, '..', '.well-known');
|
||
|
|
const files = (await fs.promises.readdir(directoryPath)).filter(
|
||
|
|
(file) => path.extname(file) === '.json',
|
||
|
|
);
|
||
|
|
|
||
|
|
const validJsons = [];
|
||
|
|
const constructorMap = {};
|
||
|
|
|
||
|
|
if (verbose) {
|
||
|
|
console.debug('files', files);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (const file of files) {
|
||
|
|
if (path.extname(file) === '.json') {
|
||
|
|
const filePath = path.join(directoryPath, file);
|
||
|
|
const fileContent = await fs.promises.readFile(filePath, 'utf8');
|
||
|
|
const json = JSON.parse(fileContent);
|
||
|
|
|
||
|
|
if (!validateJson(json)) {
|
||
|
|
verbose && console.debug('Invalid json', json);
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (llm && map) {
|
||
|
|
constructorMap[json.name_for_model] = async () =>
|
||
|
|
await createOpenAPIPlugin({
|
||
|
|
data: json,
|
||
|
|
llm,
|
||
|
|
message,
|
||
|
|
user,
|
||
|
|
verbose,
|
||
|
|
});
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (llm) {
|
||
|
|
validJsons.push(createOpenAPIPlugin({ data: json, llm, verbose }));
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
validJsons.push(json);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (map) {
|
||
|
|
return constructorMap;
|
||
|
|
}
|
||
|
|
|
||
|
|
const plugins = (await Promise.all(validJsons)).filter((plugin) => plugin);
|
||
|
|
|
||
|
|
// if (verbose) {
|
||
|
|
// console.debug('plugins', plugins);
|
||
|
|
// console.debug(plugins[0].name);
|
||
|
|
// }
|
||
|
|
|
||
|
|
return plugins;
|
||
|
|
}
|
||
|
|
|
||
|
|
module.exports = {
|
||
|
|
loadSpecs,
|
||
|
|
validateJson,
|
||
|
|
ManifestDefinition,
|
||
|
|
};
|