Skip to content

Add OpenCode Go provider#54

Open
mulfyx wants to merge 1 commit into
raine:mainfrom
mulfyx:feat/opencode-go-provider-pr
Open

Add OpenCode Go provider#54
mulfyx wants to merge 1 commit into
raine:mainfrom
mulfyx:feat/opencode-go-provider-pr

Conversation

@mulfyx

@mulfyx mulfyx commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Add OpenCode Go provider

Closes #46.

Summary

  • Add OpenCode Go as an API-key provider behind the existing Anthropic-compatible server.
  • Route each model to the OpenCode Go wire protocol it actually supports: OpenAI-compatible chat/completions or Anthropic-compatible messages.
  • Support both canonical opencode-go/<model-id> names and unambiguous bare model IDs.
  • Reuse the existing OpenAI-compatible translation path for chat models and stream Anthropic-compatible models directly.
  • Add configuration, model catalog registration, CLI model listing, documentation, and regression coverage.

Routing and authentication

OpenCode Go splits one subscription catalog across two upstream APIs:

Upstream Authentication Models
/chat/completions Authorization: Bearer ... glm-5.2, glm-5.1, glm-5, kimi-k2.7-code, kimi-k2.6, kimi-k2.5, deepseek-v4-pro, deepseek-v4-flash, mimo-v2.5, mimo-v2.5-pro
/messages x-api-key + anthropic-version minimax-m3, minimax-m2.7, minimax-m2.5, qwen3.7-max, qwen3.7-plus, qwen3.6-plus, qwen3.5-plus

The API key is resolved in this order:

  1. CCP_OPENCODE_API_KEY
  2. OPENCODE_API_KEY
  3. opencode.apiKey in config.json

CCP_OPENCODE_BASE_URL or opencode.baseUrl can override the default https://opencode.ai/zen/go/v1 base URL.

The canonical opencode-go/ prefix can always be used to force this provider. Bare IDs are also registered where they do not conflict with an existing provider. In particular, bare kimi-k2.6 remains assigned to the existing Kimi provider, while opencode-go/kimi-k2.6 selects OpenCode Go.

The current OpenCode documentation lists 14 endpoint assignments. Live /models discovery also returned three older IDs that still completed real requests: glm-5, kimi-k2.5, and qwen3.5-plus. Three other discovered IDs were deliberately not advertised because direct requests failed: mimo-v2-pro, mimo-v2-omni, and hy3-preview.

Protocol handling

  • OpenAI-compatible models reuse the Kimi request translation code, with provider-specific Kimi fields kept out of the generic request path.
  • Dynamic system-prompt sections that recent Claude Code versions append as role: system messages are merged with the top-level system prompt before translation.
  • Their upstream SSE is decoded and translated incrementally. Claude Code receives each completed Anthropic event without waiting for the entire OpenCode response to finish.
  • Anthropic-compatible models preserve the incoming Messages shape, replace the provider-qualified model name with the upstream ID, and pass streaming responses through.
  • minimax-m3 receives OpenCode's default thinking: {"type":"adaptive"} when the caller does not provide a thinking option; an explicit caller value is preserved unchanged.
  • Streaming requests have a connection timeout but no fixed total-response deadline, so an active long-running response is not terminated after 120 seconds.
  • /v1/messages/count_tokens is handled locally and does not consume OpenCode Go quota.
  • Missing credentials produce a clear Anthropic-style authentication error.
  • Upstream 429 responses map to rate_limit_error and preserve Retry-After.
  • Buffered upstream responses are capped at 8 MiB.

The provider intentionally keeps a static reviewed model catalog and does not add a runtime models.dev dependency. This change also does not introduce a new output-token truncation policy.

Tool-call streaming fix

End-to-end Claude Code testing exposed a pre-existing bug in the shared OpenAI-compatible SSE reducer. Upstream tool-call argument fragments are keyed by the upstream tool index, but the reducer previously looked up later fragments using the generated Anthropic content-block index. If a thinking or text block appeared before the tool call, Claude Code could receive an empty tool input such as Read {} or Bash {}.

The reducer now tracks both indices independently and matches argument fragments by the upstream tool index. A regression test covers a reasoning block followed by a fragmented tool call. This also hardens the existing Kimi translation path.

Verification

  • cargo test --all-targets: 604 passed, 0 failed.
  • OpenCode provider unit tests cover endpoint selection, credential precedence, provider-qualified IDs, authentication headers, error mapping, response limits, and token counting.
  • A deterministic HTTP integration test holds the upstream terminal event open and proves that the first translated text event reaches the downstream client before upstream completion.
  • Incremental decoder tests cover every byte split, LF/CRLF framing, incomplete frames, invalid UTF-8, frame bounds, reasoning, and fragmented tool-call arguments across chunks.
  • Request-shape tests cover the qwen3.5-plus Messages route and verify that the MiniMax adaptive-thinking fallback does not overwrite caller-supplied thinking.
  • Real Claude Code CLI 2.1.207 smoke tests on the current implementation passed for all 17 supported models.
  • Each model completed a multi-turn agent flow with thinking, Read, Write, Bash auto-review, Bash execution, and final result verification.
  • The generated implementation used a handwritten stable insertion sort and was validated both by execution and by an AST check that rejected sorted() and .sort().
  • Every model trace contained incremental stream_event output. The run and one clean retry after a Claude Code auto-review timeout recorded 115 successful OpenCode Go upstream requests across all 17 models, with no failed or non-2xx requests.
  • A final clean-branch Claude Code smoke covered glm-5.2, qwen3.5-plus, and minimax-m3 as representatives of both upstream protocols and the adaptive-thinking path; all three streamed successfully with HTTP 200 and no proxy errors.
  • cargo fmt --all -- --check passes.
  • git diff --check passes.

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FR: add OpenCode Go provider

1 participant