use klieo_core::llm::LlmClient;
use klieo_flows::Flow;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
#[derive(Default, Clone)]
pub struct Registry {
models: HashMap<String, Arc<dyn LlmClient>>,
tools: HashSet<String>,
subflows: HashMap<String, Arc<dyn Flow>>,
}
impl Registry {
pub fn new() -> Self {
Self::default()
}
pub fn with_model(mut self, id: impl Into<String>, llm: Arc<dyn LlmClient>) -> Self {
self.models.insert(id.into(), llm);
self
}
pub fn with_tool(mut self, id: impl Into<String>) -> Self {
self.tools.insert(id.into());
self
}
pub fn with_subflow(mut self, id: impl Into<String>, flow: Arc<dyn Flow>) -> Self {
self.subflows.insert(id.into(), flow);
self
}
pub fn model(&self, id: &str) -> Option<Arc<dyn LlmClient>> {
self.models.get(id).cloned()
}
pub fn allows_tool(&self, id: &str) -> bool {
self.tools.contains(id)
}
pub fn subflow(&self, id: &str) -> Option<Arc<dyn Flow>> {
self.subflows.get(id).cloned()
}
pub fn model_ids(&self) -> Vec<&str> {
self.models.keys().map(String::as_str).collect()
}
pub fn tool_ids(&self) -> Vec<&str> {
self.tools.iter().map(String::as_str).collect()
}
pub fn subflow_ids(&self) -> Vec<&str> {
self.subflows.keys().map(String::as_str).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use async_trait::async_trait;
use klieo_core::agent::AgentContext;
use klieo_flows::FlowError;
use serde_json::Value;
struct NoopFlow;
#[async_trait]
impl Flow for NoopFlow {
fn name(&self) -> &str {
"noop"
}
async fn run(&self, _ctx: AgentContext, input: Value) -> Result<Value, FlowError> {
Ok(input)
}
}
#[test]
fn tool_allow_list_distinguishes_registered_from_absent() {
let r = Registry::new().with_tool("lookup");
assert!(r.allows_tool("lookup"));
assert!(!r.allows_tool("delete_everything"));
}
#[test]
fn absent_model_resolves_to_none() {
let r = Registry::new();
assert!(r.model("ghost").is_none());
}
#[test]
fn subflow_lookup_distinguishes_registered_from_absent() {
let r = Registry::new().with_subflow("fraud", Arc::new(NoopFlow));
assert!(r.subflow("fraud").is_some());
assert!(r.subflow("unknown").is_none());
}
#[test]
fn enumerates_registered_palette_ids() {
let llm = crate::test_support::dummy_llm();
let r = Registry::new()
.with_model("m1", llm.clone())
.with_model("m2", llm)
.with_tool("lookup")
.with_subflow("fraud", Arc::new(NoopFlow));
let mut models = r.model_ids();
models.sort_unstable();
assert_eq!(models, vec!["m1", "m2"]);
assert_eq!(r.tool_ids(), vec!["lookup"]);
assert_eq!(r.subflow_ids(), vec!["fraud"]);
}
#[test]
fn empty_registry_enumerates_empty() {
let r = Registry::new();
assert!(r.model_ids().is_empty());
assert!(r.tool_ids().is_empty());
assert!(r.subflow_ids().is_empty());
}
}