Skip to content

fix(mobile): run terminal chat model and effort pickers on desktop's option surface - #33976

Closed
AmoabaKelvin wants to merge 29 commits into
mainfrom
mobile-chat-session-options
Closed

AmoabaKelvin wants to merge 29 commits into
mainfrom
mobile-chat-session-options

Conversation

@AmoabaKelvin

@AmoabaKelvin AmoabaKelvin commented Oct 26, 2026 •

Copy link
Copy Markdown
Collaborator
Files Added Deleted Net
Test 33 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​962 $\color{#cf222e}{\Huge{\mathbf{−}}}$​1614 $\color{#cf222e}{\Huge{\mathbf{−}}}$​652
Prod 85 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​1704 $\color{#cf222e}{\Huge{\mathbf{−}}}$​1765 $\color{#cf222e}{\Huge{\mathbf{−}}}$​61

Stacked on #33970: review the commits after 04224b7.

ELI5

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").

What Changed

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

Why

Desktop logic wins in the mobile/desktop parity audit. The phone's own apply path missed Grok, couldn't set effort before a model report, and never saved picks. Running the desktop surface removes that copy.

Linked Issue

Part of the mobile/desktop parity audit

Visual Proof

No device captures for this fleet. The change adopts desktop's existing behavior: native-chat-pty-session-options.ts, native-chat-session-option-apply.ts and native-chat-session-option-labels.ts.

Testing

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

Desktop option tests moved with the shared modules. Mobile tests that pinned the old apply path are rewritten. New mobile tests cover per-tab surfaces, agent changes and retired surfaces, and the worker confirmed they fail without their fixes. Focused root option tests and mobile src/session pass.

AI Disclosure

Review

Codex review, 3 rounds, all findings fixed:

  • Grok lost its effort picker after discovery.
  • A pick that landed after leaving and returning to a tab was lost.
  • Picker completion could switch the wrong tab.
  • An unconfirmed Claude switch could be saved as a launch default.
  • A late pick could be saved to another host's defaults.
  • An agent change didn't reset the tab.
  • A retired surface's late write could overwrite the new agent's cache.
  • An OMP capability flip could bring back an older selection.

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

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.

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)

@AmoabaKelvin
AmoabaKelvin force-pushed the mobile-chat-session-options branch 2 times, most recently from 3321b66 to b02a180 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 →

Walkthrough

The pull request moves pending-send reconciliation and session-option logic into shared native-chat modules and updates mobile and renderer integrations. It adds shared helpers for message copying, tool presentation, output sizing, availability, and other UI calculations. Mobile pending sends now use transcript boundaries and timestamps. The change also updates model discovery and settings persistence, removes superseded mobile and renderer modules and tests, and updates related test fixtures and runtime strings.

Priority: Normal

Merge Risk: Moderate · up to aaa32

Merge is blocked by the static-analysis check. The previously identified agent-selection, photo-echo, and notice-copy concerns also remain open; resolve or explicitly accept them before merging.

Pre-merge checks: Passed 3 · Failed 2

Failed Failed checks: 2 warnings

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 26.25% 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 Warning The description covers the implementation, rationale, testing scope, review findings, compatibility notes, and checklist. It does not provide the required linked issue in the Fixes # section; “Part … Add the actual issue reference or link under Fixes #. If no visual or interaction change requires captures, write N/A and explain why. State whether CI covers pnpm lint, pnpm typecheck, pnpm test, and pnpm build, or provide thei…
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes moving the mobile terminal chat model and effort pickers onto the desktop option surface.
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: Docstring Coverage

Explanation

Docstring coverage is 26.25% 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 80 functions across 66 files. (1 skipped: 1 unsupported.)

Resolution

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

Full details: Description check

Explanation

The description covers the implementation, rationale, testing scope, review findings, compatibility notes, and checklist. It does not provide the required linked issue in the Fixes # section; “Part of the mobile/desktop parity audit” is not an issue reference or link. The visual proof section also does not use the required N/A wording, and the unchecked full validation commands do not state whether CI will cover them.

Resolution

Add the actual issue reference or link under Fixes #. If no visual or interaction change requires captures, write N/A and explain why. State whether CI covers pnpm lint, pnpm typecheck, pnpm test, and pnpm build, or provide their results.

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-session-options branch 5 times, most recently from d3106d9 to 054f998 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: 3

🔇 Additional comments: 1
mobile/src/session/use-mobile-native-chat-model-discovery.ts: 1

63-82: Trivial · Performance & Scalability

⚠️ Unverified finding
Verification ran but could not confirm this finding. It is shown for review, not as a verified issue.

Consider caching model discovery per host and agent.

Each run of this effect sends a git.discoverCommitMessageModels RPC. That RPC runs a CLI probe on the host. The effect re-runs when client, enabled, scope, or worktreeId change. These changes happen on reconnect, on a tab switch that toggles enabled, and on a switch between structured and PTY chat. Each re-run starts a new probe. The result state does not outlive the hook instance.

The comment in use-mobile-native-chat-session-option-controller.ts says mobile avoids per-visit CLI probes. This effect does not guarantee that.

Keep a module-level map keyed by [hostId, agent]. Store the in-flight promise. Evict the entry if the promise rejects or resolves to null, so a failed probe can retry. This matches the once-per-host behavior of ensureNativeChatModelEnrichment on desktop.


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: 0fa84292-b754-469d-9ad5-297b19ee16ca
Commits

Reviewing files that changed from the base of the PR and between 887b781 and 054f998.

Files selected for processing: 118
  • config/flaky-test-pattern-baseline.txt
  • mobile/src/session/MobileNativeChatDiffCard.tsx
  • mobile/src/session/MobileNativeChatFullContent.tsx
  • mobile/src/session/MobileNativeChatMessage.tsx
  • mobile/src/session/MobileNativeChatMessageActionsSheet.tsx
  • mobile/src/session/MobileNativeChatToolLine.tsx
  • mobile/src/session/MobileNativeChatToolRun.tsx
  • mobile/src/session/MobileNativeChatView.streaming-rows.test.ts
  • mobile/src/session/MobileNativeChatView.tsx
  • 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-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-session-option-records.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/MobileNativeChatTaskList.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/use-mobile-native-chat-unconfirmed-sends.ts
  • mobile/src/session/use-mobile-native-chat-controller.test.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-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-background-tasks.ts
  • mobile/src/session/use-mobile-structured-native-chat-send-bridge.test.ts
  • mobile/src/session/use-mobile-structured-session-option-stamp.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/NativeChatResolvedView.tsx
  • src/renderer/src/components/native-chat/NativeChatSessionOptionPickers.tsx
  • src/renderer/src/components/native-chat/NativeChatSessionOptionRows.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-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-status-hooks.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-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/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-availability.test.ts
  • src/shared/native-chat-availability.ts
  • src/shared/native-chat-discovered-catalog-models.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-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/input/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-session-option-state.ts
  • tests/e2e/native-chat-startup-option-pickers.unit.test.ts
Files with no reviewable changes: 16
  • mobile/src/session/native-chat/mobile-native-chat-pending-echo.test.ts
  • mobile/src/session/mobile-native-chat-message-plain-text.test.ts
  • mobile/src/session/mobile-native-chat-pending-baseline.test.ts
  • mobile/src/session/native-chat/mobile-native-chat-pending-pasted-content.test.ts
  • mobile/src/session/mobile-native-chat-message-plain-text.ts
  • config/flaky-test-pattern-baseline.txt
  • mobile/src/session/native-chat/mobile-native-chat-pending-retirement.test.ts
  • mobile/src/session/use-mobile-native-chat-turn-disclosure-opening-send.test.tsx
  • mobile/src/session/mobile-native-chat-merged-snapshot-parity.test.ts
  • mobile/src/session/mobile-native-chat-pending-baseline.ts
  • mobile/src/session/mobile-omp-session-catalog.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-labels.ts
  • mobile/src/session/use-mobile-omp-model-discovery.ts
  • mobile/src/session/mobile-session-option-records.ts
  • mobile/src/session/mobile-native-chat-render-data.test.ts
  • mobile/src/session/native-chat/mobile-native-chat-pending-retirement.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 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

Apply the shared send-time fallback when the image-preview boundary is null or not resolved.

The comment says that this filter uses the same boundary rule as the shared pending code. It does not do that in two cases:

  • Null boundary: foldedBoundaryIndex returns -1 when afterMessageId is null, so every candidate row is allowed. The shared messagesAfterPendingBoundary keeps every row only when afterEmptyTranscriptSessionId is set. Otherwise it filters rows by send time.
  • Unresolved boundary: foldedBoundaryIndex returns undefined when the boundary row is paged out. Line 179 then allows every candidate row. The shared rule falls back to send time in this case too.

How it can happen:

  1. The user sends a photo while the transcript is still loading. captureSendOrigin records afterMessageId: null with no empty-transcript claim.
  2. Older history then arrives, and the transcript becomes settled.
  3. For an image-only send, any older user row with enough image refs matches line 174. nativeChatPendingOccurrence(entry, 0) then selects the first such row.

What the user sees: the phone preview attaches to an old history message. retireLandedMobileNativeChatPending then removes the echo, because a mobile item's content key is 'empty' when it has only images. A captioned photo is affected the same way when older history has the same caption.

Fix:

  1. Add afterMessageTimestamp and afterEmptyTranscriptSessionId to PendingImagePreviewEcho.
  2. Remove the -1 and undefined shortcuts.
  3. If the boundary row is not found, filter candidates with the same timestamp rule that messageIsAfterPendingTimestamp uses.
🐛 Proposed direction
-    const tailIndex = foldedBoundaryIndex(messages, messageIndexById, entry.afterMessageId)
-    const candidate = candidates.filter(
-      (message) => tailIndex === undefined || (messageIndexById.get(message.id) ?? -1) > tailIndex
-    )[nativeChatPendingOccurrence(entry, 0) - 1]
+    const tailIndex = foldedBoundaryIndex(messages, messageIndexById, entry.afterMessageId)
+    const unbounded = entry.afterMessageId === null && entry.afterEmptyTranscriptSessionId
+    const candidate = candidates.filter((message) =>
+      tailIndex !== undefined && tailIndex !== -1
+        ? (messageIndexById.get(message.id) ?? -1) > tailIndex
+        : unbounded || isAfterPendingSendTime(message, entry)
+    )[nativeChatPendingOccurrence(entry, 0) - 1]

isAfterPendingSendTime should reuse the shared timestamp predicate. Export that predicate from native-chat-pending-sends.ts so the two rules cannot drift apart.

Comment on lines +11 to +12
const { markdown } = deriveNativeChatRowContent(
nativeChatBlocksInOwnWords(message.blocks, stoppedLabel)

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

Preserve displayed host-status text when copying a notice.

If a system message has presentation: 'history-item-too-large' and fallback wire text, MobileNativeChatNoticeRow displays AGENT_SESSION_HOST_STATUS_COPY but this helper copies the fallback text. The previous mobile converter mapped host-status presentations before copying. Restore that mapping in the shared copy path so the clipboard and Select text actions match the notice on screen. (raw.githubusercontent.com)

As per coding guidelines, “Clients and servers update independently; preserve compatibility across mixed versions.”

Source: Coding guidelines

@AmoabaKelvin
AmoabaKelvin force-pushed the mobile-chat-session-options branch 3 times, most recently from 517e3ce to aaa320a 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.

Actionable comments posted: 1


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: 4f40b0a6-3773-4a9d-8295-9b55b70d092d
Commits

Reviewing files that changed from the base of the PR and between 517e3ce and aaa320a.

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-native-chat-message-plain-text.ts
  • mobile/src/session/mobile-session-option-records.ts
  • src/renderer/src/components/native-chat/native-chat-session-option-labels.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; 7 remain after this review.

Comment on lines +20 to +25
import { buildNativeChatSessionOptionSnapshot } from './native-chat/input/native-chat-session-option-snapshot'
import {
resolveEffectiveNativeChatModelId,
withTrackedNativeChatModel,
type NativeChatSessionOptionMode
} from '../../../../shared/native-chat/input/native-chat-session-option-snapshot'
import type { NativeChatSessionOptionDispatchCommand } from './native-chat-session-option-command-dispatch'
} from './native-chat/input/native-chat-session-option-snapshot'

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.

Major · Maintainability & Code Quality · Quick win

Merge the duplicate imports from ./native-chat/input/native-chat-session-option-snapshot.

The file imports this module twice. Line 20 imports buildNativeChatSessionOptionSnapshot. Lines 21-25 import resolveEffectiveNativeChatModelId, withTrackedNativeChatModel, and NativeChatSessionOptionMode. The static analysis and typecheck job fails on this with "Modules should not be imported multiple times in the same file". The job runs oxlint with --deny-warnings, so this blocks CI. Combine both imports into one statement.

🧹 Proposed fix
--- "a/src/shared/native-chat-pty-session-options.ts"
+++ "b/src/shared/native-chat-pty-session-options.ts"
@@ -17,12 +17,12 @@
   writeNativeChatSessionOptionCache
 } from './native-chat-session-option-cache'
 import { createSessionOptionAppliers } from './native-chat-session-option-apply'
-import { buildNativeChatSessionOptionSnapshot } from './native-chat/input/native-chat-session-option-snapshot'
 import {
+  buildNativeChatSessionOptionSnapshot,
   resolveEffectiveNativeChatModelId,
   withTrackedNativeChatModel,
   type NativeChatSessionOptionMode
 } from './native-chat/input/native-chat-session-option-snapshot'
 import type { NativeChatSessionOptionDispatchCommand } from './native-chat-session-option-dispatch'
 
 type PersistSelection = (args: {
Committable suggestion

IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { buildNativeChatSessionOptionSnapshot } from './native-chat/input/native-chat-session-option-snapshot'
import {
resolveEffectiveNativeChatModelId,
withTrackedNativeChatModel,
type NativeChatSessionOptionMode
} from '../../../../shared/native-chat/input/native-chat-session-option-snapshot'
import type { NativeChatSessionOptionDispatchCommand } from './native-chat-session-option-command-dispatch'
} from './native-chat/input/native-chat-session-option-snapshot'
import {
buildNativeChatSessionOptionSnapshot,
resolveEffectiveNativeChatModelId,
withTrackedNativeChatModel,
type NativeChatSessionOptionMode
} from './native-chat/input/native-chat-session-option-snapshot'
Tools
GitHub Actions: PR 33976 | source 4414fee | workflow 4414fee | unit full / 16_static analysis and typecheck.txt

[warning] 20-20: oxlint: Modules should not be imported multiple times in the same file.

GitHub Actions: PR 33976 | source 4414fee | workflow 4414fee | unit full / static analysis and typecheck

[error] 20-20: Oxlint reported: Modules should not be imported multiple times in the same file. The command node node_modules/oxlint/bin/oxlint --config config/oxlint-code-quality-native-plugins.json src config tests mobile --deny-warnings failed with exit code 1 because warnings are denied.

Source: Pipeline failures

Mobile now uses the shared detected-then-launch precedence and transcript-readability check; the phone's remembered agent only fills in after them.
Copy now leaves out roster and background-task fallback twins and wordless provider frames.
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-session-options branch from aaa320a to e4e5eaa Compare October 27, 2026 13:59
@AmoabaKelvin

Copy link
Copy Markdown
Collaborator Author

Folded into #33977 to land the stack in one pass.

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