oxi_agent/agent_loop/
helpers.rs1use oxi_ai::{ContentBlock, TextContent, ToolCall, ToolResultMessage};
3use std::sync::atomic::{AtomicBool, Ordering};
4use std::sync::Arc;
5
6pub fn extract_tool_calls(message: &oxi_ai::AssistantMessage) -> Vec<ToolCall> {
8 let mut tool_calls = Vec::new();
9
10 for block in &message.content {
11 if let ContentBlock::ToolCall(tc) = block {
12 tool_calls.push(tc.clone());
13 }
14 }
15
16 tool_calls
17}
18
19pub fn create_tool_result_message(finalized: &FinalizedToolCall) -> ToolResultMessage {
21 let content_blocks = if let Some(ref blocks) = finalized.result.content_blocks {
22 blocks.clone()
23 } else {
24 vec![ContentBlock::Text(TextContent::new(
25 finalized.result.output.clone(),
26 ))]
27 };
28
29 ToolResultMessage::new(
30 finalized.tool_call.id.clone(),
31 &finalized.tool_call.name,
32 content_blocks,
33 )
34}
35
36pub fn should_terminate_batch(finalized_calls: &[FinalizedToolCall]) -> bool {
40 if finalized_calls.is_empty() {
41 return false;
42 }
43 finalized_calls.iter().all(|f| f.result.terminate)
44}
45
46pub fn should_stop_after_turn(
56 _messages: &[oxi_ai::Message],
57 _assistant_message: &oxi_ai::AssistantMessage,
58 max_iterations: usize,
59 external_stop: &Arc<AtomicBool>,
60 turn_number: usize,
61) -> bool {
62 if external_stop.load(Ordering::SeqCst) {
64 return true;
65 }
66
67 if turn_number >= max_iterations {
70 return true;
71 }
72
73 false
74}
75
76use crate::AgentToolResult;
77
78pub struct FinalizedToolCall {
80 pub tool_call: oxi_ai::ToolCall,
82 pub result: AgentToolResult,
84 pub is_error: bool,
86}