use async_trait::async_trait;
use crate::{ContentBlock, Message, ModelInfo, ReasoningOptions};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RoundBoundary {
ToolResultsCommitted,
AssistantMessageCommitted,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct RoundToolResult {
pub tool_use_id: String,
pub tool_name: String,
pub is_error: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum ReasoningChange {
Set(ReasoningOptions),
Clear,
}
#[derive(Clone, Debug, Default)]
#[non_exhaustive]
pub struct RoundAdjustment {
pub(crate) model: Option<ModelInfo>,
pub(crate) reasoning: Option<ReasoningChange>,
}
impl RoundAdjustment {
pub fn new() -> Self {
Self::default()
}
pub fn with_model(mut self, model: ModelInfo) -> Self {
self.model = Some(model);
self
}
pub fn with_reasoning(mut self, reasoning: ReasoningChange) -> Self {
self.reasoning = Some(reasoning);
self
}
pub fn is_empty(&self) -> bool {
self.model.is_none() && self.reasoning.is_none()
}
}
#[non_exhaustive]
pub enum RoundDecision {
Continue(RoundAdjustment),
Inject {
content: Vec<ContentBlock>,
adjust: RoundAdjustment,
},
Stop,
}
impl RoundDecision {
pub fn proceed() -> Self {
RoundDecision::Continue(RoundAdjustment::default())
}
pub fn inject(content: impl Into<Vec<ContentBlock>>) -> Self {
RoundDecision::Inject {
content: content.into(),
adjust: RoundAdjustment::default(),
}
}
pub fn stop() -> Self {
RoundDecision::Stop
}
}
pub struct RoundContext<'a> {
boundary: RoundBoundary,
assistant_message: Option<&'a Message>,
tool_results: &'a [RoundToolResult],
rounds_completed: usize,
model_requests: usize,
transport_retries: usize,
}
impl<'a> RoundContext<'a> {
pub(crate) fn new(
boundary: RoundBoundary,
assistant_message: Option<&'a Message>,
tool_results: &'a [RoundToolResult],
rounds_completed: usize,
model_requests: usize,
transport_retries: usize,
) -> Self {
Self {
boundary,
assistant_message,
tool_results,
rounds_completed,
model_requests,
transport_retries,
}
}
pub fn boundary(&self) -> RoundBoundary {
self.boundary
}
pub fn assistant_message(&self) -> Option<&Message> {
self.assistant_message
}
pub fn tool_results(&self) -> &[RoundToolResult] {
self.tool_results
}
pub fn rounds_completed(&self) -> usize {
self.rounds_completed
}
pub fn model_requests(&self) -> usize {
self.model_requests
}
pub fn transport_retries(&self) -> usize {
self.transport_retries
}
}
#[async_trait]
pub trait RoundStrategy: Send + Sync {
async fn on_round(&self, ctx: RoundContext<'_>) -> RoundDecision;
}