import { createOpencodeCatalogApiKeyAuthMethod } from
"openclaw/plugin-sdk/opencode";
import { definePluginEntry } from
"openclaw/plugin-sdk/plugin-entry";
import {
matchesExactOrPrefix,
PASSTHROUGH_GEMINI_REPLAY_HOOKS,
} from
"openclaw/plugin-sdk/provider-model-shared";
import { normalizeLowercaseStringOrEmpty } from
"openclaw/plugin-sdk/text-runtime";
import { applyOpencodeZenConfig, OPENCODE_ZEN_DEFAULT_MODEL } from
"./api.js";
import { opencodeMediaUnderstandingProvider } from
"./media-understanding-provider.js";
const PROVIDER_ID =
"opencode";
const MINIMAX_MODERN_MODEL_MATCHERS = [
"minimax-m2.7"] as
const;
function isModernOpencodeModel(modelId: string):
boolean {
const lower = normalizeLowercaseStringOrEmpty(modelId);
if (lower.endsWith(
"-free") || lower ===
"alpha-glm-4.7") {
return false;
}
return !matchesExactOrPrefix(lower, MINIMAX_MODERN_MODEL_MATCHERS);
}
export
default definePluginEntry({
id: PROVIDER_ID,
name:
"OpenCode Zen Provider",
description:
"Bundled OpenCode Zen provider plugin",
register(api) {
api.registerProvider({
id: PROVIDER_ID,
label:
"OpenCode Zen",
docsPath:
"/providers/models",
envVars: [
"OPENCODE_API_KEY",
"OPENCODE_ZEN_API_KEY"],
auth: [
createOpencodeCatalogApiKeyAuthMethod({
providerId: PROVIDER_ID,
label:
"OpenCode Zen catalog",
optionKey:
"opencodeZenApiKey",
flagName:
"--opencode-zen-api-key",
defaultModel: OPENCODE_ZEN_DEFAULT_MODEL,
applyConfig: (cfg) => applyOpencodeZenConfig(cfg),
noteMessage: [
"OpenCode uses one API key across the Zen and Go catalogs.",
"Zen provides access to Claude, GPT, Gemini, and more models.",
"Get your API key at: https://opencode.ai/auth",
"Choose the Zen catalog when you want the curated multi-model proxy.",
].join(
"\n"),
choiceId:
"opencode-zen",
choiceLabel:
"OpenCode Zen catalog",
}),
],
...PASSTHROUGH_GEMINI_REPLAY_HOOKS,
isModernModelRef: ({ modelId }) => isModernOpencodeModel(modelId),
});
api.registerMediaUnderstandingProvider(opencodeMediaUnderstandingProvider);
},
});