* Provider-order validation pass. It does not run hooks, spawn tools, or write * events. Validator compilation may populate the local cache.
( step: Pick<ToolCallStepContext, 'tools' | 'log'>, toolCall: ToolCall, )
| 174 | * events. Validator compilation may populate the local cache. |
| 175 | */ |
| 176 | function preflightToolCall( |
| 177 | step: Pick<ToolCallStepContext, 'tools' | 'log'>, |
| 178 | toolCall: ToolCall, |
| 179 | ): PreflightedToolCall { |
| 180 | const toolName = toolCall.name; |
| 181 | const parsedArgs = parseToolCallArguments(toolCall.arguments); |
| 182 | const tool = step.tools?.find((candidate) => candidate.name === toolName); |
| 183 | if (tool === undefined) { |
| 184 | return { |
| 185 | kind: 'rejected', |
| 186 | toolCall, |
| 187 | toolName, |
| 188 | args: parsedArgs.data, |
| 189 | output: `Tool "${toolName}" not found`, |
| 190 | }; |
| 191 | } |
| 192 | |
| 193 | if (parsedArgs.parseFailed) { |
| 194 | step.log?.debug('tool args JSON parse failed', { |
| 195 | toolName, |
| 196 | toolCallId: toolCall.id, |
| 197 | rawLength: toolCall.arguments?.length ?? 0, |
| 198 | error: parsedArgs.error, |
| 199 | }); |
| 200 | } |
| 201 | |
| 202 | const validationError = validateExecutableToolArgs(tool, parsedArgs.data); |
| 203 | if (validationError !== null) { |
| 204 | return { |
| 205 | kind: 'rejected', |
| 206 | toolCall, |
| 207 | toolName, |
| 208 | args: parsedArgs.data, |
| 209 | output: `Invalid args for tool "${toolName}": ${validationError}`, |
| 210 | }; |
| 211 | } |
| 212 | return { kind: 'runnable', toolCall, toolName, tool, args: parsedArgs.data }; |
| 213 | } |
| 214 | |
| 215 | function validateExecutableToolArgs(tool: ExecutableTool, args: unknown): string | null { |
| 216 | let validator = validators.get(tool); |
no test coverage detected