story-kit: start 218_story_hide_thinking_traces_from_agents_panel

This commit is contained in:
Dave
2026-02-27 09:52:02 +00:00
parent 6ca4ecc52e
commit 19f661e8e3
3 changed files with 48 additions and 166 deletions

View File

@@ -213,7 +213,7 @@ describe("RosterBadge availability state", () => {
});
});
describe("Thinking trace block in agent stream UI", () => {
describe("Thinking traces hidden from agent stream UI", () => {
beforeAll(() => {
Element.prototype.scrollIntoView = vi.fn();
});
@@ -224,8 +224,8 @@ describe("Thinking trace block in agent stream UI", () => {
mockedSubscribeAgentStream.mockReturnValue(() => {});
});
// AC1+AC2: thinking block renders with fixed max-height and is visually distinct
it("renders thinking block with max-height 96px when thinking event arrives", async () => {
// AC1: thinking block is never rendered even when thinking events arrive
it("does not render thinking block when thinking event arrives", async () => {
let emitEvent: ((e: AgentEvent) => void) | null = null;
mockedSubscribeAgentStream.mockImplementation(
(_storyId, _agentName, onEvent) => {
@@ -236,7 +236,7 @@ describe("Thinking trace block in agent stream UI", () => {
const agentList: AgentInfo[] = [
{
story_id: "160_thinking",
story_id: "218_thinking",
agent_name: "coder-1",
status: "running",
session_id: null,
@@ -248,37 +248,23 @@ describe("Thinking trace block in agent stream UI", () => {
mockedAgents.listAgents.mockResolvedValue(agentList);
render(<AgentPanel />);
// Wait for the subscription to be set up
await screen.findByTestId("roster-badge-coder-1");
// Fire a thinking event
await act(async () => {
emitEvent?.({
type: "thinking",
story_id: "160_thinking",
story_id: "218_thinking",
agent_name: "coder-1",
text: "Let me consider the problem carefully...",
});
});
const block = screen.getByTestId("thinking-block");
expect(block).toBeInTheDocument();
// AC2: fixed max-height
expect(block.style.maxHeight).toBe("96px");
// AC2: overflow scrolling
expect(block.style.overflowY).toBe("auto");
// AC1: visually distinct — italic monospace font
expect(block.style.fontStyle).toBe("italic");
expect(block.style.fontFamily).toBe("monospace");
// Contains the thinking text
expect(block.textContent).toContain(
"Let me consider the problem carefully...",
);
// AC1: thinking block must not be present
expect(screen.queryByTestId("thinking-block")).not.toBeInTheDocument();
});
// AC3: thinking block renders the "thinking" label
it("shows a thinking label in the block header", async () => {
// AC2: after thinking events, only regular output is rendered
it("renders regular output but not thinking block when both arrive", async () => {
let emitEvent: ((e: AgentEvent) => void) | null = null;
mockedSubscribeAgentStream.mockImplementation(
(_storyId, _agentName, onEvent) => {
@@ -289,7 +275,7 @@ describe("Thinking trace block in agent stream UI", () => {
const agentList: AgentInfo[] = [
{
story_id: "160_label",
story_id: "218_output",
agent_name: "coder-1",
status: "running",
session_id: null,
@@ -303,80 +289,37 @@ describe("Thinking trace block in agent stream UI", () => {
render(<AgentPanel />);
await screen.findByTestId("roster-badge-coder-1");
// Thinking event — must be ignored visually
await act(async () => {
emitEvent?.({
type: "thinking",
story_id: "160_label",
agent_name: "coder-1",
text: "thinking...",
});
});
const block = screen.getByTestId("thinking-block");
expect(block.textContent).toContain("thinking");
});
// AC4: regular text output renders outside the thinking container
it("renders regular output outside the thinking block", async () => {
let emitEvent: ((e: AgentEvent) => void) | null = null;
mockedSubscribeAgentStream.mockImplementation(
(_storyId, _agentName, onEvent) => {
emitEvent = onEvent;
return () => {};
},
);
const agentList: AgentInfo[] = [
{
story_id: "160_output",
agent_name: "coder-1",
status: "running",
session_id: null,
worktree_path: "/tmp/wt",
base_branch: "master",
log_session_id: null,
},
];
mockedAgents.listAgents.mockResolvedValue(agentList);
render(<AgentPanel />);
await screen.findByTestId("roster-badge-coder-1");
// First: thinking event
await act(async () => {
emitEvent?.({
type: "thinking",
story_id: "160_output",
story_id: "218_output",
agent_name: "coder-1",
text: "thinking deeply",
});
});
// Then: text output event
// AC3: output event still renders correctly (no regression)
await act(async () => {
emitEvent?.({
type: "output",
story_id: "160_output",
story_id: "218_output",
agent_name: "coder-1",
text: "Here is the result.",
});
});
const thinkingBlock = screen.getByTestId("thinking-block");
// AC1: no thinking block
expect(screen.queryByTestId("thinking-block")).not.toBeInTheDocument();
// AC2+AC3: output area renders the text
const outputArea = screen.getByTestId("agent-output-coder-1");
// Thinking still visible
expect(thinkingBlock).toBeInTheDocument();
expect(thinkingBlock.textContent).toContain("thinking deeply");
// Output renders in a separate element, not inside the thinking block
expect(outputArea).toBeInTheDocument();
expect(outputArea.textContent).toContain("Here is the result.");
expect(thinkingBlock.contains(outputArea)).toBe(false);
});
// AC5: thinking block remains visible when text starts
it("keeps thinking block visible after output arrives", async () => {
// AC3: output-only event stream (no thinking) still works
it("renders output event text without a thinking block", async () => {
let emitEvent: ((e: AgentEvent) => void) | null = null;
mockedSubscribeAgentStream.mockImplementation(
(_storyId, _agentName, onEvent) => {
@@ -387,7 +330,7 @@ describe("Thinking trace block in agent stream UI", () => {
const agentList: AgentInfo[] = [
{
story_id: "160_persist",
story_id: "218_noThink",
agent_name: "coder-1",
status: "running",
session_id: null,
@@ -401,25 +344,17 @@ describe("Thinking trace block in agent stream UI", () => {
render(<AgentPanel />);
await screen.findByTestId("roster-badge-coder-1");
await act(async () => {
emitEvent?.({
type: "thinking",
story_id: "160_persist",
agent_name: "coder-1",
text: "my thoughts",
});
});
await act(async () => {
emitEvent?.({
type: "output",
story_id: "160_persist",
story_id: "218_noThink",
agent_name: "coder-1",
text: "final answer",
text: "plain output line",
});
});
// Thinking block still in the DOM after output arrives
expect(screen.getByTestId("thinking-block")).toBeInTheDocument();
expect(screen.queryByTestId("thinking-block")).not.toBeInTheDocument();
const outputArea = screen.getByTestId("agent-output-coder-1");
expect(outputArea.textContent).toContain("plain output line");
});
});