From 992f28a67d878f27d61190e05b53810c15a38c25 Mon Sep 17 00:00:00 2001 From: David Gageot Date: Thu, 12 Mar 2026 16:39:29 +0100 Subject: [PATCH] Optimize builtin tool instructions for conciseness Apply Claude 4 prompt engineering best practices to all builtin tool instructions: remove meta-commentary and filler, eliminate redundancy with tool descriptions/schemas, use direct bullet points over verbose prose, and frontload critical behavioral guidance. Affected tools: filesystem, shell, think, todo, fetch, memory, deferred, tasks, model_picker, user_prompt, skills, script_shell. Update tests and e2e cassettes to match new instruction text. Assisted-By: docker-agent --- .../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 +- .../TestExec_ToolCallsNeedAcceptance.yaml | 4 +- pkg/session/session_test.go | 4 +- pkg/tools/builtin/deferred.go | 7 +--- pkg/tools/builtin/fetch.go | 2 +- pkg/tools/builtin/filesystem.go | 22 +++------- pkg/tools/builtin/memory.go | 24 +++-------- pkg/tools/builtin/memory_test.go | 4 +- pkg/tools/builtin/model_picker.go | 8 ++-- pkg/tools/builtin/script_shell.go | 30 ++++++------- pkg/tools/builtin/shell.go | 13 +++++- pkg/tools/builtin/shell_instructions.go | 42 ------------------- pkg/tools/builtin/shell_test.go | 2 +- pkg/tools/builtin/skills.go | 40 +++++++----------- pkg/tools/builtin/tasks.go | 8 ++-- pkg/tools/builtin/think.go | 12 +++--- pkg/tools/builtin/todo.go | 29 ++++--------- pkg/tools/builtin/user_prompt.go | 19 +++------ 22 files changed, 98 insertions(+), 192 deletions(-) delete mode 100644 pkg/tools/builtin/shell_instructions.go diff --git a/e2e/testdata/cassettes/TestExec_Anthropic_ToolCall.yaml b/e2e/testdata/cassettes/TestExec_Anthropic_ToolCall.yaml index 267f14704..016c89df5 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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations","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 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}' 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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations","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 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}' 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 81dd26a5a..9a266e195 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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations"}],"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 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"}}]}]} 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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations"}],"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"}}],"role":"model"},{"parts":[{"functionResponse":{"name":"call_1338bc52-c261-432d-b5e5-9dfb8f9c13bb","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 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"}}],"role":"model"},{"parts":[{"functionResponse":{"name":"call_1338bc52-c261-432d-b5e5-9dfb8f9c13bb","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"}}]}]} form: alt: - sse diff --git a/e2e/testdata/cassettes/TestExec_Mistral_ToolCall.yaml b/e2e/testdata/cassettes/TestExec_Mistral_ToolCall.yaml index be3458780..f919a1245 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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations","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 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}' 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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations","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 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}' 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 a27d99c90..07c4b47f7 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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations","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 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}' 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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations","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 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}' 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 fc720b196..b610d4289 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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations","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 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}' 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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations","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 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}' 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 c9dac0975..eaee64095 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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations","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","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 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","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: @@ -91,7 +91,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 Tool Instructions\n\nThis toolset provides comprehensive filesystem operations.\n\n### Working Directory\n- Relative paths (like \".\" or \"src/main.go\") are resolved relative to the working directory\n- Absolute paths (like \"/etc/hosts\") access files directly\n- Paths starting with \"..\" can access parent directories\n\n### Common Patterns\n- Always check if directories exist before creating files\n- Prefer read_multiple_files for batch operations\n- Use search_files_content for finding specific code or text\n\n### Performance Tips\n- Use read_multiple_files instead of multiple read_file calls\n- Use directory_tree with max_depth to limit large traversals\n- Use appropriate exclude patterns in search operations","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_5W18F6XkDh9NllAH9r0P9GuF","name":"write_file","type":"function_call"},{"call_id":"call_5W18F6XkDh9NllAH9r0P9GuF","output":"The user rejected the tool call.","type":"function_call_output"}],"model":"gpt-5-mini","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 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_5W18F6XkDh9NllAH9r0P9GuF","name":"write_file","type":"function_call"},{"call_id":"call_5W18F6XkDh9NllAH9r0P9GuF","output":"The user rejected the tool call.","type":"function_call_output"}],"model":"gpt-5-mini","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/session/session_test.go b/pkg/session/session_test.go index 2b802edf0..724294c5c 100644 --- a/pkg/session/session_test.go +++ b/pkg/session/session_test.go @@ -181,7 +181,7 @@ func TestGetMessages_CacheControl(t *testing.T) { assert.Equal(t, "instructions", messages[0].Content) assert.False(t, messages[0].CacheControl) - assert.Contains(t, messages[1].Content, "Using the Todo Tools") + assert.Contains(t, messages[1].Content, "Todo Tools") assert.True(t, messages[1].CacheControl) } @@ -212,7 +212,7 @@ func TestGetMessages_CacheControlWithSummary(t *testing.T) { assert.Len(t, checkpointIndices, 2, "should have 2 checkpoints") // Verify checkpoint #1 is on toolset instructions - assert.Contains(t, messages[checkpointIndices[0]].Content, "Using the Todo Tools", "checkpoint #1 should be on toolset instructions") + assert.Contains(t, messages[checkpointIndices[0]].Content, "Todo Tools", "checkpoint #1 should be on toolset instructions") // Verify checkpoint #2 is on date assert.Contains(t, messages[checkpointIndices[1]].Content, "Today's date", "checkpoint #2 should be on date message") diff --git a/pkg/tools/builtin/deferred.go b/pkg/tools/builtin/deferred.go index de42d1a4d..5866a0093 100644 --- a/pkg/tools/builtin/deferred.go +++ b/pkg/tools/builtin/deferred.go @@ -66,12 +66,9 @@ func (d *DeferredToolset) HasSources() bool { } func (d *DeferredToolset) Instructions() string { - return `## Deferred Tool Loading + return `## Deferred Tools -Additional tools can be discovered and loaded on-demand. - -Use search_tool to find tools by action keywords (e.g., "remote", "read", "write"). Prefer single words to maximize matches. -Use add_tool to activate a discovered tool.` +Use search_tool to discover additional tools by keyword (e.g., "remote", "read", "write"). Use add_tool to activate a discovered tool.` } type SearchToolArgs struct { diff --git a/pkg/tools/builtin/fetch.go b/pkg/tools/builtin/fetch.go index 45965b924..770458f0a 100644 --- a/pkg/tools/builtin/fetch.go +++ b/pkg/tools/builtin/fetch.go @@ -284,7 +284,7 @@ func WithTimeout(timeout time.Duration) FetchToolOption { func (t *FetchTool) Instructions() string { return `## Fetch Tool -Fetch content from HTTP/HTTPS URLs. Supports multiple URLs in a single call, output format selection (text, markdown, html), and respects robots.txt.` +Fetch content from HTTP/HTTPS URLs. Supports multiple URLs per call, output format selection (text, markdown, html), and respects robots.txt.` } func (t *FetchTool) Tools(context.Context) ([]tools.Tool, error) { diff --git a/pkg/tools/builtin/filesystem.go b/pkg/tools/builtin/filesystem.go index 080de81e6..938d1cec4 100644 --- a/pkg/tools/builtin/filesystem.go +++ b/pkg/tools/builtin/filesystem.go @@ -78,24 +78,12 @@ func NewFilesystemTool(workingDir string, opts ...FileSystemOpt) *FilesystemTool } func (t *FilesystemTool) Instructions() string { - return `## Filesystem Tool Instructions + return `## Filesystem Tools -This toolset provides comprehensive filesystem operations. - -### Working Directory -- Relative paths (like "." or "src/main.go") are resolved relative to the working directory -- Absolute paths (like "/etc/hosts") access files directly -- Paths starting with ".." can access parent directories - -### Common Patterns -- Always check if directories exist before creating files -- Prefer read_multiple_files for batch operations -- Use search_files_content for finding specific code or text - -### Performance Tips -- Use read_multiple_files instead of multiple read_file calls -- Use directory_tree with max_depth to limit large traversals -- Use appropriate exclude patterns in search operations` +- Relative paths resolve from the working directory; absolute paths and ".." work as expected +- Prefer read_multiple_files over sequential read_file calls +- 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` } type DirectoryTreeArgs struct { diff --git a/pkg/tools/builtin/memory.go b/pkg/tools/builtin/memory.go index abcd11fca..e1445f11e 100644 --- a/pkg/tools/builtin/memory.go +++ b/pkg/tools/builtin/memory.go @@ -83,26 +83,14 @@ type UpdateMemoryArgs struct { } func (t *MemoryTool) Instructions() string { - return `## Using the memory tool + return `## Memory Tools -Before taking any action or responding, check stored memories for relevant context. -Use the memory tool generously to remember things about the user. Do not mention using this tool. +Check stored memories for relevant context before acting. Store useful information silently — never mention using this tool. -### When to remember -- User preferences, corrections, and explicit requests to remember something -- Key facts, decisions, and context that may be useful in future conversations -- Project-specific conventions and patterns - -### Categories -Organize memories with a category when adding or updating (e.g. "preference", "fact", "project", "decision"). - -### Searching vs getting all -- Use "search_memories" with keywords and/or a category to find specific memories efficiently. -- Use "get_memories" only when you need a full dump of all stored memories. - -### Updating vs creating -- Use "update_memory" to edit an existing memory by ID instead of deleting and re-adding. -- Use "add_memory" only for genuinely new information.` +- Remember: user preferences, corrections, key decisions, project conventions +- Use search_memories with keywords/category for targeted lookup; use get_memories only for a full dump +- Use update_memory to edit existing entries; use add_memory only for new information +- Organize with categories: "preference", "fact", "project", "decision"` } func (t *MemoryTool) Tools(context.Context) ([]tools.Tool, error) { diff --git a/pkg/tools/builtin/memory_test.go b/pkg/tools/builtin/memory_test.go index 73288ae01..141ce2739 100644 --- a/pkg/tools/builtin/memory_test.go +++ b/pkg/tools/builtin/memory_test.go @@ -49,10 +49,10 @@ func TestMemoryTool_Instructions(t *testing.T) { tool := NewMemoryTool(manager) instructions := tool.Instructions() - assert.Contains(t, instructions, "Using the memory tool") + assert.Contains(t, instructions, "Memory Tools") assert.Contains(t, instructions, "search_memories") assert.Contains(t, instructions, "update_memory") - assert.Contains(t, instructions, "Categories") + assert.Contains(t, instructions, "preference") } func TestMemoryTool_DisplayNames(t *testing.T) { diff --git a/pkg/tools/builtin/model_picker.go b/pkg/tools/builtin/model_picker.go index b820748cd..8dd62910f 100644 --- a/pkg/tools/builtin/model_picker.go +++ b/pkg/tools/builtin/model_picker.go @@ -37,12 +37,10 @@ func NewModelPickerTool(models []string) *ModelPickerTool { // Instructions returns guidance for the LLM on when and how to use the model picker tools. func (t *ModelPickerTool) Instructions() string { return "## Model Switching\n\n" + - "You have access to multiple models and can switch between them mid-conversation " + - "using the `" + ToolNameChangeModel + "` and `" + ToolNameRevertModel + "` tools.\n\n" + "Available models: " + strings.Join(t.models, ", ") + ".\n\n" + - "Use `" + ToolNameChangeModel + "` when the current task would benefit from a different model's strengths " + - "(e.g., switching to a faster model for simple tasks or a more capable model for complex reasoning).\n" + - "Use `" + ToolNameRevertModel + "` to return to the original model after the specialized task is complete." + "Use `" + ToolNameChangeModel + "` to switch to a model better suited for the current task " + + "(e.g., faster model for simple tasks, more capable model for complex reasoning).\n" + + "Use `" + ToolNameRevertModel + "` to return to the original model when done." } // AllowedModels returns the list of models this tool allows switching to. diff --git a/pkg/tools/builtin/script_shell.go b/pkg/tools/builtin/script_shell.go index f2f18e44c..4753cd717 100644 --- a/pkg/tools/builtin/script_shell.go +++ b/pkg/tools/builtin/script_shell.go @@ -71,33 +71,29 @@ func validateConfig(toolName string, tool latest.ScriptShellToolConfig) error { } func (t *ScriptShellTool) Instructions() string { - var instructions strings.Builder - instructions.WriteString("## Custom Shell Tools\n\n") - instructions.WriteString("The following custom shell tools are available:\n\n") + var sb strings.Builder + sb.WriteString("## Custom Shell Tools\n\n") for name, tool := range t.shellTools { - fmt.Fprintf(&instructions, "### %s\n", name) + fmt.Fprintf(&sb, "### %s\n", name) if tool.Description != "" { - fmt.Fprintf(&instructions, "%s\n\n", tool.Description) + fmt.Fprintf(&sb, "%s\n", tool.Description) } else { - fmt.Fprintf(&instructions, "Execute: `%s`\n\n", tool.Cmd) + fmt.Fprintf(&sb, "Runs: `%s`\n", tool.Cmd) } - if len(tool.Args) > 0 { - instructions.WriteString("**Parameters:**\n") - for argName, argDef := range tool.Args { - required := "" - if slices.Contains(tool.Required, argName) { - required = " (required)" - } - description := argDef.(map[string]any)["description"].(string) - fmt.Fprintf(&instructions, "- `%s`: %s%s\n", argName, description, required) + for argName, argDef := range tool.Args { + description := argDef.(map[string]any)["description"].(string) + required := "" + if slices.Contains(tool.Required, argName) { + required = " (required)" } - instructions.WriteString("\n") + fmt.Fprintf(&sb, "- `%s`: %s%s\n", argName, description, required) } + sb.WriteString("\n") } - return instructions.String() + return sb.String() } func (t *ScriptShellTool) Tools(context.Context) ([]tools.Tool, error) { diff --git a/pkg/tools/builtin/shell.go b/pkg/tools/builtin/shell.go index 6efd6c917..f543aafe2 100644 --- a/pkg/tools/builtin/shell.go +++ b/pkg/tools/builtin/shell.go @@ -392,7 +392,18 @@ func formatCommandOutput(timeoutCtx, ctx context.Context, err error, rawOutput s } func (t *ShellTool) Instructions() string { - return nativeInstructions + return `## Shell Tools + +- Each call runs in a fresh shell session — no state persists between calls +- Default timeout: 30s. Set "timeout" for longer operations (builds, tests) +- Use "cwd" parameter instead of cd within commands +- Combine operations with pipes, redirections, and heredocs +- For git commits, add trailer: git commit -m "message" -m "" -m "Assisted-By: docker-agent" +- Non-zero exit codes return error info with output; timed-out commands are terminated + +### Background Jobs + +Use run_background_job for long-running processes (servers, watchers). Output capped at 10MB per job. All jobs auto-terminate when the agent stops.` } func (t *ShellTool) Tools(context.Context) ([]tools.Tool, error) { diff --git a/pkg/tools/builtin/shell_instructions.go b/pkg/tools/builtin/shell_instructions.go deleted file mode 100644 index 137f4ac5e..000000000 --- a/pkg/tools/builtin/shell_instructions.go +++ /dev/null @@ -1,42 +0,0 @@ -package builtin - -// nativeInstructions contains the usage guide for native shell mode. -const nativeInstructions = `# Shell Tool Usage Guide - -Execute shell commands in the user's environment with full control over working directories and command parameters. - -## Core Concepts - -- Commands run in the user's default shell (Unix: ${SHELL} or /bin/sh; Windows: pwsh/powershell or cmd.exe) -- Each call creates a fresh shell session — no state persists between executions -- Default working directory: agent's working directory. Override with "cwd" parameter (absolute or relative paths) -- Default timeout: 30s. Use "timeout" parameter for longer operations (e.g., builds, tests) - -## Best Practices - -- Use "cwd" instead of cd within commands -- Quote arguments with spaces or special characters -- Use pipes, redirections, and heredocs to combine operations -- Prefer inline heredocs over writing shell scripts to disk -- For git commits, add trailer: git commit -m "message" -m "" -m "Assisted-By: docker-agent" - -## Examples - -{ "cmd": "go test ./...", "cwd": ".", "timeout": 180 } -{ "cmd": "grep -r 'TODO' src/", "cwd": "." } -{ "cmd": "cat << 'EOF' | ${SHELL}\necho Hello\nEOF" } - -## Error Handling - -Non-zero exit codes return error info with output. Timed-out commands are terminated automatically. - -# Background Jobs - -Use background jobs for long-running processes (servers, watchers) that should run while other tasks are performed. - -- **run_background_job**: Start a command, returns job ID. Example: { "cmd": "npm run dev", "cwd": "frontend" } -- **list_background_jobs**: Show all jobs with status and runtime -- **view_background_job**: Get output and status of a job by job_id -- **stop_background_job**: Terminate a job and all its child processes by job_id - -**Notes**: Output capped at 10MB per job. Jobs inherit env vars at start time. All jobs auto-terminate when the agent stops.` diff --git a/pkg/tools/builtin/shell_test.go b/pkg/tools/builtin/shell_test.go index 51485e354..4de61fb82 100644 --- a/pkg/tools/builtin/shell_test.go +++ b/pkg/tools/builtin/shell_test.go @@ -131,7 +131,7 @@ func TestShellTool_Instructions(t *testing.T) { instructions := tool.Instructions() // Check that native instructions are returned - assert.Contains(t, instructions, "Shell Tool Usage Guide") + assert.Contains(t, instructions, "Shell Tools") } func TestResolveWorkDir(t *testing.T) { diff --git a/pkg/tools/builtin/skills.go b/pkg/tools/builtin/skills.go index 635df747b..e802e6fde 100644 --- a/pkg/tools/builtin/skills.go +++ b/pkg/tools/builtin/skills.go @@ -135,29 +135,28 @@ func (s *SkillsToolset) handleReadSkillFile(_ context.Context, args readSkillFil return tools.ResultSuccess(content), nil } -func (s *SkillsToolset) Instructions() string { - if len(s.skills) == 0 { - return "" - } - - hasFiles := false +// hasFiles reports whether any loaded skill has supporting files beyond SKILL.md. +func (s *SkillsToolset) hasFiles() bool { for _, skill := range s.skills { if len(skill.Files) > 1 { - hasFiles = true - break + return true } } + return false +} + +func (s *SkillsToolset) Instructions() string { + if len(s.skills) == 0 { + return "" + } var sb strings.Builder - sb.WriteString("The following skills provide specialized instructions for specific tasks. ") - sb.WriteString("Each skill's description indicates what it does and when to use it.\n\n") - sb.WriteString("When a user's request matches a skill's description, use the read_skill tool to load the skill's content. ") - sb.WriteString("The content contains detailed instructions to follow for that task.\n\n") + sb.WriteString("Skills provide specialized instructions for specific tasks. ") + sb.WriteString("When a user's request matches a skill's description, use read_skill to load its instructions.\n\n") - if hasFiles { - sb.WriteString("Some skills reference supporting files (scripts, documentation, templates). ") - sb.WriteString("When skill instructions reference a file path, use the read_skill_file tool to load it on demand. ") - sb.WriteString("Do not load all files upfront — only load them as needed.\n\n") + if s.hasFiles() { + sb.WriteString("Some skills have supporting files. ") + sb.WriteString("Use read_skill_file to load referenced files on demand — do not preload them.\n\n") } sb.WriteString("\n") @@ -213,14 +212,7 @@ func (s *SkillsToolset) Tools(context.Context) ([]tools.Tool, error) { } // Only expose read_skill_file if any skill has supporting files - hasFiles := false - for _, skill := range s.skills { - if len(skill.Files) > 1 { - hasFiles = true - break - } - } - if hasFiles { + if s.hasFiles() { result = append(result, tools.Tool{ Name: ToolNameReadSkillFile, Category: "skills", diff --git a/pkg/tools/builtin/tasks.go b/pkg/tools/builtin/tasks.go index d4817bc63..00804fda8 100644 --- a/pkg/tools/builtin/tasks.go +++ b/pkg/tools/builtin/tasks.go @@ -106,13 +106,11 @@ func NewTasksTool(storagePath string) *TasksTool { } func (t *TasksTool) Instructions() string { - return `## Using the Tasks Tools + return `## Task Tools -Persistent task management with priorities (critical > high > medium > low), statuses (pending, in_progress, done, blocked), and dependencies. +Persistent task management with priorities (critical > high > medium > low), statuses (pending, in_progress, done, blocked), and dependencies. Tasks persist across sessions. -Tasks are saved to a JSON file and survive across sessions. A task is automatically blocked if any dependency is not done. - -Workflow: create_task → list_tasks/next_task → update_task as work progresses. Use add_dependency/remove_dependency to manage ordering.` +A task is automatically blocked if any dependency is not done. Use next_task to get the highest-priority actionable task.` } func (t *TasksTool) load() taskStore { diff --git a/pkg/tools/builtin/think.go b/pkg/tools/builtin/think.go index 78e38dd0a..0c7db6e6a 100644 --- a/pkg/tools/builtin/think.go +++ b/pkg/tools/builtin/think.go @@ -33,13 +33,13 @@ func NewThinkTool() *ThinkTool { } func (t *ThinkTool) Instructions() string { - return `## Using the think tool + return `## Think Tool -Use the think tool as a scratchpad before acting or responding. Use it to: -- List rules that apply to the current request -- Check if all required information is collected -- Verify planned actions comply with policies -- Iterate over tool results for correctness` +Use the think tool as a scratchpad before acting. Think to: +- Check which rules or policies apply +- Verify you have all required information +- Validate planned actions before executing +- Reason through complex multi-step problems` } func (t *ThinkTool) Tools(context.Context) ([]tools.Tool, error) { diff --git a/pkg/tools/builtin/todo.go b/pkg/tools/builtin/todo.go index 14d9a6bf9..6d412a716 100644 --- a/pkg/tools/builtin/todo.go +++ b/pkg/tools/builtin/todo.go @@ -164,27 +164,14 @@ func NewTodoTool(opts ...TodoOption) *TodoTool { } func (t *TodoTool) Instructions() string { - return `## Using the Todo Tools - -IMPORTANT: You MUST use these tools to track the progress of your tasks: - -1. Before starting any complex task: - - Create a todo for each major step using create_todos (prefer batch creation) - - Break down complex steps into smaller todos - -2. While working: - - Update todo status to "in-progress" BEFORE starting each task - - Mark todos as "completed" IMMEDIATELY after finishing each task - - Use list_todos frequently to keep track of remaining work - -3. Task Completion Rules: - - EVERY todo you create MUST eventually be marked "completed" - - Before sending your final response, call list_todos to verify ALL todos are completed - - If any todos remain pending or in-progress, complete them or mark them completed before responding - - Never leave todos in a pending or in-progress state when you are done working - - When updating multiple todos, batch them in a single update_todos call - -This toolset is REQUIRED for maintaining task state and ensuring all steps are completed.` + return `## Todo Tools + +Track task progress with todos: +- Create todos for each major step before starting complex work (prefer batch create_todos) +- Update status to "in-progress" before starting, "completed" immediately after finishing +- Every todo MUST be marked "completed" before your final response +- Batch multiple updates in a single update_todos call +- Never leave todos pending or in-progress when done` } // addTodo creates a new todo and adds it to storage. diff --git a/pkg/tools/builtin/user_prompt.go b/pkg/tools/builtin/user_prompt.go index fe5991d9d..95caab47c 100644 --- a/pkg/tools/builtin/user_prompt.go +++ b/pkg/tools/builtin/user_prompt.go @@ -81,22 +81,15 @@ func (t *UserPromptTool) userPrompt(ctx context.Context, params UserPromptArgs) } func (t *UserPromptTool) Instructions() string { - return `## Using the user_prompt tool + return `## User Prompt Tool -Use user_prompt to ask the user a question or gather input when you need clarification, specific information, or a decision. +Ask the user a question when you need clarification, input, or a decision. -Optionally provide a "title" to label the dialog (defaults to "Question"). +Optionally provide a JSON schema to structure the response: +- Enum: {"type": "string", "enum": ["option1", "option2"], "title": "Select"} +- Object: {"type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"]} -Optionally provide a JSON schema to structure the expected response (object, primitive, or enum types). -If no schema is provided, the user can type a free-form response. - -Example schema for multiple choice: -{"type": "string", "enum": ["option1", "option2"], "title": "Select an option"} - -Example schema for structured input: -{"type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"]} - -Response contains "action" (accept/decline/cancel) and "content" (user data, only when accepted).` +Response contains "action" (accept/decline/cancel) and "content" (user data when accepted).` } func (t *UserPromptTool) Tools(context.Context) ([]tools.Tool, error) {