This RFC defines the product model for assistant replies in long-running agent sessions.
Short conversations are still useful sanity checks, but they do not exercise the hardest browser-agent states. A long-running session can:
The design should therefore be judged against the long-running case first. A short conversation should be the same lifecycle with fewer events, not a separate UI model.
The goal is not to add a Worklog widget, and it is not to make Auto Compression or duplicate stream ownership the headline. Those are supporting slices and edge cases. The headline is one coherent assistant reply lifecycle: live work, supporting activity, terminal outcome, and final answer.
Ares WebUI currently uses one chat surface to represent several different meanings:
Those meanings have repeatedly competed for the same visual space. Some long-running sessions feel noisy, some look silent while the agent is working, some recover into a different shape after reconnect, and some terminal edge cases can appear completed even when no final answer was produced.
This RFC defines the product semantics that implementation PRs and follow-up RFCs should preserve.
This inventory groups representative public issues and PRs by the long-running-session concern they expose. It is not a claim that every linked item is solved by this RFC. The classification column records durable scope, not current open/merged/superseded state: for live status, the tracking issue #3400 is authoritative.
| Concern | Representative signals | Current classification |
|---|---|---|
| Live work vs final answer boundary | #536, #3400, #3464 | Main product scope. #3464 landed the first RFC; this document is the parent contract for follow-up slices. |
| First live-to-final reply implementation | #3401, #3014, #3015 | First implementation slice. It should keep using Refs #3400; it does not close the umbrella. |
| Auto Compression visibility and context pressure | #469, #2973, #3079, #3315, #3316 | Supporting edge case. Running compression is live lifecycle status; compression-exhausted/no-final finalization is a terminal-state follow-up. |
| Replay, reconnect, session switch, and reattach | #2283, #2924, #3391 | Supporting recovery infrastructure. The product requirement is same lifecycle after replay, or an explicit degraded/restoring state. |
| Tool, activity, thinking, and visible progress | #1298, #3014, #3015 | Main reply-rendering concern. Process prose stays primary; tool/reasoning/debug detail stays supporting. |
| No-final and terminal failure outcomes | #3315, #3316 | Confirmed follow-up / active PR scope. A tool-tail or compression-exhausted run must not settle as normal completion without a real final answer. |
| Cancellation and stream ownership | #3344, #3345, #3475, #3476 | Supporting cancel/recovery scope. Early-cancel worker reconciliation is addressed by #3476; frontend cancel owner-guard hardening is the remaining follow-up. |
| Produced artifacts and output handoff | #2655, #2673, #2881, #2938, #3329, #3348, #3528 | Supporting session-output concern. Existing Artifacts and workspace:// surfaces make produced files findable; long-running replay/cancel/terminal paths must not lose the tool metadata needed to recover that handoff. |
| Sidebar/session ownership and active-session awareness | #856, #1370, #1436 | Confirmed follow-up scope when sidebar/session metadata contradicts the visible active turn. |
| User intervention during live work | #720, #965, #1062, #3058, #3061 | Child RFC scope. This parent RFC only requires that controls preserve ownership, replay, and terminal honesty. |
The lifecycle below is a product-state model, not a backend schema or
wire-event contract. At settle time, the visible reply state should be derived
from durable transcript truth, available terminal evidence, and reply
ownership. A turn should not be marked completed only because live activity
or partial assistant prose existed earlier.
%%{init: {"theme": "neutral"}}%%
flowchart TD
A([User sends message]) --> B["Turn created<br/>reply ownership established"]
B --> C["Live phase<br/>process prose + quiet tool activity"]
C --> D{Lifecycle event}
D -- stream continues --> C
D -- reload / reconnect / session switch --> E["Recovery and replay<br/>rebuild the same lifecycle from durable state"]
E --> F{Same turn recovered?}
F -- yes --> C
F -- not yet --> G["Restoring or degraded state<br/>do not mark completed from missing live data"]
G --> D
D -- user cancels --> H["Cancel requested<br/>settle only the owned reply"]
H --> I["Settle decision<br/>durable transcript truth + terminal evidence + reply ownership"]
D -- run ended / terminal evidence --> I
I --> J{Event belongs to<br/>the current visible reply?}
J -- no --> K["Ignore stale event<br/>do not mutate the current visible reply"]
J -- yes --> L{Final assistant answer present<br/>and terminal evidence is normal?}
L -- yes --> M["completed<br/>activity summary above final answer"]
L -- no --> N{Specific terminal outcome}
N -- cancelled --> O["cancelled<br/>user stopped the turn"]
N -- interrupted --> P["interrupted<br/>continuity lost before final answer"]
N -- compression_exhausted --> Q["compression_exhausted<br/>compression could not continue safely"]
N -- tool_limit_reached --> R["tool_limit_reached<br/>tool / retry / iteration ceiling hit"]
N -- no_response --> S["no_response<br/>no usable assistant final content"]
N -- other failure --> T["error<br/>fallback for other terminal failures"]
M --> U["Settled reply visible<br/>supporting activity collapsed;<br/>artifacts and workspace outputs findable"]
O --> U
P --> U
Q --> U
R --> U
S --> U
T --> U
One visible assistant reply belongs to one user turn and one active run/stream identity while that run is active.
Requirements:
While a turn is running, the assistant reply should read as a live process narrative.
Requirements:
When the turn settles, implementation detail should collapse without swallowing the final answer.
Requirements:
Refresh, reconnect, session switching, and replay should preserve the same reply model.
Requirements:
Every turn needs a terminal outcome. A turn without a final answer must not look like a normal completed answer.
Required product states:
| State | Meaning |
|---|---|
completed |
The assistant produced a final answer and the turn settled normally. |
cancelled |
The user stopped the turn. |
interrupted |
Browser, stream, worker, runtime, or network continuity was lost before a final answer was produced. |
compression_exhausted |
Context compression could not create enough room to continue safely. |
tool_limit_reached |
The run hit a tool-call, retry, or iteration ceiling before a final answer was produced. |
no_response |
The provider or runtime returned no usable assistant final content. |
error |
Fallback for failures that do not fit the above states. |
These identifiers name product states, not a wire/enum or persisted schema contract; consistent with Scope, this RFC does not mandate a backend field or event shape for them. Copy can evolve, but these semantic distinctions should stay stable in live rendering, settled rendering, and replay.
When more than one terminal condition applies, the more specific condition
should win over the generic fallback. For example, cancelled,
compression_exhausted, tool_limit_reached, and no_response should not be
flattened into a plain error only because the turn also failed to produce a
final answer.
Auto Compression is a context lifecycle transition, not a tool call and not final answer content.
Expected behavior:
Context auto-compressed.compression_exhausted
or another specific terminal outcome instead of normal completion.Confirmed follow-up scope:
Long-running sessions can exhaust tool-call limits, retry budgets, or iteration ceilings before a final answer is available.
Expected behavior:
Tool-heavy turns can end with tool output, provider failure, or no usable final assistant message.
Expected behavior:
no_response, interrupted,
compression_exhausted, tool_limit_reached, or error.Cancel is a user-visible terminal action, not just browser cleanup.
Expected behavior:
cancelled, not as provider no_response.interrupted or restoring,
not as normal completion.Classification:
Long-running work often outlives one browser attachment.
Expected behavior:
Confirmed follow-up scope:
Last-Event-ID or equivalent reconnect cursor support when it is
ready to replace or complement the current replay cursor path.Some valid long-running turns may produce little or no visible process prose before the final answer, especially when the model runs a dense sequence of tools.
Expected behavior:
Long-running sessions can end with a final answer that is itself lengthy.
Expected behavior:
Long-running sessions often create or update files in the workspace, such as plans, reports, patches, data files, generated markdown, or other artifacts. Those artifacts are part of what the user needs from the completed work, even when they are not the final answer text itself.
Expected behavior:
workspace:// links, remain supporting navigation surfaces rather than
replacing the final answer.Confirmed follow-up scope:
workspace:// preview
path from #2881 and
#2938.Long-running sessions are not only a chat-pane concern. The sidebar and session metadata help users find active work and later terminal outcomes.
Expected behavior:
During long-running work, the user may queue follow-up input, steer the current direction, or stop the run and send a replacement.
Expected behavior:
The current child contract is tracked by #3058 and #3061. That child RFC should own questions such as:
Use this map to keep implementation PRs and child RFCs scoped. The “vehicle” column names a durable track, not live merge state; the tracking issue #3400 is authoritative for current open/merged/superseded status.
| Track | Scope | Current vehicle |
|---|---|---|
| Parent product RFC | Define the long-running live-to-final assistant reply lifecycle and review checklist. | This RFC; tracking issue #3400. |
| First reply lifecycle implementation | Live process prose, quiet tool activity, settled activity summary above final answer, replay/reattach consistency, live-only compression status, supporting stream ownership fixes. | #3401. |
| Terminal/no-final stabilization | Compression exhausted, tool-tail/no-final transcript shape, context-compaction marker suppression, terminal error routing. | #3315, #3316. |
| Cancel ownership hardening | Frontend cancel should close its own SSE source and clear only its own busy state. | #3344, #3345. |
| Early-cancel startup race | Backend cancel should still interrupt the worker when the SSE registry detached before startup fully settled. | #3475, #3476. |
| Pending-intent control surface | Queue, Steer, Stop-and-send, Interrupt, delivered/applied/leftover semantics. | #3058, #3061. |
| Reattach and replay polish | Slow rebuild degraded state, replay/body timing, native cursor support, same lifecycle through replay. | Follow-up issue/PR or child RFC if protocol semantics expand. |
| Tool-limit and max-iteration terminal state | Limit reached state, control prompt visibility, no fake final answer. | Follow-up issue/PR; may involve Ares Agent if the runtime owns the limit signal. |
| Artifact handoff and recoverability | Preserve the link between final/terminal replies and workspace artifacts created or edited during the turn. | Existing Artifacts and workspace:// surfaces; follow-up issue/PR when replay, cancel, or terminal paths lose artifact metadata. |
| Sidebar/session ownership | Active/terminal state in session rows, stale spinner repair, session-list disappearance, background terminal feedback. | Follow-up issue/PR under session/runtime contracts. |
| Very long final answer ergonomics | Optional navigation/outline/preview affordances that preserve the final answer as normal prose. | Open product discussion; no implementation vehicle yet. |
This RFC sits above the current runtime, recovery, and adapter contracts:
webui-run-state-consistency-contract.md
defines how transcript, context, stream, replay, compression, and session
metadata stay coherent.canonical-session-resolution.md defines
how URL, local browser state, sidebar rows, and compression lineage resolve
to one visible session target.turn-journal.md defines crash-safe submitted-turn and
interrupted-turn recovery semantics.ares-run-adapter-contract.md defines
longer-term event/control ownership and migration gates.This RFC defines the product meaning those lower-level contracts need to preserve for long-running assistant replies.
The pending-intent control-surface RFC tracked by #3058 and #3061 should be treated as a child contract: it can define user intervention semantics without redefining the live-to-final reply lifecycle.
Use this checklist when reviewing PRs against this RFC:
Open questions are limited to product choices that are not already decided by this RFC, an active implementation PR, or a child RFC.
workspace:// links?