You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
3.2 KiB
103 lines
3.2 KiB
/**
|
|
* A2A 内部客户端
|
|
*
|
|
* 替代 collaboration.ts 的 invokeAgent(),提供与原接口兼容的
|
|
* agent 间调用能力,底层走 A2A Service 层。
|
|
*
|
|
* 设计原则:
|
|
* - 接口签名与 invokeAgent 完全兼容,便于无缝替换
|
|
* - 递归深度、超时、自调用阻断通过 A2AInvocationContext 传递
|
|
* - 未来可切换为真实 HTTP 调用本机 A2A 端点(接口不变)
|
|
*/
|
|
|
|
import type { AgentInvocation, AgentInvocationResult } from "../agent/types";
|
|
import { getAgentBySlug } from "../agent/agent";
|
|
import { createTask, sendTask } from "./service";
|
|
import { textToA2AMessage, a2aMessageToText } from "./converter";
|
|
import { DEFAULT_A2A_CONFIG, JSONRPC_ERROR_CODES } from "./types";
|
|
import type { A2AInvocationContext } from "./types";
|
|
import log4js from "logger";
|
|
|
|
const logger = log4js.getLogger("APP");
|
|
|
|
export async function invokeAgentViaA2A(
|
|
invocation: AgentInvocation,
|
|
options?: {
|
|
maxRecursionDepth?: number;
|
|
timeoutMs?: number;
|
|
maxOutputTokens?: number;
|
|
},
|
|
): Promise<AgentInvocationResult> {
|
|
const { agentSlug, input, context } = invocation;
|
|
const maxRecursionDepth = options?.maxRecursionDepth ?? DEFAULT_A2A_CONFIG.maxRecursionDepth;
|
|
const timeoutMs = options?.timeoutMs ?? DEFAULT_A2A_CONFIG.timeoutMs;
|
|
const maxOutputTokens = options?.maxOutputTokens ?? DEFAULT_A2A_CONFIG.maxOutputTokens;
|
|
|
|
const userId = context?.userId ?? null;
|
|
const callerAgentId = context?.callerAgentId ?? null;
|
|
const recursionDepth = context?.recursionDepth ?? 0;
|
|
|
|
const agent = await getAgentBySlug(agentSlug);
|
|
if (!agent) {
|
|
return { agentSlug, output: "", ok: false, error: `agent not found: ${agentSlug}` };
|
|
}
|
|
|
|
if (!agent.isCallable) {
|
|
return { agentSlug, output: "", ok: false, error: `agent not callable: ${agentSlug}` };
|
|
}
|
|
|
|
if (callerAgentId !== null && callerAgentId === agent.id) {
|
|
return { agentSlug, output: "", ok: false, error: `self-invocation blocked: agent ${agentSlug} cannot invoke itself` };
|
|
}
|
|
|
|
if (recursionDepth >= maxRecursionDepth) {
|
|
return {
|
|
agentSlug,
|
|
output: "",
|
|
ok: false,
|
|
error: `max recursion depth (${maxRecursionDepth}) reached`,
|
|
};
|
|
}
|
|
|
|
const message = textToA2AMessage(input, "user");
|
|
|
|
try {
|
|
const { task } = await createTask({
|
|
calleeAgentSlug: agentSlug,
|
|
message,
|
|
callerAgentId,
|
|
userId,
|
|
});
|
|
|
|
const a2aContext: A2AInvocationContext = {
|
|
callerAgentId,
|
|
calleeAgentId: agent.id,
|
|
calleeAgentSlug: agentSlug,
|
|
userId,
|
|
sessionId: task.sessionId,
|
|
recursionDepth,
|
|
maxRecursionDepth,
|
|
timeoutMs,
|
|
maxOutputTokens,
|
|
};
|
|
|
|
const completedTask = await sendTask(task.id, a2aContext);
|
|
|
|
const output = completedTask.message
|
|
? a2aMessageToText(completedTask.message)
|
|
: "";
|
|
|
|
logger.info(
|
|
"[A2A-CLIENT] invokeAgentViaA2A done agentSlug=%s taskId=%s outputLen=%d",
|
|
agentSlug,
|
|
task.id,
|
|
output.length,
|
|
);
|
|
|
|
return { agentSlug, output, ok: true };
|
|
} catch (err) {
|
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
logger.error("[A2A-CLIENT] invokeAgentViaA2A error agentSlug=%s error=%s", agentSlug, errorMsg);
|
|
return { agentSlug, output: "", ok: false, error: errorMsg };
|
|
}
|
|
}
|
|
|