Skip to content

fix(native-chat): chat copy that promised a retry, an update, or a coming change - #25157

Merged
brennanb2025 merged 9 commits into
mainfrom
brennanb2025/chat-copy-followups
Oct 6, 2026
Merged

brennanb2025 merged 9 commits into
mainfrom
brennanb2025/chat-copy-followups

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 10 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​46 $\color{#cf222e}{\Huge{\mathbf{−}}}$​21 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​25
Prod 13 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​139 $\color{#cf222e}{\Huge{\mathbf{−}}}$​51 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​88

ELI5

#24594 reworded native chat errors and status rows in plain language. A check of the merged copy from the user's side found lines that still promise something Orca doesn't do, or say less than Orca knows:

  • a subagent row hints that an update is still coming, when none can come;
  • the skills menu says skills don't work in SSH chats, when only the list is missing;
  • one refusal says "This isn't available in this chat." when Orca knows the reason.

This PR rewords three of them, so each line says only what is true. The fourth, the refusal you see when /compact or /clear is blocked behind an earlier message, moved to a follow-up PR: it needs a behaviour fix, not new words.

What Changed

1. Subagent and background-task rows that can no longer change

Copy
Before no recent update / 2 agents with no recent update
After status unavailable / 2 agents with status unavailable
  • Where it shows:
    • The subagent card in the transcript, for a subagent that was still working when the agent's session ended or Orca restarted. Nothing reported how it ended, and nothing ever will.
    • The background-task strip's summary line ("1 agent with status unavailable") while Orca has lost contact with a child's host.
    • Background-task rows sent by older Orca versions.
  • Problem with the old copy: for a subagent that can no longer report, "recent" suggested an update might still come.
  • Why this wording: "status unavailable" doesn't claim the child exited, which Orca can't prove (lost contact is not proof it stopped). It doesn't promise an update either. The phrase is the one the common pattern uses when it can't report a status. One deliberate difference: the common pattern counts interrupted children as "stopped", which Orca doesn't do, because it can't prove they exited.
  • Unchanged:
    • The strip's own row for a lost-contact child, which still shows the time since its last update ("No update in 2m"). That's a live state, so it stays.
    • The sidebar's "No update in 34m" and its "No recent update" status dot.

2. Skills menu in SSH chats

Copy
Before Skills aren't available in SSH chats
After Skills can't be listed in SSH chats
  • What's actually missing: Orca only skips looking up the skill list on an SSH host.
  • What still works: a skill typed by name is sent to the agent unchanged, and the built-in commands still list.

3. A write refused because this agent or location can't run as a chat

Copy
Before (send) This isn't available in this chat.
After (send) Orca can't run this agent in a chat here. Your message was not sent.
Before (history) This chat's history couldn't be loaded.
After (history) Orca can't run this agent in a chat here. This chat's history couldn't be loaded.
Chat start Chat could not be started. Orca can't run this agent in a chat here.
  • When it shows: the host refuses with "unsupported here", for example an SSH or WSL location, an agent that can't run as a chat, or a Windows machine where Orca can't read process start times. Updating Orca doesn't fix any of these.
  • What the new copy says: the cause the host already reports, plus what didn't happen, in the same shape as every other refusal.
  • What it doesn't say: it adds no next step, because none is certain for every case.
  • Unchanged: the other two "unsupported" reasons (no chat service running yet, or a client missing a capability) keep "This isn't available in this chat."; neither has a cause the user can act on.

Translations

  • All three lines are hand-translated in French, Japanese, Korean, Chinese and Spanish.
  • Spanish: main has since added the chat's notice, background-task and subagent rows. On top of those, this PR changes only the reworded lines, the per-state count sentences below, and a few count and reason strings so they read correctly for one or many.
  • The background-task summary used to join a count and a state word ("2 agents" + "done"). Spanish and French can't make the word agree that way ("3 terminado"). Each state now has its own count sentence, as the subagent card already has. English, Japanese, Korean and Chinese read exactly as before.

Only wording changes; there is no behaviour change. Mobile shows the same shared English sentences, so the phone gets item 3 as well.

Why

  • The goal: each line says only what Orca knows, and names a step only when that step exists on the screen the user is looking at.
  • Alternatives considered:
    • "stopped" (item 1) was ruled out because it claims an exit Orca can't prove.

Two related items were checked and left unchanged:

  • Codex Fast-mode switch with no reported value. Since a caption was removed earlier, the switch shows the default (Off) when Codex hasn't reported the setting. That matches the common pattern, which shows a plain on/off switch at its default. Orca also reads the setting Codex reports when a thread opens, so the switch matches Codex's real setting except with older Codex versions that don't report it. Fixing that would be a host-side change, not a wording one.
  • Screen readers and the delayed loading spinner. The loading status has no text that changes after it appears, so screen readers don't announce it, on quick opens or slow ones. Nothing is spoken before the spinner shows, so there is nothing to fix.

Linked Issue

Follow-up to #24594.

Visual Proof

Before is main, after is this PR. Each pair shows the same state in a hidden, isolated copy of the app on a Mac, driven through the app's real UI. Each screenshot is the full app window.

1. Subagent card for a subagent that can no longer report (live). A stand-in agent started a background subagent, then the stand-in was ended mid-task.

Before After
Subagent card on main: "Ran 1 subagent no recent update", row "Review the README no recent update" Subagent card on this PR: "Ran 1 subagent status unavailable", row "Review the README status unavailable"

2. Skills menu in an SSH chat (test hook, not a live SSH chat). The test Mac has no SSH server, so the project was marked as SSH-hosted in the app's memory through the test build's store; the real / menu then rendered.

Before After
Slash menu on main: Skills section says "Skills aren't available in SSH chats" Slash menu on this PR: Skills section says "Skills can't be listed in SSH chats"

3. A send refused because this agent can't run in a chat here (seeded state, not a live state). One saved refusal with that reason was written into the chat's local outbox and the window reloaded; the desktop otherwise opens a terminal before this refusal can happen.

Before After
Failed send on main: "This isn't available in this chat." with Retry Failed send on this PR: "Orca can't run this agent in a chat here. Your message was not sent." with Retry

Not captured: the background-task strip's summary line (no strip appeared on either build in this state), and the history-pane and chat-start versions of item 3; component tests cover those.

Testing

  • src/shared/agent-session-refusal-notice.test.ts: every reason × write cell is now pinned with the new wording for "unsupported here" and the old wording for the other two reasons.

  • The read-error, autocomplete, subagent-run, background-task and sidebar child-row tests are updated to the new strings.

  • background-task-roster.test.ts: a new case pins every state's English count sentence ("2 agents done", "3 stopped"), unchanged from before.

  • Localization checks pass: catalogs, extraction, coverage, and the runtime-required English catalog.

  • Typecheck: web and node.

  • I manually tested these changes locally

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

AI Disclosure

Review

Agent skill upstream boundary

  • Not applicable, or this change follows docs/reference/agent-skill-sharing-upstream-boundary.md and copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

  • Wording only: nothing changes on the wire. An older client talking to a newer host keeps its own older copy.
  • SSH: item 3 is SSH-only, and item 4 covers SSH and WSL locations.
  • Mobile: gets item 3 through the shared English copy.
  • Performance: no impact.

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)

…ming change

- Subagent and background-task rows Orca can no longer settle read "status
  unavailable" ("2 agents with status unavailable"), not "no recent update",
  which implied an update was still coming.
- /compact or /clear refused behind an unconfirmed earlier message says "Wait
  for the agent to finish, then try again." There is no Retry for that message.
- The skills menu in SSH chats says skills can't be listed there; a skill typed
  by name still goes to the agent.
- A write the host refuses because this agent or location can't run as a chat
  says "Orca can't run this agent in a chat here." plus what didn't happen.
- Spanish gains the chat notice, background-task and subagent rows it lacked.
…nd translation fixes

- Background-task header counts use one translated sentence per state
  (stateWorkingCount ... stateIdleCount), so Spanish and French can agree
  the state with the count; English output is unchanged and pinned by a test.
- es: subagent failed/idle/stopped counts and the waiting/blocked reasons
  read correctly for any count.
- fr: "listées" agrees with the feminine "skills" in the SSH skills line.
- ja: subagent status-unavailable count uses the 件 counter.
- Correct the refusal-table comment: hostUnsupported is also returned and
  recorded, not only thrown.
@brennanb2025
brennanb2025 marked this pull request as ready for review October 4, 2026 08:13
@brennanb2025

Copy link
Copy Markdown
Contributor Author

Review summary

The problem. #24594 reworded native chat errors and status rows. Read from the user's side, four of the merged lines still said something untrue:

  • A subagent that can never report again read "no recent update", as if an update might still come.
  • A /compact or /clear refused behind an unconfirmed earlier message said "or retry it", but no Retry exists anywhere this shows.
  • The SSH skills menu said skills "aren't available", but only the list is missing; a skill typed by name still works.
  • A message the host refused because this agent or location can't run as a chat said "This isn't available in this chat.", which names nothing.

Spanish was also missing the chat's notice, background-task and subagent rows entirely.

What changes for you.

  • The subagent card and the background-task summary say "status unavailable" ("2 agents with status unavailable"). This claims neither that the child stopped nor that an update is coming.
  • The /compact and /clear refusal ends with "Wait for the agent to finish, then try again." The chat shows the agent as working the whole time this can appear.
  • The SSH skills menu says "Skills can't be listed in SSH chats".
  • That refusal now reads "Orca can't run this agent in a chat here." plus what didn't happen ("Your message was not sent." / "This chat's history couldn't be loaded.").
  • Spanish gains those three sections (about 65 short strings), hand-translated. French, Japanese, Korean and Chinese get every reworded line.

What the review fixed.

  • Spanish and French background-task summaries: these joined a count and a state word, so the word couldn't agree with the count ("3 terminado"). Each state now has its own count sentence, as the subagent card already had. English, Japanese, Korean and Chinese read exactly as before, and a test pins the English.
  • Smaller translation fixes: Spanish subagent counts read right for one or many, Spanish reasons read right after a plural, French "skills" takes the right gender, and the Japanese subagent count uses its counter word.
  • PR description: corrected where "status unavailable" actually appears, how long the /compact wait can last, and how closely the wording follows the common pattern.
  • Code comment: a comment wrongly said "unsupported here" refusals are only ever thrown errors; it now says they can also be returned and saved.

What was deferred (not caused by this PR).

  • P2: a Codex message that timed out before reaching an already-idle agent keeps /compact blocked, with the chat showing "working", until idle cleanup stops the agent about 30 minutes later. Closing the chat ends it sooner. The fix is for the host to ask Codex for its current status; that's a host change for a follow-up.
  • P2: in Japanese, the background-task summary's "status unavailable" count can follow a bare number ("1 は状態を取得できません"). The same string also follows labels like "2 Agent", so it needs a per-call-site sentence; that's a follow-up.
  • P3:
    • A child that was still running when the session ended reads "stopped" in the strip but "status unavailable" on its transcript card. That mismatch predates this PR.
    • The strip row's status dot is still announced as "No recent update", a label shared with the sidebar, which stays unchanged on purpose.
    • A send refused as "can't run here" still offers a Retry that will fail again.
    • Some existing French state and kind labels are poor translations.

Checked and left unchanged.

  • Codex Fast-mode switch: with no reported value it shows Off. That matches the common pattern, and Orca reads the setting Codex reports when a thread opens.
  • Loading spinner: it isn't announced to screen readers before it appears, so there is nothing to fix.

What was verified.

  • Each finding was traced in code before changing anything, on desktop and on the phone, which shows the same English sentences.
  • Tests: targeted tests pass (21 files, 304 tests in the final readiness pass). The refusal table now pins the new wording for every reason and action.
  • Checks: the localization catalog, extraction, coverage and runtime-catalog checks pass, and so do web and node typechecks.
  • CI: green on 98befa8.
  • Review: an adversarial copy review, an independent architecture review (which agreed wording-only is the right shape and that this shouldn't split), a translation review, a second narrow round, and a final readiness review. That final review found no release-blocking issues.

What wasn't verified.

  • No screenshots. The shared remote test Mac's own Orca restarted during setup, and a one-hour retry never saw its load drop low enough (it peaked at 184). Only the subagent card's line is reachable with a stand-in agent anyway; the PR body explains why the other three aren't.
  • Nothing was exercised live: no SSH chat and no phone.

@coderabbitai

coderabbitai Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 69de6d8b-c07c-4b2c-873f-d5bfd2de755b
📥 Commits

Reviewing files that changed from the base of the PR and between 6da1dff and a12240f.

⛔ Files ignored due to path filters (1)
  • src/renderer/src/components/sidebar/__snapshots__/subagent-child-row-fallback-pixels.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (1)
  • src/renderer/src/components/native-chat/NativeChatToolRun.sentences.test.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

Agent-session notices now include a hostUnsupported explanation. Background-task count labels use state-specific translations, and unverifiable statuses say “status unavailable.” SSH skills wording now states that skills cannot be listed. Tests and translations were updated.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to a1224

The described copy and Spanish test-expectation updates do not establish a user-facing regression, so no merge-blocking issue is identified.

Architecture Summary

Architecture risk: 🔵 Low · up to 6da1d

The change affects 1 system.

Changed systems: src

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — src (service) was modified; 21 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.test.tsx: The test now expects “Skills can't be listed in SSH chats” instead of “Skills aren't available in SSH chats.”
  • observed — Modified behavior in src/renderer/src/components/native-chat/NativeChatAutocompleteMenus.tsx: Updates the translated SSH skills-unavailable message from “aren't available” to “can't be listed.”
  • observed — Modified behavior in src/renderer/src/components/native-chat/NativeChatBackgroundTasksStatus.test.tsx: The test expectation for the unverifiable row changes from “no recent update” to “status unavailable.”
  • observed — Modified behavior in src/renderer/src/components/native-chat/NativeChatSubagentRun.test.tsx: The test for an unverifiable child now expects “status unavailable” instead of “no recent update.”
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 16 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the native-chat copy changes, including wording that avoids promising a future update or change.
Description check ✅ Passed The description covers the change, its rationale, linked issue, visual proof, testing, and relevant impact. Some optional sections are blank, and the full lint, test, and build checklist remains unche…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • hostUnsupported refusal copy — the structured_agent_session_unsupported / hostUnsupported reason now maps to a new cannotRunHere sentence ("Orca can't run this agent in a chat here.") instead of notAvailable, for writes and history reads alike; registered in AGENT_SESSION_WRITE_NOTICE_COPY, the renderer SENTENCES record, en.json, and en-runtime-required.json. clientCapabilityMissing and hostDisabled keep notAvailable.
  • unverifiable state word — "no recent update" → "status unavailable" in backgroundTaskStateWord and the subagent card (single and count forms), so it neither claims an exit nor promises an update. This is shared with the sidebar child-row reason detail through agent-child-row-text.ts, so that surface changes too.
  • Background-task count sentences — backgroundTaskCountedState no longer concatenates a count with backgroundTaskStateWord; each state gets its own {{value0}} … sentence, letting fr/es agree the count with the state. English/ja/ko/zh read as before; fr/es improve ("2 agents working", not "2 agents fonctionnement").
  • settleEarlierMessage — now "Wait for the agent to finish, then try again.", dropping the mention of a Retry that isn't on screen.
  • Skills-menu SSH copy — skillsUnavailableHost now says "Skills can't be listed in SSH chats".
  • Translations — es gains the previously missing notices, backgroundTasks, and subagents.state sections (~60 strings); the four reworded lines are hand-translated in fr/ja/ko/zh. All seven state*Count keys exist in all six locales and cannotRunHere in all six.
  • Tests — refusal notice, autocomplete menus, subagent/background-task rows, history read-error, and the child-row pixel snapshot are updated; backgroundTask-roster.test.ts adds an exact per-state count-sentence case.

I ran the changed shared/renderer tests plus the child-row parity tests, both web and node typechecks, and all four localization gates locally; everything passes. The new strings are anchored by exact assertions rather than loose matches, so they will fail if the copy regresses. No behavioral, security, or cross-platform concerns found.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

…y-followups

# Conflicts:
#	src/renderer/src/i18n/en-runtime-required.json
#	src/renderer/src/i18n/locales/es.json
#	src/shared/agent-session-refusal-notice.ts

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

This run covers the single new commit since the prior pullfrog review — a merge of origin/main — and re-confirms the branch-authored surface is intact.

  • Merged origin/main (b354aab18e) into the branch, resolving three conflicted files. src/shared/agent-session-refusal-notice.ts had been split upstream: the reason-words table moved to the new src/shared/agent-session-refusal-reason-words.ts, and the branch's hostUnsupported → cannotRunHere edit (plus its messagesUnsettled comment) landed cleanly in the new file while the old file keeps main's re-export.
  • Reconciled the en-runtime-required.json and es.json locale conflicts — the branch's reworded settleEarlierMessage, cannotRunHere, and per-state background-task count sentences were combined with main's new sendOutcomeLost, receipt, taskList, notices, backgroundTasks, and goal sections. No duplicate JSON keys were introduced in any of the six catalogs.
  • Confirmed the four reworded copy lines and their translations (fr/ja/ko/zh/es) survived the merge, along with main's chatSavedByNewerOrca / updateOrcaToOpenChat additions that journalWrittenByNewerOrca's new history step depends on.

I re-ran the changed shared/renderer tests (136 passing), verify:localization-catalogs, and a duplicate-key scan across all six locale files plus the runtime catalog; everything passes. The merge resolution preserves both sides' work with no dropped changes.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

…o its own PR

Restores main's settleEarlierMessage copy in every locale and drops its comment.
The refusal's behaviour, not only its words, is being fixed separately.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

This run covers the single new commit since the prior pullfrog review — a revert that narrows the PR's scope.

  • Reverted the /compact unconfirmed-message copy — the branch's settleEarlierMessage reword ("Wait for the agent to finish, then try again.") is removed. Main's copy ("Wait for your earlier message to go through, or retry it.") is restored in all six locales, en-runtime-required.json, and agent-session-write-notice-copy.ts, and the messagesUnsettled comment in agent-session-refusal-reason-words.ts is dropped. The refusal's behaviour fix moves to a follow-up PR, so the PR now matches its own description of three reworded lines.

No test hardcodes the removed value, and the restored strings match main exactly, so the revert is internally consistent. The remaining surface (the cannotRunHere remap, the unverifiable → "status unavailable" word, the per-state background-task count sentences, and the SSH skills copy) is unchanged from the version already reviewed.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Update: scope down to three lines, and screenshots added.

  • The /compact and /clear refusal is out of this PR. Its message ("A message you sent earlier isn't confirmed yet...") still left the reader asking whether the message was sent, what "confirmed" means, and why they can't try again now. Rewording can't answer that, so the fix is a change in behaviour, in a separate PR. This PR now leaves that message exactly as it is on main, in every language.
  • The other three lines are unchanged:
    • "status unavailable" on a subagent that can no longer report;
    • "Skills can't be listed in SSH chats";
    • "Orca can't run this agent in a chat here."
  • Merged with current main. Main had added its own Spanish for these rows; the merge keeps main's translations except where this PR changes the wording or fixes how a count reads.
  • Visual proof: before and after shots of all three lines are in the description.
    • The subagent card was captured in a live state.
    • The SSH skills line uses a test hook, because the test Mac has no SSH server.
    • The "can't run here" refusal uses a seeded saved state. Each shot is labelled.
  • Checks: CI is green on 6f1c7c9. A fresh review confirmed the revert leaves no trace of the removed line and touches nothing else.

…y-followups

# Conflicts:
#	src/renderer/src/components/native-chat/NativeChatBackgroundTaskRun.test.tsx
#	src/renderer/src/components/sidebar/__snapshots__/subagent-child-row-fallback-pixels.test.tsx.snap
@brennanb2025
brennanb2025 merged commit 07981bd into main Oct 6, 2026
52 of 55 checks passed
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