fix(frontend): drop dead identity ternary and add opt-in export tests

Address review feedback on the previous export commit:

1. Removed the no-op `typeof msg.content === "string" ? msg.content : msg.content`
   expression in `formatThreadAsJSON`. Both branches returned the same value;
   the message content now flows through unchanged whether it is a string or
   the rich `MessageContent[]` shape (LangChain JSON-serialises the array
   structure correctly already).

2. Expanded the JSDoc on `ExportOptions` to make it clearer that the four
   flags are not currently wired to any UI control — callers wanting a debug
   export must build the options object explicitly. The default behaviour
   continues to match the explicit prescription in
   bytedance/deer-flow#3107 BUG-006.

3. Added opt-in coverage. The previous tests only exercised the
   `options = {}` default path; the new cases verify each flag flips the
   corresponding payload back into the export so a future debug-export
   surface does not silently break the contract.

Refs: bytedance/deer-flow#3107 (BUG-006)
This commit is contained in:
fancyboi999
2026-05-21 16:26:25 +08:00
parent 9b0d4f8069
commit 530df255b2
2 changed files with 68 additions and 7 deletions
@@ -104,6 +104,66 @@ describe("formatThreadAsMarkdown", () => {
});
});
describe("formatThreadAsMarkdown opt-in flags", () => {
it("emits reasoning when includeReasoning is true", () => {
const message = ai("final answer", {
additional_kwargs: {
reasoning_content: "step-by-step chain of thought",
},
} as Partial<Message>);
const md = formatThreadAsMarkdown(makeThread(), [message], {
includeReasoning: true,
});
expect(md).toContain("step-by-step chain of thought");
expect(md).toContain("Thinking");
});
it("emits tool call rows when includeToolCalls is true", () => {
const message = ai("ok", {
tool_calls: [{ id: "1", name: "task", args: { description: "do work" } }],
} as Partial<Message>);
const md = formatThreadAsMarkdown(makeThread(), [message], {
includeToolCalls: true,
});
expect(md).toContain("**Tool:**");
expect(md).toContain("`task`");
});
it("keeps hidden messages when includeHidden is true", () => {
const hidden = human("internal reminder", {
additional_kwargs: { hide_from_ui: true },
} as Partial<Message>);
const md = formatThreadAsMarkdown(makeThread(), [hidden], {
includeHidden: true,
});
expect(md).toContain("internal reminder");
});
});
describe("formatThreadAsJSON opt-in flags", () => {
it("emits tool_calls field when includeToolCalls is true", () => {
const message = ai("ok", {
tool_calls: [{ id: "1", name: "task", args: { description: "x" } }],
} as Partial<Message>);
const raw = formatThreadAsJSON(makeThread(), [message], {
includeToolCalls: true,
});
expect(raw).toContain("tool_calls");
expect(raw).toContain('"task"');
});
it("keeps tool messages when includeToolMessages is true", () => {
const raw = formatThreadAsJSON(
makeThread(),
[toolMsg("Task Succeeded. Result: keep me")],
{ includeToolMessages: true },
);
const parsed = JSON.parse(raw) as { messages: { type: string }[] };
expect(parsed.messages.some((m) => m.type === "tool")).toBe(true);
expect(raw).toContain("keep me");
});
});
describe("formatThreadAsJSON", () => {
it("strips hidden messages, tool messages, reasoning, and tool calls", () => {
const messages = [