Skip to main content

ainl_runtime/
adapters.rs

1//! Patch adapter registry (stub). v0.3+ will add real HTTP/shell/MCP implementations.
2
3use std::collections::HashMap;
4
5/// Trait for patch/tool adapters. Implement to give dispatched patches
6/// real execution targets. Register via [`crate::AinlRuntime::register_adapter`].
7///
8/// v0.3.0+ will ship HTTP, shell, and MCP adapter implementations.
9/// When no adapter is registered for a label, dispatch is metadata-only
10/// (existing v0.2 behavior preserved).
11pub trait PatchAdapter: Send + Sync {
12    /// Canonical slug matching ainl-semantic-tagger tool names
13    /// e.g. "bash", "search_web", "mcp", "python_repl"
14    fn name(&self) -> &str;
15
16    /// Execute the patch. Called when declared_reads are satisfied.
17    fn execute(
18        &self,
19        label: &str,
20        frame: &HashMap<String, serde_json::Value>,
21    ) -> Result<serde_json::Value, String>;
22}
23
24#[derive(Default)]
25pub struct AdapterRegistry {
26    adapters: HashMap<String, Box<dyn PatchAdapter>>,
27}
28
29impl AdapterRegistry {
30    pub fn new() -> Self {
31        Self::default()
32    }
33
34    pub fn register(&mut self, adapter: impl PatchAdapter + 'static) {
35        self.adapters.insert(adapter.name().to_string(), Box::new(adapter));
36    }
37
38    pub fn get(&self, name: &str) -> Option<&dyn PatchAdapter> {
39        self.adapters.get(name).map(|boxed| boxed.as_ref())
40    }
41
42    pub fn registered_names(&self) -> Vec<&str> {
43        self.adapters.keys().map(|s| s.as_str()).collect()
44    }
45
46    pub fn is_empty(&self) -> bool {
47        self.adapters.is_empty()
48    }
49}