use std::collections::HashMap;
use crate::actions::ActionDef;
use crate::exploration::{DependencyGraph, SelectResult};
use crate::extensions::Extensions;
use crate::types::WorkerId;
pub use super::manager::{BatchDecisionRequest, ManagerId, WorkerDecisionRequest};
pub trait BatchInvoker: Send + Sync {
fn invoke(&self, request: BatchDecisionRequest, extensions: &Extensions) -> BatchInvokeResult;
fn plan_dependencies(
&self,
_task: &str,
_actions: &[ActionDef],
_hint: Option<&SelectResult>,
) -> Option<DependencyGraph> {
None
}
fn name(&self) -> &str;
fn is_healthy(&self) -> bool {
true
}
}
pub type BatchInvokeResult = Vec<(WorkerId, Result<DecisionResponse, BatchInvokeError>)>;
#[derive(Debug, Clone, thiserror::Error)]
pub enum BatchInvokeError {
#[error("Batch invoke error (transient): {0}")]
Transient(String),
#[error("Batch invoke error: {0}")]
Permanent(String),
}
impl BatchInvokeError {
pub fn transient(message: impl Into<String>) -> Self {
Self::Transient(message.into())
}
pub fn permanent(message: impl Into<String>) -> Self {
Self::Permanent(message.into())
}
pub fn is_transient(&self) -> bool {
matches!(self, Self::Transient(_))
}
pub fn message(&self) -> &str {
match self {
Self::Transient(msg) => msg,
Self::Permanent(msg) => msg,
}
}
}
impl From<crate::error::SwarmError> for BatchInvokeError {
fn from(err: crate::error::SwarmError) -> Self {
if err.is_transient() {
Self::Transient(err.message())
} else {
Self::Permanent(err.message())
}
}
}
impl From<BatchInvokeError> for crate::error::SwarmError {
fn from(err: BatchInvokeError) -> Self {
match err {
BatchInvokeError::Transient(message) => {
crate::error::SwarmError::LlmTransient { message }
}
BatchInvokeError::Permanent(message) => {
crate::error::SwarmError::LlmPermanent { message }
}
}
}
}
#[derive(Debug, Clone)]
pub struct DecisionResponse {
pub tool: String,
pub target: String,
pub args: HashMap<String, String>,
pub reasoning: Option<String>,
pub confidence: f64,
pub prompt: Option<String>,
pub raw_response: Option<String>,
}
impl Default for DecisionResponse {
fn default() -> Self {
Self {
tool: String::new(),
target: String::new(),
args: HashMap::new(),
reasoning: None,
confidence: 0.0,
prompt: None,
raw_response: None,
}
}
}