You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(mobile): use desktop's rules for chat tool rows, pending echoes and session option picks - #33977
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.
Tool-run header (native-chat Add Ghostty-style drag-to-reorder terminal panes #24). Desktop and mobile each had their own copy of the live/count/"Result"/failed/interrupted rules. Both now use nativeChatToolRunHeader in src/shared/native-chat/tools/native-chat-tool-run-header.ts; "Result" joins the shared copy table.
Tool-line detail (Fix GitHub status refresh on activity #42). A new shared nativeChatToolLineView decides failed, results, whether the row opens, and the result preview, for both apps. It builds on sanitized toolWebSearchResults, the same list desktop's results panel already renders.
Clipped output note (We don't sync the status of the closed gh issue on the side panel #41). Before: the phone showed "Showing {n} of {bytes} bytes." Now: "Showing 64.0 KB of 2.30 MB.", like desktop. formatBytes moved to src/shared/format-bytes.ts (the old file re-exports it). The payload picker, clip rule and copy are in src/shared/native-chat/tools/native-chat-tool-output.ts.
Message Copy (Being able to see previous agent sessions whenever I open a new worktree #27). Before: the phone joined every text block. Now: it uses desktop's nativeChatMessageCopyText (moved to src/shared/native-chat-message-copy-text.ts). That drops wordless provider frames, roster/background-task fallback twins and whitespace-only blocks.
#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.
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.
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:
Source control & file viewer console is not very discoverable #36's terminal-title fallback is parked. The phone only receives the tab's display title, not the pane's own title. Doing it safely needs the host to send a pane-scoped title agent per leaf, which is a separate main-process change.
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)
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.
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: 3 · 1 · 1
Failed checks: 1 warning · 1 inconclusive
Check name
Status
Explanation
Resolution
Docstring Coverage
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
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 checks: 3 passed
Check name
Status
Explanation
Title check
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
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
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.
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 1 remain after this review.
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.
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.
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.
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
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) {
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.
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review.
AmoabaKelvin
changed the title
fix(mobile): track structured chat option picks with desktop's pick bookkeeping
fix(mobile): use desktop's rules for chat tool rows, pending echoes and session option picks
Oct 27, 2026
…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.
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.
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
mainkeeps 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.
nativeChatToolRunHeaderinsrc/shared/native-chat/tools/native-chat-tool-run-header.ts; "Result" joins the shared copy table.nativeChatToolLineViewdecides failed, results, whether the row opens, and the result preview, for both apps. It builds on sanitizedtoolWebSearchResults, the same list desktop's results panel already renders.formatBytesmoved tosrc/shared/format-bytes.ts(the old file re-exports it). The payload picker, clip rule and copy are insrc/shared/native-chat/tools/native-chat-tool-output.ts.native-chat-edit-model.tsandnative-chat-task-list.ts.nativeChatMessageCopyText(moved tosrc/shared/native-chat-message-copy-text.ts). That drops wordless provider frames, roster/background-task fallback twins and whitespace-only blocks.isNativeChatTranscriptLocalReadable.src/shared/native-chat-availability.ts. The phone now tries the live agent, then the launch agent, then its remembered agent last. The remembered slot stays: it covers host frames that drop the agent type (fix(mobile): keep a terminal tab's chat identity while its handle is unchanged #32251).structuredSessionForegroundCommandsfilter, like desktop. The running Codex foreground shell no longer shows in the strip mid-turn (the jump Stop native chat jumping when Codex starts a foreground command #26503 fixed on desktop).#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.
native-chat-pending-occurrence.tsmoved as-is tosrc/shared/.native-chat-pending.tsis nowsrc/shared/native-chat-pending-sends.ts, including the 8-send cap asNATIVE_CHAT_PENDING_SEND_LIMIT. The cache and launch-prompt code stay in the renderer.GLUE_SLIDE_BUDGETand the baseline module are deleted. A small adapter inmobile-native-chat-pending-echo.tsmaps phone sends toNativeChatPendingSend.messageSortRankproduces. The phone appends its three groups in that order rather than re-sorting rows the host already ordered, socompareMessagesis 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").
src/shared/native-chat-session-option-labels.ts, an English table plus asaycallback desktop wraps withtranslate. The pill shows Med / XHigh / Min like desktop, and the effort sheet title is "Effort".previousModelId. Now: the desktop PTY option surface moved tosrc/shared, along with its appliers, option cache and dispatch types. That coverscreateNativeChatPtySessionOptions,createSessionOptionAppliersandresolveEffectiveNativeChatModelId. 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.nativeChatSessionOptionsWriteRPC, as desktop does withpersistSelection/adoptModelAsLaunchDefault.src/shared/native-chat-discovered-catalog-models.ts. That keepsisDefaultandcontextWindowTokens, and authoritative discovery retires a persisted model it no longer lists.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.
unknown), and re-read options only on fence, stamp or session change.src/shared/structured-agent-session-option-pick-book.tstracks pending picks per option, and desktop'suse-structured-agent-session-optionsuses 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.mutateresult 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/sharedthat 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
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/sessionand RPC recording tests and the root native-chat tests.Agent skill upstream boundary
Notes
#33969: Use desktop's rules for chat tool rows, copy text and agent order
Mobile behavior removed (desktop wins):
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):
Desktop: no behavior change. Code moved;
pendingSendsAsMessagesis split so the phone can callvisibleNativeChatPendingSends.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):
Phone-only gaps kept:
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):
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
N/Awith reasonpnpm lint,pnpm typecheck,pnpm test, andpnpm buildpass (or CI will cover; local preferred)