feat(web): a coding agent is titled from its first exchange as a turn ends, not from the plan as it starts
What
A coding agent's title now comes from its conversation, the way ChatGPT, Claude, and Cursor name a chat. Before, it came from the plan when the session started.
- When: at each
turn.completed(apps/web/coder/hooks/store.ts). The call is forked after the relay has written the turn's answer. The start-time title path is deleted. - From what: the developer's first message, their latest message when it is a different one (so a retry after a greeting sees the task that followed), and the agent's latest reply. Only text parts are used, each cut to 2,000 characters. The same Haiku call as before (low effort, 20 s timeout, 64 output tokens). The plan name is no longer in the prompt. A Start-button agent's first message already is the plan, so it needs no special case.
- Too thin to name: the instructions tell the model to answer with nothing when no task is named yet (a greeting, or an image with no words). An empty, failed, or timed-out answer writes nothing, so the next turn's end tries again. This runs for the agent's first 3 turns (
CODER.TITLE_TURNS). After that the tab keeps the model-name fallback. - Set once: the title is written through
fillCodingAgentTitle, which writes only when no title exists. A title that already exists, including one the developer set by renaming, is never regenerated. - Subagent titles (
titleSubagent) are unchanged.
No new tables, flags, states, or jobs.
One supporting change: the title hold now covers the agent's own title
The desktop stops reading an ended agent at its last empty page. A title that lands a second after turn 1 ends would therefore never reach the open tab. The existing titleMayLand hold, which already waits for a worker's late title, now also waits while the agent is untitled, its newest turn is one of its first 3, and that turn completed within TITLE_TIMEOUT. The messages endpoint re-reads the agent's title after the hold, as the worker endpoint already does.
Tests
All on the scripted title model. Each fails without the change.
- An agent started on a task is titled from its exchange, with no plan name in the prompt. A later turn makes no call, and a rename is never overwritten.
- A plan-started agent is titled from the plan it said first.
- A greeting first exchange is retried on turn 2, and the retry prompt carries the follow-up task. An image-only first message (#2116) is retried on turn 2. An agent that is still untitled after its third turn gets no more calls.
- A failed call leaves the agent untitled.
- Route: an ended, untitled agent's read waits for its own title and answers with it when it lands. Past the title call's bound, or after the agent's third turn, it answers at once with no title.
The worker-title route fixture now gives its agent a title, so those tests still exercise the worker title alone. #2119's sandbox-admission test keeps its admission checks; its title assertion is dropped, since titling no longer happens at session start.
Verification
./scripts/check.shpasses.- CI could not verify the Mac UI, and
./scripts/verify.shwas not run (this is a Linux cloud VM; LUKE-159 is the manual Mac pass). The change is server-side. The desktop is untouched and already shows the model name until a title arrives.
š¤ Generated with Claude Code