#[cfg(any(test, feature = "mock"))]
pub mod mock;
use std::sync::Arc;
use async_trait::async_trait;
use serde_json::Value;
use crate::error::Result;
#[async_trait]
pub trait LlmProvider: Send + Sync {
async fn complete(&self, request: Value, conn: Option<&str>) -> Result<Value>;
}
#[async_trait]
pub trait ToolInvoker: Send + Sync {
async fn invoke(&self, slug: &str, args: Value, conn: Option<&str>) -> Result<Value>;
}
#[async_trait]
pub trait HttpClient: Send + Sync {
async fn request(&self, request: Value, conn: Option<&str>) -> Result<Value>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CodeLanguage {
JavaScript,
Python,
}
#[async_trait]
pub trait CodeRunner: Send + Sync {
async fn run(&self, language: CodeLanguage, source: &str, input: Value) -> Result<Value>;
}
#[async_trait]
pub trait StateStore: Send + Sync {
async fn load(&self, key: &str) -> Result<Option<Value>>;
async fn store(&self, key: &str, value: Value) -> Result<()>;
}
#[derive(Clone)]
pub struct Capabilities {
pub llm: Arc<dyn LlmProvider>,
pub tools: Arc<dyn ToolInvoker>,
pub http: Arc<dyn HttpClient>,
pub code: Arc<dyn CodeRunner>,
pub state: Arc<dyn StateStore>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::caps::mock::mock_capabilities;
use serde_json::json;
#[test]
fn code_language_is_copy_and_comparable() {
let js = CodeLanguage::JavaScript;
let copied = js; assert_eq!(js, copied);
assert_eq!(js, CodeLanguage::JavaScript);
assert_ne!(CodeLanguage::JavaScript, CodeLanguage::Python);
}
#[test]
fn code_language_debug_names_the_variant() {
assert_eq!(format!("{:?}", CodeLanguage::JavaScript), "JavaScript");
assert_eq!(format!("{:?}", CodeLanguage::Python), "Python");
}
#[test]
fn capabilities_bundle_is_cloneable_and_shares_impls() {
let caps = mock_capabilities();
let clone = caps.clone();
assert!(Arc::ptr_eq(&caps.llm, &clone.llm));
assert!(Arc::ptr_eq(&caps.tools, &clone.tools));
assert!(Arc::ptr_eq(&caps.http, &clone.http));
assert!(Arc::ptr_eq(&caps.code, &clone.code));
assert!(Arc::ptr_eq(&caps.state, &clone.state));
}
#[tokio::test]
async fn capabilities_dispatch_through_trait_objects() {
let caps = mock_capabilities();
let out = caps
.llm
.complete(json!({"prompt": "hi"}), None)
.await
.unwrap();
assert_eq!(out["completion"]["prompt"], "hi");
}
}