Skip to content

feat(provider): add OpenCode Zen provider with multi-backend routing and cost tracking#2594

Merged
tusharmath merged 13 commits intomainfrom
opencode-zen-provider
Mar 19, 2026
Merged

feat(provider): add OpenCode Zen provider with multi-backend routing and cost tracking#2594
tusharmath merged 13 commits intomainfrom
opencode-zen-provider

Conversation

@amitksingh1490
Copy link
Copy Markdown
Contributor

@amitksingh1490 amitksingh1490 commented Mar 18, 2026

Summary

Add OpenCode Zen provider with intelligent multi-backend routing and cost tracking via ping events.

Context

OpenCode Zen (opencode.ai) provides a unified API endpoint that aggregates multiple LLM providers (Anthropic, OpenAI, Google, and others). While it appears to be OpenAI-compatible, it requires specialized handling that cannot be achieved with a standard OpenAI-compatible provider for several critical reasons:

Why a New Provider Was Needed

1. Multi-Backend Routing by Model Prefix
OpenCode Zen routes requests to different backends based on the model name:

  • claude-* models → Anthropic Messages API (/v1/messages)
  • gpt-5* models → OpenAI Responses API (/v1/responses)
  • gemini-* models → Google API (/v1)
  • Other models (GLM, MiniMax, Kimi) → OpenAI Chat Completions (/v1/chat/completions)

Each backend has different endpoint URLs, request/response formats, and streaming behaviors. A simple OpenAI-compatible provider cannot handle this routing complexity.

2. Non-Standard SSE Content Types
The Anthropic backend returns Server-Sent Events with non-standard content types that fail reqwest-eventsource's validation. The provider must detect this and fall back to raw byte streaming with manual SSE parsing.

3. Cost-Bearing Ping Events
OpenCode Zen injects custom ping events into the stream that carry cost information:

{"type":"ping","cost":"0.00675010"}

These must be captured and forwarded as usage data. Standard OpenAI-compatible providers would fail on these unknown event types.

4. Response Type Variations
Different backends return different response structures:

  • Anthropic: SSE with content_block_delta events
  • OpenAI Responses: Structured response events with tool call handling
  • Google: Different streaming format
  • OpenAI Chat: Standard chat completion format

Changes

New OpenCode Zen Provider (opencode_zen.rs)

  • Intelligent routing based on model prefix to 4 different backends
  • Delegates to existing provider implementations (Anthropic, OpenAI, OpenAIResponses, Google)
  • URL and response type adaptation per backend

OpenAI Responses Enhancements

  • Added ping event handling for cost tracking from proxy servers
  • Added Unknown event variant to silently ignore unrecognized events
  • Introduced StreamItem enum to handle both standard events and pre-resolved messages

Anthropic Provider Updates

  • Added should_use_raw_sse() detection for OpenCode Zen
  • Implemented chat_raw_sse() for manual SSE parsing when content-type validation would fail
  • Uses eventsource_stream crate for raw byte SSE parsing

Context Reasoning Fix

  • append_message() now accepts both reasoning (flat string) and reasoning_details (structured)
  • Merges flat reasoning into reasoning_details array for consistent handling
  • Fixes orchestrator to pass both parameters correctly

Provider Configuration

  • Added OpenCode Zen to provider.json with 20+ models across all backends
  • Models include Claude 4.x, GPT-5.x, Gemini 3.x, and others

Links

@github-actions github-actions Bot added the type: feature Brand new functionality, features, pages, workflows, endpoints, etc. label Mar 18, 2026
@amitksingh1490 amitksingh1490 changed the title feat(provider): add opencode zen routing and ping cost handling feat(provider): add OpenCode Zen provider with multi-backend routing and cost tracking Mar 18, 2026
Comment on lines +89 to +91
if is_complete_usage {
// Replace with the latest complete usage
usage = *current_usage;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical Bug: Cost data loss when cost-only event precedes complete usage event

When replacing usage with complete usage, any previously accumulated cost is lost. This occurs when a cost-only ping event arrives before a complete usage chunk.

Scenario:

  1. Cost-only event arrives: usage.cost = Some(0.005)
  2. Complete usage event arrives: usage = *current_usage (which has cost: None)
  3. Result: The cost from step 1 is lost
if is_complete_usage {
    // Replace with the latest complete usage, but preserve cost if already set
    let existing_cost = usage.cost;
    usage = *current_usage;
    if usage.cost.is_none() && existing_cost.is_some() {
        usage.cost = existing_cost;
    }
}

The existing test test_into_full_cost_only_event_adds_cost_to_usage only validates cost-only events AFTER complete usage, not before.

Suggested change
if is_complete_usage {
// Replace with the latest complete usage
usage = *current_usage;
if is_complete_usage {
// Replace with the latest complete usage, but preserve cost if already set
let existing_cost = usage.cost;
usage = *current_usage;
if usage.cost.is_none() && existing_cost.is_some() {
usage.cost = existing_cost;
}

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Comment thread crates/forge_app/src/dto/anthropic/response.rs Outdated
@tusharmath tusharmath merged commit 40cfcc8 into main Mar 19, 2026
10 checks passed
@tusharmath tusharmath deleted the opencode-zen-provider branch March 19, 2026 08:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature Brand new functionality, features, pages, workflows, endpoints, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants