Skip to content

fix(native-chat): an interrupted reply's note stops blaming the agent - #28681

Draft
brennanb2025 wants to merge 1 commit into
mainfrom
brennanb2025/cut-turn-neutral-notice
Draft

brennanb2025 wants to merge 1 commit into
mainfrom
brennanb2025/cut-turn-neutral-notice

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 22 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​159 $\color{#cf222e}{\Huge{\mathbf{−}}}$​314 $\color{#cf222e}{\Huge{\mathbf{−}}}$​155
Prod 24 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​165 $\color{#cf222e}{\Huge{\mathbf{−}}}$​169 $\color{#cf222e}{\Huge{\mathbf{−}}}$​4

ELI5

When Orca quits, crashes, restarts or loses a chat's agent in the middle of a reply, the chat shows a note under the cut-off reply. When Orca could not tell why the reply stopped, that note said "Codex stopped while this response was in progress" in error red, which blames the agent for something Orca did. Now that note says "This response was interrupted. You can continue in this conversation." in the same muted card Orca already uses when it knows the cause, with the Continue button inside it.

What Changed

The problem. A native chat reply can be cut off with nobody pressing Stop: Orca quits or updates, Orca crashes, a paired server stops, or Orca reopens a chat and finds the agent process from before is gone. Main already has a muted "stop card" for the cases where Orca knows the cause ("Orca on studio-mac was closed while this response was in progress.", with Continue inside the card). But when the cause is unknown, most often when a reopen finds the previous agent process gone, the host wrote the agent-failure sentence (" stopped while this response was in progress. You can continue in this conversation.") in error red, with an "agent exited" failure attached. The transcript's own fallback note for a cut turn with no explanation used the same red sentence. Nothing had failed; the user was told the agent broke.

What the user sees now.

  • Cause known (quit, update, crash, remote server stop): unchanged. Same wording naming the cause and machine, muted, Continue inside the card.
  • Cause unknown (the reopen case): "This response was interrupted." in the muted stop card, with Continue inside it. Where the host cannot continue the cut, the card adds "You can continue in this conversation." as the known-cause card already does.
  • Cut turn with no note at all (for example an idle eviction): the derived fallback note reads "This response was interrupted. You can continue in this conversation." in the same muted card, without a Continue button (see the deviations below).
  • The agent's own crash while Orca keeps running is unchanged: same red row.
  • The folded ("collapsed") view of a finished turn keeps each of these notes visible, as main already does for Orca-stop notes.
  • The phone shows the same neutral sentence, because it prints the host's text.

The mechanism.

  • One row body for every cut Orca knows was not a person's Stop: agentSessionOrcaStopRowBody (src/shared/agent-session-orca-stop.ts) stores the neutral sentence, muted tone, the existing orca-stop presentation, and the cause only when it is known. The quit/update row, the reopen row and the transcript's derived note all use it. It no longer stores red text or an "agent exited" failure fact for clients that predate the cause.
  • readAgentSessionOrcaStopRow says whether a row is the host's own stop row (cause known or not). The Continue reader the client and host share (latestNativeChatOrcaStopCut) now accepts a host row with no cause, so Continue appears on the reopen row. A transcript-derived note never counts, because the host never wrote it and would refuse the Continue.
  • The notice row renders an orca-stop row with no nameable cause through the same card with a new translated sentence (orcaStopInterrupted, in all six locales), built in native-chat-orca-stop-words.ts beside the existing cause sentences.
  • Mixed versions: a newer client can open a chat on an older host whose reopen row is red and blames the agent. That row has one exact shape: an Orca-written status row whose id starts with stale-session: and that has no presentation. Main writes that prefix only for its rows about a cut. The projection shows that shape as the neutral row, without Continue, which that host would refuse.
  • Cleanup: the agent name no longer feeds these rows, so the failureTextContext/agentName plumbing that existed only for them is removed.

Why

The note should say what Orca actually knows. When the cause is unknown, Orca knows only that the reply was interrupted, so it says that, neutrally, on the card that already exists for interruptions, instead of using an agent-failure sentence. Reusing main's stop card keeps one look and one Continue for every Orca-side interruption rather than adding a second notice style.

Alternatives considered:

Deviations from the common pattern (interruption by the execution host is told apart from a provider failure and shown in neutral wording):

  • Intended: cause-known rows are now stored muted as well, with no red copy for clients that predate the cause. Safe because only development builds predate the cause-aware card. On those builds the row may be folded or show the neutral host sentence.
  • Intended: a derived note (a cut turn no row explains) offers no Continue. It appears only when no host row exists (idle eviction, a quit that died mid-settle, journals written before host rows). The note tells the user to continue in the conversation, and sending a message does.
  • Intended: the older-host reopen row is reworded on display, matched by its exact stored shape. It can be removed once no supported host predates this change.
  • Intended: if an agent's own crash could not be recorded before Orca lost it, the later reopen cannot tell the crash from Orca losing the process, and writes the neutral row. That is the honest reading of what the reopen knows.

Out of scope: the status mark mapping (Interrupted vs Failed on the sidebar, tab bar and phone) and how long settled marks stay visible. Those are the sibling PRs.

Linked Issue

Replaces part of #25670

Fixes #

Visual Proof

Pending: QA to follow

Testing

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

  • New: the existing "one Continue, in the card" session test now renders the real folding transcript over four cut turns: an older host's red reopen row, a known-cause quit row, the agent's own exit row, and a no-cause reopen row. It checks that every turn is collapsed, each turn has exactly one visible explanation, the known cause keeps its wording, the agent's exit stays red, the older host's row reads neutral with no Continue, and the one Continue sits inside the muted neutral card. It fails if the fold stops keeping Orca-stop rows visible.

  • Extended: the host test for the reopen row now checks that Continue is offered on a no-cause row the host wrote, and the transcript hook test checks that a derived note never offers Continue.

  • Updated existing host, shared and mobile tests from the old red wording to the neutral row. Deleted the test file that pinned "stored red for clients that predate the cause".

  • Ran: every test file that touches these rows (36 files, 444 tests) plus the two mobile tests. orca-ci-checks: see the PR's CI.

AI Disclosure

Review

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • SSH / paired servers: the host writes the row; a paired server's chat shows the same card ("the remote server" when unnamed). Mixed client/host versions are covered above.
  • Mobile: prints the host's neutral sentence; its derived note uses the same shared code.
  • No migration: rows written before this change by this build's own host are shown through the same older-host display rule.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

When a reopen finds the agent process gone, or a cut turn has no note, the
chat said '<Agent> stopped while this response was in progress' in error red.
Every row about a reply cut with nobody asking now stores one muted body,
'This response was interrupted. You can continue in this conversation.', on
the existing Orca-stop card: a known cause keeps its wording, the host's
no-cause row gets Continue inside the card, and a derived note never offers
a Continue the host would refuse. An older host's red reopen row reads the
same on a newer client. The agent's own crash row is unchanged.

Replaces part of #25670.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant