Skip to content

Commit 3b0dae3

Browse files
(fix): Fix Claude Code Adapter for Supervised Chats
1 parent b96308f commit 3b0dae3

File tree

2 files changed

+55
-3
lines changed

2 files changed

+55
-3
lines changed

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

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ describe("ClaudeAdapterLive", () => {
298298

299299
const createInput = harness.getLastCreateQueryInput();
300300
assert.deepEqual(createInput?.options.settingSources, ["user", "project", "local"]);
301-
assert.equal(createInput?.options.permissionMode, undefined);
301+
assert.equal(createInput?.options.permissionMode, "default");
302302
assert.equal(createInput?.options.allowDangerouslySkipPermissions, undefined);
303303
}).pipe(
304304
Effect.provideService(Random.Random, makeDeterministicRandomService()),
@@ -2548,6 +2548,57 @@ describe("ClaudeAdapterLive", () => {
25482548
);
25492549
});
25502550

2551+
it.effect(
2552+
"restores default permission mode on sendTurn when supervised sessions leave plan mode",
2553+
() => {
2554+
const harness = makeHarness();
2555+
return Effect.gen(function* () {
2556+
const adapter = yield* ClaudeAdapter;
2557+
2558+
const session = yield* adapter.startSession({
2559+
threadId: THREAD_ID,
2560+
provider: "claudeAgent",
2561+
runtimeMode: "approval-required",
2562+
});
2563+
2564+
yield* adapter.sendTurn({
2565+
threadId: session.threadId,
2566+
input: "plan this",
2567+
interactionMode: "plan",
2568+
attachments: [],
2569+
});
2570+
2571+
const turnCompletedFiber = yield* Stream.filter(
2572+
adapter.streamEvents,
2573+
(event) => event.type === "turn.completed",
2574+
).pipe(Stream.runHead, Effect.forkChild);
2575+
2576+
harness.query.emit({
2577+
type: "result",
2578+
subtype: "success",
2579+
is_error: false,
2580+
errors: [],
2581+
session_id: "sdk-session-plan-restore-ask",
2582+
uuid: "result-plan-ask",
2583+
} as unknown as SDKMessage);
2584+
2585+
yield* Fiber.join(turnCompletedFiber);
2586+
2587+
yield* adapter.sendTurn({
2588+
threadId: session.threadId,
2589+
input: "now do it",
2590+
interactionMode: "default",
2591+
attachments: [],
2592+
});
2593+
2594+
assert.deepEqual(harness.query.setPermissionModeCalls, ["plan", "default"]);
2595+
}).pipe(
2596+
Effect.provideService(Random.Random, makeDeterministicRandomService()),
2597+
Effect.provide(harness.layer),
2598+
);
2599+
},
2600+
);
2601+
25512602
it.effect("does not call setPermissionMode when interactionMode is absent", () => {
25522603
const harness = makeHarness();
25532604
return Effect.gen(function* () {

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2693,7 +2693,8 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (
26932693
? modelSelection.options.thinking
26942694
: undefined;
26952695
const effectiveEffort = getEffectiveClaudeCodeEffort(effort);
2696-
const permissionMode = input.runtimeMode === "full-access" ? "bypassPermissions" : undefined;
2696+
const permissionMode: PermissionMode =
2697+
input.runtimeMode === "full-access" ? "bypassPermissions" : "default";
26972698
const settings = {
26982699
...(typeof thinking === "boolean" ? { alwaysThinkingEnabled: thinking } : {}),
26992700
...(fastMode ? { fastMode: true } : {}),
@@ -2705,7 +2706,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (
27052706
pathToClaudeCodeExecutable: claudeBinaryPath,
27062707
settingSources: [...CLAUDE_SETTING_SOURCES],
27072708
...(effectiveEffort ? { effort: effectiveEffort } : {}),
2708-
...(permissionMode ? { permissionMode } : {}),
2709+
permissionMode,
27092710
...(permissionMode === "bypassPermissions"
27102711
? { allowDangerouslySkipPermissions: true }
27112712
: {}),

0 commit comments

Comments
 (0)