kova
Async-first Rust library for building LLM-powered agents. Trait-based architecture with pluggable providers, tool calling, structured output, prompt caching, embeddings, pull-based streaming, thinking-model support, MCP integration, and telemetry. The agent is stateless — the host owns conversation history.
Installation
[]
= "0.1"
# With OpenTelemetry tracing
= { = "0.1", = ["telemetry"] }
Or with cargo:
Architecture
kova
├── agent # Agent + AgentBuilder — the main orchestration loop
├── provider # LlmProvider trait + OpenAI / Bedrock / Gemini / Ollama implementations
├── tool # Tool trait + thread-safe ToolRegistry
├── tools # Built-in fs/shell/web tools (feature `tools` / `web-tools`)
├── mcp # MCP client (stdio / HTTP+SSE / Streamable HTTP + OAuth) + McpTool adapter
├── streaming # SSE / line-framing helpers for provider streams
├── telemetry # TelemetryConfig + MetricsCollector
├── models # Shared data types (messages, content blocks, events)
└── error # Unified KovaError enum
Providers
| Provider | Auth | Thinking models |
|---|---|---|
OpenAiCompatibleProvider |
Bearer token | with_reasoning_effort("high") for o-series models |
BedrockProvider |
SigV4 (explicit / profile / default chain) | with_additional_model_request_fields(json!({"budgetTokens": N})) for Claude |
GeminiProvider |
x-goog-api-key |
with_thinking_budget(N) for gemini-3.5-* models etc |
OllamaProvider |
None (local) | with_think(OllamaThink::High) for qwen3, deepseek-r1, etc. |
Chain-of-thought output from thinking models is returned in ModelResponse::thinking and never stored in conversation history. During streaming it arrives as AgentEvent::ThinkingDelta.
Quick Start
use Arc;
use *;
use ;
async
Stateless by design
Agent::run is the core primitive: you own the conversation history, the agent owns the
turn. Nothing is read from or written to any store — persistence, sessions, and
compaction belong to the host.
let mut history = vec!;
let response = agent.run.await?; // tools execute, loop runs
history.extend; // you persist
println!;
Streaming
Pull-based, no handler registration needed:
use StreamExt;
use AgentEvent;
let stream = agent.run_stream;
pin_mut!;
while let Some = stream.next.await
Reliability
Transient provider failures (connection errors, timeouts, 408/429/5xx) are retried
automatically with exponential backoff — default 2 retries, configurable or disableable
via AgentBuilder::retry_config(RetryConfig { .. }).
Feature Flags
| Flag | Default | Description |
|---|---|---|
openai |
on | OpenAI-compatible provider |
gemini |
on | Google Gemini provider |
ollama |
on | Ollama provider |
bedrock |
on | AWS Bedrock provider (pulls in the AWS SDK crates) |
telemetry |
off | Adds OpenTelemetry dependencies; enables OTLP/Jaeger/stdout span export |
tools |
off | Built-in filesystem and shell tools (read_file, list_dir, search, edit_file, write_file, patch_file, shell) |
web-tools |
off | Adds the fetch_webpage tool and the SSRF-guarded fetch_text helper (for building further network tools); pulls in an HTML parser and readability extraction. Implies tools |
Skip the AWS dependency tree entirely if you don't need Bedrock:
[]
= { = "0.3", = false, = ["openai"] }
Without the telemetry feature, TelemetryConfig::init() installs a lightweight tracing_subscriber — zero OTEL overhead.
The built-in tools are opt-in to keep the core dependency-light. Enable them and register against an injected ToolPolicy that confines filesystem access and guards the web tools against SSRF:
[]
= { = "0.3", = ["web-tools"] }
use Arc;
use ;
let policy = new;
let mut builder = new.provider;
for tool in register_all_tools_with_policy
let agent = builder.build?;
Documentation
| Document | Contents |
|---|---|
| docs/design.md | Architecture, agentic loop, design decisions |
| docs/api-reference.md | Full API with code examples for every module |
| docs/changelog.md | Version history |
| docs/contributing.md | Conventions, adding providers/tools, test guide |