Show agent session history on mobile#6786
Conversation
Bring the desktop "Agent Session History" panel to Orca Mobile as a per-worktree screen: browse past agent transcript sessions across the host with scope tabs (Workspace/Project/All), search, grouping, session cards, and tap-to-read message previews. The transcript scan previously ran only over Electron IPC, so mobile could not reach it. Expose it over the runtime RPC protocol mobile already speaks (aiVault.listSessions) so the scan runs on whichever host owns the transcripts — correct for local and SSH/remote hosts. Both the desktop IPC handler and the new RPC method share one cache, so opening the desktop panel and the mobile screen never double-scan. The pure filter/group/display logic is lifted into /shared (the renderer re-exports it) so the standalone mobile package can reuse it. Mobile narrows scoped tabs client-side by cwd path-prefix because the host scan treats scope paths as a widening union. Resume-from-mobile is intentionally a follow-up.
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR adds Agent Session History to the mobile app and refactors related AI Vault logic. Shared session display and filtering code moves into 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
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: 6
🧹 Nitpick comments (2)
src/shared/ai-vault-session-filters.test.ts (1)
79-85: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd a quoted operator regression case.
When fixing the parser, cover
repo:"my repo"andpath:"/Users/ada/My Project"here so paths/repo labels with spaces stay supported.mobile/src/agent-history/agent-history-scope-paths.test.ts (1)
39-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a Windows-path regression case.
This helper depends on case-insensitive Windows normalization, but the suite only locks in POSIX inputs. A
C:\Repo\Appvsc:/repo/appfixture would pin the cross-platform contract here.Suggested coverage
+ it('dedupes equivalent Windows paths case-insensitively', () => { + const windowsActive = worktree({ worktreeId: 'w1', path: 'C:\\Repo\\App', repoId: 'repo-1' }) + const windowsDupe = worktree({ worktreeId: 'w2', path: 'c:/repo/app', repoId: 'repo-1' }) + expect( + deriveMobileAiVaultScopePaths('project', windowsActive, [windowsActive, windowsDupe]) + ).toEqual(['C:\\Repo\\App']) + })
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: b36d8821-3fe9-4898-864b-f49703a05369
📒 Files selected for processing (28)
mobile/app/h/[hostId]/agent-history/[worktreeId].tsxmobile/app/h/[hostId]/index.tsxmobile/app/h/_layout.tsxmobile/src/agent-history/MobileAgentSessionHistoryList.tsxmobile/src/agent-history/MobileAgentSessionHistoryPanel.tsxmobile/src/agent-history/agent-history-capability.tsmobile/src/agent-history/agent-history-scope-paths.test.tsmobile/src/agent-history/agent-history-scope-paths.tsmobile/src/agent-history/agent-history-sections.tsmobile/src/agent-history/agent-history-session-card.test.tsmobile/src/agent-history/agent-history-session-card.tsmobile/src/agent-history/agent-history-styles.tsmobile/src/agent-history/use-mobile-agent-history-state.tsmobile/src/agent-history/worktree-navigation-actions.tssrc/main/ai-vault/cached-session-list.tssrc/main/index.tssrc/main/ipc/ai-vault.tssrc/main/runtime/orca-runtime.tssrc/main/runtime/rpc/methods/ai-vault.test.tssrc/main/runtime/rpc/methods/ai-vault.tssrc/main/runtime/rpc/methods/index.tssrc/renderer/src/components/right-sidebar/ai-vault-session-display.tssrc/renderer/src/components/right-sidebar/ai-vault-session-filters.tssrc/renderer/src/components/right-sidebar/ai-vault-session-projects.tssrc/shared/ai-vault-session-display.tssrc/shared/ai-vault-session-filters.test.tssrc/shared/ai-vault-session-filters.tssrc/shared/protocol-version.ts
- Authorize aiVault.listSessions in the mobile RPC allowlist so the mobile client's call is not rejected before dispatch (without this the screen could never load sessions at runtime). - Name each SectionList section's rows `data` (the field React Native reads) instead of `cards`, fixing a type error and silent empty-section rendering.
- Match quoted repo:/path: search operator values so labels and paths with spaces match (e.g. path:"/Users/ada/My Project"). - Hold a scoped tab in loading until the worktree list resolves instead of firing an unscoped fetch that briefly shows unrelated host history; proceed once loaded even if the worktree is absent (no stuck spinner). - Clear cached host capabilities on disconnect/host-switch and failed status.get so a capability-gated action can't linger for a host that doesn't support it. - Cover the real OrcaRuntimeService codex-home forwarding path and the quoted-operator parser with tests.
Stabilization updateMerged current
One red check is not from this PR: the full-suite |
Co-authored-by: Orca <help@stably.ai>
|
Ready to review this PR? Stage has broken it down into 7 individual chapters for you: Chapters generated by Stage for commit e641cd4 on Jun 30, 2026 8:50pm UTC. |
Co-authored-by: Orca <help@stably.ai>
…ts-to-mobile # Conflicts: # mobile/app/h/_layout.tsx # src/main/index.ts # src/main/ipc/ai-vault.ts # src/main/runtime/orca-runtime.ts # src/main/runtime/runtime-rpc.ts # src/shared/runtime-types.ts
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
Co-authored-by: Orca <help@stably.ai>
…ts-to-mobile Reconciles the mobile aiVault.listSessions RPC with main's runtime-host scanning (#7631), OMP sessions (#7618/#7628), host-aware attribution (#7367), and zero-turn recovery (#7889): - One aiVault.listSessions serves mobile (no executionHostId), the desktop parent, and web clients: bounded params kept, results served from the shared host-local cache and restamped per-caller at the RPC edge. - Desktop's runtime-host RPC client caps scopePaths to the shared bound so large desktops degrade gracefully instead of failing validation. - Desktop IPC local scope delegates to the shared cache module (single cache with the RPC path); ssh/runtime/all merges keep main's outer cache. - Main's zero-turn empty-session semantics and ExecutionHostId-typed project attribution replayed onto the /shared lifted filter core. - Mobile resume forwards session.filePath so OMP resumes by absolute transcript path (desktop parity). Co-authored-by: Orca <help@stably.ai>
…ment The extracted cache module's .finally() cleared inflight tracking unconditionally, dropping the if (inflightKey === key) guard its sibling outer cache kept: an older scan resolving after a different-key scan replaced the tracking would null the newer scan's dedup slot, so a re-request started a duplicate transcript rescan. Mirrors the sibling guard; the regression test flushes a macrotask so a reverted guard fails fast on the call count instead of hanging. Co-authored-by: Orca <help@stably.ai>
…ts-to-mobile Take main's side of the mobile session-screen PR probe: the source-control hub (#7923) now loads branch identity inside MobileSourceControlPanel, so the session screen only gates the dock icon on the GitHub remote probe. Co-authored-by: Orca <help@stably.ai>
…capability - Clamp scopePaths (64) instead of rejecting, cap limit at 2000, and make executionHostId optional so mobile can omit it; restamp per caller. - Retain successful mobile terminal-create mutation ids for 60s so resume retries dedupe after transient socket drops. - Gate the session-header Agent History action on the aiVault.v1 capability (mirrors the host-list action) so old hosts never show a dead-end entry. - Fix stale contract comments (scopePaths clamp semantics; filters move includes quoted repo:/path: operator parsing).
…2025/add-agents-to-mobile # Conflicts: # src/main/ipc/ai-vault.ts # src/renderer/src/components/right-sidebar/ai-vault-session-display.ts
AiVaultSession.subagent became required on main; the five fixtures added on this branch predate it. Top-level scanned sessions carry null.
What changes
Adds Agent Session History to Orca Mobile as a per-worktree screen. From a worktree's action sheet, tap Agent Session History to browse past agent transcript sessions on that host: scope tabs (Workspace / Project / All), search (including
repo:/path:operators), grouping, session cards (agent, title, last message, message count, time-ago, "current worktree" badge), and tap a session to read its message preview.What does not change: this is browse + preview only. Resuming an agent session from mobile is a deliberate follow-up, not in this PR. Desktop behavior is unchanged — the desktop "Agent Session History" panel keeps working exactly as before.
Why the plumbing
The transcript scan that powers this used to be reachable only over Electron IPC, so the mobile client literally could not see it. This PR exposes the same host scan over the runtime RPC protocol mobile already speaks (
aiVault.listSessions). The scan runs on whichever host owns the transcripts, so it is correct for local and SSH/remote hosts. The desktop IPC handler and the new RPC method share a single 15s-TTL cache, so opening the desktop panel and the mobile screen never double-scan.Design approach
aiVault.listSessions(boundedlimit/scopePathsparams) wrapping the existing transcript scanner, advertised via a new staticaiVault.v1runtime capability so older hosts degrade gracefully (the mobile entry is hidden when the host lacks it).src/main/ai-vault/cached-session-list.ts) used by both the IPC handler and the RPC method. Codex-home + WSL inputs are sourced from theOrcaRuntimeServiceconstructor (which runs in both window mode andorca serve), not the window-only handler path — otherwise remote/SSH hosts would silently drop managed-Codex sessions./shared(the desktop renderer now re-exports it) so the standalone mobile package can reuse it; Metro can't import renderer modules./sharedstays a leaf (zero renderer imports).Design-review outcome
Ran the iterative design review to clean (3 rounds, no remaining P0/P1, no direction-level findings). It caught two load-bearing issues in the draft before implementation: (1) sourcing codex-home from the window-only handler would break it under
orca serve/SSH — moved to the runtime constructor seam; (2) the renderer filter helpers import runtime values and Metro can't resolve renderer modules — so the pure core is lifted to/sharedrather than imported.Implementation & deviations
Implemented as designed. Two deviations, both noted:
worktree-navigation-actions.tsto keep the mobile host index file under its line budget without amax-linesdisable. No behavior change.Completeness verification
Read-only verification confirmed all requirements implemented (host RPC + bounds + capability, single shared cache, serve-mode codex-home,
/sharedleaf invariant + renderer re-export parity, capability-gated mobile entry + screen, scope/search/grouping/cards/preview, virtualization + lazy preview, interaction states, no resume code). Verdict: complete.Headline behavior status
Implemented. The full path executes in production code: tap worktree → capability-gated action → per-worktree screen →
aiVault.listSessionsRPC → shared cache → on-disk transcript scan → rendered sessions, with working scope tabs / search / grouping / preview. No fixtures or dormant scaffolding. Resume is intentionally deferred (follow-up PR).Perf audit
No actionable findings. Touched hot paths: the RPC dispatch (forwards to a cached async scan — no sync heavy work), and the mobile render (memoized sections, stable list keys, virtualized
SectionList, lazy preview rendered only on tap). No polling (loads on mount/reconnect, scope switch reuses the host TTL withforce:false, pull-to-refresh usesforce:true). Lifecycle guarded bymountedRef/generationRef; no timers/listeners to leak.Accepted gap: the scanner ships the full (bounded: ≤5 messages × 220 chars)
previewMessagesarray per session even though preview is lazy-rendered. This is inherent to the existing scanner output shape (desktop receives the same payload); trimming it would require a scanner change, out of scope. Mitigated by virtualization + lazy render. QA watch item: rapid search typing on a large history (un-debounced filter, matches desktop today); adduseDeferredValueonly if real jank is observed.Code-review loop
Two rounds, two independent reviewers each (four total).
scope: 'all'). Fixed: narrow client-side by cwd path-prefix, with a fallback to unnarrowed until the worktree list loads. Added narrowing tests.brennan-test-changes result
Validated the desktop consumer of the refactor in the running Electron app (the testable end-to-end surface in this environment): launched the PR worktree, confirmed identity (branch
brennanb2025/add-agents-to-mobile), opened the desktop "Agent Session History" panel, and confirmed it renders 500 real sessions with working search (incl.repo:operator), scope tabs, and all three grouping modes, zero panel-related console errors. This exercises the lifted/sharedlogic through the renderer re-export and the shared cache via the IPC path. Verdict: land for the desktop-consumer concern.Accepted validation gaps (this environment):
mobile/node_modulesis incomplete (no react-native/expo), so the RN app can't run here. The new.tsxmirror the exact untyped patterns of existing mobile screens; mobile oxlint + the standalone vitest suite pass. CI runs the full mobile typecheck with complete deps.Static checks & focused tests
tsgotypecheck: node + web projects clean.git diff --check: clean.aiVault.listSessionsRPC tests +/sharedfilter parity tests pass (13); desktop IPC + renderer filter + register-core-handlers suites still pass (1331).src/agent-history17 pass (scope-path derivation, scope narrowing incl. fallback, card view-model, capability lockstep).Remaining risks / non-actionable
Made with Orca 🐋
Mobile backcompat review (2026-07-10) + pre-merge fixes
Full
/mobile-backcompat-review(4 independent reviewers + verification): compatible — no P0 blockers. Version-skew matrix verified both directions: mobile gates everyaiVault.listSessionscall on theaiVault.v1capability fromstatus.get(old hosts get an explicit unsupported/graceful state), all newRuntimeStatus/RuntimeWorktreePsSummaryfields are optional-additive, no persisted keys renamed, host paths go through the shared Windows/WSL-aware helpers, resume is blocked on SSH/runtime workspaces.Fixes applied from the review:
aiVault.v1(was the one ungated entry point; old hosts saw a dead-end "update host" panel)./sharedalso added quotedrepo:/path:operator parsing).User-visible workspace-list changes to be aware of (intentional desktop parity, verified against desktop source):
sortOrderdesc, perworktrees:persistSortOrder); unranked/headless hosts fall back to agent-attention order.unreadis no longer a sort key.worktree-list-groups.ts).ALL_GROUP_KEY, making the desktop-syncedcollapsedGroupsstate coherent across surfaces. One-time effect: users who had "All" collapsed will see the whole ungrouped list collapsed once after upgrade.Merged
origin/main(@143c36e56): reconciled with #7423 (AI Vault subagent display) — kept itsaiVault:listSubagentSessionshandler on top of the shared-cache refactor (getAiVaultWslHomeDirsnow exported fromcached-session-list), and moved itssessionModelLabelintosrc/shared/ai-vault-session-displaybehind the renderer re-export. Post-merge: typecheck clean, 747 desktop ai-vault/runtime tests and 1392 mobile tests pass.