An open API service indexing awesome lists of open source software.

https://github.com/danielkov/agentkit

Rust toolkit for building LLM agent applications, e.g.: coding agents, assistant CLIs and multi-agent tools.
https://github.com/danielkov/agentkit

ai ai-agents ai-agents-framework llm-tools

Last synced: about 1 month ago
JSON representation

Rust toolkit for building LLM agent applications, e.g.: coding agents, assistant CLIs and multi-agent tools.

Awesome Lists containing this project

README

          

# agentkit

`agentkit` is a Rust toolkit for building LLM agent applications such as coding agents, assistant CLIs, and multi-agent tools.

The project is intentionally split into small crates behind feature flags so hosts can pull in only the pieces they need.

## Current status

`agentkit` is past the design-only stage. The repo currently includes working implementations for:

- normalized transcript, content-part, and delta types with fluent builders
- a runtime-agnostic loop driver with blocking approval interrupts plus cooperative yields for end-of-turn input and between-tool-round interjection
- federated tool sources behind a single `ToolSource` trait — frozen `ToolRegistry`s, dynamic catalogs, and MCP-backed sources compose by registration order, with collision policies and live `ToolCatalogChanged` events
- trait-based tools, permissions, and approval handoff
- a `TranscriptObserver` channel for loss-free transcript reconstruction (persistence, replication, audit) alongside the operational `LoopObserver` event stream
- built-in filesystem, shell, and skills tools
- context loading for `AGENTS.md` and skills directories
- MCP integration on top of [`rmcp`](https://crates.io/crates/rmcp): stdio + Streamable HTTP transports, discovery, tool/resource/prompt adapters, auth replay, lifecycle management (connect / disconnect / refresh), pluggable sampling/elicitation/roots responders, and a broadcast subscription for server-pushed progress, logging, resource updates, list-changed, and cancellation events
- reporting observers
- compaction triggers, strategy pipelines, and backend-driven semantic compaction
- async task management with foreground/background scheduling, routing policies, detach-after-timeout, and notification of background-tool completion through the loop event stream
- optional turn cancellation with resumable sessions
- prompt caching with automatic and explicit strategies, retention hints, and cache keys
- a generic completions adapter base for building provider crates
- provider adapters for OpenRouter, OpenAI, Anthropic, Cerebras, Ollama, vLLM, Groq, and Mistral

The repo also ships multiple examples that exercise these pieces end to end.

## Crates

- `agentkit-core`
- transcript, parts, deltas, IDs, usage, and cancellation primitives
- `agentkit-capabilities`
- lower-level invocable/resource/prompt abstraction
- `agentkit-tools-core`
- tools, registry, executor, permissions, approvals, auth requests
- `agentkit-loop`
- model session abstraction, driver, interrupts, tool roundtrips
- `agentkit-context`
- `AGENTS.md` and skills loading
- `agentkit-mcp`
- MCP integration built on `rmcp`: stdio + Streamable HTTP transports, discovery, lifecycle, auth + replay, tool/resource/prompt adapters, sampling/elicitation/roots responders, and a server-event broadcast
- `agentkit-reporting`
- loop observers and reporting adapters
- `agentkit-compaction`
- compaction triggers, strategies, pipelines, backend hooks
- `agentkit-task-manager`
- task scheduling for tool execution: foreground, background, and detach-after-timeout routing
- `agentkit-tool-fs`
- filesystem tools
- `agentkit-tool-shell`
- shell execution tool
- `agentkit-tool-skills`
- progressive skill discovery and activation
- `agentkit-http`
- HTTP transport abstraction (`HttpClient`, `Http`, `HttpRequestBuilder`) with a default reqwest-backed implementation and an optional `reqwest-middleware` adapter
- `agentkit-adapter-completions`
- generic chat completions adapter base for building provider crates
- `agentkit-provider-openrouter`
- OpenRouter adapter
- `agentkit-provider-openai`
- OpenAI adapter
- `agentkit-provider-anthropic`
- Anthropic Messages API adapter with streaming, prompt caching, extended thinking, and server-side tools (web search, web fetch, code execution)
- `agentkit-provider-cerebras`
- Cerebras Inference API adapter with streaming, reasoning, strict JSON schema, compression (msgpack/gzip), predicted outputs, service tiers, and Files + Batch API
- `agentkit-provider-ollama`
- Ollama adapter
- `agentkit-provider-vllm`
- vLLM adapter
- `agentkit-provider-groq`
- Groq adapter
- `agentkit-provider-mistral`
- Mistral adapter
- `agentkit`
- umbrella crate with feature-gated re-exports

## Built-in tools today

Filesystem:

- `fs_read_file`
- supports optional `from` / `to` line ranges
- `fs_write_file`
- `fs_replace_in_file`
- `fs_move`
- `fs_delete`
- `fs_list_directory`
- `fs_create_directory`

Shell:

- `shell_exec`

The filesystem crate also supports session-scoped read-before-write enforcement through `FileSystemToolResources` and `FileSystemToolPolicy`.

## Quick start

1. Set your OpenRouter API key and model — either through environment variables or directly in code via `OpenRouterConfig::new(api_key, model)`.
2. Run one of the examples.

Example commands:

```bash
cargo run -p openrouter-chat -- "hello"
```

```bash
cargo run -p openrouter-coding-agent -- \
"Use fs_read_file on ./Cargo.toml and return only the workspace member count as an integer."
```

```bash
cargo run -p openrouter-agent-cli -- --mcp-mock \
"Return only the secret from the MCP tool."
```

## Example progression

- `openrouter-chat`
- minimal chat loop
- now supports `Ctrl-C` turn cancellation
- `openrouter-coding-agent`
- one-shot coding-oriented prompt runner with filesystem tools
- `openrouter-context-agent`
- context loading from `AGENTS.md` and skills
- `openrouter-mcp-tool`
- MCP tool discovery and invocation
- `openrouter-subagent-tool`
- custom tool that runs a nested agent
- `openrouter-compaction-agent`
- structural, semantic, and hybrid compaction
- semantic compaction uses a nested agent as the backend
- `openrouter-parallel-agent`
- async task manager with foreground fs tools and detach-after-timeout shell tools
- `TaskManagerHandle` event stream printed to stderr
- `openrouter-agent-cli`
- combined example using context, tools, shell, MCP, compaction, and reporting
- `anthropic-chat`
- streaming REPL against Anthropic's Messages API, with server tools
(`--web-search`, `--web-fetch`, `--code-exec`), extended thinking
(`--thinking`), and a streaming / buffered toggle (`--streaming` /
`--no-streaming`)
- `cerebras-chat`
- interactive REPL against Cerebras `/v1/chat/completions`; CLI flags
cover every `CerebrasConfig` knob (sampling, reasoning, response
format, compression, service tier, predicted outputs, local tools)
and slash commands (`/show`, `/usage`, `/ratelimit`, `/headers`,
`/models`, `/reset`) surface runtime state
- `cerebras-batch`
- one-shot CLI over the Cerebras Files + Batch APIs: `files upload|list|get|content|delete`,
`batches create|submit|list|get|cancel|wait`, and `run` to submit → wait → dump outputs

## Examples

### Minimal chat

Build an agent with a provider adapter and an opening user turn, then drive the loop:

```rust
use agentkit_core::{Item, ItemKind};
use agentkit_loop::{
Agent, LoopInterrupt, LoopStep, PromptCacheRequest, PromptCacheRetention, SessionConfig,
};
use agentkit_provider_openrouter::{OpenRouterAdapter, OpenRouterConfig};

let adapter = OpenRouterAdapter::new(
OpenRouterConfig::new("sk-or-v1-...", "openrouter/auto")
.with_temperature(0.0),
)?;

let agent = Agent::builder()
.model(adapter)
// Optional — preload a prior transcript (system prompt or resumed
// session) and the next user turn. Both default to empty.
.input(vec![Item::text(ItemKind::User, "Hello!")])
.build()?;

let mut driver = agent
.start(SessionConfig::new("chat").with_cache(
PromptCacheRequest::automatic().with_retention(PromptCacheRetention::Short),
))
.await?;

// First next() dispatches the model directly because we preloaded input.
match driver.next().await? {
LoopStep::Finished(result) => { /* render result.items */ }
LoopStep::Interrupt(LoopInterrupt::ApprovalRequest(pending)) => {
/* blocking: approve or deny via the PendingApproval handle */
}
LoopStep::Interrupt(LoopInterrupt::AwaitingInput(req)) => {
/* cooperative: req.submit(&mut driver, more_items)? then call next() */
}
LoopStep::Interrupt(LoopInterrupt::AfterToolResult(_)) => { /* call next() to resume */ }
}
```

`AgentBuilder::transcript` preloads the prior transcript as passive starting state — typically `[system_item]` for a fresh session, or a transcript loaded from disk when resuming. `AgentBuilder::input` preloads the next user turn into the driver's pending-input queue: when non-empty, the first `next()` dispatches the model directly; when left empty (the default for turn-based loops), the first `next()` yields `AwaitingInput` and every user turn flows through the `InputRequest` / `ToolRoundInfo` handles surfaced on the cooperative interrupts. There is no out-of-turn `submit_input` entry point.

### Tools and permissions

Register filesystem tools with a path-scoped permission policy. Tool sources federate — call `add_tool_source` once per source (registry, MCP catalog reader, skill watcher, …) and the agent walks them in registration order:

```rust
use agentkit_core::MetadataMap;
use agentkit_loop::Agent;
use agentkit_tools_core::{
CompositePermissionChecker, PathPolicy, PermissionCode, PermissionDecision, PermissionDenial,
};

let permissions = CompositePermissionChecker::new(PermissionDecision::Deny(PermissionDenial {
code: PermissionCode::UnknownRequest,
message: "not allowed by policy".into(),
metadata: MetadataMap::new(),
}))
.with_policy(
PathPolicy::new()
.allow_root(std::env::current_dir()?)
.require_approval_outside_allowed(false),
);

let agent = Agent::builder()
.model(adapter)
.add_tool_source(agentkit_tool_fs::registry())
.permissions(permissions)
.build()?;
```

### Reporting

Compose multiple observers to log output, track usage, and record transcripts:

```rust
use agentkit_reporting::{CompositeReporter, JsonlReporter, StdoutReporter, UsageReporter};

let reporter = CompositeReporter::new()
.with_observer(StdoutReporter::new(std::io::stderr()).with_usage(false))
.with_observer(JsonlReporter::new(Vec::new()))
.with_observer(UsageReporter::new());

let agent = Agent::builder()
.model(adapter)
.observer(reporter)
.build()?;
```

### Compaction

Configure structural compaction that drops reasoning and failed tool results, then keeps the most recent items:

```rust
use agentkit_compaction::{
CompactionConfig, CompactionPipeline, DropFailedToolResultsStrategy,
DropReasoningStrategy, ItemCountTrigger, KeepRecentStrategy,
};
use agentkit_core::ItemKind;

let compaction = CompactionConfig::new(
ItemCountTrigger::new(10),
CompactionPipeline::new()
.with_strategy(DropReasoningStrategy::new())
.with_strategy(DropFailedToolResultsStrategy::new())
.with_strategy(
KeepRecentStrategy::new(8)
.preserve_kind(ItemKind::System)
.preserve_kind(ItemKind::Context),
),
);

let agent = Agent::builder()
.model(adapter)
.compaction(compaction)
.build()?;
```

### Async task management

Route shell commands to background execution with automatic detach-after-timeout:

```rust
use agentkit_task_manager::{AsyncTaskManager, RoutingDecision};
use std::time::Duration;

let task_manager = AsyncTaskManager::new().routing(|req: &agentkit_tools_core::ToolRequest| {
if req.tool_name.0 == "shell_exec" {
RoutingDecision::ForegroundThenDetachAfter(Duration::from_secs(5))
} else {
RoutingDecision::Foreground
}
});

let agent = Agent::builder()
.model(adapter)
.add_tool_source(tools)
.task_manager(task_manager)
.build()?;
```

## Feature flags

The umbrella crate re-exports subcrates behind feature flags.

Default flags:

- `core`
- `capabilities`
- `tools`
- `task-manager`
- `loop`
- `reporting`

Optional flags:

- `compaction`
- `context`
- `mcp`
- `adapter-completions`
- `provider-openrouter`
- `provider-openai`
- `provider-anthropic`
- `provider-cerebras`
- `provider-ollama`
- `provider-vllm`
- `provider-groq`
- `provider-mistral`
- `tool-fs`
- `tool-shell`
- `tool-skills`

More detail is in [docs/feature-flags.md](./docs/feature-flags.md).

## Docs

- [docs/getting-started.md](./docs/getting-started.md)
- [docs/architecture.md](./docs/architecture.md)
- [docs/core.md](./docs/core.md)
- [docs/tools.md](./docs/tools.md)
- [docs/loop.md](./docs/loop.md)
- [docs/permissions.md](./docs/permissions.md)
- [docs/capabilities.md](./docs/capabilities.md)
- [docs/context.md](./docs/context.md)
- [docs/mcp.md](./docs/mcp.md)
- [docs/compaction.md](./docs/compaction.md)
- [docs/reporting.md](./docs/reporting.md)
- [docs/feature-flags.md](./docs/feature-flags.md)
- [docs/README.md](./docs/README.md)