import { z } from "zod"; import type { JSONSchema7 } from "json-schema"; import type { ToolExecutor, ToolResult } from "../../registry"; import type { AgentInvokeToolConfig } from "./config"; import { invokeAgent } from "../../../agent/collaboration"; import { listAgents } from "../../../agent/agent"; export const agentInvokeInputSchema = z.object({ agentSlug: z.string().min(1).max(100).describe("目标 agent 的 slug"), input: z.string().min(1).max(50000).describe("传递给目标 agent 的任务描述/输入内容"), }); type AgentInvokeInput = z.infer; export const agentInvokeExecutor: ToolExecutor = { buildInputSchema(_config: AgentInvokeToolConfig): JSONSchema7 { return { type: "object", properties: { agentSlug: { type: "string", description: "目标 agent 的 slug(唯一标识符)", }, input: { type: "string", description: "传递给目标 agent 的任务描述或输入内容", }, }, required: ["agentSlug", "input"], }; }, buildDescription(_config: AgentInvokeToolConfig): string { return "调用另一个 agent 来处理子任务。目标 agent 必须已启用且标记为可调用(isCallable)。传入 agent slug 和任务描述,返回目标 agent 的回复内容。支持多级调用链,但有递归深度限制。"; }, async buildDescriptionAsync(_config: AgentInvokeToolConfig, ctx?: { agentId?: number | null }): Promise { const base = this.buildDescription(_config); const callableAgents = await listAgents(true); const currentAgentId = ctx?.agentId ?? null; const available = callableAgents.filter((a) => a.isCallable === 1 && a.id !== currentAgentId); if (available.length === 0) { return `${base}\n\n当前没有可调用的 Agent。请勿调用此工具。`; } const agentList = available.map((a) => `- slug: "${a.slug}" — ${a.name}: ${a.description ?? "无描述"}`).join("\n"); return `${base}\n\n可调用的 Agent 列表(通过 agentSlug 参数指定):\n${agentList}`; }, formatResult(result: ToolResult, _config: AgentInvokeToolConfig): string { if (!result.success) { return `Agent 调用失败: ${result.error ?? "未知错误"}`; } const meta = result.metadata; const agentSlug = meta?.agentSlug ?? "unknown"; const depth = meta?.recursionDepth ?? 0; const duration = meta?.durationMs ?? 0; const data = typeof result.data === "string" ? result.data : JSON.stringify(result.data); return `[Agent "${agentSlug}" 调用完成 | 深度: ${depth} | 耗时: ${duration}ms]\n${data}`; }, async execute( input: unknown, config: AgentInvokeToolConfig, ctx: { userId: number | null; agentId?: number | null; recursionDepth?: number }, ): Promise { const start = Date.now(); const parsed = agentInvokeInputSchema.safeParse(input); if (!parsed.success) { return { success: false, data: null, error: `参数校验失败: ${parsed.error.message}`, metadata: { durationMs: Date.now() - start }, }; } const data: AgentInvokeInput = parsed.data; const currentDepth = ctx.recursionDepth ?? 0; const result = await invokeAgent( { agentSlug: data.agentSlug, input: data.input, context: { userId: ctx.userId, callerAgentId: ctx.agentId ?? null, recursionDepth: currentDepth + 1, }, }, { maxRecursionDepth: config.maxRecursionDepth, timeoutMs: config.timeoutMs, maxOutputTokens: config.maxOutputTokens, }, ); if (!result.ok) { return { success: false, data: null, error: result.error ?? `调用 agent ${data.agentSlug} 失败`, metadata: { durationMs: Date.now() - start }, }; } let output = result.output; if (output.length > config.resultTruncateLength) { output = output.slice(0, config.resultTruncateLength) + `\n...[结果已截断,原始长度 ${output.length} 字符]`; } return { success: true, data: output, metadata: { durationMs: Date.now() - start, agentSlug: data.agentSlug, recursionDepth: currentDepth + 1, }, }; }, };