mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
fix(kiro): strip leaked <thinking> tags from content stream (#2158)
CodeWhisperer leaks literal <thinking> blocks into assistantResponseEvent, duplicating reasoning already routed via reasoningContentEvent. Track inThinking state to strip these tags during SSE transform, handling split chunks across tag boundaries. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
decolua
co-authored by
Cursor
parent
b66b5c68ce
commit
eff81b1242
@@ -122,7 +122,8 @@ export class KiroExecutor extends BaseExecutor {
|
||||
hasReasoningContent: false,
|
||||
reasoningChunkCount: 0,
|
||||
toolCallIndex: 0,
|
||||
seenToolIds: new Map()
|
||||
seenToolIds: new Map(),
|
||||
inThinking: false
|
||||
};
|
||||
|
||||
const transformStream = new TransformStream({
|
||||
@@ -159,7 +160,36 @@ export class KiroExecutor extends BaseExecutor {
|
||||
|
||||
// Handle assistantResponseEvent
|
||||
if (eventType === "assistantResponseEvent" && event.payload?.content) {
|
||||
const content = event.payload.content;
|
||||
let content = event.payload.content;
|
||||
|
||||
// Kiro Claude models can leak <thinking> blocks into the content stream.
|
||||
// We strip these literal tags to prevent duplication, as the reasoning
|
||||
// is already routed correctly via reasoningContentEvent.
|
||||
if (state.inThinking) {
|
||||
if (content.includes("</thinking>")) {
|
||||
state.inThinking = false;
|
||||
const after = content.split("</thinking>").slice(1).join("</thinking>");
|
||||
content = after.startsWith("\n") ? after.substring(1) : after;
|
||||
} else {
|
||||
content = ""; // Drop entirely while inside thinking block
|
||||
}
|
||||
} else if (content.includes("<thinking>")) {
|
||||
state.inThinking = true;
|
||||
if (content.includes("</thinking>")) {
|
||||
state.inThinking = false;
|
||||
const before = content.split("<thinking>")[0];
|
||||
const after = content.split("</thinking>").slice(1).join("</thinking>");
|
||||
content = before + (after.startsWith("\n") ? after.substring(1) : after);
|
||||
} else {
|
||||
content = content.split("<thinking>")[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!content && state.hasReasoningContent) {
|
||||
// If we stripped everything, skip emitting an empty content chunk
|
||||
continue;
|
||||
}
|
||||
|
||||
state.totalContentLength += content.length;
|
||||
|
||||
const chunk = {
|
||||
|
||||
Reference in New Issue
Block a user