pub mod config;
pub use enki_core as core;
pub use enki_llm as llm;
pub use enki_local as local;
pub use enki_memory as memory;
pub use enki_observability::logging;
pub use enki_observability::metrics;
#[cfg(feature = "mcp")]
pub use enki_mcp as mcp;
pub use config::{AgentConfig, MemoryBackendType, MemoryConfig, MeshConfig};
pub use enki_core::{
Agent, AgentContext, AgentEvent, Memory, MemoryEntry, MemoryQuery, Mesh, Message, VectorMemory,
};
pub use enki_llm::{LLMConfig, LlmAgent, LlmAgentBuilder, UniversalLLMClient};
pub use enki_local::LocalMesh;
pub use enki_memory::InMemoryBackend;
#[cfg(feature = "sqlite")]
pub use enki_memory::SqliteBackend;
#[cfg(feature = "redis")]
pub use enki_memory::RedisBackend;
#[cfg(feature = "qdrant")]
pub use enki_memory::QdrantBackend;
#[cfg(feature = "chromadb")]
pub use enki_memory::ChromaDBBackend;
#[cfg(feature = "pinecone")]
pub use enki_memory::PineconeBackend;
#[cfg(feature = "mcp")]
pub use enki_mcp::{McpAgentServer, McpClient, McpTransport};
pub trait LlmAgentFromConfig {
fn from_config(config: AgentConfig) -> core::error::Result<LlmAgent>;
}
impl LlmAgentFromConfig for LlmAgent {
fn from_config(config: AgentConfig) -> core::error::Result<LlmAgent> {
let mut builder = LlmAgentBuilder::new(&config.name, &config.model)
.with_system_prompt(&config.system_prompt);
if let Some(ref api_key) = config.api_key {
builder = builder.with_api_key(api_key);
}
if let Some(temperature) = config.temperature {
builder = builder.with_temperature(temperature);
}
if let Some(max_tokens) = config.max_tokens {
builder = builder.with_max_tokens(max_tokens);
}
builder.build()
}
}
pub trait MemoryFromConfig {
fn from_config(config: &MemoryConfig) -> Self;
}
impl MemoryFromConfig for InMemoryBackend {
fn from_config(config: &MemoryConfig) -> Self {
let mut backend = InMemoryBackend::new();
if let Some(max_entries) = config.max_entries {
backend = backend.with_max_entries(max_entries);
}
if let Some(ttl_seconds) = config.ttl_seconds {
backend = backend.with_ttl_seconds(ttl_seconds);
}
backend
}
}
#[cfg(any(
feature = "sqlite",
feature = "redis",
feature = "qdrant",
feature = "chromadb",
feature = "pinecone"
))]
#[async_trait::async_trait]
pub trait MemoryFromConfigAsync {
async fn from_config_async(config: &MemoryConfig) -> core::error::Result<Self>
where
Self: Sized;
}
#[cfg(feature = "sqlite")]
#[async_trait::async_trait]
impl MemoryFromConfigAsync for SqliteBackend {
async fn from_config_async(config: &MemoryConfig) -> core::error::Result<Self> {
let path = config.path.as_deref().unwrap_or(":memory:");
SqliteBackend::new(path).await
}
}
#[cfg(feature = "redis")]
#[async_trait::async_trait]
impl MemoryFromConfigAsync for RedisBackend {
async fn from_config_async(config: &MemoryConfig) -> core::error::Result<Self> {
let url = config.url.as_deref().unwrap_or("redis://localhost:6379");
let mut backend = RedisBackend::new(url).await?;
if let Some(ref prefix) = config.prefix {
backend = backend.with_prefix(prefix);
}
if let Some(ttl_seconds) = config.ttl_seconds {
backend = backend.with_ttl_seconds(ttl_seconds);
}
Ok(backend)
}
}
#[cfg(feature = "qdrant")]
#[async_trait::async_trait]
impl MemoryFromConfigAsync for QdrantBackend {
async fn from_config_async(config: &MemoryConfig) -> core::error::Result<Self> {
let grpc_url = config
.grpc_url
.as_deref()
.unwrap_or("http://localhost:6334");
let collection = config.collection.as_deref().unwrap_or("enki_memory");
let dimensions = config.dimensions.unwrap_or(384);
QdrantBackend::new(grpc_url, collection, dimensions).await
}
}
#[cfg(feature = "chromadb")]
#[async_trait::async_trait]
impl MemoryFromConfigAsync for ChromaDBBackend {
async fn from_config_async(config: &MemoryConfig) -> core::error::Result<Self> {
let url = config.url.as_deref().unwrap_or("http://localhost:8000");
let collection = config.collection.as_deref().unwrap_or("enki_memory");
ChromaDBBackend::new(url, collection).await
}
}
#[cfg(feature = "pinecone")]
#[async_trait::async_trait]
impl MemoryFromConfigAsync for PineconeBackend {
async fn from_config_async(config: &MemoryConfig) -> core::error::Result<Self> {
let api_key = config
.api_key
.as_deref()
.ok_or_else(|| core::error::Error::MemoryError("Pinecone requires api_key".into()))?;
let collection = config.collection.as_deref().unwrap_or("enki-memory");
let dimensions = config.dimensions.unwrap_or(1536);
PineconeBackend::new(api_key, collection, dimensions).await
}
}