Release v0.51.261 — Release IC (stage-r11) (#3616)
Some checks failed
Release & Docker / release (push) Has been cancelled
Some checks failed
Release & Docker / release (push) Has been cancelled
## Release v0.51.261 — Release IC (stage-r11) Live Todos panel via an explicit `todo_state` SSE contract. ### Fixed | Issue/PR | Author | Fix | |----------|--------|-----| | #3373 follow-up (#3454) | @v2psv | The Todos side panel now tracks `todo` tool state **live during an active run** instead of staying stale until settle / rolling back on a mid-stream reload. A dedicated `todo_state` SSE event sends a full, redacted, idempotent snapshot on todo-tool completion (no more truncated `tool_complete.preview`); the same `api.todo_state` parser feeds live + cold-load; live snapshots persist into INFLIGHT so reload/reattach restores the panel; cold-load vs INFLIGHT reconciled by timestamp (incl. the `coldTs===0` compressed-session edge); legacy reverse-scan kept as fallback for old servers. | ### Gate - Full pytest suite: **7692 passed, 0 failed** - ESLint: CLEAN · ruff: CLEAN · browser-smoke: CLEAN - Codex (regression): **SAFE TO SHIP** — verified the new `todo_state` SSE handler composes with existing dispatch (no double-subscribe), INFLIGHT persistence is cleared on terminal/cancel (composes with discard_session + turn-journal), timestamp reconciliation can't let a stale local snapshot win, redaction holds, the legacy reverse-scan fallback still works with no double-render, and the `models.py` change is todo-scoped (no CLI-classification interaction). Co-authored-by: v2psv <v2psv@users.noreply.github.com>
This commit is contained in:
@@ -137,6 +137,14 @@ def _persisted_session_ids_snapshot() -> frozenset[str]:
|
||||
return ids
|
||||
|
||||
|
||||
def _session_dir_has_persisted_session_files() -> bool:
|
||||
"""Return True when the current session dir has at least one session JSON file."""
|
||||
try:
|
||||
return any(not p.name.startswith('_') for p in SESSION_DIR.glob('*.json'))
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def _rebuild_session_index_background() -> None:
|
||||
try:
|
||||
_write_session_index(updates=None)
|
||||
@@ -2825,6 +2833,8 @@ def all_sessions(diag=None):
|
||||
with LOCK:
|
||||
in_memory_ids = set(SESSIONS.keys())
|
||||
persisted_ids = _persisted_session_ids_snapshot()
|
||||
if not index and _session_dir_has_persisted_session_files():
|
||||
raise ValueError("empty session index while session files exist")
|
||||
index = [
|
||||
s for s in index
|
||||
if (
|
||||
@@ -2839,6 +2849,8 @@ def all_sessions(diag=None):
|
||||
)
|
||||
)
|
||||
]
|
||||
if not index and _session_dir_has_persisted_session_files():
|
||||
raise ValueError("session index has no live rows while session files exist")
|
||||
backfilled = []
|
||||
for i, s in enumerate(index):
|
||||
if 'last_message_at' not in s:
|
||||
|
||||
Reference in New Issue
Block a user