Repository navigation
fix(agent-pane): show the whole todo list, as Claude's check/spinner card #21623
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 17 commits
38e54ca
c15a5af
54c194f
0cf4c2e
8b66525
5ce1fbc
28e1a5c
7bf5729
cf0bdd5
2e1857a
7384349
e6ccef3
e22275d
4cdd92e
df45559
4bae129
e7c84b8
17925e0
39cad31
536a39c
938215d
2cd4b1a
29fb864
d28d8f8
ec3e2ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -287,7 +287,7 @@ function shapeTurn( | |
| return live | ||
| ? liveTurn(user, turn, clockOffset, liveRuns) | ||
| : last | ||
| ? turn | ||
| ? turn.map(endedPlan) | ||
| : settledWithoutSummary(user, turn, expanded); | ||
| const summary = turn[end]!; | ||
| const body = turn.slice(0, end); | ||
|
|
@@ -322,9 +322,9 @@ function shapeTurn( | |
| if (open) | ||
| shaped.push(...work.map((row) => ({ ...row, id: isEdit(row) ? `${row.id}${FOLDED}` : row.id, settled: true }))); | ||
| } | ||
| shaped.push(...groups, ...renderRows(body, version)); | ||
| shaped.push(...groups.map(endedPlan), ...renderRows(body, version)); | ||
| if (answer) shaped.push(answer); | ||
| shaped.push(...rest, ...editsCard(edits)); | ||
| shaped.push(...rest.map(endedPlan), ...editsCard(edits)); | ||
| const preview = turnPreviewUrl(user, turn); | ||
| if (preview) shaped.push({ id: `${PREVIEW}-${user.id}`, version, at: summary.at, kind: PREVIEW, text: preview }); | ||
| // The footer copies the answer, so it carries the answer's text; the last turn's also retries | ||
|
|
@@ -338,7 +338,8 @@ function shapeTurn( | |
| }); | ||
| // Anything after the summary (late tool updates, or a turn the agent started on its own) | ||
| // draws as it came. | ||
| shaped.push(...turn.slice(end + 1)); | ||
| // A turn the agent started on its own while still working keeps its plan live. | ||
| shaped.push(...turn.slice(end + 1).map(live ? (row) => row : endedPlan)); | ||
| return shaped; | ||
| } | ||
|
|
||
|
|
@@ -397,6 +398,11 @@ const staysOut = (row: AcpmuxRow) => | |
| // A session offer waits for the person's Start or Dismiss. | ||
| row.kind === "sessionOffer"; | ||
|
|
||
| /// A finished turn's todo list: a step the agent left in progress no longer spins. The version | ||
| /// moves off the live one (v to 2v + 1), so the memoized row draws again when the turn ends. | ||
| const endedPlan = (row: AcpmuxRow): AcpmuxRow => | ||
| row.kind === "plan" && row.plan ? { ...row, turnEnded: true, version: row.version * 2 + 1 } : row; | ||
|
Comment on lines
+412
to
+413
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Opening a long, finished chat can load a plan update and summary without their earlier prompt. |
||
|
|
||
| /// A turn that ended without a summary (history paged in from before acpmux kept one, or a | ||
| /// turn a restart cut off): its work folds under "N previous messages", like any | ||
| /// reloaded turn without timing, and its answer and edits draw after it. | ||
|
|
@@ -405,7 +411,7 @@ function settledWithoutSummary(user: AcpmuxRow, turn: AcpmuxRow[], expanded: Rea | |
| const final = answerAt(rows); | ||
| const before = final >= 0 ? rows.slice(0, final) : rows; | ||
| const work = before.filter((row) => !staysOut(row)); | ||
| if (work.length === 0) return rows; | ||
| if (work.length === 0) return rows.map(endedPlan); | ||
| const id = `${WORKED}-${user.id}`; | ||
| const open = expanded.has(id); | ||
| const edits = work.filter(isEdit); | ||
|
|
@@ -414,8 +420,8 @@ function settledWithoutSummary(user: AcpmuxRow, turn: AcpmuxRow[], expanded: Rea | |
| return [ | ||
| { id, version: version * 2 + (open ? 1 : 0), at: user.at, kind: WORKED, previous }, | ||
| ...(open ? work.map((row) => ({ ...row, id: isEdit(row) ? `${row.id}${FOLDED}` : row.id, settled: true })) : []), | ||
| ...before.filter(staysOut), | ||
| ...(final >= 0 ? rows.slice(final) : []), | ||
| ...before.filter(staysOut).map(endedPlan), | ||
| ...(final >= 0 ? rows.slice(final).map(endedPlan) : []), | ||
| ...editsCard(edits), | ||
| ]; | ||
| } | ||
|
|
||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the agent starts another turn on its own,
direct.tskeepsplanRowacrossturn_resultandturn_started. The next plan update reuses the row before the previous summary.groups.map(endedPlan)then setsturnEndedeven while the agent is working, so the active step shows a still ring instead of spinning.Start a new plan row at that turn boundary, and cover this sequence with an event-based test.