Skip to content

fix(agent): persist canonical todo state across tab switches and restarts#4159

Closed
JesonChou wants to merge 1 commit into
esengine:main-v2from
JesonChou:fix/canonical-todo-persist
Closed

fix(agent): persist canonical todo state across tab switches and restarts#4159
JesonChou wants to merge 1 commit into
esengine:main-v2from
JesonChou:fix/canonical-todo-persist

Conversation

@JesonChou

Copy link
Copy Markdown
Contributor

Builds on #4132 · Closes #4105

Description

Relationship to #4132

#4132 fixed the host-advance ID collision (static "host-advance" → unique host-advance-{seq}-{idx}), ensuring multiple complete_step calls within a single turn correctly update the TodoPanel. This PR addresses the remaining half of #4105: the panel still reverted after tab switch or restart because the synthetic events were never persisted to the session file.

Problem

Host-advance synthetic todo_write events (emitTodoState) update the frontend TodoPanel in real time but are emitted to the event sink, not written as provider.Message to the session file. When the session is reloaded (restart, tab switch, reconnect) the frontend rebuilds its transcript from the session file and only sees the last explicit model todo_write, missing every intermediate host-advance.

Reproduction (after #4132):

1. Model todo_write: [A:in_progress, B:pending, C:pending]
2. complete_step A → panel shows 1/3 ✓
3. complete_step B → panel shows 2/3 ✓
4. Restart or switch tabs and back → panel reverts to 1/3 ✗

Fix

Two complementary mechanisms:

  1. HistoryWithCanonicalTodos — appends a synthetic assistant message carrying the canonical todo state at the end of the history response. Called from HistoryForTab (desktop) and GET /history (HTTP).

  2. EmitCanonicalTodoState — emits the canonical state as a live event through the sink, so the frontend receives it even when tab state is served from the in-memory cache without a full history reload.

Preserved (unchanged)

Files changed

File Lines Change
internal/agent/agent.go +23 Add CanonicalTodoState getter and EmitCanonicalTodoState method
internal/control/controller.go +17 Add HistoryWithCanonicalTodos and EmitCanonicalTodoState
desktop/app.go +3 / −1 Call emit + inject in HistoryForTab
internal/serve/serve.go +3 / −1 Call HistoryWithCanonicalTodos in GET /history

@github-actions github-actions Bot added v2 Go rewrite (1.x) — main-v2 branch, active development desktop Wails desktop app (desktop/**) agent Core agent loop (internal/agent, internal/control) labels Jun 12, 2026
…arts

Builds on esengine#4132 (unique host-advance IDs) by fixing the remaining half of
esengine#4105: host-advance events were emitted in real time but never persisted, so
the TodoPanel reverted on tab switch or restart.

Add HistoryWithCanonicalTodos that injects the canonical task list into the
history response, and EmitCanonicalTodoState that pushes it via the live
stream, covering both history-load and cached-tab-switch paths.

Closes esengine#4105.

Regression:
  internal/agent         PASS
  internal/agent/testutil PASS
  internal/control       PASS (1 pre-existing MCP env failure)
  internal/serve         PASS (1 pre-existing HTML lang failure)
  internal/evidence      PASS
  Full ./...             PASS (9 pre-existing env failures unchanged)

Copy link
Copy Markdown
Collaborator

Thanks again for this contribution. I opened #4313 as an integration PR that carries forward this PR's core finding: restored/tab-switched history must not fall back to stale todo_write state after host-advanced todo progress.

#4313 combines that contribution with the related plan-seed, completed-panel, and restored-history work from #4230, #4271, and #4309, plus the additional success/error replay guards found during review. To keep review focused, I’m closing this PR as superseded by #4313. You are credited in the integration commit and PR body.

@SivanCola SivanCola closed this Jun 13, 2026
esengine pushed a commit that referenced this pull request Jun 14, 2026
…#4313)

Seed the agent's canonical todo state from approved plans so later complete_step calls advance the visible panel, and rebuild restored desktop history by replaying todo_write/complete_step only on explicitly successful tool results (missing or errored results no longer count as completed). Hide the panel once all todos are done, keyed to stable content rather than array identity. Integrates #4159, #4230, #4271, and #4309.

Closes #4259
Closes #4105
Closes #4170
Closes #4241

Co-authored-by: JesonChou <51042251+JesonChou@users.noreply.github.com>
Co-authored-by: ashishexee <144021866+ashishexee@users.noreply.github.com>
Co-authored-by: GTC2080 <140309575+GTC2080@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Core agent loop (internal/agent, internal/control) desktop Wails desktop app (desktop/**) v2 Go rewrite (1.x) — main-v2 branch, active development

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: 代办任务更新不同步

2 participants