Skip to content

fix(mobile): use desktop's rules for chat tool rows, pending echoes and session option picks - #33977

Merged
AmoabaKelvin merged 34 commits into
mainfrom
mobile-chat-option-picks
Oct 27, 2026
Merged

AmoabaKelvin merged 34 commits into
mainfrom
mobile-chat-option-picks

Conversation

@AmoabaKelvin

@AmoabaKelvin AmoabaKelvin commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator
Files Added Deleted Net
Test 40 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1053 $\color{#cf222e}{\Huge{\mathbf{−}}}$​1669 $\color{#cf222e}{\Huge{\mathbf{−}}}$​616
Prod 92 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1888 $\color{#cf222e}{\Huge{\mathbf{−}}}$​1849 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​39

ELI5

Phone chats now follow desktop's rules for tool rows, copied text and file sizes, for the placeholder bubble shown after you send, and for the model and effort pickers. Picks made quickly one after another, or whose reply is lost, now behave as they do on desktop.

This PR now also carries #33969, #33970 and #33976, folded in so the stack lands in fewer passes while main keeps moving the files it touches.

What Changed

#33969: Use desktop's rules for chat tool rows, copy text and agent order

Tool rows, copied message text and file sizes in chat now follow desktop's rules on the phone. The phone also hides the Codex foreground shell from its background-task strip, and picks a terminal's chat agent in desktop's order.

#33970: Match and place pending chat echoes with desktop's rule

After you send a message in a terminal chat, the phone shows a placeholder bubble until the agent records it. The phone now decides when that bubble is done with desktop's rule. A bubble that is never matched now sits at the bottom, as on desktop.

  • Echo matching (native-chat Fix update checker 406 error and add menu feedback #8). Before: the phone counted matching user rows across the whole loaded window, with its own glue matcher. Paging in an older identical "yes" could clear a new echo before its row landed. If an earlier send never landed, a combined row could clear the sends after it. Now: the phone matches only rows after the point each message was sent, anchored at the first open send, with pasted image paths stripped. This is desktop's rule.
    • native-chat-pending-occurrence.ts moved as-is to src/shared/.
    • The rule part of native-chat-pending.ts is now src/shared/native-chat-pending-sends.ts, including the 8-send cap as NATIVE_CHAT_PENDING_SEND_LIMIT. The cache and launch-prompt code stay in the renderer.
    • The mobile matcher, counters, GLUE_SLIDE_BUDGET and the baseline module are deleted. A small adapter in mobile-native-chat-pending-echo.ts maps phone sends to NativeChatPendingSend.
  • Unmatched echo placement (Fix excessive re-renders causing UI lag #26). Before: an echo the TUI never recorded stayed where it was sent (A1, hi, A2). Now: transcript rows, then the streaming bubble, then unmatched echoes (A1, A2, hi), the order desktop's messageSortRank produces. The phone appends its three groups in that order rather than re-sorting rows the host already ordered, so compareMessages is not lifted.

#33976: Run terminal chat model and effort pickers on desktop's option surface

The model and effort picker in a phone terminal chat now runs on desktop's code. Grok chats get pickers too, picks are saved as the next launch's defaults, and the labels match desktop ("Med", "XHigh").

  • Option labels (native-chat [P2] Duplicated "checking for updates" #35). Before: the phone showed the catalog's raw labels and fell back to "Options". Now: labels come from src/shared/native-chat-session-option-labels.ts, an English table plus a say callback desktop wraps with translate. The pill shows Med / XHigh / Min like desktop, and the effort sheet title is "Effort".
  • Terminal option pickers (Fix first worktree card top border cutoff #15). Before: the phone built pickers only for Claude, Codex and OMP and re-implemented option apply around a tracked previousModelId. Now: the desktop PTY option surface moved to src/shared, along with its appliers, option cache and dispatch types. That covers createNativeChatPtySessionOptions, createSessionOptionAppliers and resolveEffectiveNativeChatModelId. The phone builds one surface per tab from them, so Grok and any agent with a catalog get pickers. The renderer cache path stays as a re-export so its 16 importers don't change.
  • Launch defaults (Fix TypeScript error and linting issues in TabBar #34). Before: terminal-chat picks on the phone were never saved. Now: they're saved as the host's launch defaults through the existing nativeChatSessionOptionsWrite RPC, as desktop does with persistSelection / adoptModelAsLaunchDefault.
  • OMP and option-stamp copies (agent-sessions Add right sidebar with file explorer, source control, and Monaco editor #21, options items).
    • The OMP live model-switch gate comes from the shared surface; the mobile copy is deleted.
    • The OMP discovery mapping moved to src/shared/native-chat-discovered-catalog-models.ts. That keeps isDefault and contextWindowTokens, and authoritative discovery retires a persisted model it no longer lists.
    • The structured option stamp moved into structured-agent-session-option-state.ts.

#33977: Track structured chat option picks with desktop's pick bookkeeping

In a structured chat, changing the model and then the effort quickly from the phone used to drop the second change. A lost reply could also make the phone show a model the agent never switched to. The phone now tracks picks with desktop's bookkeeping.

  • Option pick bookkeeping (agent-sessions Add Orca logo and polish README header #13).
    • Before: the phone refused a second pick while any pick was in flight, committed a pick whose reply was lost (unknown), and re-read options only on fence, stamp or session change.
    • Now: the shared src/shared/structured-agent-session-option-pick-book.ts tracks pending picks per option, and desktop's use-structured-agent-session-options uses it too. A repeat of the same option waits, picks of different options go together, a lost reply doesn't count as done, and a stale reply commits only its own option.
    • The phone also re-reads options each turn and after the provider starts, and shows picks at once while the host is still starting the provider, as desktop does.
  • The write sequence stays in each hook, because the two mutate result shapes and readback logic differ.

Why

Desktop logic wins in the mobile/desktop parity audit. Each rule here lived twice and had drifted; each now has one copy in src/shared that desktop and the phone both use.

Linked Issue

Part of the mobile/desktop parity audit.

Visual Proof

No device captures for this fleet. Each change adopts desktop behaviour that already exists; the sections above name the desktop code each one follows.

Testing

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

Each folded PR moved desktop's tests with its shared rule and rewrote the mobile tests that pinned the old phone behaviour. Locally: changed-file lint, ratchets and the runtime catalog check pass, along with the mobile src/session and RPC recording tests and the root native-chat tests.

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

#33969: Use desktop's rules for chat tool rows, copy text and agent order

Mobile behavior removed (desktop wins):

  • A remembered agent no longer outranks the launch agent.
  • Copy no longer includes roster or background-task fallback twins, wordless provider frames or whitespace-only blocks. The phone still shows background-task twins as text until it gets a task row.
  • In grouped work runs, the header no longer counts ask calls.

Desktop behavior change: a WebSearch call whose only results are unsafe (e.g. ftp://x) no longer shows a caret that opens an empty panel. The shared rule uses the same sanitized list desktop's panel already rendered.

Not done here:

Compatibility: no wire or host change. Folder workspaces, SSH and all host OSes are unaffected.

#33970: Match and place pending chat echoes with desktop's rule

Mobile behavior removed (desktop wins):

  • An unmatched echo no longer stays where it was sent; it sits at the bottom.
  • Matching no longer counts the whole loaded window.
  • If an earlier send never lands, a combined row no longer clears the sends after it.
  • An echo is hidden once its row lands and pruned when the agent replies, instead of being removed at once.
  • Sends made while the transcript is still loading no longer re-point at the first loaded row; they fall back to send time, as on desktop.
  • At most 8 open echoes per chat; the oldest is dropped.

Desktop: no behavior change. Code moved; pendingSendsAsMessages is split so the phone can call visibleNativeChatPendingSends.

Compatibility: phone-local state only, no wire change. As on desktop over SSH, a send made while loading compares the phone's clock with host row times.

#33976: Run terminal chat model and effort pickers on desktop's option surface

Mobile behavior removed (desktop wins):

  • A terminal pick whose write or reply never came back is no longer committed.
  • The "Options" / raw-label placeholder in the pill is gone when no values are known.
  • A hook-reported OMP model that authoritative discovery doesn't list is dropped, as on desktop.
  • The per-tab option record cap went from 32 to the shared 128.

Phone-only gaps kept:

  • The phone keeps applying Claude hook-model reports. Desktop reads the terminal screen instead, which the phone can't do.
  • A Claude model switch is not saved as a launch default from the phone, because desktop confirms it on the terminal screen. Effort picks are saved.
  • The phone fetches model lists only for OMP and Grok. Doing it for Claude and Codex would mean a CLI probe on the host on every visit.

Desktop: no visible change. The effort label's translation default is now the literal 'Effort', which every locale already has.

Compatibility: no new wire fields. Discovery and settings-write failures are swallowed, so old hosts behave as before. The discovery reply schema accepts replies with or without catalogOrigin.

#33977: Track structured chat option picks with desktop's pick bookkeeping

Mobile behavior removed (desktop wins):

  • A structured pick whose reply never came back is no longer committed.
  • The phone no longer refuses a pick of a different option while one is in flight. The picker still greys out its controls while a pick is pending; that is presentation only.

Desktop: no behavior change; the hook calls the shared bookkeeping.

Compatibility: an old host without the status feed reports no start phase, so the phone behaves as before. No wire change.

Checklist

  • 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)

@AmoabaKelvin
AmoabaKelvin force-pushed the mobile-chat-option-picks branch 2 times, most recently from a2ffda0 to 4dc1c39 Compare October 27, 2026 01:20
@AmoabaKelvin
AmoabaKelvin marked this pull request as ready for review October 27, 2026 01:21
@coderabbitai

coderabbitai Bot commented Oct 27, 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
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3238cb57-e028-4808-859c-96f123f5aa86
Commits

Reviewing files that changed from the base of the PR and between 7672d28 and a631cdd.

Files selected for processing: 12
  • config/flaky-test-pattern-baseline.txt
  • mobile/src/session/MobileNativeChatFullContent.tsx
  • mobile/src/session/MobileNativeChatView.streaming-rows.test.ts
  • mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts.ts
  • mobile/src/session/native-chat/transcript/MobileNativeChatMessage.tsx
  • mobile/src/session/native-chat/transcript/MobileNativeChatMessageActionsSheet.tsx
  • mobile/src/session/native-chat/transcript/MobileNativeChatToolLine.tsx
  • mobile/src/session/native-chat/transcript/mobile-native-chat-message-plain-text.test.ts
  • mobile/src/session/native-chat/transcript/mobile-native-chat-message-plain-text.ts
  • mobile/src/session/native-chat/transcript/mobile-native-chat-pending-baseline.test.ts
  • mobile/src/session/native-chat/transcript/mobile-native-chat-pending-baseline.ts
  • mobile/src/session/native-chat/transcript/use-mobile-native-chat-turn-disclosure-opening-send.test.tsx
Files with no reviewable changes: 7
  • mobile/src/session/native-chat/transcript/mobile-native-chat-message-plain-text.test.ts
  • mobile/src/session/native-chat/transcript/mobile-native-chat-pending-baseline.test.ts
  • config/flaky-test-pattern-baseline.txt
  • mobile/src/session/native-chat/transcript/mobile-native-chat-pending-baseline.ts
  • mobile/src/session/native-chat/transcript/use-mobile-native-chat-turn-disclosure-opening-send.test.tsx
  • mobile/src/session/native-chat/transcript/mobile-native-chat-message-plain-text.ts
  • mobile/src/session/native-chat/transcript/MobileNativeChatToolLine.tsx

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

Walkthrough

The pull request moves native-chat behavior into shared modules. It centralizes pending-send reconciliation, session-option labels and surfaces, model discovery, structured-option pick tracking, availability checks, message-copy generation, tool rendering, output formatting, edit labels, task counts, and byte formatting. Mobile and renderer components adopt these helpers. Related tests and fixtures are updated, and obsolete mobile and renderer implementations are removed.

Priority: Normal

Merge Risk: Moderate · previous review a631c

Pending echoes and session-option updates can retain or display stale state in reachable failure and replacement races. These correctness risks should be fixed before merging.

Pre-merge checks: Passed 3 · Failed 1 · Inconclusive 1

Failed Failed checks: 1 warning · 1 inconclusive

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 20.59% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surv… Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check Inconclusive The description follows the template sections: ELI5, What Changed, Why, Linked Issue, Visual Proof, Testing, AI Disclosure section, Review, Agent skill upstream boundary, Notes, and Checklist. It expl… Add a linked issue (replace 'Part of the mobile/desktop parity audit' with a 'Fixes #NNN' or 'Refs' line that points to an actual issue). Attach before/after captures or a video for the mobile UI changes (tool-row labels, clipped-output not…
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title is "fix(mobile): use desktop's rules for chat tool rows, pending echoes and session option picks". It states the main change: mobile native chat adopts the desktop rules for tool rows, pendi…
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.
Full details: Title check

Explanation

The title is "fix(mobile): use desktop's rules for chat tool rows, pending echoes and session option picks". It states the main change: mobile native chat adopts the desktop rules for tool rows, pending echoes, and option picks. The raw summary and PR objectives match this. The title is long (92 characters) but specific and accurate. It does not cover the copy, file-size, and agent-order changes, which is acceptable.

Full details: Docstring Coverage

Explanation

Docstring coverage is 20.59% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 68 functions across 54 files.

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Full details: Description check

Explanation

The description follows the template sections: ELI5, What Changed, Why, Linked Issue, Visual Proof, Testing, AI Disclosure section, Review, Agent skill upstream boundary, Notes, and Checklist. It explains the changes in detail, with before/after behavior, mechanisms, and compatibility notes. Gaps: the Linked Issue section says only "Part of the mobile/desktop parity audit" and has no 'Fixes #' issue link, which the template requires for outside contributors. Visual Proof says no device captures were made. The template requires a BEFORE/AFTER for UI or behavior changes, and the text gives no reason beyond 'no device captures for this fleet'. Testing leaves the manual-test box unchecked and the pnpm lint/typecheck/test/build checklist item unchecked. The Review section is empty. The AI Disclosure section is empty, though it is optional for internal contributors.

Resolution

Add a linked issue (replace 'Part of the mobile/desktop parity audit' with a 'Fixes #NNN' or 'Refs' line that points to an actual issue). Attach before/after captures or a video for the mobile UI changes (tool-row labels, clipped-output note, option pill labels, pending bubble placement), or write N/A with a specific reason. State which platforms were tested manually and check the manual-test box, or explain why it is not checked. Run pnpm lint, pnpm typecheck, pnpm test, and pnpm build locally, or state that CI covers them and check that box. Complete the AI Disclosure section if an AI model was used to make the changes, or confirm that the author is a StablyAI team member. Remove or fill in the empty Review section.

Finishing Touches: 💡 2
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · 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.

@AmoabaKelvin
AmoabaKelvin force-pushed the mobile-chat-option-picks branch from 4dc1c39 to db5253c Compare October 27, 2026 01:31

@coderabbitai coderabbitai 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.

Actionable comments posted: 2


Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d773d77d-f200-4e8c-8369-1b1689a7238a
Commits

Reviewing files that changed from the base of the PR and between 0cee6cb and db5253c.

Files selected for processing: 187
  • mobile/src/session/MobileNativeChatAsk.test.tsx
  • mobile/src/session/MobileNativeChatAsk.tsx
  • mobile/src/session/MobileNativeChatAskOptionRow.tsx
  • mobile/src/session/MobileNativeChatDiffCard.tsx
  • mobile/src/session/MobileNativeChatFullContent.tsx
  • mobile/src/session/MobileNativeChatMessage.tsx
  • mobile/src/session/MobileNativeChatMessageActionsSheet.tsx
  • mobile/src/session/MobileNativeChatPromptCard.tsx
  • mobile/src/session/MobileNativeChatStructuredAsk.tsx
  • mobile/src/session/MobileNativeChatTaskList.tsx
  • mobile/src/session/MobileNativeChatToolLine.tsx
  • mobile/src/session/MobileNativeChatToolRun.tsx
  • mobile/src/session/MobileNativeChatView.prompt-presentation.test.ts
  • mobile/src/session/MobileNativeChatView.streaming-rows.test.ts
  • mobile/src/session/MobileNativeChatView.tsx
  • mobile/src/session/__mocks__/mobile-prompt-controller.ts
  • mobile/src/session/mobile-native-chat-controller-contract.ts
  • mobile/src/session/mobile-native-chat-merged-snapshot-parity.test.ts
  • mobile/src/session/mobile-native-chat-message-plain-text.test.ts
  • mobile/src/session/mobile-native-chat-message-plain-text.ts
  • mobile/src/session/mobile-native-chat-pending-baseline.test.ts
  • mobile/src/session/mobile-native-chat-pending-baseline.ts
  • mobile/src/session/mobile-native-chat-permission.test.ts
  • mobile/src/session/mobile-native-chat-permission.ts
  • mobile/src/session/mobile-native-chat-prompt-dismissals.ts
  • mobile/src/session/mobile-native-chat-question.test.ts
  • mobile/src/session/mobile-native-chat-question.ts
  • mobile/src/session/mobile-native-chat-render-data.test.ts
  • mobile/src/session/mobile-native-chat-render-data.ts
  • mobile/src/session/mobile-omp-session-catalog.ts
  • mobile/src/session/mobile-prompt-controller.test.ts
  • mobile/src/session/mobile-session-option-records.ts
  • mobile/src/session/mobile-structured-actionable-prompt.ts
  • mobile/src/session/mobile-structured-agent-prompts-grouped.test.ts
  • mobile/src/session/mobile-structured-agent-prompts.ts
  • mobile/src/session/mobile-structured-agent-session-cancel.ts
  • mobile/src/session/mobile-structured-agent-session-contract.ts
  • mobile/src/session/mobile-structured-grouped-question.test.ts
  • mobile/src/session/mobile-structured-grouped-question.ts
  • mobile/src/session/native-chat/composer/MobileNativeChatComposer.test.ts
  • mobile/src/session/native-chat/composer/mobile-native-chat-draft-reconcile.test.ts
  • mobile/src/session/native-chat/composer/mobile-native-chat-draft-reconcile.ts
  • mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts-glued-pending.test.ts
  • mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts.ts
  • mobile/src/session/native-chat/input/MobileNativeChatSessionOptionPickers.tsx
  • mobile/src/session/native-chat/input/MobileNativeChatSessionOptionRows.tsx
  • mobile/src/session/native-chat/input/MobileNativeChatSessionOptionSegments.tsx
  • mobile/src/session/native-chat/input/mobile-native-chat-session-option-labels.ts
  • mobile/src/session/native-chat/input/mobile-native-chat-session-option-persistence.ts
  • mobile/src/session/native-chat/input/use-mobile-native-chat-session-option-controller.ts
  • mobile/src/session/native-chat/input/use-mobile-native-chat-session-options.test.ts
  • mobile/src/session/native-chat/input/use-mobile-native-chat-session-options.ts
  • mobile/src/session/native-chat/mobile-native-chat-eligibility.test.ts
  • mobile/src/session/native-chat/mobile-native-chat-eligibility.ts
  • mobile/src/session/native-chat/mobile-native-chat-pending-echo.test.ts
  • mobile/src/session/native-chat/mobile-native-chat-pending-echo.ts
  • mobile/src/session/native-chat/mobile-native-chat-pending-pasted-content.test.ts
  • mobile/src/session/native-chat/mobile-native-chat-pending-retirement.test.ts
  • mobile/src/session/native-chat/mobile-native-chat-pending-retirement.ts
  • mobile/src/session/native-chat/mobile-native-chat-send.ts
  • mobile/src/session/native-chat/use-mobile-native-chat-unconfirmed-sends.ts
  • mobile/src/session/use-mobile-native-chat-answer-send.test.ts
  • mobile/src/session/use-mobile-native-chat-answer-send.ts
  • mobile/src/session/use-mobile-native-chat-ask-dismiss.test.ts
  • mobile/src/session/use-mobile-native-chat-ask-dismiss.ts
  • mobile/src/session/use-mobile-native-chat-controller.test.ts
  • mobile/src/session/use-mobile-native-chat-controller.ts
  • mobile/src/session/use-mobile-native-chat-message-send.test.ts
  • mobile/src/session/use-mobile-native-chat-message-send.ts
  • mobile/src/session/use-mobile-native-chat-model-discovery.test.ts
  • mobile/src/session/use-mobile-native-chat-model-discovery.ts
  • mobile/src/session/use-mobile-native-chat-prompt-cards.ts
  • mobile/src/session/use-mobile-native-chat-prompt-dismiss.ts
  • mobile/src/session/use-mobile-native-chat-prompt-presentation.ts
  • mobile/src/session/use-mobile-native-chat-prompts.test.ts
  • mobile/src/session/use-mobile-native-chat-prompts.ts
  • mobile/src/session/use-mobile-native-chat-readability.ts
  • mobile/src/session/use-mobile-native-chat-turn-disclosure-opening-send.test.tsx
  • mobile/src/session/use-mobile-omp-model-discovery.ts
  • mobile/src/session/use-mobile-structured-agent-options.first-frame.test.ts
  • mobile/src/session/use-mobile-structured-agent-options.permission-mode.test.ts
  • mobile/src/session/use-mobile-structured-agent-options.test.ts
  • mobile/src/session/use-mobile-structured-agent-options.ts
  • mobile/src/session/use-mobile-structured-agent-session-prompt-cancel.test.tsx
  • mobile/src/session/use-mobile-structured-agent-session.test.tsx
  • mobile/src/session/use-mobile-structured-agent-session.ts
  • mobile/src/session/use-mobile-structured-background-tasks.ts
  • mobile/src/session/use-mobile-structured-native-chat-send-bridge.test.ts
  • mobile/src/session/use-mobile-structured-option-state.ts
  • mobile/src/session/use-mobile-structured-prompt-responses.test.tsx
  • mobile/src/session/use-mobile-structured-prompt-responses.ts
  • mobile/src/session/use-mobile-structured-session-option-stamp.ts
  • src/main/runtime/rpc/methods/terminal/terminal-send-method.ts
  • src/main/runtime/rpc/methods/terminal/terminal-send-question-answered.ts
  • src/main/runtime/rpc/terminal-send-question-answered.test.ts
  • src/renderer/src/components/native-chat/NativeChatDiffCard.tsx
  • src/renderer/src/components/native-chat/NativeChatMessageRow.tsx
  • src/renderer/src/components/native-chat/NativeChatModelCombobox.tsx
  • src/renderer/src/components/native-chat/NativeChatQuestionCard.tsx
  • src/renderer/src/components/native-chat/NativeChatResolvedView.tsx
  • src/renderer/src/components/native-chat/NativeChatSessionOptionPickers.tsx
  • src/renderer/src/components/native-chat/NativeChatSessionOptionRows.tsx
  • src/renderer/src/components/native-chat/NativeChatStructuredQuestionCard.tsx
  • src/renderer/src/components/native-chat/NativeChatTaskList.tsx
  • src/renderer/src/components/native-chat/NativeChatToolLine.tsx
  • src/renderer/src/components/native-chat/NativeChatToolOutput.tsx
  • src/renderer/src/components/native-chat/NativeChatToolRun.tsx
  • src/renderer/src/components/native-chat/claude-model-switch-confirmation.ts
  • src/renderer/src/components/native-chat/native-chat-context-command.test.tsx
  • src/renderer/src/components/native-chat/native-chat-dismiss-key.ts
  • src/renderer/src/components/native-chat/native-chat-interactive-prompt.test.ts
  • src/renderer/src/components/native-chat/native-chat-interactive-prompt.ts
  • src/renderer/src/components/native-chat/native-chat-launch-default-adoption.test.ts
  • src/renderer/src/components/native-chat/native-chat-message-copy-text.ts
  • src/renderer/src/components/native-chat/native-chat-pane-resolution.ts
  • src/renderer/src/components/native-chat/native-chat-pending.test.ts
  • src/renderer/src/components/native-chat/native-chat-pending.ts
  • src/renderer/src/components/native-chat/native-chat-pty-retired-model.test.ts
  • src/renderer/src/components/native-chat/native-chat-retire-persisted-model.test.ts
  • src/renderer/src/components/native-chat/native-chat-session-assembler.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-cache.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-discovery.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-enrichment.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-labels-text.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-labels.ts
  • src/renderer/src/components/native-chat/native-chat-stopped-before-start-row.ts
  • src/renderer/src/components/native-chat/native-chat-tool-line-label.ts
  • src/renderer/src/components/native-chat/omp-model-switch-capability.test.ts
  • src/renderer/src/components/native-chat/structured-agent-session-message-projection.ts
  • src/renderer/src/components/native-chat/structured-agent-session-prompt-response.ts
  • src/renderer/src/components/native-chat/structured-agent-session-status-hooks.ts
  • src/renderer/src/components/native-chat/structured-conversation-command-send.ts
  • src/renderer/src/components/native-chat/use-native-chat-interactive-prompt-card.ts
  • src/renderer/src/components/native-chat/use-native-chat-local-command-answer.ts
  • src/renderer/src/components/native-chat/use-native-chat-pending-delivery.ts
  • src/renderer/src/components/native-chat/use-native-chat-picker-command-dispatch.ts
  • src/renderer/src/components/native-chat/use-native-chat-prompt-card-presentation.ts
  • src/renderer/src/components/native-chat/use-native-chat-pty-composer-send.ts
  • src/renderer/src/components/native-chat/use-native-chat-session-option-command.ts
  • src/renderer/src/components/native-chat/use-native-chat-session-options.test.ts
  • src/renderer/src/components/native-chat/use-native-chat-session-options.ts
  • src/renderer/src/components/native-chat/use-native-chat-toggle-shortcut.surface-owner.test.ts
  • src/renderer/src/components/native-chat/use-native-chat-toggle-shortcut.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-option-state.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-options.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-send-options.test.tsx
  • src/renderer/src/components/native-chat/use-structured-agent-session-send-options.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session.ts
  • src/renderer/src/components/status-bar/workspace-space-format.ts
  • src/renderer/src/components/tab-bar/tab-bar-item-surface.tsx
  • src/renderer/src/components/terminal-pane/use-terminal-pane-chat-state.ts
  • src/renderer/src/i18n/en-runtime-required.json
  • src/shared/format-bytes.ts
  • src/shared/native-chat-ask-card-rules.ts
  • src/shared/native-chat-availability.test.ts
  • src/shared/native-chat-availability.ts
  • src/shared/native-chat-discovered-catalog-models.ts
  • src/shared/native-chat-interactive-prompt.test.ts
  • src/shared/native-chat-interactive-prompt.ts
  • src/shared/native-chat-message-copy-text.test.ts
  • src/shared/native-chat-message-copy-text.ts
  • src/shared/native-chat-pending-occurrence.test.ts
  • src/shared/native-chat-pending-occurrence.ts
  • src/shared/native-chat-pending-pasted-content.test.ts
  • src/shared/native-chat-pending-sends.test.ts
  • src/shared/native-chat-pending-sends.ts
  • src/shared/native-chat-prompt-dismiss-key.test.ts
  • src/shared/native-chat-prompt-dismiss-key.ts
  • src/shared/native-chat-pty-session-options.test.ts
  • src/shared/native-chat-pty-session-options.ts
  • src/shared/native-chat-session-option-apply.ts
  • src/shared/native-chat-session-option-cache.ts
  • src/shared/native-chat-session-option-dispatch.ts
  • src/shared/native-chat-session-option-labels.test.ts
  • src/shared/native-chat-session-option-labels.ts
  • src/shared/native-chat-stopped-before-start.ts
  • src/shared/native-chat-task-list.ts
  • src/shared/native-chat/tools/native-chat-edit-model.ts
  • src/shared/native-chat/tools/native-chat-tool-activity.ts
  • src/shared/native-chat/tools/native-chat-tool-line-view.ts
  • src/shared/native-chat/tools/native-chat-tool-output.ts
  • src/shared/native-chat/tools/native-chat-tool-run-header.ts
  • src/shared/structured-agent-question-card.ts
  • src/shared/structured-agent-session-message-projection.ts
  • src/shared/structured-agent-session-option-pick-book.test.ts
  • src/shared/structured-agent-session-option-pick-book.ts
  • src/shared/structured-agent-session-option-state.ts
Files with no reviewable changes: 24
  • mobile/src/session/mobile-structured-agent-prompts-grouped.test.ts
  • mobile/src/session/mobile-structured-grouped-question.test.ts
  • mobile/src/session/mobile-native-chat-permission.test.ts
  • mobile/src/session/use-mobile-native-chat-turn-disclosure-opening-send.test.tsx
  • mobile/src/session/native-chat/mobile-native-chat-pending-pasted-content.test.ts
  • mobile/src/session/mobile-native-chat-pending-baseline.test.ts
  • mobile/src/session/native-chat/mobile-native-chat-pending-echo.test.ts
  • mobile/src/session/mobile-native-chat-render-data.test.ts
  • mobile/src/session/mobile-native-chat-message-plain-text.ts
  • mobile/src/session/mobile-native-chat-message-plain-text.test.ts
  • mobile/src/session/use-mobile-omp-model-discovery.ts
  • mobile/src/session/use-mobile-structured-agent-session-prompt-cancel.test.tsx
  • src/renderer/src/components/native-chat/native-chat-dismiss-key.ts
  • mobile/src/session/mobile-native-chat-merged-snapshot-parity.test.ts
  • mobile/src/session/native-chat/mobile-native-chat-send.ts
  • mobile/src/session/mobile-omp-session-catalog.ts
  • mobile/src/session/mobile-native-chat-pending-baseline.ts
  • mobile/src/session/mobile-session-option-records.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-labels.ts
  • mobile/src/session/mobile-structured-grouped-question.ts
  • src/renderer/src/components/native-chat/structured-agent-session-message-projection.ts
  • mobile/src/session/native-chat/mobile-native-chat-pending-retirement.ts
  • mobile/src/session/mobile-native-chat-question.test.ts
  • mobile/src/session/native-chat/mobile-native-chat-pending-retirement.test.ts

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

Comment on lines +176 to +180
const tailIndex = foldedBoundaryIndex(messages, messageIndexById, entry.afterMessageId)
// Same boundary-relative occurrence as the shared pending rule, so older identical rows cannot bind.
const candidate = candidates.filter(
(message) => tailIndex === undefined || (messageIndexById.get(message.id) ?? -1) > tailIndex
)[nativeChatPendingOccurrence(entry, 0) - 1]

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.

Minor · Functional Correctness · Quick win

Supported by static analysis

Script executed:

sed -n 100,200p mobile/src/session/native-chat/composer/mobile-native-chat-draft-reconcile.ts
sed -n 36,100p src/shared/native-chat-pending-sends.ts

Repository: stablyai/orca

Length of output: 6551


Fall back to the send time when the boundary row is missing.

When foldedBoundaryIndex returns undefined, the current filter accepts every matching candidate. Occurrence 1 can therefore bind the oldest identical image prompt in the loaded window. Use the same timestamp fallback as messagesAfterPendingBoundary so an older prompt cannot receive the preview URI when the boundary row is paged out.

@AmoabaKelvin
AmoabaKelvin force-pushed the mobile-chat-option-picks branch 4 times, most recently from 6de9641 to 5643003 Compare October 27, 2026 04:40

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

Minor · Schedule readback when a stale accepted… · use-mobile-structured-agent-options.ts:226-230

mobile/src/session/use-mobile-structured-agent-options.ts:226-230
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Schedule readback when a stale accepted response discards returned option values.

A stale model response can commit only its own option while discarding a returned effort value. The current completion code requires isCurrent(), so that response cannot latch readback. If the newer effort write then fails, both writes settle without an options read. Mobile can display a value different from the host until a later optionStamp or turnId refresh.

Keep the shownAtOnce behavior for immediate-starting picks. Add a separate flag for discarded returned values. The existing pick-book commit still prevents the readback from overwriting a newer pick.

Suggested fix
       let readsBack = shownAtOnce
+      let discardedReturnedOptions = false
       try {
...
         const committed =
           sameRecord() && result.sameFence
             ? structuredOptionPickCommit(optionPicks.current, pick, result.value.options)
             : null
+        discardedReturnedOptions =
+          result.sameFence &&
+          committed !== null &&
+          Object.keys(result.value.options ?? {}).some((key) => !(key in committed))
         if (committed) {
...
-          writes.current.readback ||= readsBack && isCurrent()
+          writes.current.readback ||= readsBack && (isCurrent() || discardedReturnedOptions)

Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 76fc3a21-bced-4ace-b379-21f34eed67f7
Commits

Reviewing files that changed from the base of the PR and between db5253c and 5643003.

Files selected for processing: 14
  • config/flaky-test-pattern-baseline.txt
  • mobile/src/session/MobileNativeChatToolRun.tsx
  • mobile/src/session/MobileNativeChatView.streaming-rows.test.ts
  • mobile/src/session/MobileNativeChatView.tsx
  • mobile/src/session/native-chat/input/MobileNativeChatTaskList.tsx
  • mobile/src/session/use-mobile-native-chat-controller.test.ts
  • mobile/src/session/use-mobile-native-chat-readability.ts
  • mobile/src/session/use-mobile-structured-agent-session.ts
  • src/renderer/src/components/native-chat/native-chat-session-assembler.ts
  • src/renderer/src/components/native-chat/use-structured-agent-session-options.ts
  • src/renderer/src/i18n/en-runtime-required.json
  • src/shared/native-chat/input/native-chat-task-list.ts
  • tests/e2e/native-chat-startup-option-pickers.unit.test.ts
  • tests/e2e/structured-permission-report-publication.unit.test.ts
Files with no reviewable changes: 2
  • config/flaky-test-pattern-baseline.txt
  • mobile/src/session/use-mobile-structured-agent-session.ts
Files skipped from review as they are similar to previous changes: 1
  • src/renderer/src/i18n/en-runtime-required.json

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

Comment on lines +158 to +160
const committed =
result && sameRecord()
? structuredOptionPickCommit(optionPicks.current, pick, result.options)

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.

Minor · Data Integrity & Integration · Quick win

Supported by static analysis

Script executed:

sed -n '1,230p' src/shared/structured-agent-session-option-pick-book.ts
sed -n '120,335p' src/renderer/src/components/native-chat/use-structured-agent-session-options.ts

Repository: stablyai/orca

Length of output: 10223


Script executed:

rg -n -F -e 'beginOptionWrite' -e 'finishWrite' -e 'readback' -e 'scheduleRead' -- src/renderer/src/components/native-chat/ || test "$?" -eq 1
echo '---'
cat -n src/renderer/src/components/native-chat/use-structured-agent-session-option-state.ts | sed -n '1,260p'

Repository: stablyai/orca

Length of output: 15195


Read back after a stale reply discards returned values.

When an older accepted pick returns values that are not committed, no readback is requested. A later failed pick does not request one either. Local effort can then stay on the pre-pick value while the host holds the returned value. The next option read, which runs on a turn or host-option change, corrects it. Request a readback when the accepted reply's values are not all committed.

🐛 Suggested fix
       let result: AgentSessionOptionResult | null = null
+      let discardsReply = false
       try {
         result = await mutate<AgentSessionOptionResult>(
           'agentSession.setOption',
           'agentSession.setOption',
           { key: id, value: encoded }
         )
         const committed =
           result && sameRecord()
             ? structuredOptionPickCommit(optionPicks.current, pick, result.options)
             : null
+        discardsReply =
+          Boolean(result) &&
+          !(committed && Object.keys(result?.options ?? {}).every((key) => key in committed))
         if (committed) {
-        finishWrite(isCurrent() && Boolean(result || shownAtOnce))
+        finishWrite((isCurrent() && Boolean(result || shownAtOnce)) || discardsReply)

@AmoabaKelvin
AmoabaKelvin force-pushed the mobile-chat-option-picks branch 3 times, most recently from d1f4337 to 7672d28 Compare October 27, 2026 13:30

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

Minor · Retire the old surface when switch capability… · use-mobile-native-chat-session-options.ts:186-193

mobile/src/session/native-chat/input/use-mobile-native-chat-session-options.ts:186-193
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Retire the old surface when switch capability changes.

If canSwitchOmpModel changes during a pending pick, this branch creates a new surface but leaves the old entry active. When the old command completes, its surface can publish its separate record to the same scope cache after the replacement surface has written newer state. Retire the replaced entry for either change, and reconcile an accepted command through the active surface or a fresh report. (raw.githubusercontent.com)


Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 04bdf8bf-293b-4320-a33c-c26ced4d9105
Commits

Reviewing files that changed from the base of the PR and between d1f4337 and 7672d28.

Files selected for processing: 34
  • mobile/src/session/MobileNativeChatDiffCard.tsx
  • mobile/src/session/MobileNativeChatFullContent.tsx
  • mobile/src/session/MobileNativeChatView.streaming-rows.test.ts
  • mobile/src/session/mobile-native-chat-message-plain-text.ts
  • mobile/src/session/mobile-session-option-records.ts
  • mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts-glued-pending.test.ts
  • mobile/src/session/native-chat/composer/use-mobile-native-chat-drafts.ts
  • mobile/src/session/native-chat/input/MobileNativeChatSessionOptionPickers.tsx
  • mobile/src/session/native-chat/input/MobileNativeChatSessionOptionRows.tsx
  • mobile/src/session/native-chat/input/MobileNativeChatSessionOptionSegments.tsx
  • mobile/src/session/native-chat/input/mobile-native-chat-session-option-labels.ts
  • mobile/src/session/native-chat/input/mobile-native-chat-session-option-persistence.ts
  • mobile/src/session/native-chat/input/use-mobile-native-chat-session-options.ts
  • mobile/src/session/native-chat/transcript/MobileNativeChatToolLine.tsx
  • mobile/src/session/native-chat/transcript/MobileNativeChatToolRun.tsx
  • src/renderer/src/components/native-chat/NativeChatModelCombobox.tsx
  • src/renderer/src/components/native-chat/native-chat-message-copy-text.ts
  • src/renderer/src/components/native-chat/native-chat-pending.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-cache.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-enrichment.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-labels.ts
  • src/renderer/src/components/native-chat/use-native-chat-picker-command-dispatch.ts
  • src/renderer/src/components/native-chat/use-native-chat-pty-composer-send.ts
  • src/renderer/src/components/native-chat/use-native-chat-session-options.ts
  • src/renderer/src/i18n/en-runtime-required.json
  • src/shared/native-chat-discovered-catalog-models.ts
  • src/shared/native-chat-message-copy-text.ts
  • src/shared/native-chat-pty-session-options.test.ts
  • src/shared/native-chat-pty-session-options.ts
  • src/shared/native-chat-session-option-apply.ts
  • src/shared/native-chat-session-option-cache.ts
  • src/shared/native-chat-session-option-labels.test.ts
  • src/shared/native-chat-session-option-labels.ts
  • src/shared/structured-agent-session-option-state.ts
Files with no reviewable changes: 3
  • mobile/src/session/mobile-session-option-records.ts
  • mobile/src/session/mobile-native-chat-message-plain-text.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-labels.ts
Files skipped from review as they are similar to previous changes: 2
  • src/shared/structured-agent-session-option-state.ts
  • src/renderer/src/i18n/en-runtime-required.json

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

Mobile reuses it instead of its own matcher.
…hed ones

Uses desktop's rule: rows before the send no longer retire an echo, a send that
never lands no longer lets later glued sends retire, and an unmatched echo sits
below later turns.
… at eight

Same input and bound as desktop; each open send rescans the transcript.
Mobile's options pill now shortens effort levels (Med, XHigh, Min) and names
choices and options the way desktop does, from one English table that desktop
translates.
…p surface

The terminal-chat option surface, its appliers, the option cache and the
dispatch types move to src/shared, and the phone builds its pickers from them.
Grok and every other agent with a catalog now get model and effort pickers on
the phone, picks are saved as the host's launch defaults, the OMP live switch
gate and discovery mapping come from one copy, and authoritative discovery
retires persisted models it no longer lists. The option stamp moves to shared.
The phone keeps one option surface per chat, so a pick that lands after leaving
and returning shows there, and a picker command only switches the chat it came
from. Discovered models merge with the seed catalog as on desktop, so Grok keeps
its effort picker. A Claude model switch the phone cannot confirm is never
saved as a launch default.
A tab that runs another agent drops its kept option surfaces, report markers
and cached record, so a fresh session shows its own model. A pick that lands
after the phone moved to another chat is not saved as a launch default.
A write that lands after its tab started another agent no longer publishes the
old agent's record, and a changed OMP switch capability rebuilds the chat's
surface from the cache instead of reviving an older one.
Desktop translation pieces use literal English defaults so the localization gate can read them, the selected-choice lookup is shared once, and the phone keeps one option surface per tab with the agent change detected from the cached record.
@AmoabaKelvin
AmoabaKelvin force-pushed the mobile-chat-option-picks branch from 8494f24 to a631cdd Compare October 27, 2026 14:26
…mobile

Desktop and the phone now track picks per option through one shared book: a
repeat of an option on its way waits, other options go together, a lost reply
is not a pick done, and a stale reply only commits its own option. The phone
also re-reads options each turn and after the provider starts, and shows picks
at once while the host is still starting the provider.
…dget and pass the phone turn in the e2e harness
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