Skip to content

Comments

fix: normalize toolCall arguments to prevent Anthropic API rejection#2213

Closed
manzienkog wants to merge 1 commit intoopenclaw:mainfrom
manzienkog:main
Closed

fix: normalize toolCall arguments to prevent Anthropic API rejection#2213
manzienkog wants to merge 1 commit intoopenclaw:mainfrom
manzienkog:main

Conversation

@manzienkog
Copy link

@manzienkog manzienkog commented Jan 26, 2026

Problem

Some models (e.g., via google-antigravity) omit the arguments field for tools with no required parameters. When this happens, pi-ai passes undefined to Anthropic's input field, causing API rejection:

messages.N.content.M.tool_use.input: Field required

Solution

Added normalizeToolCallArguments() which ensures arguments is always an object (defaulting to {}) before messages reach the API.

Affected tools

  • memory_status
  • load_memory (without trigger)
  • Any tool with optional-only or no parameters

Testing

Added tests in tool-call-id.test.ts covering:

  • Already-present arguments (no-op)
  • Undefined arguments → {}
  • Null arguments → {}
  • Multiple toolCalls in single message
  • Different tool types (toolCall, toolUse, functionCall)
  • Non-assistant messages unchanged

Greptile Overview

Greptile Summary

This PR adds normalizeToolCallArguments() to ensure assistant tool-call blocks always have an object-valued arguments field (defaulting missing/null to {}), preventing downstream providers (notably Anthropic) from rejecting messages where tool input is required but omitted by upstream models. The normalization is exported via pi-embedded-helpers and applied in the Google transcript sanitization pipeline (sanitizeSessionHistory), and a dedicated vitest suite is added to validate behavior across tool block types and message roles.

Confidence Score: 4/5

  • This PR is largely safe to merge and should fix the reported provider rejection scenario.
  • Changes are small and localized (pure normalization + wiring + tests). The main risk is scope/semantics (normalizing tool-call arguments for all providers) and a slightly misleading comment; no functional regressions were evident from code inspection, but I couldn’t run the test suite in this environment (pnpm unavailable).
  • src/agents/pi-embedded-runner/google.ts (ensure the intended scope of normalization/comment matches behavior)

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

Some models (e.g., via google-antigravity) omit the 'arguments' field
for tools with no required parameters. When this happens, pi-ai passes
undefined to Anthropic's 'input' field, causing API rejection with:
  'messages.N.content.M.tool_use.input: Field required'

This fix adds normalizeToolCallArguments() which ensures arguments is
always an object (defaulting to {}) before messages reach the API.

Fixes tool calls for:
- memory_status
- load_memory (without trigger)
- Any tool with optional-only or no parameters
@sebslight sebslight added gateway Gateway runtime and removed gateway Gateway runtime labels Jan 26, 2026
@ChiTienHsieh
Copy link

We hit this exact bug running clawdbot v2026.1.24-3 with Google Antigravity on a Hetzner VPS and spent time tracing the root cause on our end. Confirming the fix is correct.

Root cause trace

  1. Ingestiongoogle-gemini-cli.js:532:

    arguments: part.functionCall.args

    For zero-arg tools like session_status, args is undefined. The property gets stripped by JSON serialization, so session JSONL stores the block without an arguments key at all.

  2. Replayanthropic.js:470:

    input: block.arguments

    block.arguments is undefined → stripped by JSON.stringify → Anthropic API rejects with tool_use.input: Field required. Session is permanently broken until /reset.

Assessment

PR #2213's normalizeToolCallArguments is the right defensive fix at the replay/sanitization stage. Clean implementation, good test coverage, correct pipeline placement.

Suggestion: Consider also adding ?? {} at the ingestion point (google-gemini-cli.js:532) so corrupted sessions aren't written in the first place — belt-and-suspenders.

Grade: A. Ship it.


Investigated hands-on from a VM running clawdbot with Antigravity — session JSONL confirmed missing arguments key on zero-arg tool calls.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 339 to +343

// Normalize toolCall arguments to ensure they're always an object.
// Some models omit `arguments` for tools with no required params,
// but Anthropic API requires `input` to be present.
const normalizedArgs = normalizeToolCallArguments(repairedTools);
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3] Comment mentions Anthropic, but this normalization runs unconditionally

sanitizeSessionHistory always applies normalizeToolCallArguments regardless of provider/model (google, openai-responses, etc.). The comment at google.ts:340-343 says “Anthropic API requires input”, which is true for the reported failure, but it’s misleading in this location since the logic isn’t Anthropic-specific; consider rewording to reflect that we’re normalizing transcript/tool-call shape for downstream consumers/providers in general.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/google.ts
Line: 339:343

Comment:
[P3] Comment mentions Anthropic, but this normalization runs unconditionally

`sanitizeSessionHistory` always applies `normalizeToolCallArguments` regardless of provider/model (`google`, `openai-responses`, etc.). The comment at `google.ts:340-343` says “Anthropic API requires `input`”, which is true for the reported failure, but it’s misleading in this location since the logic isn’t Anthropic-specific; consider rewording to reflect that we’re normalizing transcript/tool-call shape for downstream consumers/providers in general.

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@vignesh07
Copy link
Contributor

Thanks for the careful fix and clear context.

We’re closing this PR because malformed tool-call handling has since been addressed in later updates on main, so this exact change is now superseded.

Really appreciate the contribution.

@vignesh07 vignesh07 closed this Feb 12, 2026
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.

4 participants