fix(todos): stream live state updates with inflight recovery#3454
Conversation
236e527 to
888db2b
Compare
|
Reading the full diff at One thing I'd flag before merge — a hot-path perf regression in the redaction helper. Code reference
def _redact_snapshot(snapshot: dict) -> dict:
from typing import cast
from api.helpers import _redact_value
return cast(dict, _redact_value(snapshot))
def _redact_text(text, *, _enabled=None):
if _enabled is None:
from api.config import load_settings
_enabled = bool(load_settings().get("api_redact_enabled", True))So every string in the snapshot triggers its own Why it matters here
RecommendationThread the setting once, mirroring def _redact_snapshot(snapshot: dict) -> dict:
from typing import cast
from api.helpers import _redact_value
from api.config import load_settings
_enabled = bool(load_settings().get("api_redact_enabled", True))
return cast(dict, _redact_value(snapshot, _enabled=_enabled))That's one read per emission instead of one per string, and it keeps the fail-closed behavior intact (a raising Test note
Everything else looks solid — CI is green across the 3.11/3.12/3.13 matrix and the cross-session |
888db2b to
6de7667
Compare
|
Re-read
from api.config import load_settings
from api.helpers import _redact_value
_enabled = bool(load_settings().get("api_redact_enabled", True))
return cast(dict, _redact_value(snapshot, _enabled=_enabled))That's one The new No further concerns from me on the redaction path. LGTM. |
Bug Description
Follow-up to the cold-load todo state work from #3373.
The Todos panel can now hydrate correctly after a page refresh, but it still does not consistently track the current
todotool state while an agent run is active.Before this PR:
todotool calls updated the agent-side TodoStore, but the side panel usually stayed stale until the run settled.Root Cause
The panel historically derived todo state by reverse-scanning settled
toolmessages inS.messages.That works after a completed turn, but not during a live run:
toolmessages appear inS.messages;tool_complete.previewis truncated and not a durable structured state contract;Fix
This PR adds an explicit todo-state contract across server, SSE, and frontend state:
todo_stateSSE event when thetodotool completes.tool_complete.preview.api.todo_stateparser / normalizer for live emission and cold-load state.S.todos+S.todoStateMetaas the Todos panel source of truth.coldTs === 0edge case for compressed sessions.session.todo_statesidecars when a freshmessages=1response does not include one.How to Verify
Manual verification path:
todotool multiple times.session.todo_state.Test Plan
Ran locally after rebasing onto
origin/master:Result:
Also ran:
Result:
Additional local hygiene checks:
No whitespace errors or conflict markers found.
Risk Assessment
Low / Medium.
The change is scoped to Todos panel state propagation and recovery. The new SSE event is additive, and the frontend keeps the legacy message-scan fallback for compatibility with older servers.
Risk is mainly in state reconciliation:
out-of-order SSE replay is guarded by timestamp checks;
cross-session events are filtered by session_id;
malformed or non-todo payloads are ignored;
live SSE snapshots are redacted before emission;
cold-load snapshots continue to pass through session response redaction.
The PR intentionally keeps the detector symmetric with the existing agent TodoStore hydration logic so the WebUI panel does not disagree with the agent-side state.