Skip to content

Repository files navigation

OpenCode.DotnetClient

BuildPublish NuGetNuGetNuGet Downloads.NETLicense

A simple .NET client library for the OpenCode API, enabling easy integration of OpenCode's AI coding capabilities into C# applications.

📋 Overview

This is a Proof of Concept (POC) .NET client for OpenCode API, built with:

  • Refit for type-safe HTTP client
  • System.Text.Json for JSON serialization
  • xUnit for testing

🚀 Features

  • Session Management: create, get, list, delete sessions
  • Prompt Sending: send prompts to AI models (sync + async)
  • Message Retrieval: fetch messages from sessions
  • Todo Support: get todo lists for sessions
  • TUI Control: programmatically control terminal interface (append, submit, clear prompts, execute commands, show toasts)
  • Event Streaming: real-time SSE event streaming with robust error handling
  • Type-Safe API: Refit-based type-safe HTTP calls
  • Async/Await: full async support with cancellation tokens
  • Dependency Injection: proper HttpClient management with IHttpClientFactory support
  • Error Handling: custom exception types for different error scenarios
  • Configuration: flexible options for timeouts, base URL, and default model settings
  • Comprehensive Tests: unit + integration tests
  • Production-Ready: follows .NET best practices and clean code principles

📦 Installation

NuGet Package

dotnet add package Olbrasoft.OpenCode.DotnetClient

Or via Package Manager Console:

Install-Package Olbrasoft.OpenCode.DotnetClient

Prerequisites

  • .NET 10.0 SDK or later
  • Running OpenCode server (default: http://localhost:4096)

Building from Source

git clone https://github.com/Olbrasoft/OpenCode.DotnetClient.git
cd OpenCode.DotnetClient
dotnet build

Running Tests

dotnet test

Note: Integration tests require a running OpenCode server at http://localhost:4096.

📖 Usage

Basic Example

usingOpenCode.DotnetClient;// Create clientusingvarclient=newOpenCodeClient("http://localhost:4096");// Create a new sessionvarsession=awaitclient.CreateSessionAsync("My AI Session");Console.WriteLine($"Session created: {session.Id}");// Send a promptvarresponse=awaitclient.SendPromptAsync(session.Id,"Write a hello world function in C#",providerId:"anthropic",modelId:"claude-3-5-sonnet-20241022");// Get the responseforeach(varpartinresponse.Parts){if(part.Type=="text"){Console.WriteLine(part.Text);}}// List messages in sessionvarmessages=awaitclient.GetMessagesAsync(session.Id);Console.WriteLine($"Total messages: {messages.Count}");// Cleanupawaitclient.DeleteSessionAsync(session.Id);

Event Streaming

Listen to real-time events from OpenCode server:

usingvareventStream=client.CreateEventStream();awaitforeach(varglobalEventineventStream.StreamGlobalEventsAsync()){Console.WriteLine($"[{globalEvent.Payload.Type}] in {globalEvent.Directory}");// Handle specific event typesswitch(globalEvent.Payload.Type){case"session.status":Console.WriteLine("Session status changed");break;case"message.updated":Console.WriteLine("Message was updated");break;case"todo.updated":Console.WriteLine("Todo list changed");break;case"file.edited":Console.WriteLine("File was edited");break;}}

Todos

Get todos for a session:

vartodos=awaitclient.GetTodosAsync(session.Id);foreach(vartodointodos){Console.WriteLine($"[{todo.Status}] {todo.Content} (Priority: {todo.Priority})");}

Advanced Usage

Configuration Options

// Create client with custom configurationvaroptions=newOpenCodeClientOptions{BaseUrl="http://localhost:4096",Timeout=TimeSpan.FromMinutes(10),DefaultProviderId="anthropic",DefaultModelId="claude-3-5-sonnet-20241022",ThrowOnError=true};usingvarclient=newOpenCodeClient(options);

Dependency Injection (ASP.NET Core)

Recommended approach for production applications to avoid socket exhaustion:

// In Program.cs or Startup.csbuilder.Services.AddHttpClient<OpenCodeClient>((serviceProvider,httpClient)=>{httpClient.BaseAddress=newUri("http://localhost:4096");httpClient.Timeout=TimeSpan.FromMinutes(5);});// Or with IHttpClientFactorybuilder.Services.AddHttpClient("OpenCodeApi", client =>{client.BaseAddress=newUri("http://localhost:4096");client.Timeout=TimeSpan.FromMinutes(5);});builder.Services.AddScoped<OpenCodeClient>(sp =>{varhttpClientFactory=sp.GetRequiredService<IHttpClientFactory>();varhttpClient=httpClientFactory.CreateClient("OpenCodeApi");returnnewOpenCodeClient(httpClient);});// Usage in controllerspublicclassMyController:ControllerBase{privatereadonlyOpenCodeClient_openCodeClient;publicMyController(OpenCodeClientopenCodeClient){_openCodeClient=openCodeClient;}}

Custom HttpClient (Simple Usage)

For console applications or simple scenarios:

varhttpClient=newHttpClient{BaseAddress=newUri("http://localhost:4096"),Timeout=TimeSpan.FromMinutes(5)};usingvarclient=newOpenCodeClient(httpClient);

Error Handling

The client includes custom exception types for better error handling:

try{varsession=awaitclient.CreateSessionAsync("My Session");varresponse=awaitclient.SendPromptAsync(session.Id,"Write a hello world function");}catch(OpenCodeConnectionExceptionex){// Connection failures (server unreachable, timeout)Console.WriteLine($"Connection failed: {ex.Message}");}catch(OpenCodeApiExceptionex){// API errors (4xx, 5xx responses)Console.WriteLine($"API error {ex.StatusCode}: {ex.Message}");Console.WriteLine($"Response: {ex.ResponseContent}");}catch(OpenCodeExceptionex){// Other OpenCode errorsConsole.WriteLine($"OpenCode error: {ex.Message}");}

Cancellation Support

All async methods support cancellation tokens:

usingvarcts=newCancellationTokenSource(TimeSpan.FromSeconds(30));try{varsessions=awaitclient.GetSessionsAsync(cancellationToken:cts.Token);varresponse=awaitclient.SendPromptAsync(sessionId:"ses_abc123",prompt:"Long-running task...",cancellationToken:cts.Token);}catch(OperationCanceledException){Console.WriteLine("Operation was cancelled");}

Working with Sessions

// List all sessionsvarsessions=awaitclient.GetSessionsAsync();// Get specific sessionvarsession=awaitclient.GetSessionAsync("ses_abc123");// Create session with title and parentvarchildSession=awaitclient.CreateSessionAsync(title:"Feature Development",parentId:session.Id);// Delete sessionawaitclient.DeleteSessionAsync(session.Id);

Sending Prompts

// Simple text promptvarresponse=awaitclient.SendPromptAsync(sessionId:"ses_abc123",prompt:"Explain SOLID principles",providerId:"anthropic",modelId:"claude-3-5-sonnet-20241022");// Async prompt (fire and forget)awaitclient.SendPromptAsyncAsync(sessionId:"ses_abc123",prompt:"Generate documentation");

Terminal User Interface (TUI) API

Control the OpenCode terminal interface programmatically:

// Append text to the prompt input (without submitting)awaitclient.AppendPromptAsync(sessionId:"ses_abc123",text:"Write a function to ");// Submit the current prompt (triggers AI processing)awaitclient.SubmitPromptAsync("ses_abc123");// Clear the prompt inputawaitclient.ClearPromptAsync("ses_abc123");// Execute a command in the sessionawaitclient.ExecuteCommandAsync(sessionId:"ses_abc123",command:"/help");// Show a toast notification in the UIawaitclient.ShowToastAsync(sessionId:"ses_abc123",message:"Operation completed successfully",type:"success"// "success", "error", "info", "warning");

TUI API Use Cases:

  • AppendPrompt: Build prompts incrementally from multiple sources
  • SubmitPrompt: Trigger AI processing after composing a prompt
  • ClearPrompt: Reset the input for a new interaction
  • ExecuteCommand: Run slash commands programmatically (/help, /clear, etc.)
  • ShowToast: Provide user feedback for background operations

🏗️ Architecture

OpenCode.DotnetClient/
├── src/
│ └── OpenCode.DotnetClient/
│ ├── Models/ # DTOs for API requests/responses
│ │ ├── Session.cs
│ │ ├── Message.cs
│ │ ├── PromptRequest.cs
│ │ ├── PromptResponse.cs
│ │ ├── Todo.cs
│ │ └── OpenCodeEvent.cs # Event models
│ ├── IOpenCodeApi.cs # Refit API interface
│ ├── OpenCodeClient.cs # Main client wrapper
│ ├── OpenCodeClientOptions.cs # Configuration options
│ ├── OpenCodeException.cs # Custom exception types
│ └── OpenCodeEventStream.cs # SSE event streaming
├── tests/
│ └── OpenCode.DotnetClient.Tests/
│ ├── OpenCodeClientTests.cs # Integration tests
│ └── OpenCodeClientUnitTests.cs # Unit tests
└── examples/
└── OpenCode.DotnetClient.Example/ # Example console app
└── Program.cs # Interactive example

🔧 API Reference

OpenCodeClient

Constructor

  • OpenCodeClient(string baseUrl = "http://localhost:4096")
  • OpenCodeClient(HttpClient httpClient)

Methods

Session Management

  • Task<List<Session>> GetSessionsAsync(string? directory = null)
  • Task<Session> CreateSessionAsync(string? title = null, string? parentId = null, string? directory = null)
  • Task<Session> GetSessionAsync(string sessionId, string? directory = null)
  • Task<bool> DeleteSessionAsync(string sessionId, string? directory = null)

Messaging

  • Task<PromptResponse> SendPromptAsync(string sessionId, string prompt, string providerId = "anthropic", string modelId = "claude-3-5-sonnet-20241022", string? directory = null)
  • Task SendPromptAsyncAsync(string sessionId, string prompt, string providerId = "anthropic", string modelId = "claude-3-5-sonnet-20241022", string? directory = null)
  • Task<List<MessageWithParts>> GetMessagesAsync(string sessionId, int? limit = null, string? directory = null)

Session Control

  • Task<bool> AbortSessionAsync(string sessionId, string? directory = null)

Todos

  • Task<List<Todo>> GetTodosAsync(string sessionId, string? directory = null)

Terminal User Interface (TUI) API

  • Task AppendPromptAsync(string sessionId, string text, string? directory = null)
  • Task SubmitPromptAsync(string sessionId, string? directory = null)
  • Task ClearPromptAsync(string sessionId, string? directory = null)
  • Task ExecuteCommandAsync(string sessionId, string command, string? directory = null)
  • Task ShowToastAsync(string sessionId, string message, string type = "info", string? directory = null)

Event Streaming

  • OpenCodeEventStream CreateEventStream()

🧪 Testing

The project includes comprehensive tests:

  • Unit Tests (4): Basic client functionality, constructors, disposal
  • Integration Tests (6): Real API calls requiring running OpenCode server

Run tests:

# All tests
dotnet test# Only unit tests (no server required)
dotnet test --filter "FullyQualifiedName~UnitTests"# Only integration tests
dotnet test --filter "FullyQualifiedName~OpenCodeClientTests"

🛠️ Development

Project Structure

This is a .NET solution with two projects:

  • OpenCode.DotnetClient: Class library (.NET 10)
  • OpenCode.DotnetClient.Tests: Test project with xUnit

Dependencies

  • Refit - Type-safe REST client
  • xUnit - Testing framework
  • Moq - Mocking framework

Building

dotnet build

Running OpenCode Server

Before running integration tests, start the OpenCode server:

opencode serve --port 4096

Running the Example

An interactive example application is included in the examples directory:

cd examples/OpenCode.DotnetClient.Example
dotnet run

The example demonstrates:

  • Event Streaming: Real-time monitoring of all OpenCode events
  • Interactive Sessions: Chat with AI through the console
  • Session Management: List and manage active sessions
  • Color-coded Output: Beautiful terminal UI with ANSI colors

See examples/README.md for detailed usage instructions.

📝 Requirements

🎯 Supported Events

The client supports real-time streaming of these OpenCode events:

Session Events

  • session.status - Session status changes (running, idle, etc.)
  • session.idle - Session becomes idle

Message Events

  • message.updated - Message content updated
  • message.removed - Message deleted

Todo Events

  • todo.updated - Todo list changes (new todos, status updates)

File Events

  • file.edited - File was edited by AI
  • file.watcher.updated - File system watcher detected changes

Other Events

  • server.instance.disposed - Server instance cleanup
  • lsp.client.diagnostics - LSP diagnostics from language servers
  • command.executed - Command execution notifications
  • installation.updated - Installation updates
  • installation.update-available - New version available

🎯 Future Enhancements

Possible improvements for future versions:

  • Error Handling: Implemented - Custom exception types with detailed error information
  • Configuration: Implemented - Strongly-typed OpenCodeClientOptions
  • Retry Policies: Add automatic retry with exponential backoff using Polly
  • NuGet Package: Publish as reusable package to nuget.org
  • Additional Endpoints: Support for more OpenCode API features (file operations, providers, models list, etc.)
  • CLI Tool: Command-line interface for quick operations
  • Logging: Integrate with ILogger for production-grade logging
  • Metrics: Add telemetry and metrics collection
  • Connection Pooling: Advanced HttpClient configuration for high-throughput scenarios

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📧 Contact

For questions or issues, please open an issue on GitHub.

🙏 Acknowledgments

  • OpenCode - The AI coding assistant
  • Refit - For the excellent HTTP client library

Note: This is a Proof of Concept (POC) implementation. For production use, additional error handling, logging, and configuration options should be added.

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages