Skip to content

fix(claude-code): stop handing the CLI's own tool calls to the harness - #5994

Open
Guykaganovsky1 wants to merge 1 commit into
tinyhumansai:mainfrom
Guykaganovsky1:fix/claude-code-cli-internal-tools
Open

fix(claude-code): stop handing the CLI's own tool calls to the harness#5994
Guykaganovsky1 wants to merge 1 commit into
tinyhumansai:mainfrom
Guykaganovsky1:fix/claude-code-cli-internal-tools

Conversation

@Guykaganovsky1

@Guykaganovsky1 Guykaganovsky1 commented Sep 3, 2026

Copy link
Copy Markdown

Summary

  • A native tool_use block from the Claude Code CLI is the CLI's own call — a builtin (Bash / Read / Write / Edit …) or a server from the --mcp-config we hand it. The CLI runs it inside its own agentic loop.
  • The matching tool_result blocks were already dropped for that reason, but the call half was still surfaced to OpenHuman's harness, which cannot run those tools and never sees a result for them.
  • With the full-access toggle on (no --disallowedTools, so the CLI keeps Bash), a turn that reached for a builtin failed repeatedly until the circuit breaker halted the run, then burned the 900s wall-clock backstop.
  • Also raises the driver's per-turn timeout from 300s to 900s (overridable), since 300s is shorter than a turn the CLI is expected to take once it is doing real work.

Problem

Observed in a live desktop session with chat_provider = "claude-code:claude-opus-5" and claude_code_settings.json = {"full_access": true}:

[tinyagents::mw] no-progress nudge — steering the model … tool=Bash step=4
[tinyagents::mw] repeated tool failure — halting run … tool=Write step=6
[tinyagents] run halted by circuit breaker; surfacing as breaker_halt (#4466)
[web-channel] run_chat_task failed … openhuman_turn_wall_clock_timeout: agent turn exceeded its 900s …
[claude-code][driver] turn timeout (300s) exceeded; killing child

Two independent defects behind one symptom:

  1. event_mapper.rs mapped every tool_use block to ProviderDelta::ToolCallStart / ToolCallArgsDelta and pushed it into ChatResponse.tool_calls — including the CLI's own builtins. The harness then tried to execute Bash, which is not an OpenHuman tool. Asymmetric with map_event's User arm, which drops the corresponding tool_result precisely because "the harness owns tools … not CC internals".
  2. TURN_TIMEOUT was a hard 300s. Full access means the CLI does real multi-step work; the child was killed mid-turn and the failure read as a provider timeout rather than a slow answer.

Solution

  1. Track the tool_use block (so its input_json_deltas and stop event are swallowed rather than leaking as stray deltas) but surface nothing — no ToolCallStart, no ToolCallArgsDelta, no entry in tool_calls. The provider is then what it actually is: a chat model whose tool use is internal. OpenHuman's own tools reach it through the prompt catalogue, not native tool calls.
  2. turn_timeout() reads OPENHUMAN_CLAUDE_CODE_TURN_TIMEOUT_SECS, defaulting to 900s to match the harness's own wall-clock backstop.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) — cli_internal_tool_calls_are_not_surfaced_to_the_harness (the regression) and text_in_a_turn_with_a_cli_tool_call_still_streams (the answer must survive the dropped block). tool_call_assembles_input pinned the old behaviour and was replaced by the first of these.
  • Diff coverage ≥ 80% — the changed mapper branches are executed by both tests. cargo test --lib inference::provider::claude_code: 45 passed, 0 failed.
  • Coverage matrix updated — N/A: bug fix to existing behaviour, no feature row added, removed or renamed
  • All affected feature IDs from the matrix are listed under ## RelatedN/A: no matrix row covers the claude-code event mapper
  • No new external network dependencies introduced — unit tests are pure event-mapper tests; no network.
  • Manual smoke checklist updated if this touches release-cut surfaces — N/A: no release-cut surface changes
  • Linked issue closed via Closes #NNNN/A: no filed issue; found while running the Claude Code CLI provider with full access

Impact

Desktop/CLI, and only for workloads routed to claude-code:<model>. Behaviour change: the aggregated response no longer reports the CLI's internal tool calls, so a caller that inspected ChatResponse.tool_calls for this provider now sees an empty list — which is the honest answer, since those calls were never executable here and never had results attached.

The timeout default triples. A genuinely hung CLI now takes 900s to surface instead of 300s; the env var is there for anyone who wants the old value back.

Verified end to end against the live CLI: "create a file … then read it back" returns File written, read back: TOOLS_WORK, the file exists on disk, and the run logs zero repeated tool failure / breaker_halt lines. The same class of turn halted at step 6 before the change.

Related

N/A — no linked issue.

Summary by CodeRabbit

  • Bug Fixes
    • Increased the default Claude Code operation timeout to 15 minutes.
    • Added an environment setting to customize the timeout duration.
    • Prevented Claude Code’s internal tool activity from appearing as user-facing tool calls.
    • Preserved normal text streaming when internal tool activity occurs.
    • Updated timeout messages and logs to show the applicable duration.

A native `tool_use` block from the Claude Code CLI is the CLI's OWN call — a
builtin (Bash / Read / Write / Edit …) or a server from the `--mcp-config` we
hand it — and the CLI executes it inside its own agentic loop. The matching
`tool_result` blocks were already dropped for exactly that reason.

The call half was surfaced anyway, as `ProviderDelta::ToolCallStart` +
`ToolCallArgsDelta` and in the aggregated `ChatResponse.tool_calls`. That hands
OpenHuman's harness a tool it does not own and cannot run, and it never sees a
result for it. With the full-access toggle on (no `--disallowedTools`, so the
CLI keeps Bash and friends) a turn that reached for `Bash` produced:

    [tinyagents::mw] no-progress nudge … tool=Bash step=4
    [tinyagents::mw] repeated tool failure — halting run … tool=Write step=6
    run halted by circuit breaker; surfacing as breaker_halt

…and the turn then burned its 900s wall-clock backstop. Neither half is
surfaced now, so this provider behaves as what it is: a chat model whose tool
use is internal. OpenHuman's own tools reach it through the prompt catalogue,
not through native tool calls.

Second fix in the same failure: the driver's per-turn timeout was 300s, which is
shorter than a turn the CLI is expected to take once full access lets it work.
The child was killed mid-turn and it surfaced as a provider timeout rather than
a slow answer. The default is now 900s — matching the harness's own backstop —
and is overridable with `OPENHUMAN_CLAUDE_CODE_TURN_TIMEOUT_SECS`.

Verified end to end against the live CLI: "create a file … then read it back"
returns `File written, read back: TOOLS_WORK`, the file exists on disk, and the
run logs zero `repeated tool failure` / `breaker_halt` lines. Before the change
the same class of turn halted at step 6.
@Guykaganovsky1
Guykaganovsky1 requested a review from a team September 3, 2026 07:19
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T07:24:21.304228Z 0426259 PR opened
🔒 Security Review Completed 2026-09-03T07:24:58.136170Z 0426259 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper found nothing blocking. Approving.

$0.0000 · 0 in / 0 out

@tinysweeper

tinysweeper Bot commented Sep 3, 2026

Copy link
Copy Markdown

How this change flows

1 changed behaviour across 8 relationships. 6 surrounding behaviours are shown (60 graph nodes walked). 36 further behaviours left out to keep the diagram readable.

flowchart LR
  n0["run_turn<br/>changed"]:::changed
  n1["handle_assistant_block"]:::impacted
  n2["Value"]:::impacted
  n3["on_block_start"]:::impacted
  n4["ProviderDelta"]:::impacted
  n5["seatbelt_profile"]:::impacted
  n6["new"]:::impacted
  n0 -->|calls| n5
  n1 -->|uses| n2
  n1 -->|calls| n3
  n1 -->|uses| n4
  n1 -->|calls| n6
  n3 -->|uses| n2
  n3 -->|uses| n4
  n3 -->|calls| n6
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading

Green: changed behaviour. Grey: surrounding behaviour. Arrows name the call, use, implementation, or test relationship. Orange: has findings. Red: has a finding that blocks the merge.

tinysweeper 0.1.0

@tinysweeper tinysweeper Bot added the priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. label Sep 3, 2026
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 6beef744-d5ec-48b3-beb9-da4f8c7d56e8

📥 Commits

Reviewing files that changed from the base of the PR and between 7be5b92 and 0426259.

📒 Files selected for processing (3)
  • src/openhuman/inference/provider/claude_code/driver.rs
  • src/openhuman/inference/provider/claude_code/event_mapper.rs
  • src/openhuman/inference/provider/claude_code/event_mapper_tests.rs

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The Claude Code driver now uses a configurable turn timeout with a 900-second default. Native CLI tool events remain internal, while text continues to stream to the harness.

Changes

Claude Code handling

Layer / File(s) Summary
Configurable turn timeout
src/openhuman/inference/provider/claude_code/driver.rs
The driver resolves the timeout from OPENHUMAN_CLAUDE_CODE_TURN_TIMEOUT_SECS, uses 900 seconds by default, and reports the resolved duration in diagnostics and errors.
Internal CLI tool event mapping
src/openhuman/inference/provider/claude_code/event_mapper.rs, src/openhuman/inference/provider/claude_code/event_mapper_tests.rs
The mapper tracks native CLI tool events for diagnostics without emitting tool-call deltas or aggregated tool calls. Tests verify that text still streams during turns containing CLI tools.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 04262

Claude Code native tool activity remains internal while text streaming is preserved, and turns use a configurable 900-second default timeout. No current merge-blocking risk is identified.

Suggested reviewers: senamakel

Poem

A rabbit watched the timeout grow,
Nine hundred seconds now flow.
CLI tools stay tucked away,
While words still stream throughout the day.
The harness hears the text in play.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: preventing Claude Code CLI-internal tool calls from reaching the harness. The timeout change is secondary and does not need to appear in t…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title clearly and concisely describes the primary change: preventing Claude Code CLI-internal tool calls from reaching the harness. The timeout change is secondary and does not need to appear in the title.

  • Fix all pre-merge checks with AI

Warning

Your free Security trial is over. An organization admin can upgrade to Advanced for continuous pull request security review or dismiss this notice.


Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant