Skip to content

Commit fb72607

Browse files
authored
fix(claude): avoid resetting the Claude model on every turn (pingdotgg#1466)
1 parent d8a485e commit fb72607

File tree

2 files changed

+92
-4
lines changed

2 files changed

+92
-4
lines changed

apps/server/src/provider/Layers/ClaudeAdapter.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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.

0 commit comments

Comments
 (0)