fix: strip Provider/ prefix from model name before sending to ai-gateway

Bug evidence from request_logs.sqlite:

  request body:    {"model":"NebulaCoder/nebulacoder-cot-v8.0", ...}
  response body:   {"error":{"message":"All target providers failed.",
                    "attempts":[
                      {"provider":"openai","provider_name":"provider-nebulacoder-ee070b8656",
                       "stage":"model_resolution",
                       "message":"Model "NebulaCoder/nebulacoder-cot-v8.0" is not configured
                                  for target provider openai.
                                  Allowed models: nebulacoder-v8.0, nebulacoder-cot-v8.0."}
                    ]}}

Root cause: prepareUpstreamCredentialAttempt has a !target branch that uses:
  bodyHasConfiguredProviderModelSelector(input.attempt.body, input.config)
    ? input.attempt.body          ← original body with "NebulaCoder/" prefix
    : normalizedBody?.body ...    ← correctly stripped

When the body parses successfully, it prefers the original body with the
Provider/ prefix. This prefixed model name reaches ai-gateway which only
knows bare model names, causing a 400.

Fix: always use normalizedBody.body (which strips the Provider/ prefix)
when available. Remove the now-unused bodyHasConfiguredProviderModelSelector.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
810senpai114514
2026-07-14 13:33:57 +08:00
parent e9f59c5425
commit b8a56a1efa
@@ -374,9 +374,7 @@ function prepareUpstreamCredentialAttempt(input: {
target
});
if (!target) {
const body = bodyHasConfiguredProviderModelSelector(input.attempt.body, input.config)
? input.attempt.body
: normalizedBody?.body ?? input.attempt.body;
const body = normalizedBody?.body ?? input.attempt.body;
return {
...input.attempt,
body: attemptBody(body),
@@ -620,11 +618,6 @@ function normalizeConfiguredProviderModelBody(
}
function bodyHasConfiguredProviderModelSelector(body: Buffer | undefined, config: AppConfig): boolean {
const parsedBody = parseJsonObjectSafe(body);
const model = stringValue(parsedBody?.model);
return Boolean(resolveConfiguredProviderModelSelector(model, config));
}
function resolveProviderCredentialRoutingTarget(