From cd46911258ed8df720938853df8b14905b385dbc Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Tue, 7 Apr 2026 10:28:08 +0200 Subject: [PATCH 1/4] add glob_files tool for finding files by name pattern Adds a new built-in glob_files tool that lets the agent find files by glob pattern (e.g. **/*.go, src/**/*.ts). Results are sorted by modification time and capped at 100 files, matching the behavior of similar tools in other coding agents. Includes TUI rendering component and unit tests. --- pkg/tools/builtin/filesystem.go | 109 ++++++++++++++++++ pkg/tui/components/tool/factory.go | 2 + .../components/tool/globfiles/globfiles.go | 60 ++++++++++ .../tool/globfiles/globfiles_test.go | 99 ++++++++++++++++ 4 files changed, 270 insertions(+) create mode 100644 pkg/tui/components/tool/globfiles/globfiles.go create mode 100644 pkg/tui/components/tool/globfiles/globfiles_test.go diff --git a/pkg/tools/builtin/filesystem.go b/pkg/tools/builtin/filesystem.go index a4b78497a..9d93ac1d9 100644 --- a/pkg/tools/builtin/filesystem.go +++ b/pkg/tools/builtin/filesystem.go @@ -12,9 +12,11 @@ import ( "os/exec" "path/filepath" "regexp" + "sort" "strings" "sync" + "github.com/bmatcuk/doublestar/v4" "github.com/docker/docker-agent/pkg/chat" "github.com/docker/docker-agent/pkg/fsx" "github.com/docker/docker-agent/pkg/shellpath" @@ -31,6 +33,7 @@ const ( ToolNameSearchFilesContent = "search_files_content" ToolNameMkdir = "create_directory" ToolNameRmdir = "remove_directory" + ToolNameGlobFiles = "glob_files" ) // PostEditConfig represents a post-edit command configuration @@ -87,6 +90,7 @@ func (t *FilesystemTool) Instructions() string { - Relative paths resolve from the working directory; absolute paths and ".." work as expected - Prefer read_multiple_files over sequential read_file calls +- Use glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts) - Use search_files_content to locate code or text across files - Use exclude patterns in searches and max_depth in directory_tree to limit output` } @@ -125,6 +129,16 @@ type ListDirectoryArgs struct { Path string `json:"path" jsonschema:"The directory path to list"` } +type GlobFilesArgs struct { + Pattern string `json:"pattern" jsonschema:"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)"` + Path string `json:"path,omitempty" jsonschema:"The directory to search in (defaults to working directory)"` +} + +type GlobFilesMeta struct { + FileCount int `json:"fileCount"` + Truncated bool `json:"truncated"` +} + type CreateDirectoryArgs struct { Paths []string `json:"paths" jsonschema:"Array of directory paths to create"` } @@ -336,6 +350,19 @@ func (t *FilesystemTool) Tools(context.Context) ([]tools.Tool, error) { Title: "Remove Directory", }, }, + { + Name: ToolNameGlobFiles, + Category: "filesystem", + Description: "Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.", + Parameters: tools.MustSchemaFor[GlobFilesArgs](), + OutputSchema: tools.MustSchemaFor[string](), + Handler: tools.NewHandler(t.handleGlobFiles), + Annotations: tools.ToolAnnotations{ + ReadOnlyHint: true, + Title: "Glob Files", + }, + AddDescriptionParameter: true, + }, }, nil } @@ -811,6 +838,88 @@ func (t *FilesystemTool) handleSearchFilesContent(_ context.Context, args Search }, nil } +func (t *FilesystemTool) handleGlobFiles(_ context.Context, args GlobFilesArgs) (*tools.ToolCallResult, error) { + searchDir := t.resolvePath(args.Path) + + info, err := os.Stat(searchDir) + if err != nil { + return tools.ResultError(fmt.Sprintf("Error accessing directory: %s", err)), nil + } + if !info.IsDir() { + return tools.ResultError(fmt.Sprintf("Path is not a directory: %s", args.Path)), nil + } + + // Build the full glob pattern relative to the search directory + fullPattern := filepath.Join(searchDir, args.Pattern) + + matches, err := doublestar.FilepathGlob(fullPattern) + if err != nil { + return tools.ResultError(fmt.Sprintf("Invalid glob pattern: %s", err)), nil + } + + // Filter ignored paths and collect file info for sorting + type fileEntry struct { + relPath string + modTime int64 + } + var entries []fileEntry + + for _, match := range matches { + if t.shouldIgnorePath(match) { + continue + } + + fi, err := os.Stat(match) + if err != nil { + continue + } + // Only return files, not directories + if fi.IsDir() { + continue + } + + relPath, err := filepath.Rel(searchDir, match) + if err != nil { + relPath = match + } + + entries = append(entries, fileEntry{relPath: relPath, modTime: fi.ModTime().UnixNano()}) + } + + // Sort by modification time, most recent first + sort.Slice(entries, func(i, j int) bool { + return entries[i].modTime > entries[j].modTime + }) + + truncated := false + if len(entries) > maxFiles { + entries = entries[:maxFiles] + truncated = true + } + + meta := GlobFilesMeta{ + FileCount: len(entries), + Truncated: truncated, + } + + if len(entries) == 0 { + return &tools.ToolCallResult{ + Output: "No files matched the pattern", + Meta: meta, + }, nil + } + + var result strings.Builder + for _, e := range entries { + fmt.Fprintln(&result, e.relPath) + } + + return &tools.ToolCallResult{ + Output: result.String(), + Meta: meta, + }, nil +} + func (t *FilesystemTool) handleWriteFile(ctx context.Context, args WriteFileArgs) (*tools.ToolCallResult, error) { resolvedPath := t.resolvePath(args.Path) diff --git a/pkg/tui/components/tool/factory.go b/pkg/tui/components/tool/factory.go index 542444bea..1ae6e0605 100644 --- a/pkg/tui/components/tool/factory.go +++ b/pkg/tui/components/tool/factory.go @@ -6,6 +6,7 @@ import ( "github.com/docker/docker-agent/pkg/tui/components/tool/defaulttool" "github.com/docker/docker-agent/pkg/tui/components/tool/directorytree" "github.com/docker/docker-agent/pkg/tui/components/tool/editfile" + "github.com/docker/docker-agent/pkg/tui/components/tool/globfiles" "github.com/docker/docker-agent/pkg/tui/components/tool/handoff" "github.com/docker/docker-agent/pkg/tui/components/tool/listdirectory" "github.com/docker/docker-agent/pkg/tui/components/tool/readfile" @@ -71,6 +72,7 @@ func newDefaultRegistry() *Registry { {[]string{builtin.ToolNameListDirectory}, listdirectory.New}, {[]string{builtin.ToolNameDirectoryTree}, directorytree.New}, {[]string{builtin.ToolNameSearchFilesContent}, searchfilescontent.New}, + {[]string{builtin.ToolNameGlobFiles}, globfiles.New}, {[]string{builtin.ToolNameShell}, shell.New}, {[]string{builtin.ToolNameFetch, "category:api"}, api.New}, { diff --git a/pkg/tui/components/tool/globfiles/globfiles.go b/pkg/tui/components/tool/globfiles/globfiles.go new file mode 100644 index 000000000..73c202688 --- /dev/null +++ b/pkg/tui/components/tool/globfiles/globfiles.go @@ -0,0 +1,60 @@ +package globfiles + +import ( + "fmt" + + "github.com/docker/docker-agent/pkg/tools/builtin" + "github.com/docker/docker-agent/pkg/tui/components/toolcommon" + "github.com/docker/docker-agent/pkg/tui/core/layout" + "github.com/docker/docker-agent/pkg/tui/service" + "github.com/docker/docker-agent/pkg/tui/types" +) + +func New(msg *types.Message, sessionState service.SessionStateReader) layout.Model { + return toolcommon.NewBase(msg, sessionState, toolcommon.SimpleRendererWithResult( + extractArgs, + extractResult, + )) +} + +func extractArgs(args string) string { + parsed, err := toolcommon.ParseArgs[builtin.GlobFilesArgs](args) + if err != nil { + return "" + } + + pattern := parsed.Pattern + if len(pattern) > 40 { + pattern = pattern[:37] + "..." + } + + if parsed.Path != "" && parsed.Path != "." { + return fmt.Sprintf("%s in %s", pattern, toolcommon.ShortenPath(parsed.Path)) + } + return pattern +} + +func extractResult(msg *types.Message) string { + if msg.ToolResult == nil || msg.ToolResult.Meta == nil { + return "no matches" + } + meta, ok := msg.ToolResult.Meta.(builtin.GlobFilesMeta) + if !ok { + return "no matches" + } + + if meta.FileCount == 0 { + return "no matches" + } + + fileWord := "file" + if meta.FileCount != 1 { + fileWord = "files" + } + + result := fmt.Sprintf("%d %s", meta.FileCount, fileWord) + if meta.Truncated { + result += " (truncated)" + } + return result +} diff --git a/pkg/tui/components/tool/globfiles/globfiles_test.go b/pkg/tui/components/tool/globfiles/globfiles_test.go new file mode 100644 index 000000000..c5f61cd26 --- /dev/null +++ b/pkg/tui/components/tool/globfiles/globfiles_test.go @@ -0,0 +1,99 @@ +package globfiles + +import ( + "testing" + + "github.com/docker/docker-agent/pkg/tools" + "github.com/docker/docker-agent/pkg/tools/builtin" + "github.com/docker/docker-agent/pkg/tui/types" +) + +func TestExtractResult(t *testing.T) { + tests := []struct { + name string + meta *builtin.GlobFilesMeta + expected string + }{ + { + name: "nil meta", + meta: nil, + expected: "no matches", + }, + { + name: "zero files", + meta: &builtin.GlobFilesMeta{FileCount: 0}, + expected: "no matches", + }, + { + name: "single file", + meta: &builtin.GlobFilesMeta{FileCount: 1}, + expected: "1 file", + }, + { + name: "multiple files", + meta: &builtin.GlobFilesMeta{FileCount: 42}, + expected: "42 files", + }, + { + name: "truncated results", + meta: &builtin.GlobFilesMeta{FileCount: 100, Truncated: true}, + expected: "100 files (truncated)", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + msg := &types.Message{} + if tt.meta != nil { + msg.ToolResult = &tools.ToolCallResult{Meta: *tt.meta} + } + result := extractResult(msg) + if result != tt.expected { + t.Errorf("extractResult() = %q, want %q", result, tt.expected) + } + }) + } +} + +func TestExtractArgs(t *testing.T) { + tests := []struct { + name string + args string + expected string + }{ + { + name: "simple pattern", + args: `{"pattern": "**/*.go"}`, + expected: "**/*.go", + }, + { + name: "pattern with path", + args: `{"pattern": "*.ts", "path": "src/components"}`, + expected: "*.ts in src/components", + }, + { + name: "pattern with dot path", + args: `{"pattern": "**/*.json", "path": "."}`, + expected: "**/*.json", + }, + { + name: "long pattern gets truncated", + args: `{"pattern": "src/very/deeply/nested/directory/structure/**/*.test.ts"}`, + expected: "src/very/deeply/nested/directory/stru...", + }, + { + name: "invalid json", + args: `invalid`, + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := extractArgs(tt.args) + if result != tt.expected { + t.Errorf("extractArgs(%q) = %q, want %q", tt.args, result, tt.expected) + } + }) + } +} From a36c3e6ac2a2f26cb19c8c9a34a938e60ee59c4f Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Tue, 7 Apr 2026 10:49:15 +0200 Subject: [PATCH 2/4] fix lint errors and update e2e cassettes for glob_files tool - Fix gci import ordering: separate doublestar from internal imports - Fix perfsprint: use string concatenation instead of fmt.Sprintf - Update all 6 e2e cassettes to include glob_files instruction text - Add glob_files tool definition to 5 fs_tools cassettes (OpenAI, Anthropic, Gemini, Mistral) --- e2e/testdata/cassettes/TestExec_Anthropic_ToolCall.yaml | 4 ++-- e2e/testdata/cassettes/TestExec_Gemini_ToolCall.yaml | 4 ++-- e2e/testdata/cassettes/TestExec_Mistral_ToolCall.yaml | 4 ++-- e2e/testdata/cassettes/TestExec_OpenAI_HideToolCalls.yaml | 4 ++-- e2e/testdata/cassettes/TestExec_OpenAI_ToolCall.yaml | 4 ++-- e2e/testdata/cassettes/TestExec_ToolCallsNeedAcceptance.yaml | 4 ++-- pkg/tools/builtin/filesystem.go | 3 ++- 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/e2e/testdata/cassettes/TestExec_Anthropic_ToolCall.yaml b/e2e/testdata/cassettes/TestExec_Anthropic_ToolCall.yaml index 016c89df5..d272a65de 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":"The directory path to traverse (relative to working directory)","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":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"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":"The directory path 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":"The file path to read","type":"string"}},"required":["path"],"type":"object"},"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"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":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","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":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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":"The directory path to traverse (relative to working directory)","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":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"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":"The directory path 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":"The file path to read","type":"string"}},"required":["path"],"type":"object"},"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"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":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","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":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"remove_directory","description":"Remove one or more empty directories."},{"input_schema":{"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"},"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json."}],"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","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":"The directory path to traverse (relative to working directory)","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":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"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":"The directory path 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":"The file path to read","type":"string"}},"required":["path"],"type":"object"},"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"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":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","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":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","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","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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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":"The directory path to traverse (relative to working directory)","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":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"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":"The directory path 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":"The file path to read","type":"string"}},"required":["path"],"type":"object"},"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"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":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","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":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"remove_directory","description":"Remove one or more empty directories."},{"input_schema":{"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"},"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json."}],"stream":true}' url: https://api.anthropic.com/v1/messages method: POST response: diff --git a/e2e/testdata/cassettes/TestExec_Gemini_ToolCall.yaml b/e2e/testdata/cassettes/TestExec_Gemini_ToolCall.yaml index c052029b6..7c40b2583 100644 --- a/e2e/testdata/cassettes/TestExec_Gemini_ToolCall.yaml +++ b/e2e/testdata/cassettes/TestExec_Gemini_ToolCall.yaml @@ -9,7 +9,7 @@ interactions: content_length: 0 host: generativelanguage.googleapis.com body: | - {"contents":[{"parts":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n"}],"role":"user"},{"parts":[{"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"}],"role":"user"},{"parts":[{"text":"How many files in testdata/working_dir? Only output the number."}],"role":"user"}],"generationConfig":{"maxOutputTokens":65536,"thinkingConfig":{"thinkingBudget":0}},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get a recursive tree view of files and directories as a JSON structure.","name":"directory_tree","parameters":{"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},{"description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","name":"edit_file","parameters":{"properties":{"edits":{"description":"Array of edit operations","items":{"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"},"path":{"description":"The file path to edit","type":"string"}},"required":["path","edits"],"type":"object"}},{"description":"Get a detailed listing of all files and directories in a specified path.","name":"list_directory","parameters":{"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","name":"read_file","parameters":{"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the contents of multiple files simultaneously.","name":"read_multiple_files","parameters":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","name":"search_files_content","parameters":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":"array"},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["path","query"],"type":"object"}},{"description":"Create a new file or completely overwrite an existing file with new content.","name":"write_file","parameters":{"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["path","content"],"type":"object"}},{"description":"Create one or more new directories or nested directory structures.","name":"create_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Remove one or more empty directories.","name":"remove_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}}]}]} + {"contents":[{"parts":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n"}],"role":"user"},{"parts":[{"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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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"}],"role":"user"},{"parts":[{"text":"How many files in testdata/working_dir? Only output the number."}],"role":"user"}],"generationConfig":{"maxOutputTokens":65536,"thinkingConfig":{"thinkingBudget":0}},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get a recursive tree view of files and directories as a JSON structure.","name":"directory_tree","parameters":{"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},{"description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","name":"edit_file","parameters":{"properties":{"edits":{"description":"Array of edit operations","items":{"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"},"path":{"description":"The file path to edit","type":"string"}},"required":["path","edits"],"type":"object"}},{"description":"Get a detailed listing of all files and directories in a specified path.","name":"list_directory","parameters":{"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","name":"read_file","parameters":{"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the contents of multiple files simultaneously.","name":"read_multiple_files","parameters":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","name":"search_files_content","parameters":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":"array"},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["path","query"],"type":"object"}},{"description":"Create a new file or completely overwrite an existing file with new content.","name":"write_file","parameters":{"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["path","content"],"type":"object"}},{"description":"Create one or more new directories or nested directory structures.","name":"create_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Remove one or more empty directories.","name":"remove_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","name":"glob_files","parameters":{"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}}]}]} form: alt: - sse @@ -33,7 +33,7 @@ interactions: content_length: 0 host: generativelanguage.googleapis.com body: | - {"contents":[{"parts":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n"}],"role":"user"},{"parts":[{"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"}],"role":"user"},{"parts":[{"text":"How many files in testdata/working_dir? Only output the number."}],"role":"user"},{"parts":[{"functionCall":{"args":{"path":"testdata/working_dir"},"name":"list_directory"},"thoughtSignature":"c2tpcF90aG91Z2h0X3NpZ25hdHVyZV92YWxpZGF0b3I="}],"role":"model"},{"parts":[{"functionResponse":{"name":"call_3df8565b-a1ef-4490-95f9-5d94296d7687","response":{"result":"FILE README.me\n"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":65536,"thinkingConfig":{"thinkingBudget":0}},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get a recursive tree view of files and directories as a JSON structure.","name":"directory_tree","parameters":{"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},{"description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","name":"edit_file","parameters":{"properties":{"edits":{"description":"Array of edit operations","items":{"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"},"path":{"description":"The file path to edit","type":"string"}},"required":["path","edits"],"type":"object"}},{"description":"Get a detailed listing of all files and directories in a specified path.","name":"list_directory","parameters":{"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","name":"read_file","parameters":{"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the contents of multiple files simultaneously.","name":"read_multiple_files","parameters":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","name":"search_files_content","parameters":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":"array"},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["path","query"],"type":"object"}},{"description":"Create a new file or completely overwrite an existing file with new content.","name":"write_file","parameters":{"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["path","content"],"type":"object"}},{"description":"Create one or more new directories or nested directory structures.","name":"create_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Remove one or more empty directories.","name":"remove_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}}]}]} + {"contents":[{"parts":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n"}],"role":"user"},{"parts":[{"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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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"}],"role":"user"},{"parts":[{"text":"How many files in testdata/working_dir? Only output the number."}],"role":"user"},{"parts":[{"functionCall":{"args":{"path":"testdata/working_dir"},"name":"list_directory"},"thoughtSignature":"c2tpcF90aG91Z2h0X3NpZ25hdHVyZV92YWxpZGF0b3I="}],"role":"model"},{"parts":[{"functionResponse":{"name":"call_3df8565b-a1ef-4490-95f9-5d94296d7687","response":{"result":"FILE README.me\n"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":65536,"thinkingConfig":{"thinkingBudget":0}},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get a recursive tree view of files and directories as a JSON structure.","name":"directory_tree","parameters":{"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},{"description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","name":"edit_file","parameters":{"properties":{"edits":{"description":"Array of edit operations","items":{"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"},"path":{"description":"The file path to edit","type":"string"}},"required":["path","edits"],"type":"object"}},{"description":"Get a detailed listing of all files and directories in a specified path.","name":"list_directory","parameters":{"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","name":"read_file","parameters":{"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the contents of multiple files simultaneously.","name":"read_multiple_files","parameters":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","name":"search_files_content","parameters":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":"array"},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["path","query"],"type":"object"}},{"description":"Create a new file or completely overwrite an existing file with new content.","name":"write_file","parameters":{"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["path","content"],"type":"object"}},{"description":"Create one or more new directories or nested directory structures.","name":"create_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Remove one or more empty directories.","name":"remove_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","name":"glob_files","parameters":{"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}}]}]} form: alt: - sse diff --git a/e2e/testdata/cassettes/TestExec_Mistral_ToolCall.yaml b/e2e/testdata/cassettes/TestExec_Mistral_ToolCall.yaml index f919a1245..a7ed011f2 100644 --- a/e2e/testdata/cassettes/TestExec_Mistral_ToolCall.yaml +++ b/e2e/testdata/cassettes/TestExec_Mistral_ToolCall.yaml @@ -8,7 +8,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.mistral.ai - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"mistral-small","max_tokens":32000,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"mistral-small","max_tokens":32000,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.mistral.ai/v1/chat/completions method: POST response: @@ -34,7 +34,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.mistral.ai - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"D9WYdiHxV","function":{"arguments":"{\"path\": \"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"D9WYdiHxV","role":"tool"}],"model":"mistral-small","max_tokens":32000,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"D9WYdiHxV","function":{"arguments":"{\"path\": \"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"D9WYdiHxV","role":"tool"}],"model":"mistral-small","max_tokens":32000,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.mistral.ai/v1/chat/completions method: POST response: diff --git a/e2e/testdata/cassettes/TestExec_OpenAI_HideToolCalls.yaml b/e2e/testdata/cassettes/TestExec_OpenAI_HideToolCalls.yaml index 07c4b47f7..63b519580 100644 --- a/e2e/testdata/cassettes/TestExec_OpenAI_HideToolCalls.yaml +++ b/e2e/testdata/cassettes/TestExec_OpenAI_HideToolCalls.yaml @@ -8,7 +8,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.openai.com - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.openai.com/v1/chat/completions method: POST response: @@ -54,7 +54,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.openai.com - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"call_dsl9jWekN0H1do1ClfeyR1iA","function":{"arguments":"{\"path\":\"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"call_dsl9jWekN0H1do1ClfeyR1iA","role":"tool"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"call_dsl9jWekN0H1do1ClfeyR1iA","function":{"arguments":"{\"path\":\"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"call_dsl9jWekN0H1do1ClfeyR1iA","role":"tool"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.openai.com/v1/chat/completions method: POST response: diff --git a/e2e/testdata/cassettes/TestExec_OpenAI_ToolCall.yaml b/e2e/testdata/cassettes/TestExec_OpenAI_ToolCall.yaml index b610d4289..a063d7e71 100644 --- a/e2e/testdata/cassettes/TestExec_OpenAI_ToolCall.yaml +++ b/e2e/testdata/cassettes/TestExec_OpenAI_ToolCall.yaml @@ -8,7 +8,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.openai.com - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.openai.com/v1/chat/completions method: POST response: @@ -54,7 +54,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.openai.com - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"call_I1tmAsYKD7bveEpXORJwVFgs","function":{"arguments":"{\"path\":\"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"call_I1tmAsYKD7bveEpXORJwVFgs","role":"tool"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"call_I1tmAsYKD7bveEpXORJwVFgs","function":{"arguments":"{\"path\":\"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"call_I1tmAsYKD7bveEpXORJwVFgs","role":"tool"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.openai.com/v1/chat/completions method: POST response: diff --git a/e2e/testdata/cassettes/TestExec_ToolCallsNeedAcceptance.yaml b/e2e/testdata/cassettes/TestExec_ToolCallsNeedAcceptance.yaml index 16d0d51f6..9153e443d 100644 --- a/e2e/testdata/cassettes/TestExec_ToolCallsNeedAcceptance.yaml +++ b/e2e/testdata/cassettes/TestExec_ToolCallsNeedAcceptance.yaml @@ -8,7 +8,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.openai.com - body: '{"input":[{"content":[{"text":"You are a knowledgeable assistant that can write test files.","type":"input_text"}],"role":"system"},{"content":[{"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","type":"input_text"}],"role":"system"},{"content":"Create a hello.txt file with \"Hello, World!\" content. Try only once. On error, exit without further message.","role":"user"}],"model":"gpt-5-mini","reasoning":{"summary":"detailed"},"tools":[{"strict":true,"parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"},"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","type":"function"}],"stream":true}' + body: '{"input":[{"content":[{"text":"You are a knowledgeable assistant that can write test files.","type":"input_text"}],"role":"system"},{"content":[{"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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","type":"input_text"}],"role":"system"},{"content":"Create a hello.txt file with \"Hello, World!\" content. Try only once. On error, exit without further message.","role":"user"}],"model":"gpt-5-mini","reasoning":{"summary":"detailed"},"tools":[{"strict":true,"parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"},"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","type":"function"}],"stream":true}' url: https://api.openai.com/v1/responses method: POST response: @@ -622,7 +622,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.openai.com - body: '{"input":[{"content":[{"text":"You are a knowledgeable assistant that can write test files.","type":"input_text"}],"role":"system"},{"content":[{"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","type":"input_text"}],"role":"system"},{"content":"Create a hello.txt file with \"Hello, World!\" content. Try only once. On error, exit without further message.","role":"user"},{"arguments":"{\"content\":\"Hello, World!\",\"path\":\"hello.txt\"}","call_id":"call_GdIrV330GhotzkZcKWdlNbPV","name":"write_file","type":"function_call"},{"call_id":"call_GdIrV330GhotzkZcKWdlNbPV","output":"The user rejected the tool call.","type":"function_call_output"}],"model":"gpt-5-mini","reasoning":{"summary":"detailed"},"tools":[{"strict":true,"parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"},"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","type":"function"}],"stream":true}' + body: '{"input":[{"content":[{"text":"You are a knowledgeable assistant that can write test files.","type":"input_text"}],"role":"system"},{"content":[{"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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","type":"input_text"}],"role":"system"},{"content":"Create a hello.txt file with \"Hello, World!\" content. Try only once. On error, exit without further message.","role":"user"},{"arguments":"{\"content\":\"Hello, World!\",\"path\":\"hello.txt\"}","call_id":"call_GdIrV330GhotzkZcKWdlNbPV","name":"write_file","type":"function_call"},{"call_id":"call_GdIrV330GhotzkZcKWdlNbPV","output":"The user rejected the tool call.","type":"function_call_output"}],"model":"gpt-5-mini","reasoning":{"summary":"detailed"},"tools":[{"strict":true,"parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"},"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","type":"function"}],"stream":true}' url: https://api.openai.com/v1/responses method: POST response: diff --git a/pkg/tools/builtin/filesystem.go b/pkg/tools/builtin/filesystem.go index 9d93ac1d9..e5ad1b827 100644 --- a/pkg/tools/builtin/filesystem.go +++ b/pkg/tools/builtin/filesystem.go @@ -17,6 +17,7 @@ import ( "sync" "github.com/bmatcuk/doublestar/v4" + "github.com/docker/docker-agent/pkg/chat" "github.com/docker/docker-agent/pkg/fsx" "github.com/docker/docker-agent/pkg/shellpath" @@ -846,7 +847,7 @@ func (t *FilesystemTool) handleGlobFiles(_ context.Context, args GlobFilesArgs) return tools.ResultError(fmt.Sprintf("Error accessing directory: %s", err)), nil } if !info.IsDir() { - return tools.ResultError(fmt.Sprintf("Path is not a directory: %s", args.Path)), nil + return tools.ResultError("Path is not a directory: " + args.Path), nil } // Build the full glob pattern relative to the search directory From 9b3dc31d04f066d8b374248defebf7daeefaf6d5 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Tue, 7 Apr 2026 10:59:02 +0200 Subject: [PATCH 3/4] fix e2e tests: canonicalize JSON in matcher and update cassettes - Add canonicalizeJSON to DefaultMatcher so property ordering in tool definitions doesn't cause mismatches between request and cassette bodies - Update cassette instruction text for new glob_files tool - Add glob_files tool definition to fs_tools cassettes - Fix gci import ordering and perfsprint lint error --- pkg/fake/proxy.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pkg/fake/proxy.go b/pkg/fake/proxy.go index ab0d872f4..a29a80709 100644 --- a/pkg/fake/proxy.go +++ b/pkg/fake/proxy.go @@ -6,6 +6,7 @@ import ( "bufio" "bytes" "context" + "encoding/json" "errors" "fmt" "io" @@ -207,6 +208,21 @@ func RemoveHeadersHook(i *cassette.Interaction) error { return nil } +// canonicalizeJSON parses a JSON string and re-serializes it with sorted map keys. +// This ensures that semantically identical JSON objects match regardless of property ordering. +// Returns the original string if parsing fails (non-JSON bodies pass through unchanged). +func canonicalizeJSON(s string) string { + var v any + if err := json.Unmarshal([]byte(s), &v); err != nil { + return s + } + canonical, err := json.Marshal(v) + if err != nil { + return s + } + return string(canonical) +} + // DefaultMatcher creates a matcher that normalizes dynamic fields for consistent matching. // The onError callback is called if reading the request body fails (nil logs and returns false). func DefaultMatcher(onError func(err error)) recorder.MatcherFunc { @@ -250,6 +266,11 @@ func DefaultMatcher(onError func(err error)) recorder.MatcherFunc { normalizedCassette = maxTokensRegex.ReplaceAllString(normalizedCassette, "") normalizedCassette = thinkingConfigRegex.ReplaceAllString(normalizedCassette, "") + // Canonicalize JSON to handle property ordering differences + // (e.g. tool definitions serialized in different key order by different SDK versions) + normalizedReq = canonicalizeJSON(normalizedReq) + normalizedCassette = canonicalizeJSON(normalizedCassette) + return normalizedReq == normalizedCassette } } From 07b7b4889b8e93fafe285a03ec9e6532f6ad8d21 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Tue, 7 Apr 2026 11:07:14 +0200 Subject: [PATCH 4/4] update e2e cassettes with exact provider-serialized glob_files tool Use actual Go provider SDK serialization for tool definitions: - OpenAI/Mistral: makeAllRequired transforms (path becomes required+nullable) - Anthropic: raw schema preserved - Gemini: raw schema preserved - Revert proxy.go matcher changes (not needed with correct cassettes) - Instruction text updated in all 6 cassettes --- .../TestExec_Anthropic_ToolCall.yaml | 4 ++-- .../cassettes/TestExec_Gemini_ToolCall.yaml | 4 ++-- .../cassettes/TestExec_Mistral_ToolCall.yaml | 4 ++-- .../TestExec_OpenAI_HideToolCalls.yaml | 4 ++-- .../cassettes/TestExec_OpenAI_ToolCall.yaml | 4 ++-- pkg/fake/proxy.go | 21 ------------------- 6 files changed, 10 insertions(+), 31 deletions(-) diff --git a/e2e/testdata/cassettes/TestExec_Anthropic_ToolCall.yaml b/e2e/testdata/cassettes/TestExec_Anthropic_ToolCall.yaml index d272a65de..afe566dab 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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":"The directory path to traverse (relative to working directory)","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":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"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":"The directory path 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":"The file path to read","type":"string"}},"required":["path"],"type":"object"},"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"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":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","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":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"remove_directory","description":"Remove one or more empty directories."},{"input_schema":{"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"},"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json."}],"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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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":"The directory path to traverse (relative to working directory)","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":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"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":"The directory path 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":"The file path to read","type":"string"}},"required":["path"],"type":"object"},"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"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":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","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":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"remove_directory","description":"Remove one or more empty directories."},{"input_schema":{"properties":{"path":{"description":"The directory to search in (defaults to working directory)","type":"string"},"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"}},"required":["pattern"],"type":"object"},"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json."}],"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","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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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":"The directory path to traverse (relative to working directory)","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":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"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":"The directory path 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":"The file path to read","type":"string"}},"required":["path"],"type":"object"},"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"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":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","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":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"remove_directory","description":"Remove one or more empty directories."},{"input_schema":{"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"},"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json."}],"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","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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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":"The directory path to traverse (relative to working directory)","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":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"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":"The directory path 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":"The file path to read","type":"string"}},"required":["path"],"type":"object"},"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly."},{"input_schema":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously."},{"input_schema":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"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":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","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":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"create_directory","description":"Create one or more new directories or nested directory structures."},{"input_schema":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"},"name":"remove_directory","description":"Remove one or more empty directories."},{"input_schema":{"properties":{"path":{"description":"The directory to search in (defaults to working directory)","type":"string"},"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"}},"required":["pattern"],"type":"object"},"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json."}],"stream":true}' url: https://api.anthropic.com/v1/messages method: POST response: diff --git a/e2e/testdata/cassettes/TestExec_Gemini_ToolCall.yaml b/e2e/testdata/cassettes/TestExec_Gemini_ToolCall.yaml index 7c40b2583..8230cbaca 100644 --- a/e2e/testdata/cassettes/TestExec_Gemini_ToolCall.yaml +++ b/e2e/testdata/cassettes/TestExec_Gemini_ToolCall.yaml @@ -9,7 +9,7 @@ interactions: content_length: 0 host: generativelanguage.googleapis.com body: | - {"contents":[{"parts":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n"}],"role":"user"},{"parts":[{"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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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"}],"role":"user"},{"parts":[{"text":"How many files in testdata/working_dir? Only output the number."}],"role":"user"}],"generationConfig":{"maxOutputTokens":65536,"thinkingConfig":{"thinkingBudget":0}},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get a recursive tree view of files and directories as a JSON structure.","name":"directory_tree","parameters":{"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},{"description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","name":"edit_file","parameters":{"properties":{"edits":{"description":"Array of edit operations","items":{"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"},"path":{"description":"The file path to edit","type":"string"}},"required":["path","edits"],"type":"object"}},{"description":"Get a detailed listing of all files and directories in a specified path.","name":"list_directory","parameters":{"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","name":"read_file","parameters":{"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the contents of multiple files simultaneously.","name":"read_multiple_files","parameters":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","name":"search_files_content","parameters":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":"array"},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["path","query"],"type":"object"}},{"description":"Create a new file or completely overwrite an existing file with new content.","name":"write_file","parameters":{"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["path","content"],"type":"object"}},{"description":"Create one or more new directories or nested directory structures.","name":"create_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Remove one or more empty directories.","name":"remove_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","name":"glob_files","parameters":{"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}}]}]} + {"contents":[{"parts":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n"}],"role":"user"},{"parts":[{"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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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"}],"role":"user"},{"parts":[{"text":"How many files in testdata/working_dir? Only output the number."}],"role":"user"}],"generationConfig":{"maxOutputTokens":65536,"thinkingConfig":{"thinkingBudget":0}},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get a recursive tree view of files and directories as a JSON structure.","name":"directory_tree","parameters":{"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},{"description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","name":"edit_file","parameters":{"properties":{"edits":{"description":"Array of edit operations","items":{"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"},"path":{"description":"The file path to edit","type":"string"}},"required":["path","edits"],"type":"object"}},{"description":"Get a detailed listing of all files and directories in a specified path.","name":"list_directory","parameters":{"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","name":"read_file","parameters":{"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the contents of multiple files simultaneously.","name":"read_multiple_files","parameters":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","name":"search_files_content","parameters":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":"array"},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["path","query"],"type":"object"}},{"description":"Create a new file or completely overwrite an existing file with new content.","name":"write_file","parameters":{"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["path","content"],"type":"object"}},{"description":"Create one or more new directories or nested directory structures.","name":"create_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Remove one or more empty directories.","name":"remove_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","name":"glob_files","parameters":{"properties":{"path":{"description":"The directory to search in (defaults to working directory)","type":"string"},"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"}},"required":["pattern"],"type":"object"}}]}]} form: alt: - sse @@ -33,7 +33,7 @@ interactions: content_length: 0 host: generativelanguage.googleapis.com body: | - {"contents":[{"parts":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n"}],"role":"user"},{"parts":[{"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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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"}],"role":"user"},{"parts":[{"text":"How many files in testdata/working_dir? Only output the number."}],"role":"user"},{"parts":[{"functionCall":{"args":{"path":"testdata/working_dir"},"name":"list_directory"},"thoughtSignature":"c2tpcF90aG91Z2h0X3NpZ25hdHVyZV92YWxpZGF0b3I="}],"role":"model"},{"parts":[{"functionResponse":{"name":"call_3df8565b-a1ef-4490-95f9-5d94296d7687","response":{"result":"FILE README.me\n"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":65536,"thinkingConfig":{"thinkingBudget":0}},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get a recursive tree view of files and directories as a JSON structure.","name":"directory_tree","parameters":{"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},{"description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","name":"edit_file","parameters":{"properties":{"edits":{"description":"Array of edit operations","items":{"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"},"path":{"description":"The file path to edit","type":"string"}},"required":["path","edits"],"type":"object"}},{"description":"Get a detailed listing of all files and directories in a specified path.","name":"list_directory","parameters":{"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","name":"read_file","parameters":{"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the contents of multiple files simultaneously.","name":"read_multiple_files","parameters":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","name":"search_files_content","parameters":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":"array"},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["path","query"],"type":"object"}},{"description":"Create a new file or completely overwrite an existing file with new content.","name":"write_file","parameters":{"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["path","content"],"type":"object"}},{"description":"Create one or more new directories or nested directory structures.","name":"create_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Remove one or more empty directories.","name":"remove_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","name":"glob_files","parameters":{"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}}]}]} + {"contents":[{"parts":[{"text":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n"}],"role":"user"},{"parts":[{"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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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"}],"role":"user"},{"parts":[{"text":"How many files in testdata/working_dir? Only output the number."}],"role":"user"},{"parts":[{"functionCall":{"args":{"path":"testdata/working_dir"},"name":"list_directory"},"thoughtSignature":"c2tpcF90aG91Z2h0X3NpZ25hdHVyZV92YWxpZGF0b3I="}],"role":"model"},{"parts":[{"functionResponse":{"name":"call_3df8565b-a1ef-4490-95f9-5d94296d7687","response":{"result":"FILE README.me\n"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":65536,"thinkingConfig":{"thinkingBudget":0}},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get a recursive tree view of files and directories as a JSON structure.","name":"directory_tree","parameters":{"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},{"description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","name":"edit_file","parameters":{"properties":{"edits":{"description":"Array of edit operations","items":{"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["oldText","newText"],"type":"object"},"type":"array"},"path":{"description":"The file path to edit","type":"string"}},"required":["path","edits"],"type":"object"}},{"description":"Get a detailed listing of all files and directories in a specified path.","name":"list_directory","parameters":{"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","name":"read_file","parameters":{"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},{"description":"Read the contents of multiple files simultaneously.","name":"read_multiple_files","parameters":{"properties":{"json":{"description":"Whether to return the result as JSON","type":"boolean"},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","name":"search_files_content","parameters":{"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":"array"},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":"boolean"},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["path","query"],"type":"object"}},{"description":"Create a new file or completely overwrite an existing file with new content.","name":"write_file","parameters":{"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["path","content"],"type":"object"}},{"description":"Create one or more new directories or nested directory structures.","name":"create_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Remove one or more empty directories.","name":"remove_directory","parameters":{"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":"array"}},"required":["paths"],"type":"object"}},{"description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","name":"glob_files","parameters":{"properties":{"path":{"description":"The directory to search in (defaults to working directory)","type":"string"},"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"}},"required":["pattern"],"type":"object"}}]}]} form: alt: - sse diff --git a/e2e/testdata/cassettes/TestExec_Mistral_ToolCall.yaml b/e2e/testdata/cassettes/TestExec_Mistral_ToolCall.yaml index a7ed011f2..592974505 100644 --- a/e2e/testdata/cassettes/TestExec_Mistral_ToolCall.yaml +++ b/e2e/testdata/cassettes/TestExec_Mistral_ToolCall.yaml @@ -8,7 +8,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.mistral.ai - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"mistral-small","max_tokens":32000,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"mistral-small","max_tokens":32000,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory to search in (defaults to working directory)","type":["string","null"]},"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"}},"required":["path","pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.mistral.ai/v1/chat/completions method: POST response: @@ -34,7 +34,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.mistral.ai - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"D9WYdiHxV","function":{"arguments":"{\"path\": \"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"D9WYdiHxV","role":"tool"}],"model":"mistral-small","max_tokens":32000,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"D9WYdiHxV","function":{"arguments":"{\"path\": \"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"D9WYdiHxV","role":"tool"}],"model":"mistral-small","max_tokens":32000,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory to search in (defaults to working directory)","type":["string","null"]},"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"}},"required":["path","pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.mistral.ai/v1/chat/completions method: POST response: diff --git a/e2e/testdata/cassettes/TestExec_OpenAI_HideToolCalls.yaml b/e2e/testdata/cassettes/TestExec_OpenAI_HideToolCalls.yaml index 63b519580..e3b586c4e 100644 --- a/e2e/testdata/cassettes/TestExec_OpenAI_HideToolCalls.yaml +++ b/e2e/testdata/cassettes/TestExec_OpenAI_HideToolCalls.yaml @@ -8,7 +8,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.openai.com - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory to search in (defaults to working directory)","type":["string","null"]},"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"}},"required":["path","pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.openai.com/v1/chat/completions method: POST response: @@ -54,7 +54,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.openai.com - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"call_dsl9jWekN0H1do1ClfeyR1iA","function":{"arguments":"{\"path\":\"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"call_dsl9jWekN0H1do1ClfeyR1iA","role":"tool"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"call_dsl9jWekN0H1do1ClfeyR1iA","function":{"arguments":"{\"path\":\"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"call_dsl9jWekN0H1do1ClfeyR1iA","role":"tool"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory to search in (defaults to working directory)","type":["string","null"]},"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"}},"required":["path","pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.openai.com/v1/chat/completions method: POST response: diff --git a/e2e/testdata/cassettes/TestExec_OpenAI_ToolCall.yaml b/e2e/testdata/cassettes/TestExec_OpenAI_ToolCall.yaml index a063d7e71..e8b6dbf8b 100644 --- a/e2e/testdata/cassettes/TestExec_OpenAI_ToolCall.yaml +++ b/e2e/testdata/cassettes/TestExec_OpenAI_ToolCall.yaml @@ -8,7 +8,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.openai.com - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory to search in (defaults to working directory)","type":["string","null"]},"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"}},"required":["path","pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.openai.com/v1/chat/completions method: POST response: @@ -54,7 +54,7 @@ interactions: proto_minor: 1 content_length: 0 host: api.openai.com - body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"call_I1tmAsYKD7bveEpXORJwVFgs","function":{"arguments":"{\"path\":\"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"call_I1tmAsYKD7bveEpXORJwVFgs","role":"tool"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"},"path":{"description":"The directory to search in (defaults to working directory)","type":"string"}},"required":["pattern"],"type":"object"}},"type":"function"}],"stream":true}' + body: '{"messages":[{"content":"You are a knowledgeable assistant that helps users with various tasks.\nBe helpful, accurate, and concise in your responses.\n","role":"system"},{"content":"## 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 glob_files to find files by name pattern (e.g. **/*.go, src/**/*.ts)\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","role":"system"},{"content":"How many files in testdata/working_dir? Only output the number.","role":"user"},{"tool_calls":[{"id":"call_I1tmAsYKD7bveEpXORJwVFgs","function":{"arguments":"{\"path\":\"testdata/working_dir\"}","name":"list_directory"},"type":"function"}],"role":"assistant"},{"content":"FILE README.me\n","tool_call_id":"call_I1tmAsYKD7bveEpXORJwVFgs","role":"tool"}],"model":"gpt-4o","max_tokens":16384,"stream_options":{"include_usage":true},"tools":[{"function":{"name":"directory_tree","description":"Get a recursive tree view of files and directories as a JSON structure.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to traverse (relative to working directory)","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"edit_file","description":"Make line-based edits to a text file. Each edit replaces exact line sequences with new content.","parameters":{"additionalProperties":false,"properties":{"edits":{"description":"Array of edit operations","items":{"additionalProperties":false,"properties":{"newText":{"description":"The replacement text","type":"string"},"oldText":{"description":"The exact text to replace","type":"string"}},"required":["newText","oldText"],"type":"object"},"type":["null","array"]},"path":{"description":"The file path to edit","type":"string"}},"required":["edits","path"],"type":"object"}},"type":"function"},{"function":{"name":"list_directory","description":"Get a detailed listing of all files and directories in a specified path.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory path to list","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_file","description":"Read the complete contents of a file from the file system. Supports text files and images (jpg, png, gif, webp). Images are returned as image content that you can view directly.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The file path to read","type":"string"}},"required":["path"],"type":"object"}},"type":"function"},{"function":{"name":"read_multiple_files","description":"Read the contents of multiple files simultaneously.","parameters":{"additionalProperties":false,"properties":{"json":{"description":"Whether to return the result as JSON","type":["boolean","null"]},"paths":{"description":"Array of file paths to read","items":{"type":"string"},"type":["null","array"]}},"required":["json","paths"],"type":"object"}},"type":"function"},{"function":{"name":"search_files_content","description":"Searches for text or regex patterns in the content of files matching a GLOB pattern.","parameters":{"additionalProperties":false,"properties":{"excludePatterns":{"description":"Patterns to exclude from search","items":{"type":"string"},"type":["null","array"]},"is_regex":{"description":"If true, treat query as regex; otherwise literal text","type":["boolean","null"]},"path":{"description":"The starting directory path","type":"string"},"query":{"description":"The text or regex pattern to search for","type":"string"}},"required":["excludePatterns","is_regex","path","query"],"type":"object"}},"type":"function"},{"function":{"name":"write_file","description":"Create a new file or completely overwrite an existing file with new content.","parameters":{"additionalProperties":false,"properties":{"content":{"description":"The content to write to the file","type":"string"},"path":{"description":"The file path to write","type":"string"}},"required":["content","path"],"type":"object"}},"type":"function"},{"function":{"name":"create_directory","description":"Create one or more new directories or nested directory structures.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to create","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"remove_directory","description":"Remove one or more empty directories.","parameters":{"additionalProperties":false,"properties":{"paths":{"description":"Array of directory paths to remove","items":{"type":"string"},"type":["null","array"]}},"required":["paths"],"type":"object"}},"type":"function"},{"function":{"name":"glob_files","description":"Find files by glob pattern. Returns matching file paths sorted by modification time. Supports patterns like **/*.go, src/**/*.ts, *.json.","parameters":{"additionalProperties":false,"properties":{"path":{"description":"The directory to search in (defaults to working directory)","type":["string","null"]},"pattern":{"description":"The glob pattern to match files against (e.g. **/*.go, src/**/*.ts)","type":"string"}},"required":["path","pattern"],"type":"object"}},"type":"function"}],"stream":true}' url: https://api.openai.com/v1/chat/completions method: POST response: diff --git a/pkg/fake/proxy.go b/pkg/fake/proxy.go index a29a80709..ab0d872f4 100644 --- a/pkg/fake/proxy.go +++ b/pkg/fake/proxy.go @@ -6,7 +6,6 @@ import ( "bufio" "bytes" "context" - "encoding/json" "errors" "fmt" "io" @@ -208,21 +207,6 @@ func RemoveHeadersHook(i *cassette.Interaction) error { return nil } -// canonicalizeJSON parses a JSON string and re-serializes it with sorted map keys. -// This ensures that semantically identical JSON objects match regardless of property ordering. -// Returns the original string if parsing fails (non-JSON bodies pass through unchanged). -func canonicalizeJSON(s string) string { - var v any - if err := json.Unmarshal([]byte(s), &v); err != nil { - return s - } - canonical, err := json.Marshal(v) - if err != nil { - return s - } - return string(canonical) -} - // DefaultMatcher creates a matcher that normalizes dynamic fields for consistent matching. // The onError callback is called if reading the request body fails (nil logs and returns false). func DefaultMatcher(onError func(err error)) recorder.MatcherFunc { @@ -266,11 +250,6 @@ func DefaultMatcher(onError func(err error)) recorder.MatcherFunc { normalizedCassette = maxTokensRegex.ReplaceAllString(normalizedCassette, "") normalizedCassette = thinkingConfigRegex.ReplaceAllString(normalizedCassette, "") - // Canonicalize JSON to handle property ordering differences - // (e.g. tool definitions serialized in different key order by different SDK versions) - normalizedReq = canonicalizeJSON(normalizedReq) - normalizedCassette = canonicalizeJSON(normalizedCassette) - return normalizedReq == normalizedCassette } }