mirror of
https://github.com/coleam00/Archon
synced 2026-04-21 13:37:41 +00:00
fix: eliminate duplicate text and tool calls in workflow execution view
Three fixes for message duplication during live workflow execution: 1. dag-executor: Add missing `tool_call_formatted` category to loop iteration tool messages. Without this, the web adapter sent tool text as both a regular SSE text event AND a structured tool_call event, causing each tool to appear twice (raw text + rendered card). Regular DAG nodes already had this metadata. 2. WorkflowLogs: Add text content dedup in SSE/DB merge. During live execution, the same text (e.g. "Starting workflow...") can appear in both DB (REST fetch) and SSE (event buffer replay). Collects DB text into a Set and skips matching SSE text messages. 3. orchestrator-agent: Suppress remainingMessage re-send in stream mode. The routing AI streams text chunks before /invoke-workflow is detected, then retracts them. Without suppression, remainingMessage re-sends the same text. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
968dfadcf5
commit
4e56c86dff
3 changed files with 32 additions and 2 deletions
|
|
@ -898,13 +898,20 @@ async function handleStreamMode(
|
|||
if (platform.emitRetract) {
|
||||
await platform.emitRetract(conversationId);
|
||||
}
|
||||
// In stream mode, pre-command text was already sent chunk-by-chunk
|
||||
// and then retracted. Suppress remainingMessage to avoid re-sending
|
||||
// it (which causes duplicate text in the chat).
|
||||
const streamSafeInvocation = {
|
||||
...commands.workflowInvocation,
|
||||
remainingMessage: '',
|
||||
};
|
||||
await handleWorkflowInvocationResult(
|
||||
platform,
|
||||
conversationId,
|
||||
conversation,
|
||||
codebases,
|
||||
workflows,
|
||||
commands.workflowInvocation,
|
||||
streamSafeInvocation,
|
||||
originalMessage,
|
||||
isolationHints,
|
||||
issueContext
|
||||
|
|
|
|||
|
|
@ -388,10 +388,31 @@ export function WorkflowLogs({
|
|||
filteredDbMessages = dbMessages;
|
||||
}
|
||||
|
||||
// Collect DB text content for dedup against SSE text messages.
|
||||
// During live execution, the same text (e.g., "🚀 Starting workflow...") can appear
|
||||
// in both DB (from REST fetch on mount) and SSE (from event buffer replay).
|
||||
// Without dedup, the text shows up twice in the message list.
|
||||
const dbTextContents = new Set<string>();
|
||||
for (const dm of filteredDbMessages) {
|
||||
if (dm.role === 'assistant' && dm.content) {
|
||||
dbTextContents.add(dm.content);
|
||||
}
|
||||
}
|
||||
|
||||
// Strip SSE tool calls that already appear in DB messages (completed).
|
||||
// Also strip SSE text messages that are already in DB (prevents duplicate text).
|
||||
const dedupedSse: ChatMessage[] = [];
|
||||
for (const m of sseMessages) {
|
||||
if (!m.toolCalls?.length) {
|
||||
// Skip SSE text-only messages whose content already exists in DB.
|
||||
if (m.content && dbTextContents.has(m.content)) {
|
||||
continue;
|
||||
}
|
||||
// Also skip if DB has a message that starts with the SSE content
|
||||
// (SSE text was flushed to DB before SSE finished accumulating).
|
||||
if (m.content && [...dbTextContents].some(dc => dc.startsWith(m.content))) {
|
||||
continue;
|
||||
}
|
||||
if (m.isStreaming || m.content) dedupedSse.push(m);
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1915,7 +1915,9 @@ async function executeLoopNode(
|
|||
if (platform.getStreamingMode() === 'stream') {
|
||||
const toolMsg = formatToolCall(msg.toolName, msg.toolInput);
|
||||
if (toolMsg) {
|
||||
await safeSendMessage(platform, conversationId, toolMsg, msgContext);
|
||||
await safeSendMessage(platform, conversationId, toolMsg, msgContext, {
|
||||
category: 'tool_call_formatted',
|
||||
} as WorkflowMessageMetadata);
|
||||
}
|
||||
if (platform.sendStructuredEvent) {
|
||||
await platform.sendStructuredEvent(conversationId, msg);
|
||||
|
|
|
|||
Loading…
Reference in a new issue