Skip to content

feat: add OpenCode Go provider source - #10537

Open
tooplick wants to merge 2 commits into
AstrBotDevs:masterfrom
tooplick:feat/opencode-go-provider
Open

tooplick wants to merge 2 commits into
AstrBotDevs:masterfrom
tooplick:feat/opencode-go-provider

Conversation

@tooplick

@tooplick tooplick commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add the OpenCode Go provider source: a subscription gateway serving models through different API protocols
  • Route each model to its protocol — OpenAI Chat Completions (/chat/completions), Anthropic Messages (/messages) or OpenAI Responses (/responses) — by delegating to the existing \ProviderOpenAIOfficial\ / \ProviderAnthropic\ / \ProviderOpenAIResponses\ adapters instead of re-implementing any protocol
  • Refresh the model-to-protocol mapping from \GET /models\ metadata; unknown models fall back to chat completions
  • Send a per-conversation \x-opencode-session\ header (mapped from the AstrBot session ID) with a stable per-instance fallback, since the gateway rejects empty values
  • Register the adapter in \manager.py, add the \OpenCode Go\ WebUI config template, provider icon (lobehub CDN), selector ordering and i18n descriptions (zh-CN/en-US/ja-JP/ru-RU)

Test plan

  • \uv run ruff format --check .\ + \uv run ruff check .\ pass
  • Pylance type check clean
  • Mock-gateway capture tests: /v1/messages\ (claude-haiku-5-5), /v1/chat/completions\ (kimi-k3) and /responses\ routing all send \x-opencode-session\ + \Authorization: Bearer; streaming (SSE) and non-streaming verified
  • \cd dashboard && pnpm build\ passes (vue-tsc + vite)
  • Manual smoke in WebUI with a real key

Summary by Sourcery

Add OpenCode Go as a configurable multi-protocol provider source.

New Features:

  • Add the OpenCode Go provider with support for models served through OpenAI Chat Completions, Anthropic Messages, and OpenAI Responses protocols.
  • Refresh model availability and protocol routing from gateway metadata, with chat-completions fallback for unknown models.
  • Forward per-conversation OpenCode session identifiers and required bearer authentication across requests.

Enhancements:

  • Reuse existing OpenAI, Anthropic, and OpenAI Responses provider adapters for consistent streaming and non-streaming behavior.

Chores:

  • Register OpenCode Go in provider configuration and the WebUI with localized descriptions, ordering, and branding.

Route each OpenCode Go model to the API protocol serving it (OpenAI chat completions, Anthropic messages, or OpenAI responses) by delegating to the existing provider adapters, refresh the model-to-protocol mapping from GET /models metadata, and send a per-conversation x-opencode-session header with a stable fallback. Register the provider in the manager and add the WebUI config template, provider icon, selector ordering and i18n descriptions.

@sourcery-ai sourcery-ai Bot left a comment

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.

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="astrbot/core/provider/sources/opencode_go_source.py" line_range="283" />
<code_context>
+            self.provider_config.get("api_base") or OPENCODE_GO_API_BASE
+        ).rstrip("/")
+        try:
+            headers = build_provider_headers(self.provider_config.get("custom_headers"))
+            async with create_proxy_client(
+                "OpenCodeGo",
</code_context>
<issue_to_address>
**Live models stay unavailable**

When the gateway requires bearer authentication for GET /models, `get_models` omits the configured provider API key from its custom-header-only request, so the gateway rejects it and the exception handler returns only seeded models; callers cannot discover live models or refresh protocol mappings.

Add the configured API key as a bearer Authorization header to the `/models` request.
</issue_to_address>

### Comment 2
<location path="astrbot/core/provider/sources/opencode_go_source.py" line_range="214" />
<code_context>
+                **(delegate_config.get("custom_headers") or {}),
+                # The Anthropic SDK only sends x-api-key; the gateway expects
+                # the same bearer token as the other protocols.
+                "Authorization": f"Bearer {self.get_current_key()}",
+            }
+            self._anthropic = _OpenCodeAnthropic(
</code_context>
<issue_to_address>
**Rotated keys fail Anthropic requests**

When the active API key changes after the Anthropic delegate is created, `_get_anthropic` snapshots `get_current_key()` in the delegate’s Authorization header, so later Anthropic requests keep using the old key and fail authentication.

Update the Anthropic delegate’s Authorization header to use the current API key when the active key changes.
</issue_to_address>

### Comment 3
<location path="astrbot/core/provider/sources/opencode_go_source.py" line_range="217-218" />
<code_context>
+                "Authorization": f"Bearer {self.get_current_key()}",
+            }
+            self._anthropic = _OpenCodeAnthropic(
+                delegate_config, self._provider_settings
+            )
+        return self._anthropic
+
</code_context>
<issue_to_address>
**Delegate clients remain open**

When the provider is terminated after either delegate has been initialized, the inherited `ProviderOpenAIOfficial.terminate` closes only the outer client, leaving the Anthropic and Responses delegate clients open and leaking their HTTP resources.

Override `terminate` to close the clients created by both delegates as well as the outer client.

Also at `astrbot/core/provider/sources/opencode_go_source.py:229-230`.
</issue_to_address>

Sourcery assessment

Approval pending. 3 findings to address first.

Blocking findings: astrbot/core/provider/sources/opencode_go_source.py:283, astrbot/core/provider/sources/opencode_go_source.py:214, astrbot/core/provider/sources/opencode_go_source.py:218


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread astrbot/core/provider/sources/opencode_go_source.py
Comment thread astrbot/core/provider/sources/opencode_go_source.py
Comment thread astrbot/core/provider/sources/opencode_go_source.py
- Authenticate GET /models with the configured bearer key so live models and protocol mappings can be refreshed
- Inject the current bearer key per request on protocol delegates so key rotation is picked up (covers Anthropic and Responses delegates)
- Close both protocol delegate clients in terminate() so provider removal does not leak HTTP resources

@sourcery-ai sourcery-ai Bot left a comment

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.

Sourcery assessment

Approved.

This branch has not been deployed

No deployments
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.

1 participant