Skip to content

Commit 7d66f89

Browse files
Sagid Magomedovedelauna
authored andcommitted
test(tag-matcher): add tests for unmatched closing tags
Add two regression tests that verify depth never goes negative: 1. stray closer with no opener "final</think>text" → stays text 2. duplicate closer after a proper close "<think>thinking</think>final</think>text" → second </think> stays text Both cases ensure we only decrement depth and pop activeTagNames when depth > 0, preventing underflow and treating the extra tag as plain text.
1 parent ae1a395 commit 7d66f89

1 file changed

Lines changed: 49 additions & 0 deletions

File tree

src/api/providers/__tests__/openai.spec.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,55 @@ describe("OpenAiHandler", () => {
777777
])
778778
})
779779

780+
it("should treat stray closing tag as plain text when no tag is open", async () => {
781+
mockCreate.mockImplementationOnce(() => ({
782+
[Symbol.asyncIterator]: () => ({
783+
next: vi
784+
.fn()
785+
.mockResolvedValueOnce({
786+
done: false,
787+
value: { choices: [{ delta: { content: "final</think>text" } }] },
788+
})
789+
.mockResolvedValueOnce({ done: true }),
790+
}),
791+
}))
792+
793+
const stream = handler.createMessage(systemPrompt, messages)
794+
const chunks: any[] = []
795+
for await (const chunk of stream) {
796+
chunks.push(chunk)
797+
}
798+
799+
expect(chunks).toEqual([{ type: "text", text: "final</think>text" }])
800+
})
801+
802+
it("should treat extra closing tag after a closed block as plain text", async () => {
803+
mockCreate.mockImplementationOnce(() => ({
804+
[Symbol.asyncIterator]: () => ({
805+
next: vi
806+
.fn()
807+
.mockResolvedValueOnce({
808+
done: false,
809+
value: {
810+
choices: [{ delta: { content: "<think>thinking</think>final</think>text" } }],
811+
},
812+
})
813+
.mockResolvedValueOnce({ done: true }),
814+
}),
815+
}))
816+
817+
const stream = handler.createMessage(systemPrompt, messages)
818+
const chunks: any[] = []
819+
for await (const chunk of stream) {
820+
chunks.push(chunk)
821+
}
822+
823+
expect(chunks).toEqual([
824+
{ type: "reasoning", text: "thinking" },
825+
{ type: "text", text: "final</think>text" },
826+
])
827+
})
828+
780829
it("should handle <think> tags that start at beginning of stream", async () => {
781830
mockCreate.mockImplementationOnce(() => ({
782831
[Symbol.asyncIterator]: () => ({

0 commit comments

Comments
 (0)