* Refine live-to-final long-running session RFC * Mark RFC accepted, decouple from live PR status, normalize terminal state names Three follow-up adjustments to the refined live-to-final RFC: - Status: Proposed -> Accepted, since the doc is now referenced as the parent contract for follow-up slices; live implementation status stays in #3400. - Keep volatile PR/merge state out of the RFC body. The Public Inventory and Delivery map now state that their classification/vehicle columns record durable scope, and that #3400 is authoritative for open/merged/superseded status. Dropped the point-in-time "has shipped through release" / "remains an active PR" assertions that would drift as PRs land. - Normalize terminal-state naming: use the backticked snake_case identifiers (`cancelled`, `compression_exhausted`, `tool_limit_reached`, `no_response`, `interrupted`, `error`) consistently in prose, and add a note that these name product states, not a wire/enum or persisted schema contract (consistent with Scope, which does not own a backend schema change). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add artifact handoff scope to live-to-final RFC * Add live-to-final lifecycle flowchart to RFC --------- Co-authored-by: Frank Song <franksong2702@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,82 +1,173 @@
|
|||||||
# Live-to-Final Assistant Replies for Long-Running Agent Sessions
|
# Live-to-Final Assistant Replies for Long-Running Agent Sessions
|
||||||
|
|
||||||
- **Status:** Proposed
|
- **Status:** Accepted (parent contract; implementation tracked in [#3400](https://github.com/nesquena/hermes-webui/issues/3400))
|
||||||
- **Author:** @franksong2702
|
- **Author:** @franksong2702
|
||||||
- **Created:** 2026-06-03
|
- **Created:** 2026-06-03
|
||||||
- **Tracking issue:** [#3400](https://github.com/nesquena/hermes-webui/issues/3400)
|
- **Tracking issue:** [#3400](https://github.com/nesquena/hermes-webui/issues/3400)
|
||||||
|
|
||||||
## Background
|
## Background: Long-Running Sessions Are The Anchor
|
||||||
|
|
||||||
This RFC is anchored on long-running agent sessions.
|
This RFC defines the product model for assistant replies in long-running agent
|
||||||
|
sessions.
|
||||||
|
|
||||||
Short conversations are useful sanity checks, but they do not exercise the
|
Short conversations are still useful sanity checks, but they do not exercise
|
||||||
hardest browser-agent states. A long-running session can spend minutes waiting,
|
the hardest browser-agent states. A long-running session can:
|
||||||
make many tool calls, produce a long final answer, cross context-pressure
|
|
||||||
boundaries, hit tool-call or retry limits, lose network continuity, and still
|
|
||||||
need to recover into a readable final transcript.
|
|
||||||
|
|
||||||
The product model should therefore be defined against the long-running case. A
|
- keep the user waiting for minutes,
|
||||||
|
- make many tool calls,
|
||||||
|
- produce a long final answer,
|
||||||
|
- create or update workspace artifacts,
|
||||||
|
- cross Auto Compression boundaries,
|
||||||
|
- hit tool-call, retry, or iteration limits,
|
||||||
|
- lose browser, network, or SSE continuity,
|
||||||
|
- receive a user cancel or interruption request while startup is still racing,
|
||||||
|
- switch sessions or reload before the turn settles.
|
||||||
|
|
||||||
|
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
|
short conversation should be the same lifecycle with fewer events, not a
|
||||||
separate UI model.
|
separate UI model.
|
||||||
|
|
||||||
## Problem
|
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.
|
||||||
|
|
||||||
|
## Product Problem
|
||||||
|
|
||||||
Hermes WebUI currently uses one chat surface to represent several different
|
Hermes WebUI currently uses one chat surface to represent several different
|
||||||
things:
|
meanings:
|
||||||
|
|
||||||
- the assistant's live process text while work is still running,
|
- the assistant's live process text while work is still running,
|
||||||
- tool activity and lifecycle status that support that work,
|
- tool activity and lifecycle status that support that work,
|
||||||
- recovery or replay state after refresh, reconnect, or session switching,
|
- recovery or replay state after refresh, reconnect, or session switching,
|
||||||
|
- terminal outcomes such as cancel, interruption, no response, or tool limit,
|
||||||
- the final answer after the turn settles.
|
- the final answer after the turn settles.
|
||||||
|
|
||||||
Those meanings have repeatedly competed for the same visual space. The result is
|
Those meanings have repeatedly competed for the same visual space. Some
|
||||||
that some long-running sessions feel noisy, some look silent while the agent is
|
long-running sessions feel noisy, some look silent while the agent is working,
|
||||||
working, some recover into a different shape after reconnect, and some terminal
|
some recover into a different shape after reconnect, and some terminal edge
|
||||||
edge cases can appear completed even when no final answer was produced.
|
cases can appear completed even when no final answer was produced.
|
||||||
|
|
||||||
This RFC defines the product semantics for that lifecycle.
|
This RFC defines the product semantics that implementation PRs and follow-up
|
||||||
|
RFCs should preserve.
|
||||||
|
|
||||||
## Public Issue Signals
|
## Scope
|
||||||
|
|
||||||
The public issue history already shows the same problem recurring from several
|
### This RFC owns
|
||||||
directions. The table below uses representative examples; the broader inventory
|
|
||||||
lives in [#3400](https://github.com/nesquena/hermes-webui/issues/3400).
|
|
||||||
|
|
||||||
| Signal | Examples | Product implication |
|
- The visible lifecycle of one assistant reply from live work to final or
|
||||||
|
terminal outcome.
|
||||||
|
- The boundary between process prose, tool activity, lifecycle status, and the
|
||||||
|
final answer.
|
||||||
|
- Long-running edge-case semantics for Auto Compression, no-final answers,
|
||||||
|
tool/iteration limits, cancel/interruption, replay/reconnect/session switch,
|
||||||
|
produced artifacts/output handoff, and sidebar/session ownership.
|
||||||
|
- The classification of work into implemented slices, active PRs, confirmed
|
||||||
|
follow-ups, and child RFCs.
|
||||||
|
|
||||||
|
### This RFC does not own
|
||||||
|
|
||||||
|
- Pixel-level styling.
|
||||||
|
- Provider/model selection.
|
||||||
|
- A backend tool-event schema change such as a shared display-title field.
|
||||||
|
- A new runtime adapter, runner process, storage format, or SSE protocol.
|
||||||
|
- Rich artifact rendering, executable HTML, visualization plugins, or Canvas
|
||||||
|
editing surfaces. This RFC only owns how produced artifacts remain findable
|
||||||
|
from the reply lifecycle.
|
||||||
|
- The full command semantics for Queue, Steer, Stop-and-send, and Interrupt.
|
||||||
|
Those belong to the pending-intent control-surface contract tracked by
|
||||||
|
[#3058](https://github.com/nesquena/hermes-webui/issues/3058) and
|
||||||
|
[#3061](https://github.com/nesquena/hermes-webui/pull/3061).
|
||||||
|
|
||||||
|
## Public Inventory
|
||||||
|
|
||||||
|
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](https://github.com/nesquena/hermes-webui/issues/3400) is authoritative.
|
||||||
|
|
||||||
|
| Concern | Representative signals | Current classification |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| Working output and final answer can blur together | [#536](https://github.com/nesquena/hermes-webui/issues/536) | Running process and final answer need separate semantics. |
|
| Live work vs final answer boundary | [#536](https://github.com/nesquena/hermes-webui/issues/536), [#3400](https://github.com/nesquena/hermes-webui/issues/3400), [#3464](https://github.com/nesquena/hermes-webui/pull/3464) | Main product scope. #3464 landed the first RFC; this document is the parent contract for follow-up slices. |
|
||||||
| Compression state is hard to represent cleanly | [#469](https://github.com/nesquena/hermes-webui/issues/469), [#2973](https://github.com/nesquena/hermes-webui/issues/2973), [#3079](https://github.com/nesquena/hermes-webui/issues/3079) | Context compression should be visible while useful, but not become final transcript content. |
|
| First live-to-final reply implementation | [#3401](https://github.com/nesquena/hermes-webui/pull/3401), [#3014](https://github.com/nesquena/hermes-webui/issues/3014), [#3015](https://github.com/nesquena/hermes-webui/pull/3015) | First implementation slice. It should keep using `Refs #3400`; it does not close the umbrella. |
|
||||||
| Replay, reconnect, and session switching can lose active context | [#2283](https://github.com/nesquena/hermes-webui/issues/2283), [#2924](https://github.com/nesquena/hermes-webui/issues/2924), [#3391](https://github.com/nesquena/hermes-webui/issues/3391) | A recovered session should rebuild the same reply lifecycle as the live render. |
|
| Auto Compression visibility and context pressure | [#469](https://github.com/nesquena/hermes-webui/issues/469), [#2973](https://github.com/nesquena/hermes-webui/issues/2973), [#3079](https://github.com/nesquena/hermes-webui/issues/3079), [#3315](https://github.com/nesquena/hermes-webui/issues/3315), [#3316](https://github.com/nesquena/hermes-webui/pull/3316) | Supporting edge case. Running compression is live lifecycle status; compression-exhausted/no-final finalization is a terminal-state follow-up. |
|
||||||
| Tool, activity, thinking, and progress rendering can become noisy or silent | [#1298](https://github.com/nesquena/hermes-webui/issues/1298), [#3014](https://github.com/nesquena/hermes-webui/issues/3014), [#3015](https://github.com/nesquena/hermes-webui/issues/3015) | Process text should stay primary; tool activity should remain supporting detail. |
|
| Replay, reconnect, session switch, and reattach | [#2283](https://github.com/nesquena/hermes-webui/pull/2283), [#2924](https://github.com/nesquena/hermes-webui/issues/2924), [#3391](https://github.com/nesquena/hermes-webui/pull/3391) | Supporting recovery infrastructure. The product requirement is same lifecycle after replay, or an explicit degraded/restoring state. |
|
||||||
| Terminal turns can end without a real final answer | [#3315](https://github.com/nesquena/hermes-webui/issues/3315), [#3316](https://github.com/nesquena/hermes-webui/issues/3316) | No-final, compression-exhausted, and tool-limit outcomes need explicit terminal states. |
|
| Tool, activity, thinking, and visible progress | [#1298](https://github.com/nesquena/hermes-webui/issues/1298), [#3014](https://github.com/nesquena/hermes-webui/issues/3014), [#3015](https://github.com/nesquena/hermes-webui/pull/3015) | Main reply-rendering concern. Process prose stays primary; tool/reasoning/debug detail stays supporting. |
|
||||||
| Stream ownership and cancellation affect what the user sees | [#3344](https://github.com/nesquena/hermes-webui/issues/3344), [#3345](https://github.com/nesquena/hermes-webui/issues/3345) | One visible turn must own its live, terminal, and final events. |
|
| No-final and terminal failure outcomes | [#3315](https://github.com/nesquena/hermes-webui/issues/3315), [#3316](https://github.com/nesquena/hermes-webui/pull/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. |
|
||||||
| Session awareness affects live work visibility | [#856](https://github.com/nesquena/hermes-webui/issues/856), [#1370](https://github.com/nesquena/hermes-webui/issues/1370), [#1436](https://github.com/nesquena/hermes-webui/issues/1436) | Sidebar/session state must not contradict the visible active session. |
|
| Cancellation and stream ownership | [#3344](https://github.com/nesquena/hermes-webui/issues/3344), [#3345](https://github.com/nesquena/hermes-webui/pull/3345), [#3475](https://github.com/nesquena/hermes-webui/issues/3475), [#3476](https://github.com/nesquena/hermes-webui/pull/3476) | Supporting cancel/recovery scope. Early-cancel worker reconciliation is addressed by [#3476](https://github.com/nesquena/hermes-webui/pull/3476); frontend cancel owner-guard hardening is the remaining follow-up. |
|
||||||
| Busy input changes live-session control | [#720](https://github.com/nesquena/hermes-webui/issues/720), [#965](https://github.com/nesquena/hermes-webui/pull/965), [#1062](https://github.com/nesquena/hermes-webui/pull/1062) | Queue, steer, and interrupt are adjacent controls for long-running sessions, but command-level behavior belongs to a separate control-surface contract. |
|
| Produced artifacts and output handoff | [#2655](https://github.com/nesquena/hermes-webui/issues/2655), [#2673](https://github.com/nesquena/hermes-webui/pull/2673), [#2881](https://github.com/nesquena/hermes-webui/issues/2881), [#2938](https://github.com/nesquena/hermes-webui/pull/2938), [#3329](https://github.com/nesquena/hermes-webui/pull/3329), [#3348](https://github.com/nesquena/hermes-webui/pull/3348), [#3528](https://github.com/nesquena/hermes-webui/issues/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](https://github.com/nesquena/hermes-webui/issues/856), [#1370](https://github.com/nesquena/hermes-webui/pull/1370), [#1436](https://github.com/nesquena/hermes-webui/issues/1436) | Confirmed follow-up scope when sidebar/session metadata contradicts the visible active turn. |
|
||||||
## Goals
|
| User intervention during live work | [#720](https://github.com/nesquena/hermes-webui/issues/720), [#965](https://github.com/nesquena/hermes-webui/pull/965), [#1062](https://github.com/nesquena/hermes-webui/pull/1062), [#3058](https://github.com/nesquena/hermes-webui/issues/3058), [#3061](https://github.com/nesquena/hermes-webui/pull/3061) | Child RFC scope. This parent RFC only requires that controls preserve ownership, replay, and terminal honesty. |
|
||||||
|
|
||||||
- Define the product model for assistant replies in long-running sessions.
|
|
||||||
- Make live process text, tool activity, lifecycle status, and the final answer
|
|
||||||
share one coherent turn lifecycle.
|
|
||||||
- Preserve the same lifecycle through replay, reconnect, refresh, and session
|
|
||||||
switching.
|
|
||||||
- Name terminal outcomes honestly when the run does not produce a normal final
|
|
||||||
answer.
|
|
||||||
- Define which long-running edge cases belong to the first slice and which
|
|
||||||
should be handled by later slices.
|
|
||||||
|
|
||||||
## Non-goals
|
|
||||||
|
|
||||||
This RFC does not define:
|
|
||||||
|
|
||||||
- pixel-level styling,
|
|
||||||
- provider/model selection,
|
|
||||||
- command-level queue/steer/interrupt behavior,
|
|
||||||
- a new runtime adapter, storage format, or SSE protocol,
|
|
||||||
- a backend tool-event schema change such as a shared display-title field.
|
|
||||||
|
|
||||||
## Product Model
|
## Product Model
|
||||||
|
|
||||||
|
### Lifecycle flow
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
%%{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
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reply ownership
|
||||||
|
|
||||||
|
One visible assistant reply belongs to one user turn and one active run/stream
|
||||||
|
identity while that run is active.
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
- A live event should attach to the assistant reply that owns the run.
|
||||||
|
- A later turn in the same session must not inherit stale live events from an
|
||||||
|
older stream.
|
||||||
|
- A background session can continue running, but its live stream should not
|
||||||
|
mutate the visible pane for another session.
|
||||||
|
- A terminal event should settle the same turn it belongs to, or route through
|
||||||
|
a background/error path if the user is no longer viewing that session.
|
||||||
|
- Sidebar state should not contradict the visible owner. If the sidebar says a
|
||||||
|
session is running, opening it should show live work, a restoring/degraded
|
||||||
|
state, or an honest terminal state.
|
||||||
|
|
||||||
### Live phase
|
### Live phase
|
||||||
|
|
||||||
While a turn is running, the assistant reply should read as a live process
|
While a turn is running, the assistant reply should read as a live process
|
||||||
@@ -89,6 +180,8 @@ Requirements:
|
|||||||
- Tool rows and tool groups are collapsed by default.
|
- Tool rows and tool groups are collapsed by default.
|
||||||
- Full commands, arguments, raw output, and large payloads stay behind deeper
|
- Full commands, arguments, raw output, and large payloads stay behind deeper
|
||||||
disclosure.
|
disclosure.
|
||||||
|
- Thinking/reasoning that is not user-facing progress should not be the only
|
||||||
|
visible signal that work is happening.
|
||||||
- The run timer/status belongs with the active live turn, not as a top
|
- The run timer/status belongs with the active live turn, not as a top
|
||||||
transcript artifact.
|
transcript artifact.
|
||||||
- Running-only lifecycle markers are transient.
|
- Running-only lifecycle markers are transient.
|
||||||
@@ -104,17 +197,17 @@ Requirements:
|
|||||||
- A compact activity summary appears above the final answer.
|
- A compact activity summary appears above the final answer.
|
||||||
- The activity summary is collapsed by default.
|
- The activity summary is collapsed by default.
|
||||||
- Expanding it reveals readable process history and tool history.
|
- Expanding it reveals readable process history and tool history.
|
||||||
- Raw command/output detail remains behind a deeper disclosure.
|
- Raw command/output detail remains behind deeper disclosure.
|
||||||
- The final answer remains ordinary assistant prose below the summary.
|
- The final answer remains ordinary assistant prose below the summary.
|
||||||
- Running-only markers disappear from the settled transcript unless they explain
|
- Running-only markers disappear from the settled transcript unless they
|
||||||
a visible error or recovery outcome.
|
explain a visible error or recovery outcome.
|
||||||
- Very long final answers remain complete and readable. They should not be
|
- Very long final answers remain complete and readable. They should not be
|
||||||
hidden inside the activity summary or replaced by a progress/status artifact.
|
hidden inside the activity summary or replaced by a progress/status artifact.
|
||||||
|
|
||||||
### Recovery and replay
|
### Recovery and replay
|
||||||
|
|
||||||
Refresh, reconnect, session switching, and replay should preserve the same reply
|
Refresh, reconnect, session switching, and replay should preserve the same
|
||||||
model.
|
reply model.
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
|
|
||||||
@@ -124,43 +217,46 @@ Requirements:
|
|||||||
- If the exact live scene cannot be reconstructed immediately, the UI should
|
- If the exact live scene cannot be reconstructed immediately, the UI should
|
||||||
show an explicit restoring or degraded state instead of an empty running
|
show an explicit restoring or degraded state instead of an empty running
|
||||||
shell.
|
shell.
|
||||||
|
- Replay must be idempotent. It should not duplicate tokens, progress prose,
|
||||||
|
reasoning, tool rows, compression rows, or terminal cards.
|
||||||
- Old in-progress browser state must not override durable session truth.
|
- Old in-progress browser state must not override durable session truth.
|
||||||
- Recovery/control events stay internal unless they describe a user-visible
|
- Recovery/control events stay internal unless they describe a user-visible
|
||||||
terminal outcome.
|
terminal outcome.
|
||||||
|
|
||||||
### Terminal outcomes
|
### Terminal outcomes
|
||||||
|
|
||||||
Every turn needs a terminal outcome. A turn without a final answer must not look
|
Every turn needs a terminal outcome. A turn without a final answer must not
|
||||||
like a normal completed answer.
|
look like a normal completed answer.
|
||||||
|
|
||||||
Required product states:
|
Required product states:
|
||||||
|
|
||||||
- **completed**: the assistant produced a final answer and the turn settled
|
| State | Meaning |
|
||||||
normally.
|
| --- | --- |
|
||||||
- **cancelled**: the user stopped the turn.
|
| `completed` | The assistant produced a final answer and the turn settled normally. |
|
||||||
- **interrupted**: browser, stream, worker, or network continuity was lost
|
| `cancelled` | The user stopped the turn. |
|
||||||
before a final answer was produced.
|
| `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
|
| `compression_exhausted` | Context compression could not create enough room to continue safely. |
|
||||||
continue safely.
|
| `tool_limit_reached` | The run hit a tool-call, retry, or iteration ceiling before a final answer was produced. |
|
||||||
- **tool limit reached**: the run hit a tool-call, retry, or iteration ceiling
|
| `no_response` | The provider or runtime returned no usable assistant final content. |
|
||||||
before a final answer was produced.
|
| `error` | Fallback for failures that do not fit the above states. |
|
||||||
- **no response**: the provider or runtime returned no usable assistant content.
|
|
||||||
- **error**: fallback for failures that do not fit the above states.
|
|
||||||
|
|
||||||
Copy can evolve, but these semantic distinctions should stay stable in live
|
These identifiers name product states, not a wire/enum or persisted schema
|
||||||
rendering, settled rendering, and replay.
|
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
|
When more than one terminal condition applies, the more specific condition
|
||||||
should win over the generic fallback. For example, cancelled, compression
|
should win over the generic fallback. For example, `cancelled`,
|
||||||
exhausted, tool limit reached, and no response should not be flattened into a
|
`compression_exhausted`, `tool_limit_reached`, and `no_response` should not be
|
||||||
plain error only because the turn also failed to produce a final answer.
|
flattened into a plain `error` only because the turn also failed to produce a
|
||||||
|
final answer.
|
||||||
|
|
||||||
## Long-Running Edge Cases
|
## Long-Running Edge Cases
|
||||||
|
|
||||||
### Auto Compression
|
### Auto Compression
|
||||||
|
|
||||||
Auto Compression is a context lifecycle transition, not a tool call and not final
|
Auto Compression is a context lifecycle transition, not a tool call and not
|
||||||
answer content.
|
final answer content.
|
||||||
|
|
||||||
Expected behavior:
|
Expected behavior:
|
||||||
|
|
||||||
@@ -171,26 +267,24 @@ Expected behavior:
|
|||||||
remain understandable without turning compression into the main transcript.
|
remain understandable without turning compression into the main transcript.
|
||||||
- Do not keep compression status text in the settled transcript unless it
|
- Do not keep compression status text in the settled transcript unless it
|
||||||
explains an error or recovery state.
|
explains an error or recovery state.
|
||||||
|
- If compression fails to create enough room, surface `compression_exhausted`
|
||||||
|
or another specific terminal outcome instead of normal completion.
|
||||||
- Compression success in the UI does not by itself prove model-facing context
|
- Compression success in the UI does not by itself prove model-facing context
|
||||||
was pruned; that remains a separate runtime/context invariant.
|
was pruned; that remains a runtime/context invariant covered by the run-state
|
||||||
|
consistency contract.
|
||||||
|
|
||||||
### Very long final answers
|
Confirmed follow-up scope:
|
||||||
|
|
||||||
Long-running sessions can end with a final answer that is itself lengthy.
|
- Add or standardize an explicit per-pass compression completion event if the
|
||||||
|
UI otherwise has to infer completion from later stream events.
|
||||||
|
- Keep compression-exhausted/no-final handling aligned with
|
||||||
|
[#3315](https://github.com/nesquena/hermes-webui/issues/3315) and
|
||||||
|
[#3316](https://github.com/nesquena/hermes-webui/pull/3316).
|
||||||
|
|
||||||
Expected behavior:
|
### Tool-call, retry, and iteration ceilings
|
||||||
|
|
||||||
- The final answer remains the primary settled assistant content.
|
Long-running sessions can exhaust tool-call limits, retry budgets, or
|
||||||
- Supporting activity stays above it and collapsed by default.
|
iteration ceilings before a final answer is available.
|
||||||
- Streaming and settle transitions should not jump the user away from the final
|
|
||||||
answer or make the answer look like tool output.
|
|
||||||
- Any additional collapse, preview, or navigation affordance for very long final
|
|
||||||
answers should preserve the full answer as ordinary assistant prose.
|
|
||||||
|
|
||||||
### Tool-call and retry ceilings
|
|
||||||
|
|
||||||
Long-running sessions can exhaust tool-call limits, retry budgets, or iteration
|
|
||||||
ceilings before a final answer is available.
|
|
||||||
|
|
||||||
Expected behavior:
|
Expected behavior:
|
||||||
|
|
||||||
@@ -198,10 +292,12 @@ Expected behavior:
|
|||||||
- Preserve the readable work history that led to the limit.
|
- Preserve the readable work history that led to the limit.
|
||||||
- Keep the final area honest: show that the run stopped because a limit was
|
- Keep the final area honest: show that the run stopped because a limit was
|
||||||
reached rather than inventing a final answer.
|
reached rather than inventing a final answer.
|
||||||
- Do not persist internal control prompts as ordinary user-visible transcript
|
- Internal continuation or control prompts used by the runtime must not persist
|
||||||
content.
|
as ordinary user-authored transcript content.
|
||||||
|
- The product state should not depend on whether the limit came from provider
|
||||||
|
policy, Hermes Agent iteration budget, or WebUI adapter/runtime policy.
|
||||||
|
|
||||||
### No-final and provider failure
|
### No-final answer and provider failure
|
||||||
|
|
||||||
Tool-heavy turns can end with tool output, provider failure, or no usable final
|
Tool-heavy turns can end with tool output, provider failure, or no usable final
|
||||||
assistant message.
|
assistant message.
|
||||||
@@ -209,10 +305,38 @@ assistant message.
|
|||||||
Expected behavior:
|
Expected behavior:
|
||||||
|
|
||||||
- Detect the absence of a final assistant answer at settle time.
|
- Detect the absence of a final assistant answer at settle time.
|
||||||
- Surface a terminal state such as no response, interrupted, compression
|
- Surface a terminal state such as `no_response`, `interrupted`,
|
||||||
exhausted, tool limit reached, or error.
|
`compression_exhausted`, `tool_limit_reached`, or `error`.
|
||||||
- Do not mark the turn completed only because some assistant/tool activity
|
- Do not mark the turn completed only because some assistant/tool activity
|
||||||
occurred earlier.
|
occurred earlier.
|
||||||
|
- Do not treat internal context-compaction reference material as a final
|
||||||
|
assistant answer.
|
||||||
|
|
||||||
|
### Cancel and interruption
|
||||||
|
|
||||||
|
Cancel is a user-visible terminal action, not just browser cleanup.
|
||||||
|
|
||||||
|
Expected behavior:
|
||||||
|
|
||||||
|
- If the user cancels before the run fully starts, the backend still reconciles
|
||||||
|
against the live worker state where possible.
|
||||||
|
- If the user cancels after live text, reasoning, or tools have appeared,
|
||||||
|
already-visible work should not be silently lost.
|
||||||
|
- The frontend cancel path should close the SSE source it owns and only clear
|
||||||
|
busy state for the stream it actually cancelled.
|
||||||
|
- A cancelled turn should settle as `cancelled`, not as provider `no_response`.
|
||||||
|
- A network or worker interruption should settle as `interrupted` or restoring,
|
||||||
|
not as normal completion.
|
||||||
|
|
||||||
|
Classification:
|
||||||
|
|
||||||
|
- The early startup cancel race tracked by
|
||||||
|
[#3475](https://github.com/nesquena/hermes-webui/issues/3475) is addressed by
|
||||||
|
[#3476](https://github.com/nesquena/hermes-webui/pull/3476).
|
||||||
|
- The owner-aware browser cancel cleanup tracked by
|
||||||
|
[#3344](https://github.com/nesquena/hermes-webui/issues/3344) and
|
||||||
|
[#3345](https://github.com/nesquena/hermes-webui/pull/3345) remains a
|
||||||
|
focused follow-up.
|
||||||
|
|
||||||
### Reconnect and session switch
|
### Reconnect and session switch
|
||||||
|
|
||||||
@@ -225,77 +349,164 @@ Expected behavior:
|
|||||||
- Slow rebuild should be visibly restoring or degraded, not blank.
|
- Slow rebuild should be visibly restoring or degraded, not blank.
|
||||||
- Sidebar/session metadata should not point the user at a stale or wrong active
|
- Sidebar/session metadata should not point the user at a stale or wrong active
|
||||||
session.
|
session.
|
||||||
|
- Replay should use the same visible lifecycle as live rendering rather than a
|
||||||
|
flattened alternate presentation.
|
||||||
|
|
||||||
|
Confirmed follow-up scope:
|
||||||
|
|
||||||
|
- A clearer restoring/degraded state during slow reattach.
|
||||||
|
- Native `Last-Event-ID` or equivalent reconnect cursor support when it is
|
||||||
|
ready to replace or complement the current replay cursor path.
|
||||||
|
- Additional tests that prove live and replay use the same lifecycle for
|
||||||
|
process prose, tool rows, compression status, and terminal states.
|
||||||
|
|
||||||
|
### Tool-only or low-prose runs
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
- The UI should not fabricate assistant prose.
|
||||||
|
- Tool activity should remain readable enough that the turn does not look
|
||||||
|
empty or broken.
|
||||||
|
- Empty placeholders should be filtered rather than rendered as blank prose.
|
||||||
|
- If no final answer arrives, the terminal state should explain that outcome
|
||||||
|
instead of leaving only a tool list.
|
||||||
|
|
||||||
|
### Very long final answers
|
||||||
|
|
||||||
|
Long-running sessions can end with a final answer that is itself lengthy.
|
||||||
|
|
||||||
|
Expected behavior:
|
||||||
|
|
||||||
|
- The final answer remains the primary settled assistant content.
|
||||||
|
- Supporting activity stays above it and collapsed by default.
|
||||||
|
- Streaming and settle transitions should not jump the user away from the final
|
||||||
|
answer or make the answer look like tool output.
|
||||||
|
- Any additional collapse, preview, outline, or navigation affordance for very
|
||||||
|
long final answers must preserve the full answer as ordinary assistant prose.
|
||||||
|
|
||||||
|
### Produced artifacts and output handoff
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
- Existing artifact surfaces, such as the session Artifacts tab and
|
||||||
|
`workspace://` links, remain supporting navigation surfaces rather than
|
||||||
|
replacing the final answer.
|
||||||
|
- If a turn creates or edits workspace artifacts, the settled reply should not
|
||||||
|
hide the fact that those artifacts exist or make them impossible to find.
|
||||||
|
- Reconnect, replay, session switching, cancel, interruption, and no-final
|
||||||
|
terminal paths should preserve enough tool/artifact metadata to rebuild the
|
||||||
|
same artifact handoff.
|
||||||
|
- A terminal failure should still distinguish between "no final answer" and
|
||||||
|
"some artifacts were produced before the run stopped".
|
||||||
|
- Large generated files or rich artifact types should route through the
|
||||||
|
workspace/artifact preview model instead of being expanded into the main chat
|
||||||
|
transcript by default.
|
||||||
|
|
||||||
|
Confirmed follow-up scope:
|
||||||
|
|
||||||
|
- Keep artifact recoverability aligned with the session-scoped Artifacts tab
|
||||||
|
work in [#2655](https://github.com/nesquena/hermes-webui/issues/2655) and
|
||||||
|
[#2673](https://github.com/nesquena/hermes-webui/pull/2673).
|
||||||
|
- Keep final-answer artifact links aligned with the `workspace://` preview
|
||||||
|
path from [#2881](https://github.com/nesquena/hermes-webui/issues/2881) and
|
||||||
|
[#2938](https://github.com/nesquena/hermes-webui/pull/2938).
|
||||||
|
- Treat interrupted/cancelled tool-history loss, such as
|
||||||
|
[#3528](https://github.com/nesquena/hermes-webui/issues/3528), as a
|
||||||
|
live-to-final recoverability bug when it prevents artifact reconstruction.
|
||||||
|
|
||||||
|
### Sidebar and session ownership
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
- A session row's running indicator should reflect a real active run or a
|
||||||
|
clearly restorable state, not stale persisted metadata alone.
|
||||||
|
- Background completion, cancellation, or failure should be represented without
|
||||||
|
stealing the visible pane from the user.
|
||||||
|
- Session switching should not erase pending live context, in-flight snapshots,
|
||||||
|
tool history, or terminal outcome state.
|
||||||
|
- Maintenance writes, stale cleanup, and background repair should not make old
|
||||||
|
sessions look newly active unless meaningful user/assistant activity happened.
|
||||||
|
|
||||||
### User intervention
|
### User intervention
|
||||||
|
|
||||||
During long-running work, the user may need to queue follow-up input, steer the
|
During long-running work, the user may queue follow-up input, steer the current
|
||||||
current direction, or interrupt the run.
|
direction, or stop the run and send a replacement.
|
||||||
|
|
||||||
Expected behavior:
|
Expected behavior:
|
||||||
|
|
||||||
- These controls should not corrupt the live-to-final reply lifecycle.
|
- These controls should not corrupt the live-to-final reply lifecycle.
|
||||||
- Queue/steer/interrupt command semantics should be defined in a separate
|
- Queue/Steer/Stop-and-send/Interrupt command semantics should be defined in a
|
||||||
control-surface contract.
|
separate control-surface contract.
|
||||||
- This RFC only requires that live-session controls preserve clear ownership,
|
- This RFC only requires that live-session controls preserve clear ownership,
|
||||||
terminal outcomes, and replayable state.
|
terminal outcomes, and replayable state.
|
||||||
|
|
||||||
## Delivery Plan
|
The current child contract is tracked by
|
||||||
|
[#3058](https://github.com/nesquena/hermes-webui/issues/3058) and
|
||||||
|
[#3061](https://github.com/nesquena/hermes-webui/pull/3061). That child RFC
|
||||||
|
should own questions such as:
|
||||||
|
|
||||||
### Slice 1: live-to-final reply lifecycle
|
- whether Queue is browser-backed or server-backed in each slice,
|
||||||
|
- when Queue can upgrade to Steer,
|
||||||
|
- what Stop-and-send means,
|
||||||
|
- how delivered vs applied Steer is represented,
|
||||||
|
- what happens to leftover Steer after the run ends.
|
||||||
|
|
||||||
The first implementation slice is represented by #3401. It should demonstrate
|
## Delivery And Follow-Up Map
|
||||||
the core reply model:
|
|
||||||
|
|
||||||
- live process text is primary,
|
Use this map to keep implementation PRs and child RFCs scoped. The "vehicle"
|
||||||
- tool activity is quiet and progressively disclosed,
|
column names a durable track, not live merge state; the tracking issue
|
||||||
- running-only compression status is transient,
|
[#3400](https://github.com/nesquena/hermes-webui/issues/3400) is authoritative
|
||||||
- the settled activity summary appears above the final answer,
|
for current open/merged/superseded status.
|
||||||
- settle-time rendering does not falsely present a no-final turn as completed,
|
|
||||||
- replay and reattach rebuild the same visible structure,
|
|
||||||
- stream ownership fixes are limited to preserving the visible turn's ownership,
|
|
||||||
terminal events, and replay.
|
|
||||||
|
|
||||||
This slice should use `Refs #3400`; it should not close the umbrella issue.
|
| 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](https://github.com/nesquena/hermes-webui/issues/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](https://github.com/nesquena/hermes-webui/pull/3401). |
|
||||||
|
| Terminal/no-final stabilization | Compression exhausted, tool-tail/no-final transcript shape, context-compaction marker suppression, terminal error routing. | [#3315](https://github.com/nesquena/hermes-webui/issues/3315), [#3316](https://github.com/nesquena/hermes-webui/pull/3316). |
|
||||||
|
| Cancel ownership hardening | Frontend cancel should close its own SSE source and clear only its own busy state. | [#3344](https://github.com/nesquena/hermes-webui/issues/3344), [#3345](https://github.com/nesquena/hermes-webui/pull/3345). |
|
||||||
|
| Early-cancel startup race | Backend cancel should still interrupt the worker when the SSE registry detached before startup fully settled. | [#3475](https://github.com/nesquena/hermes-webui/issues/3475), [#3476](https://github.com/nesquena/hermes-webui/pull/3476). |
|
||||||
|
| Pending-intent control surface | Queue, Steer, Stop-and-send, Interrupt, delivered/applied/leftover semantics. | [#3058](https://github.com/nesquena/hermes-webui/issues/3058), [#3061](https://github.com/nesquena/hermes-webui/pull/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 Hermes 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. |
|
||||||
|
|
||||||
### Slice 2: terminal and recovery stabilization
|
## Relationship To Existing Contracts
|
||||||
|
|
||||||
The next slice should close the edge cases that make long-running sessions look
|
This RFC sits above the current runtime, recovery, and adapter contracts:
|
||||||
misleading after they stop or recover:
|
|
||||||
|
|
||||||
- cancelled and interrupted final rendering,
|
- [`webui-run-state-consistency-contract.md`](webui-run-state-consistency-contract.md)
|
||||||
- compression-exhausted terminal rendering,
|
defines how transcript, context, stream, replay, compression, and session
|
||||||
- tool-limit / max-retry terminal rendering,
|
metadata stay coherent.
|
||||||
- no-final-answer provider failure classification,
|
- [`canonical-session-resolution.md`](canonical-session-resolution.md) defines
|
||||||
- explicit restoring/degraded state during slow reattach,
|
how URL, local browser state, sidebar rows, and compression lineage resolve
|
||||||
- empty process placeholders that make tool-only runs look broken,
|
to one visible session target.
|
||||||
- live-vs-settled label clarity for tool activity.
|
- [`turn-journal.md`](turn-journal.md) defines crash-safe submitted-turn and
|
||||||
|
interrupted-turn recovery semantics.
|
||||||
|
- [`hermes-run-adapter-contract.md`](hermes-run-adapter-contract.md) defines
|
||||||
|
longer-term event/control ownership and migration gates.
|
||||||
|
|
||||||
### Slice 3: live-session control surface
|
This RFC defines the product meaning those lower-level contracts need to
|
||||||
|
preserve for long-running assistant replies.
|
||||||
|
|
||||||
The next adjacent product area is user intervention during live work:
|
The pending-intent control-surface RFC tracked by
|
||||||
|
[#3058](https://github.com/nesquena/hermes-webui/issues/3058) and
|
||||||
- queue follow-up input while a turn is running,
|
[#3061](https://github.com/nesquena/hermes-webui/pull/3061) should be treated
|
||||||
- steer a live turn without losing ownership of the current reply,
|
as a child contract: it can define user intervention semantics without
|
||||||
- interrupt a live turn and preserve the user's corrective intent,
|
redefining the live-to-final reply lifecycle.
|
||||||
- define busy-input defaults and prompt visibility,
|
|
||||||
- ensure these controls replay and settle into the same terminal model.
|
|
||||||
|
|
||||||
This slice should reference the existing busy-input / CLI-parity history, but it
|
|
||||||
should be designed as a control-surface contract rather than as a reply-content
|
|
||||||
change.
|
|
||||||
|
|
||||||
### Slice 4: session and protocol integration
|
|
||||||
|
|
||||||
Broader integration work should stay separate from the reply-content model:
|
|
||||||
|
|
||||||
- native `Last-Event-ID` or equivalent reconnect cursor support,
|
|
||||||
- sidebar/session awareness for active long-running work,
|
|
||||||
- session-list disappearance or stale-session repair,
|
|
||||||
- shared tool display-title normalization across legacy live stream, persisted
|
|
||||||
tool calls, replay, gateway paths, and future adapter/runner paths.
|
|
||||||
|
|
||||||
These are important follow-ups, but they should not be mixed into the first
|
|
||||||
reply-lifecycle implementation slice.
|
|
||||||
|
|
||||||
## Review Checklist
|
## Review Checklist
|
||||||
|
|
||||||
@@ -307,34 +518,32 @@ Use this checklist when reviewing PRs against this RFC:
|
|||||||
- Does the final answer remain separate from supporting activity?
|
- Does the final answer remain separate from supporting activity?
|
||||||
- Are compression, no-final, tool-limit, cancel, and interrupt outcomes
|
- Are compression, no-final, tool-limit, cancel, and interrupt outcomes
|
||||||
classified honestly?
|
classified honestly?
|
||||||
- Does reconnect/session switch rebuild the same reply lifecycle?
|
- Does reconnect/session switch rebuild the same reply lifecycle or degrade
|
||||||
|
explicitly?
|
||||||
|
- If the turn produced workspace artifacts, can the user still find them after
|
||||||
|
settle, replay, reconnect, cancel, or terminal failure?
|
||||||
- Do internal recovery or control messages stay out of ordinary chat content?
|
- Do internal recovery or control messages stay out of ordinary chat content?
|
||||||
- Is the PR's slice clear: lifecycle, terminal/recovery, live controls, or
|
- Does sidebar/session state agree with the visible active or terminal turn?
|
||||||
session/protocol integration?
|
- Is the PR's slice clear: lifecycle, terminal/recovery, cancel ownership,
|
||||||
|
live controls, sidebar/session ownership, or protocol integration?
|
||||||
## Relationship To Existing Contracts
|
- If the change belongs to Queue/Steer/Stop-and-send/Interrupt, is it routed to
|
||||||
|
the child control-surface RFC instead of being hidden inside this parent RFC?
|
||||||
This RFC sits above the current run-state and adapter contracts:
|
|
||||||
|
|
||||||
- [`webui-run-state-consistency-contract.md`](webui-run-state-consistency-contract.md)
|
|
||||||
defines how transcript, context, stream, replay, compression, and session
|
|
||||||
metadata stay coherent.
|
|
||||||
- [`canonical-session-resolution.md`](canonical-session-resolution.md) defines
|
|
||||||
how URL, local browser state, sidebar rows, and compression lineage resolve to
|
|
||||||
one visible session target.
|
|
||||||
- [`turn-journal.md`](turn-journal.md) defines crash-safe submitted-turn and
|
|
||||||
interrupted-turn recovery semantics.
|
|
||||||
- [`hermes-run-adapter-contract.md`](hermes-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.
|
|
||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
- Should very long final answers need additional navigation or preview
|
Open questions are limited to product choices that are not already decided by
|
||||||
affordances beyond the standard chat transcript behavior?
|
this RFC, an active implementation PR, or a child RFC.
|
||||||
- Should repeated compression passes in one turn be shown as separate transient
|
|
||||||
statuses or summarized into one compression lifecycle marker?
|
- Should very long final answers gain additional navigation, outline, or
|
||||||
- Should queue, steer, and interrupt receive a dedicated public control-surface
|
preview affordances beyond standard chat transcript behavior? If yes, what
|
||||||
RFC, or should that contract live inside the existing adapter/control RFC?
|
threshold triggers them and how do they preserve the answer as ordinary
|
||||||
|
assistant prose?
|
||||||
|
- When a turn produces multiple workspace artifacts, should the final answer
|
||||||
|
include an automatic artifact summary or navigation affordance, or should the
|
||||||
|
product rely on the existing Artifacts tab and explicit `workspace://` links?
|
||||||
|
- What is the minimum sidebar signal for background long-running sessions that
|
||||||
|
have completed, failed, cancelled, or need attention while the user was
|
||||||
|
viewing another session?
|
||||||
|
- Which terminal outcomes should offer inline recovery actions, such as retry,
|
||||||
|
continue, inspect details, or reopen from checkpoint, and which should remain
|
||||||
|
informational only?
|
||||||
|
|||||||
Reference in New Issue
Block a user