diff --git a/providers/anthropic/anthropic.go b/providers/anthropic/anthropic.go index b1bcee24cd40d6751c73dab9317e6c30c97037ed..25ac81dab38230debc3c5ad6fb5d6cb933665a30 100644 --- a/providers/anthropic/anthropic.go +++ b/providers/anthropic/anthropic.go @@ -638,7 +638,10 @@ func (a languageModel) toTools(tools []fantasy.Tool, toolChoice *fantasy.ToolCho }, } case fantasy.ToolChoiceNone: - return anthropicTools, anthropicToolChoice, warnings + none := anthropic.NewToolChoiceNoneParam() + anthropicToolChoice = &anthropic.ToolChoiceUnionParam{ + OfNone: &none, + } default: anthropicToolChoice = &anthropic.ToolChoiceUnionParam{ OfTool: &anthropic.ToolChoiceToolParam{ diff --git a/providers/anthropic/anthropic_test.go b/providers/anthropic/anthropic_test.go index 51adb7c333110ed1c3a490cce32312ef05df8be9..5f137a78be7a0b2f6fcfbad8403474ac5ece376a 100644 --- a/providers/anthropic/anthropic_test.go +++ b/providers/anthropic/anthropic_test.go @@ -1333,3 +1333,34 @@ func TestStream_WebSearchResponse(t *testing.T) { require.NotEmpty(t, textDeltas, "should have text deltas") require.Equal(t, "Here are the results.", textDeltas[0].Delta) } + +func TestGenerate_ToolChoiceNone(t *testing.T) { + t.Parallel() + + server, calls := newAnthropicJSONServer(mockAnthropicGenerateResponse()) + defer server.Close() + + provider, err := New( + WithAPIKey("test-api-key"), + WithBaseURL(server.URL), + ) + require.NoError(t, err) + + model, err := provider.LanguageModel(context.Background(), "claude-sonnet-4-20250514") + require.NoError(t, err) + + toolChoiceNone := fantasy.ToolChoiceNone + _, err = model.Generate(context.Background(), fantasy.Call{ + Prompt: testPrompt(), + Tools: []fantasy.Tool{ + WebSearchTool(nil), + }, + ToolChoice: &toolChoiceNone, + }) + require.NoError(t, err) + + call := awaitAnthropicCall(t, calls) + toolChoice, ok := call.body["tool_choice"].(map[string]any) + require.True(t, ok, "request body should have tool_choice") + require.Equal(t, "none", toolChoice["type"], "tool_choice should be 'none'") +}