import { type QueryRouterServer, type App, type RouteInfo } from '@kevisual/router' import { generateText, tool, type ModelMessage, type LanguageModel, type GenerateTextResult } from 'ai'; import z from 'zod'; import { filter } from '@kevisual/js-filter' export const createTool = async (app: QueryRouterServer | App, message: { path: string, key: string, token?: string }) => { const route = app.findRoute({ path: message.path, key: message.key }); if (!route) { console.error(`未找到路径 ${message.path} 和 key ${message.key} 的路由`); return null; } const _tool = tool({ description: route?.metadata?.summary || route?.description || '无描述', inputSchema: z.object({ ...route.metadata?.args }), // 这里可以根据实际需要定义输入参数的 schema execute: async (args: any) => { const res = await app.run({ path: message.path, key: message.key, payload: args, token: message.token }); return res; } }); return _tool; } export const createTools = async (opts: { app: QueryRouterServer | App, token?: string }) => { const { app, token } = opts; const tools: Record = {}; for (const route of app.routes) { const id = route.id!; const _tool = await createTool(app, { path: route.path!, key: route.key!, token }); if (_tool && id) { tools[id] = _tool; } } return tools; } type Route = Partial type AgentResult = { result: GenerateTextResult, any>, messages: ModelMessage[], } export const reCallAgent = async (opts: { messages?: ModelMessage[], tools?: Record, languageModel: LanguageModel }): Promise => { const { messages = [], tools = {}, languageModel } = opts; const result = await generateText({ model: languageModel, messages, tools, }); const step = result.steps[0]!; if (step.finishReason === 'tool-calls') { messages.push(...result.response.messages); return reCallAgent({ messages, tools, languageModel }); } return { result, messages }; } export const runAgent = async (opts: { app: QueryRouterServer | App, messages?: ModelMessage[], routes?: Route[], query?: string, languageModel: LanguageModel, token: string }) => { const { app, languageModel } = opts; let messages = opts.messages || []; let routes = opts?.routes || app.routes; if (opts.query) { routes = filter(routes, opts.query); }; const tools = await createTools({ app, token: opts.token }); return await reCallAgent({ messages, tools, languageModel }); }