AGENTSDK
🥧 The Power Behind Pie
agentsdk is the modular engine that powers Pie — a fast, minimal AI coding agent in Rust.
Pie provides the terminal-based user experience and persistent sessions, while AgentSDK provides the robust, ECS-based orchestration layer, type-safe tools, and plugin infrastructure. Together, they offer a highly extensible foundation for building autonomous AI assistants.
A lean Rust SDK for building AI agents with OpenAI-compatible APIs. Type-safe tools, streaming, ECS-based plugin system, and agentic loops out of the box.
Features
- MCP Support — Bridge any Model Context Protocol server using the
agentsdk-plugin-mcpplugin. - ECS-based plugin system — lifecycle hooks with shared state via
hecs::World; compose plugins, detect changes, inspect state post-run - Type-safe tools — derive tools from plain Rust functions with the
#[tool]macro - OpenAI-compatible — works with OpenAI, OpenRouter, and any compatible endpoint
- History plugins —
FileHistoryPluginfor persistence,MemoryHistoryPluginfor in-memory history - JSON Schema generation — automatic input/output schemas via
schemars - Retry policy — configurable retry with backoff for API errors
- Parallel tool calls — execute multiple tool calls concurrently
Installation
Quick Start
use ;
use async_trait;
// Define a tool from a plain function
/// Get the current weather for a location
// A plugin that streams text deltas to stdout
;
async
Defining Tools
Use the #[tool] macro to turn any function into a callable tool:
use ;
/// Calculate the sum of two numbers
The macro automatically:
- Uses the function name as the tool name
- Extracts the description from doc comments
- Generates a JSON Schema from the parameters
- Supports both sync and async functions
Struct parameters
use ;
use JsonSchema;
use Deserialize;
/// Search for documents
Tool context
Access runtime context (model name, extensions) via ToolContext:
use ;
Plugin System
Plugins extend the agent with custom behavior through lifecycle hooks. Every method has a default no-op so you only implement what you need.
Lifecycle
| Hook | Timing | Type |
|---|---|---|
init |
Once when the agent starts | Setup |
shutdown |
Once when the agent finishes | Cleanup |
on_text_delta |
Each streaming chunk | Observability |
on_model_response_completed |
Full turn received | Observability |
prepare_system_prompt |
Before each model call | Control flow (merged) |
on_tool_pre_execute |
Before a tool runs | Control flow (first decisive wins) |
on_tool_post_execute |
After a tool succeeds | Control flow (first decisive wins) |
on_tool_error |
When a tool fails | Control flow (first decisive wins) |
on_completion |
Final text produced | Control flow (first decisive wins) |
on_api_error |
API call fails | Retry decision |
PluginContext
Each hook receives a [PluginContext] wrapping a [hecs::World] with a dedicated entity for the agent session:
async
Built-in plugins
MemoryHistoryPlugin— in-memory conversation history (no persistence)FileHistoryPlugin— JSON-file-backed persistence; loads oninit, saves onshutdown
AgentRunOutput
agent.run().await returns an AgentRunOutput containing the full hecs::World. Use it to inspect plugin state after execution:
let output = agent.run.await?;
let history: Messages = output.world.
.map
.unwrap_or_default;
Configuration
Agent options
builder
.model
.temperature
.max_tokens
.max_iterations // limit agent loop iterations (default: 25)
.with_tool
.build?
Plugins
Plugins are registered on the builder and receive lifecycle events in registration order:
builder
.client
.options
.plugin
.plugin
.build?
State is shared between plugins through a [hecs::World] — each plugin reads/writes typed components on the agent entity.
OpenAI client
let config = ModelConfig ;
let client = new;
// OR from environment variables
let config = from_env?;
Contributing
See CONTRIBUTING.md.
License
MIT — see LICENSE.