Merge remote-tracking branch 'origin/master' into gitea/feature/end
Resolved conflicts taking origin/master (v0.5.55) as canonical, with local features re-applied: - runtime log level (LOG_LEVEL env + dashboard Settings → Logging, applied immediately and persisted across restarts) - free/noAuth provider enable/disable toggle via providerStrategies.enabled - parallel model testing (Test All Models / Test Selected Keys)
This commit is contained in:
@@ -2,9 +2,8 @@ import { PROVIDERS } from "./providers.js";
|
||||
import REGISTRY from "../providers/registry/index.js";
|
||||
// PROVIDER_MODELS now built from providers/registry (transport + models co-located)
|
||||
import { PROVIDER_MODELS } from "../providers/index.js";
|
||||
import { modelQuotaFamily, modelStrip, modelTargetFormat } from "../providers/models/schema.js";
|
||||
import { modelQuotaFamily, modelStrip, modelTargetFormat, modelSupportedFormats, normalizeModelId } from "../providers/models/schema.js";
|
||||
import { CODEX_REVIEW_SUFFIX } from "../providers/models/helpers.js";
|
||||
|
||||
export { PROVIDER_MODELS };
|
||||
|
||||
|
||||
@@ -18,46 +17,82 @@ export function getDefaultModel(aliasOrId) {
|
||||
return models?.[0]?.id || null;
|
||||
}
|
||||
|
||||
// Providers whose registry uses dots in version numbers (e.g. "claude-sonnet-4.5").
|
||||
// For these, we tolerate clients sending dashes ("claude-sonnet-4-5") by normalizing
|
||||
// digit-hyphen-digit to digit-dot-digit before lookup. Other providers are left untouched.
|
||||
const DOT_VERSION_PROVIDERS = new Set(["kr", "kiro"]);
|
||||
|
||||
// Find a registry entry by id. For Kiro models, tolerates dash/dot version separators
|
||||
// ("claude-sonnet-4-5" ~= "claude-sonnet-4.5"). Other providers use exact match only.
|
||||
function findModel(models, modelId, aliasOrId) {
|
||||
if (!models) return undefined;
|
||||
const found = models.find(m => m.id === modelId);
|
||||
if (found) return found;
|
||||
if (!DOT_VERSION_PROVIDERS.has(aliasOrId)) return undefined;
|
||||
const normalized = normalizeModelId(modelId);
|
||||
if (normalized === modelId) return undefined;
|
||||
return models.find(m => m.id === normalized);
|
||||
}
|
||||
|
||||
export function isValidModel(aliasOrId, modelId, passthroughProviders = new Set()) {
|
||||
if (passthroughProviders.has(aliasOrId)) return true;
|
||||
const models = PROVIDER_MODELS[aliasOrId];
|
||||
if (!models) return false;
|
||||
return models.some(m => m.id === modelId);
|
||||
return !!findModel(models, modelId, aliasOrId);
|
||||
}
|
||||
|
||||
export function findModelName(aliasOrId, modelId) {
|
||||
const models = PROVIDER_MODELS[aliasOrId];
|
||||
if (!models) return modelId;
|
||||
const found = models.find(m => m.id === modelId);
|
||||
const found = findModel(models, modelId, aliasOrId);
|
||||
return found?.name || modelId;
|
||||
}
|
||||
|
||||
export function getModelTargetFormat(aliasOrId, modelId) {
|
||||
const models = PROVIDER_MODELS[aliasOrId];
|
||||
if (!models) return null;
|
||||
return modelTargetFormat(models.find(m => m.id === modelId));
|
||||
return modelTargetFormat(findModel(models, modelId, aliasOrId));
|
||||
}
|
||||
|
||||
// Declared upstream formats for a model (registry `supportedFormats`). Drives the
|
||||
// per-model guard on the sourceFormat-matched transport; null when undeclared.
|
||||
export function getModelSupportedFormats(aliasOrId, modelId) {
|
||||
const models = PROVIDER_MODELS[aliasOrId];
|
||||
if (!models) return null;
|
||||
return modelSupportedFormats(findModel(models, modelId, aliasOrId));
|
||||
}
|
||||
|
||||
export function getModelType(aliasOrId, modelId) {
|
||||
const models = PROVIDER_MODELS[aliasOrId];
|
||||
if (!models) return null;
|
||||
const found = models.find(m => m.id === modelId);
|
||||
const found = findModel(models, modelId, aliasOrId);
|
||||
return found?.kind || found?.type || null;
|
||||
}
|
||||
|
||||
export function getModelUpstreamId(aliasOrId, modelId) {
|
||||
// Split off thinking suffix "(level)" so lookup hits the base id; re-append it to
|
||||
// the result so downstream applyThinking still sees the suffix (body.model is stripped separately).
|
||||
const sufMatch = typeof modelId === "string" ? modelId.match(/\([^()]+\)\s*$/) : null;
|
||||
const suffix = sufMatch ? sufMatch[0] : "";
|
||||
const baseId = suffix ? modelId.slice(0, sufMatch.index).trim() : modelId;
|
||||
const models = PROVIDER_MODELS[aliasOrId];
|
||||
const found = models?.find(m => m.id === modelId);
|
||||
if (found?.upstreamModelId) return found.upstreamModelId;
|
||||
if (aliasOrId === "cx" && typeof modelId === "string" && modelId.endsWith(CODEX_REVIEW_SUFFIX)) {
|
||||
return modelId.slice(0, -CODEX_REVIEW_SUFFIX.length);
|
||||
const found = findModel(models, baseId, aliasOrId);
|
||||
const resolvedId = found?.upstreamModelId || found?.id;
|
||||
if (resolvedId) {
|
||||
const presetMatch = resolvedId.match(/\([^()]+\)\s*$/);
|
||||
const presetSuffix = presetMatch?.[0] || "";
|
||||
const resolvedBase = presetSuffix ? resolvedId.slice(0, presetMatch.index).trim() : resolvedId;
|
||||
return resolvedBase + (suffix || presetSuffix);
|
||||
}
|
||||
return modelId;
|
||||
if (aliasOrId === "cx" && typeof baseId === "string" && baseId.endsWith(CODEX_REVIEW_SUFFIX)) {
|
||||
return baseId.slice(0, -CODEX_REVIEW_SUFFIX.length) + suffix;
|
||||
}
|
||||
return baseId + suffix;
|
||||
}
|
||||
|
||||
export function getModelQuotaFamily(aliasOrId, modelId) {
|
||||
const models = PROVIDER_MODELS[aliasOrId];
|
||||
return modelQuotaFamily(models?.find(m => m.id === modelId));
|
||||
return modelQuotaFamily(findModel(models, modelId, aliasOrId));
|
||||
}
|
||||
|
||||
// OAuth short aliases — derived from registry `alias` (single source). everything else: alias = id.
|
||||
@@ -79,5 +114,5 @@ export function getModelsByProviderId(providerId) {
|
||||
// Get strip list for a model entry (explicit opt-in only)
|
||||
// Returns array of content types to strip, e.g. ["image", "audio"]
|
||||
export function getModelStrip(alias, modelId) {
|
||||
return modelStrip(PROVIDER_MODELS[alias]?.find(m => m.id === modelId));
|
||||
return modelStrip(findModel(PROVIDER_MODELS[alias], modelId, alias));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user