plugin.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import OpenAPIClientAxios from "openapi-client-axios";
  2. import { getLang, Lang } from "../locales";
  3. import { StoreKey } from "../constant";
  4. import { nanoid } from "nanoid";
  5. import { createPersistStore } from "../utils/store";
  6. import yaml from "js-yaml";
  7. export type Plugin = {
  8. id: string;
  9. createdAt: number;
  10. title: string;
  11. version: string;
  12. content: string;
  13. builtin: boolean;
  14. };
  15. export type FunctionToolItem = {
  16. type: string;
  17. function: {
  18. name: string;
  19. description?: string;
  20. parameters: Object;
  21. };
  22. };
  23. type FunctionToolServiceItem = {
  24. api: OpenAPIClientAxios;
  25. length: number;
  26. tools: FunctionToolItem[];
  27. funcs: Record<string, Function>;
  28. };
  29. export const FunctionToolService = {
  30. tools: {} as Record<string, FunctionToolServiceItem>,
  31. add(plugin: Plugin, replace = false) {
  32. if (!replace && this.tools[plugin.id]) return this.tools[plugin.id];
  33. const api = new OpenAPIClientAxios({
  34. definition: yaml.load(plugin.content) as any,
  35. });
  36. console.log("add", plugin, api);
  37. try {
  38. api.initSync();
  39. } catch (e) {}
  40. const operations = api.getOperations();
  41. return (this.tools[plugin.id] = {
  42. api,
  43. length: operations.length,
  44. tools: operations.map((o) => {
  45. // @ts-ignore
  46. const parameters = o?.requestBody?.content["application/json"]
  47. ?.schema || {
  48. type: "object",
  49. properties: {},
  50. };
  51. if (!parameters["required"]) {
  52. parameters["required"] = [];
  53. }
  54. if (o.parameters instanceof Array) {
  55. o.parameters.forEach((p) => {
  56. // @ts-ignore
  57. if (p?.in == "query" || p?.in == "path") {
  58. // const name = `${p.in}__${p.name}`
  59. // @ts-ignore
  60. const name = p?.name;
  61. parameters["properties"][name] = {
  62. // @ts-ignore
  63. type: p.schema.type,
  64. // @ts-ignore
  65. description: p.description,
  66. };
  67. // @ts-ignore
  68. if (p.required) {
  69. parameters["required"].push(name);
  70. }
  71. }
  72. });
  73. }
  74. return {
  75. type: "function",
  76. function: {
  77. name: o.operationId,
  78. description: o.description,
  79. parameters: parameters,
  80. },
  81. } as FunctionToolItem;
  82. }),
  83. funcs: operations.reduce((s, o) => {
  84. // @ts-ignore
  85. s[o.operationId] = api.client[o.operationId];
  86. return s;
  87. }, {}),
  88. });
  89. },
  90. get(id: string) {
  91. return this.tools[id];
  92. },
  93. };
  94. export const createEmptyPlugin = () =>
  95. ({
  96. id: nanoid(),
  97. title: "",
  98. version: "1.0.0",
  99. content: "",
  100. builtin: false,
  101. createdAt: Date.now(),
  102. }) as Plugin;
  103. export const DEFAULT_PLUGIN_STATE = {
  104. plugins: {} as Record<string, Plugin>,
  105. };
  106. export const usePluginStore = createPersistStore(
  107. { ...DEFAULT_PLUGIN_STATE },
  108. (set, get) => ({
  109. create(plugin?: Partial<Plugin>) {
  110. const plugins = get().plugins;
  111. const id = nanoid();
  112. plugins[id] = {
  113. ...createEmptyPlugin(),
  114. ...plugin,
  115. id,
  116. builtin: false,
  117. };
  118. set(() => ({ plugins }));
  119. get().markUpdate();
  120. return plugins[id];
  121. },
  122. updatePlugin(id: string, updater: (plugin: Plugin) => void) {
  123. const plugins = get().plugins;
  124. const plugin = plugins[id];
  125. if (!plugin) return;
  126. const updatePlugin = { ...plugin };
  127. updater(updatePlugin);
  128. plugins[id] = updatePlugin;
  129. set(() => ({ plugins }));
  130. get().markUpdate();
  131. },
  132. delete(id: string) {
  133. const plugins = get().plugins;
  134. delete plugins[id];
  135. set(() => ({ plugins }));
  136. get().markUpdate();
  137. },
  138. getAsTools(ids: string[]) {
  139. const plugins = get().plugins;
  140. const selected = ids
  141. .map((id) => plugins[id])
  142. .filter((i) => i)
  143. .map((p) => FunctionToolService.add(p));
  144. return [
  145. // @ts-ignore
  146. selected.reduce((s, i) => s.concat(i.tools), []),
  147. selected.reduce((s, i) => Object.assign(s, i.funcs), {}),
  148. ];
  149. },
  150. get(id?: string) {
  151. return get().plugins[id ?? 1145141919810];
  152. },
  153. getAll() {
  154. return Object.values(get().plugins).sort(
  155. (a, b) => b.createdAt - a.createdAt,
  156. );
  157. },
  158. }),
  159. {
  160. name: StoreKey.Plugin,
  161. version: 1,
  162. },
  163. );