fix: combo credential resolution ignores target.providerId — prefer combo target's providerId over model-inferred provider

Root cause: model string provider prefix (e.g. "xiaomi" from
"xiaomi/mimo-v2-flash") differs from the credential DB provider ID
(e.g. "opengate") when a combo target has a custom providerId. The
pre-selection and execution flows both looked up credentials using the
model-inferred provider, which didn't match any DB entry.

Fix A (chat.ts): checkModelAvailable now uses target.providerId when
available, falling back to modelInfo.provider.

Fix B (chat.ts): handleSingleModelChat now accepts runtimeOptions.providerId
and preferentially uses it for credential lookup instead of re-resolving
the provider from the model string.

Fix C (model.ts): add "xiaomi" alias for "xiaomi-mimo" so direct
(non-combo) model requests to xiaomi/mimo-* also resolve correctly.
This commit is contained in:
oyi77
2026-05-30 22:06:02 +07:00
parent 53c8ffcc34
commit d698e957fb
2 changed files with 24 additions and 3 deletions

View File

@@ -38,6 +38,10 @@ ALIAS_TO_PROVIDER_ID["opencode"] = "opencode-zen";
// OpenCode's Zen provider now uses the "opencode" slug, but OmniRoute registers
// it as "opencode-zen". This alias ensures `opencode/<model>` resolves correctly.
ALIAS_TO_PROVIDER_ID["opencode"] = "opencode-zen";
// xiaomi/ is the user-visible prefix for MiMo models; register it so
// parseModel("xiaomi/mimo-v2-flash") resolves provider = "xiaomi-mimo" instead
// of falling through to the identity fallback ("xiaomi").
ALIAS_TO_PROVIDER_ID["xiaomi"] = "xiaomi-mimo";
// Provider-scoped legacy model aliases. Used to normalize provider/model inputs
// and keep backward compatibility when upstream IDs change.

View File

@@ -448,13 +448,18 @@ export async function handleChat(request: any, clientRawRequest: any = null) {
connectionId?: string | null;
allowedConnectionIds?: string[] | null;
executionKey?: string | null;
providerId?: string | null;
}
) => {
if (isComboLiveTest) return true;
// Use getModelInfo to properly resolve custom prefixes
// Use getModelInfo to resolve custom prefixes, but prefer the combo
// target's providerId when available — the model string's provider
// prefix may differ from the credential provider ID (e.g. model
// "xiaomi/mimo-v2-flash" resolves to provider "xiaomi" but the combo
// target specifies providerId: "opengate" for credential lookup).
const modelInfo = await getModelInfo(modelString);
const provider = modelInfo.provider;
const provider = target?.providerId || modelInfo.provider;
if (!provider) return true; // can't determine provider, let it try
const resolvedModel = modelInfo.model || modelString;
@@ -510,6 +515,7 @@ export async function handleChat(request: any, clientRawRequest: any = null) {
stepId?: string | null;
allowedConnectionIds?: string[] | null;
failoverBeforeRetry?: boolean;
providerId?: string | null;
}
) =>
handleSingleModelChat(
@@ -534,6 +540,7 @@ export async function handleChat(request: any, clientRawRequest: any = null) {
getComboCredentialCacheKey(m, target)
),
cachedSettings: settings,
providerId: target?.providerId ?? null,
},
combo.strategy,
true
@@ -664,6 +671,7 @@ async function handleSingleModelChat(
allowRateLimitedConnection?: boolean;
preselectedCredentials?: any;
cachedSettings?: any;
providerId?: string | null;
} = {},
comboStrategy: string | null = null,
isCombo: boolean = false
@@ -695,6 +703,8 @@ async function handleSingleModelChat(
executionKey?: string | null;
stepId?: string | null;
failoverBeforeRetry?: boolean;
allowRateLimitedConnection?: boolean;
providerId?: string | null;
}
) =>
handleSingleModelChat(
@@ -713,6 +723,8 @@ async function handleSingleModelChat(
comboStepId: null,
comboExecutionKey: null,
skipUpstreamRetry: target?.failoverBeforeRetry ?? false,
allowRateLimitedConnection: target?.allowRateLimitedConnection === true,
providerId: target?.providerId ?? null,
},
redirectCombo.strategy ?? "priority",
false
@@ -726,7 +738,12 @@ async function handleSingleModelChat(
});
}
const { provider, model, sourceFormat, targetFormat, extendedContext, apiFormat } = resolved;
const { provider: resolvedProvider, model, sourceFormat, targetFormat, extendedContext, apiFormat } = resolved;
// Prefer the combo target's providerId when available — the model string's
// provider prefix may differ from the credential provider ID (e.g. model
// "xiaomi/mimo-v2-flash" resolves to provider "xiaomi" but the combo target
// may specify providerId: "opengate" for credential lookup).
const provider = runtimeOptions.providerId || resolvedProvider;
const forceLiveComboTest = runtimeOptions.forceLiveComboTest === true;
const hasForcedConnection =
typeof runtimeOptions.forcedConnectionId === "string" &&