fix(orchestrator): Keep Claude child work on the child thread - #5456
fix(orchestrator): Keep Claude child work on the child thread#5456mwolson wants to merge 244 commits into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
25de21d to
0af2a6e
Compare
0e1b4fe to
1598863
Compare
ApprovabilityVerdict: Skipped Macroscope did not run approvability analysis for this PR. Diff is too large for automated approval analysis, so this PR cannot be approved automatically. You can add or adjust custom eligibility rules. Learn more. |
22bd872 to
a27c1cc
Compare
1598863 to
b5f1b94
Compare
a186d64 to
5b1a115
Compare
b5f1b94 to
9c18ee2
Compare
96891a3 to
993407d
Compare
Co-authored-by: codex <codex@users.noreply.github.com>
- Initialize provider as unchecked in a pending state - Update initial probe message to reflect session-local status
- Type the runtime effect with `Scope` - Build the ACP session runtime without wrapping it in `Effect.scoped`
- Use strict TurnId and ProviderItemId parsing in Codex session routing - Decode in-memory stdio chunks in streaming mode to avoid split UTF-8 corruption
- Transfer session-owned scopes into adapter state - Ensure runtime scopes close on stop and startup failure - Add regression coverage for scoped lifecycle cleanup
- Close the managed native event logger when the adapter layer tears down - Make session runtime close idempotent with an atomic closed flag - Add coverage for flushing thread native logs on shutdown
- Use codex app-server snapshots for auth, models, and skills - Remove legacy CLI/config discovery paths and related helpers - Update tests for the new provider status flow
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
- Add paginated thread history with bounded snapshots and replay limits - Trim oversized wire payloads and support progressive mobile history loading
- Add optional title regeneration request and start time to thread shells - Cover cache serialization on mobile and client runtime
- ChatView: pingdotgg#5880 auto-settle-on-merge setting flows into effectiveSettled, pingdotgg#5644 browser favicon project registration effect, activeProjectRef memo, desktopByTabId on both RightPanelTabs mounts - server: provide ServerSecretStore to the McpSessionRegistry's ServerEnvironment layer (pingdotgg#6325 reads publish opt-in per descriptor) - mobile: 3-way merged main's deltas into the v2 thread screens (NewTaskDraftScreen keeps the branch title seed + main's environmentId, threadListV2 keeps both new test suites, queries imports deduped) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…toggles Restores main's one-inset rule (pingdotgg#5226) that a rebase resolution had overridden with a conditional right-2 offset, which made the controls jump sideways whenever the right panel opened. Also restores the live-agent count badge on the right-panel toggle (pingdotgg#5745) that the round-6 replay dropped, and applies the same fixed-position rule to the pull requests page: the toggle now stays mounted at one absolute inset in both states, with a footprint spacer in the list header so the refresh button never slides underneath it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The right controls carry mr-px (main's border compensation for anchoring inside the panel frame), which left the sidebar trigger one pixel closer to its edge and the sheet-mode tab bar one pixel tighter than the closed state. Mirror the pixel on the trigger and the sheet layout-controls slot so all three read the same inset. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gger The trigger's icon falls through to the Button default (size-4) while the right cluster hard-coded size-3.5, so the two ends of the titlebar read a pixel apart on every edge. All five layout-control icons now use size-4, matching the trigger and the pull requests page's refresh icon. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Omit transcript bodies from shell rows - Query archived threads separately and stream compact resume metadata
Re-applies the deltas that mid-stack blob reverts discarded, and merges main's work into the v2-owned surfaces: - keybindings: main's STATIC_KEYBINDING_COMMANDS rename plus both new commands (rightPanel.toggleMaximized alongside threadPanel.toggle) - OpenInPicker: main's remote-open/SSH routing and favorite-editor shortcut layered onto the branch's panel/toolbar variants; the extracted shouldShowOpenInPicker now takes remoteOpenMode - ChatMarkdown: main's bare-filename resolver (pingdotgg#6297) ported into the branch's module-level component factory, plus pingdotgg#4133 title-attribute stripping on links and images - ComposerPrimaryActions: main's pingdotgg#4781 model (stop stays reachable, send joins it when Enter-to-send is unavailable) carrying the branch's steering send button - ComposerPendingUserInputPanel: main's collapsible redesign with the v2 RuntimeRequestId and responseCapability gate - ChatComposer: main's oversized-prompt submission guard wrapping the branch's dispatch-mode send - preview shell: main's container-aware width clamp ported into the branch's usePreviewPanelInlineSize hook - MessagesTimeline/Sidebar: main's day-aware timestamps, code-font tool bodies and provider accent badges on the v2 runtime shell - index.css: main's @variant dark migration (pingdotgg#6381) replaces the branch's standalone .dark block - contracts: main's send-turn image mime allowlist re-homed to chatAttachment.ts, where v2 keeps the other send-turn limits Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports v1's pingdotgg#5246 guard into the v2 dispatcher: a stored receipt only proves that this exact command already ran for the thread it was recorded against, so returning it for a command aimed at a different thread reports success for work that never happened there. The check is extracted as canReplayCommandReceipt so the rule is unit-testable, and reuse now fails with OrchestratorCommandIdConflictError like the v1 path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Keep prominent activity rows visible with lifecycle status and provider metadata - Move feed sizing logic into tested helpers and preserve native measurement for activity groups
Re-applies the deltas that mid-stack blob reverts discarded, and merges main's round-9 work into the v2-owned surfaces: - settings: main's Integrations page (pingdotgg#7082) coexists with the branch's Scheduled Tasks page in the path union, section labels, icons, and search catalog - contracts: main's preview appearance/zoom/viewport settings imports restored beside the branch's modelSelection home for ModelSelection - mobile: main's built-in themes (pingdotgg#6619) re-applied to the v2 thread screens and work log (useThemeColor over hand-rolled color-scheme ternaries) - MessagesTimeline: main's pingdotgg#7157 cleanup adopted (toolCallExpandedBody class name unexported, implementation-detail test dropped) - ChangedFilesTree: main's styled tooltip (pingdotgg#7209) carrying the v2 runId - pullRequestDetail tests: branch's row-action coverage renamed onto main's buildAddSelectionToAgentHandoff (pingdotgg#6597) - lint: migrated the six branch-owned native title tooltips that main's new no-native-title-tooltip rule (pingdotgg#7209) flags to styled Tooltips (GitActionsControl, QueuedRunsControl, TimelineSystemDivider, MessagesTimeline intent badge and MCP tool logo) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports pingdotgg#7083 into the v2 session path, which replaced the v1 ProviderService where main's gate lives. Instead of withholding the whole t3-code MCP credential — on this branch it also carries the thread orchestration and worktree toolkits — the credential is minted without the "preview" capability when enableAgentBrowserAccess is off, so every preview tool call rejects while orchestration stays available. ProviderSessionManager reads the setting at prepare time (deny on an unreadable settings file, matching main), rotates a reused credential whose capability set no longer reflects the setting, and the session config now carries browserToolsAvailable so the Codex adapter keeps its developer instructions truthful via main's parameterized instruction builders instead of the removed constants. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
519c42a to
4c55679
Compare
…s style simplification Main's pingdotgg#6381 deleted the shared .workspace-topbar and scroll-fade rules from index.css after inlining them at main's own call sites, but this branch's slim chat chrome still references both classes. The round-8 rebase took the deletion without migrating the branch call sites, so the header collapsed to zero height — the breadcrumb sat on the window edge, timeline rows scrolled unfaded through it, and the thread-details popover anchored to the collapsed header. Restores both as composable utilities in pingdotgg#6381's own style: a workspace-topbar utility for the titlebar rows, and the branch's chat-timeline-scroll-fade mask (soft ramp plus a full-height scrollbar column). Also drops the duplicated media override and its dead settings-page-scroll-fade selector. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ation A follow-up sweep against pingdotgg#6381 found the branch still carrying the pre-simplification forms it replaced, which my earlier fix had papered over with a compat utility instead of finishing the migration: - ChatView now uses main's inlined titlebar sizing and the data-workspace-titlebar-controls hook on both control clusters. The class-based markup was silently missing the themed-toggle bridge (html[data-theme-id] [data-workspace-titlebar-controls] …), so custom themes lost their titlebar accent in the thread view. - The scroll-to-end pill becomes main's Button size="xs" variant="glass" instead of a hand-rolled button recreating it. - MessagesTimeline uses main's consolidated topbar-scroll-fade utility; the byte-identical chat-timeline-scroll-fade copy and the workspace-topbar compat utility are gone. - The composer-glass dark rules move into nested @variant dark like main's (the raw .dark duplicates could drift from the nested copies they shadowed), including the branch-only queue strip. - The pre-pingdotgg#6381 dialog-glass/dialog-backdrop/dropdown-glass class rules and their .dark variants are deleted: the pingdotgg#6381 utilities plus call-site shadow utilities own every declaration, and the stale dropdown rule still had the saturate-less backdrop-filter. The dead model-picker-surface dark rule goes with them. index.css now has zero raw .dark selectors outside the variant definitions, matching the doctrine in .macroscope/check-run-agents/ui-consistency.md. Verified against the emitted production CSS: dark variants compile to :is(.dark,.dark *) with their @supports color-mix fallbacks intact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Complete retry items when provider activity resumes - Keep retry progress visible across web and mobile clients
9c18ee2 to
ea1bb95
Compare
CI Check fails on current CTM because layerTest now surfaces ServerSettingsError while the ProviderSessionManager test layer requires never. orDie matches the other test layers.
A provider-native subagent could open its child thread with an empty or whitespace-only user message, which renders as an empty bubble under the "Sent by another agent" label. The Claude adapter emitted the opening prompt whenever the subagent was new, and a task_progress frame can register a subagent before any frame carries its prompt, so the message was emitted with the "" default and never rewritten when the real prompt arrived on a later task_started. A shared hasSubagentPromptText guard now gates every subagent opening message. The Claude adapter emits it the first time the task prompt actually has text rather than on first registration, so a late prompt still opens the child thread exactly once. Codex's existing length check becomes trim-aware, and Cursor and ACP pick up the same guard.
ea1bb95 to
4c2c69c
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 68422a1. Configure here.
2d623ac to
37f40d9
Compare

What Changed
A Claude child can keep talking after the parent root settles. Later text, tools, and results were landing on the parent thread, so the child's work showed up in the wrong conversation. Those later frames now stay on the child.
A blank or whitespace Agent prompt, or progress that arrived before the real prompt, opened the child with an empty "Sent by another agent" bubble. The child now waits for real prompt text before showing that opening message. A child that never gets a prompt still runs. It just starts with no blank bubble.
Checked on a live Claude thread. One Agent launched with a single space, another with a real prompt. The blank child had no user message. The sibling had exactly one opening message with the real prompt.
Why
Settle on the parent is not the end of that child's stream. Routing later frames with the parent's turn mixed the two conversations.
The empty bubble was the same class of mistake: the child thread showed a user message that nobody sent.
Review both here. #5388 claude-postsettle-attribution is closed as absorbed.
UI Changes
Child output after the parent settles stays in the child thread on web and mobile. A blank Agent launch no longer creates an empty "Sent by another agent" bubble.
No before/after screenshots.
Checklist
Note
Low Risk
Narrow behavioral change in ACP subagent UI projection with no auth, persistence, or routing logic touched.
Overview
When an ACP provider registers a subagent child thread, the adapter only projects the opening user message and turn item if
hasSubagentPromptText(update.prompt)is true (non-empty after trim).Previously, every subagent launch always emitted
message.updatedandturn_item.updatedfor the prompt, which could surface an empty “Sent by another agent” bubble when the agent sent a whitespace-only prompt or progress arrived before real prompt text.Child thread creation and subagent metadata emission are unchanged; only the optional prompt conversation artifacts are gated.
Reviewed by Cursor Bugbot for commit ed223fe. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix Claude child thread output attribution after root thread settlement
hasSubagentPromptTextto suppress empty opening user message bubbles in child threads when a subagent prompt is blank, whitespace-only, null, or undefined; applied across Claude, ACP, Codex, and Cursor adapters.ClaudeAdapterV2to track subagent lineages per native thread across turns, serializing SDK message handling via a semaphore and using generation-based guards to prevent duplicate emissions.parent_tool_use_idare routed to the correct child thread rather than leaking to the root.'Background task completed.') from the visible run queue inderiveThreadQueueWorkflowState.ClaudeAdapterV2internal state; subagent indexing moved from per-turn to session scope, which changes how interrupts, session closes, and failed wake drains are handled.Macroscope summarized ed223fe.