use std::ops::Deref;
use std::sync::Arc;
use crate::types::{AgentMessage, AssistantMessage, LlmMessage, ToolResultMessage};
pub type ConvertToLlmFn = dyn Fn(&AgentMessage) -> Option<LlmMessage> + Send + Sync;
pub struct ContextMessages {
messages: Vec<AgentMessage>,
mirror: Vec<Option<Arc<LlmMessage>>>,
}
impl ContextMessages {
#[must_use]
pub fn new(messages: Vec<AgentMessage>) -> Self {
Self {
messages,
mirror: Vec::new(),
}
}
pub fn push(&mut self, message: AgentMessage) {
self.messages.push(message);
}
pub fn extend<I: IntoIterator<Item = AgentMessage>>(&mut self, iter: I) {
self.messages.extend(iter);
}
pub fn append(&mut self, other: &mut Vec<AgentMessage>) {
self.messages.append(other);
}
pub fn set(&mut self, index: usize, message: AgentMessage) {
self.messages[index] = message;
if index < self.mirror.len() {
self.mirror.truncate(index);
}
}
pub fn make_mut(&mut self) -> &mut Vec<AgentMessage> {
self.mirror.clear();
&mut self.messages
}
pub fn take_vec(&mut self) -> Vec<AgentMessage> {
self.mirror.clear();
std::mem::take(&mut self.messages)
}
#[must_use]
pub fn into_vec(self) -> Vec<AgentMessage> {
self.messages
}
#[must_use]
pub fn as_slice(&self) -> &[AgentMessage] {
&self.messages
}
pub fn snapshot_llm(&mut self) -> Arc<Vec<Arc<LlmMessage>>> {
let start = self.mirror.len();
for message in &self.messages[start..] {
self.mirror.push(match message {
AgentMessage::Llm(llm) => Some(Arc::new(llm.clone())),
AgentMessage::Custom(_) => None,
});
}
Arc::new(self.mirror.iter().flatten().cloned().collect())
}
}
impl Deref for ContextMessages {
type Target = [AgentMessage];
fn deref(&self) -> &Self::Target {
&self.messages
}
}
pub struct LoopState {
pub context_messages: ContextMessages,
pub pending_messages: Vec<AgentMessage>,
pub initial_new_messages_len: usize,
pub overflow_signal: bool,
pub overflow_recovery_attempted: bool,
pub turn_index: usize,
pub accumulated_usage: crate::types::Usage,
pub accumulated_cost: crate::types::Cost,
pub last_assistant_message: Option<AssistantMessage>,
pub last_tool_results: Vec<ToolResultMessage>,
pub transfer_chain: crate::transfer::TransferChain,
pub reasoning_only_nudged: bool,
}
pub enum TurnOutcome {
ContinueInner,
BreakInner,
Return,
}
pub struct ToolCallInfo {
pub id: String,
pub name: String,
pub arguments: serde_json::Value,
pub is_incomplete: bool,
}
#[allow(clippy::large_enum_variant)]
pub enum StreamResult {
Message(AssistantMessage),
ContextOverflow,
Aborted,
ChannelClosed,
}
pub enum ToolExecOutcome {
Completed {
results: Vec<ToolResultMessage>,
tool_metrics: Vec<crate::metrics::ToolExecMetrics>,
transfer_signal: Option<crate::transfer::TransferSignal>,
injected_messages: Vec<AgentMessage>,
},
Stopped {
results: Vec<ToolResultMessage>,
tool_metrics: Vec<crate::metrics::ToolExecMetrics>,
reason: String,
injected_messages: Vec<AgentMessage>,
},
SteeringInterrupt {
completed: Vec<ToolResultMessage>,
cancelled: Vec<ToolResultMessage>,
steering_messages: Vec<AgentMessage>,
tool_metrics: Vec<crate::metrics::ToolExecMetrics>,
injected_messages: Vec<AgentMessage>,
},
Aborted {
results: Vec<ToolResultMessage>,
tool_metrics: Vec<crate::metrics::ToolExecMetrics>,
injected_messages: Vec<AgentMessage>,
},
ChannelClosed,
}
#[cfg(test)]
#[path = "types_tests.rs"]
mod tests;