diff --git a/internal/einomcp/tool_invoke_notify.go b/internal/einomcp/tool_invoke_notify.go index b43ca44a..a776a7bc 100644 --- a/internal/einomcp/tool_invoke_notify.go +++ b/internal/einomcp/tool_invoke_notify.go @@ -2,8 +2,8 @@ package einomcp import "sync" -// ToolInvokeNotifyHolder 由 Eino run loop 在迭代开始前 Set 回调;MCP/execute 桥在工具调用结束时 Fire, -// 用于清除 pending tool_call(tool_result 由 ADK schema.Tool 事件推送,含流式工具与 reduction 后正文)。 +// ToolInvokeNotifyHolder 由 Eino run loop 与 MCP/execute 桥共享;Fire 在工具原始返回时触发。 +// UI 的 tool_result 须等 ADK schema.Tool 事件(reduction 后正文),不在此 holder 的回调里推送。 type ToolInvokeNotifyHolder struct { mu sync.RWMutex fn func(toolCallID, toolName, einoAgent string, success bool, content string, invokeErr error) diff --git a/internal/multiagent/eino_adk_run_loop.go b/internal/multiagent/eino_adk_run_loop.go index 4c7bbc08..d55e7cf0 100644 --- a/internal/multiagent/eino_adk_run_loop.go +++ b/internal/multiagent/eino_adk_run_loop.go @@ -299,6 +299,8 @@ func runEinoADKAgentLoop(ctx context.Context, args *einoADKRunLoopArgs, baseMsgs var toolResultSent sync.Map // toolCallID -> struct{};ADK Tool 事件去重(权威正文来自 reduction 处理后的 agent 上下文) tryEmitToolResultProgress := func(toolName, content, toolCallID string, isErr bool, agentName string) { + // 仅由 ADK schema.Tool 事件调用;MCP/execute 桥在 reduction 前的 ToolInvokeNotify 不得推送 tool_result, + // 否则全量输出会先占位并触发 toolResultSent 去重,导致 UI/监控展示与 agent 实际收到的截断正文不一致。 if progress == nil { return } @@ -316,6 +318,7 @@ func runEinoADKAgentLoop(ctx context.Context, args *einoADKRunLoopArgs, baseMsgs "isError": isErr, "result": content, "resultPreview": preview, + "agentFacing": true, // 与 reduction 后送入 ChatModel 的正文一致,供前端展示 "conversationId": conversationID, "einoAgent": agentName, "einoRole": einoRoleTag(agentName), @@ -350,25 +353,6 @@ func runEinoADKAgentLoop(ctx context.Context, args *einoADKRunLoopArgs, baseMsgs } progress("tool_result", fmt.Sprintf("工具结果 (%s)", toolName), data) } - if args.ToolInvokeNotify != nil { - args.ToolInvokeNotify.Set(func(toolCallID, toolName, einoAgent string, success bool, content string, invokeErr error) { - // Eino execute / MCP 桥在工具返回时 Fire;若 ADK schema.Tool 事件迟迟不到,此处立即推送 - // tool_result 解除 UI「执行中」。tryEmitToolResultProgress 经 toolResultSent 去重,ADK 晚到不重复。 - isErr := !success || invokeErr != nil - body := einoToolResultBody(content) - if einoToolResultIsError(toolName, content) { - isErr = true - } - if tail := friendlyEinoExecuteInvokeTail(invokeErr); tail != "" { - if body == "" { - body = tail - } else if !strings.Contains(body, tail) { - body = strings.TrimSpace(body) + "\n\n" + tail - } - } - tryEmitToolResultProgress(toolName, body, toolCallID, isErr, einoAgent) - }) - } if args.EinoCallbacks != nil { ctx = einoobserve.AttachAgentRunCallbacks(ctx, args.EinoCallbacks, einoobserve.Params{