| 1474 | } |
| 1475 | |
| 1476 | pub async fn execute_tool_calls( |
| 1477 | session: &mut Session, |
| 1478 | tool_registry: Arc<opencode_tool::ToolRegistry>, |
| 1479 | ctx: opencode_tool::ToolContext, |
| 1480 | provider: Arc<dyn Provider>, |
| 1481 | provider_id: &str, |
| 1482 | model_id: &str, |
| 1483 | ) -> anyhow::Result<()> { |
| 1484 | let last_assistant = session |
| 1485 | .messages |
| 1486 | .iter() |
| 1487 | .rev() |
| 1488 | .find(|m| matches!(m.role, MessageRole::Assistant)); |
| 1489 | |
| 1490 | let tool_calls: Vec<(String, String, serde_json::Value)> = match last_assistant { |
| 1491 | Some(msg) => msg |
| 1492 | .parts |
| 1493 | .iter() |
| 1494 | .filter_map(|p| match &p.part_type { |
| 1495 | PartType::ToolCall { id, name, input } => { |
| 1496 | Some((id.clone(), name.clone(), input.clone())) |
| 1497 | } |
| 1498 | _ => None, |
| 1499 | }) |
| 1500 | .collect(), |
| 1501 | None => return Ok(()), |
| 1502 | }; |
| 1503 | |
| 1504 | if tool_calls.is_empty() { |
| 1505 | return Ok(()); |
| 1506 | } |
| 1507 | |
| 1508 | let subsessions = Arc::new(Mutex::new(Self::load_persisted_subsessions(session))); |
| 1509 | let default_model = format!("{}:{}", provider_id, model_id); |
| 1510 | let ctx = Self::with_persistent_subsession_callbacks( |
| 1511 | ctx, |
| 1512 | subsessions.clone(), |
| 1513 | provider, |
| 1514 | tool_registry.clone(), |
| 1515 | default_model, |
| 1516 | ); |
| 1517 | |
| 1518 | let tool_results_msg = { |
| 1519 | let mut msg = SessionMessage::assistant(ctx.session_id.clone()); |
| 1520 | for (call_id, tool_name, input) in tool_calls { |
| 1521 | let mut tool_ctx = ctx.clone(); |
| 1522 | tool_ctx.call_id = Some(call_id.clone()); |
| 1523 | let result = match tool_registry.execute(&tool_name, input, tool_ctx).await { |
| 1524 | Ok(result) => (result.output, false), |
| 1525 | Err(e) => (format!("Error: {}", e), true), |
| 1526 | }; |
| 1527 | |
| 1528 | msg.parts.push(crate::MessagePart { |
| 1529 | id: format!("prt_{}", uuid::Uuid::new_v4()), |
| 1530 | part_type: PartType::ToolResult { |
| 1531 | tool_call_id: call_id, |
| 1532 | content: result.0, |
| 1533 | is_error: result.1, |