github →

New request

#2361: Define WebUI run state consistency across transcript, context, streams, and replay

We'll provision a sandbox, run an agent against the issue, and open a draft PR. You can pull the branch and iterate from there.

Issue
enhancementstreamingtracking

Problem

Recent WebUI streaming/recovery bugs are not isolated rendering mistakes. They repeatedly happen at the boundaries between several copies of the same running agent turn:

  • the visible transcript the user can see,
  • the model context / context_messages the agent actually receives,
  • pending_user_message and active stream metadata,
  • live SSE events and in-memory stream state,
  • durable run journal / replay state,
  • automatic compression summaries and active-task handoff text,
  • the browser's live timeline DOM/cache,
  • sidebar ordering, unread state, and updated_at metadata.

When those layers diverge, the user sees failures that feel unrelated: a visible prompt is not sent back to the model after recovery, a live run loses or reorders its tool/thinking timeline after session switches, a cleanup pass resurfaces old sessions, auto-compression reference cards leak into the active turn, or a stale compressed task resumes when the user intended a fresh chat.

This issue tracks a consistency contract for those layers. The goal is to stop treating each new symptom as a one-off patch and instead define the invariants every future streaming, recovery, replay, compression, and sidebar PR must preserve.

Why this is not just an umbrella bug

This is not a bucket for every WebUI issue. It should produce a reviewable contract that answers concrete product and implementation questions:

  • Which state layer is the source of truth for a running turn?
  • When is it acceptable for the visible transcript and model context to differ?
  • What must survive refresh, session switch, WebUI restart, and stale-stream cleanup?
  • What is replay allowed to reconstruct, and what must remain a live-only presentation cache?
  • How should automatic compression be represented so it helps the agent without visually polluting the user's active turn?
  • What does a future PR need to prove before it changes streaming, recovery, context reconstruction, compression, or sidebar timestamps?

The expected output is a short RFC/checklist that reviewers and future PR authors can follow.

Relationship to #1925

#1925 defines the larger direction: WebUI should become a thin observability/control client over a clearer Hermes Agent runtime boundary.

This issue is narrower and more immediate. It documents the state consistency rules that must hold both before and after that runtime boundary exists. In other words:

  • #1925 is about where execution ownership should move.
  • This issue is about keeping transcript, context, stream, replay, compression, and UI state coherent while WebUI still has multiple overlapping state layers.

Initial issue map

These examples show the repeated boundary pattern:

ExampleState boundary exposed
#2341 / #2342Active reattach could show agent activity without the pending user turn that started it.
#2344 / #2347Session switching could lose or reorder the live thinking/tool/interim timeline.
#2345 / #2349Stale stream cleanup could mutate session timestamps and make old sessions look active.
#2346 / #2348Thinking cards could mirror user-visible interim progress text and duplicate content.
#2353 / #2354Recovered pending user turns could be visible but missing from model context.
#2355 / #2357Auto-compression rotation could leave reference-only compression cards in the active conversation tail.
#2308 / #2309Compressed sessions could resume stale agent tasks when the user starts an ordinary fresh chat.
#2283Run event journal replay is a foundation, but replay also needs explicit consistency rules.

Some of these are already fixed, closed, or being handled in separate PRs. They are referenced here as evidence for the contract, not as sub-tasks to reopen.

Proposed contract areas

The RFC should define at least these invariants:

  1. A visible current user turn must be represented in the model context unless WebUI deliberately excludes it and tells the user why.
  2. Active turn UI must preserve the user action that started the work before assistant text, thinking cards, tool cards, or activity groups.
  3. Refresh, reconnect, and session switch must preserve chronological live-scene order or explicitly downgrade to a structured replay state.
  4. Runtime maintenance such as stale-stream cleanup must not imply new user activity or refresh sidebar ordering.
  5. Replay must be cursor-safe and idempotent: it should not duplicate assistant text, thinking text, tool cards, or compression cards.
  6. Compression summaries are agent-facing recovery handoffs, not automatically user-facing active-turn content and not implicit current user intent.
  7. Long-running observation should have a degraded/heartbeat path so one or many active sessions do not make the UI appear silent or block ordinary APIs.
  8. Every PR touching streaming/recovery/context/compression/sidebar state should name the state layer it changes and the regression that proves the invariant still holds.

Non-goals

  • This issue does not implement a runner process or sidecar.
  • This issue does not replace #1925.
  • This issue should not reopen already-fixed narrow bugs.
  • This issue should not rewrite the streaming protocol by itself.
  • This issue should not become a catch-all for unrelated UI polish.

Expected first artifact

Open a draft documentation PR adding an RFC such as:

docs/rfcs/webui-run-state-consistency-contract.md

That PR should cross-reference this issue and #1925, define the state layers/invariants, and provide a review checklist for future implementation PRs.

Assessmentadvisory
feature●●● hard85% confidence

Architectural enhancement to formalize and enforce consistency invariants across streaming, recovery, replay, and compression subsystems.

Likely files
  • api/models/runs.py
  • api/services/streaming.py
  • api/services/replay.py
  • api/services/compression.py
  • static/js/chat/timeline.js
  • static/js/services/sse.js
  • api/routes/sessions.py
  • docs/architecture/state-contract.md
Create the request

This opens a fresh agent run and a draft PR for issue #2361.

Cancel