use serde::{Deserialize, Serialize};
use std::fmt;
use terraphim_types::capability::{Capability, Provider};
use thiserror::Error;
#[derive(Debug, Clone)]
pub struct RoutingDecision {
pub provider: Provider,
pub matched_capabilities: Vec<Capability>,
pub confidence: f32,
pub reason: RoutingReason,
}
#[derive(Debug, Clone, PartialEq)]
pub enum RoutingReason {
KeywordMatch { keyword: String },
CapabilityMatch { capabilities: Vec<Capability> },
ExplicitMention { mention: String },
Fallback,
}
impl fmt::Display for RoutingReason {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RoutingReason::KeywordMatch { keyword } => {
write!(f, "keyword match: '{}'", keyword)
}
RoutingReason::CapabilityMatch { capabilities } => {
write!(f, "capability match: {:?}", capabilities)
}
RoutingReason::ExplicitMention { mention } => {
write!(f, "explicit mention: {}", mention)
}
RoutingReason::Fallback => {
write!(f, "fallback to default")
}
}
}
}
#[derive(Debug, Clone, Default)]
pub struct RoutingContext {
pub source_agent: Option<String>,
pub conversation_id: Option<String>,
pub user_id: Option<String>,
pub strategy_override: Option<String>,
}
#[derive(Debug)]
pub enum RoutingResult {
LlmResponse(String),
AgentSpawned(ProcessId),
Error(String),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ProcessId(pub String);
impl ProcessId {
pub fn new() -> Self {
Self(uuid::Uuid::new_v4().to_string())
}
}
impl Default for ProcessId {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for ProcessId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Error, Debug, Clone)]
pub enum RoutingError {
#[error("No provider found for capabilities: {0:?}")]
NoProviderFound(Vec<Capability>),
#[error("Provider not found: {0}")]
ProviderNotFound(String),
#[error("Registry error: {0}")]
RegistryError(String),
#[error("Execution error: {0}")]
ExecutionError(String),
#[error("IO error: {0}")]
Io(String),
#[error("Serialization error: {0}")]
Serialization(String),
}
#[derive(Debug, Clone)]
pub struct Task {
pub id: String,
pub source: String,
pub target: String,
pub context: String,
pub created_at: chrono::DateTime<chrono::Utc>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_process_id_generation() {
let id1 = ProcessId::new();
let id2 = ProcessId::new();
assert_ne!(id1.0, id2.0);
assert!(!id1.0.is_empty());
}
#[test]
fn test_routing_reason_display() {
let reason = RoutingReason::KeywordMatch {
keyword: "think".to_string(),
};
assert_eq!(reason.to_string(), "keyword match: 'think'");
let reason = RoutingReason::Fallback;
assert_eq!(reason.to_string(), "fallback to default");
}
}