Repository navigation
feat(sidebar): show live Codex subagent progress - #12311
parkavenue9639 wants to merge 1 commit into
Conversation
|
Important Review skippedWe couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting You can disable this status message by setting the Use the checkbox below for a quick retry:
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 change adds Codex subagent progress tracking across the main process, shared state, and renderer. It adds lifecycle reconciliation for working, waiting, idle, and completed child states. The sidebar now creates validated progress targets, resolves local or runtime transcript routes, and renders read-only progress sheets. Subagent rows carry session metadata, display formatted labels, and expose selection state. Tests cover routing, transcript scoping, lifecycle polling, native-chat decoding, component behavior, and end-to-end concurrent and session-boundary flows. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/renderer/src/components/sidebar/WorktreeCardAgents.tsx (1)
285-289: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider extracting the shared activation resolver.
The same three-way activation ternary exists here and at lines 350-354. The Codex branch also allocates a new closure on every render, so memoized rows re-render even when their props are unchanged. A single memoized resolver keeps both views aligned and preserves row memoization.
♻️ Proposed refactor
+ const resolveRowActivation = useCallback( + (agent: DashboardAgentRowData) => + agent.rowSource === 'retained' + ? handleActivateRetainedAgent + : agent.subagentSession?.provider === 'codex' + ? () => handleOpenCodexSubagentProgress(agent) + : handleActivateAgentTab, + [handleActivateAgentTab, handleActivateRetainedAgent, handleOpenCodexSubagentProgress] + )Then use
onActivate={resolveRowActivation(agent)}in both render paths.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 91e529f8-4edd-48cd-bd83-beccb6d6165e
📒 Files selected for processing (18)
src/renderer/src/components/dashboard/DashboardAgentRow.tsxsrc/renderer/src/components/dashboard/useDashboardData.tssrc/renderer/src/components/sidebar/CodexSubagentProgressSheet.test.tsxsrc/renderer/src/components/sidebar/CodexSubagentProgressSheet.tsxsrc/renderer/src/components/sidebar/WorktreeCardAgents.activation.test.tsxsrc/renderer/src/components/sidebar/WorktreeCardAgents.tsxsrc/renderer/src/components/sidebar/codex-subagent-progress-host-authority.test.tssrc/renderer/src/components/sidebar/codex-subagent-progress-host-authority.tssrc/renderer/src/components/sidebar/codex-subagent-progress-route.test.tssrc/renderer/src/components/sidebar/codex-subagent-progress-route.tssrc/renderer/src/components/sidebar/codex-subagent-progress-target.test.tssrc/renderer/src/components/sidebar/codex-subagent-progress-target.tssrc/renderer/src/components/sidebar/index.tsxsrc/renderer/src/components/sidebar/useWorktreeAgentRows.test.tssrc/renderer/src/components/sidebar/worktree-card-compact-agent-row.tsxsrc/renderer/src/components/sidebar/worktree-subagent-child-rows.tssrc/renderer/src/i18n/locales/en.jsonsrc/renderer/src/store/slices/ui.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/agent-hooks/server-codex-subagent-transcript.test.ts (1)
225-242: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider extracting a local hook POST helper.
This block repeats the port, token header, and body shape used by the other tests in this file. A local
postCodexHook(server, payload)helper, like the one insrc/main/agent-hooks/server-codex-subagent-dynamic-lifecycle.test.ts, keeps the new test focused on the lifecycle assertions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 23724f25-c105-4670-89a5-617b5ca09d98
📥 Commits
Reviewing files that changed from the base of the PR and between 8254880 and 97f3498f2d8ed421d5c12363c7cb91e4d28e5e68.
📒 Files selected for processing (36)
src/main/agent-hooks/server-codex-subagent-dynamic-lifecycle.test.tssrc/main/agent-hooks/server-codex-subagent-transcript.test.tssrc/main/agent-hooks/server.tssrc/main/native-chat/transcript-line-decoders-codex.tssrc/main/native-chat/transcript-reader.test.tssrc/renderer/src/assets/main.csssrc/renderer/src/components/agent-child-disclosure-label.tssrc/renderer/src/components/codex-subagent-display-label.tssrc/renderer/src/components/dashboard/DashboardAgentChildDisclosure.tsxsrc/renderer/src/components/dashboard/DashboardAgentRow.tsxsrc/renderer/src/components/sidebar/CodexSubagentProgressSheet.test.tsxsrc/renderer/src/components/sidebar/CodexSubagentProgressSheet.tsxsrc/renderer/src/components/sidebar/WorktreeCardAgents.activation.test.tsxsrc/renderer/src/components/sidebar/WorktreeCardAgents.tsxsrc/renderer/src/components/sidebar/codex-subagent-progress-selection.test.tssrc/renderer/src/components/sidebar/codex-subagent-progress-selection.tssrc/renderer/src/components/sidebar/codex-subagent-progress-target.test.tssrc/renderer/src/components/sidebar/codex-subagent-progress-target.tssrc/renderer/src/components/sidebar/codex-subagent-transcript-scope.test.tssrc/renderer/src/components/sidebar/codex-subagent-transcript-scope.tssrc/renderer/src/components/sidebar/worktree-card-compact-agent-row.subagent.test.tsxsrc/renderer/src/components/sidebar/worktree-card-compact-agent-row.tsxsrc/renderer/src/components/ui/sheet.test.tsxsrc/renderer/src/components/ui/sheet.tsxsrc/renderer/src/i18n/locales/en.jsonsrc/renderer/src/i18n/locales/es.jsonsrc/renderer/src/i18n/locales/ja.jsonsrc/renderer/src/i18n/locales/ko.jsonsrc/renderer/src/i18n/locales/zh.jsonsrc/shared/agent-hook-listener.tssrc/shared/codex-subagent-roster.test.tssrc/shared/codex-subagent-roster.tssrc/shared/codex-subagent-transcript-lifecycle.tssrc/shared/codex-subagent-transcript.test.tssrc/shared/codex-subagent-transcript.tstests/e2e/codex-subagent-sidebar-lifecycle.spec.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- src/renderer/src/components/sidebar/codex-subagent-progress-target.ts
- src/renderer/src/components/sidebar/codex-subagent-progress-target.test.ts
- src/renderer/src/components/sidebar/CodexSubagentProgressSheet.tsx
- src/renderer/src/components/sidebar/WorktreeCardAgents.activation.test.tsx
- src/renderer/src/components/sidebar/WorktreeCardAgents.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
tests/e2e/helpers/codex-subagent-rollout-fixture.ts (1)
149-151: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winInclude the response body in the hook failure message.
Three specs depend on this helper. When the hook server rejects a post, the current message reports only the status code. A 400 or 401 then gives no reason. Read the body and add it to the error.
♻️ Proposed change
if (response.status !== 204) { - throw new Error(`Codex hook POST returned ${response.status}`) + const body = await response.text().catch(() => '') + throw new Error( + `Codex hook POST returned ${response.status}${body ? `: ${body.slice(0, 500)}` : ''}` + ) }
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a10d1ae3-e9b5-455f-b6ba-9955b8cf0a29
📥 Commits
Reviewing files that changed from the base of the PR and between 97f3498f2d8ed421d5c12363c7cb91e4d28e5e68 and 39a1faf384cc5833a14d0c51c93e8917a6c62044.
📒 Files selected for processing (3)
tests/e2e/codex-subagent-concurrent-progress.spec.tstests/e2e/codex-subagent-state-and-session.spec.tstests/e2e/helpers/codex-subagent-rollout-fixture.ts
|
Thanks for the PR |
|
Thank you, @AmethystLiang! I also tagged you in the community discussion where I raised this missing capability. This is a high-frequency workflow for me—I often need to open a Codex subagent from the sidebar and follow its live progress—so I would really appreciate a review when you have a chance. Thanks again! |
df1125c to
588112d
Compare
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
tests/e2e/codex-subagent-state-and-session.spec.ts (2)
78-80: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider adding an explicit timeout to the parent-row assertion.
Line 78 waits up to 15 s for the child row to reach
Idle. Line 79 then asserts the parent row showsDonewith the default timeout. The parent status derives from a separate polling pass, so it can settle after the child row. The same pattern repeats at Lines 91, 118, and 125. If the CI default timeout is short, these assertions can flake.♻️ Proposed change
- await expect(parentAgentRow(orcaPage, context.prompt).getByLabel('Done')).toBeVisible() + await expect(parentAgentRow(orcaPage, context.prompt).getByLabel('Done')).toBeVisible({ + timeout: 15_000 + })
122-127: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReuse the existing
childRowlocator.Line 41 already defines
childRowfor the same session id. Line 122 recreates the locator. ReusechildRowfor consistency.♻️ Proposed change
- await expect(childAgentRow(orcaPage, childId)).toHaveCount(0, { + await expect(childRow).toHaveCount(0, { timeout: 15_000 })
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4a0a20c4-9e3e-4997-a4d8-1c41aa080d85
📥 Commits
Reviewing files that changed from the base of the PR and between b3965f3 and 588112d34da08a43ff7f0cbab3e5d61698f4adee.
📒 Files selected for processing (48)
src/main/agent-hooks/server-codex-subagent-dynamic-lifecycle.test.tssrc/main/agent-hooks/server-codex-subagent-transcript.test.tssrc/main/agent-hooks/server.tssrc/main/native-chat/transcript-reader.test.tssrc/renderer/src/assets/main.csssrc/renderer/src/components/agent-child-disclosure-label.tssrc/renderer/src/components/codex-subagent-display-label.tssrc/renderer/src/components/dashboard/DashboardAgentChildDisclosure.tsxsrc/renderer/src/components/dashboard/DashboardAgentRow.test.tsxsrc/renderer/src/components/dashboard/DashboardAgentRow.tsxsrc/renderer/src/components/dashboard/useDashboardData.tssrc/renderer/src/components/sidebar/CodexSubagentProgressSheet.test.tsxsrc/renderer/src/components/sidebar/CodexSubagentProgressSheet.tsxsrc/renderer/src/components/sidebar/WorktreeCardAgents.activation.test.tsxsrc/renderer/src/components/sidebar/WorktreeCardAgents.tsxsrc/renderer/src/components/sidebar/codex-subagent-progress-host-authority.test.tssrc/renderer/src/components/sidebar/codex-subagent-progress-host-authority.tssrc/renderer/src/components/sidebar/codex-subagent-progress-route.test.tssrc/renderer/src/components/sidebar/codex-subagent-progress-route.tssrc/renderer/src/components/sidebar/codex-subagent-progress-selection.test.tssrc/renderer/src/components/sidebar/codex-subagent-progress-selection.tssrc/renderer/src/components/sidebar/codex-subagent-progress-target.test.tssrc/renderer/src/components/sidebar/codex-subagent-progress-target.tssrc/renderer/src/components/sidebar/codex-subagent-transcript-scope.test.tssrc/renderer/src/components/sidebar/codex-subagent-transcript-scope.tssrc/renderer/src/components/sidebar/index.tsxsrc/renderer/src/components/sidebar/useWorktreeAgentRows.test.tssrc/renderer/src/components/sidebar/worktree-card-compact-agent-row.subagent.test.tsxsrc/renderer/src/components/sidebar/worktree-card-compact-agent-row.tsxsrc/renderer/src/components/sidebar/worktree-subagent-child-rows.tssrc/renderer/src/components/ui/sheet.test.tsxsrc/renderer/src/components/ui/sheet.tsxsrc/renderer/src/i18n/locales/en.jsonsrc/renderer/src/i18n/locales/es.jsonsrc/renderer/src/i18n/locales/ja.jsonsrc/renderer/src/i18n/locales/ko.jsonsrc/renderer/src/i18n/locales/zh.jsonsrc/renderer/src/store/slices/ui.tssrc/shared/agent-hook-listener.tssrc/shared/codex-subagent-roster.test.tssrc/shared/codex-subagent-roster.tssrc/shared/codex-subagent-transcript-lifecycle.tssrc/shared/codex-subagent-transcript.test.tssrc/shared/codex-subagent-transcript.tstests/e2e/codex-subagent-concurrent-progress.spec.tstests/e2e/codex-subagent-sidebar-lifecycle.spec.tstests/e2e/codex-subagent-state-and-session.spec.tstests/e2e/helpers/codex-subagent-rollout-fixture.ts
🚧 Files skipped from review as they are similar to previous changes (46)
- src/shared/codex-subagent-transcript.test.ts
- src/renderer/src/components/sidebar/useWorktreeAgentRows.test.ts
- src/renderer/src/components/codex-subagent-display-label.ts
- src/renderer/src/components/sidebar/codex-subagent-progress-selection.test.ts
- src/renderer/src/store/slices/ui.ts
- src/renderer/src/i18n/locales/ja.json
- src/renderer/src/components/agent-child-disclosure-label.ts
- src/renderer/src/components/ui/sheet.test.tsx
- src/renderer/src/components/sidebar/codex-subagent-progress-route.ts
- src/renderer/src/components/ui/sheet.tsx
- src/renderer/src/components/sidebar/CodexSubagentProgressSheet.test.tsx
- src/renderer/src/components/sidebar/codex-subagent-progress-host-authority.test.ts
- src/renderer/src/components/dashboard/useDashboardData.ts
- src/renderer/src/components/sidebar/index.tsx
- src/renderer/src/i18n/locales/es.json
- src/renderer/src/assets/main.css
- src/renderer/src/i18n/locales/en.json
- src/renderer/src/components/sidebar/worktree-subagent-child-rows.ts
- src/renderer/src/components/sidebar/worktree-card-compact-agent-row.subagent.test.tsx
- tests/e2e/codex-subagent-sidebar-lifecycle.spec.ts
- src/main/native-chat/transcript-reader.test.ts
- src/renderer/src/components/sidebar/codex-subagent-transcript-scope.ts
- src/renderer/src/components/sidebar/worktree-card-compact-agent-row.tsx
- src/renderer/src/components/sidebar/CodexSubagentProgressSheet.tsx
- src/renderer/src/components/sidebar/codex-subagent-progress-target.test.ts
- src/renderer/src/components/dashboard/DashboardAgentChildDisclosure.tsx
- src/shared/agent-hook-listener.ts
- src/main/agent-hooks/server-codex-subagent-transcript.test.ts
- src/renderer/src/components/sidebar/codex-subagent-progress-target.ts
- src/renderer/src/i18n/locales/zh.json
- src/renderer/src/components/sidebar/codex-subagent-progress-host-authority.ts
- src/renderer/src/components/sidebar/codex-subagent-transcript-scope.test.ts
- src/main/agent-hooks/server-codex-subagent-dynamic-lifecycle.test.ts
- src/main/agent-hooks/server.ts
- tests/e2e/codex-subagent-concurrent-progress.spec.ts
- src/renderer/src/components/dashboard/DashboardAgentRow.test.tsx
- src/shared/codex-subagent-roster.ts
- tests/e2e/helpers/codex-subagent-rollout-fixture.ts
- src/shared/codex-subagent-transcript-lifecycle.ts
- src/renderer/src/i18n/locales/ko.json
- src/renderer/src/components/sidebar/codex-subagent-progress-route.test.ts
- src/shared/codex-subagent-roster.test.ts
- src/renderer/src/components/dashboard/DashboardAgentRow.tsx
- src/renderer/src/components/sidebar/WorktreeCardAgents.tsx
- src/renderer/src/components/sidebar/WorktreeCardAgents.activation.test.tsx
- src/shared/codex-subagent-transcript.ts
588112d to
ebf835a
Compare
74f3894 to
38eb09f
Compare
Rebased onto upstream/main (d5dc7b9): the original 11 branch commits are folded into this one. Adaptations the new base required: - agent-hook-listener split (stablyai#16187): hasCodexParentTranscript moved to providers/codex-state.ts and refreshCodexSubagentTranscriptStatus to providers/codex-events.ts. - server.ts split into agent-hooks/server/*: the poll loop now lives in server-status-retries.ts on top of CodexSubagentPollScheduler, which gained an optional per-entry delayMs so the quiet-roster backoff (1s -> 5s) coexists with the shared coalesced timer. - renderer store split: the codex-subagent-progress modal type moved to slices/ui/ui-slice-contract-contextual.ts. - compact row: canonical-label tooltip now composes with upstream's monitoring ordering; row activation moved to use-codex-subagent-row-activation.ts to stay under max-lines. - tests adapted: TooltipProvider wraps (AgentStateDot tooltip), useNow-based freshness (mocked in the sheet test), scheduler-backed poll assertions, pane-agent-identity inventory entry.
38eb09f to
a59e657
Compare
Summary
working,waiting, andidlefrom the child rollout so a parked child does not keep its completed parent marked as running.fork_turns: "all") child rollouts at the provider-authored child start boundary. Parent user/assistant turns copied into the rollout stay hidden while the child's messages, reasoning, custom tool calls, and results remain live./root/<name>child labels while retaining canonical metadata in tooltips.This is a focused follow-up to #9637. It does not close the remaining cross-worktree orchestration and deduplication scope in #8251.
Closes #12621
Refs #8251
Screenshots
The screenshot was captured from an isolated Electron E2E profile with synthetic Codex rollouts; no user session history is included.
Testing
pnpm lintpnpm typecheck(full typecheck insidepnpm build;typecheck:webrepeated on the final commit)pnpm testcompleted after rebasing ontoupstream/main@41c4d8e8: 56,376 passed, 190 skipped, and 23 failed across nine unrelated files when launched inside an Orca-managed macOS terminal.shell-startup-feature-channelpassed 12/12 after clearing inherited Orca shell variables; the WSL separator passed 4/4 with the ignored cross-version checkout cache temporarily moved outside the scan and then restored.git_branch/find_git_branch), and 13 happy-dom/xterm IME assertions do not activate or clear the expected composition overlay in this runtime.idle → working → waiting → working → complete, parent-state convergence, parent-session replacement/stale-watcher isolation, and parent/other-child history exclusion. Every scenario passed twice with 2 workers (8/8).pnpm buildpassed after the rebase, including full typecheck, relay, CLI, Electron/Vite, built-skills verification, web projection, and macOS native helpers. The optional/usr/local/bin/orca-devsymlink refresh was denied without elevation, but the build continued and exited successfully.git diff --checkfdaba84b6a: the 3 current poll/dynamic-lifecycle/transcript files / 11 tests passed; all 12 Codex subagent test files / 51 tests passed; fullpnpm typecheck, fullpnpm lint, formatting, andgit diff --checkpassed. The server integration test covers transcript-only child discovery after more than 60 seconds of quiet polling and restoration of the 1-second cadence on the next Codex turn.Additional real-session validation used Codex CLI 0.146.0 in an isolated dev profile. A child spawned with
fork_turns: "all"showed its unique progress marker and live tool activity, did not show the unique parent-history marker, transitioned to Idle with its final result retained, disappeared from the dynamic child row after completion, and returned its result to a Done parent.A second real-session matrix on the same CLI started three children with distinct long-running, short-running, and
wait_agentpaths. Orca showed the long child as Working and the parked child as Idle after the short child completed; completed rows disappeared independently. Switching the non-modal sheet from the completed long child to the waiting child replaced the transcript instead of merging it. Aftersend_messageresumed the parked child, its sheet retained only its own progress/wait/resume records, all live child rows cleared, and the parent converged to Done withREAL_PARENT_DONE_20260804.Review Notes
The implementation was iterated against real dynamic child sessions, including children that start after the initial parent hook, park in
wait_agent, resume, complete, disappear, and are followed by a new child. The generic Codex transcript view is unchanged by the parent-prefix filter; scoping is applied only in the subagent progress surface using the capturedstartedAtboundary.The hook server keeps a 1-second incremental parent-rollout poll while the lead is working or a transcript child is tracked. With an empty roster and a non-working or pre-prompt lead, it backs off from 1 to 2 to 4 to 5 seconds, reducing steady quiet filesystem checks by 80%; child activity or any new Codex hook restores the 1-second cadence. The quiet poll stays capped instead of stopping because transcript-only late child creation can arrive without another hook. Reads reuse the existing cursor and byte/line bounds rather than rescanning whole files or all sessions.
The change considers macOS, Linux, Windows, local worktrees, folder workspaces, managed runtimes, runtime-owned SSH panes, and legacy SSH fail-closed behavior. It adds no Git commands or native dependencies.
Security Audit
Notes