use std::future::Future;
use std::pin::Pin;
use serde::{Deserialize, Serialize};
use crate::stdlib::shared::truncated;
pub const AGENTS_MODULE_NAME: &str = "submilli:agents";
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AgentRequest {
pub agent: String,
pub input: String,
pub schema: Option<String>,
pub caller: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AgentOutcome {
pub text: String,
pub usage: Option<AgentUsage>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct AgentUsage {
pub input_tokens: Option<u64>,
pub output_tokens: Option<u64>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AgentInfo {
pub name: String,
pub description: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum AgentCallError {
NotConfigured,
NotFound { agent: String },
Failed { agent: String, message: String },
Cancelled { agent: String },
}
impl std::fmt::Display for AgentCallError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NotConfigured => write!(
f,
"no agent provider is configured: this harness does not run sub-agents"
),
Self::NotFound { agent } => write!(
f,
"no agent named `{}`; call `list()` for the agents you may use",
truncated(agent)
),
Self::Failed { agent, message } => {
write!(f, "agent `{}` failed: {message}", truncated(agent))
}
Self::Cancelled { agent } => write!(f, "agent `{}` was cancelled", truncated(agent)),
}
}
}
impl std::error::Error for AgentCallError {}
pub trait AgentProvider: Send + Sync {
fn run<'a>(
&'a self,
request: AgentRequest,
) -> Pin<Box<dyn Future<Output = Result<AgentOutcome, AgentCallError>> + Send + 'a>>;
fn agents<'a>(
&'a self,
) -> Pin<Box<dyn Future<Output = Result<Vec<AgentInfo>, AgentCallError>> + Send + 'a>>;
}