|
| 1 | +/** |
| 2 | + * Converts a tool definition to ANTML (Anthropic Markup Language) format |
| 3 | + * as used internally by Claude for tool calling. |
| 4 | + * |
| 5 | + * Based on the Claude 4 System Card: https://www-cdn.anthropic.com/6be99a52cb68eb70eb9572b4cafad13df32ed995.pdf |
| 6 | + * |
| 7 | + * Tool definitions are provided in JSON schema within <functions> tags: |
| 8 | + * <functions> |
| 9 | + * <function>{"description": "...", "name": "...", "parameters": {...}}</function> |
| 10 | + * ... (other functions) ... |
| 11 | + * </functions> |
| 12 | + * |
| 13 | + * Tool calls are made using <antml:function_calls> blocks: |
| 14 | + * <antml:function_calls> |
| 15 | + * <antml:invoke name="tool_name"> |
| 16 | + * <antml:parameter name="param_name">value</antml:parameter> |
| 17 | + * </antml:invoke> |
| 18 | + * </antml:function_calls> |
| 19 | + */ |
| 20 | + |
| 21 | +export interface ToolDefinition { |
| 22 | + name: string |
| 23 | + description?: string |
| 24 | + descriptionForAgent?: string |
| 25 | + inputSchema: { |
| 26 | + type: string |
| 27 | + properties: Record<string, any> |
| 28 | + required?: string[] |
| 29 | + [key: string]: any |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +/** |
| 34 | + * Converts a single tool definition (JSON schema) to the <function> tag format. |
| 35 | + * This is for *defining* the tool, not calling it. |
| 36 | + * @param toolDef The tool definition object |
| 37 | + * @returns The tool definition as a JSON string wrapped in <function> tags |
| 38 | + */ |
| 39 | +export function toolDefinitionToAntmlDefinition(toolDef: ToolDefinition): string { |
| 40 | + const functionDef = { |
| 41 | + name: toolDef.name, |
| 42 | + description: toolDef.descriptionForAgent || toolDef.description || "", |
| 43 | + parameters: toolDef.inputSchema, |
| 44 | + } |
| 45 | + const jsonString = JSON.stringify(functionDef) |
| 46 | + return `<function>${jsonString}</function>` |
| 47 | +} |
| 48 | + |
| 49 | +/** |
| 50 | + * Converts multiple tool definitions to the complete <functions> block. |
| 51 | + * This is for *defining* the tools. |
| 52 | + * @param toolDefs Array of tool definition objects |
| 53 | + * @returns Complete <functions> block with all tool definitions |
| 54 | + */ |
| 55 | +export function toolDefinitionsToAntmlDefinitions(toolDefs: ToolDefinition[]): string { |
| 56 | + const functionTags = toolDefs.map((toolDef) => toolDefinitionToAntmlDefinition(toolDef)) |
| 57 | + return `Here are the functions available in JSONSchema format: |
| 58 | +<functions> |
| 59 | + ${functionTags.join("\n ")} |
| 60 | +</functions>` |
| 61 | +} |
| 62 | + |
| 63 | +/** |
| 64 | + * Creates an example of an ANTML tool call for a given tool definition. |
| 65 | + * This is for *calling* a tool. |
| 66 | + * @param toolDef The tool definition object |
| 67 | + * @param exampleValues Optional example values for parameters |
| 68 | + * @returns Example ANTML function call string |
| 69 | + */ |
| 70 | +export function toolDefinitionToAntmlCallExample(toolDef: ToolDefinition, exampleValues: Record<string, any> = {}): string { |
| 71 | + const properties = toolDef.inputSchema.properties || {} |
| 72 | + let parametersXml = "" |
| 73 | + if (Object.keys(properties).length > 0) { |
| 74 | + parametersXml = Object.entries(properties) |
| 75 | + .map(([paramName]) => { |
| 76 | + const exampleValue = exampleValues[paramName] || `$${paramName.toUpperCase()}` // Use placeholder like $PARAMETER_NAME |
| 77 | + return ` <antml:parameter name="${paramName}">${exampleValue}</antml:parameter>` |
| 78 | + }) |
| 79 | + .join("\n") |
| 80 | + } else { |
| 81 | + // Handle tools with no parameters |
| 82 | + parametersXml = " <!-- This tool takes no parameters -->" |
| 83 | + } |
| 84 | + |
| 85 | + return `<antml:function_calls> |
| 86 | + <antml:invoke name="${toolDef.name}"> |
| 87 | +${parametersXml} |
| 88 | + </antml:invoke> |
| 89 | +</antml:function_calls>` |
| 90 | +} |
| 91 | + |
| 92 | +/** |
| 93 | + * Creates a complete system prompt section for tools in ANTML format, |
| 94 | + * including instructions and tool definitions. |
| 95 | + * @param toolDefs Array of tool definition objects |
| 96 | + * @param includeInstructions Whether to include the standard tool calling instructions |
| 97 | + * @returns Complete system prompt section for ANTML tools |
| 98 | + */ |
| 99 | +export function createAntmlToolPrompt(toolDefs: ToolDefinition[], includeInstructions: boolean = true): string { |
| 100 | + if (toolDefs.length === 0 && includeInstructions) { |
| 101 | + // If no tools but instructions are requested, still provide basic instruction. |
| 102 | + return `In this environment you have access to a set of tools you can use to answer the user's question. |
| 103 | +You can invoke functions by writing a "<antml:function_calls>" block as part of your reply. |
| 104 | +However, no tools are currently available.` |
| 105 | + } |
| 106 | + if (toolDefs.length === 0) { |
| 107 | + return "" |
| 108 | + } |
| 109 | + |
| 110 | + let prompt = "" |
| 111 | + |
| 112 | + if (includeInstructions) { |
| 113 | + // Generate a generic example or use the first tool for a more concrete example |
| 114 | + const exampleToolCall = |
| 115 | + toolDefs.length > 0 |
| 116 | + ? toolDefinitionToAntmlCallExample(toolDefs[0]) |
| 117 | + : `<antml:function_calls> |
| 118 | + <antml:invoke name="$FUNCTION_NAME"> |
| 119 | + <antml:parameter name="$PARAMETER_NAME">$VALUE</antml:parameter> |
| 120 | + </antml:invoke> |
| 121 | +</antml:function_calls>` |
| 122 | + |
| 123 | + prompt += `In this environment you have access to a set of tools you can use to answer the user's question. |
| 124 | +
|
| 125 | +You can invoke functions by writing a "<antml:function_calls>" block as part of your reply. For example: |
| 126 | +${exampleToolCall} |
| 127 | +
|
| 128 | +String and scalar parameters should be specified as is, while lists and objects should use JSON format. |
| 129 | +The output is not expected to be valid XML and is parsed with regular expressions. |
| 130 | +DO NOT use antml unless you intend to invoke a tool. |
| 131 | +` |
| 132 | + } |
| 133 | + |
| 134 | + prompt += toolDefinitionsToAntmlDefinitions(toolDefs) |
| 135 | + |
| 136 | + if (includeInstructions) { |
| 137 | + prompt += ` |
| 138 | +
|
| 139 | +Answer the user's request using the relevant tool(s), if they are available. Check that all required parameters for each tool call are provided or can be reasonably 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.` |
| 140 | + } |
| 141 | + |
| 142 | + return prompt |
| 143 | +} |
| 144 | + |
| 145 | +// --- SimpleXML Functions (Cline's internal format) --- |
| 146 | + |
| 147 | +/** |
| 148 | + * Converts a single tool definition to the SimpleXML format |
| 149 | + * as used by Cline's current system prompts for non-ANTML models. |
| 150 | + * @param toolDef The tool definition object |
| 151 | + * @returns The tool definition formatted for SimpleXML usage |
| 152 | + */ |
| 153 | +export function toolDefinitionToSimpleXml(toolDef: ToolDefinition): string { |
| 154 | + const description = toolDef.descriptionForAgent || toolDef.description || "" |
| 155 | + const properties = toolDef.inputSchema.properties || {} |
| 156 | + const required = toolDef.inputSchema.required || [] |
| 157 | + |
| 158 | + let parameterDocs = "" |
| 159 | + if (Object.keys(properties).length > 0) { |
| 160 | + parameterDocs = "Parameters:\n" |
| 161 | + for (const [paramName, paramDef] of Object.entries(properties)) { |
| 162 | + const isRequired = required.includes(paramName) |
| 163 | + const requiredText = isRequired ? "(required)" : "(optional)" |
| 164 | + const paramDescription = (paramDef as any).description || "No description." |
| 165 | + parameterDocs += `- ${paramName}: ${requiredText} ${paramDescription}\n` |
| 166 | + } |
| 167 | + } |
| 168 | + |
| 169 | + const exampleParams = Object.keys(properties) |
| 170 | + .map((paramName) => `<${paramName}>${paramName} value here</${paramName}>`) |
| 171 | + .join("\n") |
| 172 | + |
| 173 | + const usageExample = `Usage: |
| 174 | +<${toolDef.name}> |
| 175 | +${exampleParams.length > 0 ? exampleParams + "\n" : ""}</${toolDef.name}>` |
| 176 | + |
| 177 | + return `## ${toolDef.name} |
| 178 | +Description: ${description} |
| 179 | +${parameterDocs.trim()} |
| 180 | +${usageExample}` |
| 181 | +} |
| 182 | + |
| 183 | +/** |
| 184 | + * Converts multiple tool definitions to the complete SimpleXML format. |
| 185 | + * @param toolDefs Array of tool definition objects |
| 186 | + * @returns Complete tools documentation in SimpleXML format |
| 187 | + */ |
| 188 | +export function toolDefinitionsToSimpleXml(toolDefs: ToolDefinition[]): string { |
| 189 | + const toolDocs = toolDefs.map((toolDef) => toolDefinitionToSimpleXml(toolDef)) |
| 190 | + return `# Tools |
| 191 | +
|
| 192 | +${toolDocs.join("\n\n")}` |
| 193 | +} |
| 194 | + |
| 195 | +/** |
| 196 | + * Creates a complete system prompt section for tools in SimpleXML format. |
| 197 | + * @param toolDefs Array of tool definition objects |
| 198 | + * @param includeInstructions Whether to include the standard tool calling instructions |
| 199 | + * @returns Complete system prompt section for SimpleXML tools |
| 200 | + */ |
| 201 | +export function createSimpleXmlToolPrompt(toolDefs: ToolDefinition[], includeInstructions: boolean = true): string { |
| 202 | + if (toolDefs.length === 0) { |
| 203 | + return "" |
| 204 | + } |
| 205 | + |
| 206 | + let prompt = "" |
| 207 | + |
| 208 | + if (includeInstructions) { |
| 209 | + prompt += `TOOL USE |
| 210 | +
|
| 211 | +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. |
| 212 | +
|
| 213 | +# Tool Use Formatting |
| 214 | +
|
| 215 | +Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure: |
| 216 | +
|
| 217 | +<tool_name> |
| 218 | +<parameter1_name>value1</parameter1_name> |
| 219 | +<parameter2_name>value2</parameter2_name> |
| 220 | +... |
| 221 | +</tool_name> |
| 222 | +
|
| 223 | +For example: |
| 224 | +
|
| 225 | +<read_file> |
| 226 | +<path>src/main.js</path> |
| 227 | +</read_file> |
| 228 | +
|
| 229 | +Always adhere to this format for the tool use to ensure proper parsing and execution. |
| 230 | +` |
| 231 | + } |
| 232 | + |
| 233 | + prompt += toolDefinitionsToSimpleXml(toolDefs) |
| 234 | + |
| 235 | + if (includeInstructions) { |
| 236 | + prompt += ` |
| 237 | +
|
| 238 | +# Tool Use Guidelines |
| 239 | +
|
| 240 | +1. Choose the most appropriate tool based on the task and the tool descriptions provided. |
| 241 | +2. If multiple actions are needed, use one tool at a time per message to accomplish the task iteratively. |
| 242 | +3. Formulate your tool use using the XML format specified for each tool. |
| 243 | +4. After each tool use, the user will respond with the result of that tool use. |
| 244 | +5. ALWAYS wait for user confirmation after each tool use before proceeding.` |
| 245 | + } |
| 246 | + return prompt |
| 247 | +} |
0 commit comments