openclaw/src/auto-reply/reply/directive-handling.model-picker.ts
Luke 7761e7626f
Providers: add Opencode Go support (#42313)
* feat(providers): add opencode-go provider support and onboarding

* Onboard: unify OpenCode auth handling openclaw#42313 thanks @ImLukeF

* Docs: merge OpenCode Zen and Go docs openclaw#42313 thanks @ImLukeF

* Update CHANGELOG.md

---------

Co-authored-by: Ubuntu <ubuntu@vps-90352893.vps.ovh.ca>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-03-11 01:31:06 -04:00

99 lines
2.3 KiB
TypeScript

import { type ModelRef, normalizeProviderId } from "../../agents/model-selection.js";
import type { OpenClawConfig } from "../../config/config.js";
export type ModelPickerCatalogEntry = {
provider: string;
id: string;
name?: string;
};
export type ModelPickerItem = ModelRef;
const MODEL_PICK_PROVIDER_PREFERENCE = [
"anthropic",
"openai",
"openai-codex",
"minimax",
"synthetic",
"google",
"zai",
"openrouter",
"opencode",
"opencode-go",
"github-copilot",
"groq",
"cerebras",
"mistral",
"xai",
"lmstudio",
] as const;
const PROVIDER_RANK = new Map<string, number>(
MODEL_PICK_PROVIDER_PREFERENCE.map((provider, idx) => [provider, idx]),
);
function compareProvidersForPicker(a: string, b: string): number {
const pa = PROVIDER_RANK.get(a);
const pb = PROVIDER_RANK.get(b);
if (pa !== undefined && pb !== undefined) {
return pa - pb;
}
if (pa !== undefined) {
return -1;
}
if (pb !== undefined) {
return 1;
}
return a.localeCompare(b);
}
export function buildModelPickerItems(catalog: ModelPickerCatalogEntry[]): ModelPickerItem[] {
const seen = new Set<string>();
const out: ModelPickerItem[] = [];
for (const entry of catalog) {
const provider = normalizeProviderId(entry.provider);
const model = entry.id?.trim();
if (!provider || !model) {
continue;
}
const key = `${provider}/${model}`;
if (seen.has(key)) {
continue;
}
seen.add(key);
out.push({ model, provider });
}
// Sort by provider preference first, then by model name
out.sort((a, b) => {
const providerOrder = compareProvidersForPicker(a.provider, b.provider);
if (providerOrder !== 0) {
return providerOrder;
}
return a.model.toLowerCase().localeCompare(b.model.toLowerCase());
});
return out;
}
export function resolveProviderEndpointLabel(
provider: string,
cfg: OpenClawConfig,
): { endpoint?: string; api?: string } {
const normalized = normalizeProviderId(provider);
const providers = (cfg.models?.providers ?? {}) as Record<
string,
{ baseUrl?: string; api?: string } | undefined
>;
const entry = providers[normalized];
const endpoint = entry?.baseUrl?.trim();
const api = entry?.api?.trim();
return {
endpoint: endpoint || undefined,
api: api || undefined,
};
}