klieo-core 3.3.0

Core traits + runtime for the klieo agent framework.
Documentation

klieo-core

Core traits + runtime for the klieo agent framework.

Part of the klieo Rust agent framework.

Newcomers: start with klieo::App

Direct klieo-core use means hand-wiring Arc<dyn …> ports for LLM, memory, bus, tools, and runlog into an AgentContext. That's the advanced wiring path. For laptop-dev and the common case reach for the klieo umbrella crate:

# async fn run() -> anyhow::Result<()> {
let app = klieo::App::local().build().await?;
# let _ = app; Ok(()) }

App::local() wires LLM (Ollama), short/long/episodic memory (in-memory + SQLite), pubsub (in-process), and a tool dispatcher with sensible defaults. klieo-core is the trait surface those defaults program against — pick this crate directly only when you're writing a new provider, a custom port implementation, or a bespoke AgentContext.

What it is

klieo-core defines the trait surface that all klieo crates program against. Implement these traits once; swap implementations without touching agent code.

Trait surface

Trait / Type Purpose
Agent Runnable agent with typed input/output
SimpleAgent Built-in single-LLM agent implementation
Tool / ToolInvoker Callable tool + dispatcher
LlmClient LLM completion provider
ShortTermMemory Ephemeral key-value memory
LongTermMemory Persistent / vector memory
EpisodicMemory Append-only episode log
Pubsub Publish/subscribe bus
RequestReply RPC over bus
KvStore Distributed key-value store
JobQueue Durable work queue
ServerOutbound Server-initiated outbound requests (MCP/A2A)

Worked example — SimpleAgent

SimpleAgent is the trait-level entry point — built-in single-LLM agent with a tool catalogue, ready to plug into a hand-wired AgentContext or into klieo::App via .agent(...).

[dependencies]
klieo-core = "3"
use klieo_core::llm::ToolDef;
use klieo_core::{Agent, SimpleAgent};

let agent = SimpleAgent::new(
    "weather-bot",
    "Answer weather questions. Use the get_forecast tool when asked.",
    vec![ToolDef::new(
        "get_forecast",
        "Get the forecast for a city.",
        serde_json::json!({
            "type": "object",
            "properties": { "city": { "type": "string" } },
            "required": ["city"],
        }),
    )],
);

assert_eq!(agent.name(), "weather-bot");
assert_eq!(agent.tools().len(), 1);

SimpleAgent::new(name, system_prompt, catalogue) returns an Agent. Running it needs an AgentContext — open klieo::App::builder() to get one wired up; or hand-wire AgentContextBuilder directly when you own every port.

Implementing a custom Tool

For one-off tools, reach for the #[tool] macro from klieo-macros — generates Tool + JSON schema from an async fn. For tools that don't fit the macro shape (custom schema, hand-tuned error mapping, stateful tools) implement the trait directly:

use klieo_core::tool::{Tool, ToolCtx};
use klieo_core::error::ToolError;
use async_trait::async_trait;

struct MyTool;

#[async_trait]
impl Tool for MyTool {
    fn name(&self) -> &str { "my_tool" }
    fn description(&self) -> &str { "Does something useful." }
    fn json_schema(&self) -> &serde_json::Value {
        static SCHEMA: std::sync::OnceLock<serde_json::Value> = std::sync::OnceLock::new();
        SCHEMA.get_or_init(|| serde_json::json!({}))
    }

    async fn invoke(
        &self,
        _args: serde_json::Value,
        _ctx: ToolCtx,
    ) -> Result<serde_json::Value, ToolError> {
        Ok(serde_json::json!({ "result": "ok" }))
    }
}

Status

3.x — stable. See docs/SEMVER.md.

License

MIT — see LICENSE.