File size: 2,763 Bytes
3b6afc0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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,
};