feat(orchestrator): introduce new orchestrator - #2829
juliusmarminge wants to merge 655 commits into
Conversation
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
| return decodeTranscript({ | ||
| ...metadata, | ||
| entries, | ||
| }); | ||
| }); |
There was a problem hiding this comment.
🟢 Low testkit/ReplayTranscriptNdjson.ts:116
The call to decodeTranscript at line 116 invokes Schema.decodeUnknownSync, which throws on validation failure. Since this isn't wrapped in Effect.try, any validation error becomes an uncaught exception (defect) instead of a typed ProviderReplayNdjsonParseError. This breaks the function's declared error contract. Consider wrapping the call in Effect.try to catch the exception and convert it to the declared error type.
- return decodeTranscript({
- ...metadata,
- entries,
- });
+ return yield* Effect.try({
+ try: () =>
+ decodeTranscript({
+ ...metadata,
+ entries,
+ }),
+ catch: (cause) =>
+ new ProviderReplayNdjsonLineParseError({
+ lineNumber: lines.length,
+ line: "<transcript validation>",
+ cause,
+ }),
+ });🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file apps/server/src/orchestration-v2/testkit/ReplayTranscriptNdjson.ts around lines 116-120:
The call to `decodeTranscript` at line 116 invokes `Schema.decodeUnknownSync`, which throws on validation failure. Since this isn't wrapped in `Effect.try`, any validation error becomes an uncaught exception (defect) instead of a typed `ProviderReplayNdjsonParseError`. This breaks the function's declared error contract. Consider wrapping the call in `Effect.try` to catch the exception and convert it to the declared error type.
Evidence trail:
apps/server/src/orchestration-v2/testkit/ReplayTranscriptNdjson.ts lines 50-53: `decodeTranscript = Schema.decodeUnknownSync(ProviderReplayTranscript)` — throws on failure.
Line 116-118: `return decodeTranscript({...metadata, entries})` — called directly inside Effect.gen without Effect.try wrapper.
Lines 55-68 (`parseReplayRecord`): same pattern but correctly wrapped in `Effect.try`.
Line 80: function declares error type `ProviderReplayNdjsonParseError`.
packages/contracts/src/orchestrationV2.ts lines 1561-1568: `ProviderReplayTranscript` schema with `TrimmedNonEmptyString` fields that can fail validation.
…der adapters (t3-29f.6) Assessment of upstream PR pingdotgg#2829 (pingdotgg/t3code) from juliusmarminge: WIP wire orchestration v2 provider adapters with Codex and Claude adapters, event sourcing, provider session management, and replay testkit. Relevance to target issues: - pingdotgg#2838 (session resume): HIGH — ProviderSessionManager persists session IDs and separates startSession/resumeSession operations - pingdotgg#2778 (subagent hang): MEDIUM — ProviderEventIngestor provides infrastructure to forward permission events, but UI plumbing not yet wired - pingdotgg#2886 (thread stuck working): HIGH — event-sourced projections replace mutable state flags, eliminating sticky "working" states The PR is a draft (34 commits, not merged). No OpenCode ACP adapter exists yet in v2 — OpenCode would need its own adapter wired into the ProviderAdapterRegistry. Recommend watching for merge and adding an OpenCode adapter post-merge.
…n v2 provider adapters)
The upstream PR pingdotgg#2829 added orchestrationV2 methods to the WsRpcClient interface. The test mock in service.threadSubscriptions.test.ts was missing the orchestrationV2 property, causing a typecheck failure: 'Property orchestrationV2 is missing in type...' Added orchestrationV2 mock with dispatchCommand, getThreadProjection, subscribeShell, and subscribeThread as vi.fn() stubs.
The upstream PR pingdotgg#2829 targets a newer Effect version than our fork's pinned effect@4.0.0-beta.73. Fixes: - Replace Random.nextUUIDv4 with Crypto.randomUUIDv4 (beta.73 API) - Fix deterministic Service tag keys to match fork convention (include file path segments; e.g. Adapters/ClaudeAdapterV2/...) - Replace Schema.decodeSync with Schema.decodeUnknownEffect inside Effect.gen generators (tsgo schemaSyncInEffect rule) - Replace inline Schema.encodeUnknownSync with module-level wrappers to avoid schemaSyncInEffect rule inside generators
|
🚀 Expo continuous deployment is ready!
|
| Effect.gen(function* () { | ||
| const threadId = payloadInput.threadId ?? input.threadId; | ||
| const eventId = yield* idAllocator.allocate.event({ | ||
| threadId, | ||
| providerSessionId: input.providerSessionId, | ||
| }); | ||
| const occurredAt = yield* DateTime.now; | ||
| return yield* Schema.decodeUnknownEffect(OrchestrationV2DomainEvent)( | ||
| compactUndefined({ | ||
| id: eventId, | ||
| type: payloadInput.type, | ||
| threadId, | ||
| runId: payloadInput.runId ?? input.runId, | ||
| nodeId: payloadInput.nodeId ?? input.nodeId, | ||
| provider: input.event.provider, | ||
| rawEventId: input.rawEventId, | ||
| occurredAt, | ||
| payload: payloadInput.payload, | ||
| }), | ||
| ); |
There was a problem hiding this comment.
🟡 Medium orchestration-v2/ProviderEventIngestor.ts:109
In makeDomainEvent, the ?? operator on lines 121 and 123 treats explicit null as equivalent to undefined, causing payloadInput.runId ?? input.runId to fall back to input.runId when payloadInput.runId is explicitly null. Since the type is readonly runId?: RunId | null, this means explicit null values from the caller (e.g., input.event.node.runId being null on line 172) are incorrectly overwritten instead of preserved. Consider using === undefined checks like lines 161-162 and 210-211, or use payloadInput.runId === undefined ? input.runId : payloadInput.runId.
const threadId = payloadInput.threadId ?? input.threadId;
- const runId = payloadInput.runId ?? input.runId;
- const nodeId = payloadInput.nodeId ?? input.nodeId;
+ const runId = payloadInput.runId === undefined ? input.runId : payloadInput.runId;
+ const nodeId = payloadInput.nodeId === undefined ? input.nodeId : payloadInput.nodeId;🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/server/src/orchestration-v2/ProviderEventIngestor.ts around lines 109-128:
In `makeDomainEvent`, the `??` operator on lines 121 and 123 treats explicit `null` as equivalent to `undefined`, causing `payloadInput.runId ?? input.runId` to fall back to `input.runId` when `payloadInput.runId` is explicitly `null`. Since the type is `readonly runId?: RunId | null`, this means explicit `null` values from the caller (e.g., `input.event.node.runId` being `null` on line 172) are incorrectly overwritten instead of preserved. Consider using `=== undefined` checks like lines 161-162 and 210-211, or use `payloadInput.runId === undefined ? input.runId : payloadInput.runId`.
Evidence trail:
apps/server/src/orchestration-v2/ProviderEventIngestor.ts lines 105-106 (payloadInput type with `RunId | null`), line 121 (`runId: payloadInput.runId ?? input.runId`), line 122 (`nodeId: payloadInput.nodeId ?? input.nodeId`), lines 161-162 and 210-211 (codebase uses `=== undefined` pattern elsewhere). packages/contracts/src/orchestrationV2.ts line 358 (`runId: Schema.NullOr(RunId)` on ExecutionNode - confirms null is a valid value), line 857 (`runId: Schema.optional(RunId)` on EventBase - domain event uses optional/undefined, not null). apps/server/src/orchestration-v2/ProviderEventIngestor.ts lines 80-81 (compactUndefined only strips undefined, not null).
79031a1 to
4e68dcb
Compare
4e68dcb to
c7539b9
Compare
| function nativeThreadId(provider: ProviderKind, thread: OrchestrationV2ProviderThread): string { | ||
| const id = thread.nativeThreadRef?.nativeId; | ||
| if (id === null || id === undefined || id.trim().length === 0) { | ||
| throw new ProviderAdapterProtocolError({ |
There was a problem hiding this comment.
🟡 Medium Adapters/AcpAdapterV2.ts:271
When nativeThreadId is called inside Effect.gen generators (e.g., lines 899, 1813), the thrown ProviderAdapterProtocolError becomes an untyped defect instead of a typed failure. This bypasses Effect.mapError and other typed error handlers, causing the error to propagate as an unexpected defect. Consider converting nativeThreadId to return Effect<string, ProviderAdapterProtocolError> and yielding it at each call site, or inlining the validation with yield* new ProviderAdapterProtocolError(...) so the failure is properly typed.
Also found in 1 other location(s)
apps/server/src/orchestration-v2/ThreadManagementService.ts:278
The statement
return yield* managementError(...)cannot work correctly becausemanagementError()returns aThreadManagementErrorinstance, not anEffect. Theyield*operator inEffect.genexpects an Effect value. This should bereturn yield* Effect.fail(managementError(...)). The correct pattern is demonstrated elsewhere in this file (lines 241-246) whereEffect.fail(managementError(...))is properly used. This same bug pattern repeats at lines 291, 333, 357, 374, 390, 406, and 427.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts around line 271:
When `nativeThreadId` is called inside `Effect.gen` generators (e.g., lines 899, 1813), the thrown `ProviderAdapterProtocolError` becomes an untyped defect instead of a typed failure. This bypasses `Effect.mapError` and other typed error handlers, causing the error to propagate as an unexpected defect. Consider converting `nativeThreadId` to return `Effect<string, ProviderAdapterProtocolError>` and yielding it at each call site, or inlining the validation with `yield* new ProviderAdapterProtocolError(...)` so the failure is properly typed.
Evidence trail:
1. nativeThreadId function with throw: apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts lines 268-277
2. Call site inside Effect.gen: apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts line 899
3. Call site inside Effect.gen: apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts line 1813
4. Correct yield* pattern for comparison: apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts line 1808
5. ProviderAdapterProtocolError class definition: apps/server/src/orchestration-v2/ProviderAdapter.ts lines 316-327
6. Effect.gen implementation delegating to fromIteratorUnsafe: https://github.com/Effect-TS/effect-smol packages/effect/src/internal/effect.ts lines 1104-1125
7. fromIteratorUnsafe calling iter.next() without try/catch: https://github.com/Effect-TS/effect-smol packages/effect/src/internal/effect.ts lines 1285-1307
8. FiberImpl.runLoop catch block converting thrown errors to exitDie: https://github.com/Effect-TS/effect-smol packages/effect/src/internal/effect.ts lines 646-650
9. die = exitDie producing Effect<never> (untyped): https://github.com/Effect-TS/effect-smol packages/effect/src/internal/effect.ts line 947
Also found in 1 other location(s):
- apps/server/src/orchestration-v2/ThreadManagementService.ts:278 -- The statement `return yield* managementError(...)` cannot work correctly because `managementError()` returns a `ThreadManagementError` instance, not an `Effect`. The `yield*` operator in `Effect.gen` expects an Effect value. This should be `return yield* Effect.fail(managementError(...))`. The correct pattern is demonstrated elsewhere in this file (lines 241-246) where `Effect.fail(managementError(...))` is properly used. This same bug pattern repeats at lines 291, 333, 357, 374, 390, 406, and 427.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Background-task notifications and delegated completions queued behind a held queue are hidden from the queue UI, so the Resume queue control never appeared, yet thread.settle counted them as active work. Settle now cancels those automatic runs in the same transaction; user-queued messages still block it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep main's recycled mobile list and per-row clock scoping alongside V2 runtime ownership, subagent filtering, and unread completion labels. Preserve provider compatibility diagnostics and shared PR badge controls while retaining V2 authentication actions and linked-PR tooltips. Port main's PR batching and settlement quota improvements into the V2 services.
…13311) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…erk bridge (#13204) Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…3347) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Summary
Validation
Notes
Closes
Verified against the branch with code/commit evidence. Issues listed under High confidence have a concrete V2 mechanism (named in the note). Medium confidence items belong to a V1 race or lifecycle class that V2 structurally removes; prune any you want to re-verify after merge.
High confidence
Closes #871 — V2 mints message identity itself in
orchestration-v2/IdAllocator.ts(random id scoped by thread + ordinal) instead of keying projections on provider-supplied message…Closes #4673 — V2 owns queue state in the orchestrator with explicit queue controls and pending-question commands (
fix(queue): preserve and hold queued messages after restart,fea… Closes #2778 — V2 tracks delegated children in projections and wakes the parent when they finish (fix(orchestrator): Stop treating a wait timeout as a dead child (#7427),fix(orch…Closes #4952
Closes #4873
Closes #4775
Closes #4795
Closes #4710
Closes #4668
Closes #4619
Closes #4584
Closes #4561
Closes #4713
Closes #4198
Closes #4452
Closes #3797
Closes #4232
Closes #3666
Closes #3580
Closes #2785
Closes #2789
Closes #3138
Closes #1404
Closes #231
Closes #216
Closes #12940 — CursorAdapterV2 passes enableAgentRetries: true to the Cursor SDK session (apps/server/src/orchestration-v2/Adapters/CursorAdapterV2.ts:331)
Closes #12928 — AcpAdapterV2 maps ACP tool kind
searchtofile_searchand onlyfetchtoweb_search, replacing main's canonicalItemTypeFromAcpToolKind which lumpssearchand…Closes #12915 — The buggy schedulePromptAdmissionRecovery path lives only in V1's OpenCodeAdapter.ts, which V2 removes in favour of OpenCodeAdapterV2 plus commits 'correlate OpenCode…
Closes #12904 — V2 deletes the V1 provider adapter layer that raised ProviderAdapterSessionClosedError and replaces it with ProviderSessionManager plus ProviderRuntimeRecoveryService,…
Closes #12679 — The branch carries 'fix(server): preserve provider history across repeated rollbacks (#12676)' and 'fix(pi): use native forks and preserve rollback session identity',…
Closes #12285 — The settledDeliveryCount cohort cap no longer exists on the branch.
Closes #12100 — V2 makes queuing server-owned with a queued_turn intent released as a separate turn after the active turn (fix(web): retain server-side queuing on v2, fix(orchestratio…
Closes #11968 — V2's orchestrator MCP toolkit ships t3_thread_update with action='rename' that defaults to the calling thread (apps/server/src/mcp/ThreadMetadataMcpService.ts, toolkit…
Closes #11889 — V2 deletes the reactor-based path (orchestration-v2/ThreadDeletion.ts runs through the serialized orchestrator and effect worker) and lands 'fix(server): cancel pendin…
Closes #11799 — V2's ProviderSessionManager release path writes runtime-request.updated with a not_resumable capability for every pending approval_request and user_input_request bound…
Closes #11730 — V2's server-owned settlement rejects threads with pendingBackgroundTasks/live activity (ThreadSettlementService.isAutoSettlementCandidate) and adds 'feat(orchestrator)…
Closes #11711 — V2's isAutoSettlementCandidate in orchestration-v2/ThreadSettlementService.ts returns false when pinnedAt is set (covered by ThreadSettlementService.test.ts 'excludes…
Closes #11428 — V2 commit "fix: stop retained background work after a turn settles" makes ProviderTurnControlService.interrupt accept a non-running run that still has pending backgrou…
Closes #10928 — orchestration-v2/RestartContinuation.ts dispatches the automatic continuation with the source run's modelSelection, whose options carry reasoningEffort, so the restart…
Closes #10786 — V2 records the reply on the
user_input_requestturn item itself asquestionAnswer(answers plusquestionTextById) in Orchestrator.ts rather than synthesizing a u…Closes #10545 — V2 adds a distinct Limited stop state with resume/snooze-at-reset ("feat(v2): show provider limit stops as Limited (#12677)", "#12686", "#12687"), documented in the V2…
Closes #10480 — V2 runs Cursor through the official
@cursor/sdkand explicitly does not use Cursor's ACP transport for V2 execution (user-cursor.md.Closes #10099 — V2 makes settlement server-owned in ThreadSettlementService.
Closes #9107 — V2 models provider-owned background work as first-class turn items (background_task/background_command/monitor in orchestrationV2.ts) with normalized post-settlement W…
Closes #9047 — apps/server/src/provider/Layers/CursorAdapter.ts does not exist on V2.
Closes #9029 — ClaudeAdapterV2 projects TodoWrite todos into todo_list plan items rather than depending on Task tools, surfaced by "fix(web): surface v2 todo-list plans as task progr…
Closes #8946 — V2's deriveTurnFolds pulls subagent items and background work entries into the run fold and drops main's agent-spawn never-fold exclusion.
Closes #8594 — The V1 ClaudeAdapter is deleted on V2.
Closes #8499 — V2 models native subagents and maps nested Codex subagent threads into thread lineage, rendered by "feat(web): show subagent models and running count in Lineage" after…
Closes #8091 — Task steps are projected from the persisted event log, and "fix(orchestrator): preserve task-step elapsed time across restart (#10051)" restores the list after relaunch.
Closes #7328 — V2 ports title regeneration to the orchestrator with tracked contract state: 'feat(contracts): track thread title regeneration', 'feat(orchestration): port thread titl…
Closes #7281 — V2 carries per-subagent model through projections: 'fix(claude): retain requested subagent models', 'fix(server): preserve Claude subagent models', 'feat(web): show su…
Closes #7244 — V2 runs Cursor on the official @cursor/sdk and treats CURSOR_API_KEY as the auth method (docs/user/cursor.md prerequisites.
Closes #7155 — V2's provider session recovery plus '[orchestrator-v2] fix(orchestrator): Restore Claude session continuity for resume, wake, and idle release (#3860)' rebuilds the re…
Closes #7075 — V2's CodexSessionRuntime sends thread/resume with excludeTurns: true on the main resume path (apps/server/src/provider/Layers/CodexSessionRuntime.ts:751 on the branch,…
Closes #5953 — V2 models native Codex subagents as separate projected child threads (feat(orchestration-v2): model native subagents.
Closes #5750 — ProviderRuntimeRecoveryService reconciles non-terminal runs against actual provider inventory at startup/shutdown and retires the outbox effects tied to the lost proce…
Closes #5518 — V2 tracks delegated children in projections and settlement (fix(notifications): silence subagent threads.
Closes #5476 — Server-owned ThreadSettlementService returns no settlement whenever any linked pull request snapshot is missing or still open, and the guarded thread.auto-settle comma…
Closes #5454 — ProviderRuntimeRecoveryService reconciles on startup/shutdown and cancels every pending runtimeRequest with a user-facing 'server restarted before the provider work co…
Closes #5436 — V2 makes the follow-up queue server-owned and durable (queued messages keep order and are held across a server restart.
Closes #5110 — V2 adds ProviderTextDeltaCoalescer and ThreadLiveEventCoalescer, which buffer and flush provider text deltas before persistence/publication instead of writing one dura…
Closes #4650 —
ClaudeAdapterV2handles the SDKcompact_boundarymessage and publishesusedTokens: afterTokenCountfromcompact_metadata.post_tokens, replacing V1's monotonic…Closes #4495 — The failing call site (
context.query.setPermissionModewrapped asturn/setPermissionModeinapps/server/src/provider/Layers/ClaudeAdapter.ts) does not exist in V2.Closes #2477 — V2 models native subagents as distinct lineage nodes with their own projection rows rather than splicing their text into the parent stream — `feat(orchestration-v2): m…
Medium confidence (under review)
Closes #4568
Closes #4766
Closes #4456
Closes #4399
Closes #3744
Closes #2921
Closes #3624
Closes #3149
Closes #2336
Closes #538
Closes #2173
Closes #2065
Closes #12926 — The 'Provider session did not survive a server restart' path exists only on main (serverRuntimeStartup.ts:346)
Closes #12885 — Cross-thread session eviction is a V1 session-lifecycle race.
Closes #12762 — V2 never replays the V1 event log: LegacyV1ThreadImporter reads projection_thread_messages from a statev2.sqlite snapshot, so a legacy thread.message-sent row missing…
Closes #12694 — V2 replaces ensureSessionForThread's restart branch with ProviderSessionTransitionPolicy plus recovery that checks providerThreadHasPendingBackgroundTasks before retir…
Closes #12502 — Stuck-Working class that V2 addresses via run finalization separate from provider turn completion plus 'fix(grok): Prevent spurious wake run after in-turn monitors' an…
Closes #12467 — The branch adds 'fix(server): recover Pi resumes without reusing native history (#12933)' and 'fix(pi): use native forks and preserve rollback session identity', which…
Closes #12456 — The recovery path it skips (schedulePromptAdmissionRecovery in V1's OpenCodeAdapter) is deleted in V2, whose OpenCode admission and stream-EOF handling is rebuilt in O…
Closes #12374 — Same Cursor ACP transport-drop class as #12940, which V2 addresses by enabling enableAgentRetries in CursorAdapterV2.
Closes #12325 — Same never-terminating tool-row class.
Closes #12206 — ProviderAdapterSessionClosedError is the ACP session-lifecycle class V2 rewrites ('feat(providers): standardize ACP providers', 'fix(antigravity): accept supported leg…
Closes #12187 — V2's run interrupt explicitly handles runs in preparing/starting with no provider turn, emitting an interrupt result and marking attempt/node/run interrupted ('Handle…
Closes #12155 — V2 carries reasoning as typed turn items across clients ('fix(providers): enable Codex and Claude reasoning summaries in V2', 'fix(timeline): align V2 reasoning disclo…
Closes #12136 — Same OpenCode prompt-admission rework as #11889 ('guard OpenCode prompt admission races', 'abort external OpenCode sessions on release') plus V2's interrupt path that…
Closes #12131 — V2 tracks subagents in server projections and replaces the ad-hoc agents panel with projection-backed lineage/workspace-card surfaces ('refactor(web): remove the agent…
Closes #12094 — The V2 timeline rewrite re-lays out these exact rows ('fix(web): anchor turn duration below the initiating prompt', 'fix: keep working timers anchored to the active ru…
Closes #12072 — V2's mobile timeline is rebuilt on paged V2 turn items with LegendList owning end-follow and anchoring ('fix(mobile): keep scroll bounds current after animations', 'pe…
Closes #12037 — V2 keeps a failed turn as a settled transcript item instead of wedging the thread ('fix(v2): keep failed turns visible in the transcript', 'fix(server): preserve gener…
Closes #11992 — V2 reworks the mobile running-turn UI so the pill is part of the composer hub and scroll bounds track animations ('feat(mobile): make the composer pill the hub for the…
Closes #11907 — V2 commits intent, projection and command receipt in one transaction with idempotent receipts, and holds sends as server-side queued turns, removing the V1 admission r…
Closes #11903 — Mobile timelines are rebuilt from V2 typed turn items ('Render mobile timelines from V2 turn items', 'Enrich mobile V2 execution items', 'fix(chat): present and summar…
Closes #11796 — The V1 processTurnInterruptRequested path is gone.
Closes #11777 — V2 projects native Codex subagents as durable child nodes with results ('Map nested Codex subagent threads correctly', 'feat(subagents): disclose projected results con…
Closes #11670 — V2 standardizes ACP providers behind one adapter with session recovery and surfaces typed failures ('feat(providers): standardize ACP providers', 'fix(server): surface…
Closes #11432 — V2 maps Codex background command completions to typed turn items (codexBackgroundCommandDetail, source kind background_command) and renders background completions as t…
Closes #11353 — V2 persists each assistant text block as its own ordered assistant_message turn item with its own messageId, so a later item in the same turn cannot overwrite an earli…
Closes #11182 — Branch-only "perf(server): stop decoding unrelated events during startup" (#12846) rewrites ProjectionPipeline bootstrap to read cursor metadata instead of full event…
Closes #10973 — V2 commit "fix(server): recover OpenCode status reconciliation" ignores stale timers and duplicate evidence so an older prompt's idle event cannot finish newer steerin…
Closes #10934 — The "Provider session did not survive a server restart" path exists only on main.
Closes #10798 — V2 replaces the Codex adapter with scoped session runtimes plus a provider session recovery service, and run state is orchestrator-owned rather than derived from the a…
Closes #10684 — Same mechanism as #10202: V2's durable
thread.model-selection.setcommand andthread.model-selection-updatedprojection replace per-client sticky model state.Closes #10375 — ClaudeAdapterV2 classifies
local_bashtask types explicitly and never fabricates a subagent for them, and V2 rebuilt the worklog rows ("fix(timeline): unify worklog…Closes #10202 — V2 makes thread model selection durable server state via the
thread.model-selection.setcommand andthread.model-selection-updatedevent, which every subscribed cl…Closes #10192 — V2 projects questions as turn items rendered identically across clients and makes settlement server-owned ("fix: align V2 question and checkpoint timelines across clie…
Closes #10185 — V2 models native subagents in projections and surfaces their models in Lineage, replacing the Agents right panel ("feat(web): show subagent models and running count in…
Closes #9892 — V2 tracks subagents in projections and maps Grok task envelopes to subagent lineage ("Map Grok task envelopes to subagent lineage", "feat(orchestration-v2): model nati…
Closes #9772 — V2 orders the transcript from the append-only event log and pages history by keyset rather than by wall-clock timestamps ("perf(orchestration): bound history reads in…
Closes #9698 — V2 separates run finalization from provider turn completion and retires background work after a turn settles ("fix: stop retained background work after a turn settles"…
Closes #9672 — V2 models queued messages as first-class durable
queued_turnintents promoted by the serialized orchestrator ("fix(queue): preserve and hold queued messages after re…Closes #9607 — V2's provider session recovery restarts live sessions after dead/stale records and reopens Claude queries on credential rotation ("fix(server): restart the live sessio…
Closes #9586 — V2 makes liveness an orchestrator projection and the settlement service detaches idle provider sessions ("fix(orchestrator): Restore Claude session continuity for resu…
Closes #9414 — V2 adds bounded per-thread history loading with true-end paging and bounded snapshots ("perf(orchestration): bound complete thread snapshots", "fix(orchestration): pag…
Closes #9352 — V2 shows live context usage in the composer meter as a first-class V2 surface ("feat(orchestration-v2): show live context usage in the meter (#8144)", "fix(server): ke…
Closes #9214 — Fold derivation now keys on server-owned runIds instead of provider turn ids, and "fix(server): recover OpenCode status reconciliation" makes OpenCode run state author…
Closes #8945 — V2 folds group by server-owned runId and deliberately keep every provider turn since the initiating prompt in one visual response, so a mid-turn pause no longer starts…
Closes #8896 — V2 isolates its migrations from the V1 database and flags divergent migration ids ("test(server): prove v1 to v2 cutover on a copied database and flag divergent migrat…
Closes #8873 — V2 replaces the checkpoint reactor with effect-worker checkpointing that starts the provider turn when baseline capture fails (#12153) and finalizes runs when checkpoi…
Closes #8648 — V2 bounds history reads in SQL, bounds complete thread snapshots and resume payloads, releases thread history after turn startup, and keeps tool payloads out of comple…
Closes #8618 — Stop is a serialized V2 command whose intent commits with a durable receipt, and "fix(orchestrator): report terminal runs after wait timeout" ends the stuck Thinking s…
Closes #8382 — V2 adds AcpRuntimeModel parsing of ACP usage_update/state_update usage into a per-session contextUsage snapshot that feeds "feat(orchestration-v2): show live context u…
Closes #8320 — V2 records provider session lifecycle as persisted typed events with a session recovery service, plus "fix(server): surface actionable provider failure messages (#1256…
Closes #8263 — ProviderTurnStartService prunes and recreates a missing worktree at the thread's branch before starting the provider turn ("fix(orchestration): recreate missing worktr…
Closes #8259 — V2 shares Codex sessions across orchestration threads and maps turns to provider instances.
Closes #8146 — V2 replaces the hand-written Codex wire with the generated effect-codex-app-server schemas and app-server integration, so initialize payload decoding is regenerated fr…
Closes #8105 — V2 projects file-change and diff items per run and thread and narrows subscriptions to the viewed thread, so opening a second thread cannot capture another thread's li…
Closes #8022 — V2 Cursor execution and provider checks no longer use the ACP transport or cursor/list_available_models — it goes through the official SDK ('Switch Cursor provider to…
Closes #7781 — V2 replaces the inferred turn→checkpoint range with durable run identity and checkpoint coordination ('fix(orchestration): stabilize Codex turn mapping and settlement'…
Closes #7722 — V2 models native Codex subagents as first-class threads with orchestrator-owned stop ('Map nested Codex subagent threads correctly', 'fix(server): wait for native Code…
Closes #7589 — V2 records provider turn state independently from run finalization and settles threads server-side, and 'fix(server): restore Claude resume compaction' covers the comp…
Closes #7314 — V2 models subagents in projections and re-derives status from events ('feat(orchestration-v2): model native subagents', 'refactor(mobile): share subagent status indica…
Closes #6517 — V1's ProviderCommandReactor semaphore is replaced by the serialized orchestrator plus effect worker.
Closes #6389 — The V2 Claude adapter emits into the orchestrator where events and projections commit in one transaction, removing the in-flight-tool map race at finalize.
Closes #6368 — Thread settlement and snooze become server-owned in ThreadSettlementService ('fix(server): keep old failures from waking snoozed V2 threads (#9903)', 'fix: reconcile m…
Closes #6358 — V2's server-owned settlement evaluates without a connected client and 'fix(orchestration): reanchor unsettled threads' removes the stuck-unsettled state that pins the…
Closes #6128 — The V1 thread read model that caused the archived_at asymmetry is replaced by V2's projection store and ThreadLifecycleService, with archive handled as a domain comman…
Closes #5958 — The reported 'Orchestration command invariant failed' comes from the V1 OrchestrationEngine command path, which V2 replaces with the serialized Orchestrator and EventS…
Closes #5952 — V2 SubagentProjection plus OpenCodeAdapterV2 child-session mapping (fix(opencode): route child-session approvals through the v2 adapter) projects native child sessions…
Closes #5754 — CodexAdapterV2 maps collab wait/spawn items and empty receiver sets explicitly (replay fixture subagent_v2 covers a wait with empty receiverThreadIds), and RunFinaliza…
Closes #5685 — V2 CheckpointRollbackService coordinates workspace rollback with the provider conversation and the timeline (fix: align V2 question and checkpoint timelines across cli…
Closes #5514 — V2 ThreadPullRequestService skips settled threads in ordinary discovery and only stamps a link.
Closes #5447 — Commands are serialized through one orchestrator with idempotent receipts and sessions are owned by ProviderSessionManager, removing the duplicate-dispatch race that p…
Closes #5395 — ClaudeAdapterV2 maps sidechain items onto V2's native subagent model (feat(orchestration-v2): model native subagents.
Closes #5323 — Shutdown/startup runtime reconciliation records an explicit cancellation for work interrupted by the quit, replacing the stale 'stream failed' state a killed provider…
Closes #5035 — V2 drops the V1 per-event runProjectorForEvent nesting: EventSink commits events, projections, receipt and outbox in a single sql.withTransaction, removing the nested-…
Closes #4962 — V2 projects delegated-child progress server-side and shares it with mobile (refactor(mobile): share subagent status indicators.
Closes #4944 — V2 owns provider switching through ProviderSwitchService/ProviderSessionTransitionPolicy/ProviderSessionManager (Allow provider switching via handoff in chat threads.
Closes #4818 — V2 threads no longer write through the V1 receipt repository.
Closes #4728 — V2 reprojects Claude assistant text blocks and buffers streaming output per block (
fix(timeline): preview live reasoning and buffer complete paragraphs), so text emi…Closes #4723 —
fix(orchestration): recreate missing worktrees before turnsprunes stale registrations and recreates the saved branch/path inProviderTurnStartService, andProvid… Closes #4560 — V2 binds each thread to its own provider session record (orchestration_v2_projection_provider_sessions, keyed by provider instance + thread) and serializes commands… Closes #4225 — V2 commits the user-message event before any provider work runs in the effect worker, so a provider auth failure leaves the prompt persisted and rendered instead of sw… Closes #4178 — V2 bounds the read model and subscription payloads:perf(orchestration): bound complete thread snapshots,feat(orchestration): bound thread history and resume paylo…Closes #2644 — V2 separates provider turn completion from run finalization and rewrites the OpenCode adapter's turn mapping, so a finished provider turn settles the thread rather tha…
Closes #2519 — V2 projects proposed plans as first-class rows (
fix(server): project Claude plans and todos,fix(server): preserve Claude planning lifecycle, inline-plans rework),…Closes #2343 — V2 provider session recovery plus budgeted context handoff rebuild a resumed thread's context from the persisted transcript when the native provider session is gone, r…
Closes #881 — Run and turn state are derived from the committed event log and recovered at startup by the V2 recovery services, so a resumed thread shows real provider activity inst…
Supersedes
These pull requests target the V1 orchestration/provider layers this PR replaces, and V2 already delivers the same fix or feature by another route. They are linked here (not auto-closed) so their authors can find the replacement; most were closed pending V2, the rest stay open for maintainer review.
High confidence
reconcile-idleaction for delayed prompt admission (commits `correlate OpenCode prompt admi…t3_worktree_handoff,t3_worktree_status, andt3_worktree_listin the MCP worktree toolkit, including the queued continuation prompt.t3_thread_launch(pluscreate_threads) for handing work to a new workspace-aware thread.fix(acp): support Devin terminals, questions, and native subagents).t3_thread_launch,t3_thread_send,t3_thread_wait,t3_thread_read) with durab…tasksubagents as read-only child app threads with their tool activity and final result (docs/user/cursor.md, SubagentProjection).thread.auto-settlecommand rejects newer activity and live/blocked work and detaches idle provider sessions (`provi…updateTodostool calls into task steps withemitsTodoList: true.t3_thread_fork, ContextHandoffServiceV2, commitsfix(orchestration-v2): resolve cross-provider forksand `f…supportsSubagents/exposesSubagentThreadIdsand maps child sessions through SubagentProjection into real child threads.user_input_requestitems andruntime-request.respondcommits the resolution plus the user message in one transaction against t…providerID/modelIDfrom the native payload per assistant message and records it on the V2 turn (modelfield on the turn projecti…queueHeldin orchestrationV2 contracts.ThreadCommandExecutorand re-validates restore inCheckpointRestoreSafety"at command admission and again before pr…thread.user-input.dismisscommand andProviderEventIngestor.dismissNativeUserInputs, which clears native user inputs when the turn ends or th…usageLimitResetAtinorchestrationV2.ts.CursorAcpSupport.tsand maps runtime modes onto the Cursor SDK directly: "full access disables its sandbox, while restricted modes and explicit non-full-a…ProviderTurnStartServicerecreates a missing worktree before starting a provider turn ("provider turn start recreating missing worktree"), matching commit "fix(…ThreadCommandExecutoris aKeyedSerialExecutor<ThreadId>, serializing per-thread work "without coupling unrelated identities to a process-wide mutex".ThreadForkService,thread.forkcommand, mobile fork/merge-back surfaces in commits "fix(mobile): wait for fork shell before navigation" and "pr…ThreadForkServicewith fork lineage, lazy context transfer and merge-back handoffs (commits "Add thread fork lineage and lazy context transfer", "feat(mcp):…CheckpointRestoreSafetyresolvesfileSystem.realPathon both the checkpoint scope cwd and the thread worktree before comparing, so symlinked paths compare equal.GrokAdapterV2.thread.visit/thread.visitedevents withlastVisitedAton the thread projection plus athread.mark-unreadcommand, so ever…CursorAdapter.tsand runs Cursor throughCursorAdapterV2/CursorAgentSdkon the official@cursor/sdk(docs/user/cursor.md: "does not use Cursor's ACP…Partially / likely superseded
contextUsagetracking drives the V2 live context meter (commit `feat(orchestration-v2): show live context us…fix(acp): support Devin terminals, questions, and native subagents) rather than a bespo…idleDuringAdmissionand emitsreconcile-idle, replacing the V1 idle/turn-boundary handling.admissionPending/idleDuringAdmission/reconcile-idle) so an idle signal during admission no long…ProviderRuntimeRecoveryServiceplus "harden Grok v2 runtime lifecycle" and "dedupe Grok continuation dispatch" handle crashed sessions centrally.SubagentProjection), so per-subagent stream isolation is structural.ActivityPayloadProjection.tswithShellStreamand the v2 activity log ("fold completed trailing background activity", "keep shell snapshots bounded and…UsageLimitRecoveryWorkerwithusageLimitContinuationOfRunId("feat(v2): resume limited threads when usage resets (feat(v2): resume limited threads when usage resets #12686)", "share scheduling for tasks an…CursorSdkCatalogvia@cursor/sdkinstead of the CLI (CursorProvider.ts loses ~1060 lines of CLI probing), so CLI-version model f…ProviderSessionReaper.ts.SubagentProjectionplus "Codex background command completion and subagent resume" track subagent lifecycle in projections rather than in the deleted `ClaudeAdap…RunFinalizationServicefrom provider turn completion and makes settlement server-owned inThreadSettlementService("stop retained background work afte…ProviderSessionManager+ProviderRuntimeRecoveryService, which retires effects tied to lost provider processes before admitting new wo…RuntimeRequestService/runtime-request.respondreads the persisted request, validates required answers, and commits the resolution and user message in one tran…CodexAdapterV2persists Codex async notifications asuser_input_requestturn items and runtime requests that survive turn end, provider exit, and restart.AcpRegistryAdapterV2, "feat(providers): standardize ACP providers") lets registry agents be added without a first-party driver, so the bes…ProviderSessionDirectory/ProviderServicewithProviderSessionManagerandProviderSessionTransitionPolicy, which decide resume versus fresh session from persisted session state.SubagentProjection("feat(orchestration-v2): model native subagents", "show subagent details and history in workspace card")OpenCodeAdapterV2("cancel pending OpenCode prompts safely", "abort external OpenC…Closes discussions
Discussions cannot be auto-closed; these are linked so they can be resolved by hand after merge.
Allow provider switching via handoff in chat threadsplusfeat(server): preserve budgeted history across provider handoffs— and the sidebar doc tells limited threads toswitch to another provider instance.Snooze until reset/Resume at resetprefilled from the provider's reported reset time, withSnooze limited threadsandAuto-resume limited threadsdefaults (feat(v2): resume limited threads when usage resets).t3_preview_closeandt3_preview_listMCP tools (feat(mcp): expose preview list and close); main has neither.create_threads,t3_thread_launch,t3_thread_configure,t3_thread_waitandt3_thread_interruptas MCP tools, so an agent can spawn and drive threads on other providers/models.feat(providers): standardize ACP providers) with per-instance executable override, so a new ACP agent no longer needs a first-party driver and BUILT_IN_DRIVERS entry.thread is bound to driver/resume state is incompatiblehard binds, carrying a budgeted portable context selection into the new provider (docs/user/portable-handoffs.md).t3_thread_list,t3_thread_read,t3_thread_search— though the standalone CLI surface is not part of it.t3_thread_fork,t3_thread_merge_back,ThreadRelationshipsControl), delivering the side-exploration-without-derailing goal though not an ephemeral side-panel thread.defaultRuntimeModeserver setting surfaced in Settings → Project defaults (new on the branch; absent from main).kimi acpwithout a bespoke provider.agent_thought_chunk,usage_update,available_commands_updateandconfig_option_update, andfix(grok): align ACP extensions with open source runtimecovers the xAI extension hooks.feat(providers): standardize ACP providers (#6461)gives every ACP provider the command catalog, config options/reasoning effort and usage-driven context meter via AcpAdapterV2.plan/architectmode and plan-category config options, restoring build configuration afterwards — mode mapping rather than/plantext.Map Grok task envelopes to subagent lineage,feat(orchestration-v2): model native subagents).t3_thread_listandt3_thread_send(new on the branch; absent on main), and the activity log summarizesSent 5 messages to 2 threads.tasksubagents as read-only child app threads with their tool activity (docs/user/cursor.md), and subagent lineage is tracked in V2 projections.ThreadAgentsSheetandSubagentStatusDot(neither exists on main) plusrefactor(mobile): share subagent status indicators.t3_thread_launchMCP tool takes an explicit optionalprojectId(witht3_project_list/t3_project_readto find it), so an agent can start a top-level thread in another project.delegate_taskruns T3-owned child agents asynchronously with per-task provider/model overrides, projected as subagent lineage inside the parent thread.t3_thread_sendwithmode='auto'(starts an idle thread, steers or queues otherwise) plusclientRequestIdidempotency backed by durable command receipts.feat(providers): add Pi coding agent (#7211), PiDriver/PiProvider, native Pi forks and resume recovery).Note
Introduce orchestration V2 runtime, services, provider adapters, and MCP toolkits
EnvironmentApiorchestration interface withorchestrationV2; removesserverUpdateThreadContinuationcapability;CursorSettingsno longer exposesbinaryPathorapiEndpoint;ProviderUsageLimitsIngestionLiveno longer subscribes to runtime events; thread routing resolves existing non-deleted threads directly to ready instead of loadingMacroscope summarized 6102d00.
Note
Medium Risk
Mobile thread persistence and list/archive/stop behavior change with V2 runtime semantics; removing the thread-transfer report workflow reduces PR visibility into transfer budget regressions.
Overview
This slice of the orchestration V2 rollout retires the thread-transfer PR comment pipeline (trusted publisher script, tests, and
workflow_runworkflow) while CI can still emit transfer artifacts; it also installsbuild-essentialin CI so ACP process-tree fixtures compile instead of soft-skipping.Mobile moves onto shared V2 client-runtime pieces: SQLite cache uses
ORCHESTRATION_CACHE_SCHEMA_VERSIONand stored V2 shell/thread snapshots, runtime wiring swaps in bounded thread snapshot loading and history control, and thread detail/review/archive flows read projections (runtime,RuntimeRequestId, checkpoint summaries fromrunId) instead of V1 session/turn shapes. UX additions include activity inspector, queue control, relationships banner, progressive history controls, server visit watermarking, stricter archive rules viathreadCanArchive, and approval/user-input cards that honor live vs dead providerresponseCapability.Smaller touches: shared brand mark module, new uniwind adaptive color tokens, desktop env test for user-data dir names, README link to appearance docs, and marketing copy for Cursor harness.
Reviewed by Cursor Bugbot for commit 9eeed8c. Bugbot is set up for automated code reviews on this repo. Configure here.