From e00c28f229dce31b7694461f755930eec371884c Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Thu, 4 Sep 2025 11:51:22 -0300 Subject: [PATCH] test: add test with tool --- providertests/provider_test.go | 45 +++++++++++++ .../TestTool/anthropic-claude-sonnet.yaml | 63 +++++++++++++++++++ .../testdata/TestTool/openai-gpt-4o.yaml | 63 +++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 providertests/testdata/TestTool/anthropic-claude-sonnet.yaml create mode 100644 providertests/testdata/TestTool/openai-gpt-4o.yaml diff --git a/providertests/provider_test.go b/providertests/provider_test.go index 0f77692dfc3d6af0910f49cfa1e4f83a5ea34ab9..81cb0cb521388fa0d5d594b7145a9973424bd85e 100644 --- a/providertests/provider_test.go +++ b/providertests/provider_test.go @@ -1,6 +1,7 @@ package providertests import ( + "context" "strings" "testing" @@ -37,3 +38,47 @@ func TestSimple(t *testing.T) { }) } } + +func TestTool(t *testing.T) { + for _, pair := range languageModelBuilders { + t.Run(pair.name, func(t *testing.T) { + r := newRecorder(t) + + languageModel, err := pair.builder(r) + if err != nil { + t.Fatalf("failed to build language model: %v", err) + } + + type WeatherInput struct { + Location string `json:"location" description:"the city"` + } + + weatherTool := ai.NewAgentTool( + "weather", + "Get weather information for a location", + func(ctx context.Context, input WeatherInput, _ ai.ToolCall) (ai.ToolResponse, error) { + return ai.NewTextResponse("40 C"), nil + }, + ) + + agent := ai.NewAgent( + languageModel, + ai.WithSystemPrompt("You are a helpful assistant"), + ai.WithTools(weatherTool), + ) + result, err := agent.Generate(t.Context(), ai.AgentCall{ + Prompt: "What's the weather in Florence?", + }) + if err != nil { + t.Fatalf("failed to generate: %v", err) + } + + want1 := "Florence" + want2 := "40" + got := result.Response.Content.Text() + if !strings.Contains(got, want1) || !strings.Contains(got, want2) { + t.Fatalf("unexpected response: got %q, want %q %q", got, want1, want2) + } + }) + } +} diff --git a/providertests/testdata/TestTool/anthropic-claude-sonnet.yaml b/providertests/testdata/TestTool/anthropic-claude-sonnet.yaml new file mode 100644 index 0000000000000000000000000000000000000000..7babf85fe8b66b5da5d94881f083a8dd379e3069 --- /dev/null +++ b/providertests/testdata/TestTool/anthropic-claude-sonnet.yaml @@ -0,0 +1,63 @@ +--- +version: 2 +interactions: +- id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 490 + host: "" + body: "{\"max_tokens\":4096,\"messages\":[{\"content\":[{\"text\":\"What's the weather in Florence?\",\"type\":\"text\"}],\"role\":\"user\"}],\"model\":\"claude-sonnet-4-20250514\",\"system\":[{\"text\":\"You are a helpful assistant\",\"type\":\"text\"}],\"tool_choice\":{\"disable_parallel_tool_use\":false,\"type\":\"auto\"},\"tools\":[{\"input_schema\":{\"properties\":{\"location\":{\"description\":\"the city\",\"type\":\"string\"}},\"required\":[\"location\"],\"type\":\"object\"},\"name\":\"weather\",\"description\":\"Get weather information for a location\"}]}" + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Anthropic/Go 1.10.0 + url: https://api.anthropic.com/v1/messages + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: "{\"id\":\"msg_01EnEXYvvJsZqCkmy6JSJbmZ\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-sonnet-4-20250514\",\"content\":[{\"type\":\"text\",\"text\":\"I'll get the weather information for Florence for you.\"},{\"type\":\"tool_use\",\"id\":\"toolu_01DuHpbePNYnbErjgBf5iHsF\",\"name\":\"weather\",\"input\":{\"location\":\"Florence\"}}],\"stop_reason\":\"tool_use\",\"stop_sequence\":null,\"usage\":{\"input_tokens\":392,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"cache_creation\":{\"ephemeral_5m_input_tokens\":0,\"ephemeral_1h_input_tokens\":0},\"output_tokens\":63,\"service_tier\":\"standard\"}}" + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 2.213104625s +- id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 850 + host: "" + body: "{\"max_tokens\":4096,\"messages\":[{\"content\":[{\"text\":\"What's the weather in Florence?\",\"type\":\"text\"}],\"role\":\"user\"},{\"content\":[{\"text\":\"I'll get the weather information for Florence for you.\",\"type\":\"text\"},{\"id\":\"toolu_01DuHpbePNYnbErjgBf5iHsF\",\"input\":{\"location\":\"Florence\"},\"name\":\"weather\",\"type\":\"tool_use\"}],\"role\":\"assistant\"},{\"content\":[{\"tool_use_id\":\"toolu_01DuHpbePNYnbErjgBf5iHsF\",\"content\":[{\"text\":\"40 C\",\"type\":\"text\"}],\"type\":\"tool_result\"}],\"role\":\"user\"}],\"model\":\"claude-sonnet-4-20250514\",\"system\":[{\"text\":\"You are a helpful assistant\",\"type\":\"text\"}],\"tool_choice\":{\"disable_parallel_tool_use\":false,\"type\":\"auto\"},\"tools\":[{\"input_schema\":{\"properties\":{\"location\":{\"description\":\"the city\",\"type\":\"string\"}},\"required\":[\"location\"],\"type\":\"object\"},\"name\":\"weather\",\"description\":\"Get weather information for a location\"}]}" + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Anthropic/Go 1.10.0 + url: https://api.anthropic.com/v1/messages + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: "{\"id\":\"msg_01HyNDRGB4Vs42jfUPPcBaak\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-sonnet-4-20250514\",\"content\":[{\"type\":\"text\",\"text\":\"The current temperature in Florence is 40°C (104°F). That's quite hot! Make sure to stay hydrated and seek shade or air conditioning if you're in the area.\"}],\"stop_reason\":\"end_turn\",\"stop_sequence\":null,\"usage\":{\"input_tokens\":470,\"cache_creation_input_tokens\":0,\"cache_read_input_tokens\":0,\"cache_creation\":{\"ephemeral_5m_input_tokens\":0,\"ephemeral_1h_input_tokens\":0},\"output_tokens\":42,\"service_tier\":\"standard\"}}" + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 2.306400542s diff --git a/providertests/testdata/TestTool/openai-gpt-4o.yaml b/providertests/testdata/TestTool/openai-gpt-4o.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3a2a9ad710e878cc484ee246cd521fb49616b516 --- /dev/null +++ b/providertests/testdata/TestTool/openai-gpt-4o.yaml @@ -0,0 +1,63 @@ +--- +version: 2 +interactions: +- id: 0 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 424 + host: "" + body: "{\"messages\":[{\"content\":\"You are a helpful assistant\",\"role\":\"system\"},{\"content\":\"What's the weather in Florence?\",\"role\":\"user\"}],\"model\":\"gpt-4o\",\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"weather\",\"strict\":false,\"description\":\"Get weather information for a location\",\"parameters\":{\"properties\":{\"location\":{\"description\":\"the city\",\"type\":\"string\"}},\"required\":[\"location\"],\"type\":\"object\"}},\"type\":\"function\"}]}" + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - OpenAI/Go 2.3.0 + url: https://api.openai.com/v1/chat/completions + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: "{\n \"id\": \"chatcmpl-CC5MhNb2zdVtCwHG9w33J2Ht2fRLk\",\n \"object\": \"chat.completion\",\n \"created\": 1756996595,\n \"model\": \"gpt-4o-2024-08-06\",\n \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": \"assistant\",\n \"content\": null,\n \"tool_calls\": [\n {\n \"id\": \"call_VDWPAXXYtOgpIp7VtHaQDlFz\",\n \"type\": \"function\",\n \"function\": {\n \"name\": \"weather\",\n \"arguments\": \"{\\\"location\\\":\\\"Florence\\\"}\"\n }\n }\n ],\n \"refusal\": null,\n \"annotations\": []\n },\n \"logprobs\": null,\n \"finish_reason\": \"tool_calls\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": 59,\n \"completion_tokens\": 14,\n \"total_tokens\": 73,\n \"prompt_tokens_details\": {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": \"default\",\n \"system_fingerprint\": \"fp_f33640a400\"\n}\n" + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 2.399816792s +- id: 1 + request: + proto: HTTP/1.1 + proto_major: 1 + proto_minor: 1 + content_length: 669 + host: "" + body: "{\"messages\":[{\"content\":\"You are a helpful assistant\",\"role\":\"system\"},{\"content\":\"What's the weather in Florence?\",\"role\":\"user\"},{\"tool_calls\":[{\"id\":\"call_VDWPAXXYtOgpIp7VtHaQDlFz\",\"function\":{\"arguments\":\"{\\\"location\\\":\\\"Florence\\\"}\",\"name\":\"weather\"},\"type\":\"function\"}],\"role\":\"assistant\"},{\"content\":\"40 C\",\"tool_call_id\":\"call_VDWPAXXYtOgpIp7VtHaQDlFz\",\"role\":\"tool\"}],\"model\":\"gpt-4o\",\"tool_choice\":\"auto\",\"tools\":[{\"function\":{\"name\":\"weather\",\"strict\":false,\"description\":\"Get weather information for a location\",\"parameters\":{\"properties\":{\"location\":{\"description\":\"the city\",\"type\":\"string\"}},\"required\":[\"location\"],\"type\":\"object\"}},\"type\":\"function\"}]}" + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - OpenAI/Go 2.3.0 + url: https://api.openai.com/v1/chat/completions + method: POST + response: + proto: HTTP/2.0 + proto_major: 2 + proto_minor: 0 + content_length: -1 + uncompressed: true + body: "{\n \"id\": \"chatcmpl-CC5MmCn0b4nV6e0m4ZGC7tX1t0JhL\",\n \"object\": \"chat.completion\",\n \"created\": 1756996600,\n \"model\": \"gpt-4o-2024-08-06\",\n \"choices\": [\n {\n \"index\": 0,\n \"message\": {\n \"role\": \"assistant\",\n \"content\": \"The current temperature in Florence is 40°C.\",\n \"refusal\": null,\n \"annotations\": []\n },\n \"logprobs\": null,\n \"finish_reason\": \"stop\"\n }\n ],\n \"usage\": {\n \"prompt_tokens\": 82,\n \"completion_tokens\": 11,\n \"total_tokens\": 93,\n \"prompt_tokens_details\": {\n \"cached_tokens\": 0,\n \"audio_tokens\": 0\n },\n \"completion_tokens_details\": {\n \"reasoning_tokens\": 0,\n \"audio_tokens\": 0,\n \"accepted_prediction_tokens\": 0,\n \"rejected_prediction_tokens\": 0\n }\n },\n \"service_tier\": \"default\",\n \"system_fingerprint\": \"fp_f33640a400\"\n}\n" + headers: + Content-Type: + - application/json + status: 200 OK + code: 200 + duration: 2.093890917s