Repository navigation
feat(mobile): show a native chat's subagents like desktop - #26125
Conversation
Move the background-tasks roster, header, view and the transcript roster header into src/shared, with the words behind one English table that desktop translates under its existing keys, so desktop output is unchanged. The phone now draws the running child work strip above the composer (with Stop, under desktop's conditions) and the transcript's subagent-group row, from the host data it already receives. Child rows read unverifiable once the session stream is lost.
… row - Roster row: spoken through one label that names its clock only once the group settles; the verdict wraps instead of pushing the headline or chevron out. - One twin rule: derive() and the phone both call isReplacedSubagentGroupTwin. - Desktop strip says Stop / Stop all / details-unavailable through the shared table. - One memoized composer tray holds the strip and the queued cards; the strip carries its own conversation key. - The strip latches the host clock offset once per conversation, so frames that change nothing keep its rows memoized, and reads elapsed on the host's clock. - Initial narrow guess includes the strip's margins; group labels uppercase by style; the header ellipsizes at large text; row state words reuse mobile's.
…cards Both siblings in the composer tray were keyed by the conversation's sessionKey, so React logged a duplicate-key error whenever a structured chat with running subagents opened.
The offset was latched per conversation, so a host restart or clock correction while the chat stayed open left every elapsed time off until the chat was left. It is now derived from each frame's host sample, rounded to a second so jitter alone keeps the rows memoized.
The narrow total ("N background tasks") now replaces only a breakdown across
several kinds. A single kind keeps its state forms at every width, so a phone and
a narrow desktop pane still read "2 agents waiting — needs approval".
|
The phone received native-chat child-work records but showed no running list or Stop button, and its “Ran N subagents” sentence could not expand. This PR adds the running strip above the composer and an expandable live/finished transcript group, using the shared desktop logic. Single-kind headers retain their working/waiting state on both the phone and narrow desktop panes; mixed kinds still show a total. The PR body includes before/after screenshots for both platforms. The later phone spacing follow-up makes the header and rows shorter, with tighter AGENTS padding; its fresh expanded screenshot shows both agents and Stop controls at Three Debug native scheduler crashes were recorded on this PR versus zero on main; the cause was not found, and no Release build could be tested on this machine. Both JavaScript builds used the same installed Debug native binary. The first two crashes lack precise action timestamps; the third overlaps composer-intended tap/typing with the developer Inspector visible, but its actual target, accepted text and failing command remain unproven. Inspector-off Stop/composer/completion and the final matched typing check were blocked by the Simulator helper, with none of the seven final typing trials delivered. A clean native Stop request and row removal passed separately; ordinary completion and controlled Inspector-enabled completion/reopen passed on both builds through host roster updates. No production crash fix was selected without a proven cause. The final review found no remaining proven production defect in the round-two delta or the agreed header change. Fixes cover sibling keys, translated Stop controls, clock correction, disclosure lifetime and wrapping. The added catalog test's forbidden reflection lookup was replaced with checked object access. Worktree-list child rows remain a separate follow-up awaiting Brennan's go. Further consolidation of child-row wording, transcript-group clock correction and disconnected-group presentation remain deferred; the strip's clock correction is included, and group rows retain the last reported state as on desktop. Before the latest main merge and spacing change, at Current head Hidden local Mac Electron captures verified narrow and wide headers, expansion/collapse, the actual Stop request and the recorded acknowledgement/row removal, with no renderer errors. Both desktop and iOS captures use recorded host data; they do not verify live-agent termination. Windows, Linux, WSL/SSH execution, Android, screen readers, mixed-version pairing and network recovery remain unverified. No wire or stored-setting changes were introduced. Ready for review with the native evidence above disclosed. This PR has not been merged, auto-merge has not been enabled, and the follow-up has not started. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (11)
🚧 Files skipped from review as they are similar to previous changes (1)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review. 📝 WalkthroughWalkthroughThe change adds shared background-task roster and header helpers, then connects them to desktop components and a mobile structured-session composer tray. Mobile transcript messages now render expandable subagent-group rows using shared group formatting. The English runtime-required catalog adds background-task, subagent, and chat failure copy. Priority: ➖ Normal Merge Risk: ⚪ Minimal · up to No confirmed issue blocks merging after normal checks. The reported Debug crashes remain unexplained, but their cause has not been linked to this change. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Docstring CoverageExplanation Docstring coverage is 37.76% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 98 functions across 50 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
e02d49ed-2c02-49f3-94f2-277f14506053
📒 Files selected for processing (53)
mobile/src/components/AgentStateDot.tsxmobile/src/hooks/use-now.tsmobile/src/session/MobileNativeChatBackgroundTasks.test.tsxmobile/src/session/MobileNativeChatBackgroundTasks.tsxmobile/src/session/MobileNativeChatMessage.subagent-group.test.tsxmobile/src/session/MobileNativeChatMessage.tsxmobile/src/session/MobileNativeChatOverlay.test.tsmobile/src/session/MobileNativeChatOverlay.tsxmobile/src/session/MobileNativeChatSubagentGroup.tsxmobile/src/session/MobileNativeChatView.tsxmobile/src/session/__mocks__/mobile-prompt-controller.tsmobile/src/session/mobile-agent-child-row-text.tsmobile/src/session/mobile-native-chat-controller-contract.tsmobile/src/session/mobile-native-chat-render-data.tsmobile/src/session/use-mobile-native-chat-composer-tray.test.tsxmobile/src/session/use-mobile-native-chat-composer-tray.tsmobile/src/session/use-mobile-native-chat-controller.tsmobile/src/session/use-mobile-native-chat-queued-slot.test.tsxmobile/src/session/use-mobile-native-chat-queued-slot.tsmobile/src/session/use-mobile-native-chat-turn-disclosure.tsmobile/src/session/use-mobile-structured-agent-session-background-tasks.test.tsxmobile/src/session/use-mobile-structured-agent-session.tsmobile/src/session/use-mobile-structured-background-tasks.tssrc/renderer/src/components/agent-child-row-parity.test.tsxsrc/renderer/src/components/agent-child-row-text.tssrc/renderer/src/components/native-chat/NativeChatBackgroundTaskRun.tsxsrc/renderer/src/components/native-chat/NativeChatBackgroundTasksStatus.test.tsxsrc/renderer/src/components/native-chat/NativeChatBackgroundTasksStatus.tsxsrc/renderer/src/components/native-chat/NativeChatStructuredSessionStatus.tsxsrc/renderer/src/components/native-chat/NativeChatSubagentRun.tsxsrc/renderer/src/components/native-chat/background-task-header-content.tssrc/renderer/src/components/native-chat/background-task-roster.tssrc/renderer/src/components/native-chat/background-task-words-text.test.tssrc/renderer/src/components/native-chat/background-task-words-text.tssrc/renderer/src/components/native-chat/native-chat-subagent-group-words-text.test.tssrc/renderer/src/components/native-chat/native-chat-subagent-group-words-text.tssrc/renderer/src/components/native-chat/structured-child-records-switch.test.tsxsrc/renderer/src/components/native-chat/use-structured-agent-session-transport-state.tssrc/renderer/src/components/sidebar/worktree-sidebar-running-children.test.tssrc/renderer/src/i18n/en-runtime-required.jsonsrc/shared/agent-child-row-lead-trail.tssrc/shared/agent-child-row-stream-context.tssrc/shared/background-task-copy.tssrc/shared/background-task-header-content.tssrc/shared/background-task-roster.test.tssrc/shared/background-task-roster.tssrc/shared/native-chat-row-content.tssrc/shared/native-chat-subagent-group-header.test.tssrc/shared/native-chat-subagent-group-header.tssrc/shared/native-chat-subagent-summary.test.tssrc/shared/native-chat-subagent-summary.tssrc/shared/structured-session-background-tasks-view.test.tssrc/shared/structured-session-background-tasks-view.ts
💤 Files with no reviewable changes (2)
- mobile/src/session/use-mobile-native-chat-queued-slot.test.tsx
- mobile/src/session/use-mobile-native-chat-queued-slot.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review.
| /** The row's blocks less any roster twin a drawn group replaces. */ | ||
| export function withoutSubagentGroupTwins(blocks: readonly NativeChatBlock[]): NativeChatBlock[] { | ||
| const drawsGroup = subagentGroupBlocks(blocks).length > 0 | ||
| return blocks.filter((block) => !isReplacedSubagentGroupTwin(block, drawsGroup)) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
sed -n '1,115p' src/shared/native-chat-row-content.ts
sed -n '55,103p' src/shared/worker-transcript-text.ts
sed -n '180,260p' src/shared/native-chat-subagent-summary.tsRepository: stablyai/orca
Length of output: 9554
🏁 Script executed:
set -o pipefail
printf '%s\n' '--- background task helper references ---'
rg -n -F -- 'claimBackgroundTaskTwins' src mobile || test "$?" -eq 1
printf '%s\n' '--- helper implementation and surrounding declarations ---'
sed -n '1,260p' src/shared/native-chat-background-task-row.ts
printf '%s\n' '--- desktop caller exact block ---'
nl -ba src/shared/native-chat-row-content.ts | sed -n '1,75p'
printf '%s\n' '--- shared group filter and mobile caller ---'
nl -ba src/shared/native-chat-subagent-summary.ts | sed -n '198,225p'
nl -ba mobile/src/session/MobileNativeChatMessage.tsx | sed -n '232,258p'Repository: stablyai/orca
Length of output: 15032
Keep desktop task indexes stable while fixing group-twin matching.
withoutSubagentGroupTwins uses one drawsGroup flag, so one renderable group causes every fallback-shaped text block to be removed. In a mixed renderable/childless row, this removes the childless group’s fallback text.
Desktop must not call this filter before its task-twin predicate. claimBackgroundTaskTwins(split.prose) stores indexes from the original array, and desktop reads them with taskTwins.twinTextIndexes.has(index). Removing a block first shifts those indexes and can misclassify a background-task twin.
Make the shared group-twin check index-aware so it matches only fallback text paired with a renderable group. Use that predicate from mobile and from desktop’s existing filter over the unmodified split.prose. Do not prefilter split.prose before applying taskTwins.twinTextIndexes.

ELI5
When a native chat started subagents, the phone showed no running list or Stop button. Its conversation showed only a sentence such as “Ran 2 subagents,” which could not expand. The phone already received the host’s child-work records, but did not render them. After the main turn ended, it could look as though all work had finished while children still ran.
The phone now shows running child work above the message box and an expandable subagent group in the conversation.
What Changed
src/shared, used by desktop and phone. Desktop keeps its translation keys; phone uses the same English copy. The phone corrects strip elapsed times from each host clock sample and preserves expansion across a temporary empty roster.Why
Sharing the existing desktop derivation keeps the phone and desktop on the same host-owned state and presentation rules. A second phone-only roster would duplicate that logic. The strip and transcript group cover running work and history separately, so finished children stay in the conversation rather than above the composer.
Phone worktree-list child rows are a separate follow-up. Opening a child’s own transcript and shell-command transcript blocks on the phone are also outside this PR.
Visual Proof
The original parity captures below use native iOS Simulator on iPhone SE and the same recorded host scenario. Before is main
80d45095d2f; after is8a1cc6676ea(then production-identical to0e1afaa2823). They precede the later main merge and compact phone spacing at27cb2b536f8. These captures use an encrypted mock host, rather than a live agent session. The current compact strip is shown in the fresh native screenshot comment and below; it shows two working agents and both Stop controls above the composer.Both waiting: the full “2 agents waiting — needs approval” header fits the narrow phone.
Finished group expanded:
The recorded host acknowledged Stop for “Review refund flow”: that row leaves the strip while “Write refund tests” keeps running. This checks the request and rendered update; it does not establish that a live agent process was stopped.
Desktop: the actual hidden Orca Electron app on local macOS, using the same recorded host scenario and the same frozen before/after builds above. The strip measured 360 px for narrow captures and 736 px for wide captures, across its 384 px boundary. Wide headers matched before/after; each narrow header fit without truncation. The full app remains visible in these captures.
Desktop expansion and Stop used actual Playwright clicks on the rendered controls. The recorded host acknowledged the selected child's Stop request; the waiting child remained. No live agent process was run or stopped.
Native crash evidence and blocked follow-up checks are disclosed at the top of Testing below.
Testing
3 debug-build crashes on this PR vs 0 on main (
Scheduler::uiManagerDidDispatchCommand), cause not found; Release build could not be produced on this machine. These were the same installed Debug native binary running each JavaScript build. The first two crashes lack precise action timestamps; the third overlaps an acknowledged composer-intended tap and typing while the developer Inspector was visible. The actual target, accepted text and failing command remain unproven. A genuine native Release build did not finish within the authorized time limit, so no Release executable or embedded JavaScript was tested.A clean native Stop request and row removal passed separately. Ordinary last-child completion and controlled Inspector/text-selection/completion/reopen passed on both builds, using host-published roster updates for completion. The Inspector-off continuation and final matched typing check were blocked by the Simulator helper, rather than recorded as product failures: its single final attach failed before any of the seven requested typing trials were delivered. No production crash fix was selected without a proven cause. These results remain for the reviewer to assess before merging.
Current merged/compact head
27cb2b536f8passed targeted mobile rendering, session and controller/importer tests, mobile production and test-ratchet typechecks (946 test files), and root node, renderer and CLI typechecks. The four main conflicts preserve inline phone visuals alongside the subagent strip/group. The final pre-push checker completed all 22 steps: 20 passed; normal lint reports the 304-line test manifest inherited unchanged from main, and native lint reports the same five earlier base/head import-cycle warnings. React Doctor passes after committing the merge. Header/row/Stop minima are 36/32/32 pt with 4/6 pt hitSlop; native parent bounds can limit the requested 44 pt touch areas. Actual native touch coverage and large-text layout were not verified. CI at this head completed with six checks passed, two failed and 19 skipped. The failures are the same 304-line test manifest inherited unchanged from main and the aggregate verification failure caused by that lint result. Mobile Checks, the Headless Node server and the mobile web bundle passed. Other PR unit, platform and package jobs were skipped after the static failure. CI is not green; no new PR-specific failure was found against pinned main995ef11ce77.The original CI passed at
0e1afaa2823on the single failed-jobs rerun. The first Linux package attempt exhausted its time limit installing Ubuntu package tools; the aggregate failure came from that cancellation. The rerun passed both jobs without source changes. Desktop QA used a hidden local Mac because the usual Mac test host was unavailable; remote Windows setup was blocked. Native Simulator and Electron checks use recorded data. Live agent execution, Android, screen readers, mixed-version runtime pairing, disconnected/reconnecting hosts, Windows, Linux, WSL and SSH execution are not verified by these captures.Review
Codex final-delta and proportional readiness review found no remaining production defect in the round-two fixes or the agreed narrow-header change. The added translation test's forbidden
Reflect.getlookup was replaced with checked object access and verified. The shared behavior was reviewed for remote ownership, wire compatibility, bounded disclosure state, Stop failures and timer cleanup. Automated checks do not establish native accessibility, battery cost or every host topology.Agent skill upstream boundary
Checklist