Skip to content

fix(claude-cli): return updatedInput in can_use_tool allow response for Claude Code 2.1#98665

Merged
vincentkoc merged 1 commit into
openclaw:mainfrom
yetval:fix/claude-live-canusetool-updatedinput
Jul 1, 2026
Merged

fix(claude-cli): return updatedInput in can_use_tool allow response for Claude Code 2.1#98665
vincentkoc merged 1 commit into
openclaw:mainfrom
yetval:fix/claude-live-canusetool-updatedinput

Conversation

@yetval

@yetval yetval commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

In a claude-cli-backed session, every native tool call that Claude Code routes through its permission flow (control_request / can_use_tool) fails against @anthropic-ai/claude-code >= 2.1.156. OpenClaw answers an approved request with the deprecated { behavior: "allow" } shape, but Claude Code 2.1 tightened its PermissionResult schema so the allow branch now requires an updatedInput record. The CLI rejects the response with a ZodError (invalid_union on updatedInput) before the tool runs, so the turn stalls.

This is the underlying failure behind issue #81099 (the AskUserQuestion variant that surfaces as invalid_union on updatedInput) and is reported directly in issue #95171 (all approval-gated tools: Bash, WebFetch, Grep with path, Glob outside cwd). Pinning Claude Code to 2.0.77 restores tool calls, confirming the break is on the OpenClaw bridge side.

Why This Change Was Made

handleClaudeLiveControlRequest in src/agents/cli-runner/claude-live-session.ts builds the control_response. On main the allow branch is:

response: allowed
  ? {
      behavior: "allow",
      ...(toolUseId ? { toolUseID: toolUseId } : {}),
    }
  : { behavior: "deny", ... }

The allow object omits updatedInput. Claude Code >= 2.1 validates the response against a union whose allow branch is { behavior: "allow", updatedInput: <record>, ... }; a missing updatedInput matches neither branch, so validation throws before the tool executes.

The fix echoes the tool input back unchanged as updatedInput (OpenClaw does not modify the tool input, so the original input is the correct value):

const toolInput = isRecord(request.input) ? request.input : {};
...
response: allowed
  ? {
      behavior: "allow",
      updatedInput: toolInput,
      ...(toolUseId ? { toolUseID: toolUseId } : {}),
    }
  : { behavior: "deny", ... }

Boundary: this is the only Claude live-session surface that answers can_use_tool. The other behavior: "allow" site, src/agents/harness/native-hook-relay.ts, is the codex-only provider adapter (NATIVE_HOOK_RELAY_PROVIDERS = ["codex"]) emitting the settings-hook hookSpecificOutput schema, a different provider contract that Claude does not route through; it is intentionally untouched. The deny branch is unchanged.

Dependency contract: the installed claude 2.1.197 binary emits the allow decision internally as behavior:"allow",updatedInput:<input> and logs returned updatedInput that failed schema validation on mismatch, matching the ZodError in #95171.

User Impact

claude-cli sessions on Claude Code >= 2.1.156 can once again use native tools through the approval flow. AskUserQuestion and every other approval-gated tool stop failing with a ZodError and the assistant turn proceeds. No config or migration is required; the deny path and existing behavior are unchanged.

Evidence

Real behavior proof

Behavior addressed: on a claude-cli backend, an approved can_use_tool request was answered with a shape Claude Code >= 2.1.156 rejects (invalid_union on updatedInput), stalling every native tool call including AskUserQuestion.
Real environment tested: drove the real prepared-run entry point executePreparedCliRun with backend.liveSession = "claude-stdio" on pristine origin/main (ce4a259) and on the patched tree, feeding a real control_request / can_use_tool line for the AskUserQuestion payload from issue #81099. The real live-session dispatcher, the real handleClaudeLiveControlRequest, and the real writeClaudeLiveControlResponse stay in play; only the spawned CLI OS process is stubbed, and the verbatim bytes OpenClaw writes to the CLI stdin are captured. The dependency contract is the installed claude 2.1.197 binary, whose allow shape is behavior:"allow",updatedInput:<input>.
Exact steps or command run after this patch: fed the AskUserQuestion can_use_tool request through executePreparedCliRun and captured the control_response.response object OpenClaw emits to the CLI.
Evidence after fix:

# BEFORE (pristine main ce4a259485) - emitted allow control_response.response
{"behavior":"allow","toolUseID":"tool-ask-1"}
# AFTER (this patch, identical AskUserQuestion request) - emitted allow control_response.response
{"behavior":"allow","updatedInput":{"questions":[{"question":"How do you want to watch these issues?","header":"Watch style","multiSelect":false,"options":[{"label":"Scheduled daily digest","description":"Cron job once a day."},{"label":"GitHub subscribe + notify","description":"Subscribe via API."}]}]},"toolUseID":"tool-ask-1"}

Observed result after fix: before the change OpenClaw emits an allow decision with no updatedInput, the exact shape Claude Code 2.1 rejects; after the change it emits updatedInput carrying the unmodified tool input, matching the shape the 2.1.197 binary expects, so the approved tool proceeds.
What was not tested: no live network round-trip against Anthropic was run (that requires an authenticated model turn to emit a real tool call); full build not run.

Verification

  • node scripts/run-vitest.mjs src/agents/cli-runner.spawn.test.ts: the two allow control_response cases now assert updatedInput round-trips the tool input; both pass with the patch and the added assertion fails on pristine main.
  • oxfmt --check and run-oxlint.mjs on the changed files: clean.
  • run-tsgo.mjs -p tsconfig.core.json and the core-test tsconfig: clean.

Related: #95171 (canonical report of this regression). Adjacent open PR #91544 targets the separate AskUserQuestion picker/answer bridge and does not change this line.

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 openclaw#95171.
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XS labels Jul 1, 2026
@clawsweeper

clawsweeper Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 1, 2026, 10:51 AM ET / 14:51 UTC.

Summary
The PR adds updatedInput to allowed Claude live can_use_tool control responses and extends focused spawn tests to assert the echoed input.

PR surface: Source +2, Tests +2. Total +4 across 2 files.

Reproducibility: yes. source-level: current main and v2026.6.11 still emit the old allow response without updatedInput, and the canonical issue includes a concrete Claude Code 2.1 ZodError repro. I did not run a fresh authenticated live Anthropic tool call in this read-only review.

Review metrics: 1 noteworthy metric.

  • Claude permission response fields: 1 field added. updatedInput is a dependency protocol field on the allow response, so version compatibility is the key maintainer check before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #95171
Summary: This PR is a direct candidate fix for the canonical Claude Code 2.1 can_use_tool allow-response schema regression; the broader AskUserQuestion bridge remains only partially overlapping.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Risk before merge

  • [P1] No authenticated end-to-end Anthropic tool execution was run in this review; the available proof covers the OpenClaw control-response bytes plus package contract inspection.

Maintainer options:

  1. Decide the mitigation before merge
    Land this narrow live-session response-shape fix as the canonical repair for the Claude Code 2.1 approval regression, while leaving the broader AskUserQuestion picker bridge to its separate issue/PR path.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • No automated repair is needed because there are no blocking findings; the remaining action is ordinary maintainer selection and merge review among duplicate candidate fixes.

Security
Cleared: The diff only changes internal TypeScript runtime response construction and focused tests; it adds no dependency, workflow, lockfile, secret, permission, or downloaded-code execution surface.

Review details

Best possible solution:

Land this narrow live-session response-shape fix as the canonical repair for the Claude Code 2.1 approval regression, while leaving the broader AskUserQuestion picker bridge to its separate issue/PR path.

Do we have a high-confidence way to reproduce the issue?

Yes, source-level: current main and v2026.6.11 still emit the old allow response without updatedInput, and the canonical issue includes a concrete Claude Code 2.1 ZodError repro. I did not run a fresh authenticated live Anthropic tool call in this read-only review.

Is this the best way to solve the issue?

Yes. Updating the Claude live stdio control-response boundary to echo the original tool input as updatedInput is the narrow maintainable fix, and the Codex-only native hook relay is a separate provider contract.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 909be7bcbc70.

Label changes

Label changes:

  • add P1: The PR targets a user-facing Claude CLI regression where approval-gated native tools fail before execution.
  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes terminal proof capturing before/after control_response bytes through the real OpenClaw prepared-run/live-session dispatcher, with the spawned Claude process stubbed and the dependency contract separately inspected.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes terminal proof capturing before/after control_response bytes through the real OpenClaw prepared-run/live-session dispatcher, with the spawned Claude process stubbed and the dependency contract separately inspected.

Label justifications:

  • P1: The PR targets a user-facing Claude CLI regression where approval-gated native tools fail before execution.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes terminal proof capturing before/after control_response bytes through the real OpenClaw prepared-run/live-session dispatcher, with the spawned Claude process stubbed and the dependency contract separately inspected.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes terminal proof capturing before/after control_response bytes through the real OpenClaw prepared-run/live-session dispatcher, with the spawned Claude process stubbed and the dependency contract separately inspected.
Evidence reviewed

PR surface:

Source +2, Tests +2. Total +4 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 2 0 +2
Tests 1 4 2 +2
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 6 2 +4

What I checked:

Likely related people:

  • guthirry: Authored the merged commit in fix(agents): honor effective exec policy for Claude live Bash #86330 that added Claude live can_use_tool control-response handling and tests. (role: introduced current behavior; confidence: high; commits: 6783e83af3b5; files: src/agents/cli-runner/claude-live-session.ts, src/agents/cli-runner.spawn.test.ts)
  • sallyom: Opened and merged the Claude live Bash/control-request policy PR that carried this behavior into main. (role: feature-history merger; confidence: high; commits: 86c861e0febc, f0b6f7005363; files: src/agents/cli-runner/claude-live-session.ts, src/agents/cli-runner.spawn.test.ts)
  • vincentkoc: Recent release/current-main history reintroduced the split Claude live-session file in this checkout and touched the same agent runtime area. (role: recent area contributor; confidence: medium; commits: e085fa1a3ffd; files: src/agents/cli-runner/claude-live-session.ts, src/agents/cli-runner.spawn.test.ts)
  • steipete: Earlier path history shows repeated Claude CLI runner and spawn-test work around the affected file family. (role: foundational CLI runner contributor; confidence: medium; commits: 4e099689c075, 89d7a24a3523, 461d0050d997; files: src/agents/cli-runner.spawn.test.ts, src/agents/cli-runner/execute.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P1 High-priority user-facing bug, regression, or broken workflow. labels Jul 1, 2026
@vincentkoc
vincentkoc merged commit a5a8d99 into openclaw:main Jul 1, 2026
141 of 147 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 2, 2026
…penclaw#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 openclaw#95171.
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 3, 2026
…penclaw#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 openclaw#95171.
sheyanmin pushed a commit to sheyanmin/openclaw that referenced this pull request Jul 8, 2026
…penclaw#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 openclaw#95171.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants