diff --git a/src/features/providers/sheets/forms/BaseProviderForm.tsx b/src/features/providers/sheets/forms/BaseProviderForm.tsx index 8290634..b025e70 100644 --- a/src/features/providers/sheets/forms/BaseProviderForm.tsx +++ b/src/features/providers/sheets/forms/BaseProviderForm.tsx @@ -226,6 +226,13 @@ export function BaseProviderForm({ return (resource.raw as { apiKey?: string } | undefined)?.apiKey ?? ''; }, [brand, mode, resource]); + const fallbackAuthIndex = useMemo(() => { + if (mode !== 'edit' || !resource) return ''; + return ( + (resource.raw as { authIndex?: string } | undefined)?.authIndex ?? '' + ); + }, [mode, resource]); + const connectivityMessages = useMemo( () => ({ baseUrlRequired: t('providersPage.connectivity.baseUrlRequired'), @@ -249,6 +256,7 @@ export function BaseProviderForm({ apiKeyEntries: form.apiKeyEntries, apiKey: form.apiKey, fallbackApiKey, + authIndex: fallbackAuthIndex, }, connectivityMessages ); @@ -260,6 +268,7 @@ export function BaseProviderForm({ apiKeyEntries: form.apiKeyEntries, apiKey: form.apiKey, fallbackApiKey, + authIndex: fallbackAuthIndex, }); const [discoveryOpen, setDiscoveryOpen] = useState(false); diff --git a/src/features/providers/sheets/forms/useConnectivityTest.ts b/src/features/providers/sheets/forms/useConnectivityTest.ts index 900802c..b8c2f8d 100644 --- a/src/features/providers/sheets/forms/useConnectivityTest.ts +++ b/src/features/providers/sheets/forms/useConnectivityTest.ts @@ -77,6 +77,7 @@ export interface UseConnectivityTestArgs { apiKeyEntries?: ApiKeyEntryInput[]; apiKey?: string; fallbackApiKey?: string; + authIndex?: string; } export interface ConnectivityErrorMessages { @@ -110,6 +111,7 @@ export function useConnectivityTest( apiKeyEntries, apiKey, fallbackApiKey, + authIndex, } = args; const entriesCount = apiKeyEntries?.length ?? 0; @@ -302,8 +304,9 @@ export function useConnectivityTest( const headerKey = resolveBearerToken(customHeaders); const hasApiKeyHeader = hasHeader(customHeaders, 'x-api-key'); const resolvedKey = explicitKey || persistedKey || headerKey; + const resolvedAuthIndex = (authIndex ?? '').trim() || undefined; - if (!resolvedKey && !hasApiKeyHeader) { + if (!resolvedKey && !hasApiKeyHeader && !resolvedAuthIndex) { setClaudeStatus({ state: 'error', message: messages.apiKeyRequired }); return; } @@ -324,6 +327,7 @@ export function useConnectivityTest( try { const result = await apiCallApi.request( { + authIndex: resolvedAuthIndex, method: 'POST', url: endpoint, header: headerObj, @@ -358,6 +362,7 @@ export function useConnectivityTest( } }, [ apiKey, + authIndex, baseUrl, brand, fallbackApiKey, diff --git a/src/features/providers/sheets/forms/useModelDiscovery.ts b/src/features/providers/sheets/forms/useModelDiscovery.ts index 5014b7c..874b5cb 100644 --- a/src/features/providers/sheets/forms/useModelDiscovery.ts +++ b/src/features/providers/sheets/forms/useModelDiscovery.ts @@ -44,6 +44,7 @@ export interface UseModelDiscoveryArgs { apiKeyEntries?: ApiKeyEntryInput[]; apiKey?: string; fallbackApiKey?: string; + authIndex?: string; } export interface UseModelDiscoveryResult { @@ -59,8 +60,15 @@ export interface UseModelDiscoveryResult { export function useModelDiscovery( args: UseModelDiscoveryArgs ): UseModelDiscoveryResult { - const { brand, baseUrl, formHeaders, apiKeyEntries, apiKey, fallbackApiKey } = - args; + const { + brand, + baseUrl, + formHeaders, + apiKeyEntries, + apiKey, + fallbackApiKey, + authIndex, + } = args; const available = isModelDiscoveryBrand(brand); const [loading, setLoading] = useState(false); @@ -74,27 +82,31 @@ export function useModelDiscovery( setError(null); try { const baseHeaders = buildHeaderObject(formHeaders); + const resolvedAuthIndex = (authIndex ?? '').trim() || undefined; let next: ModelInfo[] = []; if (brand === 'gemini') { const key = (apiKey ?? '').trim() || (fallbackApiKey ?? '').trim(); next = await modelsApi.fetchGeminiModelsViaApiCall( baseUrl, key, - baseHeaders + baseHeaders, + resolvedAuthIndex ); } else if (brand === 'codex') { const key = (apiKey ?? '').trim() || (fallbackApiKey ?? '').trim(); next = await modelsApi.fetchV1ModelsViaApiCall( baseUrl, key, - baseHeaders + baseHeaders, + resolvedAuthIndex ); } else if (brand === 'claude') { const key = (apiKey ?? '').trim() || (fallbackApiKey ?? '').trim(); next = await modelsApi.fetchClaudeModelsViaApiCall( baseUrl, key, - baseHeaders + baseHeaders, + resolvedAuthIndex ); } else if (brand === 'openaiCompatibility') { const firstEntry = (apiKeyEntries ?? []).find((e) => @@ -129,7 +141,16 @@ export function useModelDiscovery( } finally { setLoading(false); } - }, [available, apiKey, apiKeyEntries, baseUrl, brand, fallbackApiKey, formHeaders]); + }, [ + available, + apiKey, + apiKeyEntries, + authIndex, + baseUrl, + brand, + fallbackApiKey, + formHeaders, + ]); const reset = useCallback(() => { setModels([]); diff --git a/src/services/api/models.ts b/src/services/api/models.ts index b18886d..9977d5b 100644 --- a/src/services/api/models.ts +++ b/src/services/api/models.ts @@ -108,7 +108,8 @@ export const modelsApi = { async fetchV1ModelsViaApiCall( baseUrl: string, apiKey?: string, - headers: Record = {} + headers: Record = {}, + authIndex?: string ) { const endpoint = buildV1ModelsEndpoint(baseUrl); if (!endpoint) { @@ -121,6 +122,7 @@ export const modelsApi = { } const result = await apiCallApi.request({ + authIndex: authIndex?.trim() || undefined, method: 'GET', url: endpoint, header: Object.keys(resolvedHeaders).length ? resolvedHeaders : undefined @@ -140,7 +142,8 @@ export const modelsApi = { async fetchModelsViaApiCall( baseUrl: string, apiKey?: string, - headers: Record = {} + headers: Record = {}, + authIndex?: string ) { const endpoint = buildModelsEndpoint(baseUrl); if (!endpoint) { @@ -153,6 +156,7 @@ export const modelsApi = { } const result = await apiCallApi.request({ + authIndex: authIndex?.trim() || undefined, method: 'GET', url: endpoint, header: Object.keys(resolvedHeaders).length ? resolvedHeaders : undefined @@ -185,7 +189,8 @@ export const modelsApi = { async fetchClaudeModelsViaApiCall( baseUrl: string, apiKey?: string, - headers: Record = {} + headers: Record = {}, + authIndex?: string ) { const endpoint = buildClaudeModelsEndpoint(baseUrl); if (!endpoint) { @@ -205,12 +210,14 @@ export const modelsApi = { resolvedHeaders['anthropic-version'] = DEFAULT_ANTHROPIC_VERSION; } + const trimmedAuthIndex = authIndex?.trim() || undefined; const signature = buildRequestSignature(endpoint, resolvedHeaders); const existing = CLAUDE_MODELS_IN_FLIGHT.get(signature); if (existing) return existing; const request = (async () => { const result = await apiCallApi.request({ + authIndex: trimmedAuthIndex, method: 'GET', url: endpoint, header: Object.keys(resolvedHeaders).length ? resolvedHeaders : undefined @@ -239,7 +246,8 @@ export const modelsApi = { async fetchGeminiModelsViaApiCall( baseUrl: string, apiKey?: string, - headers: Record = {} + headers: Record = {}, + authIndex?: string ) { const endpoint = buildGeminiModelsEndpoint(baseUrl); if (!endpoint) { @@ -252,6 +260,7 @@ export const modelsApi = { resolvedHeaders['x-goog-api-key'] = resolvedApiKey; } + const trimmedAuthIndex = authIndex?.trim() || undefined; const signature = buildRequestSignature(endpoint, resolvedHeaders); const existing = GEMINI_MODELS_IN_FLIGHT.get(signature); if (existing) return existing; @@ -268,6 +277,7 @@ export const modelsApi = { } const result = await apiCallApi.request({ + authIndex: trimmedAuthIndex, method: 'GET', url: url.toString(), header: Object.keys(resolvedHeaders).length ? resolvedHeaders : undefined