Files
dirigent/crates/opencode_client/README.md
T
2026-05-08 01:59:04 +02:00

6.1 KiB

opencode_client

A Rust client library for interacting with the OpenCode.ai API.

Purpose

This package provides a type-safe, ergonomic Rust interface to the OpenCode.ai API, enabling any Rust application to interact with OpenCode sessions and messages. It's designed to be reusable across different UI frameworks and platforms (web, mobile, desktop, CLI).

⚠️ Important: API Ownership

ALL OpenCode.ai API functionality lives in this package. This includes:

  • REST API endpoints (sessions, messages, files, etc.)
  • 🚧 Server-Sent Events (SSE) for real-time streaming (planned)
  • 🔮 WebSocket connections (if needed in future)
  • 🔮 Authentication flows
  • 🔮 Rate limiting and retry logic

UI packages (web, mobile, desktop) should remain thin presentation layers that consume this client library. Never implement API calls directly in UI code.

Features

  • Type-safe API: Full Rust type definitions for all OpenCode API structures
  • Async/await: Built on reqwest for non-blocking HTTP operations
  • Optional logging: Flexible logging callbacks for integration with any logging system
  • WASM compatible: Works in browser environments via WebAssembly
  • Zero UI dependencies: Pure business logic, usable anywhere

Usage

Basic Example

use opencode_client::OpenCodeClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = OpenCodeClient::new("http://localhost:12225");

    // List all sessions
    let sessions = client.list_sessions().await?;
    println!("Found {} sessions", sessions.len());

    // Get messages from a session
    if let Some(session) = sessions.first() {
        let messages = client.list_messages(&session.id).await?;
        println!("Session has {} messages", messages.len());
    }

    Ok(())
}

With Logging Callbacks

use opencode_client::OpenCodeClient;
use std::sync::Arc;

let client = OpenCodeClient::new("http://localhost:12225")
    .with_logging(
        Arc::new(|cat, msg| println!("[INFO] {}: {}", cat, msg)),
        Arc::new(|cat, msg| println!("[SUCCESS] {}: {}", cat, msg)),
        Arc::new(|cat, msg| eprintln!("[ERROR] {}: {}", cat, msg)),
    );

// Now all API calls will log through your callbacks
let sessions = client.list_sessions().await?;

Sending Messages

let message_with_parts = client
    .send_message("session_id", "Hello, world!".to_string())
    .await?;

// Access the message info and parts
println!("Message ID: {}", get_message_id(&message_with_parts.info));
for part in &message_with_parts.parts {
    match part {
        Part::Text(text) => println!("Text: {}", text.text),
        Part::Reasoning(reasoning) => println!("Reasoning: {}", reasoning.text),
        Part::Tool(tool) => println!("Tool: {} ({})", tool.tool, tool.state),
        _ => {}
    }
}

Architecture

The client is organized into three main modules:

  • types.rs: All OpenCode API type definitions (Session, Message, Part, etc.)
  • client.rs: HTTP client implementation with CRUD operations
  • lib.rs: Public API exports

The client uses tagged enums for discriminated unions (e.g., Message::User vs Message::Assistant) and serde for JSON serialization/deserialization.

API Reference

For detailed API documentation, see:

Key Types

  • OpenCodeClient: Main client struct
  • Session: Session metadata (id, title, project, timestamps)
  • Message: Tagged enum for User or Assistant messages
    • UserMessage: User-sent messages with optional summary
    • AssistantMessage: AI responses with tokens, cost, system prompt, and metadata
  • MessageWithParts: Complete message with content parts (info + parts array)
  • Part: Message content enum:
    • Text(TextPart): Regular text content
    • Reasoning(ReasoningPart): AI reasoning/thinking process
    • Tool(ToolPart): Tool execution with state tracking
    • StepStart(GenericPart): Step boundary marker
    • StepFinish(GenericPart): Step completion marker
    • Unknown: Future-proof fallback
  • ToolPart: Tool execution details with:
    • tool: Tool name (string)
    • call_id: Unique call identifier
    • state: ToolState enum (Pending, Running, Completed, Error)
  • ToolState: Execution state with status-specific data:
    • Pending: Waiting to start
    • Running { input, title?, metadata?, time }: Currently executing
    • Completed { input, output, title, metadata, time, attachments? }: Successful completion
    • Error { input, error, metadata?, time }: Failed execution
  • ClientError: Error types (Http, Request, Serialization)

Dependencies

  • reqwest: Async HTTP client (with JSON support)
  • serde/serde_json: JSON serialization
  • chrono: Timestamp handling
  • wasm-bindgen/web-sys: WASM compatibility (target-specific)
  • web: Uses this client for browser-based UI
  • mobile (future): Will use this client for mobile apps
  • desktop (future): Will use this client for desktop apps

Development

# Build
cargo build -p opencode_client

# Test
cargo test -p opencode_client

# Documentation
cargo doc --open -p opencode_client

Roadmap

See detailed implementation plans:

Upcoming Features

  • SSE Event Streaming 🚧

    • Real-time message part updates
    • Live session state changes
    • Connection resilience and reconnection
    • See: docs/building/sse_implementation.md
  • File Operations 📋

    • Read files from workspace
    • Search files and symbols
    • Track file status
  • Advanced Session Management 📋

    • Create/delete sessions
    • Fork sessions
    • Session diffs and summaries

Known Issues & Differences

See OpenCode API Documentation for details on differences between the official API spec and actual implementation (e.g., optional fields, missing fields, additional part types).