Files
buzz/desktop/src/features/agents/ui/agentSessionTranscriptGrouping.test.mjs
Taylor Ho 9f65106822 refactor(agents): drop transcript compact mode and simplify row spacing
- Remove the compact layout prop from AgentSessionTranscriptList,
  ManagedAgentSessionPanel, and AgentSessionThreadPanel; always render the
  tighter transcript density
- Revert consecutive tool-call grouping (tool_group segments, ToolCallGroup,
  segment spacing helpers) and render each tool as a normal transcript row
- Add symmetric per-type row spacing: my-2.5 for messages, my-1 for tools,
  my-2 for other items
- Simplify ToolItem wrapper padding now that grouped/compact props are gone
2026-06-15 01:14:10 -07:00

214 lines
5.7 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import {
buildTranscriptDisplayBlocks,
flattenDisplayBlocks,
formatTurnSetupLabel,
} from "./agentSessionTranscriptGrouping.ts";
const baseTimestamp = "2026-06-14T22:20:23.000Z";
function lifecycle(id, title, acpSource, turnId, text = "") {
return {
id,
type: "lifecycle",
title,
text,
timestamp: baseTimestamp,
acpSource,
turnId,
sessionId: "sess-1",
channelId: "channel-1",
};
}
function userPrompt(id, text, turnId) {
return {
id,
type: "message",
role: "user",
title: "Buzz event",
text,
timestamp: baseTimestamp,
acpSource: "session/prompt:user",
turnId,
sessionId: "sess-1",
channelId: "channel-1",
};
}
function promptContext(id, turnId) {
return {
id,
type: "metadata",
title: "Prompt context",
sections: [{ title: "Channel", body: "general" }],
timestamp: baseTimestamp,
acpSource: "session/prompt:context",
turnId,
sessionId: "sess-1",
channelId: "channel-1",
};
}
function assistantMessage(id, text, turnId) {
return {
id,
type: "message",
role: "assistant",
title: "Assistant",
text,
timestamp: "2026-06-14T22:20:47.000Z",
acpSource: "agent_message_chunk",
turnId,
sessionId: "sess-1",
channelId: "channel-1",
};
}
function toolCall(id, turnId) {
return {
id,
type: "tool",
title: "Shell",
toolName: "buzz-dev-mcp__shell",
buzzToolName: null,
status: "completed",
args: {},
result: "ok",
isError: false,
timestamp: "2026-06-14T22:20:47.000Z",
startedAt: "2026-06-14T22:20:47.000Z",
completedAt: "2026-06-14T22:20:47.400Z",
acpSource: "tool_call_update",
turnId,
sessionId: "sess-1",
channelId: "channel-1",
};
}
test("buildTranscriptDisplayBlocks bundles user prompt, setup, and context together", () => {
const rawItems = [
lifecycle(
"turn",
"Turn started",
"turn_started",
"turn-1",
"Triggered by 1 event.",
),
lifecycle("session", "Session ready", "session_resolved", "turn-1"),
userPrompt("prompt", "@Ned deliberate, wider pass", "turn-1"),
promptContext("context", "turn-1"),
assistantMessage("assistant", "Thinking out loud.", "turn-1"),
toolCall("tool", "turn-1"),
];
const blocks = buildTranscriptDisplayBlocks(rawItems);
const displayOrder = flattenDisplayBlocks(blocks).map((item) => item.id);
assert.deepEqual(displayOrder, [
"prompt",
"turn",
"session",
"context",
"assistant",
"tool",
]);
const turnBlock = blocks[0];
assert.equal(turnBlock?.kind, "turn");
assert.equal(turnBlock.segments[0]?.kind, "prompt");
const promptSegment = turnBlock.segments[0];
assert.equal(promptSegment.user.id, "prompt");
assert.equal(promptSegment.context?.id, "context");
assert.equal(promptSegment.setup.length, 2);
assert.equal(turnBlock.segments[1]?.kind, "item");
assert.equal(turnBlock.segments[2]?.kind, "item");
});
test("buildTranscriptDisplayBlocks collapses setup lifecycle inside prompt bundle", () => {
const rawItems = [
lifecycle("turn", "Turn started", "turn_started", "turn-1"),
lifecycle("session", "Session ready", "session_resolved", "turn-1"),
userPrompt("prompt", "hello", "turn-1"),
];
const blocks = buildTranscriptDisplayBlocks(rawItems);
assert.equal(blocks.length, 1);
assert.equal(blocks[0]?.kind, "turn");
const turnBlock = blocks[0];
assert.equal(turnBlock.segments.length, 1);
assert.equal(turnBlock.segments[0]?.kind, "prompt");
assert.equal(
formatTurnSetupLabel(turnBlock.segments[0].setup),
"Turn started · Session ready",
);
});
test("buildTranscriptDisplayBlocks hides setup and context when prompt is missing", () => {
const rawItems = [
lifecycle("turn", "Turn started", "turn_started", "turn-1"),
lifecycle("session", "Session ready", "session_resolved", "turn-1"),
promptContext("context", "turn-1"),
toolCall("tool", "turn-1"),
];
const blocks = buildTranscriptDisplayBlocks(rawItems);
const displayOrder = flattenDisplayBlocks(blocks).map((item) => item.id);
assert.deepEqual(displayOrder, ["tool"]);
});
test("buildTranscriptDisplayBlocks drops setup-and-context-only turns", () => {
const rawItems = [
lifecycle("turn", "Turn started", "turn_started", "turn-1"),
lifecycle("session", "Session ready", "session_resolved", "turn-1"),
promptContext("context", "turn-1"),
];
const blocks = buildTranscriptDisplayBlocks(rawItems);
assert.deepEqual(blocks, []);
});
test("buildTranscriptDisplayBlocks leaves error lifecycle prominent outside prompt bundle", () => {
const rawItems = [
lifecycle("turn", "Turn started", "turn_started", "turn-1"),
userPrompt("prompt", "hello", "turn-1"),
lifecycle(
"error",
"Turn error",
"turn_error",
"turn-1",
"timeout: agent hung",
),
];
const blocks = buildTranscriptDisplayBlocks(rawItems);
const displayOrder = flattenDisplayBlocks(blocks).map((item) => item.id);
assert.deepEqual(displayOrder, ["prompt", "turn", "error"]);
assert.equal(blocks[0]?.segments[0]?.kind, "prompt");
assert.equal(blocks[0]?.segments[1]?.kind, "item");
assert.equal(blocks[0]?.segments[1]?.item.id, "error");
});
test("buildTranscriptDisplayBlocks passes through items without turnId", () => {
const orphan = {
id: "orphan",
type: "lifecycle",
title: "Wire parse error",
text: "bad json",
timestamp: baseTimestamp,
acpSource: "acp_parse_error",
channelId: "channel-1",
};
const blocks = buildTranscriptDisplayBlocks([orphan]);
assert.equal(blocks.length, 1);
assert.equal(blocks[0]?.kind, "single");
assert.equal(blocks[0]?.item.id, "orphan");
});