diff --git a/frontend/src/features/workstate/ProjectWorkStatePanel.tsx b/frontend/src/features/workstate/ProjectWorkStatePanel.tsx index 41283edc..f72df5bb 100644 --- a/frontend/src/features/workstate/ProjectWorkStatePanel.tsx +++ b/frontend/src/features/workstate/ProjectWorkStatePanel.tsx @@ -159,6 +159,28 @@ function backgroundTaskSummary(tasks: BackgroundCompletion[]): string | null { return `${tasks.length} background task${tasks.length > 1 ? "s" : ""}`; } +function compactIntent(text: string | null): string | null { + const normalized = text?.replace(/\s+/g, " ").trim(); + if (!normalized) return null; + return normalized.length <= 44 ? normalized : `${normalized.slice(0, 41)}...`; +} + +function compactIndicator({ + tickets, + inboxDepth, + backgroundTasks, +}: { + tickets: AgentTicketState[]; + inboxDepth: number; + backgroundTasks: BackgroundCompletion[]; +}): string | null { + const queuedTickets = tickets.filter((ticket) => ticket.status === "queued").length; + if (queuedTickets > 0) return `+${queuedTickets}`; + if (inboxDepth > 0) return `${inboxDepth} inbox`; + if (backgroundTasks.length > 0) return `${backgroundTasks.length} bg`; + return null; +} + function requesterLabel(ticket: AgentTicketState): string { if (ticket.source.kind === "human") return "Human"; const id = shortTicket(ticket.source.agentId); @@ -592,16 +614,13 @@ function AgentRow({ const currentTurn = busy || tickets.some((ticket) => ticket.status === "inProgress"); const activeTicket = tickets.find((ticket) => ticket.status === "inProgress"); - const activeSummary = activeTicket - ? conversations.get(activeTicket.conversationId) - : undefined; const statusLabel = agentStatusLabel(live, busy); const taskSummary = backgroundTaskSummary(backgroundTasks); - const activityLine = + const activityLine = compactIntent( activeTicket?.taskPreview ?? - (busyState.state === "busy" ? `Ticket ${shortTicket(busyState.ticket)}` : null) ?? - (inboxDepth > 0 ? `${inboxDepth} queued` : null) ?? - taskSummary; + (busyState.state === "busy" ? `Ticket ${shortTicket(busyState.ticket)}` : null), + ); + const indicator = compactIndicator({ tickets, inboxDepth, backgroundTasks }); const hasActions = Boolean(agent.live); const hasDetails = hasActions || @@ -665,18 +684,26 @@ function AgentRow({ return (
  • -
    - - +
    + + {agent.name} {activityLine && ( - + {activityLine} )} - + + {indicator && ( + + {indicator} + + )}
    - {!detailsOpen && activeSummary && ( - - )} - {detailsOpen && (
    { expect(within(list).getByLabelText("9 more characters")).toBeTruthy(); }); + it("keeps long ticket intent out of the default agent row", async () => { + const longPreview = + "Goal: inspect the entire repository and produce a verbose implementation summary"; + const workState = new MockWorkStateGateway(); + workState._setProjectWorkState(PROJECT_ID, { + agents: [ + { + agentId: "agent-long", + name: "Git", + profileId: "codex", + busy: { + state: "busy", + ticket: "ticket-long-abcdef", + sinceMs: 789, + }, + tickets: [ + { + ticketId: "ticket-long-abcdef", + conversationId: "conversation-long", + position: 0, + status: "inProgress", + source: { kind: "human" }, + requesterLabel: "Anthony", + taskPreview: longPreview, + taskLen: longPreview.length, + }, + ], + }, + ], + }); + + renderPanel(workState); + + expect(await screen.findByText("Git")).toBeTruthy(); + expect(screen.queryByText(longPreview)).toBeNull(); + expect(screen.getByText("Goal: inspect the entire repository and p...")).toBeTruthy(); + await openAgentDetails("Git"); + const list = await screen.findByLabelText("Git tickets"); + expect(within(list).getByText(longPreview)).toBeTruthy(); + }); + it("renders two tickets in FIFO order", async () => { const workState = new MockWorkStateGateway(); workState._setProjectWorkState(PROJECT_ID, { @@ -291,7 +332,9 @@ describe("ProjectWorkStatePanel", () => { renderPanel(workState); - expect(await screen.findByText("6 background tasks (3 active, 3 failed)")).toBeTruthy(); + expect(await screen.findByText("Runner")).toBeTruthy(); + expect(screen.getByText("6 bg")).toBeTruthy(); + expect(screen.queryByText("6 background tasks (3 active, 3 failed)")).toBeNull(); expect(screen.queryByLabelText("Runner background tasks")).toBeNull(); const list = await openBackgroundTasks("Runner"); const cancelButtons = within(list).getAllByRole("button", { name: "Cancel" }); @@ -378,7 +421,9 @@ describe("ProjectWorkStatePanel", () => { renderPanel(workState); - expect(await screen.findByText("4 background tasks (1 active, 1 failed)")).toBeTruthy(); + expect(await screen.findByText("Reporter")).toBeTruthy(); + expect(screen.getByText("4 bg")).toBeTruthy(); + expect(screen.queryByText("4 background tasks (1 active, 1 failed)")).toBeNull(); expect(screen.queryByLabelText("Reporter background tasks")).toBeNull(); const list = await openBackgroundTasks("Reporter"); // Terminal tasks with a summary render it discreetly. @@ -604,6 +649,12 @@ describe("ProjectWorkStatePanel", () => { expect(await screen.findByText("Continue implementation")).toBeTruthy(); expect(screen.queryByLabelText("Summarizer tickets")).toBeNull(); + expect(screen.queryByText("Goal: Ship the Work panel summaries")).toBeNull(); + expect( + screen.queryByText("Previous turn established the adapter boundary."), + ).toBeNull(); + expect(screen.queryByRole("button", { name: "View" })).toBeNull(); + expect(screen.queryByRole("button", { name: "Copy" })).toBeNull(); await openAgentDetails("Summarizer"); const list = await screen.findByLabelText("Summarizer tickets"); expect(within(list).getAllByText("Summary")).toHaveLength(2);