import { parseAssistantMessageSections, parseContentWithToolCalls, } from "./chatMessageSections"; describe("parseAssistantMessageSections", () => { it("returns plain assistant content when there is no thought block", () => { expect(parseAssistantMessageSections("直接回答")).toEqual({ answer: "直接回答", thought: null, thoughtComplete: false, }); }); it("extracts a completed thought block and keeps the final answer visible", () => { expect( parseAssistantMessageSections("先分析需求\n\n最终回答"), ).toEqual({ answer: "最终回答", thought: "先分析需求", thoughtComplete: true, }); }); it("supports streaming thought content before the closing tag arrives", () => { expect( parseAssistantMessageSections("准备中...\n继续推理中"), ).toEqual({ answer: "准备中...", thought: "继续推理中", thoughtComplete: false, }); }); it("merges multiple thought blocks into a single collapsed section", () => { expect( parseAssistantMessageSections( "第一段思考\n答案开头\n第二段思考\n答案结尾", ), ).toEqual({ answer: "答案开头\n\n答案结尾", thought: "第一段思考\n\n第二段思考", thoughtComplete: true, }); }); }); describe("parseContentWithToolCalls", () => { it("returns a single text segment when there are no tool calls", () => { const result = parseContentWithToolCalls("普通文本回答"); expect(result.segments).toEqual([ { type: "text", content: "普通文本回答" }, ]); expect(result.toolCalls).toHaveLength(0); }); it("parses a complete tool_call block", () => { const content = '分析完成。\n{"tool":"locate_junctions","params":{"ids":["J1","J2"]}}\n以上是结果。'; const result = parseContentWithToolCalls(content); expect(result.toolCalls).toHaveLength(1); expect(result.toolCalls[0].tool).toBe("locate_junctions"); expect(result.toolCalls[0].params).toEqual({ ids: ["J1", "J2"] }); expect(result.segments).toHaveLength(3); expect(result.segments[0]).toEqual({ type: "text", content: "分析完成。", }); expect(result.segments[1]).toMatchObject({ type: "tool_call", toolCall: { tool: "locate_junctions" }, }); expect(result.segments[2]).toEqual({ type: "text", content: "以上是结果。", }); }); it("parses multiple tool_call blocks", () => { const content = '文本1\n{"tool":"locate_pipes","params":{"ids":["P1"]}}\n文本2\n{"tool":"chart","params":{"title":"图"}}'; const result = parseContentWithToolCalls(content); expect(result.toolCalls).toHaveLength(2); expect(result.toolCalls[0].tool).toBe("locate_pipes"); expect(result.toolCalls[1].tool).toBe("chart"); expect(result.segments).toHaveLength(4); }); it("detects an unclosed tool_call tag as pending (streaming)", () => { const content = '正在分析...\n{"tool":"locate_no'; const result = parseContentWithToolCalls(content); expect(result.segments).toHaveLength(2); expect(result.segments[0]).toEqual({ type: "text", content: "正在分析...", }); expect(result.segments[1]).toEqual({ type: "tool_call_pending" }); expect(result.toolCalls).toHaveLength(0); }); it("strips partial opening tags during streaming", () => { const content = "正在分析...\n { const content = '前文\n{invalid json}\n后文'; const result = parseContentWithToolCalls(content); // Malformed tool call is treated as text expect(result.toolCalls).toHaveLength(0); expect(result.segments.length).toBeGreaterThanOrEqual(2); }); it("returns empty segments for empty content", () => { const result = parseContentWithToolCalls(""); expect(result.segments).toHaveLength(0); expect(result.toolCalls).toHaveLength(0); }); });