Validate the tool use request from LLM, including basic checks like fs_read file should exist, as well as user-defined preToolUse hook check.
(&mut self, os: &Os, tool_uses: Vec<AssistantToolUse>)
| 3269 | // Validate the tool use request from LLM, including basic checks like fs_read file should exist, as |
| 3270 | // well as user-defined preToolUse hook check. |
| 3271 | async fn validate_tools(&mut self, os: &Os, tool_uses: Vec<AssistantToolUse>) -> Result<ChatState, ChatError> { |
| 3272 | let conv_id = self.conversation.conversation_id().to_owned(); |
| 3273 | debug!(?tool_uses, "Validating tool uses"); |
| 3274 | let mut queued_tools: Vec<QueuedTool> = Vec::new(); |
| 3275 | let mut tool_results: Vec<ToolUseResult> = Vec::new(); |
| 3276 | |
| 3277 | for tool_use in tool_uses { |
| 3278 | let tool_use_id = tool_use.id.clone(); |
| 3279 | let tool_use_name = tool_use.name.clone(); |
| 3280 | let tool_input = tool_use.args.clone(); |
| 3281 | let mut tool_telemetry = ToolUseEventBuilder::new( |
| 3282 | conv_id.clone(), |
| 3283 | tool_use.id.clone(), |
| 3284 | self.conversation.model_info.as_ref().map(|m| m.model_id.clone()), |
| 3285 | ) |
| 3286 | .set_tool_use_id(tool_use_id.clone()) |
| 3287 | .set_tool_name(tool_use.name.clone()) |
| 3288 | .utterance_id(self.conversation.message_id().map(|s| s.to_string())); |
| 3289 | match self.conversation.tool_manager.get_tool_from_tool_use(tool_use).await { |
| 3290 | Ok(mut tool) => { |
| 3291 | // Apply non-Q-generated context to tools |
| 3292 | self.contextualize_tool(&mut tool); |
| 3293 | |
| 3294 | match tool.validate(os).await { |
| 3295 | Ok(()) => { |
| 3296 | tool_telemetry.is_valid = Some(true); |
| 3297 | queued_tools.push(QueuedTool { |
| 3298 | id: tool_use_id.clone(), |
| 3299 | name: tool_use_name, |
| 3300 | tool, |
| 3301 | accepted: false, |
| 3302 | tool_input, |
| 3303 | }); |
| 3304 | }, |
| 3305 | Err(err) => { |
| 3306 | tool_telemetry.is_valid = Some(false); |
| 3307 | tool_results.push(ToolUseResult { |
| 3308 | tool_use_id: tool_use_id.clone(), |
| 3309 | content: vec![ToolUseResultBlock::Text(format!( |
| 3310 | "Failed to validate tool parameters: {err}" |
| 3311 | ))], |
| 3312 | status: ToolResultStatus::Error, |
| 3313 | }); |
| 3314 | }, |
| 3315 | }; |
| 3316 | }, |
| 3317 | Err(err) => { |
| 3318 | tool_telemetry.is_valid = Some(false); |
| 3319 | tool_results.push(err.into()); |
| 3320 | }, |
| 3321 | } |
| 3322 | self.tool_use_telemetry_events.insert(tool_use_id, tool_telemetry); |
| 3323 | } |
| 3324 | |
| 3325 | // If we have any validation errors, then return them immediately to the model. |
| 3326 | if !tool_results.is_empty() { |
| 3327 | debug!(?tool_results, "Error found in the model tools"); |
| 3328 | queue!( |
nothing calls this directly
no test coverage detected