From 5f94f0bbffa54c42609e202b4ca4b8a73f3d6011 Mon Sep 17 00:00:00 2001 From: sherlock Date: Fri, 20 Mar 2026 10:00:47 +0530 Subject: [PATCH 01/15] =?UTF-8?q?refactor:=20rename=20claudeCode=20?= =?UTF-8?q?=E2=86=92=20claudeAgent=20to=20align=20with=20upstream=20naming?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preparatory rename for upstream sync. Upstream renamed the provider kind from "claudeCode" to "claudeAgent" and type names accordingly. This rename reduces future sync friction. - Provider kind: "claudeCode" → "claudeAgent" - ClaudeCodeProviderStartOptions → ClaudeProviderStartOptions - ClaudeCodeModelOptions → ClaudeModelOptions - ClaudeCodeAdapter → ClaudeAdapter (files + class) - ClaudeCodeTraitsPicker → ClaudeTraitsPicker --- .docs/provider-architecture.md | 2 +- .plans/17-claude-code.md | 18 ++-- .../OrchestrationEngineHarness.integration.ts | 2 +- .../TestProviderAdapter.integration.ts | 10 +-- .../orchestrationEngine.integration.test.ts | 84 +++++++++---------- apps/server/src/git/Layers/GitManager.test.ts | 2 +- .../Layers/CheckpointReactor.test.ts | 22 ++--- .../Layers/ProviderCommandReactor.test.ts | 14 ++-- .../Layers/ProviderRuntimeIngestion.test.ts | 8 +- ...eAdapter.test.ts => ClaudeAdapter.test.ts} | 82 +++++++++--------- ...{ClaudeCodeAdapter.ts => ClaudeAdapter.ts} | 48 +++++------ .../src/provider/Layers/CodexAdapter.test.ts | 4 +- .../Layers/ProviderAdapterConformance.test.ts | 10 +-- .../Layers/ProviderAdapterRegistry.test.ts | 14 ++-- .../Layers/ProviderAdapterRegistry.ts | 4 +- .../provider/Layers/ProviderService.test.ts | 16 ++-- .../Layers/ProviderSessionDirectory.ts | 2 +- .../src/provider/Services/ClaudeAdapter.ts | 31 +++++++ .../provider/Services/ClaudeCodeAdapter.ts | 31 ------- .../src/provider/Services/ProviderAdapter.ts | 2 +- apps/server/src/serverLayers.ts | 4 +- apps/server/src/wsServer.ts | 4 +- apps/web/src/appSettings.test.ts | 8 +- apps/web/src/appSettings.ts | 10 +-- apps/web/src/components/ChatView.tsx | 26 +++--- apps/web/src/components/ProviderLogo.tsx | 2 +- apps/web/src/components/Sidebar.tsx | 8 +- ...raitsPicker.tsx => ClaudeTraitsPicker.tsx} | 4 +- .../components/chat/ProviderModelPicker.tsx | 8 +- apps/web/src/composerDraftStore.ts | 44 +++++----- apps/web/src/lib/threadDraftDefaults.test.ts | 10 +-- apps/web/src/lib/threadProvider.test.ts | 4 +- apps/web/src/lib/threadProvider.ts | 10 +-- apps/web/src/routes/__root.tsx | 2 +- apps/web/src/routes/_chat.settings.tsx | 4 +- apps/web/src/session-logic.test.ts | 6 +- apps/web/src/session-logic.ts | 4 +- apps/web/src/store.test.ts | 10 +-- packages/contracts/src/model.ts | 20 ++--- packages/contracts/src/orchestration.test.ts | 4 +- packages/contracts/src/orchestration.ts | 10 +-- packages/contracts/src/provider.test.ts | 12 +-- .../contracts/src/providerRuntime.test.ts | 2 +- packages/shared/src/model.test.ts | 26 +++--- packages/shared/src/model.ts | 8 +- 45 files changed, 328 insertions(+), 328 deletions(-) rename apps/server/src/provider/Layers/{ClaudeCodeAdapter.test.ts => ClaudeAdapter.test.ts} (93%) rename apps/server/src/provider/Layers/{ClaudeCodeAdapter.ts => ClaudeAdapter.ts} (97%) create mode 100644 apps/server/src/provider/Services/ClaudeAdapter.ts delete mode 100644 apps/server/src/provider/Services/ClaudeCodeAdapter.ts rename apps/web/src/components/chat/{ClaudeCodeTraitsPicker.tsx => ClaudeTraitsPicker.tsx} (93%) diff --git a/.docs/provider-architecture.md b/.docs/provider-architecture.md index 794b6aa5d5..9c140b2f4d 100644 --- a/.docs/provider-architecture.md +++ b/.docs/provider-architecture.md @@ -13,7 +13,7 @@ Methods mirror the `NativeApi` interface defined in `@t3tools/contracts`: - `providers.respondToRequest`, `providers.stopSession` - `shell.openInEditor`, `server.getConfig` -Codex is the only implemented provider. `claudeCode` is reserved in contracts/UI. +Codex is the only implemented provider. `claudeAgent` is reserved in contracts/UI. ## Client transport diff --git a/.plans/17-claude-code.md b/.plans/17-claude-code.md index 822dbd806b..c697011d3c 100644 --- a/.plans/17-claude-code.md +++ b/.plans/17-claude-code.md @@ -1,6 +1,6 @@ # Plan: Claude Code Integration (Orchestration Architecture) -> **Note -- Multi-provider scope:** This plan was originally written for the Claude Code adapter, but the patterns described here (adapter shape, canonical runtime mapping, resume cursor ownership, provider registry wiring, and orchestration integration) apply equally to the full multi-provider adapter infrastructure now implemented in this PR: **ClaudeCodeAdapter**, **CopilotAdapter**, **OpenCodeAdapter**, **GeminiCliAdapter**, **KiloAdapter**, and **AmpAdapter**. Where the text says "Claude adapter", read it as the reference implementation; every other adapter follows the same contract surface. +> **Note -- Multi-provider scope:** This plan was originally written for the Claude Code adapter, but the patterns described here (adapter shape, canonical runtime mapping, resume cursor ownership, provider registry wiring, and orchestration integration) apply equally to the full multi-provider adapter infrastructure now implemented in this PR: **ClaudeAdapter**, **CopilotAdapter**, **OpenCodeAdapter**, **GeminiCliAdapter**, **KiloAdapter**, and **AmpAdapter**. Where the text says "Claude adapter", read it as the reference implementation; every other adapter follows the same contract surface. ## Why this plan was rewritten @@ -90,8 +90,8 @@ Update/add tests in `packages/contracts/src/*.test.ts` for: Create: -1. `apps/server/src/provider/Services/ClaudeCodeAdapter.ts` -2. `apps/server/src/provider/Layers/ClaudeCodeAdapter.ts` +1. `apps/server/src/provider/Services/ClaudeAdapter.ts` +2. `apps/server/src/provider/Layers/ClaudeAdapter.ts` Adapter must implement `ProviderAdapterShape`. @@ -181,7 +181,7 @@ const acquireSession = (input: ProviderSessionStartInput) => }, catch: (cause) => new ProviderAdapterProcessError({ - provider: "claudeCode", + provider: "claudeAgent", sessionId: "pending", detail: "Failed to start Claude runtime session.", cause, @@ -200,7 +200,7 @@ const sdkMessageStream = Stream.fromAsyncIterable( session.result, (cause) => new ProviderAdapterProcessError({ - provider: "claudeCode", + provider: "claudeAgent", sessionId, detail: "Claude runtime stream failed.", cause, @@ -223,7 +223,7 @@ const sdkMessageStream = Stream.async `ClaudeCodeAdapter` +1. add `claudeAgent` -> `ClaudeAdapter` 2. ensure `ProviderService.listProviderStatuses()` reports Claude availability ### 3.2 Persist provider binding @@ -309,7 +309,7 @@ Required validation: Update `ProviderCommandReactor` / orchestration flow: -1. If a thread turn start requests `provider: "claudeCode"`, start Claude if no active session exists. +1. If a thread turn start requests `provider: "claudeAgent"`, start Claude if no active session exists. 2. If a thread already has Claude session binding, reuse it. 3. If provider switches between Codex and Claude, explicitly stop/rebind before next send. @@ -405,7 +405,7 @@ Cover: ### 6.2 Adapter layer tests -Add `ClaudeCodeAdapter.test.ts` covering: +Add `ClaudeAdapter.test.ts` covering: 1. session start 2. event mapping diff --git a/apps/server/integration/OrchestrationEngineHarness.integration.ts b/apps/server/integration/OrchestrationEngineHarness.integration.ts index 642f9b3dec..04433700d3 100644 --- a/apps/server/integration/OrchestrationEngineHarness.integration.ts +++ b/apps/server/integration/OrchestrationEngineHarness.integration.ts @@ -205,7 +205,7 @@ export interface OrchestrationIntegrationHarness { } interface MakeOrchestrationIntegrationHarnessOptions { - readonly provider?: "codex" | "claudeCode"; + readonly provider?: "codex" | "claudeAgent"; readonly realCodex?: boolean; } diff --git a/apps/server/integration/TestProviderAdapter.integration.ts b/apps/server/integration/TestProviderAdapter.integration.ts index 76a9cb8973..374265a5c7 100644 --- a/apps/server/integration/TestProviderAdapter.integration.ts +++ b/apps/server/integration/TestProviderAdapter.integration.ts @@ -36,7 +36,7 @@ export interface TestTurnResponse { export type FixtureProviderRuntimeEvent = { readonly type: string; readonly eventId: EventId; - readonly provider: "codex" | "claudeCode" | "cursor"; + readonly provider: "codex" | "claudeAgent" | "cursor"; readonly createdAt: string; readonly threadId: string; readonly turnId?: string | undefined; @@ -178,7 +178,7 @@ function normalizeFixtureEvent(rawEvent: Record): ProviderRunti export interface TestProviderAdapterHarness { readonly adapter: ProviderAdapterShape; - readonly provider: "codex" | "claudeCode"; + readonly provider: "codex" | "claudeAgent"; readonly queueTurnResponse: ( threadId: ThreadId, response: TestTurnResponse, @@ -198,7 +198,7 @@ export interface TestProviderAdapterHarness { } interface MakeTestProviderAdapterHarnessOptions { - readonly provider?: "codex" | "claudeCode"; + readonly provider?: "codex" | "claudeAgent"; } function nowIso(): string { @@ -206,7 +206,7 @@ function nowIso(): string { } function sessionNotFound( - provider: "codex" | "claudeCode", + provider: "codex" | "claudeAgent", threadId: ThreadId, ): ProviderAdapterSessionNotFoundError { return new ProviderAdapterSessionNotFoundError({ @@ -216,7 +216,7 @@ function sessionNotFound( } function missingSessionEffect( - provider: "codex" | "claudeCode", + provider: "codex" | "claudeAgent", threadId: ThreadId, ): Effect.Effect { return Effect.fail(sessionNotFound(provider, threadId)); diff --git a/apps/server/integration/orchestrationEngine.integration.test.ts b/apps/server/integration/orchestrationEngine.integration.test.ts index 5223ead40b..4102b3d86e 100644 --- a/apps/server/integration/orchestrationEngine.integration.test.ts +++ b/apps/server/integration/orchestrationEngine.integration.test.ts @@ -36,7 +36,7 @@ const PROJECT_ID = asProjectId("project-1"); const THREAD_ID = ThreadId.makeUnsafe("thread-1"); const FIXTURE_TURN_ID = "fixture-turn"; const APPROVAL_REQUEST_ID = asApprovalRequestId("req-approval-1"); -type IntegrationProvider = "codex" | "claudeCode"; +type IntegrationProvider = "codex" | "claudeAgent"; function nowIso() { return new Date().toISOString(); @@ -883,7 +883,7 @@ it.live( ), ); -it.live("starts a claudeCode session on first turn when provider is requested", () => +it.live("starts a claudeAgent session on first turn when provider is requested", () => withHarness( (harness) => Effect.gen(function* () { @@ -893,20 +893,20 @@ it.live("starts a claudeCode session on first turn when provider is requested", events: [ { type: "turn.started", - ...runtimeBase("evt-claude-start-1", "2026-02-24T10:10:00.000Z", "claudeCode"), + ...runtimeBase("evt-claude-start-1", "2026-02-24T10:10:00.000Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, }, { type: "message.delta", - ...runtimeBase("evt-claude-start-2", "2026-02-24T10:10:00.050Z", "claudeCode"), + ...runtimeBase("evt-claude-start-2", "2026-02-24T10:10:00.050Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, delta: "Claude first turn.\n", }, { type: "turn.completed", - ...runtimeBase("evt-claude-start-3", "2026-02-24T10:10:00.100Z", "claudeCode"), + ...runtimeBase("evt-claude-start-3", "2026-02-24T10:10:00.100Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, status: "completed", @@ -919,25 +919,25 @@ it.live("starts a claudeCode session on first turn when provider is requested", commandId: "cmd-turn-start-claude-initial", messageId: "msg-user-claude-initial", text: "Use Claude", - provider: "claudeCode", + provider: "claudeAgent", }); const thread = yield* harness.waitForThread( THREAD_ID, (entry) => - entry.session?.providerName === "claudeCode" && + entry.session?.providerName === "claudeAgent" && entry.session.status === "ready" && entry.messages.some( (message) => message.role === "assistant" && message.text === "Claude first turn.\n", ), ); - assert.equal(thread.session?.providerName, "claudeCode"); + assert.equal(thread.session?.providerName, "claudeAgent"); }), - "claudeCode", + "claudeAgent", ), ); -it.live("recovers claudeCode sessions after provider stopAll using persisted resume state", () => +it.live("recovers claudeAgent sessions after provider stopAll using persisted resume state", () => withHarness( (harness) => Effect.gen(function* () { @@ -947,20 +947,20 @@ it.live("recovers claudeCode sessions after provider stopAll using persisted res events: [ { type: "turn.started", - ...runtimeBase("evt-claude-recover-1", "2026-02-24T10:11:00.000Z", "claudeCode"), + ...runtimeBase("evt-claude-recover-1", "2026-02-24T10:11:00.000Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, }, { type: "message.delta", - ...runtimeBase("evt-claude-recover-2", "2026-02-24T10:11:00.050Z", "claudeCode"), + ...runtimeBase("evt-claude-recover-2", "2026-02-24T10:11:00.050Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, delta: "Turn before restart.\n", }, { type: "turn.completed", - ...runtimeBase("evt-claude-recover-3", "2026-02-24T10:11:00.100Z", "claudeCode"), + ...runtimeBase("evt-claude-recover-3", "2026-02-24T10:11:00.100Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, status: "completed", @@ -973,7 +973,7 @@ it.live("recovers claudeCode sessions after provider stopAll using persisted res commandId: "cmd-turn-start-claude-recover-1", messageId: "msg-user-claude-recover-1", text: "Before restart", - provider: "claudeCode", + provider: "claudeAgent", }); yield* harness.waitForThread( @@ -993,20 +993,20 @@ it.live("recovers claudeCode sessions after provider stopAll using persisted res events: [ { type: "turn.started", - ...runtimeBase("evt-claude-recover-4", "2026-02-24T10:11:01.000Z", "claudeCode"), + ...runtimeBase("evt-claude-recover-4", "2026-02-24T10:11:01.000Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, }, { type: "message.delta", - ...runtimeBase("evt-claude-recover-5", "2026-02-24T10:11:01.050Z", "claudeCode"), + ...runtimeBase("evt-claude-recover-5", "2026-02-24T10:11:01.050Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, delta: "Turn after restart.\n", }, { type: "turn.completed", - ...runtimeBase("evt-claude-recover-6", "2026-02-24T10:11:01.100Z", "claudeCode"), + ...runtimeBase("evt-claude-recover-6", "2026-02-24T10:11:01.100Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, status: "completed", @@ -1029,20 +1029,20 @@ it.live("recovers claudeCode sessions after provider stopAll using persisted res const recoveredThread = yield* harness.waitForThread( THREAD_ID, (entry) => - entry.session?.providerName === "claudeCode" && + entry.session?.providerName === "claudeAgent" && entry.messages.some( (message) => message.role === "user" && message.text === "After restart", ) && !entry.activities.some((activity) => activity.kind === "provider.turn.start.failed"), ); - assert.equal(recoveredThread.session?.providerName, "claudeCode"); + assert.equal(recoveredThread.session?.providerName, "claudeAgent"); assert.equal(recoveredThread.session?.threadId, "thread-1"); }), - "claudeCode", + "claudeAgent", ), ); -it.live("forwards claudeCode approval responses to the provider session", () => +it.live("forwards claudeAgent approval responses to the provider session", () => withHarness( (harness) => Effect.gen(function* () { @@ -1052,13 +1052,13 @@ it.live("forwards claudeCode approval responses to the provider session", () => events: [ { type: "turn.started", - ...runtimeBase("evt-claude-approval-1", "2026-02-24T10:12:00.000Z", "claudeCode"), + ...runtimeBase("evt-claude-approval-1", "2026-02-24T10:12:00.000Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, }, { type: "approval.requested", - ...runtimeBase("evt-claude-approval-2", "2026-02-24T10:12:00.050Z", "claudeCode"), + ...runtimeBase("evt-claude-approval-2", "2026-02-24T10:12:00.050Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, requestId: APPROVAL_REQUEST_ID, @@ -1067,7 +1067,7 @@ it.live("forwards claudeCode approval responses to the provider session", () => }, { type: "turn.completed", - ...runtimeBase("evt-claude-approval-3", "2026-02-24T10:12:00.100Z", "claudeCode"), + ...runtimeBase("evt-claude-approval-3", "2026-02-24T10:12:00.100Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, status: "completed", @@ -1080,7 +1080,7 @@ it.live("forwards claudeCode approval responses to the provider session", () => commandId: "cmd-turn-start-claude-approval", messageId: "msg-user-claude-approval", text: "Need approval", - provider: "claudeCode", + provider: "claudeAgent", }); const thread = yield* harness.waitForThread(THREAD_ID, (entry) => @@ -1109,11 +1109,11 @@ it.live("forwards claudeCode approval responses to the provider session", () => ); assert.equal(approvalResponses[0]?.decision, "accept"); }), - "claudeCode", + "claudeAgent", ), ); -it.live("forwards thread.turn.interrupt to claudeCode provider sessions", () => +it.live("forwards thread.turn.interrupt to claudeAgent provider sessions", () => withHarness( (harness) => Effect.gen(function* () { @@ -1123,20 +1123,20 @@ it.live("forwards thread.turn.interrupt to claudeCode provider sessions", () => events: [ { type: "turn.started", - ...runtimeBase("evt-claude-interrupt-1", "2026-02-24T10:13:00.000Z", "claudeCode"), + ...runtimeBase("evt-claude-interrupt-1", "2026-02-24T10:13:00.000Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, }, { type: "message.delta", - ...runtimeBase("evt-claude-interrupt-2", "2026-02-24T10:13:00.050Z", "claudeCode"), + ...runtimeBase("evt-claude-interrupt-2", "2026-02-24T10:13:00.050Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, delta: "Long running output.\n", }, { type: "turn.completed", - ...runtimeBase("evt-claude-interrupt-3", "2026-02-24T10:13:00.100Z", "claudeCode"), + ...runtimeBase("evt-claude-interrupt-3", "2026-02-24T10:13:00.100Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, status: "completed", @@ -1149,7 +1149,7 @@ it.live("forwards thread.turn.interrupt to claudeCode provider sessions", () => commandId: "cmd-turn-start-claude-interrupt", messageId: "msg-user-claude-interrupt", text: "Start long turn", - provider: "claudeCode", + provider: "claudeAgent", }); const thread = yield* harness.waitForThread( @@ -1175,11 +1175,11 @@ it.live("forwards thread.turn.interrupt to claudeCode provider sessions", () => ); assert.equal(interruptCalls.length, 1); }), - "claudeCode", + "claudeAgent", ), ); -it.live("reverts claudeCode turns and rolls back provider conversation state", () => +it.live("reverts claudeAgent turns and rolls back provider conversation state", () => withHarness( (harness) => Effect.gen(function* () { @@ -1189,20 +1189,20 @@ it.live("reverts claudeCode turns and rolls back provider conversation state", ( events: [ { type: "turn.started", - ...runtimeBase("evt-claude-revert-1", "2026-02-24T10:14:00.000Z", "claudeCode"), + ...runtimeBase("evt-claude-revert-1", "2026-02-24T10:14:00.000Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, }, { type: "message.delta", - ...runtimeBase("evt-claude-revert-2", "2026-02-24T10:14:00.050Z", "claudeCode"), + ...runtimeBase("evt-claude-revert-2", "2026-02-24T10:14:00.050Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, delta: "README -> v2\n", }, { type: "turn.completed", - ...runtimeBase("evt-claude-revert-3", "2026-02-24T10:14:00.100Z", "claudeCode"), + ...runtimeBase("evt-claude-revert-3", "2026-02-24T10:14:00.100Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, status: "completed", @@ -1219,7 +1219,7 @@ it.live("reverts claudeCode turns and rolls back provider conversation state", ( commandId: "cmd-turn-start-claude-revert-1", messageId: "msg-user-claude-revert-1", text: "First Claude edit", - provider: "claudeCode", + provider: "claudeAgent", }); yield* harness.waitForThread( @@ -1232,20 +1232,20 @@ it.live("reverts claudeCode turns and rolls back provider conversation state", ( events: [ { type: "turn.started", - ...runtimeBase("evt-claude-revert-4", "2026-02-24T10:14:01.000Z", "claudeCode"), + ...runtimeBase("evt-claude-revert-4", "2026-02-24T10:14:01.000Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, }, { type: "message.delta", - ...runtimeBase("evt-claude-revert-5", "2026-02-24T10:14:01.050Z", "claudeCode"), + ...runtimeBase("evt-claude-revert-5", "2026-02-24T10:14:01.050Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, delta: "README -> v3\n", }, { type: "turn.completed", - ...runtimeBase("evt-claude-revert-6", "2026-02-24T10:14:01.100Z", "claudeCode"), + ...runtimeBase("evt-claude-revert-6", "2026-02-24T10:14:01.100Z", "claudeAgent"), threadId: THREAD_ID, turnId: FIXTURE_TURN_ID, status: "completed", @@ -1269,7 +1269,7 @@ it.live("reverts claudeCode turns and rolls back provider conversation state", ( (entry) => entry.latestTurn?.turnId === "turn-2" && entry.checkpoints.length === 2 && - entry.session?.providerName === "claudeCode", + entry.session?.providerName === "claudeAgent", ); yield* harness.engine.dispatch({ @@ -1296,6 +1296,6 @@ it.live("reverts claudeCode turns and rolls back provider conversation state", ( ); assert.deepEqual(harness.adapterHarness!.getRollbackCalls(THREAD_ID), [1]); }), - "claudeCode", + "claudeAgent", ), ); diff --git a/apps/server/src/git/Layers/GitManager.test.ts b/apps/server/src/git/Layers/GitManager.test.ts index f60dc7c100..78f8c3cac0 100644 --- a/apps/server/src/git/Layers/GitManager.test.ts +++ b/apps/server/src/git/Layers/GitManager.test.ts @@ -454,7 +454,7 @@ function runStackedAction( provider?: | "codex" | "copilot" - | "claudeCode" + | "claudeAgent" | "cursor" | "opencode" | "geminiCli" diff --git a/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts b/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts index 64547bd0ef..cf8eab18c8 100644 --- a/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts +++ b/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts @@ -48,7 +48,7 @@ type LegacyProviderRuntimeEvent = { readonly provider: | "codex" | "copilot" - | "claudeCode" + | "claudeAgent" | "cursor" | "opencode" | "geminiCli" @@ -67,7 +67,7 @@ function createProviderServiceHarness( cwd: string, hasSession = true, sessionCwd = cwd, - providerName: "codex" | "claudeCode" = "codex", + providerName: "codex" | "claudeAgent" = "codex", ) { const now = new Date().toISOString(); const runtimeEventPubSub = Effect.runSync(PubSub.unbounded()); @@ -244,7 +244,7 @@ describe("CheckpointReactor", () => { readonly projectWorkspaceRoot?: string; readonly threadWorktreePath?: string | null; readonly providerSessionCwd?: string; - readonly providerName?: "codex" | "claudeCode"; + readonly providerName?: "codex" | "claudeAgent"; }) { const cwd = createGitRepository(); tempDirs.push(cwd); @@ -487,10 +487,10 @@ describe("CheckpointReactor", () => { expect(thread.checkpoints[0]?.checkpointTurnCount).toBe(1); }); - it("captures pre-turn and completion checkpoints for claudeCode runtime events", async () => { + it("captures pre-turn and completion checkpoints for claudeAgent runtime events", async () => { const harness = await createHarness({ seedFilesystemCheckpoints: false, - providerName: "claudeCode", + providerName: "claudeAgent", }); const createdAt = new Date().toISOString(); @@ -502,7 +502,7 @@ describe("CheckpointReactor", () => { session: { threadId: ThreadId.makeUnsafe("thread-1"), status: "ready", - providerName: "claudeCode", + providerName: "claudeAgent", runtimeMode: "approval-required", activeTurnId: null, lastError: null, @@ -515,7 +515,7 @@ describe("CheckpointReactor", () => { harness.provider.emit({ type: "turn.started", eventId: EventId.makeUnsafe("evt-turn-started-claude-1"), - provider: "claudeCode", + provider: "claudeAgent", createdAt: new Date().toISOString(), threadId: ThreadId.makeUnsafe("thread-1"), turnId: asTurnId("turn-claude-1"), @@ -529,7 +529,7 @@ describe("CheckpointReactor", () => { harness.provider.emit({ type: "turn.completed", eventId: EventId.makeUnsafe("evt-turn-completed-claude-1"), - provider: "claudeCode", + provider: "claudeAgent", createdAt: new Date().toISOString(), threadId: ThreadId.makeUnsafe("thread-1"), turnId: asTurnId("turn-claude-1"), @@ -863,8 +863,8 @@ describe("CheckpointReactor", () => { ).toBe(false); }); - it("executes provider revert and emits thread.reverted for claudeCode sessions", async () => { - const harness = await createHarness({ providerName: "claudeCode" }); + it("executes provider revert and emits thread.reverted for claudeAgent sessions", async () => { + const harness = await createHarness({ providerName: "claudeAgent" }); const createdAt = new Date().toISOString(); await Effect.runPromise( @@ -875,7 +875,7 @@ describe("CheckpointReactor", () => { session: { threadId: ThreadId.makeUnsafe("thread-1"), status: "ready", - providerName: "claudeCode", + providerName: "claudeAgent", runtimeMode: "approval-required", activeTurnId: null, lastError: null, diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts index 4c530ecec9..b27d5ed530 100644 --- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts +++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts @@ -98,7 +98,7 @@ describe("ProviderCommandReactor", () => { input !== null && "provider" in input && (input.provider === "codex" || - input.provider === "claudeCode" || + input.provider === "claudeAgent" || input.provider === "cursor") ? input.provider : "codex"; @@ -404,7 +404,7 @@ describe("ProviderCommandReactor", () => { text: "hello claude", attachments: [], }, - provider: "claudeCode", + provider: "claudeAgent", interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", createdAt: now, @@ -414,7 +414,7 @@ describe("ProviderCommandReactor", () => { await waitFor(() => harness.startSession.mock.calls.length === 1); await waitFor(() => harness.sendTurn.mock.calls.length === 1); expect(harness.startSession.mock.calls[0]?.[1]).toMatchObject({ - provider: "claudeCode", + provider: "claudeAgent", cwd: "/tmp/provider-project", model: "gpt-5-codex", runtimeMode: "approval-required", @@ -422,7 +422,7 @@ describe("ProviderCommandReactor", () => { const readModel = await Effect.runPromise(harness.engine.getReadModel()); const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); - expect(thread?.session?.providerName).toBe("claudeCode"); + expect(thread?.session?.providerName).toBe("claudeAgent"); expect(thread?.session?.threadId).toBe("thread-1"); }); @@ -736,7 +736,7 @@ describe("ProviderCommandReactor", () => { text: "second", attachments: [], }, - provider: "claudeCode", + provider: "claudeAgent", interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE, runtimeMode: "approval-required", createdAt: now, @@ -749,7 +749,7 @@ describe("ProviderCommandReactor", () => { expect(harness.stopSession.mock.calls.length).toBe(0); expect(harness.startSession.mock.calls[1]?.[1]).toMatchObject({ threadId: ThreadId.makeUnsafe("thread-1"), - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "approval-required", }); expect(harness.startSession.mock.calls[1]?.[1]).not.toHaveProperty("resumeCursor"); @@ -757,7 +757,7 @@ describe("ProviderCommandReactor", () => { const readModel = await Effect.runPromise(harness.engine.getReadModel()); const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); expect(thread?.session?.threadId).toBe("thread-1"); - expect(thread?.session?.providerName).toBe("claudeCode"); + expect(thread?.session?.providerName).toBe("claudeAgent"); expect(thread?.session?.runtimeMode).toBe("approval-required"); }); diff --git a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts index e4c0c67276..ddc61f569a 100644 --- a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts +++ b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts @@ -49,7 +49,7 @@ type LegacyProviderRuntimeEvent = { readonly provider: | "codex" | "copilot" - | "claudeCode" + | "claudeAgent" | "cursor" | "opencode" | "geminiCli" @@ -423,7 +423,7 @@ describe("ProviderRuntimeIngestion", () => { session: { threadId: ThreadId.makeUnsafe("thread-1"), status: "ready", - providerName: "claudeCode", + providerName: "claudeAgent", runtimeMode: "approval-required", activeTurnId: null, updatedAt: seededAt, @@ -436,7 +436,7 @@ describe("ProviderRuntimeIngestion", () => { harness.emit({ type: "turn.started", eventId: asEventId("evt-turn-started-claude-placeholder"), - provider: "claudeCode", + provider: "claudeAgent", createdAt: new Date().toISOString(), threadId: asThreadId("thread-1"), turnId: asTurnId("turn-claude-placeholder"), @@ -452,7 +452,7 @@ describe("ProviderRuntimeIngestion", () => { harness.emit({ type: "turn.completed", eventId: asEventId("evt-turn-completed-claude-placeholder"), - provider: "claudeCode", + provider: "claudeAgent", createdAt: new Date().toISOString(), threadId: asThreadId("thread-1"), turnId: asTurnId("turn-claude-placeholder"), diff --git a/apps/server/src/provider/Layers/ClaudeCodeAdapter.test.ts b/apps/server/src/provider/Layers/ClaudeAdapter.test.ts similarity index 93% rename from apps/server/src/provider/Layers/ClaudeCodeAdapter.test.ts rename to apps/server/src/provider/Layers/ClaudeAdapter.test.ts index 46c444f2a3..8d8d74ce9a 100644 --- a/apps/server/src/provider/Layers/ClaudeCodeAdapter.test.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.test.ts @@ -11,11 +11,11 @@ import { assert, describe, it } from "@effect/vitest"; import { Effect, Fiber, Random, Stream } from "effect"; import { ProviderAdapterValidationError } from "../Errors.ts"; -import { ClaudeCodeAdapter } from "../Services/ClaudeCodeAdapter.ts"; +import { ClaudeAdapter } from "../Services/ClaudeAdapter.ts"; import { - makeClaudeCodeAdapterLive, - type ClaudeCodeAdapterLiveOptions, -} from "./ClaudeCodeAdapter.ts"; + makeClaudeAdapterLive, + type ClaudeAdapterLiveOptions, +} from "./ClaudeAdapter.ts"; class FakeClaudeQuery implements AsyncIterable { private readonly queue: Array = []; @@ -98,7 +98,7 @@ class FakeClaudeQuery implements AsyncIterable { } interface Harness { - readonly layer: ReturnType; + readonly layer: ReturnType; readonly query: FakeClaudeQuery; readonly getLastCreateQueryInput: () => | { @@ -110,7 +110,7 @@ interface Harness { function makeHarness(config?: { readonly nativeEventLogPath?: string; - readonly nativeEventLogger?: ClaudeCodeAdapterLiveOptions["nativeEventLogger"]; + readonly nativeEventLogger?: ClaudeAdapterLiveOptions["nativeEventLogger"]; }): Harness { const query = new FakeClaudeQuery(); let createInput: @@ -120,7 +120,7 @@ function makeHarness(config?: { } | undefined; - const adapterOptions: ClaudeCodeAdapterLiveOptions = { + const adapterOptions: ClaudeAdapterLiveOptions = { createQuery: (input) => { createInput = input; return query; @@ -138,7 +138,7 @@ function makeHarness(config?: { }; return { - layer: makeClaudeCodeAdapterLive(adapterOptions), + layer: makeClaudeAdapterLive(adapterOptions), query, getLastCreateQueryInput: () => createInput, }; @@ -163,11 +163,11 @@ function makeDeterministicRandomService(seed = 0x1234_5678): { const THREAD_ID = ThreadId.makeUnsafe("thread-claude-1"); const RESUME_THREAD_ID = ThreadId.makeUnsafe("thread-claude-resume"); -describe("ClaudeCodeAdapterLive", () => { - it.effect("returns validation error for non-claudeCode provider on startSession", () => { +describe("ClaudeAdapterLive", () => { + it.effect("returns validation error for non-claudeAgent provider on startSession", () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; const result = yield* adapter .startSession({ threadId: THREAD_ID, provider: "codex", runtimeMode: "full-access" }) .pipe(Effect.result); @@ -179,9 +179,9 @@ describe("ClaudeCodeAdapterLive", () => { assert.deepEqual( result.failure, new ProviderAdapterValidationError({ - provider: "claudeCode", + provider: "claudeAgent", operation: "startSession", - issue: "Expected provider 'claudeCode' but received 'codex'.", + issue: "Expected provider 'claudeAgent' but received 'codex'.", }), ); }).pipe( @@ -193,10 +193,10 @@ describe("ClaudeCodeAdapterLive", () => { it.effect("derives bypass permission mode from full-access runtime policy", () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "full-access", }); @@ -213,13 +213,13 @@ describe("ClaudeCodeAdapterLive", () => { it.effect("keeps explicit claude permission mode over runtime-derived defaults", () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "full-access", providerOptions: { - claudeCode: { + claudeAgent: { permissionMode: "plan", }, }, @@ -247,10 +247,10 @@ describe("ClaudeCodeAdapterLive", () => { process.env.PATH = "/usr/bin:/bin"; return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "full-access", }); @@ -296,7 +296,7 @@ describe("ClaudeCodeAdapterLive", () => { it.effect("maps Claude stream/runtime messages to canonical provider runtime events", () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; const runtimeEventsFiber = yield* Stream.take(adapter.streamEvents, 11).pipe( Stream.runCollect, @@ -305,7 +305,7 @@ describe("ClaudeCodeAdapterLive", () => { const session = yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", model: "claude-sonnet-4-5", runtimeMode: "full-access", }); @@ -435,7 +435,7 @@ describe("ClaudeCodeAdapterLive", () => { () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; const runtimeEventsFiber = yield* Stream.take(adapter.streamEvents, 9).pipe( Stream.runCollect, @@ -444,7 +444,7 @@ describe("ClaudeCodeAdapterLive", () => { const session = yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "full-access", }); @@ -527,7 +527,7 @@ describe("ClaudeCodeAdapterLive", () => { it.effect("falls back to assistant payload text when stream deltas are absent", () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; const runtimeEventsFiber = yield* Stream.take(adapter.streamEvents, 9).pipe( Stream.runCollect, @@ -536,7 +536,7 @@ describe("ClaudeCodeAdapterLive", () => { const session = yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "full-access", }); @@ -597,7 +597,7 @@ describe("ClaudeCodeAdapterLive", () => { it.effect("does not fabricate provider thread ids before first SDK session_id", () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; const runtimeEventsFiber = yield* Stream.take(adapter.streamEvents, 5).pipe( Stream.runCollect, @@ -606,7 +606,7 @@ describe("ClaudeCodeAdapterLive", () => { const session = yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "full-access", }); assert.equal(session.threadId, THREAD_ID); @@ -687,11 +687,11 @@ describe("ClaudeCodeAdapterLive", () => { it.effect("bridges approval request/response lifecycle through canUseTool", () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; const session = yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "approval-required", }); @@ -764,11 +764,11 @@ describe("ClaudeCodeAdapterLive", () => { it.effect("passes parsed resume cursor values to Claude query options", () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; const session = yield* adapter.startSession({ threadId: RESUME_THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", resumeCursor: { threadId: "resume-thread-1", resume: "550e8400-e29b-41d4-a716-446655440000", @@ -798,11 +798,11 @@ describe("ClaudeCodeAdapterLive", () => { it.effect("does not synthesize resume session id from generated thread ids", () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; const session = yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "full-access", }); @@ -821,11 +821,11 @@ describe("ClaudeCodeAdapterLive", () => { () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; const session = yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "full-access", }); @@ -845,11 +845,11 @@ describe("ClaudeCodeAdapterLive", () => { it.effect("updates model on sendTurn when model override is provided", () => { const harness = makeHarness(); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; const session = yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "full-access", }); yield* adapter.sendTurn({ @@ -886,11 +886,11 @@ describe("ClaudeCodeAdapterLive", () => { }, }); return Effect.gen(function* () { - const adapter = yield* ClaudeCodeAdapter; + const adapter = yield* ClaudeAdapter; const session = yield* adapter.startSession({ threadId: THREAD_ID, - provider: "claudeCode", + provider: "claudeAgent", runtimeMode: "full-access", }); const turn = yield* adapter.sendTurn({ @@ -933,7 +933,7 @@ describe("ClaudeCodeAdapterLive", () => { assert.equal(nativeEvents.length > 0, true); assert.equal( - nativeEvents.some((record) => record.event?.provider === "claudeCode"), + nativeEvents.some((record) => record.event?.provider === "claudeAgent"), true, ); assert.equal( diff --git a/apps/server/src/provider/Layers/ClaudeCodeAdapter.ts b/apps/server/src/provider/Layers/ClaudeAdapter.ts similarity index 97% rename from apps/server/src/provider/Layers/ClaudeCodeAdapter.ts rename to apps/server/src/provider/Layers/ClaudeAdapter.ts index 5f1a328b51..a5d095c8c6 100644 --- a/apps/server/src/provider/Layers/ClaudeCodeAdapter.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.ts @@ -1,10 +1,10 @@ /** - * ClaudeCodeAdapterLive - Scoped live implementation for the Claude Code provider adapter. + * ClaudeAdapterLive - Scoped live implementation for the Claude Code provider adapter. * * Wraps `@anthropic-ai/claude-agent-sdk` query sessions behind the generic * provider adapter contract and emits canonical runtime events. * - * @module ClaudeCodeAdapterLive + * @module ClaudeAdapterLive */ import { createRequire } from "node:module"; import * as Path from "node:path"; @@ -50,13 +50,13 @@ import { type ProviderAdapterError, } from "../Errors.ts"; import { getProviderCapabilities } from "../Services/ProviderAdapter.ts"; -import { ClaudeCodeAdapter, type ClaudeCodeAdapterShape } from "../Services/ClaudeCodeAdapter.ts"; +import { ClaudeAdapter, type ClaudeAdapterShape } from "../Services/ClaudeAdapter.ts"; import { type EventNdjsonLogger, makeEventNdjsonLogger } from "./EventNdjsonLogger.ts"; import { toMessage } from "../toMessage.ts"; import { createLogger } from "../../logger"; -const PROVIDER = "claudeCode" as const; +const PROVIDER = "claudeAgent" as const; const logger = createLogger(PROVIDER); /** @@ -237,7 +237,7 @@ interface ClaudeQueryRuntime extends AsyncIterable { readonly close: () => void; } -export interface ClaudeCodeAdapterLiveOptions { +export interface ClaudeAdapterLiveOptions { readonly createQuery?: (input: { readonly prompt: AsyncIterable; readonly options: ClaudeQueryOptions; @@ -622,7 +622,7 @@ function sdkNativeItemId(message: SDKMessageLoose): string | undefined { return undefined; } -function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { +function makeClaudeAdapter(options?: ClaudeAdapterLiveOptions) { return Effect.gen(function* () { const nativeEventLogger = options?.nativeEventLogger ?? @@ -1564,7 +1564,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { return Effect.succeed(context); }; - const startSession: ClaudeCodeAdapterShape["startSession"] = (input) => + const startSession: ClaudeAdapterShape["startSession"] = (input) => Effect.gen(function* () { if (input.provider !== undefined && input.provider !== PROVIDER) { return yield* new ProviderAdapterValidationError({ @@ -1723,12 +1723,12 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { }), ); - const providerOptions = input.providerOptions?.claudeCode; - const claudeCodeModelOptions = input.modelOptions?.claudeCode; + const providerOptions = input.providerOptions?.claudeAgent; + const claudeAgentModelOptions = input.modelOptions?.claudeAgent; const permissionMode = toPermissionMode(providerOptions?.permissionMode) ?? (input.runtimeMode === "full-access" ? "bypassPermissions" : undefined); - const effort = claudeCodeModelOptions?.effort as EffortLevel | undefined; + const effort = claudeAgentModelOptions?.effort as EffortLevel | undefined; const pathToClaudeCodeExecutable = yield* Effect.try({ try: () => @@ -1890,7 +1890,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { }; }); - const sendTurn: ClaudeCodeAdapterShape["sendTurn"] = (input) => + const sendTurn: ClaudeAdapterShape["sendTurn"] = (input) => Effect.gen(function* () { const context = yield* requireSession(input.threadId); @@ -1963,7 +1963,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { }; }); - const interruptTurn: ClaudeCodeAdapterShape["interruptTurn"] = (threadId, _turnId) => + const interruptTurn: ClaudeAdapterShape["interruptTurn"] = (threadId, _turnId) => Effect.gen(function* () { const context = yield* requireSession(threadId); yield* Effect.tryPromise({ @@ -1972,13 +1972,13 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { }); }); - const readThread: ClaudeCodeAdapterShape["readThread"] = (threadId) => + const readThread: ClaudeAdapterShape["readThread"] = (threadId) => Effect.gen(function* () { const context = yield* requireSession(threadId); return yield* snapshotThread(context); }); - const rollbackThread: ClaudeCodeAdapterShape["rollbackThread"] = (threadId, _numTurns) => + const rollbackThread: ClaudeAdapterShape["rollbackThread"] = (threadId, _numTurns) => Effect.gen(function* () { yield* requireSession(threadId); return yield* new ProviderAdapterRequestError({ @@ -1989,7 +1989,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { }); }); - const respondToRequest: ClaudeCodeAdapterShape["respondToRequest"] = ( + const respondToRequest: ClaudeAdapterShape["respondToRequest"] = ( threadId, requestId, decision, @@ -2009,7 +2009,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { yield* Deferred.succeed(pending.decision, decision); }); - const respondToUserInput: ClaudeCodeAdapterShape["respondToUserInput"] = ( + const respondToUserInput: ClaudeAdapterShape["respondToUserInput"] = ( threadId, requestId, _answers, @@ -2022,7 +2022,7 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { }), ); - const stopSession: ClaudeCodeAdapterShape["stopSession"] = (threadId) => + const stopSession: ClaudeAdapterShape["stopSession"] = (threadId) => Effect.gen(function* () { const context = yield* requireSession(threadId); yield* stopSessionInternal(context, { @@ -2030,16 +2030,16 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { }); }); - const listSessions: ClaudeCodeAdapterShape["listSessions"] = () => + const listSessions: ClaudeAdapterShape["listSessions"] = () => Effect.sync(() => Array.from(sessions.values(), ({ session }) => ({ ...session }))); - const hasSession: ClaudeCodeAdapterShape["hasSession"] = (threadId) => + const hasSession: ClaudeAdapterShape["hasSession"] = (threadId) => Effect.sync(() => { const context = sessions.get(threadId); return context !== undefined && !context.stopped; }); - const stopAll: ClaudeCodeAdapterShape["stopAll"] = () => + const stopAll: ClaudeAdapterShape["stopAll"] = () => Effect.forEach( sessions, ([, context]) => @@ -2075,12 +2075,12 @@ function makeClaudeCodeAdapter(options?: ClaudeCodeAdapterLiveOptions) { hasSession, stopAll, streamEvents: Stream.fromQueue(runtimeEventQueue), - } satisfies ClaudeCodeAdapterShape; + } satisfies ClaudeAdapterShape; }); } -export const ClaudeCodeAdapterLive = Layer.effect(ClaudeCodeAdapter, makeClaudeCodeAdapter()); +export const ClaudeAdapterLive = Layer.effect(ClaudeAdapter, makeClaudeAdapter()); -export function makeClaudeCodeAdapterLive(options?: ClaudeCodeAdapterLiveOptions) { - return Layer.effect(ClaudeCodeAdapter, makeClaudeCodeAdapter(options)); +export function makeClaudeAdapterLive(options?: ClaudeAdapterLiveOptions) { + return Layer.effect(ClaudeAdapter, makeClaudeAdapter(options)); } diff --git a/apps/server/src/provider/Layers/CodexAdapter.test.ts b/apps/server/src/provider/Layers/CodexAdapter.test.ts index 394b275456..8cdca0cb0a 100644 --- a/apps/server/src/provider/Layers/CodexAdapter.test.ts +++ b/apps/server/src/provider/Layers/CodexAdapter.test.ts @@ -172,7 +172,7 @@ validationLayer("CodexAdapterLive validation", (it) => { const adapter = yield* CodexAdapter; const result = yield* adapter .startSession({ - provider: "claudeCode", + provider: "claudeAgent", threadId: asThreadId("thread-1"), runtimeMode: "full-access", }) @@ -184,7 +184,7 @@ validationLayer("CodexAdapterLive validation", (it) => { new ProviderAdapterValidationError({ provider: "codex", operation: "startSession", - issue: "Expected provider 'codex' but received 'claudeCode'.", + issue: "Expected provider 'codex' but received 'claudeAgent'.", }), ); assert.equal(validationManager.startSessionImpl.mock.calls.length, 0); diff --git a/apps/server/src/provider/Layers/ProviderAdapterConformance.test.ts b/apps/server/src/provider/Layers/ProviderAdapterConformance.test.ts index ec40f84752..2925bf94cf 100644 --- a/apps/server/src/provider/Layers/ProviderAdapterConformance.test.ts +++ b/apps/server/src/provider/Layers/ProviderAdapterConformance.test.ts @@ -7,7 +7,7 @@ import { AmpServerManager } from "../../ampServerManager.ts"; import { GeminiCliServerManager } from "../../geminiCliServerManager.ts"; import { ServerConfig } from "../../config.ts"; import { makeAmpAdapterLive } from "./AmpAdapter.ts"; -import { makeClaudeCodeAdapterLive } from "./ClaudeCodeAdapter.ts"; +import { makeClaudeAdapterLive } from "./ClaudeAdapter.ts"; import { makeCodexAdapterLive } from "./CodexAdapter.ts"; import { makeCopilotAdapterLive } from "./CopilotAdapter.ts"; import { makeCursorAdapterLive } from "./CursorAdapter.ts"; @@ -18,7 +18,7 @@ import { validateProviderAdapterConformance, } from "../Services/ProviderAdapter.ts"; import { AmpAdapter } from "../Services/AmpAdapter.ts"; -import { ClaudeCodeAdapter } from "../Services/ClaudeCodeAdapter.ts"; +import { ClaudeAdapter } from "../Services/ClaudeAdapter.ts"; import { CodexAdapter } from "../Services/CodexAdapter.ts"; import { CopilotAdapter } from "../Services/CopilotAdapter.ts"; import { CursorAdapter } from "../Services/CursorAdapter.ts"; @@ -57,7 +57,7 @@ const copilotLayer = makeCopilotAdapterLive({ Layer.provideMerge(NodeServices.layer), ); -const claudeLayer = makeClaudeCodeAdapterLive({ +const claudeLayer = makeClaudeAdapterLive({ createQuery: () => ({ [Symbol.asyncIterator]: async function* () { @@ -104,11 +104,11 @@ describe("provider adapter conformance", () => { ), }, { - provider: "claudeCode" as const, + provider: "claudeAgent" as const, load: () => Effect.runPromise( Effect.gen(function* () { - return yield* ClaudeCodeAdapter; + return yield* ClaudeAdapter; }).pipe(Effect.provide(claudeLayer)), ), }, diff --git a/apps/server/src/provider/Layers/ProviderAdapterRegistry.test.ts b/apps/server/src/provider/Layers/ProviderAdapterRegistry.test.ts index 6b52803dd3..cce8d43c9c 100644 --- a/apps/server/src/provider/Layers/ProviderAdapterRegistry.test.ts +++ b/apps/server/src/provider/Layers/ProviderAdapterRegistry.test.ts @@ -5,7 +5,7 @@ import type { ProviderKind } from "@t3tools/contracts"; import { Effect, Layer, Stream } from "effect"; import { ProviderUnsupportedError } from "../Errors.ts"; -import { ClaudeCodeAdapter, type ClaudeCodeAdapterShape } from "../Services/ClaudeCodeAdapter.ts"; +import { ClaudeAdapter, type ClaudeAdapterShape } from "../Services/ClaudeAdapter.ts"; import { CopilotAdapter, type CopilotAdapterShape } from "../Services/CopilotAdapter.ts"; import { CodexAdapter, type CodexAdapterShape } from "../Services/CodexAdapter.ts"; import { CursorAdapter, type CursorAdapterShape } from "../Services/CursorAdapter.ts"; @@ -34,9 +34,9 @@ const fakeCodexAdapter: CodexAdapterShape = { streamEvents: Stream.empty, }; -const fakeClaudeAdapter: ClaudeCodeAdapterShape = { - provider: "claudeCode", - capabilities: getProviderCapabilities("claudeCode"), +const fakeClaudeAdapter: ClaudeAdapterShape = { + provider: "claudeAgent", + capabilities: getProviderCapabilities("claudeAgent"), startSession: vi.fn(), sendTurn: vi.fn(), interruptTurn: vi.fn(), @@ -159,7 +159,7 @@ const layer = it.layer( Layer.mergeAll( Layer.succeed(CodexAdapter, fakeCodexAdapter), Layer.succeed(CopilotAdapter, fakeCopilotAdapter), - Layer.succeed(ClaudeCodeAdapter, fakeClaudeAdapter), + Layer.succeed(ClaudeAdapter, fakeClaudeAdapter), Layer.succeed(CursorAdapter, fakeCursorAdapter), Layer.succeed(OpenCodeAdapter, fakeOpenCodeAdapter), Layer.succeed(GeminiCliAdapter, fakeGeminiCliAdapter), @@ -177,7 +177,7 @@ layer("ProviderAdapterRegistryLive", (it) => { const registry = yield* ProviderAdapterRegistry; const codex = yield* registry.getByProvider("codex"); const copilot = yield* registry.getByProvider("copilot"); - const claude = yield* registry.getByProvider("claudeCode"); + const claude = yield* registry.getByProvider("claudeAgent"); const cursor = yield* registry.getByProvider("cursor"); const opencode = yield* registry.getByProvider("opencode"); const geminiCli = yield* registry.getByProvider("geminiCli"); @@ -197,7 +197,7 @@ layer("ProviderAdapterRegistryLive", (it) => { assert.deepEqual(providers, [ "codex", "copilot", - "claudeCode", + "claudeAgent", "cursor", "opencode", "geminiCli", diff --git a/apps/server/src/provider/Layers/ProviderAdapterRegistry.ts b/apps/server/src/provider/Layers/ProviderAdapterRegistry.ts index aed87db0ac..3a4b89baeb 100644 --- a/apps/server/src/provider/Layers/ProviderAdapterRegistry.ts +++ b/apps/server/src/provider/Layers/ProviderAdapterRegistry.ts @@ -16,7 +16,7 @@ import { ProviderAdapterRegistry, type ProviderAdapterRegistryShape, } from "../Services/ProviderAdapterRegistry.ts"; -import { ClaudeCodeAdapter } from "../Services/ClaudeCodeAdapter.ts"; +import { ClaudeAdapter } from "../Services/ClaudeAdapter.ts"; import { CopilotAdapter } from "../Services/CopilotAdapter.ts"; import { CodexAdapter } from "../Services/CodexAdapter.ts"; import { CursorAdapter } from "../Services/CursorAdapter.ts"; @@ -37,7 +37,7 @@ const makeProviderAdapterRegistry = (options?: ProviderAdapterRegistryLiveOption : [ yield* CodexAdapter, yield* CopilotAdapter, - yield* ClaudeCodeAdapter, + yield* ClaudeAdapter, yield* CursorAdapter, yield* OpenCodeAdapter, yield* GeminiCliAdapter, diff --git a/apps/server/src/provider/Layers/ProviderService.test.ts b/apps/server/src/provider/Layers/ProviderService.test.ts index 41d9a098a6..f2709ec408 100644 --- a/apps/server/src/provider/Layers/ProviderService.test.ts +++ b/apps/server/src/provider/Layers/ProviderService.test.ts @@ -56,7 +56,7 @@ type LegacyProviderRuntimeEvent = { readonly provider: | "codex" | "copilot" - | "claudeCode" + | "claudeAgent" | "cursor" | "opencode" | "geminiCli" @@ -224,15 +224,15 @@ const sleep = (ms: number) => function makeProviderServiceLayer() { const codex = makeFakeCodexAdapter(); - const claude = makeFakeCodexAdapter("claudeCode"); + const claude = makeFakeCodexAdapter("claudeAgent"); const registry: typeof ProviderAdapterRegistry.Service = { getByProvider: (provider) => provider === "codex" ? Effect.succeed(codex.adapter) - : provider === "claudeCode" + : provider === "claudeAgent" ? Effect.succeed(claude.adapter) : Effect.fail(new ProviderUnsupportedError({ provider })), - listProviders: () => Effect.succeed(["codex", "claudeCode"]), + listProviders: () => Effect.succeed(["codex", "claudeAgent"]), }; const providerAdapterLayer = Layer.succeed(ProviderAdapterRegistry, registry); @@ -504,24 +504,24 @@ routing.layer("ProviderServiceLive routing", (it) => { }), ); - it.effect("routes explicit claudeCode provider session starts to the claude adapter", () => + it.effect("routes explicit claudeAgent provider session starts to the claude adapter", () => Effect.gen(function* () { const provider = yield* ProviderService; const session = yield* provider.startSession(asThreadId("thread-claude"), { - provider: "claudeCode", + provider: "claudeAgent", threadId: asThreadId("thread-claude"), cwd: "/tmp/project-claude", runtimeMode: "full-access", }); - assert.equal(session.provider, "claudeCode"); + assert.equal(session.provider, "claudeAgent"); assert.equal(routing.claude.startSession.mock.calls.length, 1); const startInput = routing.claude.startSession.mock.calls[0]?.[0]; assert.equal(typeof startInput === "object" && startInput !== null, true); if (startInput && typeof startInput === "object") { const startPayload = startInput as { provider?: string; cwd?: string }; - assert.equal(startPayload.provider, "claudeCode"); + assert.equal(startPayload.provider, "claudeAgent"); assert.equal(startPayload.cwd, "/tmp/project-claude"); } }), diff --git a/apps/server/src/provider/Layers/ProviderSessionDirectory.ts b/apps/server/src/provider/Layers/ProviderSessionDirectory.ts index 937a883dbf..26f62e4dd1 100644 --- a/apps/server/src/provider/Layers/ProviderSessionDirectory.ts +++ b/apps/server/src/provider/Layers/ProviderSessionDirectory.ts @@ -25,7 +25,7 @@ function decodeProviderKind( if ( providerName === "codex" || providerName === "copilot" || - providerName === "claudeCode" || + providerName === "claudeAgent" || providerName === "cursor" || providerName === "opencode" || providerName === "geminiCli" || diff --git a/apps/server/src/provider/Services/ClaudeAdapter.ts b/apps/server/src/provider/Services/ClaudeAdapter.ts new file mode 100644 index 0000000000..f08a3aab87 --- /dev/null +++ b/apps/server/src/provider/Services/ClaudeAdapter.ts @@ -0,0 +1,31 @@ +/** + * ClaudeAdapter - Claude Code implementation of the generic provider adapter contract. + * + * This service owns Claude runtime/session semantics and emits canonical + * provider runtime events. It does not perform cross-provider routing, shared + * event fan-out, or checkpoint orchestration. + * + * Uses Effect `ServiceMap.Service` for dependency injection and returns the + * shared provider-adapter error channel with `provider: "claudeAgent"` context. + * + * @module ClaudeAdapter + */ +import { ServiceMap } from "effect"; + +import type { ProviderAdapterError } from "../Errors.ts"; +import type { ProviderAdapterShape } from "./ProviderAdapter.ts"; + +/** + * ClaudeAdapterShape - Service API for the Claude Code provider adapter. + */ +export interface ClaudeAdapterShape extends ProviderAdapterShape { + readonly provider: "claudeAgent"; +} + +/** + * ClaudeAdapter - Service tag for Claude Code provider adapter operations. + */ +export class ClaudeAdapter extends ServiceMap.Service< + ClaudeAdapter, + ClaudeAdapterShape +>()("t3/provider/Services/ClaudeAdapter") {} diff --git a/apps/server/src/provider/Services/ClaudeCodeAdapter.ts b/apps/server/src/provider/Services/ClaudeCodeAdapter.ts deleted file mode 100644 index 6ef6876061..0000000000 --- a/apps/server/src/provider/Services/ClaudeCodeAdapter.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * ClaudeCodeAdapter - Claude Code implementation of the generic provider adapter contract. - * - * This service owns Claude runtime/session semantics and emits canonical - * provider runtime events. It does not perform cross-provider routing, shared - * event fan-out, or checkpoint orchestration. - * - * Uses Effect `ServiceMap.Service` for dependency injection and returns the - * shared provider-adapter error channel with `provider: "claudeCode"` context. - * - * @module ClaudeCodeAdapter - */ -import { ServiceMap } from "effect"; - -import type { ProviderAdapterError } from "../Errors.ts"; -import type { ProviderAdapterShape } from "./ProviderAdapter.ts"; - -/** - * ClaudeCodeAdapterShape - Service API for the Claude Code provider adapter. - */ -export interface ClaudeCodeAdapterShape extends ProviderAdapterShape { - readonly provider: "claudeCode"; -} - -/** - * ClaudeCodeAdapter - Service tag for Claude Code provider adapter operations. - */ -export class ClaudeCodeAdapter extends ServiceMap.Service< - ClaudeCodeAdapter, - ClaudeCodeAdapterShape ->()("t3/provider/Services/ClaudeCodeAdapter") {} diff --git a/apps/server/src/provider/Services/ProviderAdapter.ts b/apps/server/src/provider/Services/ProviderAdapter.ts index be6f8b61eb..f153c2bf07 100644 --- a/apps/server/src/provider/Services/ProviderAdapter.ts +++ b/apps/server/src/provider/Services/ProviderAdapter.ts @@ -121,7 +121,7 @@ export const PROVIDER_CAPABILITIES_BY_PROVIDER: Readonly< supportsAttachments: true, persistentRuntime: true, }, - claudeCode: { + claudeAgent: { sessionModelSwitch: "in-session", transport: "sdk-query", modelDiscovery: "session-native", diff --git a/apps/server/src/serverLayers.ts b/apps/server/src/serverLayers.ts index 08457d5bf4..3b489c1d6e 100644 --- a/apps/server/src/serverLayers.ts +++ b/apps/server/src/serverLayers.ts @@ -19,7 +19,7 @@ import { OrchestrationProjectionSnapshotQueryLive } from "./orchestration/Layers import { ProviderRuntimeIngestionLive } from "./orchestration/Layers/ProviderRuntimeIngestion"; import { RuntimeReceiptBusLive } from "./orchestration/Layers/RuntimeReceiptBus"; import { ProviderUnsupportedError } from "./provider/Errors"; -import { makeClaudeCodeAdapterLive } from "./provider/Layers/ClaudeCodeAdapter"; +import { makeClaudeAdapterLive } from "./provider/Layers/ClaudeAdapter"; import { makeCopilotAdapterLive } from "./provider/Layers/CopilotAdapter"; import { makeCodexAdapterLive } from "./provider/Layers/CodexAdapter"; import { makeCursorAdapterLive } from "./provider/Layers/CursorAdapter"; @@ -69,7 +69,7 @@ export function makeServerProviderLayer(): Layer.Layer< const copilotAdapterLayer = makeCopilotAdapterLive( nativeEventLogger ? { nativeEventLogger } : undefined, ); - const claudeAdapterLayer = makeClaudeCodeAdapterLive( + const claudeAdapterLayer = makeClaudeAdapterLive( nativeEventLogger ? { nativeEventLogger } : undefined, ); const cursorAdapterLayer = makeCursorAdapterLive( diff --git a/apps/server/src/wsServer.ts b/apps/server/src/wsServer.ts index 99c1daaf2b..b5cc9efce1 100644 --- a/apps/server/src/wsServer.ts +++ b/apps/server/src/wsServer.ts @@ -77,7 +77,7 @@ import { fetchOpenCodeModels } from "./opencodeServerManager.ts"; import { fetchCopilotModels, fetchCopilotUsage } from "./provider/Layers/CopilotAdapter.ts"; import { fetchCursorModels } from "./provider/Layers/CursorAdapter.ts"; import { fetchCursorUsage } from "./provider/Layers/CursorUsage.ts"; -import { fetchClaudeCodeUsage } from "./provider/Layers/ClaudeCodeAdapter.ts"; +import { fetchClaudeCodeUsage } from "./provider/Layers/ClaudeAdapter.ts"; import { fetchCodexUsage } from "./provider/Layers/CodexAdapter.ts"; import { @@ -984,7 +984,7 @@ export const createServer = Effect.fn(function* (): Effect.fn.Return< }); return usage satisfies ProviderUsageResult; } - if (provider === "claudeCode") { + if (provider === "claudeAgent") { return fetchClaudeCodeUsage() satisfies ProviderUsageResult; } if (provider === "geminiCli") { diff --git a/apps/web/src/appSettings.test.ts b/apps/web/src/appSettings.test.ts index 2085b727aa..8f080baf83 100644 --- a/apps/web/src/appSettings.test.ts +++ b/apps/web/src/appSettings.test.ts @@ -79,8 +79,8 @@ describe("normalizeCustomModelSlugs", () => { }); it("normalizes provider-specific aliases for claude and cursor", () => { - expect(normalizeCustomModelSlugs(["sonnet"], "claudeCode")).toEqual([]); - expect(normalizeCustomModelSlugs(["claude/custom-sonnet"], "claudeCode")).toEqual([ + expect(normalizeCustomModelSlugs(["sonnet"], "claudeAgent")).toEqual([]); + expect(normalizeCustomModelSlugs(["claude/custom-sonnet"], "claudeAgent")).toEqual([ "claude/custom-sonnet", ]); expect(normalizeCustomModelSlugs(["composer"], "cursor")).toEqual([]); @@ -116,7 +116,7 @@ describe("getAppModelOptions", () => { }); it("keeps a saved custom provider model available as an exact slug option", () => { - const options = getAppModelOptions("claudeCode", ["claude/custom-opus"], "claude/custom-opus"); + const options = getAppModelOptions("claudeAgent", ["claude/custom-opus"], "claude/custom-opus"); expect(options.some((option) => option.slug === "claude/custom-opus" && option.isCustom)).toBe( true, @@ -169,7 +169,7 @@ describe("timestamp format defaults", () => { }); it("includes provider-specific custom slugs in non-codex model lists", () => { - const claudeOptions = getAppModelOptions("claudeCode", ["claude/custom-opus"]); + const claudeOptions = getAppModelOptions("claudeAgent", ["claude/custom-opus"]); const cursorOptions = getAppModelOptions("cursor", ["cursor/custom-model"]); expect(claudeOptions.some((option) => option.slug === "claude/custom-opus")).toBe(true); diff --git a/apps/web/src/appSettings.ts b/apps/web/src/appSettings.ts index c1d4200a7b..6904775f64 100644 --- a/apps/web/src/appSettings.ts +++ b/apps/web/src/appSettings.ts @@ -37,7 +37,7 @@ export const DEFAULT_TIMESTAMP_FORMAT: TimestampFormat = "locale"; const BUILT_IN_MODEL_SLUGS_BY_PROVIDER: Record> = { codex: new Set(getModelOptions("codex").map((option) => option.slug)), copilot: new Set(getModelOptions("copilot").map((option) => option.slug)), - claudeCode: new Set(getModelOptions("claudeCode").map((option) => option.slug)), + claudeAgent: new Set(getModelOptions("claudeAgent").map((option) => option.slug)), cursor: new Set(getModelOptions("cursor").map((option) => option.slug)), opencode: new Set(getModelOptions("opencode").map((option) => option.slug)), geminiCli: new Set(getModelOptions("geminiCli").map((option) => option.slug)), @@ -47,7 +47,7 @@ const BUILT_IN_MODEL_SLUGS_BY_PROVIDER: Record const PROVIDER_KINDS = [ "codex", "copilot", - "claudeCode", + "claudeAgent", "cursor", "opencode", "geminiCli", @@ -216,7 +216,7 @@ export function getCustomModelsForProvider( switch (provider) { case "copilot": return settings.customCopilotModels; - case "claudeCode": + case "claudeAgent": return settings.customClaudeModels; case "cursor": return settings.customCursorModels; @@ -238,7 +238,7 @@ export function patchCustomModels(provider: ProviderKind, models: string[]): Par switch (provider) { case "copilot": return { customCopilotModels: models }; - case "claudeCode": + case "claudeAgent": return { customClaudeModels: models }; case "cursor": return { customCursorModels: models }; @@ -283,7 +283,7 @@ function normalizeAppSettings(settings: AppSettings): AppSettings { ...settings, customCodexModels: normalizeCustomModelSlugs(settings.customCodexModels, "codex"), customCopilotModels: normalizeCustomModelSlugs(settings.customCopilotModels, "copilot"), - customClaudeModels: normalizeCustomModelSlugs(settings.customClaudeModels, "claudeCode"), + customClaudeModels: normalizeCustomModelSlugs(settings.customClaudeModels, "claudeAgent"), customCursorModels: normalizeCustomModelSlugs(settings.customCursorModels, "cursor"), customOpencodeModels: normalizeCustomModelSlugs(settings.customOpencodeModels, "opencode"), customGeminiCliModels: normalizeCustomModelSlugs(settings.customGeminiCliModels, "geminiCli"), diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index dbf352a715..97155717f4 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -160,7 +160,7 @@ import { import { ComposerCommandItem, ComposerCommandMenu } from "./chat/ComposerCommandMenu"; import { ComposerPendingApprovalActions } from "./chat/ComposerPendingApprovalActions"; import { CodexTraitsPicker } from "./chat/CodexTraitsPicker"; -import { ClaudeCodeTraitsPicker } from "./chat/ClaudeCodeTraitsPicker"; +import { ClaudeTraitsPicker } from "./chat/ClaudeTraitsPicker"; import { CursorTraitsPicker } from "./chat/CursorTraitsPicker"; import { CompactComposerControlsMenu } from "./chat/CompactComposerControlsMenu"; import { ComposerPendingApprovalPanel } from "./chat/ComposerPendingApprovalPanel"; @@ -603,7 +603,7 @@ export default function ChatView({ threadId }: ChatViewProps) { () => ({ codex: settings.customCodexModels, copilot: settings.customCopilotModels, - claudeCode: settings.customClaudeModels, + claudeAgent: settings.customClaudeModels, cursor: settings.customCursorModels, opencode: settings.customOpencodeModels, geminiCli: settings.customGeminiCliModels, @@ -642,10 +642,10 @@ export default function ChatView({ threadId }: ChatViewProps) { const selectedEffort = composerDraft.effort ?? getDefaultReasoningEffort(selectedProvider); const selectedCodexFastModeEnabled = selectedProvider === "codex" ? composerDraft.codexFastMode : false; - const claudeCodeEffortOptions = getClaudeCodeEffortOptions(selectedProvider); - const supportsClaudeCodeEffort = claudeCodeEffortOptions.length > 0; + const claudeAgentEffortOptions = getClaudeCodeEffortOptions(selectedProvider); + const supportsClaudeCodeEffort = claudeAgentEffortOptions.length > 0; const selectedClaudeCodeEffort = - composerDraft.claudeCodeEffort ?? getDefaultClaudeCodeEffort(selectedProvider); + composerDraft.claudeAgentEffort ?? getDefaultClaudeCodeEffort(selectedProvider); const selectedModelOptionsForDispatch = useMemo(() => { if (selectedProvider === "codex") { const codexOptions = { @@ -654,8 +654,8 @@ export default function ChatView({ threadId }: ChatViewProps) { }; return Object.keys(codexOptions).length > 0 ? { codex: codexOptions } : undefined; } - if (selectedProvider === "claudeCode" && supportsClaudeCodeEffort && selectedClaudeCodeEffort) { - return { claudeCode: { effort: selectedClaudeCodeEffort } }; + if (selectedProvider === "claudeAgent" && supportsClaudeCodeEffort && selectedClaudeCodeEffort) { + return { claudeAgent: { effort: selectedClaudeCodeEffort } }; } return undefined; }, [ @@ -3908,12 +3908,12 @@ export default function ChatView({ threadId }: ChatViewProps) { onThinkingModeChange={onCursorThinkingModeChange} /> )} - {selectedProvider === "claudeCode" && + {selectedProvider === "claudeAgent" && supportsClaudeCodeEffort && selectedClaudeCodeEffort != null && ( - )} @@ -3972,7 +3972,7 @@ export default function ChatView({ threadId }: ChatViewProps) { onFastModeChange={onCodexFastModeChange} /> - ) : selectedProvider === "claudeCode" && + ) : selectedProvider === "claudeAgent" && supportsClaudeCodeEffort && selectedClaudeCodeEffort != null ? ( <> @@ -3980,9 +3980,9 @@ export default function ChatView({ threadId }: ChatViewProps) { orientation="vertical" className="mx-0.5 hidden h-4 sm:block" /> - diff --git a/apps/web/src/components/ProviderLogo.tsx b/apps/web/src/components/ProviderLogo.tsx index ec6d63dd4b..a3bb15259c 100644 --- a/apps/web/src/components/ProviderLogo.tsx +++ b/apps/web/src/components/ProviderLogo.tsx @@ -18,7 +18,7 @@ import { const PROVIDER_ICON_BY_PROVIDER: Record = { codex: OpenAI, copilot: GitHubIcon, - claudeCode: ClaudeAI, + claudeAgent: ClaudeAI, cursor: CursorIcon, opencode: OpenCodeIcon, geminiCli: Gemini, diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index c241b82ff2..de3120db81 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -516,7 +516,7 @@ const USAGE_PROVIDERS: ReadonlyArray<{ provider: ProviderKind; label: string }> { provider: "copilot", label: "Copilot" }, { provider: "codex", label: "Codex" }, { provider: "cursor", label: "Cursor" }, - { provider: "claudeCode", label: "Claude Code" }, + { provider: "claudeAgent", label: "Claude Code" }, { provider: "geminiCli", label: "Gemini" }, { provider: "amp", label: "Amp" }, ]; @@ -547,7 +547,7 @@ function ProviderUsageSection() { const copilotUsage = useProviderUsage("copilot"); const codexUsage = useProviderUsage("codex"); const cursorUsage = useProviderUsage("cursor"); - const claudeUsage = useProviderUsage("claudeCode"); + const claudeUsage = useProviderUsage("claudeAgent"); const geminiUsage = useProviderUsage("geminiCli"); const ampUsage = useProviderUsage("amp"); @@ -555,7 +555,7 @@ function ProviderUsageSection() { copilot: copilotUsage.data, codex: codexUsage.data, cursor: cursorUsage.data, - claudeCode: claudeUsage.data, + claudeAgent: claudeUsage.data, geminiCli: geminiUsage.data, amp: ampUsage.data, }; @@ -617,7 +617,7 @@ function ProviderUsageSection() { } // Session usage (no quota) — show token/cost summary if ( - provider !== "claudeCode" && + provider !== "claudeAgent" && data?.sessionUsage && (data.sessionUsage.totalTokens || data.sessionUsage.totalCostUsd) ) { diff --git a/apps/web/src/components/chat/ClaudeCodeTraitsPicker.tsx b/apps/web/src/components/chat/ClaudeTraitsPicker.tsx similarity index 93% rename from apps/web/src/components/chat/ClaudeCodeTraitsPicker.tsx rename to apps/web/src/components/chat/ClaudeTraitsPicker.tsx index 41f917294a..293f87173b 100644 --- a/apps/web/src/components/chat/ClaudeCodeTraitsPicker.tsx +++ b/apps/web/src/components/chat/ClaudeTraitsPicker.tsx @@ -12,13 +12,13 @@ export const CLAUDE_CODE_EFFORT_LABEL: Record = { max: "Max", }; -export const ClaudeCodeTraitsPicker = memo(function ClaudeCodeTraitsPicker(props: { +export const ClaudeTraitsPicker = memo(function ClaudeTraitsPicker(props: { effort: ClaudeCodeEffort; options: ReadonlyArray; onEffortChange: (effort: ClaudeCodeEffort) => void; }) { const [isMenuOpen, setIsMenuOpen] = useState(false); - const defaultEffort = getDefaultClaudeCodeEffort("claudeCode"); + const defaultEffort = getDefaultClaudeCodeEffort("claudeAgent"); return ( = { codex: OpenAI, copilot: GitHubIcon, - claudeCode: ClaudeAI, + claudeAgent: ClaudeAI, cursor: CursorIcon, opencode: OpenCodeIcon, geminiCli: Gemini, @@ -281,7 +281,7 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: { aria-hidden="true" className={cn( "size-4 shrink-0", - props.provider === "claudeCode" ? "" : "text-muted-foreground/70", + props.provider === "claudeAgent" ? "" : "text-muted-foreground/70", )} /> {selectedModelLabel} @@ -438,7 +438,7 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: { aria-hidden="true" className={cn( "size-4 shrink-0 opacity-80", - option.value === "claudeCode" ? "" : "text-muted-foreground/85", + option.value === "claudeAgent" ? "" : "text-muted-foreground/85", )} /> {option.label} diff --git a/apps/web/src/composerDraftStore.ts b/apps/web/src/composerDraftStore.ts index 0e82d3fa08..45afa7d183 100644 --- a/apps/web/src/composerDraftStore.ts +++ b/apps/web/src/composerDraftStore.ts @@ -99,7 +99,7 @@ interface PersistedComposerThreadDraftState { interactionMode?: ProviderInteractionMode | null; effort?: CodexReasoningEffort | null; codexFastMode?: boolean | null; - claudeCodeEffort?: ClaudeCodeEffort | null; + claudeAgentEffort?: ClaudeCodeEffort | null; serviceTier?: string | null; } @@ -131,7 +131,7 @@ interface ComposerThreadDraftState { interactionMode: ProviderInteractionMode | null; effort: CodexReasoningEffort | null; codexFastMode: boolean; - claudeCodeEffort: ClaudeCodeEffort | null; + claudeAgentEffort: ClaudeCodeEffort | null; } export interface DraftThreadState { @@ -241,7 +241,7 @@ const EMPTY_THREAD_DRAFT = Object.freeze({ interactionMode: null, effort: null, codexFastMode: false, - claudeCodeEffort: null, + claudeAgentEffort: null, }) as ComposerThreadDraftState; const REASONING_EFFORT_VALUES = new Set( @@ -249,7 +249,7 @@ const REASONING_EFFORT_VALUES = new Set( ); const CLAUDE_CODE_EFFORT_VALUES = new Set( - CLAUDE_CODE_EFFORT_OPTIONS_BY_PROVIDER.claudeCode, + CLAUDE_CODE_EFFORT_OPTIONS_BY_PROVIDER.claudeAgent, ); function createEmptyThreadDraft(): ComposerThreadDraftState { @@ -265,7 +265,7 @@ function createEmptyThreadDraft(): ComposerThreadDraftState { interactionMode: null, effort: null, codexFastMode: false, - claudeCodeEffort: null, + claudeAgentEffort: null, }; } @@ -338,14 +338,14 @@ function shouldRemoveDraft(draft: ComposerThreadDraftState): boolean { draft.interactionMode === null && draft.effort === null && draft.codexFastMode === false && - draft.claudeCodeEffort === null + draft.claudeAgentEffort === null ); } function normalizeProviderKind(value: unknown): ProviderKind | null { return value === "codex" || value === "copilot" || - value === "claudeCode" || + value === "claudeAgent" || value === "cursor" || value === "opencode" || value === "geminiCli" || @@ -584,12 +584,12 @@ function normalizePersistedComposerDraftState(value: unknown): PersistedComposer const codexFastMode = draftCandidate.codexFastMode === true || (typeof draftCandidate.serviceTier === "string" && draftCandidate.serviceTier === "fast"); - const claudeCodeEffortCandidate = - typeof draftCandidate.claudeCodeEffort === "string" ? draftCandidate.claudeCodeEffort : null; - const claudeCodeEffort = - claudeCodeEffortCandidate && - CLAUDE_CODE_EFFORT_VALUES.has(claudeCodeEffortCandidate as ClaudeCodeEffort) - ? (claudeCodeEffortCandidate as ClaudeCodeEffort) + const claudeAgentEffortCandidate = + typeof draftCandidate.claudeAgentEffort === "string" ? draftCandidate.claudeAgentEffort : null; + const claudeAgentEffort = + claudeAgentEffortCandidate && + CLAUDE_CODE_EFFORT_VALUES.has(claudeAgentEffortCandidate as ClaudeCodeEffort) + ? (claudeAgentEffortCandidate as ClaudeCodeEffort) : null; const prompt = ensureInlineTerminalContextPlaceholders( promptCandidate, @@ -605,7 +605,7 @@ function normalizePersistedComposerDraftState(value: unknown): PersistedComposer !interactionMode && !effort && !codexFastMode && - !claudeCodeEffort + !claudeAgentEffort ) { continue; } @@ -619,7 +619,7 @@ function normalizePersistedComposerDraftState(value: unknown): PersistedComposer ...(interactionMode ? { interactionMode } : {}), ...(effort ? { effort } : {}), ...(codexFastMode ? { codexFastMode } : {}), - ...(claudeCodeEffort ? { claudeCodeEffort } : {}), + ...(claudeAgentEffort ? { claudeAgentEffort } : {}), }; } return { @@ -731,7 +731,7 @@ function toHydratedThreadDraft( interactionMode: persistedDraft.interactionMode ?? null, effort: persistedDraft.effort ?? null, codexFastMode: persistedDraft.codexFastMode === true, - claudeCodeEffort: persistedDraft.claudeCodeEffort ?? null, + claudeAgentEffort: persistedDraft.claudeAgentEffort ?? null, }; } @@ -1198,7 +1198,7 @@ export const useComposerDraftStore = create()( const nextEffort = effort && CLAUDE_CODE_EFFORT_VALUES.has(effort) && - effort !== DEFAULT_CLAUDE_CODE_EFFORT_BY_PROVIDER.claudeCode + effort !== DEFAULT_CLAUDE_CODE_EFFORT_BY_PROVIDER.claudeAgent ? effort : null; set((state) => { @@ -1207,12 +1207,12 @@ export const useComposerDraftStore = create()( return state; } const base = existing ?? createEmptyThreadDraft(); - if (base.claudeCodeEffort === nextEffort) { + if (base.claudeAgentEffort === nextEffort) { return state; } const nextDraft: ComposerThreadDraftState = { ...base, - claudeCodeEffort: nextEffort, + claudeAgentEffort: nextEffort, }; const nextDraftsByThreadId = { ...state.draftsByThreadId }; if (shouldRemoveDraft(nextDraft)) { @@ -1581,7 +1581,7 @@ export const useComposerDraftStore = create()( draft.interactionMode === null && draft.effort === null && draft.codexFastMode === false && - draft.claudeCodeEffort === null + draft.claudeAgentEffort === null ) { continue; } @@ -1618,8 +1618,8 @@ export const useComposerDraftStore = create()( if (draft.codexFastMode) { persistedDraft.codexFastMode = true; } - if (draft.claudeCodeEffort) { - persistedDraft.claudeCodeEffort = draft.claudeCodeEffort; + if (draft.claudeAgentEffort) { + persistedDraft.claudeAgentEffort = draft.claudeAgentEffort; } persistedDraftsByThreadId[threadId as ThreadId] = persistedDraft; } diff --git a/apps/web/src/lib/threadDraftDefaults.test.ts b/apps/web/src/lib/threadDraftDefaults.test.ts index 49c1a273e5..c7a003471e 100644 --- a/apps/web/src/lib/threadDraftDefaults.test.ts +++ b/apps/web/src/lib/threadDraftDefaults.test.ts @@ -53,7 +53,7 @@ describe("resolveDraftThreadDefaults", () => { makeThread({ id: ThreadId.makeUnsafe("thread-other-project"), projectId: ProjectId.makeUnsafe("project-2"), - provider: "claudeCode", + provider: "claudeAgent", model: "claude-sonnet-4-6", createdAt: "2026-03-09T10:00:00.000Z", }), @@ -80,7 +80,7 @@ describe("resolveDraftThreadDefaults", () => { makeThread({ id: ThreadId.makeUnsafe("thread-newest"), projectId: ProjectId.makeUnsafe("project-2"), - provider: "claudeCode", + provider: "claudeAgent", model: "claude-sonnet-4-6", createdAt: "2026-03-09T10:00:00.000Z", }), @@ -90,7 +90,7 @@ describe("resolveDraftThreadDefaults", () => { }); expect(defaults).toEqual({ - provider: "claudeCode", + provider: "claudeAgent", model: "claude-sonnet-4-6", }); }); @@ -108,7 +108,7 @@ describe("resolveDraftThreadDefaults", () => { }), makeThread({ id: ThreadId.makeUnsafe("thread-newer"), - provider: "claudeCode", + provider: "claudeAgent", model: "claude-sonnet-4-6", createdAt: "2026-03-08T10:00:00.000Z", }), @@ -131,7 +131,7 @@ describe("resolveDraftThreadDefaults", () => { }); expect(defaults).toEqual({ - provider: "claudeCode", + provider: "claudeAgent", model: "claude-sonnet-4-6", }); }); diff --git a/apps/web/src/lib/threadProvider.test.ts b/apps/web/src/lib/threadProvider.test.ts index 2737379da2..eb7f59a236 100644 --- a/apps/web/src/lib/threadProvider.test.ts +++ b/apps/web/src/lib/threadProvider.test.ts @@ -6,9 +6,9 @@ describe("inferProviderForThreadModel", () => { expect( inferProviderForThreadModel({ model: "gpt-5.3-codex", - sessionProviderName: "claudeCode", + sessionProviderName: "claudeAgent", }), - ).toBe("claudeCode"); + ).toBe("claudeAgent"); }); it("infers cursor threads from composer models", () => { diff --git a/apps/web/src/lib/threadProvider.ts b/apps/web/src/lib/threadProvider.ts index 3689401c4e..fdf019353f 100644 --- a/apps/web/src/lib/threadProvider.ts +++ b/apps/web/src/lib/threadProvider.ts @@ -5,7 +5,7 @@ import type { Thread } from "../types"; const PROVIDER_KINDS = [ "codex", "copilot", - "claudeCode", + "claudeAgent", "cursor", "opencode", "geminiCli", @@ -20,7 +20,7 @@ const COPILOT_MODEL_SLUGS = new Set( getModelOptions("copilot").map((option) => option.slug), ); const CLAUDE_MODEL_SLUGS = new Set( - getModelOptions("claudeCode").map((option) => option.slug), + getModelOptions("claudeAgent").map((option) => option.slug), ); const CURSOR_MODEL_SLUGS = new Set(getModelOptions("cursor").map((option) => option.slug)); const OPENCODE_MODEL_SLUGS = new Set( @@ -89,9 +89,9 @@ export function inferProviderForThreadModel(input: { return "cursor"; } - const normalizedClaude = normalizeModelSlug(input.model, "claudeCode"); + const normalizedClaude = normalizeModelSlug(input.model, "claudeAgent"); if (normalizedClaude && CLAUDE_MODEL_SLUGS.has(normalizedClaude)) { - return "claudeCode"; + return "claudeAgent"; } const normalizedCodex = normalizeModelSlug(input.model, "codex"); @@ -117,7 +117,7 @@ export function inferProviderForThreadModel(input: { return "cursor"; } - return input.model.trim().startsWith("claude-") ? "claudeCode" : "codex"; + return input.model.trim().startsWith("claude-") ? "claudeAgent" : "codex"; } export function resolveThreadProvider(thread: Pick): ProviderKind { diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index 3be2df7320..883204b74d 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -41,7 +41,7 @@ export const Route = createRootRouteWithContext<{ const PROVIDER_KINDS = [ "codex", "copilot", - "claudeCode", + "claudeAgent", "cursor", "opencode", "geminiCli", diff --git a/apps/web/src/routes/_chat.settings.tsx b/apps/web/src/routes/_chat.settings.tsx index 01107dae57..dd0aa3cfda 100644 --- a/apps/web/src/routes/_chat.settings.tsx +++ b/apps/web/src/routes/_chat.settings.tsx @@ -76,7 +76,7 @@ const MODEL_PROVIDER_SETTINGS: Array<{ example: "gpt-5.1-codex-max", }, { - provider: "claudeCode", + provider: "claudeAgent", title: "Claude Code", description: "Save additional Claude model slugs for the picker and `/model` command.", placeholder: "your-claude-model-slug", @@ -231,7 +231,7 @@ function SettingsRouteView() { >({ codex: "", copilot: "", - claudeCode: "", + claudeAgent: "", cursor: "", opencode: "", geminiCli: "", diff --git a/apps/web/src/session-logic.test.ts b/apps/web/src/session-logic.test.ts index fbd0104332..eab66866f1 100644 --- a/apps/web/src/session-logic.test.ts +++ b/apps/web/src/session-logic.test.ts @@ -772,7 +772,7 @@ describe("deriveActiveWorkStartedAt", () => { describe("PROVIDER_OPTIONS", () => { it("advertises all currently integrated providers", () => { const copilot = PROVIDER_OPTIONS.find((option) => option.value === "copilot"); - const claude = PROVIDER_OPTIONS.find((option) => option.value === "claudeCode"); + const claude = PROVIDER_OPTIONS.find((option) => option.value === "claudeAgent"); const cursor = PROVIDER_OPTIONS.find((option) => option.value === "cursor"); const opencode = PROVIDER_OPTIONS.find((option) => option.value === "opencode"); const geminiCli = PROVIDER_OPTIONS.find((option) => option.value === "geminiCli"); @@ -780,7 +780,7 @@ describe("PROVIDER_OPTIONS", () => { expect(PROVIDER_OPTIONS).toEqual([ { value: "codex", label: "Codex", available: true }, { value: "copilot", label: "GitHub Copilot", available: true }, - { value: "claudeCode", label: "Claude Code", available: true }, + { value: "claudeAgent", label: "Claude Code", available: true }, { value: "cursor", label: "Cursor Agent", available: true }, { value: "opencode", label: "OpenCode", available: true }, { value: "geminiCli", label: "Gemini CLI", available: true }, @@ -793,7 +793,7 @@ describe("PROVIDER_OPTIONS", () => { available: true, }); expect(claude).toEqual({ - value: "claudeCode", + value: "claudeAgent", label: "Claude Code", available: true, }); diff --git a/apps/web/src/session-logic.ts b/apps/web/src/session-logic.ts index 50cc33e5d2..37683df5cc 100644 --- a/apps/web/src/session-logic.ts +++ b/apps/web/src/session-logic.ts @@ -18,7 +18,7 @@ import type { TurnDiffSummary, } from "./types"; -export type ProviderPickerKind = ProviderKind | "claudeCode" | "cursor"; +export type ProviderPickerKind = ProviderKind | "claudeAgent" | "cursor"; export const PROVIDER_OPTIONS: Array<{ value: ProviderPickerKind; @@ -27,7 +27,7 @@ export const PROVIDER_OPTIONS: Array<{ }> = [ { value: "codex", label: "Codex", available: true }, { value: "copilot", label: "GitHub Copilot", available: true }, - { value: "claudeCode", label: "Claude Code", available: true }, + { value: "claudeAgent", label: "Claude Code", available: true }, { value: "cursor", label: "Cursor Agent", available: true }, { value: "opencode", label: "OpenCode", available: true }, { value: "geminiCli", label: "Gemini CLI", available: true }, diff --git a/apps/web/src/store.test.ts b/apps/web/src/store.test.ts index 77e822b97c..8c3816d231 100644 --- a/apps/web/src/store.test.ts +++ b/apps/web/src/store.test.ts @@ -199,7 +199,7 @@ describe("store read model sync", () => { expect(next.threads[0]?.model).toBe("claude-opus-4-6"); }); - it("resolves claude aliases when session provider is claudeCode", () => { + it("resolves claude aliases when session provider is claudeAgent", () => { const initialState = makeState(makeThread()); const readModel = makeReadModel( makeReadModelThread({ @@ -207,7 +207,7 @@ describe("store read model sync", () => { session: { threadId: ThreadId.makeUnsafe("thread-1"), status: "ready", - providerName: "claudeCode", + providerName: "claudeAgent", runtimeMode: "approval-required", activeTurnId: null, lastError: null, @@ -247,10 +247,10 @@ describe("store read model sync", () => { it("preserves the previous provider when a thread session closes", () => { const initialState = makeState( makeThread({ - provider: "claudeCode", + provider: "claudeAgent", model: "claude-sonnet-4-6", session: { - provider: "claudeCode", + provider: "claudeAgent", status: "ready", orchestrationStatus: "ready", createdAt: "2026-02-27T00:00:00.000Z", @@ -267,7 +267,7 @@ describe("store read model sync", () => { const next = syncServerReadModel(initialState, readModel); - expect(next.threads[0]?.provider).toBe("claudeCode"); + expect(next.threads[0]?.provider).toBe("claudeAgent"); expect(next.threads[0]?.model).toBe("claude-sonnet-4-6"); expect(next.threads[0]?.session).toBeNull(); }); diff --git a/packages/contracts/src/model.ts b/packages/contracts/src/model.ts index 60b46f8f62..78a67a552b 100644 --- a/packages/contracts/src/model.ts +++ b/packages/contracts/src/model.ts @@ -30,11 +30,11 @@ export const OpencodeModelOptions = Schema.Struct({ }); export type OpencodeModelOptions = typeof OpencodeModelOptions.Type; -export const ClaudeCodeModelOptions = Schema.Struct({ +export const ClaudeModelOptions = Schema.Struct({ thinking: Schema.optional(Schema.Boolean), effort: Schema.optional(Schema.Literals(CLAUDE_CODE_EFFORT_OPTIONS)), }); -export type ClaudeCodeModelOptions = typeof ClaudeCodeModelOptions.Type; +export type ClaudeModelOptions = typeof ClaudeModelOptions.Type; export const CursorModelOptions = Schema.Struct({ reasoning: Schema.optional(Schema.Literals(CURSOR_REASONING_OPTIONS)), @@ -65,7 +65,7 @@ export type KiloModelOptions = typeof KiloModelOptions.Type; export const ProviderModelOptions = Schema.Struct({ codex: Schema.optional(CodexModelOptions), copilot: Schema.optional(CopilotModelOptions), - claudeCode: Schema.optional(ClaudeCodeModelOptions), + claudeAgent: Schema.optional(ClaudeModelOptions), cursor: Schema.optional(CursorModelOptions), opencode: Schema.optional(OpencodeModelOptions), geminiCli: Schema.optional(GeminiCliModelOptions), @@ -146,7 +146,7 @@ export const MODEL_OPTIONS_BY_PROVIDER = { { slug: "gpt-5-mini", name: "GPT-5 mini" }, { slug: "gpt-4.1", name: "GPT-4.1" }, ], - claudeCode: [ + claudeAgent: [ { slug: "claude-opus-4-6", name: "Claude Opus 4.6" }, { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, { slug: "claude-haiku-4-5", name: "Claude Haiku 4.5" }, @@ -223,7 +223,7 @@ export type CursorModelSlug = (typeof MODEL_OPTIONS_BY_PROVIDER)["cursor"][numbe export const DEFAULT_MODEL_BY_PROVIDER = { codex: "gpt-5.4", copilot: "claude-sonnet-4.6", - claudeCode: "claude-sonnet-4-6", + claudeAgent: "claude-sonnet-4-6", cursor: "opus-4.6-thinking", opencode: "gpt-5", geminiCli: "gemini-2.5-pro", @@ -263,7 +263,7 @@ export const MODEL_SLUG_ALIASES_BY_PROVIDER: Record { it("accepts claude runtime knobs", () => { const parsed = decodeProviderSessionStartInput({ threadId: "thread-1", - provider: "claudeCode", + provider: "claudeAgent", cwd: "/tmp/workspace", model: "claude-sonnet-4-6", providerOptions: { - claudeCode: { + claudeAgent: { binaryPath: "/usr/local/bin/claude", permissionMode: "plan", maxThinkingTokens: 12_000, @@ -78,10 +78,10 @@ describe("ProviderSessionStartInput", () => { }, runtimeMode: "full-access", }); - expect(parsed.provider).toBe("claudeCode"); - expect(parsed.providerOptions?.claudeCode?.binaryPath).toBe("/usr/local/bin/claude"); - expect(parsed.providerOptions?.claudeCode?.permissionMode).toBe("plan"); - expect(parsed.providerOptions?.claudeCode?.maxThinkingTokens).toBe(12_000); + expect(parsed.provider).toBe("claudeAgent"); + expect(parsed.providerOptions?.claudeAgent?.binaryPath).toBe("/usr/local/bin/claude"); + expect(parsed.providerOptions?.claudeAgent?.permissionMode).toBe("plan"); + expect(parsed.providerOptions?.claudeAgent?.maxThinkingTokens).toBe(12_000); expect(parsed.runtimeMode).toBe("full-access"); }); diff --git a/packages/contracts/src/providerRuntime.test.ts b/packages/contracts/src/providerRuntime.test.ts index 6daf679fe2..b049830605 100644 --- a/packages/contracts/src/providerRuntime.test.ts +++ b/packages/contracts/src/providerRuntime.test.ts @@ -10,7 +10,7 @@ describe("ProviderRuntimeEvent", () => { const parsed = decodeRuntimeEvent({ type: "turn.plan.updated", eventId: "event-1", - provider: "claudeCode", + provider: "claudeAgent", sessionId: "runtime-session-1", createdAt: "2026-02-28T00:00:00.000Z", threadId: "thread-1", diff --git a/packages/shared/src/model.test.ts b/packages/shared/src/model.test.ts index 9587045643..49e97627a6 100644 --- a/packages/shared/src/model.test.ts +++ b/packages/shared/src/model.test.ts @@ -43,9 +43,9 @@ describe("normalizeModelSlug", () => { }); it("uses provider-specific aliases", () => { - expect(normalizeModelSlug("sonnet", "claudeCode")).toBe("claude-sonnet-4-6"); - expect(normalizeModelSlug("opus-4.6", "claudeCode")).toBe("claude-opus-4-6"); - expect(normalizeModelSlug("claude-haiku-4-5-20251001", "claudeCode")).toBe("claude-haiku-4-5"); + expect(normalizeModelSlug("sonnet", "claudeAgent")).toBe("claude-sonnet-4-6"); + expect(normalizeModelSlug("opus-4.6", "claudeAgent")).toBe("claude-opus-4-6"); + expect(normalizeModelSlug("claude-haiku-4-5-20251001", "claudeAgent")).toBe("claude-haiku-4-5"); expect(normalizeModelSlug("composer", "cursor")).toBe("composer-1.5"); expect(normalizeModelSlug("gpt-5.3-codex-spark", "cursor")).toBe("gpt-5.3-codex-spark-preview"); expect(normalizeModelSlug("gpt-5.4", "cursor")).toBe("gpt-5.4-medium"); @@ -79,12 +79,12 @@ describe("resolveModelSlug", () => { }); it("supports provider-aware resolution", () => { - expect(resolveModelSlugForProvider("claudeCode", undefined)).toBe( - DEFAULT_MODEL_BY_PROVIDER.claudeCode, + expect(resolveModelSlugForProvider("claudeAgent", undefined)).toBe( + DEFAULT_MODEL_BY_PROVIDER.claudeAgent, ); - expect(resolveModelSlugForProvider("claudeCode", "sonnet")).toBe("claude-sonnet-4-6"); - expect(resolveModelSlugForProvider("claudeCode", "gpt-5.3-codex")).toBe( - DEFAULT_MODEL_BY_PROVIDER.claudeCode, + expect(resolveModelSlugForProvider("claudeAgent", "sonnet")).toBe("claude-sonnet-4-6"); + expect(resolveModelSlugForProvider("claudeAgent", "gpt-5.3-codex")).toBe( + DEFAULT_MODEL_BY_PROVIDER.claudeAgent, ); expect(resolveModelSlugForProvider("cursor", undefined)).toBe(DEFAULT_MODEL_BY_PROVIDER.cursor); expect(resolveModelSlugForProvider("cursor", "composer")).toBe("composer-1.5"); @@ -99,7 +99,7 @@ describe("resolveModelSlug", () => { it("keeps codex defaults for backward compatibility", () => { expect(getDefaultModel()).toBe(DEFAULT_MODEL); expect(getModelOptions()).toEqual(MODEL_OPTIONS); - expect(getModelOptions("claudeCode")).toEqual(MODEL_OPTIONS_BY_PROVIDER.claudeCode); + expect(getModelOptions("claudeAgent")).toEqual(MODEL_OPTIONS_BY_PROVIDER.claudeAgent); expect(getModelOptions("cursor")).toEqual(MODEL_OPTIONS_BY_PROVIDER.cursor); expect(getCursorModelFamilyOptions()).toEqual(CURSOR_MODEL_FAMILY_OPTIONS); }); @@ -190,8 +190,8 @@ describe("getReasoningEffortOptions", () => { expect(getReasoningEffortOptions("codex")).toEqual(REASONING_EFFORT_OPTIONS_BY_PROVIDER.codex); }); - it("returns no reasoning options for claudeCode", () => { - expect(getReasoningEffortOptions("claudeCode")).toEqual([]); + it("returns no reasoning options for claudeAgent", () => { + expect(getReasoningEffortOptions("claudeAgent")).toEqual([]); }); it("returns no reasoning options for cursor", () => { @@ -202,8 +202,8 @@ describe("getReasoningEffortOptions", () => { describe("getDefaultReasoningEffort", () => { it("returns provider-scoped defaults", () => { expect(getDefaultReasoningEffort("codex")).toBe(DEFAULT_REASONING_EFFORT_BY_PROVIDER.codex); - expect(getDefaultReasoningEffort("claudeCode")).toBe( - DEFAULT_REASONING_EFFORT_BY_PROVIDER.claudeCode, + expect(getDefaultReasoningEffort("claudeAgent")).toBe( + DEFAULT_REASONING_EFFORT_BY_PROVIDER.claudeAgent, ); expect(getDefaultReasoningEffort("cursor")).toBe(DEFAULT_REASONING_EFFORT_BY_PROVIDER.cursor); }); diff --git a/packages/shared/src/model.ts b/packages/shared/src/model.ts index 7ad63ca16d..49cf928de0 100644 --- a/packages/shared/src/model.ts +++ b/packages/shared/src/model.ts @@ -222,7 +222,7 @@ const CURSOR_MODEL_CAPABILITY_BY_FAMILY: Record> = { codex: new Set(MODEL_OPTIONS_BY_PROVIDER.codex.map((option) => option.slug)), copilot: new Set(MODEL_OPTIONS_BY_PROVIDER.copilot.map((option) => option.slug)), - claudeCode: new Set(MODEL_OPTIONS_BY_PROVIDER.claudeCode.map((option) => option.slug)), + claudeAgent: new Set(MODEL_OPTIONS_BY_PROVIDER.claudeAgent.map((option) => option.slug)), cursor: new Set(MODEL_OPTIONS_BY_PROVIDER.cursor.map((option) => option.slug)), opencode: new Set(MODEL_OPTIONS_BY_PROVIDER.opencode.map((option) => option.slug)), kilo: new Set(MODEL_OPTIONS_BY_PROVIDER.kilo.map((option) => option.slug)), @@ -443,15 +443,15 @@ export function getDefaultReasoningEffort( } export function getClaudeCodeEffortOptions( - provider: ProviderKind = "claudeCode", + provider: ProviderKind = "claudeAgent", ): ReadonlyArray { return CLAUDE_CODE_EFFORT_OPTIONS_BY_PROVIDER[provider]; } -export function getDefaultClaudeCodeEffort(provider: "claudeCode"): ClaudeCodeEffort; +export function getDefaultClaudeCodeEffort(provider: "claudeAgent"): ClaudeCodeEffort; export function getDefaultClaudeCodeEffort(provider: ProviderKind): ClaudeCodeEffort | null; export function getDefaultClaudeCodeEffort( - provider: ProviderKind = "claudeCode", + provider: ProviderKind = "claudeAgent", ): ClaudeCodeEffort | null { return DEFAULT_CLAUDE_CODE_EFFORT_BY_PROVIDER[provider]; } From 1fb7a2698b8f8413a6c103c778fa271b8b08577e Mon Sep 17 00:00:00 2001 From: Utkarsh Patil <73941998+UtkarshUsername@users.noreply.github.com> Date: Wed, 18 Mar 2026 22:16:09 +0530 Subject: [PATCH 02/15] fix: implement button overflow (#1193) --- apps/web/src/components/ChatView.tsx | 2 +- .../src/components/chat/CodexTraitsPicker.tsx | 25 ++++++++++++------- .../components/chat/ProviderModelPicker.tsx | 13 ++++++---- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 97155717f4..2002597fae 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -3881,7 +3881,7 @@ export default function ChatView({ threadId }: ChatViewProps) { "flex min-w-0 flex-1 items-center", isComposerFooterCompact ? "gap-1 overflow-hidden" - : "gap-1 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden sm:min-w-max sm:overflow-visible", + : "gap-1 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", )} > {/* Provider/model picker */} diff --git a/apps/web/src/components/chat/CodexTraitsPicker.tsx b/apps/web/src/components/chat/CodexTraitsPicker.tsx index 6c72f497ba..a8a65250ed 100644 --- a/apps/web/src/components/chat/CodexTraitsPicker.tsx +++ b/apps/web/src/components/chat/CodexTraitsPicker.tsx @@ -28,12 +28,7 @@ export const CodexTraitsPicker = memo(function CodexTraitsPicker(props: { high: "High", xhigh: "Extra High", }; - const triggerLabel = [ - reasoningLabelByOption[props.effort], - ...(props.fastModeEnabled ? ["Fast"] : []), - ] - .filter(Boolean) - .join(" · "); + const effortLabel = reasoningLabelByOption[props.effort]; return ( } > - {triggerLabel} -