From e5b77b9b15d01b61245a6418a7ab17b0da213464 Mon Sep 17 00:00:00 2001 From: Taylor Ho Date: Mon, 27 Jul 2026 23:04:07 -0700 Subject: [PATCH] fix(composer): past-tense plan and thought headlines in the activity pill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Normalize plan items in getActivityHeadline (agentSessionTranscriptPresentation.ts): the fallthrough previously returned the raw item title, so ACP plan updates headlined the pill as a bare "Plan" / "Plan updated" next to the past-tense tool verbs ("Read foo.ts", "Ran …") — now "Created plan" for the initial plan and "Updated plan" for update markers (keyed off isUpdate) - Normalize thought items the same way: "Thinking" → "Thought", and the plan-titled thought that rendered "Planning" → "Planned" - Assistant-message headlines (first line of the streamed reply) are deliberately untouched — they are content, not action labels - Add test coverage for all four normalized cases Co-authored-by: Taylor Ho Signed-off-by: Taylor Ho --- ...gentSessionTranscriptPresentation.test.mjs | 51 +++++++++++++++++++ .../ui/agentSessionTranscriptPresentation.ts | 14 ++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/desktop/src/features/agents/ui/agentSessionTranscriptPresentation.test.mjs b/desktop/src/features/agents/ui/agentSessionTranscriptPresentation.test.mjs index 4b6a33314..9ccf93bf9 100644 --- a/desktop/src/features/agents/ui/agentSessionTranscriptPresentation.test.mjs +++ b/desktop/src/features/agents/ui/agentSessionTranscriptPresentation.test.mjs @@ -94,6 +94,57 @@ test("getActivityHeadline basenames path-like tool objects", () => { ); }); +test("getActivityHeadline renders plan and thought items in past tense", () => { + // Bare "Plan" / "Thinking" titles must not headline next to the past-tense + // tool verbs ("Read foo.ts", "Ran …"). + assert.equal( + getActivityHeadline({ + id: "plan:1", + type: "plan", + renderClass: "plan", + title: "Plan", + text: "1. Do the thing", + timestamp: baseTimestamp, + }), + "Created plan", + ); + assert.equal( + getActivityHeadline({ + id: "plan:1:update:x", + type: "plan", + renderClass: "plan", + title: "Plan updated", + text: "Now doing step 2", + timestamp: baseTimestamp, + isUpdate: true, + targetId: "plan:1", + }), + "Updated plan", + ); + assert.equal( + getActivityHeadline({ + id: "thought:1", + type: "thought", + renderClass: "thought", + title: "Thinking", + text: "hmm", + timestamp: baseTimestamp, + }), + "Thought", + ); + assert.equal( + getActivityHeadline({ + id: "thought:2", + type: "thought", + renderClass: "thought", + title: "Plan", + text: "plan-shaped thought", + timestamp: baseTimestamp, + }), + "Planned", + ); +}); + test("getActivityHeadline keeps shell commands whole (no basenaming)", () => { assert.equal( getActivityHeadline( diff --git a/desktop/src/features/agents/ui/agentSessionTranscriptPresentation.ts b/desktop/src/features/agents/ui/agentSessionTranscriptPresentation.ts index a9541c030..d07449da3 100644 --- a/desktop/src/features/agents/ui/agentSessionTranscriptPresentation.ts +++ b/desktop/src/features/agents/ui/agentSessionTranscriptPresentation.ts @@ -64,6 +64,11 @@ function terseActionObject(summary: CompactToolSummary): string | null { * reduced to their basename), e.g. "Read foo.ts" rather than * "Read file · src/agents/ui/foo.ts" — so the composer pill's 200px cap * shows the informative part instead of ellipsizing a long preview. + * + * Action headlines are past-tense verb phrases throughout ("Read foo.ts", + * "Thought", "Updated plan") — plan and thought items are normalized here + * so no bare noun ("Plan") or present participle ("Thinking") leaks into + * the pill next to the past-tense tool verbs. */ export function getActivityHeadline(item: TranscriptItem): string | null { if (item.type === "tool") { @@ -93,7 +98,14 @@ export function getActivityHeadline(item: TranscriptItem): string | null { } if (item.type === "thought") { - return item.title === "Plan" ? "Planning" : item.title; + if (item.title === "Plan") { + return "Planned"; + } + return item.title === "Thinking" ? "Thought" : item.title; + } + + if (item.type === "plan") { + return item.isUpdate ? "Updated plan" : "Created plan"; } if (item.type === "metadata") {