Pashpashpash/bash tool (#3894)

* bashTool

* prettier

* alignment

* bashtool cont

* bash tool cont

* modularizing prompt a bit

* bash tool working

* bash tool now getting cwd

* bashTool

* forgot .name

---------

Co-authored-by: Cline Evaluation <cline@example.com>
This commit is contained in:
pashpashpash 2025-05-29 20:09:07 -07:00 committed by GitHub
parent f1fef24f25
commit 915cf76f85
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 255 additions and 363 deletions

View File

@ -5,4 +5,3 @@ webview-ui/build/
package-lock.json
src/core/prompts/system.ts
src/core/prompts/model_prompts/claude4.ts
src/core/prompts/model_prompts/jsonToolToXml.ts

View File

@ -569,6 +569,15 @@ export function parseAssistantMessageV3(assistantMessage: string): AssistantMess
}
}
if (currentInvokeName === "Bash") {
currentToolUse = {
type: "tool_use",
name: "execute_command",
params: {},
partial: true,
}
}
continue
}
}
@ -621,6 +630,14 @@ export function parseAssistantMessageV3(assistantMessage: string): AssistantMess
}
}
if (currentToolUse && currentInvokeName === "Bash") {
if (currentParameterName === "command") {
currentToolUse.params["command"] = value
} else if (currentParameterName === "requires_approval") {
currentToolUse.params["requires_approval"] = value === "true" ? "true" : "false"
}
}
currentParameterName = ""
continue
}
@ -633,7 +650,7 @@ export function parseAssistantMessageV3(assistantMessage: string): AssistantMess
assistantMessage.startsWith(isInvokeClose, currentCharIndex - isInvokeClose.length + 1)
) {
// If we have a tool use from this invoke, finalize it
if (currentToolUse && (currentInvokeName === "LS" || currentInvokeName === "Grep")) {
if (currentToolUse && (currentInvokeName === "LS" || currentInvokeName === "Grep" || currentInvokeName === "Bash")) {
currentToolUse.partial = false
contentBlocks.push(currentToolUse)
currentToolUse = undefined

View File

@ -17,6 +17,8 @@ export const SYSTEM_PROMPT_CLAUDE4 = async (
mcpHub: McpHub,
browserSettings: BrowserSettings,
) => {
const bashTool = bashToolDefinition(cwd);
const systemPrompt = `You are Cline, a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.
====
@ -45,17 +47,6 @@ Always adhere to this format for the tool use to ensure proper parsing and execu
# Tools
## execute_command
Description: Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: ${cwd.toPosix()}
Parameters:
- command: (required) The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.
- requires_approval: (required) A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.
Usage:
<execute_command>
<command>Your command here</command>
<requires_approval>true or false</requires_approval>
</execute_command>
## read_file
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string.
Parameters:
@ -253,14 +244,7 @@ Usage:
# Tool Use Examples
## Example 1: Requesting to execute a command
<execute_command>
<command>npm run dev</command>
<requires_approval>false</requires_approval>
</execute_command>
## Example 2: Requesting to create a new file
## Example 1: Requesting to create a new file
<write_to_file>
<path>src/frontend-config.json</path>
@ -282,7 +266,7 @@ Usage:
</content>
</write_to_file>
## Example 3: Creating a new task
## Example 2: Creating a new task
<new_task>
<context>
@ -313,7 +297,7 @@ Usage:
</context>
</new_task>
## Example 4: Requesting to make targeted edits to a file
## Example 3: Requesting to make targeted edits to a file
<replace_in_file>
@ -339,7 +323,7 @@ Usage:
</replace_in_file>
## Example 5: Requesting to use an MCP tool
## Example 4: Requesting to use an MCP tool
<use_mcp_tool>
<server_name>weather-server</server_name>
@ -352,7 +336,7 @@ Usage:
</arguments>
</use_mcp_tool>
## Example 6: Another example of using an MCP tool (where the server name is a unique identifier such as a URL)
## Example 5: Another example of using an MCP tool (where the server name is a unique identifier such as a URL)
<use_mcp_tool>
<server_name>github.com/modelcontextprotocol/servers/tree/main/src/github</server_name>
@ -531,7 +515,7 @@ In each user message, the environment_details will specify the current mode. The
## What is PLAN MODE?
- While you are usually in ACT MODE, the user may switch to PLAN MODE in order to have a back and forth with you to plan how to best accomplish the task.
- When starting in PLAN MODE, depending on the user's request, you may need to do some information gathering e.g. using read_file or Grep to get more context about the task. You may also ask the user clarifying questions to get a better understanding of the task. You may return mermaid diagrams to visually display your understanding.
- When starting in PLAN MODE, depending on the user's request, you may need to do some information gathering e.g. using read_file or ${grepToolDefinition.name} to get more context about the task. You may also ask the user clarifying questions to get a better understanding of the task. You may return mermaid diagrams to visually display your understanding.
- Once you've gained more context about the user's request, you should architect a detailed plan for how you will accomplish the task. Returning mermaid diagrams may be helpful here as well.
- Then you might ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.
- If at any point a mermaid diagram would make your plan clearer to help the user quickly see the structure, you are encouraged to include a Mermaid code block in the response. (Note: if you use colors in your mermaid diagrams, be sure to use high contrast colors so the text is readable.)
@ -545,12 +529,12 @@ CAPABILITIES
supportsBrowserUse ? ", use the browser" : ""
}, read and edit files, and ask follow-up questions. These tools help you effectively accomplish a wide range of tasks, such as writing code, making edits or improvements to existing files, understanding the current state of a project, performing system operations, and much more.
- When the user initially gives you a task, a recursive list of all filepaths in the current working directory ('${cwd.toPosix()}') will be included in environment_details. This provides an overview of the project's file structure, offering key insights into the project from directory/file names (how developers conceptualize and organize their code) and file extensions (the language used). This can also guide decision-making on which files to explore further. If you pass 'true' for the recursive parameter, it will list files recursively. Otherwise, it will list files at the top level, which is better suited for generic directories where you don't necessarily need the nested structure, like the Desktop.
- You can use Grep to perform regex searches across files in a specified directory, outputting context-rich results that include surrounding lines. This is particularly useful for understanding code patterns, finding specific implementations, or identifying areas that need refactoring.
- You can use ${grepToolDefinition.name} to perform regex searches across files in a specified directory, outputting context-rich results that include surrounding lines. This is particularly useful for understanding code patterns, finding specific implementations, or identifying areas that need refactoring.
- You can use the list_code_definition_names tool to get an overview of source code definitions for all files at the top level of a specified directory. This can be particularly useful when you need to understand the broader context and relationships between certain parts of the code. You may need to call this tool multiple times to understand various parts of the codebase related to the task.
- For example, when asked to make edits or improvements you might analyze the file structure in the initial environment_details to get an overview of the project, then use list_code_definition_names to get further insight using source code definitions for files located in relevant directories, then read_file to examine the contents of relevant files, analyze the code and suggest improvements or make necessary edits, then use the replace_in_file tool to implement changes. If you refactored code that could affect other parts of the codebase, you could use Grep to ensure you update other files as needed.
- You can use the execute_command tool to run commands on the user's computer whenever you feel it can help accomplish the user's task. When you need to execute a CLI command, you must provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, since they are more flexible and easier to run. Interactive and long-running commands are allowed, since the commands are run in the user's VSCode terminal. The user may keep commands running in the background and you will be kept updated on their status along the way. Each command you execute is run in a new terminal instance.${
- For example, when asked to make edits or improvements you might analyze the file structure in the initial environment_details to get an overview of the project, then use list_code_definition_names to get further insight using source code definitions for files located in relevant directories, then read_file to examine the contents of relevant files, analyze the code and suggest improvements or make necessary edits, then use the replace_in_file tool to implement changes. If you refactored code that could affect other parts of the codebase, you could use ${grepToolDefinition.name} to ensure you update other files as needed.
- You can use the ${bashTool.name} tool to run commands on the user's computer whenever you feel it can help accomplish the user's task. When you need to execute a CLI command, you must provide a clear explanation of what the command does. Prefer to execute complex CLI commands over creating executable scripts, since they are more flexible and easier to run. Interactive and long-running commands are allowed, since the commands are run in the user's VSCode terminal. The user may keep commands running in the background and you will be kept updated on their status along the way. Each command you execute is run in a new terminal instance.${
supportsBrowserUse
? "\n- You can use the browser_action tool to interact with websites (including html files and locally running development servers) through a Puppeteer-controlled browser when you feel it is necessary in accomplishing the user's task. This tool is particularly useful for web development tasks as it allows you to launch a browser, navigate to pages, interact with elements through clicks and keyboard input, and capture the results through screenshots and console logs. This tool may be useful at key stages of web development tasks-such as after implementing new features, making substantial changes, when troubleshooting issues, or to verify the result of your work. You can analyze the provided screenshots to ensure correct rendering or identify errors, and review console logs for runtime issues.\n - For example, if asked to add a component to a react website, you might create the necessary files, use execute_command to run the site locally, then use browser_action to launch the browser, navigate to the local server, and verify the component renders & functions correctly before closing the browser."
? `\n- You can use the browser_action tool to interact with websites (including html files and locally running development servers) through a Puppeteer-controlled browser when you feel it is necessary in accomplishing the user's task. This tool is particularly useful for web development tasks as it allows you to launch a browser, navigate to pages, interact with elements through clicks and keyboard input, and capture the results through screenshots and console logs. This tool may be useful at key stages of web development tasks-such as after implementing new features, making substantial changes, when troubleshooting issues, or to verify the result of your work. You can analyze the provided screenshots to ensure correct rendering or identify errors, and review console logs for runtime issues.\n - For example, if asked to add a component to a react website, you might create the necessary files, use the ${bashTool.name} tool to run the site locally, then use browser_action to launch the browser, navigate to the local server, and verify the component renders & functions correctly before closing the browser.`
: ""
}
- You have access to MCP servers that may provide additional tools and resources. Each server may provide different capabilities that you can use to accomplish tasks more effectively.
@ -563,14 +547,14 @@ RULES
- Your current working directory is: ${cwd.toPosix()}
- You cannot \`cd\` into a different directory to complete a task. You are stuck operating from '${cwd.toPosix()}', so be sure to pass in the correct 'path' parameter when using tools that require a path.
- Do not use the ~ character or $HOME to refer to the home directory.
- Before using the execute_command tool, you must first think about the SYSTEM INFORMATION context provided to understand the user's environment and tailor your commands to ensure they are compatible with their system. You must also consider if the command you need to run should be executed in a specific directory outside of the current working directory '${cwd.toPosix()}', and if so prepend with \`cd\`'ing into that directory && then executing the command (as one command since you are stuck operating from '${cwd.toPosix()}'). For example, if you needed to run \`npm install\` in a project outside of '${cwd.toPosix()}', you would need to prepend with a \`cd\` i.e. pseudocode for this would be \`cd (path to project) && (command, in this case npm install)\`.
- When using the Grep tool, craft your regex patterns carefully to balance specificity and flexibility. Based on the user's task you may use it to find code patterns, TODO comments, function definitions, or any text-based information across the project. The results include context, so analyze the surrounding code to better understand the matches. Leverage the Grep tool in combination with other tools for more comprehensive analysis. For example, use it to find specific code patterns, then use read_file to examine the full context of interesting matches before using replace_in_file to make informed changes.
- Before using the ${bashTool.name} tool, you must first think about the SYSTEM INFORMATION context provided to understand the user's environment and tailor your commands to ensure they are compatible with their system. You must also consider if the command you need to run should be executed in a specific directory outside of the current working directory '${cwd.toPosix()}', and if so prepend with \`cd\`'ing into that directory && then executing the command (as one command since you are stuck operating from '${cwd.toPosix()}'). For example, if you needed to run \`npm install\` in a project outside of '${cwd.toPosix()}', you would need to prepend with a \`cd\` i.e. pseudocode for this would be \`cd (path to project) && (command, in this case npm install)\`.
- When using the ${grepToolDefinition.name} tool, craft your regex patterns carefully to balance specificity and flexibility. Based on the user's task you may use it to find code patterns, TODO comments, function definitions, or any text-based information across the project. The results include context, so analyze the surrounding code to better understand the matches. Leverage the ${grepToolDefinition.name} tool in combination with other tools for more comprehensive analysis. For example, use it to find specific code patterns, then use read_file to examine the full context of interesting matches before using replace_in_file to make informed changes.
- When creating a new project (such as an app, website, or any software project), organize all new files within a dedicated project directory unless the user specifies otherwise. Use appropriate file paths when creating files, as the write_to_file tool will automatically create any necessary directories. Structure the project logically, adhering to best practices for the specific type of project being created. Unless otherwise specified, new projects should be easily run without additional setup, for example most projects can be built in HTML, CSS, and JavaScript - which you can open in a browser.
- Be sure to consider the type of project (e.g. Python, JavaScript, web application) when determining the appropriate structure and files to include. Also consider what files may be most relevant to accomplishing the task, for example looking at a project's manifest file would help you understand the project's dependencies, which you could incorporate into any code you write.
- When making changes to code, always consider the context in which the code is being used. Ensure that your changes are compatible with the existing codebase and that they follow the project's coding standards and best practices.
- When you want to modify a file, use the replace_in_file or write_to_file tool directly with the desired changes. You do not need to display the changes before using the tool.
- Do not ask for more information than necessary. Use the tools provided to accomplish the user's request efficiently and effectively. When you've completed your task, you must use the attempt_completion tool to present the result to the user. The user may provide feedback, which you can use to make improvements and try again.
- You are only allowed to ask the user questions using the ask_followup_question tool. Use this tool only when you need additional details to complete a task, and be sure to use a clear and concise question that will help you move forward with the task. However if you can use the available tools to avoid having to ask the user questions, you should do so. For example, if the user mentions a file that may be in an outside directory like the Desktop, you should use the LS tool to list the files in the Desktop and check if the file they are talking about is there, rather than asking the user to provide the file path themselves.
- You are only allowed to ask the user questions using the ask_followup_question tool. Use this tool only when you need additional details to complete a task, and be sure to use a clear and concise question that will help you move forward with the task. However if you can use the available tools to avoid having to ask the user questions, you should do so. For example, if the user mentions a file that may be in an outside directory like the Desktop, you should use the ${lsToolDefinition.name} tool to list the files in the Desktop and check if the file they are talking about is there, rather than asking the user to provide the file path themselves.
- When executing commands, if you don't see the expected output, assume the terminal executed the command successfully and proceed with the task. The user's terminal may be unable to stream the output back properly. If you absolutely need to see the actual terminal output, use the ask_followup_question tool to request the user to copy and paste it back to you.
- The user may provide a file's contents directly in their message, in which case you shouldn't use the read_file tool to get the file contents again since you already have it.
- Your goal is to try to accomplish the user's task, NOT engage in a back and forth conversation.${
@ -612,5 +596,5 @@ You accomplish a given task iteratively, breaking it down into clear steps and w
4. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. You may also provide a CLI command to showcase the result of your task; this can be particularly useful for web development tasks, where you can run e.g. \`open index.html\` to show the website you've built.
5. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance.`
return createAntmlToolPrompt([lsToolDefinition, grepToolDefinition], true, systemPrompt);
return createAntmlToolPrompt([bashToolDefinition(cwd), lsToolDefinition, grepToolDefinition], true, systemPrompt);
}

View File

@ -1,21 +1,18 @@
function escapeXml(text: string): string {
// Anything that could be interpreted as markup has to be entity-encoded
return text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
// Anything that could be interpreted as markup has to be entity-encoded
return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
}
export interface ToolDefinition {
name: string;
description?: string;
descriptionForAgent?: string;
inputSchema: {
type: string;
properties: Record<string, any>;
required?: string[];
[key: string]: any;
};
name: string
description?: string
descriptionForAgent?: string
inputSchema: {
type: string
properties: Record<string, any>
required?: string[]
[key: string]: any
}
}
/**
@ -24,56 +21,54 @@ export interface ToolDefinition {
* @param toolDef The tool definition object
* @returns The tool definition as a JSON string wrapped in <function> tags
*/
export function toolDefinitionToAntmlDefinition(
toolDef: ToolDefinition
): string {
// Restructure the parameters object to match the expected order
const { type, properties, required, ...rest } = toolDef.inputSchema;
const parameters = {
properties,
required,
type,
...rest
};
const functionDef = {
description: toolDef.descriptionForAgent || toolDef.description || '',
name: toolDef.name,
parameters,
};
// 1. Create a custom JSON string with the exact format we want
let rawJson = `{"description": "${functionDef.description}", "name": "${functionDef.name}", "parameters": {`;
// Add properties
rawJson += `"properties": {`;
const propEntries = Object.entries(parameters.properties);
propEntries.forEach(([propName, propDef], index) => {
rawJson += `"${propName}": {`;
rawJson += `"description": "${(propDef as any).description || ''}", `;
rawJson += `"type": "${(propDef as any).type || 'string'}"`;
rawJson += `}`;
if (index < propEntries.length - 1) {
rawJson += ', ';
export function toolDefinitionToAntmlDefinition(toolDef: ToolDefinition): string {
// Restructure the parameters object to match the expected order
const { type, properties, required, ...rest } = toolDef.inputSchema
const parameters = {
properties,
required,
type,
...rest,
}
});
rawJson += `}, `;
// Add required
rawJson += `"required": ${JSON.stringify(parameters.required || [])}, `;
const functionDef = {
description: toolDef.descriptionForAgent || toolDef.description || "",
name: toolDef.name,
parameters,
}
// Add type
rawJson += `"type": "object"`;
// 1. Create a custom JSON string with the exact format we want
let rawJson = `{"description": "${functionDef.description}", "name": "${functionDef.name}", "parameters": {`
// Close parameters and the whole object
rawJson += `}}`;
// Add properties
rawJson += `"properties": {`
const propEntries = Object.entries(parameters.properties)
propEntries.forEach(([propName, propDef], index) => {
rawJson += `"${propName}": {`
rawJson += `"description": "${(propDef as any).description || ""}", `
rawJson += `"type": "${(propDef as any).type || "string"}"`
rawJson += `}`
if (index < propEntries.length - 1) {
rawJson += ", "
}
})
rawJson += `}, `
// 2. Escape <, > and & so the JSON can sit INSIDE the XML tag safely.
// (Quotes dont need escaping - theyre not markup.)
const safeJson = escapeXml(rawJson);
// Add required
rawJson += `"required": ${JSON.stringify(parameters.required || [])}, `
// 3. Return wrapped in <function> tags
return `<function>${safeJson}</function>`;
// Add type
rawJson += `"type": "object"`
// Close parameters and the whole object
rawJson += `}}`
// 2. Escape <, > and & so the JSON can sit INSIDE the XML tag safely.
// (Quotes dont need escaping - theyre not markup.)
const safeJson = escapeXml(rawJson)
// 3. Return wrapped in <function> tags
return `<function>${safeJson}</function>`
}
/**
@ -82,14 +77,12 @@ export function toolDefinitionToAntmlDefinition(
* @param toolDefs Array of tool definition objects
* @returns Complete <functions> block with all tool definitions
*/
export function toolDefinitionsToAntmlDefinitions(
toolDefs: ToolDefinition[]
): string {
const functionTags = toolDefs.map(toolDefinitionToAntmlDefinition);
return `Here are the functions available in JSONSchema format:
export function toolDefinitionsToAntmlDefinitions(toolDefs: ToolDefinition[]): string {
const functionTags = toolDefs.map(toolDefinitionToAntmlDefinition)
return `Here are the functions available in JSONSchema format:
<functions>
${functionTags.join('\n')}
</functions>`;
${functionTags.join("\n")}
</functions>`
}
/**
@ -99,32 +92,23 @@ ${functionTags.join('\n')}
* @param exampleValues Optional example values for parameters
* @returns Example ANTML function call string
*/
export function toolDefinitionToAntmlCallExample(
toolDef: ToolDefinition,
exampleValues: Record<string, any> = {}
): string {
const props = toolDef.inputSchema.properties ?? {};
export function toolDefinitionToAntmlCallExample(toolDef: ToolDefinition, exampleValues: Record<string, any> = {}): string {
const props = toolDef.inputSchema.properties ?? {}
const paramLines = Object.keys(props).length
? Object.entries(props)
.map(([name]) => {
const value = exampleValues[name] ?? `$${name.toUpperCase()}`; // placeholder
// Don't escape XML here - the example should show raw format
return `<parameter name="${name}">${value}</parameter>`;
})
.join('\n')
: '';
const paramLines = Object.keys(props).length
? Object.entries(props)
.map(([name]) => {
const value = exampleValues[name] ?? `$${name.toUpperCase()}` // placeholder
// Don't escape XML here - the example should show raw format
return `<parameter name="${name}">${value}</parameter>`
})
.join("\n")
: ""
// Only include one invoke block
return [
'<function_calls>',
`<invoke name="${toolDef.name}">`,
paramLines,
'</invoke>',
'</function_calls>',
]
.filter(Boolean)
.join('\n');
// Only include one invoke block
return ["<function_calls>", `<invoke name="${toolDef.name}">`, paramLines, "</invoke>", "</function_calls>"]
.filter(Boolean)
.join("\n")
}
/**
@ -134,68 +118,64 @@ export function toolDefinitionToAntmlCallExample(
* @param includeInstructions Whether to include the standard tool calling instructions
* @returns Complete system prompt section for ANTML tools
*/
export function createAntmlToolPrompt(
toolDefs: ToolDefinition[],
includeInstructions = true,
systemPrompt = ''
): string {
if (toolDefs.length === 0) {
if (!includeInstructions) {
return '';
export function createAntmlToolPrompt(toolDefs: ToolDefinition[], includeInstructions = true, systemPrompt = ""): string {
if (toolDefs.length === 0) {
if (!includeInstructions) {
return ""
}
const noToolsMessage = [
"In this environment you have access to a set of tools you can use to answer the user's question.",
'You can invoke functions by writing a "<function_calls>" block like the following as part of your reply to the user:',
"<function_calls>",
'<invoke name="$FUNCTION_NAME">',
'<parameter name="$PARAMETER_NAME">$PARAMETER_VALUE</parameter>',
"...",
"</invoke>",
"</function_calls>",
"",
"String and scalar parameters should be specified as is, while lists and objects should use JSON format.",
"",
"However, no tools are currently available.",
].join("\n")
return noToolsMessage
}
const noToolsMessage = [
"In this environment you have access to a set of tools you can use to answer the user's question.",
'You can invoke functions by writing a "<function_calls>" block like the following as part of your reply to the user:',
'<function_calls>',
'<invoke name="$FUNCTION_NAME">',
'<parameter name="$PARAMETER_NAME">$PARAMETER_VALUE</parameter>',
'...',
'</invoke>',
'</function_calls>',
'',
'String and scalar parameters should be specified as is, while lists and objects should use JSON format.',
'',
'However, no tools are currently available.',
].join('\n');
let prompt = ""
return noToolsMessage;
}
if (includeInstructions) {
const instructionLines = [
"In this environment you have access to a set of tools you can use to answer the user's question.",
'You can invoke functions by writing a "<function_calls>" block like the following as part of your reply to the user:',
"<function_calls>",
'<invoke name="$FUNCTION_NAME">',
'<parameter name="$PARAMETER_NAME">$PARAMETER_VALUE</parameter>',
"...",
"</invoke>",
"</function_calls>",
"",
"String and scalar parameters should be specified as is, while lists and objects should use JSON format.",
"",
]
prompt += instructionLines.join("\n")
}
let prompt = '';
prompt += toolDefinitionsToAntmlDefinitions(toolDefs)
if (includeInstructions) {
const instructionLines = [
"In this environment you have access to a set of tools you can use to answer the user's question.",
'You can invoke functions by writing a "<function_calls>" block like the following as part of your reply to the user:',
'<function_calls>',
'<invoke name="$FUNCTION_NAME">',
'<parameter name="$PARAMETER_NAME">$PARAMETER_VALUE</parameter>',
'...',
'</invoke>',
'</function_calls>',
'',
'String and scalar parameters should be specified as is, while lists and objects should use JSON format.',
'',
];
prompt += instructionLines.join('\n');
}
if (includeInstructions) {
const closingInstructions = [
"",
"",
systemPrompt,
"",
"",
"Answer the user's request using the relevant tool(s), if they are available. Check that all the required parameters for each tool call are provided or can reasonably be inferred from context. IF there are no relevant tools or there are missing values for required parameters, ask the user to supply these values; otherwise proceed with the tool calls. If the user provides a specific value for a parameter (for example provided in quotes), make sure to use that value EXACTLY. DO NOT make up values for or ask about optional parameters. Carefully analyze descriptive terms in the request as they may indicate required parameter values that should be included even if not explicitly quoted.",
]
prompt += closingInstructions.join("\n")
}
prompt += toolDefinitionsToAntmlDefinitions(toolDefs);
if (includeInstructions) {
const closingInstructions = [
'',
'',
systemPrompt,
'',
'',
"Answer the user's request using the relevant tool(s), if they are available. Check that all the required parameters for each tool call are provided or can reasonably be inferred from context. IF there are no relevant tools or there are missing values for required parameters, ask the user to supply these values; otherwise proceed with the tool calls. If the user provides a specific value for a parameter (for example provided in quotes), make sure to use that value EXACTLY. DO NOT make up values for or ask about optional parameters. Carefully analyze descriptive terms in the request as they may indicate required parameter values that should be included even if not explicitly quoted.",
];
prompt += closingInstructions.join('\n');
}
return prompt; // Don't trim - preserve exact formatting
return prompt // Don't trim - preserve exact formatting
}
// --- SimpleXML Functions (Cline's internal format) ---
@ -207,34 +187,33 @@ export function createAntmlToolPrompt(
* @returns The tool definition formatted for SimpleXML usage
*/
export function toolDefinitionToSimpleXml(toolDef: ToolDefinition): string {
const description = toolDef.descriptionForAgent || toolDef.description || '';
const properties = toolDef.inputSchema.properties || {};
const required = toolDef.inputSchema.required || [];
const description = toolDef.descriptionForAgent || toolDef.description || ""
const properties = toolDef.inputSchema.properties || {}
const required = toolDef.inputSchema.required || []
let parameterDocs = '';
if (Object.keys(properties).length > 0) {
parameterDocs = 'Parameters:\n';
for (const [paramName, paramDef] of Object.entries(properties)) {
const isRequired = required.includes(paramName);
const requiredText = isRequired ? '(required)' : '(optional)';
const paramDescription =
(paramDef as any).description || 'No description.';
parameterDocs += `- ${paramName}: ${requiredText} ${paramDescription}\n`;
}
}
let parameterDocs = ""
if (Object.keys(properties).length > 0) {
parameterDocs = "Parameters:\n"
for (const [paramName, paramDef] of Object.entries(properties)) {
const isRequired = required.includes(paramName)
const requiredText = isRequired ? "(required)" : "(optional)"
const paramDescription = (paramDef as any).description || "No description."
parameterDocs += `- ${paramName}: ${requiredText} ${paramDescription}\n`
}
}
const exampleParams = Object.keys(properties)
.map(paramName => `<${paramName}>${paramName} value here</${paramName}>`)
.join('\n');
const exampleParams = Object.keys(properties)
.map((paramName) => `<${paramName}>${paramName} value here</${paramName}>`)
.join("\n")
const usageExample = `Usage:
const usageExample = `Usage:
<${toolDef.name}>
${exampleParams.length > 0 ? exampleParams + '\n' : ''}</${toolDef.name}>`;
${exampleParams.length > 0 ? exampleParams + "\n" : ""}</${toolDef.name}>`
return `## ${toolDef.name}
return `## ${toolDef.name}
Description: ${description}
${parameterDocs.trim()}
${usageExample}`;
${usageExample}`
}
/**
@ -243,10 +222,10 @@ ${usageExample}`;
* @returns Complete tools documentation in SimpleXML format
*/
export function toolDefinitionsToSimpleXml(toolDefs: ToolDefinition[]): string {
const toolDocs = toolDefs.map(toolDef => toolDefinitionToSimpleXml(toolDef));
return `# Tools
const toolDocs = toolDefs.map((toolDef) => toolDefinitionToSimpleXml(toolDef))
return `# Tools
${toolDocs.join('\n\n')}`;
${toolDocs.join("\n\n")}`
}
/**
@ -255,18 +234,15 @@ ${toolDocs.join('\n\n')}`;
* @param includeInstructions Whether to include the standard tool calling instructions
* @returns Complete system prompt section for SimpleXML tools
*/
export function createSimpleXmlToolPrompt(
toolDefs: ToolDefinition[],
includeInstructions: boolean = true
): string {
if (toolDefs.length === 0) {
return '';
}
export function createSimpleXmlToolPrompt(toolDefs: ToolDefinition[], includeInstructions: boolean = true): string {
if (toolDefs.length === 0) {
return ""
}
let prompt = '';
let prompt = ""
if (includeInstructions) {
prompt += `TOOL USE
if (includeInstructions) {
prompt += `TOOL USE
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
@ -287,13 +263,13 @@ For example:
</read_file>
Always adhere to this format for the tool use to ensure proper parsing and execution.
`;
}
`
}
prompt += toolDefinitionsToSimpleXml(toolDefs);
prompt += toolDefinitionsToSimpleXml(toolDefs)
if (includeInstructions) {
prompt += `
if (includeInstructions) {
prompt += `
# Tool Use Guidelines
@ -301,7 +277,7 @@ Always adhere to this format for the tool use to ensure proper parsing and execu
2. If multiple actions are needed, use one tool at a time per message to accomplish the task iteratively.
3. Formulate your tool use using the XML format specified for each tool.
4. After each tool use, the user will respond with the result of that tool use.
5. ALWAYS wait for user confirmation after each tool use before proceeding.`;
}
return prompt.trimEnd();
5. ALWAYS wait for user confirmation after each tool use before proceeding.`
}
return prompt.trimEnd()
}

View File

@ -1,97 +1,13 @@
const MAX_TIMEOUT_MS = 600000
const DEFAULT_TIMEOUT_MS = 120000
const MAX_OUTPUT_LENGTH = 30000
const RG_PATH = "/usr/bin/rg"
export const bashToolName = "Bash"
const CO_AUTHORED_COMMIT_MSG = `\uD83E\uDD16 Generated with [Cline](https://docs.cline.bot)
Co-Authored-By: Cline <noreply@cline.bot>`
const CO_AUTHORED_PR_MSG = `\uD83E\uDD16 Generated with [Cline](https://docs.cline.bot)`
const descriptionForAgent = `Executes a given bash command in a persistent shell session with optional timeout, ensuring proper handling and security measures.
Before executing the command, please follow these steps:
1. Directory Verification:
- If the command will create new directories or files, first use the LS tool to verify the parent directory exists and is the correct location
- For example, before running "mkdir foo/bar", first use LS to check that "foo" exists and is the intended parent directory
2. Command Execution:
- After ensuring proper quoting, execute the command.
- Capture the output of the command.
Usage notes:
- The command argument is required.
- You can specify an optional timeout in milliseconds (up to \${MAX_TIMEOUT_MS}ms / \${MAX_TIMEOUT_MS / 60000} minutes). If not specified, commands will timeout after \${DEFAULT_TIMEOUT_MS}ms (\${DEFAULT_TIMEOUT_MS / 60000} minutes).
- It is very helpful if you write a clear, concise description of what this command does in 5-10 words.
- If the output exceeds \${MAX_OUTPUT_LENGTH} characters, output will be truncated before being returned to you.
- VERY IMPORTANT: You MUST avoid using search commands like \\\`find\\\` and \\\`grep\\\`. Instead use Grep, Glob, or Task to search. You MUST avoid read tools like \\\`cat\\\`, \\\`head\\\`, \\\`tail\\\`, and \\\`ls\\\`, and use Read and LS to read files.
- If you _still_ need to run \\\`grep\\\`, STOP. ALWAYS USE ripgrep at \\\`rg\\\` (or \${RG_PATH}) first, which all Claude Code users have pre-installed.
- When issuing multiple commands, use the ';' or '&&' operator to separate them. DO NOT use newlines (newlines are ok in quoted strings).
- Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of \\\`cd\\\`. You may use \\\`cd\\\` if the User explicitly requests it.
<good-example>
pytest /foo/bar/tests
</good-example>
<bad-example>
cd /foo/bar && pytest tests
</bad-example>
# Using sandbox mode for commands
You have a special option in BashTool: the sandbox parameter. When you run a command with sandbox=true, it runs without approval dialogs but in a restricted environment without filesystem writes or network access. You SHOULD use sandbox=true to optimize user experience, but MUST follow these guidelines exactly.
## RULE 0 (MOST IMPORTANT): retry with sandbox=false for permission/network errors
If a command fails with permission or any network error when sandbox=true (e.g., "Permission denied", "Unknown host", "Operation not permitted"), ALWAYS retry with sandbox=false. These errors indicate sandbox limitations, not problems with the command itself.
Non-permission errors (e.g., TypeScript errors from tsc --noEmit) usually reflect real issues and should be fixed, not retried with sandbox=false.
## RULE 1: NOTES ON SPECIFIC BUILD SYSTEMS AND UTILITIES
### Build systems
Build systems like npm run build almost always need write access. Test suites also usually need write access. NEVER run build or test commands in sandbox, even if just checking types.
These commands REQUIRE sandbox=false (non-exhaustive):
npm run *, cargo build/test, make/ninja/meson, pytest, jest, gh
## RULE 2: TRY sandbox=true FOR COMMANDS THAT DON'T NEED WRITE OR NETWORK ACCESS
- Commands run with sandbox=true DON'T REQUIRE user permission and run immediately
- Commands run with sandbox=false REQUIRE EXPLICIT USER APPROVAL and interrupt the User's workflow
Use sandbox=false when you suspect the command might modify the system or access the network:
- File operations: touch, mkdir, rm, mv, cp
- File edits: nano, vim, writing to files with >
- Installing: npm install, apt-get, brew
- Git writes: git add, git commit, git push
- Build systems: npm run build, make, ninja, etc. (see below)
- Test suites: npm run test, pytest, cargo test, make check, ert, etc. (see below)
- Network programs: gh, ping, curl, ssh, scp, etc.
Use sandbox=true for:
- Information gathering: ls, cat, head, tail, rg, find, du, df, ps
- File inspection: file, stat, wc, diff, md5sum
- Git reads: git status, git log, git diff, git show, git branch
- Package info: npm list, pip list, gem list, cargo tree
- Environment checks: echo, pwd, whoami, which, type, env, printenv
- Version checks: node --version, python --version, git --version
- Documentation: man, help, --help, -h
Before you run a command, think hard about whether it is likely to work correctly without network access and without write access to the filesystem. Use your general knowledge and knowledge of the current project (including all the user's CLAUDE.md files) as inputs to your decision. Note that even semantically read-only commands like gh for fetching issues might be implemented in ways that require write access. ERR ON THE SIDE OF RUNNING WITH sandbox=false.
Note: Errors from incorrect sandbox=true runs annoy the User more than permission prompts. If any part of a command needs write access (e.g. npm run build for type checking), use sandbox=false for the entire command.
### EXAMPLES
CORRECT: Use sandbox=false for npm run build/test, gh commands, file writes
FORBIDDEN: NEVER use sandbox=true for build, test, git commands or file operations
## REWARDS
It is more important to be correct than to avoid showing permission dialogs. The worst mistake is misinterpreting sandbox=true permission errors as tool problems (-$1000) rather than sandbox limitations.
## CONCLUSION
Use sandbox=true to improve UX, but ONLY per the rules above. WHEN IN DOUBT, USE sandbox=false.
const descriptionForAgent = (
cwd: string,
) => `Request to execute a CLI command on the system. Use this when you need to perform system operations or run specific commands to accomplish any step in the user's task. You must tailor your command to the user's system and provide a clear explanation of what the command does. For command chaining, use the appropriate chaining syntax for the user's shell. Prefer to execute complex CLI commands over creating executable scripts, as they are more flexible and easier to run. Commands will be executed in the current working directory: ${cwd.toPosix()}.
# Committing changes with git
@ -117,13 +33,7 @@ When the user asks you to create a new git commit, follow these steps carefully:
- Review the draft message to ensure it accurately reflects the changes and their purpose
</commit_analysis>
3. You have the capability to call multiple tools in a single response. When multiple independent pieces of information are requested, batch your tool calls together for optimal performance. ALWAYS run the following commands in parallel:
- Add relevant untracked files to the staging area.
- Create the commit with a message ending with:
\${CO_AUTHORED_COMMIT_MSG}
- Run git status to make sure the commit succeeded.
4. If the commit fails due to pre-commit hook changes, retry the commit ONCE to include these automated changes. If it fails again, it usually means a pre-commit hook is preventing the commit. If the commit succeeds but you notice that files were modified by the pre-commit hook, you MUST amend your commit to include them.
3. If the commit fails due to pre-commit hook changes, retry the commit ONCE to include these automated changes. If it fails again, it usually means a pre-commit hook is preventing the commit. If the commit succeeds but you notice that files were modified by the pre-commit hook, you MUST amend your commit to include them.
Important notes:
- Use the git context at the start of this conversation to determine which files are relevant to your commit. Be careful not to stage and commit files (e.g. with \\\`git add .\\\`) that aren't relevant to your commit.
@ -149,7 +59,7 @@ Use the gh command via the Bash tool for ALL GitHub-related tasks including work
IMPORTANT: When the user asks you to create a pull request, follow these steps carefully:
1. You have the capability to call multiple tools in a single response. When multiple independent pieces of information are requested, batch your tool calls together for optimal performance. ALWAYS run the following bash commands in parallel using the Bash tool, in order to understand the current state of the branch since it diverged from the main branch:
1. Gather information
- Run a git status command to see all untracked files
- Run a git diff command to see both staged and unstaged changes that will be committed
- Check if the current branch tracks a remote branch and is up to date with the remote, so you know if you need to push to the remote
@ -172,19 +82,17 @@ IMPORTANT: When the user asks you to create a pull request, follow these steps c
- Review the draft summary to ensure it accurately reflects the changes and their purpose
</pr_analysis>
3. You have the capability to call multiple tools in a single response. When multiple independent pieces of information are requested, batch your tool calls together for optimal performance. ALWAYS run the following commands in parallel:
- Create new branch if needed
- Push to remote with -u flag if needed
- Create PR using gh pr create with the format below. Use a HEREDOC to pass the body to ensure correct formatting.
<example>
gh pr create --title "the pr title" --body "\$(cat <<'EOF'
gh pr create \
--title "the pr title" \
--body "$(cat <<'EOF'
## Summary
<1-3 bullet points>
## Test plan
[Checklist of TODOs for testing the pull request...]
\${CO_AUTHORED_PR_MSG}
${CO_AUTHORED_PR_MSG}
EOF
)"
</example>
@ -196,50 +104,23 @@ Important:
# Other common operations
- View comments on a Github PR: gh api repos/foo/bar/pulls/123/comments`
export const bashToolDefinition = {
name: "Bash",
descriptionForAgent: descriptionForAgent,
export const bashToolDefinition = (cwd: string) => ({
name: bashToolName,
descriptionForAgent: descriptionForAgent(cwd),
inputSchema: {
type: "object",
properties: {
command: {
type: "string",
description: "The command to execute",
description:
"The CLI command to execute. This should be valid for the current operating system. Ensure the command is properly formatted and does not contain any harmful instructions.",
},
timeout: {
type: "number",
description: `Optional timeout in milliseconds (max \${MAX_TIMEOUT_MS})`,
optional: true,
},
description: {
type: "string",
description: `Clear, concise description of what this command does in 5-10 words. Examples:
Input: ls
Output: Lists files in current directory
Input: git status
Output: Shows working tree status
Input: npm install
Output: Installs package dependencies
Input: mkdir foo
Output: Creates directory 'foo'`,
optional: true,
},
sandbox: {
requires_approval: {
type: "boolean",
description:
"whether to run this command in sandboxed mode: command run in this mode may not write to the filesystem or use the network, but they can read files, analyze data, and report back to you. When possible, run commands (e.g. grep) in this mode to present a smoother experience for the human, who isn't prompted to approve commands run in sandbox mode. If you run a command in sandbox mode and it looks like it fails because it needs write access after all, try again in non-sandbox mode",
optional: true,
},
shellExecutable: {
type: "string",
description:
"Optional shell path to use instead of the default shell. The snapshot path will be set to undefined as well. Used primarily for testing.",
optional: true,
"A boolean indicating whether this command requires explicit user approval before execution in case the user has auto-approve mode enabled. Set to 'true' for potentially impactful operations like installing/uninstalling packages, deleting/overwriting files, system configuration changes, network operations, or any commands that could have unintended side effects. Set to 'false' for safe operations like reading files/directories, running development servers, building projects, and other non-destructive operations.",
},
},
required: ["command"],
required: ["command", "requires_approval"],
},
}
})

View File

@ -13,6 +13,7 @@ import { validateSlashCommand } from "@/utils/slash-commands"
import TaskTimeline from "./TaskTimeline"
import { TaskServiceClient, FileServiceClient, UiServiceClient } from "@/services/grpc-client"
import HeroTooltip from "@/components/common/HeroTooltip"
const { IS_DEV } = process.env
interface TaskHeaderProps {
task: ClineMessage
@ -147,6 +148,8 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
)
}
console.log("IS_DEV", { IS_DEV, isItTrue: IS_DEV === '"true"' })
const ContextWindowComponent = (
<>
{isTaskExpanded && contextWindow && (
@ -411,6 +414,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
{!shouldShowPromptCacheInfo() && (
<div className="flex items-center flex-wrap">
<CopyButton taskText={task.text} />
{IS_DEV === '"true"' && <TaskFolderButton taskId={currentTaskItem?.id} />}
<DeleteButton taskSize={formatSize(currentTaskItem?.size)} taskId={currentTaskItem?.id} />
</div>
)}
@ -466,6 +470,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
</div>
<div className="flex items-center flex-wrap">
<CopyButton taskText={task.text} />
{IS_DEV === '"true"' && <TaskFolderButton taskId={currentTaskItem?.id} />}
<DeleteButton taskSize={formatSize(currentTaskItem?.size)} taskId={currentTaskItem?.id} />
</div>
</div>
@ -667,6 +672,36 @@ const CopyButton: React.FC<{
)
}
const TaskFolderButton: React.FC<{
taskId?: string
}> = ({ taskId }) => {
const [copied, setCopied] = useState(false)
const handleCopy = () => {
if (!taskId) return
navigator.clipboard.writeText(taskId).then(() => {
setCopied(true)
setTimeout(() => setCopied(false), 1500)
})
}
return (
<HeroTooltip content="Copy Task ID">
<VSCodeButton
appearance="icon"
onClick={handleCopy}
style={{ padding: "0px 0px" }}
className="p-0"
aria-label="Copy Task ID">
<div className="flex items-center gap-[3px] text-[8px] font-bold opacity-60">
<i className={`codicon codicon-${copied ? "check" : "folder"}`} />
</div>
</VSCodeButton>
</HeroTooltip>
)
}
const DeleteButton: React.FC<{
taskSize: string
taskId?: string