History

fix(claude): avoid resetting the Claude model on every turn (#1466)

Harshit Agarwal committed 7 months ago

Commit fb726071 parent d8a485e2 files · +92 −4Browse files

Unified · Split

2 files
  1. apps/server/src/provider/Layers/ClaudeAdapter.test.ts +79 −0
  2. apps/server/src/provider/Layers/ClaudeAdapter.ts +13 −4
apps/server/src/provider/Layers/ClaudeAdapter.test.ts+79−0
@@ -2384,6 +2384,85 @@ describe("ClaudeAdapterLive", () => { · 2383 unmodified lines
23842384 );
23852385 });
23862386
2387+ it.effect(
2388+ "does not re-set the Claude model when the session already uses the same effective API model",
2389+ () => {
2390+ const harness = makeHarness();
2391+ return Effect.gen(function* () {
2392+ const adapter = yield* ClaudeAdapter;
2393+ const modelSelection = {
2394+ provider: "claudeAgent" as const,
2395+ model: "claude-opus-4-6",
2396+ };
2397+
2398+ const session = yield* adapter.startSession({
2399+ threadId: THREAD_ID,
2400+ provider: "claudeAgent",
2401+ modelSelection,
2402+ runtimeMode: "full-access",
2403+ });
2404+
2405+ yield* adapter.sendTurn({
2406+ threadId: session.threadId,
2407+ input: "hello",
2408+ modelSelection,
2409+ attachments: [],
2410+ });
2411+ yield* adapter.sendTurn({
2412+ threadId: session.threadId,
2413+ input: "hello again",
2414+ modelSelection,
2415+ attachments: [],
2416+ });
2417+
2418+ assert.deepEqual(harness.query.setModelCalls, []);
2419+ }).pipe(
2420+ Effect.provideService(Random.Random, makeDeterministicRandomService()),
2421+ Effect.provide(harness.layer),
2422+ );
2423+ },
2424+ );
2425+
2426+ it.effect("re-sets the Claude model when the effective API model changes", () => {
2427+ const harness = makeHarness();
2428+ return Effect.gen(function* () {
2429+ const adapter = yield* ClaudeAdapter;
2430+
2431+ const session = yield* adapter.startSession({
2432+ threadId: THREAD_ID,
2433+ provider: "claudeAgent",
2434+ runtimeMode: "full-access",
2435+ });
2436+
2437+ yield* adapter.sendTurn({
2438+ threadId: session.threadId,
2439+ input: "hello",
2440+ modelSelection: {
2441+ provider: "claudeAgent",
2442+ model: "claude-opus-4-6",
2443+ options: {
2444+ contextWindow: "1m",
2445+ },
2446+ },
2447+ attachments: [],
2448+ });
2449+ yield* adapter.sendTurn({
2450+ threadId: session.threadId,
2451+ input: "hello again",
2452+ modelSelection: {
2453+ provider: "claudeAgent",
2454+ model: "claude-opus-4-6",
2455+ },
2456+ attachments: [],
2457+ });
2458+
2459+ assert.deepEqual(harness.query.setModelCalls, ["claude-opus-4-6[1m]", "claude-opus-4-6"]);
2460+ }).pipe(
2461+ Effect.provideService(Random.Random, makeDeterministicRandomService()),
2462+ Effect.provide(harness.layer),
2463+ );
2464+ });
2465+
23872466 it.effect("sets plan permission mode on sendTurn when interactionMode is plan", () => {
23882467 const harness = makeHarness();
23892468 return Effect.gen(function* () {
apps/server/src/provider/Layers/ClaudeAdapter.ts+13−4
@@ -148,6 +148,7 @@ interface ClaudeSessionContext { · 147 unmodified lines
148148 streamFiber: Fiber.Fiber<void, Error> | undefined;
149149 readonly startedAt: string;
150150 readonly basePermissionMode: PermissionMode | undefined;
151+ currentApiModelId: string | undefined;
151152 resumeSessionId: string | undefined;
152153 readonly pendingApprovals: Map<ApprovalRequestId, PendingApproval>;
153154 readonly pendingUserInputs: Map<ApprovalRequestId, PendingUserInput>;
@@ -2809,6 +2810,7 @@ function makeClaudeAdapter(options?: ClaudeAdapterLiveOptions) { · 2655 unmodified lines
28092810 streamFiber: undefined,
28102811 startedAt,
28112812 basePermissionMode: permissionMode,
2813+ currentApiModelId: apiModelId,
28122814 resumeSessionId: sessionId,
28132815 pendingApprovals,
28142816 pendingUserInputs,
@@ -2898,10 +2900,17 @@ function makeClaudeAdapter(options?: ClaudeAdapterLiveOptions) { · 83 unmodified lines
28982900
28992901 if (modelSelection?.model) {
29002902 const apiModelId = resolveApiModelId(modelSelection);
2901− yield* Effect.tryPromise({
2902− try: () => context.query.setModel(apiModelId),
2903− catch: (cause) => toRequestError(input.threadId, "turn/setModel", cause),
2904− });
2903+ if (context.currentApiModelId !== apiModelId) {
2904+ yield* Effect.tryPromise({
2905+ try: () => context.query.setModel(apiModelId),
2906+ catch: (cause) => toRequestError(input.threadId, "turn/setModel", cause),
2907+ });
2908+ context.currentApiModelId = apiModelId;
2909+ }
2910+ context.session = {
2911+ ...context.session,
2912+ model: modelSelection.model,
2913+ };
29052914 }
29062915
29072916 // Apply interaction mode by switching the SDK's permission mode.