diff --git a/e2e/testdata/cassettes/TestExec_Anthropic_ToolCall.yaml b/e2e/testdata/cassettes/TestExec_Anthropic_ToolCall.yaml index 2be642e14..1387b087f 100644 --- a/e2e/testdata/cassettes/TestExec_Anthropic_ToolCall.yaml +++ b/e2e/testdata/cassettes/TestExec_Anthropic_ToolCall.yaml @@ -8,7 +8,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.anthropic.com - body: '{"max_tokens":64000,"messages":[{"content":[{"text":"How many files in testdata/working_dir? Only output the number.","cache_control":{"type":"ephemeral"},"type":"text"}],"role":"user"}],"model":"claude-sonnet-4-0","system":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.","type":"text"},{"text":"## Filesystem Tools\n\n- Relative paths resolve from the working directory; absolute paths and \"..\" work as expected\n- Prefer read_multiple_files over sequential read_file calls\n- Use search_files_content to locate code or text across files\n- Use exclude patterns in searches and max_depth in directory_tree to limit output","cache_control":{"type":"ephemeral"},"type":"text"}],"tools":[{"input_schema":{"properties":{"path":{"description":"Directory to traverse","type":"string"}},"required":["path"],"type":"object"},"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure."},{"input_schema":{"properties":{"path":{"description":"File to edit","type":"string"},"edits":{"description":"Edits to apply","items":{"additionalProperties":false,"properties":{"oldText":{"description":"Exact text to replace","type":"string"},"newText":{"description":"Replacement text","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"}},"required":["path","edits"],"type":"object"},"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content."},{"input_schema":{"properties":{"path":{"description":"Directory to list","type":"string"}},"required":["path"],"type":"object"},"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path."},{"input_schema":{"properties":{"path":{"description":"File to read","type":"string"},"line":{"description":"1-based line number to start reading from (text files only; defaults to the first line)","type":["null","integer"]},"limit":{"description":"Maximum number of lines to read (text files only; defaults to reading through the end of the file)","type":["null","integer"]}},"required":["path"],"type":"object"},"name":"read_file","description":"Read the contents of a file from the file system. By default the complete file is returned; for text files the optional line (1-based start line) and limit (maximum number of lines) arguments select a line range. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"paths":{"description":"Files to read","items":{"type":"string"},"type":"array"},"json":{"description":"Return result as JSON","type":"boolean"}},"required":["paths"],"type":"object"},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"path":{"description":"Starting directory","type":"string"},"query":{"description":"Text or regex to search","type":"string"},"is_regex":{"description":"Treat query as regex","type":"boolean"},"excludePatterns":{"description":"Patterns to exclude","items":{"type":"string"},"type":["null","array"]}},"required":["path","query"],"type":"object"},"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern."},{"input_schema":{"properties":{"path":{"description":"File to write","type":"string"},"content":{"description":"File content","type":"string"}},"required":["path","content"],"type":"object"},"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content."},{"input_schema":{"properties":{"paths":{"description":"Directories to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Directories to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"},"name":"remove_directory","description":"Remove one or more empty directories."}],"stream":true}' + body: '{"max_tokens":64000,"messages":[{"content":[{"text":"How many files in testdata/working_dir? Only output the number.","cache_control":{"type":"ephemeral"},"type":"text"}],"role":"user"}],"model":"claude-sonnet-4-0","system":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.","type":"text"},{"text":"## Filesystem Tools\n\n- Relative paths resolve from the working directory; absolute paths and \"..\" work as expected\n- Prefer read_multiple_files over sequential read_file calls\n- Use search_files_content to locate code or text across files\n- Use exclude patterns in searches and max_depth in directory_tree to limit output","cache_control":{"type":"ephemeral"},"type":"text"}],"tools":[{"input_schema":{"properties":{"path":{"description":"Directory to traverse","type":"string"}},"required":["path"],"type":"object","additionalProperties":false},"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure."},{"input_schema":{"properties":{"path":{"description":"File to edit","type":"string"},"edits":{"description":"Edits to apply","items":{"additionalProperties":false,"properties":{"oldText":{"description":"Exact text to replace","type":"string"},"newText":{"description":"Replacement text","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"}},"required":["path","edits"],"type":"object","additionalProperties":false},"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content."},{"input_schema":{"properties":{"path":{"description":"Directory to list","type":"string"}},"required":["path"],"type":"object","additionalProperties":false},"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path."},{"input_schema":{"properties":{"path":{"description":"File to read","type":"string"},"line":{"description":"1-based line number to start reading from (text files only; defaults to the first line)","type":["null","integer"]},"limit":{"description":"Maximum number of lines to read (text files only; defaults to reading through the end of the file)","type":["null","integer"]}},"required":["path"],"type":"object","additionalProperties":false},"name":"read_file","description":"Read the contents of a file from the file system. By default the complete file is returned; for text files the optional line (1-based start line) and limit (maximum number of lines) arguments select a line range. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"paths":{"description":"Files to read","items":{"type":"string"},"type":"array"},"json":{"description":"Return result as JSON","type":"boolean"}},"required":["paths"],"type":"object","additionalProperties":false},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"path":{"description":"Starting directory","type":"string"},"query":{"description":"Text or regex to search","type":"string"},"is_regex":{"description":"Treat query as regex","type":"boolean"},"excludePatterns":{"description":"Patterns to exclude","items":{"type":"string"},"type":["null","array"]}},"required":["path","query"],"type":"object","additionalProperties":false},"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern."},{"input_schema":{"properties":{"path":{"description":"File to write","type":"string"},"content":{"description":"File content","type":"string"}},"required":["path","content"],"type":"object","additionalProperties":false},"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content."},{"input_schema":{"properties":{"paths":{"description":"Directories to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object","additionalProperties":false},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Directories to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object","additionalProperties":false},"name":"remove_directory","description":"Remove one or more empty directories."}],"stream":true}' url: https://api.anthropic.com/v1/messages method: POST response: @@ -55,7 +55,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.anthropic.com - body: '{"max_tokens":64000,"messages":[{"content":[{"text":"How many files in testdata/working_dir? Only output the number.","type":"text"}],"role":"user"},{"content":[{"id":"toolu_012gmfqnoTX8c5aV3vMWUnas","input":{"path":"testdata/working_dir"},"name":"list_directory","cache_control":{"type":"ephemeral"},"type":"tool_use"}],"role":"assistant"},{"content":[{"tool_use_id":"toolu_012gmfqnoTX8c5aV3vMWUnas","is_error":false,"cache_control":{"type":"ephemeral"},"content":[{"text":"FILE README.me\n","type":"text"}],"type":"tool_result"}],"role":"user"}],"model":"claude-sonnet-4-0","system":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.","type":"text"},{"text":"## Filesystem Tools\n\n- Relative paths resolve from the working directory; absolute paths and \"..\" work as expected\n- Prefer read_multiple_files over sequential read_file calls\n- Use search_files_content to locate code or text across files\n- Use exclude patterns in searches and max_depth in directory_tree to limit output","cache_control":{"type":"ephemeral"},"type":"text"}],"tools":[{"input_schema":{"properties":{"path":{"description":"Directory to traverse","type":"string"}},"required":["path"],"type":"object"},"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure."},{"input_schema":{"properties":{"path":{"description":"File to edit","type":"string"},"edits":{"description":"Edits to apply","items":{"additionalProperties":false,"properties":{"oldText":{"description":"Exact text to replace","type":"string"},"newText":{"description":"Replacement text","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"}},"required":["path","edits"],"type":"object"},"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content."},{"input_schema":{"properties":{"path":{"description":"Directory to list","type":"string"}},"required":["path"],"type":"object"},"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path."},{"input_schema":{"properties":{"path":{"description":"File to read","type":"string"},"line":{"description":"1-based line number to start reading from (text files only; defaults to the first line)","type":["null","integer"]},"limit":{"description":"Maximum number of lines to read (text files only; defaults to reading through the end of the file)","type":["null","integer"]}},"required":["path"],"type":"object"},"name":"read_file","description":"Read the contents of a file from the file system. By default the complete file is returned; for text files the optional line (1-based start line) and limit (maximum number of lines) arguments select a line range. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"paths":{"description":"Files to read","items":{"type":"string"},"type":"array"},"json":{"description":"Return result as JSON","type":"boolean"}},"required":["paths"],"type":"object"},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"path":{"description":"Starting directory","type":"string"},"query":{"description":"Text or regex to search","type":"string"},"is_regex":{"description":"Treat query as regex","type":"boolean"},"excludePatterns":{"description":"Patterns to exclude","items":{"type":"string"},"type":["null","array"]}},"required":["path","query"],"type":"object"},"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern."},{"input_schema":{"properties":{"path":{"description":"File to write","type":"string"},"content":{"description":"File content","type":"string"}},"required":["path","content"],"type":"object"},"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content."},{"input_schema":{"properties":{"paths":{"description":"Directories to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Directories to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"},"name":"remove_directory","description":"Remove one or more empty directories."}],"stream":true}' + body: '{"max_tokens":64000,"messages":[{"content":[{"text":"How many files in testdata/working_dir? Only output the number.","type":"text"}],"role":"user"},{"content":[{"id":"toolu_012gmfqnoTX8c5aV3vMWUnas","input":{"path":"testdata/working_dir"},"name":"list_directory","cache_control":{"type":"ephemeral"},"type":"tool_use"}],"role":"assistant"},{"content":[{"tool_use_id":"toolu_012gmfqnoTX8c5aV3vMWUnas","is_error":false,"cache_control":{"type":"ephemeral"},"content":[{"text":"FILE README.me\n","type":"text"}],"type":"tool_result"}],"role":"user"}],"model":"claude-sonnet-4-0","system":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.","type":"text"},{"text":"## Filesystem Tools\n\n- Relative paths resolve from the working directory; absolute paths and \"..\" work as expected\n- Prefer read_multiple_files over sequential read_file calls\n- Use search_files_content to locate code or text across files\n- Use exclude patterns in searches and max_depth in directory_tree to limit output","cache_control":{"type":"ephemeral"},"type":"text"}],"tools":[{"input_schema":{"properties":{"path":{"description":"Directory to traverse","type":"string"}},"required":["path"],"type":"object","additionalProperties":false},"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure."},{"input_schema":{"properties":{"path":{"description":"File to edit","type":"string"},"edits":{"description":"Edits to apply","items":{"additionalProperties":false,"properties":{"oldText":{"description":"Exact text to replace","type":"string"},"newText":{"description":"Replacement text","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"}},"required":["path","edits"],"type":"object","additionalProperties":false},"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content."},{"input_schema":{"properties":{"path":{"description":"Directory to list","type":"string"}},"required":["path"],"type":"object","additionalProperties":false},"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path."},{"input_schema":{"properties":{"path":{"description":"File to read","type":"string"},"line":{"description":"1-based line number to start reading from (text files only; defaults to the first line)","type":["null","integer"]},"limit":{"description":"Maximum number of lines to read (text files only; defaults to reading through the end of the file)","type":["null","integer"]}},"required":["path"],"type":"object","additionalProperties":false},"name":"read_file","description":"Read the contents of a file from the file system. By default the complete file is returned; for text files the optional line (1-based start line) and limit (maximum number of lines) arguments select a line range. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"paths":{"description":"Files to read","items":{"type":"string"},"type":"array"},"json":{"description":"Return result as JSON","type":"boolean"}},"required":["paths"],"type":"object","additionalProperties":false},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"path":{"description":"Starting directory","type":"string"},"query":{"description":"Text or regex to search","type":"string"},"is_regex":{"description":"Treat query as regex","type":"boolean"},"excludePatterns":{"description":"Patterns to exclude","items":{"type":"string"},"type":["null","array"]}},"required":["path","query"],"type":"object","additionalProperties":false},"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern."},{"input_schema":{"properties":{"path":{"description":"File to write","type":"string"},"content":{"description":"File content","type":"string"}},"required":["path","content"],"type":"object","additionalProperties":false},"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content."},{"input_schema":{"properties":{"paths":{"description":"Directories to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object","additionalProperties":false},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Directories to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object","additionalProperties":false},"name":"remove_directory","description":"Remove one or more empty directories."}],"stream":true}' url: https://api.anthropic.com/v1/messages method: POST response: diff --git a/go.mod b/go.mod index 5b2dd56aa..8eeb637d8 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/a2aproject/a2a-go/v2 v2.5.0 github.com/alecthomas/chroma/v2 v2.27.0 github.com/alpkeskin/gotoon v0.1.1 - github.com/anthropics/anthropic-sdk-go v1.74.0 + github.com/anthropics/anthropic-sdk-go v1.79.1 github.com/atotto/clipboard v0.1.4 github.com/aws/aws-sdk-go-v2 v1.47.1 github.com/aws/aws-sdk-go-v2/config v1.33.6 diff --git a/go.sum b/go.sum index 1737c544c..3394efbec 100644 --- a/go.sum +++ b/go.sum @@ -53,8 +53,8 @@ github.com/alpkeskin/gotoon v0.1.1 h1:GQOVwMfWKINnfEA6slrXHJaJYDwnUFmrPlXOtnuja1 github.com/alpkeskin/gotoon v0.1.1/go.mod h1:XRTz8RM4tz8M2nB37MNRN8rHF4YgeYd8nIXmoU0B0+M= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= -github.com/anthropics/anthropic-sdk-go v1.74.0 h1:u6pcrBJHLJZb1Q6uziqQ5VLvAjh82sJrreWmABdOOas= -github.com/anthropics/anthropic-sdk-go v1.74.0/go.mod h1:x+lPk/cCl48uRegeP0hlYYBN1b7bEBTveInIMgLicnY= +github.com/anthropics/anthropic-sdk-go v1.79.1 h1:R+DGl2fpI8mIg7OGjEEHpr1WN7HOja76sz89Z2DMcqk= +github.com/anthropics/anthropic-sdk-go v1.79.1/go.mod h1:x+lPk/cCl48uRegeP0hlYYBN1b7bEBTveInIMgLicnY= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/apparentlymart/go-textseg/v17 v17.0.1 h1:bpMXRgQ5cEoRNuQke1a80/Nl6w3G5eoIbWo9f3gXkAs= diff --git a/pkg/model/provider/anthropic/task_budget_test.go b/pkg/model/provider/anthropic/task_budget_test.go index 43973c002..925f63ca8 100644 --- a/pkg/model/provider/anthropic/task_budget_test.go +++ b/pkg/model/provider/anthropic/task_budget_test.go @@ -6,6 +6,7 @@ import ( "io" "net/http" "net/http/httptest" + "strings" "testing" "github.com/anthropics/anthropic-sdk-go" @@ -120,9 +121,7 @@ func TestTaskBudget_RoutesToBetaAPIWithBetaHeader(t *testing.T) { ) srv := anthropicTestServer(t, func(r *http.Request, body []byte) { gotPath = r.URL.Path - // The SDK emits one `anthropic-beta` header per beta via - // WithHeaderAdd, so use Values (not Get) to see every entry. - gotBetas = r.Header.Values("anthropic-beta") + gotBetas = strings.Split(r.Header.Get("anthropic-beta"), ",") gotBody = body }) @@ -165,7 +164,7 @@ func TestNoTaskBudget_UsesStandardPath(t *testing.T) { ) srv := anthropicTestServer(t, func(r *http.Request, _ []byte) { gotPath = r.URL.Path - gotBetas = r.Header.Values("anthropic-beta") + gotBetas = strings.Split(r.Header.Get("anthropic-beta"), ",") }) client := newTestClient(srv, latest.ModelConfig{ @@ -193,7 +192,7 @@ func TestZeroTaskBudget_DisablesFeature(t *testing.T) { var gotBetas []string var gotBody []byte srv := anthropicTestServer(t, func(r *http.Request, body []byte) { - gotBetas = r.Header.Values("anthropic-beta") + gotBetas = strings.Split(r.Header.Get("anthropic-beta"), ",") gotBody = body }) diff --git a/pkg/model/provider/schema_test.go b/pkg/model/provider/schema_test.go index 0c36ed90d..3d18f8f73 100644 --- a/pkg/model/provider/schema_test.go +++ b/pkg/model/provider/schema_test.go @@ -263,6 +263,7 @@ func TestSchemaForAnthropic(t *testing.T) { "type": "string" } }, + "additionalProperties": false, "required": ["repo"] }`, string(schemaJSON)) }