From 70949929db0a0bae2fc1bc0adcfa74a7b62a0696 Mon Sep 17 00:00:00 2001 From: DragonBaiMo <907693786@qq.com> Date: Fri, 20 Feb 2026 20:34:40 +0800 Subject: [PATCH] fix(kiro): deduplicate thinking stream emission --- internal/runtime/executor/kiro_executor.go | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/internal/runtime/executor/kiro_executor.go b/internal/runtime/executor/kiro_executor.go index a8237cd7..3d1e2d51 100644 --- a/internal/runtime/executor/kiro_executor.go +++ b/internal/runtime/executor/kiro_executor.go @@ -2551,6 +2551,7 @@ func (e *KiroExecutor) streamToChannel(ctx context.Context, body io.Reader, out isThinkingBlockOpen := false // Track if thinking content block SSE event is open thinkingBlockIndex := -1 // Index of the thinking content block var accumulatedThinkingContent strings.Builder // Accumulate thinking content for token counting + hasOfficialReasoningEvent := false // Disable tag parsing after official reasoning events appear // Buffer for handling partial tag matches at chunk boundaries var pendingContent strings.Builder // Buffer content that might be part of a tag @@ -2986,6 +2987,31 @@ func (e *KiroExecutor) streamToChannel(ctx context.Context, body io.Reader, out lastUsageUpdateTime = time.Now() } + if hasOfficialReasoningEvent { + processText := strings.TrimSpace(strings.ReplaceAll(strings.ReplaceAll(contentDelta, kirocommon.ThinkingStartTag, ""), kirocommon.ThinkingEndTag, "")) + if processText != "" { + if !isTextBlockOpen { + contentBlockIndex++ + isTextBlockOpen = true + blockStart := kiroclaude.BuildClaudeContentBlockStartEvent(contentBlockIndex, "text", "", "") + sseData := sdktranslator.TranslateStream(ctx, sdktranslator.FromString("kiro"), targetFormat, model, originalReq, claudeBody, blockStart, &translatorParam) + for _, chunk := range sseData { + if chunk != "" { + out <- cliproxyexecutor.StreamChunk{Payload: []byte(chunk + "\n\n")} + } + } + } + claudeEvent := kiroclaude.BuildClaudeStreamEvent(processText, contentBlockIndex) + sseData := sdktranslator.TranslateStream(ctx, sdktranslator.FromString("kiro"), targetFormat, model, originalReq, claudeBody, claudeEvent, &translatorParam) + for _, chunk := range sseData { + if chunk != "" { + out <- cliproxyexecutor.StreamChunk{Payload: []byte(chunk + "\n\n")} + } + } + } + continue + } + // TAG-BASED THINKING PARSING: Parse tags from content // Combine pending content with new content for processing pendingContent.WriteString(contentDelta) @@ -3264,6 +3290,7 @@ func (e *KiroExecutor) streamToChannel(ctx context.Context, body io.Reader, out } if thinkingText != "" { + hasOfficialReasoningEvent = true // Close text block if open before starting thinking block if isTextBlockOpen && contentBlockIndex >= 0 { blockStop := kiroclaude.BuildClaudeContentBlockStopEvent(contentBlockIndex)