Release v0.51.261 — Release IC (stage-r11) (#3616)
## 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:
1 parent
ba987040c7
commit
6703978c60
12 files changed
+863
-69
No files matched your search
@@ -43,6 +43,7 @@ from api.helpers import redact_session_data, _redact_text
|
||||
from api.compression_anchor import is_context_compression_marker, visible_messages_for_anchor
|
||||
from api.metering import meter
|
||||
from api.run_journal import RunJournalWriter
|
||||
from api.todo_state import emit_todo_state
|
||||
from api.turn_journal import append_turn_journal_event_for_stream
|
||||
from api.usage import prompt_cache_hit_percent
|
||||
from api.models import (
|
||||
@@ -4996,6 +4997,35 @@ def _run_agent_streaming(
|
||||
'duration': cb_kwargs.get('duration'),
|
||||
'is_error': bool(cb_kwargs.get('is_error', False)),
|
||||
})
|
||||
# Mirror the todo tool's in-memory state into a
|
||||
# dedicated SSE event so the Todos panel can update
|
||||
# in real-time without waiting for the turn to
|
||||
# settle. The helper guards on name=='todo', sends
|
||||
# the full snapshot (idempotent under SSE replay)
|
||||
# and swallows internal errors so emission never
|
||||
# breaks tool delivery. Prefer the structured
|
||||
# `result` kwarg from modern Hermes builds; fall
|
||||
# back to the truncated `preview` only when the
|
||||
# callback was invoked without one (older builds).
|
||||
#
|
||||
# Graceful degradation on old builds: `preview` is a
|
||||
# truncated snippet, so its JSON is usually unparseable.
|
||||
# parse_todo_tool_result() then returns None and NO
|
||||
# todo_state event is emitted — live panel updates are
|
||||
# silently unavailable on pre-`result` builds. This is
|
||||
# intended: the panel still hydrates via cold-load on the
|
||||
# next session GET; it just won't update mid-stream.
|
||||
emit_todo_state(
|
||||
put,
|
||||
name=name,
|
||||
function_result=(
|
||||
cb_kwargs.get('result')
|
||||
if cb_kwargs.get('result') is not None
|
||||
else preview
|
||||
),
|
||||
session_id=session_id,
|
||||
stream_id=stream_id,
|
||||
)
|
||||
_tool_stats = meter().get_stats()
|
||||
_tool_stats['session_id'] = session_id
|
||||
_tool_stats['usage'] = _live_usage_snapshot()
|
||||
@@ -5064,6 +5094,20 @@ def _run_agent_streaming(
|
||||
'tid': tool_call_id,
|
||||
'is_error': False,
|
||||
})
|
||||
# Mirror the todo tool's in-memory state into
|
||||
# a dedicated SSE event so the Todos panel can
|
||||
# update in real-time without waiting for the
|
||||
# turn to settle. See the legacy path above
|
||||
# for the contract; the helper handles the
|
||||
# name guard, payload shape, and swallow-all
|
||||
# error policy.
|
||||
emit_todo_state(
|
||||
put,
|
||||
name=name,
|
||||
function_result=function_result,
|
||||
session_id=session_id,
|
||||
stream_id=stream_id,
|
||||
)
|
||||
_tool_stats = meter().get_stats()
|
||||
_tool_stats['session_id'] = session_id
|
||||
_tool_stats['usage'] = _live_usage_snapshot()
|
||||
|
||||
Reference in new issue
Block a user