# 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

```rust
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

```rust
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

```rust
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:
- [OpenCode API Documentation](../../docs/api/opencode.md)
- Or run: `cargo doc --open -p opencode_client`

## 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)

## Related Packages

- **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

```bash
# Build
cargo build -p opencode_client

# Test
cargo test -p opencode_client

# Documentation
cargo doc --open -p opencode_client
```

## Roadmap

See detailed implementation plans:
- [SSE Implementation](../../docs/building/00/sse_implementation.md) - Real-time event streaming
- [OpenCode API Reference](../../docs/building/general/opencode_api.md) - Complete API documentation

### 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](../../docs/building/general/opencode_api.md) for details on differences between the official API spec and actual implementation (e.g., optional fields, missing fields, additional part types).
