fix: live reasoning, tool progress, in-flight session recovery (#367)

* fix: preserve live session output across chat switches

(cherry picked from commit 401e3b643d25e8dad8c06883b478b3c3073f07a5)

* fix: preserve todo state after session reload

(cherry picked from commit 7ee093ba19978af23b79148df2f2347e2f1e5bde)

* fix: preserve live assistant anchor across rerenders

* fix: stream live reasoning and tool progress

* fix: recover inflight session state after reload

* fix: add loadInflightState stub + CHANGELOG v0.50.21

- static/ui.js: add loadInflightState() function (currently returns null —
  the typeof guard in sessions.js means reload recovery works via the
  else-path attachLiveStream call; this stub satisfies the guard cleanly
  and documents the extension point for future localStorage-backed state)
- CHANGELOG.md: v0.50.21 entry; 960 tests (up from 949)

---------

Co-authored-by: Jordan SkyLF <jordan@skylinkfiber.net>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
This commit is contained in:
nesquena-hermes
2026-04-13 16:18:15 -07:00
committed by GitHub
parent bcdd7ed3f3
commit 9542639a90
9 changed files with 609 additions and 73 deletions

View File

@@ -365,6 +365,10 @@ def handle_get(handler, parsed) -> bool:
raw = s.compact() | {
"messages": s.messages,
"tool_calls": getattr(s, "tool_calls", []),
"active_stream_id": getattr(s, "active_stream_id", None),
"pending_user_message": getattr(s, "pending_user_message", None),
"pending_attachments": getattr(s, "pending_attachments", []),
"pending_started_at": getattr(s, "pending_started_at", None),
}
return j(handler, {"session": redact_session_data(raw)})
except KeyError:
@@ -1683,11 +1687,15 @@ def _handle_chat_start(handler, body):
attachments = [str(a) for a in (body.get("attachments") or [])][:20]
workspace = str(Path(body.get("workspace") or s.workspace).expanduser().resolve())
model = body.get("model") or s.model
stream_id = uuid.uuid4().hex
s.workspace = workspace
s.model = model
s.active_stream_id = stream_id
s.pending_user_message = msg
s.pending_attachments = attachments
s.pending_started_at = time.time()
s.save()
set_last_workspace(workspace)
stream_id = uuid.uuid4().hex
q = queue.Queue()
with STREAMS_LOCK:
STREAMS[stream_id] = q