diff --git a/containers/api-proxy/providers/anthropic.js b/containers/api-proxy/providers/anthropic.js index b7f7d73a..1c482eab 100644 --- a/containers/api-proxy/providers/anthropic.js +++ b/containers/api-proxy/providers/anthropic.js @@ -11,7 +11,7 @@ * Body transforms: model alias rewriting + optional prompt-cache optimisations */ -const { normalizeApiTarget, normalizeBasePath, composeBodyTransforms } = require('../proxy-utils'); +const { composeBodyTransforms, createBaseAdapterConfig } = require('../proxy-utils'); let makeAnthropicTransform, loadCustomTransform, EXTENDED_CACHE_BETA; try { @@ -34,9 +34,12 @@ try { * @returns {import('./index').ProviderAdapter} */ function createAnthropicAdapter(env, deps = {}) { - const apiKey = (env.ANTHROPIC_API_KEY || '').trim() || undefined; - const rawTarget = normalizeApiTarget(env.ANTHROPIC_API_TARGET) || 'api.anthropic.com'; - const basePath = normalizeBasePath(env.ANTHROPIC_API_BASE_PATH); + const { apiKey, rawTarget, basePath } = createBaseAdapterConfig(env, { + keyEnvVar: 'ANTHROPIC_API_KEY', + targetEnvVar: 'ANTHROPIC_API_TARGET', + basePathEnvVar: 'ANTHROPIC_API_BASE_PATH', + defaultTarget: 'api.anthropic.com', + }); // ── Anthropic-specific optimisations ────────────────────────────────────── const autoCache = (env.AWF_ANTHROPIC_AUTO_CACHE === '1' || env.AWF_ANTHROPIC_AUTO_CACHE === 'true'); diff --git a/containers/api-proxy/providers/gemini.js b/containers/api-proxy/providers/gemini.js index 344de5e5..b08763a7 100644 --- a/containers/api-proxy/providers/gemini.js +++ b/containers/api-proxy/providers/gemini.js @@ -13,7 +13,7 @@ * Gemini SDK versions append alongside the header. */ -const { normalizeApiTarget, normalizeBasePath, stripGeminiKeyParam } = require('../proxy-utils'); +const { stripGeminiKeyParam, createBaseAdapterConfig } = require('../proxy-utils'); /** * Create the Google Gemini provider adapter. @@ -23,9 +23,12 @@ const { normalizeApiTarget, normalizeBasePath, stripGeminiKeyParam } = require(' * @returns {import('./index').ProviderAdapter} */ function createGeminiAdapter(env, deps = {}) { - const apiKey = (env.GEMINI_API_KEY || '').trim() || undefined; - const rawTarget = normalizeApiTarget(env.GEMINI_API_TARGET) || 'generativelanguage.googleapis.com'; - const basePath = normalizeBasePath(env.GEMINI_API_BASE_PATH); + const { apiKey, rawTarget, basePath } = createBaseAdapterConfig(env, { + keyEnvVar: 'GEMINI_API_KEY', + targetEnvVar: 'GEMINI_API_TARGET', + basePathEnvVar: 'GEMINI_API_BASE_PATH', + defaultTarget: 'generativelanguage.googleapis.com', + }); const bodyTransform = deps.bodyTransform || null; diff --git a/containers/api-proxy/providers/openai.js b/containers/api-proxy/providers/openai.js index 6332de8d..8df7bac9 100644 --- a/containers/api-proxy/providers/openai.js +++ b/containers/api-proxy/providers/openai.js @@ -10,7 +10,7 @@ * Base path: OPENAI_API_BASE_PATH (default: /v1 for the public endpoint) */ -const { normalizeApiTarget, normalizeBasePath } = require('../proxy-utils'); +const { createBaseAdapterConfig } = require('../proxy-utils'); /** * Create the OpenAI provider adapter. @@ -20,9 +20,12 @@ const { normalizeApiTarget, normalizeBasePath } = require('../proxy-utils'); * @returns {import('./index').ProviderAdapter} */ function createOpenAIAdapter(env, deps = {}) { - const apiKey = (env.OPENAI_API_KEY || '').trim() || undefined; - const rawTarget = normalizeApiTarget(env.OPENAI_API_TARGET) || 'api.openai.com'; - const explicitBasePath = normalizeBasePath(env.OPENAI_API_BASE_PATH); + const { apiKey, rawTarget, basePath: explicitBasePath } = createBaseAdapterConfig(env, { + keyEnvVar: 'OPENAI_API_KEY', + targetEnvVar: 'OPENAI_API_TARGET', + basePathEnvVar: 'OPENAI_API_BASE_PATH', + defaultTarget: 'api.openai.com', + }); // For the default OpenAI endpoint, unversioned clients (e.g. Codex CLI sending // /responses) need a /v1 prefix to reach the correct versioned API surface. diff --git a/containers/api-proxy/proxy-utils.js b/containers/api-proxy/proxy-utils.js index afd94553..c511c105 100644 --- a/containers/api-proxy/proxy-utils.js +++ b/containers/api-proxy/proxy-utils.js @@ -170,6 +170,29 @@ function composeBodyTransforms(first, second) { }; } +/** + * Extract common adapter configuration from environment variables. + * + * Every non-Copilot adapter repeats the same three-line pattern to read + * an API key, normalize a target hostname, and normalize a base path. + * This helper centralizes that logic so each adapter only specifies env + * var names and a default target. + * + * @param {Record} env - Environment variables + * @param {object} opts + * @param {string} opts.keyEnvVar - e.g. 'OPENAI_API_KEY' + * @param {string} opts.targetEnvVar - e.g. 'OPENAI_API_TARGET' + * @param {string} opts.basePathEnvVar - e.g. 'OPENAI_API_BASE_PATH' + * @param {string} opts.defaultTarget - e.g. 'api.openai.com' + * @returns {{ apiKey: string|undefined, rawTarget: string, basePath: string }} + */ +function createBaseAdapterConfig(env, { keyEnvVar, targetEnvVar, basePathEnvVar, defaultTarget }) { + const apiKey = (env[keyEnvVar] || '').trim() || undefined; + const rawTarget = normalizeApiTarget(env[targetEnvVar]) || defaultTarget; + const basePath = normalizeBasePath(env[basePathEnvVar]); + return { apiKey, rawTarget, basePath }; +} + module.exports = { normalizeApiTarget, normalizeBasePath, @@ -177,4 +200,5 @@ module.exports = { stripGeminiKeyParam, shouldStripHeader, composeBodyTransforms, + createBaseAdapterConfig, };