fix(gateway): preserve local oauth provider base url

Runtime identity normalization previously ran before local OAuth provider
detection, so display-name matching could no longer select the managed
backend endpoint. Defer identity normalization until after detection and
cover the ordering with a regression test.
This commit is contained in:
camjac251
2026-07-15 14:52:57 -04:00
parent 24e52a64f3
commit 16a53bb3a9
2 changed files with 38 additions and 11 deletions
@@ -40,20 +40,16 @@ export async function compileCoreGatewayConfig(
)
: [];
const pluginBillingConfig = isRecord(pluginCoreGatewayConfig.billing) ? pluginCoreGatewayConfig.billing : {};
const configuredProviderPlugins = normalizeClaudeCodeOauthProviderPlugins(
normalizeCoreProviderPluginNames(
[
...(config.providerPlugins ?? []).filter(providerPluginEnabled),
...pluginService.getCoreProviderPlugins().filter(providerPluginEnabled)
],
config.Providers
)
);
const providerPlugins = await withKimiOauthRuntimeDefaults(
const configuredProviderPlugins = normalizeClaudeCodeOauthProviderPlugins([
...(config.providerPlugins ?? []).filter(providerPluginEnabled),
...pluginService.getCoreProviderPlugins().filter(providerPluginEnabled)
]);
const providerPluginsWithRuntimeDefaults = await withKimiOauthRuntimeDefaults(
await withGrokOauthRuntimeDefaults(withCodexOauthRuntimeDefaults(configuredProviderPlugins))
);
const codexOauthProviderNames = codexOauthLocalProviderNames(providerPluginsWithRuntimeDefaults);
const providerPlugins = normalizeCoreProviderPluginNames(providerPluginsWithRuntimeDefaults, config.Providers);
const providerPluginsWithCapabilityAliases = withProviderCapabilityPluginAliases(providerPlugins, config.Providers);
const codexOauthProviderNames = codexOauthLocalProviderNames(providerPlugins);
const virtualModelProfiles = coreGatewayVirtualModelProfiles(config);
const coreEndpoint = endpoint(config.gateway.coreHost, config.gateway.corePort);
const proxyPreloadFile = upstreamProxyUrl ? writeGatewayProxyPreloadFile(config, upstreamProxyUrl) : undefined;
@@ -1,5 +1,6 @@
import assert from "node:assert/strict";
import test from "node:test";
import { codexDefaultBaseUrl } from "@ccr/core/agents/local-providers/service.ts";
import { createDefaultAppConfig } from "@ccr/core/config/default-config.ts";
import { compileCoreGatewayConfig } from "@ccr/core/gateway/core-runtime/config-compiler.ts";
import { prepareGatewayUpstreamAttemptForTest } from "@ccr/core/gateway/upstream/executor.ts";
@@ -62,6 +63,36 @@ test("provider plugins use compiled runtime and capability identities", async ()
assert.equal(unscopedPlugin, unchangedPlugin);
});
test("Codex OAuth plugins retain the default base URL after runtime identity normalization", async () => {
const config = createDefaultAppConfig({ generatedConfigFile: "/tmp/ccr-codex-oauth-runtime-identity.json" });
config.providerPlugins = [
{
codexOauth: {},
key: "ccr-local-agent-codex-api-codex-oauth",
providerName: "Codex API"
}
];
config.Providers = [
{
api_base_url: "https://configured.example.test/v1",
id: "codex-api",
models: ["gpt-5-codex"],
name: "Codex API",
type: "openai_responses"
}
];
const compiled = await compileCoreGatewayConfig(
config,
"raw-trace-token",
"billing-usage-token",
"core-auth-token"
);
assert.equal(compiled.providerPlugins[0].providerName, "codex-api");
assert.equal(compiled.providers[0].baseurl, codexDefaultBaseUrl);
});
test("credential-free fallback headers use the provider runtime identity", () => {
const provider = {
api_base_url: "https://api.example.test",