Skip to content

Send {} for empty Anthropic tool_use input instead of null#544

Merged
qmuntal merged 3 commits into
microsoft:mainfrom
PratikDhanave:fix-anthropic-empty-toolargs
Jul 18, 2026
Merged

Send {} for empty Anthropic tool_use input instead of null#544
qmuntal merged 3 commits into
microsoft:mainfrom
PratikDhanave:fix-anthropic-empty-toolargs

Conversation

@PratikDhanave

Copy link
Copy Markdown
Contributor

Problem

In buildMessageParams (provider/anthropicprovider/agent.go), a FunctionCallContent is converted to an Anthropic tool_use block:

var args map[string]any
if c.Arguments != "" {
    if err := json.Unmarshal([]byte(c.Arguments), &args); err != nil {
        return ..., err
    }
}
content = append(content, anthropic.NewToolUseBlock(c.CallID, args, c.Name))

When c.Arguments is empty, args stays nil, and a nil map serializes to "input": null. Anthropic requires a tool_use block's input to be an object and rejects null with a 400. So replaying a conversation history that contains a no-argument tool call (e.g. a tool with no parameters, or a call carried over from another provider that emits empty arguments) breaks the request.

Fix

Default args to an empty object (map[string]any{}) when it is nil — i.e. when Arguments is empty/absent, or decodes to JSON null — so the serialized input is always {}.

Test

TestToolUseEmptyArgumentsSerializeAsObject (black-box, in agent_test.go) runs the agent over a history containing an assistant FunctionCallContent{Arguments: ""}, captures the request body sent to the server, and asserts the tool_use block's input is a JSON object. Fails on main (input = null), passes with the fix.

When a FunctionCallContent has empty Arguments, buildMessageParams left
the parsed args map nil and passed it to NewToolUseBlock. A nil map
serializes to "input": null, but Anthropic requires a tool_use block's
input to be an object and rejects null — so replaying history that
contains a no-argument tool call produced a 400.

Default the args map to an empty object when Arguments is empty or absent
(and when it decodes to null), so the tool_use input is always {}. Adds a
request-capturing test asserting the serialized tool_use input is an
object.
Copilot AI review requested due to automatic review settings July 18, 2026 03:30
@PratikDhanave
PratikDhanave requested a review from a team as a code owner July 18, 2026 03:30

Copilot AI 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.

Pull request overview

This PR fixes Anthropic tool_use serialization so that no-argument tool calls send an empty object ({}) for input instead of null, which Anthropic rejects with a 400 when replaying conversation history.

Changes:

  • Default args to map[string]any{} when tool arguments are empty/absent (or decode to JSON null) so tool_use.input is always an object.
  • Add a black-box regression test that captures the outbound request body and asserts tool_use.input is a JSON object for empty FunctionCallContent.Arguments.
  • Minor gofmt/formatting adjustments in existing test helper/setup code.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
provider/anthropicprovider/agent.go Ensure nil tool argument maps serialize as {} to satisfy Anthropic’s tool_use.input object requirement.
provider/anthropicprovider/agent_test.go Add regression coverage verifying empty tool arguments serialize to an object, plus small formatting changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread provider/anthropicprovider/agent_test.go Outdated
Address review feedback: replace unchecked assertions on the decoded
request body with guarded ones so a schema mismatch reports a readable
failure instead of panicking.
@qmuntal
qmuntal added this pull request to the merge queue Jul 18, 2026
Merged via the queue into microsoft:main with commit eb8b844 Jul 18, 2026
19 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.

3 participants