diff --git a/ui/src/ui/format.test.ts b/ui/src/ui/format.test.ts index d7acecebb..2a687c099 100644 --- a/ui/src/ui/format.test.ts +++ b/ui/src/ui/format.test.ts @@ -21,6 +21,7 @@ describe("stripThinkingTags", () => { it("returns original text when no tags exist", () => { expect(stripThinkingTags("Hello")).toBe("Hello"); }); +<<<<<<< fix/tui-final-tag-strip it("strips segments", () => { const input = "\n\nHello there\n\n"; @@ -39,4 +40,27 @@ describe("stripThinkingTags", () => { expect(stripThinkingTags("Hello")).toBe("Hello"); }); }); +||||||| temp/landpr- +}); +======= +>>>>>>> local + it("strips segments while keeping content", () => { + const input = "\n\nHello there\n\n"; + expect(stripThinkingTags(input)).toBe("Hello there\n\n"); + }); + + it("strips mixed and tags", () => { + const input = "reasoning\n\nHello"; + expect(stripThinkingTags(input)).toBe("Hello"); + }); + + it("strips unpaired tags", () => { + expect(stripThinkingTags("Hello")).toBe("Hello"); + expect(stripThinkingTags("Hello")).toBe("Hello"); + }); + + it("keeps incomplete { + expect(stripThinkingTags(" v.length > 0); } +<<<<<<< fix/tui-final-tag-strip const THINKING_TAG_RE = /<\s*\/?\s*(?:think(?:ing)?|final)\s*>/gi; const THINKING_OPEN_RE = /<\s*(?:think(?:ing)?|final)\s*>/i; const THINKING_CLOSE_RE = /<\s*\/\s*(?:think(?:ing)?|final)\s*>/i; +||||||| temp/landpr- +const THINKING_TAG_RE = /<\s*\/?\s*think(?:ing)?\s*>/gi; +const THINKING_OPEN_RE = /<\s*think(?:ing)?\s*>/i; +const THINKING_CLOSE_RE = /<\s*\/\s*think(?:ing)?\s*>/i; +======= +const FINAL_TAG_RE = /<\s*\/?\s*final\s*>/gi; +const THINKING_TAG_RE = /<\s*\/?\s*think(?:ing)?\s*>/gi; +const THINKING_OPEN_RE = /<\s*think(?:ing)?\s*>/i; +const THINKING_CLOSE_RE = /<\s*\/\s*think(?:ing)?\s*>/i; +>>>>>>> local export function stripThinkingTags(value: string): string { if (!value) return value; - const hasOpen = THINKING_OPEN_RE.test(value); - const hasClose = THINKING_CLOSE_RE.test(value); - if (!hasOpen && !hasClose) return value; - // If we don't have a balanced pair, avoid dropping trailing content. - if (hasOpen !== hasClose) { - if (!hasOpen) return value.replace(THINKING_CLOSE_RE, "").trimStart(); - return value.replace(THINKING_OPEN_RE, "").trimStart(); + let cleaned = value; + let strippedFinal = false; + if (FINAL_TAG_RE.test(cleaned)) { + FINAL_TAG_RE.lastIndex = 0; + cleaned = cleaned.replace(FINAL_TAG_RE, ""); + strippedFinal = true; + } else { + FINAL_TAG_RE.lastIndex = 0; } - if (!THINKING_TAG_RE.test(value)) return value; + const hasOpen = THINKING_OPEN_RE.test(cleaned); + const hasClose = THINKING_CLOSE_RE.test(cleaned); + if (!hasOpen && !hasClose) return strippedFinal ? cleaned.trimStart() : cleaned; + // If we don't have a balanced pair, avoid dropping trailing content. + if (hasOpen !== hasClose) { + if (!hasOpen) return cleaned.replace(THINKING_CLOSE_RE, "").trimStart(); + return cleaned.replace(THINKING_OPEN_RE, "").trimStart(); + } + + if (!THINKING_TAG_RE.test(cleaned)) { + THINKING_TAG_RE.lastIndex = 0; + return strippedFinal ? cleaned.trimStart() : cleaned; + } THINKING_TAG_RE.lastIndex = 0; let result = ""; let lastIndex = 0; let inThinking = false; - for (const match of value.matchAll(THINKING_TAG_RE)) { + for (const match of cleaned.matchAll(THINKING_TAG_RE)) { const idx = match.index ?? 0; if (!inThinking) { - result += value.slice(lastIndex, idx); + result += cleaned.slice(lastIndex, idx); } const tag = match[0].toLowerCase(); inThinking = !tag.includes("/"); lastIndex = idx + match[0].length; } if (!inThinking) { - result += value.slice(lastIndex); + result += cleaned.slice(lastIndex); } return result.trimStart(); }