Skip to content

Commit a5a8d99

Browse files
authored
fix(claude-cli): return updatedInput in can_use_tool allow response (#98665)
Claude Code >= 2.1.156 tightened its PermissionResult schema so an approved can_use_tool control_response allow branch must carry an updatedInput record. The Claude live-session bridge answered with the deprecated { behavior: "allow" } shape and no updatedInput, so the CLI rejected every approval-gated native tool call (Bash, WebFetch, and AskUserQuestion among them) with a ZodError before the tool ran. Echo the tool input back unchanged as updatedInput on the allow branch, matching the shape the Claude Code 2.1 binary expects. The deny branch and all other behavior are unchanged. Fixes #95171.
1 parent 0666423 commit a5a8d99

2 files changed

Lines changed: 6 additions & 2 deletions

File tree

src/agents/cli-runner.spawn.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,14 +1960,15 @@ ${JSON.stringify({
19601960
response: {
19611961
subtype: string;
19621962
request_id: string;
1963-
response: { behavior: string; toolUseID?: string };
1963+
response: { behavior: string; toolUseID?: string; updatedInput?: unknown };
19641964
};
19651965
};
19661966
expect(parsed.type).toBe("control_response");
19671967
expect(parsed.response.subtype).toBe("success");
19681968
expect(parsed.response.request_id).toBe("req-allow");
19691969
expect(parsed.response.response.behavior).toBe("allow");
19701970
expect(parsed.response.response.toolUseID).toBe("tool-allow-1");
1971+
expect(parsed.response.response.updatedInput).toEqual({ command: "ls" });
19711972
});
19721973

19731974
it("reports Claude live stream progress and keeps native tools fresh while they are running", async () => {
@@ -2329,11 +2330,12 @@ ${JSON.stringify({
23292330
response: {
23302331
subtype: string;
23312332
request_id: string;
2332-
response: { behavior: string; toolUseID?: string };
2333+
response: { behavior: string; toolUseID?: string; updatedInput?: unknown };
23332334
};
23342335
};
23352336
expect(parsed.response.response.behavior).toBe("allow");
23362337
expect(parsed.response.response.toolUseID).toBe("tool-default-allow-1");
2338+
expect(parsed.response.response.updatedInput).toEqual({ command: "echo hi" });
23372339
});
23382340

23392341
it("answers Claude live control_request can_use_tool with deny when approval defaults are restrictive", async () => {

src/agents/cli-runner/claude-live-session.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,7 @@ function handleClaudeLiveControlRequest(
866866
return;
867867
}
868868
const toolUseId = typeof request.tool_use_id === "string" ? request.tool_use_id : undefined;
869+
const toolInput = isRecord(request.input) ? request.input : {};
869870
const allowed = turn.execPermission.security === "full" && turn.execPermission.ask === "off";
870871
writeClaudeLiveControlResponse(session, {
871872
type: "control_response",
@@ -875,6 +876,7 @@ function handleClaudeLiveControlRequest(
875876
response: allowed
876877
? {
877878
behavior: "allow",
879+
updatedInput: toolInput,
878880
...(toolUseId ? { toolUseID: toolUseId } : {}),
879881
}
880882
: {

0 commit comments

Comments
 (0)