From a077ec8d8524dd3b5a717c97538f44a0833e8194 Mon Sep 17 00:00:00 2001 From: claude-code-best Date: Fri, 5 Jun 2026 10:37:59 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20ACP=20=E6=A8=A1=E5=BC=8F=E4=B8=8B?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E9=87=8D=E5=A4=8D=E6=98=BE=E7=A4=BA=20?= =?UTF-8?q?=E2=80=94=20=E6=B5=81=E5=BC=8F=E4=BA=8B=E4=BB=B6=E4=B8=8E?= =?UTF-8?q?=E5=8A=A9=E6=89=8B=E6=B6=88=E6=81=AF=E5=8F=8C=E9=87=8D=E6=8E=A8?= =?UTF-8?q?=E9=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit stream_event 和 assistant 消息对同一文本内容各发一次 agent_message_chunk, 导致 ACP 客户端显示两遍。添加 streamingActive 标志,在收到 stream_event 后 过滤掉 assistant 消息中已被流式路径处理的 text/thinking 块。 --- src/services/acp/bridge.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/services/acp/bridge.ts b/src/services/acp/bridge.ts index 17c0831de..58c6d284b 100644 --- a/src/services/acp/bridge.ts +++ b/src/services/acp/bridge.ts @@ -633,6 +633,7 @@ export async function forwardSessionUpdates( let lastAssistantTotalUsage: number | null = null let lastAssistantModel: string | null = null let lastContextWindowSize = 200000 + let streamingActive = false try { while (!abortSignal.aborted) { @@ -788,6 +789,7 @@ export async function forwardSessionUpdates( for (const notification of notifications) { await conn.sessionUpdate(notification) } + streamingActive = true break } @@ -828,6 +830,7 @@ export async function forwardSessionUpdates( clientCapabilities, cwd, parentToolUseId, + streamingActive, }, ) for (const notification of notifications) { @@ -943,6 +946,7 @@ function assistantMessageToAcpNotifications( clientCapabilities?: ClientCapabilities parentToolUseId?: string | null cwd?: string + streamingActive?: boolean }, ): SessionNotification[] { const message = msg.message as Record | undefined @@ -967,8 +971,20 @@ function assistantMessageToAcpNotifications( ] } + // When streaming is active, text/thinking were already sent via stream_event + // messages. Filter them out to avoid duplicate agent_message_chunk / + // agent_thought_chunk notifications. String content (synthetic messages) + // is unaffected — those have no corresponding stream_events. + const contentToProcess = options?.streamingActive + ? content.filter( + block => block.type !== 'text' && block.type !== 'thinking', + ) + : content + + if (contentToProcess.length === 0) return [] + return toAcpNotifications( - content, + contentToProcess, 'assistant', sessionId, toolUseCache, @@ -988,6 +1004,7 @@ function streamEventToAcpNotifications( options?: { clientCapabilities?: ClientCapabilities cwd?: string + streamingActive?: boolean }, ): SessionNotification[] { const event = (msg as unknown as { event: Record }).event @@ -1056,6 +1073,7 @@ function toAcpNotifications( clientCapabilities?: ClientCapabilities parentToolUseId?: string | null cwd?: string + streamingActive?: boolean }, ): SessionNotification[] { const output: SessionNotification[] = []