authorgravatar for harshit9797@gmail.comHarshit Agarwal <harshit9797@gmail.com> 2026-03-28 00:34:28+05:30
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-03-27 12:04:28-07:00
logfb7260792fbbb84252213541a76dd61d52243bdf
treeb569eb68b58f012b2cef951225ec7a6b11380751
parentd8a485ea7e93f4e498be3314c0094a3af675938f
signature Signed by PGP key B5690EEEBB952194

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


2 files changed, 92 insertions(+), 4 deletions(-)

apps/server/src/provider/Layers/ClaudeAdapter.test.ts+79
......@@ -2384,6 +2384,85 @@ describe("ClaudeAdapterLive", () => {
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 {
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) {
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) {
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.