agent-runtime
agent-runtime is a unified Tokio async agent runtime for Rust. It combines orchestration primitives, episodic and semantic memory, an in-memory knowledge graph, and a ReAct (Thought-Action-Observation) agent loop in a single crate.
The library consolidates the public APIs of tokio-prompt-orchestrator, tokio-agent-memory,
mem-graph, and wasm-agent, and extends them with pluggable LLM providers, optional
file-based persistence with per-step checkpointing, lock-free runtime metrics, and a
compile-time typestate builder that prevents misconfiguration at zero runtime cost.
What it does
- ReAct agent loop — runs Thought → Action → Observation cycles with a pluggable tool
registry. Terminates on
FINAL_ANSWERormax_iterations, whichever comes first. - Episodic memory — per-agent event store with configurable decay, hybrid recall scoring, per-agent capacity limits, and recall-count tracking.
- Semantic memory — key-value store with tag-based retrieval and cosine-similarity vector search.
- Working memory — bounded LRU key-value store injected into the agent prompt.
- Knowledge graph — directed in-memory graph with BFS, DFS, Dijkstra shortest-path, transitive closure, degree and betweenness centrality, community detection, cycle detection, and subgraph extraction.
- Circuit breaker — configurable failure threshold and recovery window with a pluggable backend trait for distributed state (e.g., Redis).
- Retry policy — exponential backoff capped at 60 s.
- Deduplicator — TTL-based request deduplication with in-flight tracking.
- Backpressure guard — hard and soft capacity limits with tracing warnings.
- Pipeline — composable string-transform stage chain.
- LLM providers — built-in
AnthropicProviderandOpenAiProviderwith SSE streaming (behind feature flags). - Persistence — async
PersistenceBackendtrait andFilePersistenceBackendfor session and per-step checkpointing. - Metrics — atomic counters for active/total sessions, steps, tool calls, backpressure sheds, and memory recalls.
How it works
User Code
|
v
+--------------------+ compile-time typestate
| AgentRuntime |<---- AgentRuntimeBuilder<NeedsConfig>
| runtime.rs | .with_agent_config() -->
+----+----+----+-----+ AgentRuntimeBuilder<HasConfig>
| | | .build() (infallible)
| | |
| | +--------------------------------------------+
| | |
| +-------------------+ |
| | |
v v v
+--------------------+ +---------------------+ +--------------------+
| memory.rs | | graph.rs | | orchestrator.rs |
| | | | | |
| EpisodicStore | | GraphStore | | CircuitBreaker |
| DecayPolicy | | BFS / DFS | | RetryPolicy |
| RecallPolicy | | Dijkstra | | Deduplicator |
| per-agent cap | | transitive close | | BackpressureGuard |
| SemanticStore | | centrality | | Pipeline |
| cosine search | | community detect | +--------------------+
| WorkingMemory | | cycle detection |
| LRU eviction | +---------------------+
+--------------------+
|
v
+--------------------+
| agent.rs |
| |
| ReActLoop |<--- ToolRegistry (ToolSpec, per-tool CircuitBreaker)
| AgentConfig |
| AgentSession |
+--------------------+
|
+---------------------------+
| |
v v
+--------------------+ +--------------------+
| providers.rs | | persistence.rs |
| LlmProvider trait | | PersistenceBackend|
| AnthropicProvider | | FilePersistence |
| OpenAiProvider | | session checkpoint|
+--------------------+ | per-step snapshot |
+--------------------+
|
+---------+
v
+--------------------+
| metrics.rs |
| RuntimeMetrics |
| (atomic counters) |
+--------------------+
Data flow inside run_agent
BackpressureGuardis checked; sessions exceeding capacity are rejected immediately withAgentRuntimeError::BackpressureShed.EpisodicStoreis recalled for the agent; matching items are injected into the prompt, subject tomax_memory_recallsand the optionalmax_memory_tokenstoken budget.WorkingMemorykey-value pairs are appended to the enriched prompt.GraphStoreentity count is captured for session metadata.ReActLoopruns Thought-Action-Observation cycles, dispatching tool calls throughToolRegistry.- Per-tool
CircuitBreaker(optional) fast-fails unhealthy tools and records structured error observations withkindclassification (not_found,transient,permanent). - On completion an
AgentSessionis returned; if aPersistenceBackendis configured, the final session and every per-step snapshot are saved atomically. RuntimeMetricscounters are updated atomically throughout.
Quickstart
1. Add to Cargo.toml
[]
= "1.0"
= { = "1", = ["full"] }
To enable built-in LLM providers:
= { = "1.0", = ["anthropic", "openai"] }
To opt in to only the subsystems you need:
= { = "1.0", = false, = ["memory", "orchestrator"] }
2. Environment variables
# required for AnthropicProvider
# required for OpenAiProvider
# optional structured logging
3. Minimal example (no external services)
The default feature set (orchestrator, memory, graph, wasm) runs entirely in-process
with no API keys, no Redis, and no database.
use *;
async
4. Using a built-in provider
use ;
async
Feature Flags
| Feature | Default | Description |
|---|---|---|
orchestrator |
yes | CircuitBreaker with pluggable backends, RetryPolicy, Deduplicator, BackpressureGuard with soft limit, Pipeline |
memory |
yes | EpisodicStore with DecayPolicy, RecallPolicy::Hybrid, per-agent capacity; SemanticStore with cosine search; WorkingMemory LRU |
graph |
yes | GraphStore — BFS, DFS, Dijkstra, transitive closure, degree/betweenness centrality, community detection, subgraph, cycle detection |
wasm |
yes | ReActLoop, ToolRegistry, ToolSpec, parse_react_step, AgentConfig |
persistence |
no | PersistenceBackend trait + FilePersistenceBackend; session and per-step checkpointing |
providers |
no | LlmProvider async trait |
anthropic |
no | Built-in Anthropic Messages API provider with SSE streaming (implies providers + reqwest) |
openai |
no | Built-in OpenAI Chat Completions API provider with SSE streaming and custom base-URL support (implies providers + reqwest) |
redis-circuit-breaker |
no | Distributed CircuitBreakerBackend via Redis |
full |
no | All features simultaneously |
API Reference
AgentRuntime builder
let runtime = builder // AgentRuntimeBuilder<NeedsConfig>
.with_memory
.with_working_memory
.with_graph
.with_backpressure
.register_tool
.with_metrics
.with_checkpoint_backend // persistence feature
.with_agent_config // --> AgentRuntimeBuilder<HasConfig>
.build; // infallible
| Method | Argument | Description |
|---|---|---|
.with_agent_config(cfg) |
AgentConfig |
Required. Transitions builder to HasConfig. |
.with_memory(store) |
EpisodicStore |
Episodic memory recalled and injected into the prompt. |
.with_working_memory(wm) |
WorkingMemory |
Bounded key-value working memory appended to the prompt. |
.with_graph(graph) |
GraphStore |
Knowledge graph; entity count captured in session metadata. |
.with_backpressure(guard) |
BackpressureGuard |
Rejects sessions when in-flight count exceeds capacity. |
.register_tool(spec) |
ToolSpec |
Adds a callable tool to the ReAct loop. |
.with_metrics(m) |
Arc<RuntimeMetrics> |
Shares a custom metrics instance. |
.with_checkpoint_backend(b) |
Arc<dyn PersistenceBackend> |
Enables checkpointing (persistence feature). |
AgentConfig
| Field / Builder | Type | Default | Description |
|---|---|---|---|
max_iterations |
usize |
required | Maximum Thought-Action-Observation cycles |
model |
String |
required | Model identifier forwarded to the infer closure |
.with_system_prompt(s) |
String |
"You are a helpful AI agent." |
Injected at the head of every context string |
.with_max_memory_recalls(n) |
usize |
3 |
Maximum episodic items injected per run |
.with_max_memory_tokens(n) |
usize |
None |
Approximate token budget (~4 chars/token) |
EpisodicStore constructors
| Constructor | Description |
|---|---|
EpisodicStore::new() |
Unbounded, no decay, importance-ranked |
EpisodicStore::with_decay(policy) |
DecayPolicy::exponential(half_life_hours) |
EpisodicStore::with_recall_policy(p) |
RecallPolicy::Hybrid { recency_weight, frequency_weight } |
EpisodicStore::with_per_agent_capacity(n) |
Evicts lowest-importance item when agent exceeds n memories |
BackpressureGuard
let guard = new? // hard limit
.with_soft_limit?; // warn when depth reaches 75
CircuitBreaker
let cb = new?;
let result = cb.call?;
ToolSpec
// Synchronous handler
let spec = new;
// Async handler
let spec = new_async;
// With validation and circuit breaker
let spec = new
.with_required_fields
.with_circuit_breaker;
Error Handling
All public APIs return Result<T, AgentRuntimeError>. Match only the variants you care about:
use *;
All production code paths are panic-free. Clippy denies unwrap_used, expect_used,
panic, and todo in src/.
Running Tests
# Default feature set
# All features including persistence and providers
# A specific module
# With structured log output
RUST_LOG=agent_runtime=debug
Run the full CI suite locally:
Contributing
- Fork the repository and create a descriptive feature branch.
- Add tests for every new public function, struct, and trait. The project targets a minimum 1:1 test-to-production line ratio.
- All production paths must be panic-free. Use
Resultfor every fallible operation. Clippy deniesunwrap_used,expect_used,panic, andtodoinsrc/. - Run
cargo test --all-featuresandcargo clippy --all-features -- -D warningswith zero failures before opening a pull request. - New public items require
///doc comments. The crate enforces#![deny(missing_docs)]. - Describe the motivation and design decisions in the PR body.
Checklist before opening a PR:
-
cargo test --all-featurespasses -
cargo clippy --all-features -- -D warningspasses -
cargo fmt --all -- --checkpasses -
cargo doc --no-deps --all-featurespasses withRUSTDOCFLAGS="-D warnings" - New public items have
///doc comments
License
Licensed under the MIT License. See LICENSE for details.