Files
openworker/surfaces/gui/src/itemsFromMessages.test.ts
T
Rohit C Prasad 0e8b85e6f3 Show reasoning traces: live Thinking block + persisted disclosure
New reasoning_delta event; traces persist as a display sidecar stripped from provider feeds.
Sources: compat vendors' reasoning_content and Gemini thought summaries (include_thoughts).
Live-verified on GLM via Together and Gemini 3; Gemini tool loops stay healthy.
2026-07-22 16:15:11 -07:00

97 lines
3.7 KiB
TypeScript

// The `_display` sidecar on a persisted tool message (privacy-filter hidden
// counts) must surface on the replayed tool item — and only there; the
// agent-visible content string carries no trace.
import { describe, expect, it } from "vitest";
import { itemsFromMessages } from "./itemsFromMessages";
describe("itemsFromMessages _display sidecar", () => {
it("attaches hidden counts to the matching tool item", () => {
const items = itemsFromMessages([
{ role: "user", content: "check my mail" },
{
role: "assistant",
content: "",
tool_calls: [
{ id: "t1", function: { name: "gmail_search_messages", arguments: "{}" } },
{ id: "t2", function: { name: "gmail_get_message", arguments: "{}" } },
],
},
{
role: "tool",
tool_call_id: "t1",
content: '{"ok": true, "data": {"messages": []}}',
_display: { hidden_by_filters: 2, connector: "gmail" },
},
{ role: "tool", tool_call_id: "t2", content: '{"ok": true}' },
] as any);
const tools = items.filter((i: any) => i.kind === "tool") as any[];
expect(tools).toHaveLength(2);
expect(tools[0].hidden).toBe(2);
expect(tools[1].hidden).toBeUndefined();
expect(tools[0].preview).not.toContain("hidden"); // content stays clean
});
});
describe("itemsFromMessages timestamps", () => {
it("carries the server ts through to user/assistant items; pre-stamp history gets none", () => {
const items = itemsFromMessages([
{ role: "user", content: "hi", ts: 1752969720 },
{ role: "assistant", content: "hello", ts: 1752969724 },
{ role: "user", content: "old message" }, // saved before the server stamped ts
] as any);
expect(items).toEqual([
{ kind: "user", text: "hi", ts: 1752969720 },
{ kind: "assistant", text: "hello", ts: 1752969724 },
{ kind: "user", text: "old message" },
]);
});
});
describe("itemsFromMessages notices", () => {
it("replays persisted error/interrupted markers; only errors are retriable", () => {
const items = itemsFromMessages([
{ role: "user", content: "hi" },
{ role: "assistant", content: "partial ans" },
{ role: "notice", kind: "interrupted", ts: 1752969720 },
{ role: "user", content: "again" },
{ role: "notice", kind: "error", text: "model down", ts: 1752969724 },
] as any);
expect(items).toEqual([
{ kind: "user", text: "hi" },
{ kind: "assistant", text: "partial ans" },
{ kind: "notice", tone: "warn", text: "Interrupted." },
{ kind: "user", text: "again" },
{ kind: "notice", tone: "warn", text: "Error: model down", retriable: true },
]);
});
});
describe("itemsFromMessages model switch", () => {
it("replays the persisted model_switch marker as an info notice", () => {
const items = itemsFromMessages([
{ role: "user", content: "hi" },
{ role: "notice", kind: "model_switch", text: "Model switched to Kimi K2.6 · Moonshot" },
] as any);
expect(items[1]).toEqual({
kind: "notice",
tone: "info",
text: "Model switched to Kimi K2.6 · Moonshot",
});
});
});
describe("itemsFromMessages reasoning", () => {
it("attaches the reasoning sidecar to assistant items; thinking-only messages still render", () => {
const items = itemsFromMessages([
{ role: "user", content: "hi" },
{ role: "assistant", content: "answer", reasoning: "let me think" },
{ role: "assistant", content: "", reasoning: "stopped mid-thought" },
] as any);
expect(items[1]).toEqual({ kind: "assistant", text: "answer", reasoning: "let me think" });
expect(items[2]).toEqual({ kind: "assistant", text: "", reasoning: "stopped mid-thought" });
});
});