agent-ecosystem/src/shared/utils/opencodeModelRef.ts
2026-05-20 13:03:24 +03:00

89 lines
2 KiB
TypeScript

export interface OpenCodeQualifiedModelRef {
sourceId: string;
modelId: string;
raw: string;
}
const OPEN_CODE_SOURCE_ID_PATTERN = /^[a-z0-9._-]+$/i;
const OPEN_CODE_SOURCE_LABELS: Record<string, string> = {
anthropic: 'Anthropic',
azure: 'Azure',
bedrock: 'Bedrock',
deepseek: 'DeepSeek',
gemini: 'Gemini',
google: 'Google',
groq: 'Groq',
'llama.cpp': 'llama.cpp',
llamacpp: 'llama.cpp',
lmstudio: 'LM Studio',
'lm-studio': 'LM Studio',
minimax: 'MiniMax',
mistral: 'Mistral',
moonshot: 'Moonshot',
ollama: 'Ollama',
opencode: 'OpenCode',
openai: 'OpenAI',
'openai-compatible': 'OpenAI Compatible',
openrouter: 'OpenRouter',
together: 'Together',
vertex: 'Vertex',
vllm: 'vLLM',
xai: 'xAI',
'z-ai': 'Z.AI',
};
function humanizeOpenCodeSourceId(sourceId: string): string {
const normalized = sourceId.trim().toLowerCase();
if (!normalized) {
return sourceId;
}
const knownLabel = OPEN_CODE_SOURCE_LABELS[normalized];
if (knownLabel) {
return knownLabel;
}
return normalized
.split(/[-._]/g)
.filter(Boolean)
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
.join(' ');
}
export function parseOpenCodeQualifiedModelRef(
model: string | undefined | null
): OpenCodeQualifiedModelRef | null {
const trimmed = model?.trim();
if (!trimmed || /\s/.test(trimmed)) {
return null;
}
const separatorIndex = trimmed.indexOf('/');
if (separatorIndex <= 0 || separatorIndex >= trimmed.length - 1) {
return null;
}
const sourceId = trimmed.slice(0, separatorIndex).toLowerCase();
const modelId = trimmed.slice(separatorIndex + 1);
if (!OPEN_CODE_SOURCE_ID_PATTERN.test(sourceId) || !modelId) {
return null;
}
return {
raw: `${sourceId}/${modelId}`,
sourceId,
modelId,
};
}
export function getOpenCodeQualifiedModelSourceLabel(
model: string | undefined | null
): string | null {
const parsed = parseOpenCodeQualifiedModelRef(model);
if (!parsed) {
return null;
}
return humanizeOpenCodeSourceId(parsed.sourceId);
}