Skip to content

fix(claude-code): implement tool_choice support for forced tool calls#733

Merged
nicoloboschi merged 2 commits into
vectorize-io:mainfrom
kagura-agent:fix/claude-code-tool-choice
Mar 30, 2026
Merged

fix(claude-code): implement tool_choice support for forced tool calls#733
nicoloboschi merged 2 commits into
vectorize-io:mainfrom
kagura-agent:fix/claude-code-tool-choice

Conversation

@kagura-agent

Copy link
Copy Markdown
Contributor

Summary

Fixes #732 — Reflect agent never calls tools with claude-code provider because tool_choice parameter was accepted but completely ignored.

Root Cause

The call_with_tools() method in claude_code_llm.py declared tool_choice: str | dict[str, Any] = "auto" as a parameter but never used it. When the reflect agent passed tool_choice={"type": "function", "function": {"name": "search_mental_models"}} to force specific tools on each iteration, the claude-code provider ignored it entirely. Result: tools=[none] across all iterations, hallucinated "no information found" responses.

Fix

Since the Claude Agent SDK doesn't have a native tool_choice parameter, the fix enforces it through two mechanisms:

  1. allowed_tools filtering — restrict which tools are available to the model
  2. System prompt instructions — strongly guide the model to call required tools

Behavior for each tool_choice value:

tool_choice allowed_tools System prompt addition
{"type": "function", "function": {"name": "X"}} Only mcp__hindsight_tools__X "IMPORTANT: You MUST call the 'X' tool"
"required" All tools "You MUST call at least one tool"
"none" Empty (+ mcp_servers cleared)
"auto" (default) All tools — (existing behavior)

This mirrors the approach in openai_compatible_llm.py (lines 553-565) while adapting to the Claude Agent SDK's constraints.

Changes

  • hindsight-api-slim/hindsight_api/engine/providers/claude_code_llm.py: 43 insertions, 3 deletions
    • Added tool_choice handling logic before ClaudeAgentOptions creation
    • Updated docstring to document supported tool_choice values
    • Added debug logging for forced tool calls

Testing

  • Lint passes: ruff check clean
  • The fix only affects the call_with_tools() code path — call() (non-tool) is unchanged
  • Expected behavior: reflect agent iterations should now produce tools=[search_mental_models, search_observations, recall] instead of tools=[none]
  • Workaround (using openai provider) should no longer be needed

The call_with_tools() method now properly handles the tool_choice parameter
to force specific tool calls. Previously, the parameter was accepted but ignored,
causing the reflect agent to fail when trying to force specific tools on each
iteration.

Fixes vectorize-io#732

Changes:
- When tool_choice forces a specific function: filter allowed_tools to only
  that tool (with mcp prefix) and add a strong system prompt instruction
- When tool_choice is 'required': add instruction that model must call at
  least one tool
- When tool_choice is 'none': clear allowed_tools and mcp_servers to disable
  all tools
- When tool_choice is 'auto' (default): no change (existing behavior)

This matches the approach used in the OpenAI provider while adapting to the
Claude Agent SDK's lack of native tool_choice parameter by using allowed_tools
filtering and system prompt instructions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kagura-agent kagura-agent force-pushed the fix/claude-code-tool-choice branch from 25c2ecf to 9df390f Compare March 30, 2026 00:40
@kagura-agent

Copy link
Copy Markdown
Contributor Author

CI update: verify-generated-files now passes ✅ (fixed the alembic migration formatting).

The remaining test failures appear to be infrastructure-related (HINDSIGHT_API_LLM_VERTEXAI_PROJECT_ID not set in CI env), not related to this PR's changes. These same failures exist on other open PRs.

@nicoloboschi nicoloboschi merged commit 585ac76 into vectorize-io:main Mar 30, 2026
25 of 44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Reflect agent never calls tools with claude-code provider (tools=[none])

2 participants