mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
feat(plugins): externalize OpenCode Go provider (#117064)
This commit is contained in:
+1
-1
@@ -8585,7 +8585,7 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
|
||||
- Headings:
|
||||
- H2: Getting started
|
||||
- H2: Config example
|
||||
- H2: Built-in catalog
|
||||
- H2: Catalog
|
||||
- H2: Advanced configuration
|
||||
- H2: Related
|
||||
|
||||
|
||||
@@ -352,7 +352,7 @@ That stages grounded durable candidates into the short-term dreaming store while
|
||||
|
||||
</Accordion>
|
||||
<Accordion title="2b. OpenCode provider overrides">
|
||||
If you have added `models.providers.opencode`, `opencode-zen`, or `opencode-go` manually, it overrides the built-in OpenCode catalog from `openclaw/plugin-sdk/llm`. That can force models onto the wrong API or zero out costs. Doctor warns so you can remove the override and restore per-model API routing + costs.
|
||||
If you have added `models.providers.opencode`, `opencode-zen`, or `opencode-go` manually while the matching official external plugin is installed and enabled, it overrides that plugin-provided catalog. That can force models onto the wrong API or zero out costs. Doctor warns so you can remove the override and restore per-model API routing + costs. Without the matching plugin, the entry remains a valid standalone custom provider.
|
||||
</Accordion>
|
||||
<Accordion title="2c. Browser migration and Chrome MCP readiness">
|
||||
If your browser config still points at the removed Chrome extension path, doctor normalizes it to the current host-local Chrome MCP attach model (`browser.profiles.*.driver: "extension"` → `"existing-session"`; `browser.relayBindHost` removed).
|
||||
|
||||
@@ -612,7 +612,7 @@ If you have keys enabled, you can also test via:
|
||||
|
||||
More providers you can include in the live matrix (if you have creds/config):
|
||||
|
||||
- Built-in: `anthropic`, `cerebras`, `github-copilot`, `google`, `google-antigravity`, `google-gemini-cli`, `google-vertex`, `groq`, `mistral`, `openai`, `openrouter`, `opencode`, `opencode-go`, `xai`, `zai`
|
||||
- First-party provider plugins: `anthropic`, `cerebras`, `github-copilot`, `google`, `google-antigravity`, `google-gemini-cli`, `google-vertex`, `groq`, `mistral`, `openai`, `openrouter`, `opencode`, `opencode-go`, `xai`, `zai`
|
||||
- Via `models.providers` (custom endpoints): `minimax` (cloud/API), plus any OpenAI/Anthropic-compatible proxy (LM Studio, vLLM, LiteLLM, etc.)
|
||||
|
||||
<Tip>
|
||||
|
||||
@@ -51,7 +51,7 @@ Each entry lists the package, distribution route, and description.
|
||||
|
||||
## Core npm package
|
||||
|
||||
56 plugins
|
||||
55 plugins
|
||||
|
||||
- **[admin-http-rpc](/plugins/reference/admin-http-rpc)** (`@openclaw/admin-http-rpc`) - included in OpenClaw. OpenClaw admin HTTP RPC endpoint.
|
||||
|
||||
@@ -133,8 +133,6 @@ Each entry lists the package, distribution route, and description.
|
||||
|
||||
- **[openai](/plugins/reference/openai)** (`@openclaw/openai-provider`) - included in OpenClaw. Adds OpenAI model provider support to OpenClaw.
|
||||
|
||||
- **[opencode-go](/plugins/reference/opencode-go)** (`@openclaw/opencode-go-provider`) - included in OpenClaw. Adds OpenCode Go model provider support to OpenClaw.
|
||||
|
||||
- **[openrouter](/plugins/reference/openrouter)** (`@openclaw/openrouter-provider`) - included in OpenClaw. Adds OpenRouter model provider support to OpenClaw.
|
||||
|
||||
- **[policy](/plugins/reference/policy)** (`@openclaw/policy`) - included in OpenClaw. Adds policy-backed doctor checks for workspace conformance.
|
||||
@@ -167,7 +165,7 @@ Each entry lists the package, distribution route, and description.
|
||||
|
||||
## Official external packages
|
||||
|
||||
89 plugins
|
||||
90 plugins
|
||||
|
||||
- **[acpx](/plugins/reference/acpx)** (`@openclaw/acpx`) - npm; ClawHub. OpenClaw ACP runtime backend with plugin-owned session and transport management.
|
||||
|
||||
@@ -281,6 +279,8 @@ Each entry lists the package, distribution route, and description.
|
||||
|
||||
- **[opencode](/plugins/reference/opencode)** (`@openclaw/opencode-provider`) - npm; ClawHub: `clawhub:@openclaw/opencode-provider`. Adds OpenCode model provider support to OpenClaw.
|
||||
|
||||
- **[opencode-go](/plugins/reference/opencode-go)** (`@openclaw/opencode-go-provider`) - npm; ClawHub: `clawhub:@openclaw/opencode-go-provider`. Adds OpenCode Go model provider support to OpenClaw.
|
||||
|
||||
- **[openshell](/plugins/reference/openshell)** (`@openclaw/openshell-sandbox`) - npm; ClawHub. OpenClaw sandbox backend for the NVIDIA OpenShell CLI with mirrored local workspaces and SSH command execution.
|
||||
|
||||
- **[parallel](/tools/parallel-search)** (`@openclaw/parallel-plugin`) - npm; ClawHub: `clawhub:@openclaw/parallel-plugin`. Adds web search provider support.
|
||||
|
||||
@@ -12,7 +12,7 @@ Adds OpenCode Go model provider support to OpenClaw.
|
||||
## Distribution
|
||||
|
||||
- Package: `@openclaw/opencode-go-provider`
|
||||
- Install route: included in OpenClaw
|
||||
- Install route: npm; ClawHub: `clawhub:@openclaw/opencode-go-provider`
|
||||
|
||||
## Surface
|
||||
|
||||
|
||||
@@ -9,16 +9,25 @@ title: "OpenCode Go"
|
||||
OpenCode Go is the Go catalog inside [OpenCode](/providers/opencode). It shares
|
||||
the `OPENCODE_API_KEY` credential with the Zen catalog, but keeps its own
|
||||
runtime provider id (`opencode-go`) so upstream per-model routing stays
|
||||
correct.
|
||||
correct. OpenClaw provides it as the official external
|
||||
`@openclaw/opencode-go-provider` plugin.
|
||||
|
||||
| Property | Value |
|
||||
| ---------------- | -------------------------------------------------- |
|
||||
| Runtime provider | `opencode-go` |
|
||||
| Plugin | `@openclaw/opencode-go-provider` |
|
||||
| Auth | `OPENCODE_API_KEY` (alias: `OPENCODE_ZEN_API_KEY`) |
|
||||
| Parent setup | [OpenCode](/providers/opencode) |
|
||||
|
||||
## Getting started
|
||||
|
||||
Install the official plugin and restart the Gateway:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/opencode-go-provider
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
<Tabs>
|
||||
<Tab title="Interactive">
|
||||
<Steps>
|
||||
@@ -65,10 +74,10 @@ correct.
|
||||
}
|
||||
```
|
||||
|
||||
## Built-in catalog
|
||||
## Catalog
|
||||
|
||||
Run `openclaw models list --provider opencode-go` for the current model list.
|
||||
Bundled rows:
|
||||
Current rows:
|
||||
|
||||
| Model ref | Name | Context | Max output | Image input |
|
||||
| ------------------------------- | ----------------- | --------- | ---------- | ----------- |
|
||||
|
||||
@@ -55,6 +55,12 @@ one OpenCode setup.
|
||||
**Best for:** the OpenCode-hosted Kimi, GLM, MiniMax, Qwen, and DeepSeek lineup.
|
||||
|
||||
<Steps>
|
||||
<Step title="Install the Go catalog plugin">
|
||||
```bash
|
||||
openclaw plugins install @openclaw/opencode-go-provider
|
||||
openclaw gateway restart
|
||||
```
|
||||
</Step>
|
||||
<Step title="Run onboarding">
|
||||
```bash
|
||||
openclaw onboard --auth-choice opencode-go
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# OpenClaw OpenCode Go Provider
|
||||
|
||||
Official OpenClaw provider plugin for the OpenCode Go model catalog.
|
||||
|
||||
Install from OpenClaw:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/opencode-go-provider
|
||||
openclaw gateway restart
|
||||
```
|
||||
|
||||
Configure `OPENCODE_API_KEY` or `OPENCODE_ZEN_API_KEY`, then select an
|
||||
`opencode-go/...` model.
|
||||
|
||||
See <https://docs.openclaw.ai/providers/opencode-go> for setup and the current
|
||||
model catalog.
|
||||
@@ -41,7 +41,7 @@ function resolveOpencodeGoCatalogAuth(
|
||||
export default defineSingleProviderPluginEntry({
|
||||
id: PROVIDER_ID,
|
||||
name: "OpenCode Go Provider",
|
||||
description: "Bundled OpenCode Go provider plugin",
|
||||
description: "Official OpenCode Go provider plugin",
|
||||
manifest,
|
||||
provider: {
|
||||
label: "OpenCode Go",
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
{
|
||||
"name": "@openclaw/opencode-go-provider",
|
||||
"version": "2026.7.2",
|
||||
"private": true,
|
||||
"description": "OpenClaw OpenCode Go provider plugin",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@openclaw/plugin-sdk": "workspace:*"
|
||||
@@ -10,6 +13,23 @@
|
||||
"openclaw": {
|
||||
"extensions": [
|
||||
"./index.ts"
|
||||
]
|
||||
],
|
||||
"install": {
|
||||
"clawhubSpec": "clawhub:@openclaw/opencode-go-provider",
|
||||
"npmSpec": "@openclaw/opencode-go-provider",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.7.2"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.7.2"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.7.2",
|
||||
"bundledDist": false
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
"publishToNpm": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +295,7 @@
|
||||
"!dist/extensions/nostr/**",
|
||||
"!dist/extensions/novita/**",
|
||||
"!dist/extensions/opencode/**",
|
||||
"!dist/extensions/opencode-go/**",
|
||||
"!dist/extensions/parallel/**",
|
||||
"!dist/extensions/perplexity/**",
|
||||
"!dist/extensions/qianfan/**",
|
||||
|
||||
@@ -1190,6 +1190,69 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "@openclaw/opencode-go-provider",
|
||||
"description": "OpenClaw OpenCode Go provider plugin",
|
||||
"source": "official",
|
||||
"kind": "provider",
|
||||
"openclaw": {
|
||||
"plugin": {
|
||||
"id": "opencode-go",
|
||||
"label": "OpenCode Go"
|
||||
},
|
||||
"providerEndpoints": [
|
||||
{
|
||||
"endpointClass": "opencode-native",
|
||||
"hostSuffixes": [
|
||||
"opencode.ai"
|
||||
]
|
||||
}
|
||||
],
|
||||
"providers": [
|
||||
{
|
||||
"id": "opencode-go",
|
||||
"name": "OpenCode Go",
|
||||
"docs": "/providers/opencode-go",
|
||||
"categories": [
|
||||
"cloud",
|
||||
"llm"
|
||||
],
|
||||
"envVars": [
|
||||
"OPENCODE_API_KEY",
|
||||
"OPENCODE_ZEN_API_KEY"
|
||||
],
|
||||
"authChoices": [
|
||||
{
|
||||
"method": "api-key",
|
||||
"choiceId": "opencode-go",
|
||||
"choiceLabel": "OpenCode Go catalog",
|
||||
"groupId": "opencode",
|
||||
"groupLabel": "OpenCode",
|
||||
"groupHint": "Shared API key for Zen + Go catalogs",
|
||||
"optionKey": "opencodeGoApiKey",
|
||||
"cliFlag": "--opencode-go-api-key",
|
||||
"cliOption": "--opencode-go-api-key <key>",
|
||||
"cliDescription": "OpenCode API key (Go catalog)",
|
||||
"onboardingScopes": [
|
||||
"text-inference"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"contracts": {
|
||||
"mediaUnderstandingProviders": [
|
||||
"opencode-go"
|
||||
]
|
||||
},
|
||||
"install": {
|
||||
"clawhubSpec": "clawhub:@openclaw/opencode-go-provider",
|
||||
"npmSpec": "@openclaw/opencode-go-provider",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.7.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "@openclaw/pixverse-provider",
|
||||
"description": "OpenClaw PixVerse video provider plugin",
|
||||
|
||||
@@ -170,6 +170,7 @@ describe("listPersistedBundledPluginLocationBridges", () => {
|
||||
["mistral", "@openclaw/mistral-provider", true],
|
||||
["novita", "@openclaw/novita-provider", true],
|
||||
["opencode", "@openclaw/opencode-provider", true],
|
||||
["opencode-go", "@openclaw/opencode-go-provider", true],
|
||||
["synthetic", "@openclaw/synthetic-provider", true],
|
||||
["teams-meetings", "@openclaw/teams-meetings", true],
|
||||
["volcengine", "@openclaw/volcengine-provider", true],
|
||||
|
||||
@@ -6,6 +6,7 @@ import { OpenClawSchema } from "../config/zod-schema.js";
|
||||
import {
|
||||
formatConfigPath,
|
||||
noteImplicitFallbackClobberWarnings,
|
||||
noteOpencodeProviderOverrides,
|
||||
noteSandboxOriginProxyWarning,
|
||||
resolveConfigPathTarget,
|
||||
stripUnknownConfigKeys,
|
||||
@@ -23,6 +24,66 @@ function collectImplicitFallbackClobberWarnings(cfg: OpenClawConfig): string[] {
|
||||
}
|
||||
|
||||
describe("doctor config analysis helpers", () => {
|
||||
it("describes OpenCode overrides against the plugin-provided catalog", () => {
|
||||
noteMock.mockClear();
|
||||
|
||||
noteOpencodeProviderOverrides(
|
||||
{
|
||||
models: {
|
||||
providers: {
|
||||
opencode: {
|
||||
baseUrl: "https://opencode.ai/zen/v1",
|
||||
api: "openai-completions",
|
||||
models: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ opencodePluginActive: true },
|
||||
);
|
||||
|
||||
expect(noteMock).toHaveBeenCalledWith(
|
||||
expect.stringContaining("plugin-provided OpenCode Zen catalog"),
|
||||
"OpenCode",
|
||||
);
|
||||
expect(noteMock.mock.calls.at(-1)?.[0]).not.toContain("built-in");
|
||||
});
|
||||
|
||||
it("classifies external OpenCode overrides only while their plugins are active", () => {
|
||||
noteMock.mockClear();
|
||||
|
||||
const cfg: OpenClawConfig = {
|
||||
models: {
|
||||
providers: {
|
||||
opencode: {
|
||||
baseUrl: "https://opencode.ai/zen/v1",
|
||||
api: "openai-completions",
|
||||
models: [],
|
||||
},
|
||||
"opencode-go": {
|
||||
baseUrl: "https://opencode.ai/zen/go/v1",
|
||||
api: "openai-completions",
|
||||
models: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
noteOpencodeProviderOverrides(cfg);
|
||||
expect(noteMock).not.toHaveBeenCalled();
|
||||
|
||||
noteOpencodeProviderOverrides(cfg, {
|
||||
opencodePluginActive: true,
|
||||
opencodeGoPluginActive: true,
|
||||
});
|
||||
expect(noteMock).toHaveBeenCalledWith(
|
||||
expect.stringMatching(
|
||||
/plugin-provided OpenCode Zen catalog[\s\S]*plugin-provided OpenCode Go catalog/u,
|
||||
),
|
||||
"OpenCode",
|
||||
);
|
||||
});
|
||||
|
||||
it("formats config paths predictably", () => {
|
||||
expect(formatConfigPath([])).toBe("<root>");
|
||||
expect(formatConfigPath(["channels", "slack", "accounts", 0, "token"])).toBe(
|
||||
|
||||
@@ -129,21 +129,24 @@ export function stripUnknownConfigKeys(config: OpenClawConfig): {
|
||||
return { config: next, removed };
|
||||
}
|
||||
|
||||
/** Warns when legacy OpenCode provider overrides shadow the built-in catalog. */
|
||||
export function noteOpencodeProviderOverrides(cfg: OpenClawConfig): void {
|
||||
/** Warns when legacy OpenCode overrides shadow an active plugin-provided catalog. */
|
||||
export function noteOpencodeProviderOverrides(
|
||||
cfg: OpenClawConfig,
|
||||
options: { opencodePluginActive?: boolean; opencodeGoPluginActive?: boolean } = {},
|
||||
): void {
|
||||
const providers = cfg.models?.providers;
|
||||
if (!providers) {
|
||||
return;
|
||||
}
|
||||
|
||||
const overrides: string[] = [];
|
||||
if (providers.opencode) {
|
||||
if (options.opencodePluginActive === true && providers.opencode) {
|
||||
overrides.push("opencode");
|
||||
}
|
||||
if (providers["opencode-zen"]) {
|
||||
if (options.opencodePluginActive === true && providers["opencode-zen"]) {
|
||||
overrides.push("opencode-zen");
|
||||
}
|
||||
if (providers["opencode-go"]) {
|
||||
if (options.opencodeGoPluginActive === true && providers["opencode-go"]) {
|
||||
overrides.push("opencode-go");
|
||||
}
|
||||
if (overrides.length === 0) {
|
||||
@@ -158,7 +161,7 @@ export function noteOpencodeProviderOverrides(cfg: OpenClawConfig): void {
|
||||
? providerEntry.api
|
||||
: undefined;
|
||||
return [
|
||||
`- models.providers.${id} is set; this overrides the built-in ${providerLabel} catalog.`,
|
||||
`- models.providers.${id} is set; this overrides the plugin-provided ${providerLabel} catalog.`,
|
||||
api ? `- models.providers.${id}.api=${api}` : null,
|
||||
].filter((line): line is string => Boolean(line));
|
||||
});
|
||||
|
||||
@@ -476,7 +476,23 @@ export async function loadAndMaybeMigrateDoctorConfig(params: {
|
||||
candidate: cfg,
|
||||
});
|
||||
|
||||
noteOpencodeProviderOverrides(cfg);
|
||||
const configuredOpencodePluginIds = [
|
||||
cfg.models?.providers?.opencode || cfg.models?.providers?.["opencode-zen"]
|
||||
? "opencode"
|
||||
: undefined,
|
||||
cfg.models?.providers?.["opencode-go"] ? "opencode-go" : undefined,
|
||||
].filter((pluginId): pluginId is string => pluginId !== undefined);
|
||||
const activeOpencodePluginIds =
|
||||
configuredOpencodePluginIds.length > 0
|
||||
? (await import("../plugins/providers.js")).resolveEnabledProviderPluginIds({
|
||||
config: cfg,
|
||||
onlyPluginIds: configuredOpencodePluginIds,
|
||||
})
|
||||
: [];
|
||||
noteOpencodeProviderOverrides(cfg, {
|
||||
opencodePluginActive: activeOpencodePluginIds.includes("opencode"),
|
||||
opencodeGoPluginActive: activeOpencodePluginIds.includes("opencode-go"),
|
||||
});
|
||||
noteImplicitFallbackClobberWarnings(cfg);
|
||||
noteSandboxOriginProxyWarning(cfg);
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ describe("doctor command", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("warns about opencode provider overrides", async () => {
|
||||
it("warns about active OpenCode provider overrides", async () => {
|
||||
mockDoctorConfigSnapshot({
|
||||
config: {
|
||||
models: {
|
||||
|
||||
@@ -1981,6 +1981,27 @@ describe("official external plugin catalog", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("lists OpenCode Go with its provider and media-understanding contracts", () => {
|
||||
const opencodeGo = expectCatalogEntry("opencode-go");
|
||||
const manifest = getOfficialExternalPluginCatalogManifest(opencodeGo);
|
||||
|
||||
expect(resolveOfficialExternalPluginId(opencodeGo)).toBe("opencode-go");
|
||||
expect(resolveOfficialExternalPluginInstall(opencodeGo)).toEqual({
|
||||
clawhubSpec: "clawhub:@openclaw/opencode-go-provider",
|
||||
npmSpec: "@openclaw/opencode-go-provider",
|
||||
defaultChoice: "npm",
|
||||
minHostVersion: ">=2026.7.2",
|
||||
});
|
||||
expect(manifest?.providers?.map((provider) => provider.id)).toEqual(["opencode-go"]);
|
||||
expect(manifest?.contracts?.mediaUnderstandingProviders).toEqual(["opencode-go"]);
|
||||
expect(manifest?.providerEndpoints).toEqual([
|
||||
{
|
||||
endpointClass: "opencode-native",
|
||||
hostSuffixes: ["opencode.ai"],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("lists Synthetic as an official external provider", () => {
|
||||
const synthetic = expectCatalogEntry("synthetic");
|
||||
|
||||
|
||||
@@ -349,6 +349,7 @@ describe("bundled plugin build entries", () => {
|
||||
"mistral",
|
||||
"novita",
|
||||
"opencode",
|
||||
"opencode-go",
|
||||
"xiaomi",
|
||||
]) {
|
||||
expect(artifacts).not.toContain(`dist/extensions/${pluginId}/index.js`);
|
||||
|
||||
Reference in New Issue
Block a user