Files
oh-my-pi/packages/coding-agent/src/commit/model-selection.ts
T
can1357 5277e44139 feat(coding-agent): added canonical aliases for model role resolution
- Added canonical model equivalence types, cache helpers, and registry APIs for provider variant lookup.
- Changed model resolution to apply canonical ID overrides/excludes with provider order before fallback matching.
- Added canonical and provider model views in list-models and selector UI with canonical sorting/persistence.
- Updated role/model persistence to store selectors while runtime now resolves concrete canonical-backed provider models.
2026-04-11 08:28:50 +02:00

67 lines
2.4 KiB
TypeScript

import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
import type { Api, Model } from "@oh-my-pi/pi-ai";
import { MODEL_ROLE_IDS } from "../config/model-registry";
import {
type ModelLookupRegistry,
parseModelPattern,
resolveModelRoleValue,
resolveRoleSelection,
} from "../config/model-resolver";
import type { Settings } from "../config/settings";
import MODEL_PRIO from "../priority.json" with { type: "json" };
export interface ResolvedCommitModel {
model: Model<Api>;
apiKey: string;
thinkingLevel?: ThinkingLevel;
}
type CommitModelRegistry = ModelLookupRegistry & {
getApiKey: (model: Model<Api>) => Promise<string | undefined>;
};
export async function resolvePrimaryModel(
override: string | undefined,
settings: Settings,
modelRegistry: CommitModelRegistry,
): Promise<ResolvedCommitModel> {
const available = modelRegistry.getAvailable();
const matchPreferences = { usageOrder: settings.getStorage()?.getModelUsageOrder() };
const resolved = override
? resolveModelRoleValue(override, available, { settings, matchPreferences, modelRegistry })
: resolveRoleSelection(["commit", "smol", ...MODEL_ROLE_IDS], settings, available, modelRegistry);
const model = resolved?.model;
if (!model) {
throw new Error("No model available for commit generation");
}
const apiKey = await modelRegistry.getApiKey(model);
if (!apiKey) {
throw new Error(`No API key available for model ${model.provider}/${model.id}`);
}
return { model, apiKey, thinkingLevel: resolved?.thinkingLevel };
}
export async function resolveSmolModel(
settings: Settings,
modelRegistry: CommitModelRegistry,
fallbackModel: Model<Api>,
fallbackApiKey: string,
): Promise<ResolvedCommitModel> {
const available = modelRegistry.getAvailable();
const resolvedSmol = resolveRoleSelection(["smol"], settings, available, modelRegistry);
if (resolvedSmol?.model) {
const apiKey = await modelRegistry.getApiKey(resolvedSmol.model);
if (apiKey) return { model: resolvedSmol.model, apiKey, thinkingLevel: resolvedSmol.thinkingLevel };
}
const matchPreferences = { usageOrder: settings.getStorage()?.getModelUsageOrder() };
for (const pattern of MODEL_PRIO.smol) {
const candidate = parseModelPattern(pattern, available, matchPreferences, { modelRegistry }).model;
if (!candidate) continue;
const apiKey = await modelRegistry.getApiKey(candidate);
if (apiKey) return { model: candidate, apiKey };
}
return { model: fallbackModel, apiKey: fallbackApiKey };
}