Agents: break model-selection provider cycle

This commit is contained in:
Alex Alaniz 2026-03-13 03:00:41 -04:00
parent 12ad809e79
commit f30d0df52b
3 changed files with 70 additions and 8 deletions

View File

@ -1,5 +1,5 @@
// Keep model ID normalization dependency-free so config parsing and other
// startup-only paths do not pull in provider discovery or plugin loading.
// Keep these helpers dependency-free so config/model parsing can use them
// without pulling in provider discovery or auth-profile graphs.
export function normalizeGoogleModelId(id: string): string {
if (id === "gemini-3-pro") {
return "gemini-3-pro-preview";

View File

@ -16,12 +16,6 @@ import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "./defaults.js";
import type { ModelCatalogEntry } from "./model-catalog.js";
import { normalizeGoogleModelId } from "./model-id-normalization.js";
import { splitTrailingAuthProfile } from "./model-ref-profile.js";
import {
findNormalizedProviderKey,
findNormalizedProviderValue,
normalizeProviderId,
normalizeProviderIdForAuth,
} from "./provider-id.js";
const log = createSubsystemLogger("model-selection");
@ -41,6 +35,72 @@ function normalizeAliasKey(value: string): string {
return value.trim().toLowerCase();
}
export function normalizeProviderId(provider: string): string {
const normalized = provider.trim().toLowerCase();
if (normalized === "z.ai" || normalized === "z-ai") {
return "zai";
}
if (normalized === "opencode-zen") {
return "opencode";
}
if (normalized === "opencode-go-auth") {
return "opencode-go";
}
if (normalized === "qwen") {
return "qwen-portal";
}
if (normalized === "kimi" || normalized === "kimi-code" || normalized === "kimi-coding") {
return "kimi";
}
if (normalized === "bedrock" || normalized === "aws-bedrock") {
return "amazon-bedrock";
}
// Backward compatibility for older provider naming.
if (normalized === "bytedance" || normalized === "doubao") {
return "volcengine";
}
return normalized;
}
/** Normalize provider ID for auth lookup. Coding-plan variants share auth with base. */
export function normalizeProviderIdForAuth(provider: string): string {
const normalized = normalizeProviderId(provider);
if (normalized === "volcengine-plan") {
return "volcengine";
}
if (normalized === "byteplus-plan") {
return "byteplus";
}
return normalized;
}
export function findNormalizedProviderValue<T>(
entries: Record<string, T> | undefined,
provider: string,
): T | undefined {
if (!entries) {
return undefined;
}
const providerKey = normalizeProviderId(provider);
for (const [key, value] of Object.entries(entries)) {
if (normalizeProviderId(key) === providerKey) {
return value;
}
}
return undefined;
}
export function findNormalizedProviderKey(
entries: Record<string, unknown> | undefined,
provider: string,
): string | undefined {
if (!entries) {
return undefined;
}
const providerKey = normalizeProviderId(provider);
return Object.keys(entries).find((key) => normalizeProviderId(key) === providerKey);
}
export function modelKey(provider: string, model: string) {
const providerId = provider.trim();
const modelId = model.trim();

View File

@ -182,6 +182,8 @@ type ProfileApiKeyResolution = {
discoveryApiKey?: string;
};
export { normalizeGoogleModelId };
function toDiscoveryApiKey(value: string | undefined): string | undefined {
const trimmed = value?.trim();
if (!trimmed || isNonSecretApiKeyMarker(trimmed)) {