# 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 `SessionUpdate` events - **MCP-Compatible Content**: Structured `ContentBlock` representation - **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`: ```toml [dependencies] dirigent_protocol = "0.2" ``` ### Basic Usage ```rust 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: ```rust pub enum SessionUpdate { UserMessageChunk { message_id: String, content: ContentBlock, _meta: Option }, AgentMessageChunk { message_id: String, content: ContentBlock, _meta: Option }, AgentThoughtChunk { message_id: String, content: ContentBlock, _meta: Option }, ToolCall { message_id: String, tool_call: ToolCall, _meta: Option }, ToolCallUpdate { message_id: String, tool_call_id: String, tool_call: ToolCall, _meta: Option }, } ``` ### ContentBlock Types Structured content representation: ```rust pub enum ContentBlock { Text { text: String }, ResourceLink { uri: String, name: Option, mime_type: Option, }, } ``` ### Tool Call Lifecycle Complete tool execution tracking: ```rust pub struct ToolCall { pub id: ToolCallId, pub tool_name: String, pub status: ToolCallStatus, // Pending → Running → Completed/Error pub content: Vec, pub raw_input: Option, pub raw_output: Option, pub title: Option, pub error: Option, pub metadata: Option, } ``` ## Documentation - **[Streaming Model](docs/streaming_model.md)** - Detailed guide to the SessionUpdate event system - **[Migration Guide](docs/migration_from_0.1.md)** - Upgrading from 0.1.x to 0.2.0 - **[CHANGELOG.md](CHANGELOG.md)** - Version history and breaking changes - **[Examples](examples/)** - Working code examples ## Examples ### Streaming Text ```rust 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 ```rust 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 ```rust 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 ```rust 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 with `SessionUpdate`) **New Features:** - ACP-style `SessionUpdate` event system - MCP-compatible `ContentBlock` types - Structured `ToolCall` with lifecycle tracking - Provider metadata via `_meta` field See [CHANGELOG.md](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](docs/migration_from_0.1.md) for detailed instructions and examples. **Quick Summary:** - Replace `Event::MessagePartAdded` with `Event::SessionUpdate` - Use `SessionUpdate` variants instead of `MessagePart` - Handle tool lifecycle with `ToolCall` and `ToolCallUpdate` - Access `ContentBlock::Text { text }` instead of `MessagePart::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 started - `SessionUpdated` - Session metadata changed - `SessionDeleted` - Session removed - `SessionsListed` - Available sessions returned ### Streaming Events - `SessionUpdate` - Real-time content/tool updates (see SessionUpdate variants above) ### Message Events - `MessageStarted` - Message creation initiated - `MessageCompleted` - Message finalized - `MessageDeleted` - Message removed ### System Events - `ConnectorStateChanged` - Connector status changed - `Error` - Error occurred ## Best Practices ### For Consumers 1. **Use SessionUpdate for streaming**: The new event model provides granular updates 2. **Track tools by ID**: Maintain a HashMap of tool calls keyed by `tool_call_id` 3. **Replace tool state on update**: `ToolCallUpdate` sends complete state, not deltas 4. **Distinguish thoughts from messages**: Render `AgentThoughtChunk` differently (e.g., collapsible sections) 5. **Handle optional fields**: Provider metadata (`_meta`) may not always be present ### For Adapters 1. **Preserve provider info**: Store original IDs in `_meta.provider` for debugging 2. **Send complete tool state**: Include all tool call fields in updates 3. **Use appropriate chunk types**: Choose User/Agent/Thought for correct semantics 4. **Keep metadata minimal**: Avoid large payloads in `_meta` (use excerpts) ## Testing Run the test suite: ```bash cargo test ``` Run with output: ```bash 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](docs/) - Review [examples](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.