| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- import OpenAPIClientAxios from "openapi-client-axios";
- import { StoreKey } from "../constant";
- import { nanoid } from "nanoid";
- import { createPersistStore } from "../utils/store";
- import { getClientConfig } from "../config/client";
- import yaml from "js-yaml";
- import { adapter, getOperationId } from "../utils";
- import { useAccessStore } from "./access";
- const isApp = getClientConfig()?.isApp !== false;
- export type Plugin = {
- id: string;
- createdAt: number;
- title: string;
- version: string;
- content: string;
- builtin: boolean;
- authType?: string;
- authLocation?: string;
- authHeader?: string;
- authToken?: string;
- };
- export type FunctionToolItem = {
- type: string;
- function: {
- name: string;
- description?: string;
- parameters: Object;
- };
- };
- type FunctionToolServiceItem = {
- api: OpenAPIClientAxios;
- length: number;
- tools: FunctionToolItem[];
- funcs: Record<string, Function>;
- };
- export const FunctionToolService = {
- tools: {} as Record<string, FunctionToolServiceItem>,
- add(plugin: Plugin, replace = false) {
- if (!replace && this.tools[plugin.id]) return this.tools[plugin.id];
- const headerName = (
- plugin?.authType == "custom" ? plugin?.authHeader : "Authorization"
- ) as string;
- const tokenValue =
- plugin?.authType == "basic"
- ? `Basic ${plugin?.authToken}`
- : plugin?.authType == "bearer"
- ? `Bearer ${plugin?.authToken}`
- : plugin?.authToken;
- const authLocation = plugin?.authLocation || "header";
- const definition = yaml.load(plugin.content) as any;
- const serverURL = definition?.servers?.[0]?.url;
- const baseURL = !isApp ? "/api/proxy" : serverURL;
- const headers: Record<string, string | undefined> = {
- "X-Base-URL": !isApp ? serverURL : undefined,
- };
- if (authLocation == "header") {
- headers[headerName] = tokenValue;
- }
- // try using openaiApiKey for Dalle3 Plugin.
- if (!tokenValue && plugin.id === "dalle3") {
- const openaiApiKey = useAccessStore.getState().openaiApiKey;
- if (openaiApiKey) {
- headers[headerName] = `Bearer ${openaiApiKey}`;
- }
- }
- const api = new OpenAPIClientAxios({
- definition: yaml.load(plugin.content) as any,
- axiosConfigDefaults: {
- adapter: (window.__TAURI__ ? adapter : ["xhr"]) as any,
- baseURL,
- headers,
- },
- });
- try {
- api.initSync();
- } catch (e) {}
- const operations = api.getOperations();
- return (this.tools[plugin.id] = {
- api,
- length: operations.length,
- tools: operations.map((o) => {
- // @ts-ignore
- const parameters = o?.requestBody?.content["application/json"]
- ?.schema || {
- type: "object",
- properties: {},
- };
- if (!parameters["required"]) {
- parameters["required"] = [];
- }
- if (o.parameters instanceof Array) {
- o.parameters.forEach((p) => {
- // @ts-ignore
- if (p?.in == "query" || p?.in == "path") {
- // const name = `${p.in}__${p.name}`
- // @ts-ignore
- const name = p?.name;
- parameters["properties"][name] = {
- // @ts-ignore
- type: p.schema.type,
- // @ts-ignore
- description: p.description,
- };
- // @ts-ignore
- if (p.required) {
- parameters["required"].push(name);
- }
- }
- });
- }
- return {
- type: "function",
- function: {
- name: getOperationId(o),
- description: o.description || o.summary,
- parameters: parameters,
- },
- } as FunctionToolItem;
- }),
- funcs: operations.reduce((s, o) => {
- // @ts-ignore
- s[getOperationId(o)] = function (args) {
- const parameters: Record<string, any> = {};
- if (o.parameters instanceof Array) {
- o.parameters.forEach((p) => {
- // @ts-ignore
- parameters[p?.name] = args[p?.name];
- // @ts-ignore
- delete args[p?.name];
- });
- }
- if (authLocation == "query") {
- parameters[headerName] = tokenValue;
- } else if (authLocation == "body") {
- args[headerName] = tokenValue;
- }
- // @ts-ignore if o.operationId is null, then using o.path and o.method
- return api.client.paths[o.path][o.method](
- parameters,
- args,
- api.axiosConfigDefaults,
- );
- };
- return s;
- }, {}),
- });
- },
- get(id: string) {
- return this.tools[id];
- },
- };
- export const createEmptyPlugin = () =>
- ({
- id: nanoid(),
- title: "",
- version: "1.0.0",
- content: "",
- builtin: false,
- createdAt: Date.now(),
- }) as Plugin;
- export const DEFAULT_PLUGIN_STATE = {
- plugins: {} as Record<string, Plugin>,
- };
- export const usePluginStore = createPersistStore(
- { ...DEFAULT_PLUGIN_STATE },
- (set, get) => ({
- create(plugin?: Partial<Plugin>) {
- const plugins = get().plugins;
- const id = plugin?.id || nanoid();
- plugins[id] = {
- ...createEmptyPlugin(),
- ...plugin,
- id,
- builtin: false,
- };
- set(() => ({ plugins }));
- get().markUpdate();
- return plugins[id];
- },
- updatePlugin(id: string, updater: (plugin: Plugin) => void) {
- const plugins = get().plugins;
- const plugin = plugins[id];
- if (!plugin) return;
- const updatePlugin = { ...plugin };
- updater(updatePlugin);
- plugins[id] = updatePlugin;
- FunctionToolService.add(updatePlugin, true);
- set(() => ({ plugins }));
- get().markUpdate();
- },
- delete(id: string) {
- const plugins = get().plugins;
- delete plugins[id];
- set(() => ({ plugins }));
- get().markUpdate();
- },
- getAsTools(ids: string[]) {
- const plugins = get().plugins;
- const selected = (ids || [])
- .map((id) => plugins[id])
- .filter((i) => i)
- .map((p) => FunctionToolService.add(p));
- return [
- // @ts-ignore
- selected.reduce((s, i) => s.concat(i.tools), []),
- selected.reduce((s, i) => Object.assign(s, i.funcs), {}),
- ];
- },
- get(id?: string) {
- return get().plugins[id ?? 1145141919810];
- },
- getAll() {
- return Object.values(get().plugins).sort(
- (a, b) => b.createdAt - a.createdAt,
- );
- },
- }),
- {
- name: StoreKey.Plugin,
- version: 1,
- onRehydrateStorage(state) {
- // Skip store rehydration on server side
- if (typeof window === "undefined") {
- return;
- }
- fetch("./plugins.json")
- .then((res) => res.json())
- .then((res) => {
- Promise.all(
- res.map((item: any) =>
- // skip get schema
- state.get(item.id)
- ? item
- : fetch(item.schema)
- .then((res) => res.text())
- .then((content) => ({
- ...item,
- content,
- }))
- .catch((e) => item),
- ),
- ).then((builtinPlugins: any) => {
- builtinPlugins
- .filter((item: any) => item?.content)
- .forEach((item: any) => {
- const plugin = state.create(item);
- state.updatePlugin(plugin.id, (plugin) => {
- const tool = FunctionToolService.add(plugin, true);
- plugin.title = tool.api.definition.info.title;
- plugin.version = tool.api.definition.info.version;
- plugin.builtin = true;
- });
- });
- });
- });
- },
- },
- );
|