mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 17:40:44 +00:00
fix: canonicalize opencode-go base URL
This commit is contained in:
@@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
### Fixes
|
### Fixes
|
||||||
|
|
||||||
- Browser/Chrome MCP: reset cached existing-session control sessions when a `navigate_page` call times out, so one stuck navigation no longer poisons the browser profile until a gateway restart. (#69733) Thanks @ayeshakhalid192007-dev.
|
- Browser/Chrome MCP: reset cached existing-session control sessions when a `navigate_page` call times out, so one stuck navigation no longer poisons the browser profile until a gateway restart. (#69733) Thanks @ayeshakhalid192007-dev.
|
||||||
|
- OpenCode Go: canonicalize stale bundled `opencode-go` base URLs from `/go` or `/go/v1` to `/zen/go` or `/zen/go/v1`, so older generated model metadata stops hitting the 404 HTML endpoint. (#69898)
|
||||||
- Channels/preview streaming: centralize draft-preview finalization so Slack, Discord, Mattermost, and Matrix no longer flush temporary preview messages for media/error finals, and preserve first-reply threading for normal fallback delivery.
|
- Channels/preview streaming: centralize draft-preview finalization so Slack, Discord, Mattermost, and Matrix no longer flush temporary preview messages for media/error finals, and preserve first-reply threading for normal fallback delivery.
|
||||||
- Discord: keep slash command follow-up chunks ephemeral when the command is configured for ephemeral replies, so long `/status` output no longer leaks fallback model or runtime details into the public channel. (#69869) thanks @gumadeiras.
|
- Discord: keep slash command follow-up chunks ephemeral when the command is configured for ephemeral replies, so long `/status` output no longer leaks fallback model or runtime details into the public channel. (#69869) thanks @gumadeiras.
|
||||||
- Plugins/discovery: reject package plugin source entries that escape the package directory before explicit runtime entries or inferred built JavaScript peers can be used. (#69868) thanks @gumadeiras.
|
- Plugins/discovery: reject package plugin source entries that escape the package directory before explicit runtime entries or inferred built JavaScript peers can be used. (#69868) thanks @gumadeiras.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { describe, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { registerSingleProviderPlugin } from "../../test/helpers/plugins/plugin-registration.js";
|
||||||
import { expectPassthroughReplayPolicy } from "../../test/helpers/provider-replay-policy.ts";
|
import { expectPassthroughReplayPolicy } from "../../test/helpers/provider-replay-policy.ts";
|
||||||
import plugin from "./index.js";
|
import plugin from "./index.js";
|
||||||
|
|
||||||
@@ -19,4 +20,63 @@ describe("opencode-go provider plugin", () => {
|
|||||||
modelId: "qwen3-coder",
|
modelId: "qwen3-coder",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("canonicalizes stale OpenCode Go base URLs", async () => {
|
||||||
|
const provider = await registerSingleProviderPlugin(plugin);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
provider.normalizeConfig?.({
|
||||||
|
provider: "opencode-go",
|
||||||
|
providerConfig: {
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: "https://opencode.ai/go/v1/",
|
||||||
|
models: [],
|
||||||
|
},
|
||||||
|
} as never),
|
||||||
|
).toMatchObject({
|
||||||
|
baseUrl: "https://opencode.ai/zen/go/v1",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
provider.normalizeResolvedModel?.({
|
||||||
|
provider: "opencode-go",
|
||||||
|
model: {
|
||||||
|
provider: "opencode-go",
|
||||||
|
id: "kimi-k2.5",
|
||||||
|
name: "Kimi K2.5",
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: "https://opencode.ai/go/v1",
|
||||||
|
reasoning: true,
|
||||||
|
input: ["text"],
|
||||||
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
|
contextWindow: 262_144,
|
||||||
|
maxTokens: 65_536,
|
||||||
|
},
|
||||||
|
} as never),
|
||||||
|
).toMatchObject({
|
||||||
|
baseUrl: "https://opencode.ai/zen/go/v1",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
provider.normalizeTransport?.({
|
||||||
|
provider: "opencode-go",
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: "https://opencode.ai/go/v1",
|
||||||
|
} as never),
|
||||||
|
).toEqual({
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: "https://opencode.ai/zen/go/v1",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
provider.normalizeTransport?.({
|
||||||
|
provider: "opencode-go",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
baseUrl: "https://opencode.ai/go",
|
||||||
|
} as never),
|
||||||
|
).toEqual({
|
||||||
|
api: "anthropic-messages",
|
||||||
|
baseUrl: "https://opencode.ai/zen/go",
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { createOpencodeCatalogApiKeyAuthMethod } from "openclaw/plugin-sdk/openc
|
|||||||
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|
||||||
import { PASSTHROUGH_GEMINI_REPLAY_HOOKS } from "openclaw/plugin-sdk/provider-model-shared";
|
import { PASSTHROUGH_GEMINI_REPLAY_HOOKS } from "openclaw/plugin-sdk/provider-model-shared";
|
||||||
import { applyOpencodeGoConfig, OPENCODE_GO_DEFAULT_MODEL_REF } from "./api.js";
|
import { applyOpencodeGoConfig, OPENCODE_GO_DEFAULT_MODEL_REF } from "./api.js";
|
||||||
|
import { normalizeOpencodeGoBaseUrl } from "./provider-catalog.js";
|
||||||
|
|
||||||
const PROVIDER_ID = "opencode-go";
|
const PROVIDER_ID = "opencode-go";
|
||||||
export default definePluginEntry({
|
export default definePluginEntry({
|
||||||
@@ -31,6 +32,33 @@ export default definePluginEntry({
|
|||||||
choiceLabel: "OpenCode Go catalog",
|
choiceLabel: "OpenCode Go catalog",
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
normalizeConfig: ({ providerConfig }) => {
|
||||||
|
const normalizedBaseUrl = normalizeOpencodeGoBaseUrl({
|
||||||
|
api: providerConfig.api,
|
||||||
|
baseUrl: providerConfig.baseUrl,
|
||||||
|
});
|
||||||
|
return normalizedBaseUrl && normalizedBaseUrl !== providerConfig.baseUrl
|
||||||
|
? { ...providerConfig, baseUrl: normalizedBaseUrl }
|
||||||
|
: undefined;
|
||||||
|
},
|
||||||
|
normalizeResolvedModel: ({ model }) => {
|
||||||
|
const normalizedBaseUrl = normalizeOpencodeGoBaseUrl({
|
||||||
|
api: model.api,
|
||||||
|
baseUrl: model.baseUrl,
|
||||||
|
});
|
||||||
|
return normalizedBaseUrl && normalizedBaseUrl !== model.baseUrl
|
||||||
|
? { ...model, baseUrl: normalizedBaseUrl }
|
||||||
|
: undefined;
|
||||||
|
},
|
||||||
|
normalizeTransport: ({ api, baseUrl }) => {
|
||||||
|
const normalizedBaseUrl = normalizeOpencodeGoBaseUrl({ api, baseUrl });
|
||||||
|
return normalizedBaseUrl && normalizedBaseUrl !== baseUrl
|
||||||
|
? {
|
||||||
|
api,
|
||||||
|
baseUrl: normalizedBaseUrl,
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
},
|
||||||
...PASSTHROUGH_GEMINI_REPLAY_HOOKS,
|
...PASSTHROUGH_GEMINI_REPLAY_HOOKS,
|
||||||
isModernModelRef: () => true,
|
isModernModelRef: () => true,
|
||||||
});
|
});
|
||||||
|
|||||||
31
extensions/opencode-go/provider-catalog.ts
Normal file
31
extensions/opencode-go/provider-catalog.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
export const OPENCODE_GO_OPENAI_BASE_URL = "https://opencode.ai/zen/go/v1";
|
||||||
|
export const OPENCODE_GO_ANTHROPIC_BASE_URL = "https://opencode.ai/zen/go";
|
||||||
|
|
||||||
|
function normalizeBaseUrl(baseUrl: string | undefined): string {
|
||||||
|
return (baseUrl ?? "").trim().replace(/\/+$/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeOpencodeGoBaseUrl(params: {
|
||||||
|
api?: string | null;
|
||||||
|
baseUrl?: string;
|
||||||
|
}): string | undefined {
|
||||||
|
const normalized = normalizeBaseUrl(params.baseUrl);
|
||||||
|
if (!normalized) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (normalized === OPENCODE_GO_OPENAI_BASE_URL) {
|
||||||
|
return OPENCODE_GO_OPENAI_BASE_URL;
|
||||||
|
}
|
||||||
|
if (normalized === OPENCODE_GO_ANTHROPIC_BASE_URL) {
|
||||||
|
return OPENCODE_GO_ANTHROPIC_BASE_URL;
|
||||||
|
}
|
||||||
|
if (normalized === "https://opencode.ai/go") {
|
||||||
|
return OPENCODE_GO_ANTHROPIC_BASE_URL;
|
||||||
|
}
|
||||||
|
if (normalized === "https://opencode.ai/go/v1") {
|
||||||
|
return params.api === "anthropic-messages"
|
||||||
|
? OPENCODE_GO_ANTHROPIC_BASE_URL
|
||||||
|
: OPENCODE_GO_OPENAI_BASE_URL;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user