import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth-api-key"; import { PASSTHROUGH_GEMINI_REPLAY_HOOKS } from "openclaw/plugin-sdk/provider-model-shared"; import { applyOpencodeGoConfig, OPENCODE_GO_DEFAULT_MODEL_REF } from "./api.js"; import { opencodeGoMediaUnderstandingProvider } from "./media-understanding-provider.js"; import { listOpencodeGoSupplementalModelCatalogEntries, normalizeOpencodeGoBaseUrl, resolveOpencodeGoSupplementalModel, } from "./provider-catalog.js"; import { createOpencodeGoDeepSeekV4Wrapper } from "./stream.js"; const PROVIDER_ID = "opencode-go"; const OPENCODE_SHARED_PROFILE_IDS = ["opencode:default", "opencode-go:default"] as const; const OPENCODE_SHARED_HINT = "Shared API key for Zen + Go catalogs"; const OPENCODE_SHARED_WIZARD_GROUP = { groupId: "opencode", groupLabel: "OpenCode", groupHint: OPENCODE_SHARED_HINT, } as const; export default definePluginEntry({ id: PROVIDER_ID, name: "OpenCode Go Provider", description: "Bundled OpenCode Go provider plugin", register(api) { api.registerProvider({ id: PROVIDER_ID, label: "OpenCode Go", docsPath: "/providers/models", envVars: ["OPENCODE_API_KEY", "OPENCODE_ZEN_API_KEY"], auth: [ createProviderApiKeyAuthMethod({ providerId: PROVIDER_ID, methodId: "api-key", label: "OpenCode Go catalog", hint: OPENCODE_SHARED_HINT, optionKey: "opencodeGoApiKey", flagName: "--opencode-go-api-key", envVar: "OPENCODE_API_KEY", promptMessage: "Enter OpenCode API key", profileIds: [...OPENCODE_SHARED_PROFILE_IDS], defaultModel: OPENCODE_GO_DEFAULT_MODEL_REF, applyConfig: (cfg) => applyOpencodeGoConfig(cfg), expectedProviders: ["opencode", "opencode-go"], noteMessage: [ "OpenCode uses one API key across the Zen and Go catalogs.", "Go focuses on Kimi, GLM, and MiniMax coding models.", "Get your API key at: https://opencode.ai/auth", ].join("\n"), noteTitle: "OpenCode", wizard: { choiceId: "opencode-go", choiceLabel: "OpenCode Go catalog", ...OPENCODE_SHARED_WIZARD_GROUP, }, }), ], 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; }, resolveDynamicModel: ({ modelId }) => resolveOpencodeGoSupplementalModel(modelId), augmentModelCatalog: () => listOpencodeGoSupplementalModelCatalogEntries(), ...PASSTHROUGH_GEMINI_REPLAY_HOOKS, wrapStreamFn: (ctx) => createOpencodeGoDeepSeekV4Wrapper(ctx.streamFn, ctx.thinkingLevel), isModernModelRef: () => true, }); api.registerMediaUnderstandingProvider(opencodeGoMediaUnderstandingProvider); }, });