| ... | @@ -15,12 +15,12 @@ Claude integration must plug into this path instead of reintroducing legacy prov | ... | @@ -15,12 +15,12 @@ Claude integration must plug into this path instead of reintroducing legacy prov |
| 15 | | 15 | |
| 16 | --- | 16 | --- |
| 17 | | 17 | |
| 18 | ## Current constraints to design around | 18 | ## Current constraints to design around (post-Stage 1) |
| 19 | | 19 | |
| 20 | 1. Provider runtime ingestion expects canonical `ProviderRuntimeEvent` shapes, not provider-native payloads. | 20 | 1. Provider runtime ingestion expects canonical `ProviderRuntimeEvent` shapes, not provider-native payloads. |
| 21 | 2. `ProviderService.startSession` currently defaults to `provider: "codex"` unless explicitly provided. | 21 | 2. Start input now uses typed `providerOptions` and generic `resumeCursor`; top-level provider-specific fields were removed. |
| 22 | 3. `thread.turn.start` has no provider field today, so first-turn provider selection cannot be explicitly requested. | 22 | 3. `resumeCursor` is intentionally opaque outside adapters and must never be synthesized from `providerThreadId`. |
| 23 | 4. `ProviderService` requires adapter `startSession()` to return a `ProviderSession` with `threadId`. | 23 | 4. `ProviderService` still requires adapter `startSession()` to return a `ProviderSession` with `threadId`. |
| 24 | 5. Checkpoint revert currently calls `providerService.rollbackConversation()`, so Claude adapter needs a rollback strategy compatible with current reactor behavior. | 24 | 5. Checkpoint revert currently calls `providerService.rollbackConversation()`, so Claude adapter needs a rollback strategy compatible with current reactor behavior. |
| 25 | 6. Web currently marks Claude as unavailable (`"Claude Code (soon)"`) and model picker is Codex-only. | 25 | 6. Web currently marks Claude as unavailable (`"Claude Code (soon)"`) and model picker is Codex-only. |
| 26 | | 26 | |
| ... | @@ -61,21 +61,24 @@ Update `packages/contracts/src/orchestration.ts`: | ... | @@ -61,21 +61,24 @@ Update `packages/contracts/src/orchestration.ts`: |
| 61 | | 61 | |
| 62 | This removes the implicit “Codex unless session already exists” behavior as the only path. | 62 | This removes the implicit “Codex unless session already exists” behavior as the only path. |
| 63 | | 63 | |
| 64 | ### 1.3 Provider session start input for Claude runtime knobs | 64 | ### 1.3 Provider session start input for Claude runtime knobs (completed) |
| 65 | | 65 | |
| 66 | Update `packages/contracts/src/provider.ts`: | 66 | Update `packages/contracts/src/provider.ts`: |
| 67 | | 67 | |
| 68 | 1. Extend `ProviderSessionStartInput` with optional Claude-specific fields (for example `claudeBinaryPath`, `permissionMode`, `maxThinkingTokens`). | 68 | 1. Move provider-specific start fields into typed `providerOptions`: |
| 69 | 2. Keep fields optional so current call sites remain valid. | 69 | - `providerOptions.codex` |
| 70 | 3. Continue using generic `resumeThreadId` + `resumeCursor` as the cross-provider recovery mechanism. | 70 | - `providerOptions.claudeCode` |
| | 71 | 2. Keep `resumeCursor` as the single cross-provider resume input in `ProviderSessionStartInput`. |
| | 72 | 3. Deprecate/remove `resumeThreadId` from the generic start contract. |
| | 73 | 4. Treat `resumeCursor` as adapter-owned opaque state. |
| 71 | | 74 | |
| 72 | ### 1.4 Contract tests | 75 | ### 1.4 Contract tests (completed) |
| 73 | | 76 | |
| 74 | Update/add tests in `packages/contracts/src/*.test.ts` for: | 77 | Update/add tests in `packages/contracts/src/*.test.ts` for: |
| 75 | | 78 | |
| 76 | 1. New command payload shape. | 79 | 1. New command payload shape. |
| 77 | 2. Provider-aware model resolution behavior. | 80 | 2. Provider-aware model resolution behavior. |
| 78 | 3. Backward compatibility of existing command/schema decoding. | 81 | 3. Breaking-change expectations for removed top-level provider fields. |
| 79 | | 82 | |
| 80 | --- | 83 | --- |
| 81 | | 84 | |
| ... | @@ -100,9 +103,9 @@ Baseline adapter options to support from day one: | ... | @@ -100,9 +103,9 @@ Baseline adapter options to support from day one: |
| 100 | | 103 | |
| 101 | 1. `cwd` | 104 | 1. `cwd` |
| 102 | 2. `model` | 105 | 2. `model` |
| 103 | 3. `pathToClaudeCodeExecutable` (from `claudeBinaryPath`) | 106 | 3. `pathToClaudeCodeExecutable` (from `providerOptions.claudeCode.binaryPath`) |
| 104 | 4. `permissionMode` | 107 | 4. `permissionMode` (from `providerOptions.claudeCode.permissionMode`) |
| 105 | 5. `maxThinkingTokens` | 108 | 5. `maxThinkingTokens` (from `providerOptions.claudeCode.maxThinkingTokens`) |
| 106 | 6. `resume` | 109 | 6. `resume` |
| 107 | 7. `resumeSessionAt` | 110 | 7. `resumeSessionAt` |
| 108 | 8. `includePartialMessages` | 111 | 8. `includePartialMessages` |
| ... | @@ -120,7 +123,7 @@ Required capabilities: | ... | @@ -120,7 +123,7 @@ Required capabilities: |
| 120 | 2. Multi-turn input queue. | 123 | 2. Multi-turn input queue. |
| 121 | 3. Interrupt support. | 124 | 3. Interrupt support. |
| 122 | 4. Approval request/response bridge. | 125 | 4. Approval request/response bridge. |
| 123 | 5. Resume support via `resumeThreadId` / `resumeCursor`. | 126 | 5. Resume support via opaque `resumeCursor` (parsed inside Claude adapter only). |
| 124 | | 127 | |
| 125 | #### 2.2.a Agent SDK details to preserve | 128 | #### 2.2.a Agent SDK details to preserve |
| 126 | | 129 | |
| ... | @@ -129,7 +132,7 @@ The adapter should explicitly rely on these SDK capabilities: | ... | @@ -129,7 +132,7 @@ The adapter should explicitly rely on these SDK capabilities: |
| 129 | 1. `query()` returns an async iterable message stream and control methods (`interrupt`, `setModel`, `setPermissionMode`, `setMaxThinkingTokens`, account/status helpers). | 132 | 1. `query()` returns an async iterable message stream and control methods (`interrupt`, `setModel`, `setPermissionMode`, `setMaxThinkingTokens`, account/status helpers). |
| 130 | 2. Multi-turn input is supported via async-iterable prompt input. | 133 | 2. Multi-turn input is supported via async-iterable prompt input. |
| 131 | 3. Tool approval decisions are provided via `canUseTool`. | 134 | 3. Tool approval decisions are provided via `canUseTool`. |
| 132 | 4. Resume support uses `resume` and optional `resumeSessionAt`. | 135 | 4. Resume support uses `resume` and optional `resumeSessionAt`, both derived by parsing adapter-owned `resumeCursor`. |
| 133 | 5. Hooks can be used for lifecycle signals (`Stop`, `PostToolUse`, etc.) when we need adapter-originated checkpoint/runtime events. | 136 | 5. Hooks can be used for lifecycle signals (`Stop`, `PostToolUse`, etc.) when we need adapter-originated checkpoint/runtime events. |
| 134 | | 137 | |
| 135 | #### 2.2.b Effect-native session lifecycle skeleton | 138 | #### 2.2.b Effect-native session lifecycle skeleton |
| ... | @@ -142,21 +145,23 @@ const acquireSession = (input: ProviderSessionStartInput) => | ... | @@ -142,21 +145,23 @@ const acquireSession = (input: ProviderSessionStartInput) => |
| 142 | Effect.acquireRelease( | 145 | Effect.acquireRelease( |
| 143 | Effect.tryPromise({ | 146 | Effect.tryPromise({ |
| 144 | try: async () => { | 147 | try: async () => { |
| | 148 | const claudeOptions = input.providerOptions?.claudeCode; |
| | 149 | const resumeState = readClaudeResumeState(input.resumeCursor); |
| 145 | const abortController = new AbortController(); | 150 | const abortController = new AbortController(); |
| 146 | const result = query({ | 151 | const result = query({ |
| 147 | prompt: makePromptAsyncIterable(input.sessionId), | 152 | prompt: makePromptAsyncIterable(), |
| 148 | options: { | 153 | options: { |
| 149 | cwd: input.cwd, | 154 | cwd: input.cwd, |
| 150 | model: input.model, | 155 | model: input.model, |
| 151 | permissionMode: input.permissionMode, | 156 | permissionMode: claudeOptions?.permissionMode, |
| 152 | maxThinkingTokens: input.maxThinkingTokens, | 157 | maxThinkingTokens: claudeOptions?.maxThinkingTokens, |
| 153 | pathToClaudeCodeExecutable: input.claudeBinaryPath, | 158 | pathToClaudeCodeExecutable: claudeOptions?.binaryPath, |
| 154 | resume: input.resumeThreadId, | 159 | resume: resumeState?.threadId, |
| 155 | resumeSessionAt: readResumeCursor(input.resumeCursor), | 160 | resumeSessionAt: resumeState?.sessionAt, |
| 156 | signal: abortController.signal, | 161 | signal: abortController.signal, |
| 157 | includePartialMessages: true, | 162 | includePartialMessages: true, |
| 158 | canUseTool: makeCanUseTool(input.sessionId), | 163 | canUseTool: makeCanUseTool(), |
| 159 | hooks: makeClaudeHooks(input.sessionId), | 164 | hooks: makeClaudeHooks(), |
| 160 | }, | 165 | }, |
| 161 | }); | 166 | }); |
| 162 | return { abortController, result }; | 167 | return { abortController, result }; |
| ... | @@ -345,7 +350,8 @@ Define explicit adapter semantics: | ... | @@ -345,7 +350,8 @@ Define explicit adapter semantics: |
| 345 | | 350 | |
| 346 | 1. `sessionId`: adapter-owned stable session id. | 351 | 1. `sessionId`: adapter-owned stable session id. |
| 347 | 2. `threadId`: Claude conversation/session identifier returned as `ProviderThreadId`. | 352 | 2. `threadId`: Claude conversation/session identifier returned as `ProviderThreadId`. |
| 348 | 3. `resumeCursor`: provider-specific cursor (for example message id) needed for precise recovery/rollback. | 353 | 3. `resumeCursor`: provider-specific cursor (for example thread id + message cursor) needed for precise recovery/rollback. |
| | 354 | 4. Orchestration/shared services persist and forward `resumeCursor` unchanged without provider-specific parsing. |
| 349 | | 355 | |
| 350 | ### 2.5 Rollback/read strategy | 356 | ### 2.5 Rollback/read strategy |
| 351 | | 357 | |
| ... | @@ -402,11 +408,12 @@ Update integration tests to ensure: | ... | @@ -402,11 +408,12 @@ Update integration tests to ensure: |
| 402 | | 408 | |
| 403 | ## Phase 4: Orchestration command/reactor updates | 409 | ## Phase 4: Orchestration command/reactor updates |
| 404 | | 410 | |
| 405 | ### 4.1 Decider propagation | 411 | ### 4.1 Decider propagation (completed) |
| 406 | | 412 | |
| 407 | Update `apps/server/src/orchestration/decider.ts`: | 413 | Update `apps/server/src/orchestration/decider.ts`: |
| 408 | | 414 | |
| 409 | 1. Carry optional `provider` from `thread.turn.start` command into `thread.turn-start-requested` event payload. | 415 | 1. Carry optional `provider` from `thread.turn.start` command into `thread.turn-start-requested` event payload. |
| | 416 | 2. Keep this behavior provider-agnostic (no provider-specific runtime fields in the event payload). |
| 410 | | 417 | |
| 411 | ### 4.2 ProviderCommandReactor provider selection | 418 | ### 4.2 ProviderCommandReactor provider selection |
| 412 | | 419 | |
| ... | @@ -415,6 +422,7 @@ Update `apps/server/src/orchestration/Layers/ProviderCommandReactor.ts`: | ... | @@ -415,6 +422,7 @@ Update `apps/server/src/orchestration/Layers/ProviderCommandReactor.ts`: |
| 415 | 1. Prefer provider from turn-start event payload when starting a new session. | 422 | 1. Prefer provider from turn-start event payload when starting a new session. |
| 416 | 2. Fallback to existing thread session provider when payload omitted. | 423 | 2. Fallback to existing thread session provider when payload omitted. |
| 417 | 3. Fallback to default provider only when neither is present. | 424 | 3. Fallback to default provider only when neither is present. |
| | 425 | 4. On restart/rebind, forward the runtime session's persisted `resumeCursor` as-is (no reconstruction from `providerThreadId`). |
| 418 | | 426 | |
| 419 | Switch behavior policy (explicit in implementation): | 427 | Switch behavior policy (explicit in implementation): |
| 420 | | 428 | |
| ... | @@ -516,31 +524,26 @@ Confirm both native and canonical provider logs remain useful with multi-adapter | ... | @@ -516,31 +524,26 @@ Confirm both native and canonical provider logs remain useful with multi-adapter |
| 516 | | 524 | |
| 517 | ## File checklist | 525 | ## File checklist |
| 518 | | 526 | |
| 519 | Likely files to touch: | 527 | Likely remaining files to touch: |
| 520 | | 528 | |
| 521 | 1. `packages/contracts/src/model.ts` | 529 | 1. `apps/server/src/provider/Services/ClaudeCodeAdapter.ts` (new) |
| 522 | 2. `packages/contracts/src/orchestration.ts` | 530 | 2. `apps/server/src/provider/Layers/ClaudeCodeAdapter.ts` (new) |
| 523 | 3. `packages/contracts/src/provider.ts` | 531 | 3. `apps/server/src/provider/Layers/ProviderAdapterRegistry.ts` |
| 524 | 4. `apps/server/src/provider/Services/ClaudeCodeAdapter.ts` (new) | 532 | 4. `apps/server/src/serverLayers.ts` |
| 525 | 5. `apps/server/src/provider/Layers/ClaudeCodeAdapter.ts` (new) | 533 | 5. `apps/server/src/orchestration/Layers/ProviderCommandReactor.ts` |
| 526 | 6. `apps/server/src/provider/Layers/ProviderAdapterRegistry.ts` | 534 | 6. `apps/web/src/session-logic.ts` |
| 527 | 7. `apps/server/src/serverLayers.ts` | 535 | 7. `apps/web/src/components/ChatView.tsx` |
| 528 | 8. `apps/server/src/orchestration/decider.ts` | 536 | 8. Related tests under `apps/server/src/provider/Layers`, `apps/server/src/orchestration/Layers`, `apps/server/integration`, and `apps/web/src`. |
| 529 | 9. `apps/server/src/orchestration/Layers/ProviderCommandReactor.ts` | | |
| 530 | 10. `apps/web/src/session-logic.ts` | | |
| 531 | 11. `apps/web/src/components/ChatView.tsx` | | |
| 532 | 12. Related tests under `packages/contracts/src`, `apps/server/src/provider/Layers`, `apps/server/src/orchestration/Layers`, `apps/server/integration`, and `apps/web/src`. | | |
| 533 | | 537 | |
| 534 | --- | 538 | --- |
| 535 | | 539 | |
| 536 | ## Delivery order | 540 | ## Delivery order |
| 537 | | 541 | |
| 538 | 1. Contracts for provider selection + models. | 542 | 1. Claude adapter + unit tests on top of the new `providerOptions`/opaque-cursor contracts. |
| 539 | 2. Claude adapter + unit tests. | 543 | 2. Registry/layer wiring. |
| 540 | 3. Registry/layer wiring. | 544 | 3. Remaining reactor updates for provider-aware session selection/switching invariants. |
| 541 | 4. Reactor updates for provider-aware session start. | 545 | 4. Web provider picker + provider-aware models. |
| 542 | 5. Web provider picker + provider-aware models. | 546 | 5. Checkpoint/revert compatibility. |
| 543 | 6. Checkpoint/revert compatibility. | 547 | 6. End-to-end integration tests and stabilization. |
| 544 | 7. End-to-end integration tests and stabilization. | | |
| 545 | | 548 | |
| 546 | This order keeps risk isolated and maintains a working orchestrated path at each stage. | 549 | This order keeps risk isolated and maintains a working orchestrated path at each stage. |