use serde::{Deserialize, Serialize};
use crate::registry_spec::{AgentSpec, McpServerSpec, ModelBindingSpec, ProviderSpec};
use crate::tool_spec::ToolSpec;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum BuiltinSpec {
Agent(Box<AgentSpec>),
Provider(ProviderSpec),
Model(ModelBindingSpec),
McpServer(McpServerSpec),
Tool(ToolSpec),
}
impl BuiltinSpec {
pub fn agent(spec: AgentSpec) -> Self {
Self::Agent(Box::new(spec))
}
pub fn provider(spec: ProviderSpec) -> Self {
Self::Provider(spec)
}
pub fn model(spec: ModelBindingSpec) -> Self {
Self::Model(spec)
}
pub fn mcp_server(spec: McpServerSpec) -> Self {
Self::McpServer(spec)
}
pub fn tool(spec: ToolSpec) -> Self {
Self::Tool(spec)
}
pub fn namespace(&self) -> &'static str {
match self {
Self::Agent(_) => "agents",
Self::Provider(_) => "providers",
Self::Model(_) => "models",
Self::McpServer(_) => "mcp-servers",
Self::Tool(_) => "tools",
}
}
pub fn id(&self) -> &str {
match self {
Self::Agent(s) => &s.id,
Self::Provider(s) => &s.id,
Self::Model(s) => &s.id,
Self::McpServer(s) => &s.id,
Self::Tool(s) => &s.id,
}
}
}
#[derive(Debug, Clone)]
pub struct BuiltinSeedSet {
pub binary_version: String,
pub specs: Vec<BuiltinSpec>,
}
impl BuiltinSeedSet {
pub fn empty(binary_version: impl Into<String>) -> Self {
Self {
binary_version: binary_version.into(),
specs: Vec::new(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn constructor_agent_wraps_in_box() {
let spec = AgentSpec {
id: "a1".to_owned(),
model_id: "gpt-4o".to_owned(),
system_prompt: "hi".to_owned(),
..Default::default()
};
assert!(matches!(BuiltinSpec::agent(spec), BuiltinSpec::Agent(_)));
}
#[test]
fn constructor_provider_wraps() {
let spec = ProviderSpec {
id: "p1".to_owned(),
adapter: "openai".to_owned(),
..Default::default()
};
assert!(matches!(
BuiltinSpec::provider(spec),
BuiltinSpec::Provider(_)
));
}
#[test]
fn constructor_model_wraps() {
let spec = ModelBindingSpec {
id: "m1".to_owned(),
provider_id: "openai".to_owned(),
upstream_model: "gpt-4o".to_owned(),
};
assert!(matches!(BuiltinSpec::model(spec), BuiltinSpec::Model(_)));
}
#[test]
fn constructor_mcp_server_wraps() {
let spec = McpServerSpec {
id: "mcp1".to_owned(),
..Default::default()
};
assert!(matches!(
BuiltinSpec::mcp_server(spec),
BuiltinSpec::McpServer(_)
));
}
#[test]
fn constructor_tool_wraps() {
let spec = crate::tool_spec::ToolSpec {
id: "t1".into(),
name: "Tool 1".into(),
description: "x".into(),
..Default::default()
};
assert!(matches!(BuiltinSpec::tool(spec), BuiltinSpec::Tool(_)));
}
#[test]
fn tool_namespace_and_id() {
let spec = crate::tool_spec::ToolSpec {
id: "t1".into(),
name: "x".into(),
description: "x".into(),
..Default::default()
};
let bi = BuiltinSpec::tool(spec);
assert_eq!(bi.namespace(), "tools");
assert_eq!(bi.id(), "t1");
}
}