Dirigent Protocol
Version: 0.2.0
A Rust protocol library for agent-client interactions, aligned with Agent-Client Protocol (ACP) and Model Context Protocol (MCP) standards.
Overview
The Dirigent Protocol provides a structured, streaming-first event model for real-time agent interactions. It's designed to support multi-agent orchestration, tool execution, and rich content streaming while maintaining compatibility with standard protocols.
Features
- ACP-Style Streaming: Real-time content updates via
SessionUpdateevents - MCP-Compatible Content: Structured
ContentBlockrepresentation - Tool Lifecycle Management: Complete tool call tracking from initiation to completion
- Provider Agnostic: Adapter system for integrating different AI providers
- Type-Safe: Strongly-typed Rust API with comprehensive serde support
- Extensible: Provider metadata and extensibility hooks
Quick Start
Add to your Cargo.toml:
[dependencies]
dirigent_protocol = "0.2"
Basic Usage
use dirigent_protocol::{Event, SessionUpdate, ContentBlock};
fn handle_event(event: Event) {
match event {
Event::SessionUpdate { session_id, update } => {
match update {
SessionUpdate::AgentMessageChunk { message_id, content, .. } => {
if let ContentBlock::Text { text } = content {
println!("Agent says: {}", text);
}
}
SessionUpdate::ToolCall { tool_call, .. } => {
println!("Tool called: {}", tool_call.tool_name);
}
_ => {}
}
}
Event::SessionCreated { session } => {
println!("New session: {}", session.id);
}
_ => {}
}
}
Core Concepts
SessionUpdate Event Model
The protocol uses SessionUpdate for all streaming content:
pub enum SessionUpdate {
UserMessageChunk { message_id: String, content: ContentBlock, _meta: Option<Meta> },
AgentMessageChunk { message_id: String, content: ContentBlock, _meta: Option<Meta> },
AgentThoughtChunk { message_id: String, content: ContentBlock, _meta: Option<Meta> },
ToolCall { message_id: String, tool_call: ToolCall, _meta: Option<Meta> },
ToolCallUpdate { message_id: String, tool_call_id: String, tool_call: ToolCall, _meta: Option<Meta> },
}
ContentBlock Types
Structured content representation:
pub enum ContentBlock {
Text { text: String },
ResourceLink {
uri: String,
name: Option<String>,
mime_type: Option<String>,
},
}
Tool Call Lifecycle
Complete tool execution tracking:
pub struct ToolCall {
pub id: ToolCallId,
pub tool_name: String,
pub status: ToolCallStatus, // Pending → Running → Completed/Error
pub content: Vec<ContentBlock>,
pub raw_input: Option<Value>,
pub raw_output: Option<Value>,
pub title: Option<String>,
pub error: Option<String>,
pub metadata: Option<Value>,
}
Documentation
- Streaming Model - Detailed guide to the SessionUpdate event system
- Migration Guide - Upgrading from 0.1.x to 0.2.0
- CHANGELOG.md - Version history and breaking changes
- Examples - Working code examples
Examples
Streaming Text
use dirigent_protocol::{Event, SessionUpdate, ContentBlock};
// Agent streaming response
Event::SessionUpdate {
session_id: "session_123".to_string(),
update: SessionUpdate::AgentMessageChunk {
message_id: "msg_1".to_string(),
content: ContentBlock::Text {
text: "Hello, world!".to_string(),
},
_meta: None,
},
}
Tool Execution
use dirigent_protocol::{Event, SessionUpdate, ToolCall, ToolCallStatus};
// Tool call initiated
Event::SessionUpdate {
session_id: "session_123".to_string(),
update: SessionUpdate::ToolCall {
message_id: "msg_1".to_string(),
tool_call: ToolCall {
id: "call_1".to_string(),
tool_name: "bash".to_string(),
status: ToolCallStatus::Pending,
content: vec![],
raw_input: Some(json!({"command": "ls"})),
raw_output: None,
title: Some("List files".to_string()),
error: None,
metadata: None,
},
_meta: None,
},
}
// Tool call completed
Event::SessionUpdate {
session_id: "session_123".to_string(),
update: SessionUpdate::ToolCallUpdate {
message_id: "msg_1".to_string(),
tool_call_id: "call_1".to_string(),
tool_call: ToolCall {
id: "call_1".to_string(),
tool_name: "bash".to_string(),
status: ToolCallStatus::Completed,
content: vec![
ContentBlock::Text {
text: "file1.txt\nfile2.txt".to_string(),
},
],
raw_input: Some(json!({"command": "ls"})),
raw_output: Some(json!({"exit_code": 0})),
title: Some("List files".to_string()),
error: None,
metadata: None,
},
_meta: None,
},
}
Agent Thinking
use dirigent_protocol::{Event, SessionUpdate, ContentBlock};
// Agent internal reasoning
Event::SessionUpdate {
session_id: "session_123".to_string(),
update: SessionUpdate::AgentThoughtChunk {
message_id: "msg_1".to_string(),
content: ContentBlock::Text {
text: "Analyzing the user's request...".to_string(),
},
_meta: None,
},
}
Adapters
The protocol includes adapter modules for translating provider-specific events:
- OpenCode Adapter: Converts OpenCode.ai events to Dirigent Protocol
- REST Adapter: Translates REST API responses
Using an Adapter
use dirigent_protocol::adapters::opencode::OpenCodeAdapter;
let adapter = OpenCodeAdapter::new();
let dirigent_events = adapter.translate_event(opencode_event);
Version History
0.2.0 (Current)
Breaking Changes:
- Removed
Event::MessagePartAdded(replaced withSessionUpdate)
New Features:
- ACP-style
SessionUpdateevent system - MCP-compatible
ContentBlocktypes - Structured
ToolCallwith lifecycle tracking - Provider metadata via
_metafield
See CHANGELOG.md for details.
0.1.0
Initial release with basic event types and adapters.
Migration from 0.1.x
If you're upgrading from version 0.1.x, see the Migration Guide for detailed instructions and examples.
Quick Summary:
- Replace
Event::MessagePartAddedwithEvent::SessionUpdate - Use
SessionUpdatevariants instead ofMessagePart - Handle tool lifecycle with
ToolCallandToolCallUpdate - Access
ContentBlock::Text { text }instead ofMessagePart::Text { content }
Architecture
dirigent_protocol/
├── src/
│ ├── types/ # Core types
│ │ ├── content.rs # ContentBlock definitions
│ │ ├── updates.rs # SessionUpdate variants
│ │ ├── tool.rs # Tool call types
│ │ └── meta.rs # Provider metadata
│ ├── session.rs # Session types
│ ├── conversation.rs # Message types
│ ├── events.rs # Event enum
│ └── adapters/ # Provider adapters
│ ├── opencode.rs # OpenCode adapter
│ └── rest.rs # REST adapter
├── docs/ # Documentation
├── examples/ # Code examples
└── tests/ # Integration tests
Event Types
The protocol defines several event categories:
Session Events
SessionCreated- New session startedSessionUpdated- Session metadata changedSessionDeleted- Session removedSessionsListed- Available sessions returned
Streaming Events
SessionUpdate- Real-time content/tool updates (see SessionUpdate variants above)
Message Events
MessageStarted- Message creation initiatedMessageCompleted- Message finalizedMessageDeleted- Message removed
System Events
ConnectorStateChanged- Connector status changedError- Error occurred
Best Practices
For Consumers
- Use SessionUpdate for streaming: The new event model provides granular updates
- Track tools by ID: Maintain a HashMap of tool calls keyed by
tool_call_id - Replace tool state on update:
ToolCallUpdatesends complete state, not deltas - Distinguish thoughts from messages: Render
AgentThoughtChunkdifferently (e.g., collapsible sections) - Handle optional fields: Provider metadata (
_meta) may not always be present
For Adapters
- Preserve provider info: Store original IDs in
_meta.providerfor debugging - Send complete tool state: Include all tool call fields in updates
- Use appropriate chunk types: Choose User/Agent/Thought for correct semantics
- Keep metadata minimal: Avoid large payloads in
_meta(use excerpts)
Testing
Run the test suite:
cargo test
Run with output:
cargo test -- --nocapture
Contributing
Contributions welcome! Please ensure:
- All tests pass
- New features include tests
- Documentation is updated
- Code follows Rust conventions
License
[License information here]
Related Projects
- dirigent_core - Multi-agent orchestration runtime
- opencode_client - OpenCode.ai HTTP client library
- dirigent_archive - Session persistence
Support
For questions or issues:
- Check the documentation
- Review examples
- Open an issue on the repository
Standards Alignment
This protocol is designed to align with:
- Agent-Client Protocol (ACP) - Streaming model and event types
- Model Context Protocol (MCP) - Content block structure
Differences from standards are documented for compatibility and future convergence.