diff --git a/src/config/inference-sources.ts b/src/config/inference-sources.ts index 0e5304e5f..6a24c8457 100644 --- a/src/config/inference-sources.ts +++ b/src/config/inference-sources.ts @@ -14,7 +14,11 @@ import { OPENAI_API_BASE_URL, firstClassProviderById, } from "../../packages/first-class-providers/src/index.js"; -import { normalizeOpenAICompatibleBaseURL, type Settings } from "./settings.js"; +import { + normalizeOpenAICompatibleBaseURL, + type ProviderSettings, + type Settings, +} from "./settings.js"; import { resolveSessionEffort, type ReasoningEffort, @@ -43,6 +47,19 @@ function catalogEntry( return catalog.find((e) => e.name === provider); } +// Resolve the API key to send for a provider: the catalog entry wins, then +// the operator's settings row, else the field is omitted entirely. +function apiKeyFor( + entry: ProviderCatalogEntry | undefined, + providerSettings: ProviderSettings | undefined, +): { apiKey: string } | Record { + return entry?.apiKey !== undefined + ? { apiKey: entry.apiKey } + : providerSettings?.apiKey !== undefined + ? { apiKey: providerSettings.apiKey } + : {}; +} + // First-party OpenAI reasoning models reject `max_tokens` and require // `max_completion_tokens`. The requirement is declared per model on the // first-class OpenAI API-key path's `maxCompletionTokensModels` field — never @@ -129,11 +146,7 @@ export function buildInferenceSourceForRef( ) { return buildGoSource({ id: ref.provider, - ...(entry?.apiKey !== undefined - ? { apiKey: entry.apiKey } - : providerSettings?.apiKey !== undefined - ? { apiKey: providerSettings.apiKey } - : {}), + ...apiKeyFor(entry, providerSettings), model: ref.model, sessionId: ctx.sessionId, ...(effort !== undefined ? { reasoningEffort: effort } : {}), @@ -147,11 +160,7 @@ export function buildInferenceSourceForRef( ) { return buildZenSource({ id: ref.provider, - ...(entry?.apiKey !== undefined - ? { apiKey: entry.apiKey } - : providerSettings?.apiKey !== undefined - ? { apiKey: providerSettings.apiKey } - : {}), + ...apiKeyFor(entry, providerSettings), model: ref.model, sessionId: ctx.sessionId, ...(effort !== undefined ? { reasoningEffort: effort } : {}), @@ -161,11 +170,7 @@ export function buildInferenceSourceForRef( return buildAnthropicSource({ id: ref.provider, baseURL, - ...(entry?.apiKey !== undefined - ? { apiKey: entry.apiKey } - : providerSettings?.apiKey !== undefined - ? { apiKey: providerSettings.apiKey } - : {}), + ...apiKeyFor(entry, providerSettings), model: ref.model, }); } @@ -173,11 +178,7 @@ export function buildInferenceSourceForRef( return buildBifrostSource({ id: ref.provider, baseURL, - ...(entry?.apiKey !== undefined - ? { apiKey: entry.apiKey } - : providerSettings?.apiKey !== undefined - ? { apiKey: providerSettings.apiKey } - : {}), + ...apiKeyFor(entry, providerSettings), model: ref.model, ...(effort !== undefined ? { reasoningEffort: effort } : {}), }); @@ -210,11 +211,7 @@ export function buildInferenceSourceForRef( return buildOpenAISource({ id: ref.provider, baseURL, - ...(entry?.apiKey !== undefined - ? { apiKey: entry.apiKey } - : providerSettings?.apiKey !== undefined - ? { apiKey: providerSettings.apiKey } - : {}), + ...apiKeyFor(entry, providerSettings), model: ref.model, ...(customEffort !== undefined ? { reasoningEffort: customEffort } : {}), ...(maxTokens !== undefined ? { maxTokens } : {}),