mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-06-16 21:03:58 +08:00
fix(providers): remove per-key headers input for openai-compatibility
The backend OpenAICompatibilityAPIKey struct only has api-key and proxy-url (internal/config/config.go:570-577). PUT /openai-compatibility unmarshals into this struct (config_lists.go:439) and discards any unknown field, so per-entry headers submitted from the UI never persist and never reach the runtime request path. The GET response wrapper also has no headers field (config_auth_index.go:31-34). Drop the per-entry headers input from BaseProviderForm and the ApiKeyEntry/ApiKeyEntryInput types. Connectivity test and model discovery stop reading entry-level headers — they continue to apply provider-level headers, which is the supported contract.
This commit is contained in:
@@ -55,15 +55,8 @@ const emptyModel = (): ModelEntryInput => ({ name: '', alias: '' });
|
||||
const emptyApiKeyEntry = (): ApiKeyEntryInput => ({
|
||||
apiKey: '',
|
||||
proxyUrl: '',
|
||||
headersText: '',
|
||||
});
|
||||
|
||||
const headersObjectToText = (headers?: Record<string, string>): string =>
|
||||
Object.entries(headers ?? {})
|
||||
.filter(([k]) => k.trim())
|
||||
.map(([k, v]) => `${k}: ${v}`)
|
||||
.join('\n');
|
||||
|
||||
const stripDisableAllRule = (list?: string[]): string[] =>
|
||||
(list ?? []).filter((s) => s.trim() !== '*');
|
||||
|
||||
@@ -124,7 +117,6 @@ function buildInitialForm(
|
||||
? cfg.apiKeyEntries.map((entry) => ({
|
||||
apiKey: entry.apiKey,
|
||||
proxyUrl: entry.proxyUrl ?? '',
|
||||
headersText: headersObjectToText(entry.headers),
|
||||
authIndex: entry.authIndex,
|
||||
}))
|
||||
: [emptyApiKeyEntry()],
|
||||
@@ -823,30 +815,6 @@ export function BaseProviderForm({
|
||||
placeholder="http://127.0.0.1:7890"
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.field}>
|
||||
<label className={styles.label}>
|
||||
{t('providersPage.form.headers')}
|
||||
<span className={styles.labelHint}>
|
||||
{' '}
|
||||
· {t('providersPage.form.headersHint')}
|
||||
</span>
|
||||
</label>
|
||||
<textarea
|
||||
className={styles.textarea}
|
||||
value={entry.headersText}
|
||||
rows={3}
|
||||
onChange={(e) =>
|
||||
updateField(
|
||||
'apiKeyEntries',
|
||||
apiKeyEntries.map((it, i) =>
|
||||
i === realIdx ? { ...it, headersText: e.target.value } : it
|
||||
)
|
||||
)
|
||||
}
|
||||
disabled={mutating}
|
||||
placeholder="X-Custom-Header: value"
|
||||
/>
|
||||
</div>
|
||||
{status.state === 'error' ? (
|
||||
<div className={styles.connectivityError}>
|
||||
{status.message}
|
||||
|
||||
@@ -42,23 +42,6 @@ const pickModel = (
|
||||
return '';
|
||||
};
|
||||
|
||||
const parseHeadersText = (text: string): Record<string, string> => {
|
||||
const out: Record<string, string> = {};
|
||||
String(text ?? '')
|
||||
.split(/\n+/)
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean)
|
||||
.forEach((line) => {
|
||||
const sep = line.indexOf(':');
|
||||
if (sep <= 0) return;
|
||||
const key = line.slice(0, sep).trim();
|
||||
const value = line.slice(sep + 1).trim();
|
||||
if (!key) return;
|
||||
out[key] = value;
|
||||
});
|
||||
return out;
|
||||
};
|
||||
|
||||
const resolveBearerToken = (headers: Record<string, string>): string => {
|
||||
const auth = Object.entries(headers).find(
|
||||
([k]) => k.toLowerCase() === 'authorization'
|
||||
@@ -130,7 +113,6 @@ export function useConnectivityTest(
|
||||
entry.apiKey ?? '',
|
||||
entry.authIndex ?? '',
|
||||
entry.proxyUrl ?? '',
|
||||
entry.headersText ?? '',
|
||||
].join('||')
|
||||
),
|
||||
[apiKeyEntries]
|
||||
@@ -225,7 +207,6 @@ export function useConnectivityTest(
|
||||
const headerObj: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
...buildHeaderObject(formHeaders),
|
||||
...parseHeadersText(entry?.headersText ?? ''),
|
||||
};
|
||||
if (!hasHeader(headerObj, 'authorization')) {
|
||||
if (entryKey) {
|
||||
|
||||
@@ -14,23 +14,6 @@ export const MODEL_DISCOVERY_BRANDS: ReadonlyArray<ProviderBrand> = [
|
||||
export const isModelDiscoveryBrand = (brand: ProviderBrand): boolean =>
|
||||
MODEL_DISCOVERY_BRANDS.includes(brand);
|
||||
|
||||
const parseHeadersText = (text: string): Record<string, string> => {
|
||||
const out: Record<string, string> = {};
|
||||
String(text ?? '')
|
||||
.split(/\n+/)
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean)
|
||||
.forEach((line) => {
|
||||
const sep = line.indexOf(':');
|
||||
if (sep <= 0) return;
|
||||
const key = line.slice(0, sep).trim();
|
||||
const value = line.slice(sep + 1).trim();
|
||||
if (!key) return;
|
||||
out[key] = value;
|
||||
});
|
||||
return out;
|
||||
};
|
||||
|
||||
const toErrorMessage = (err: unknown): string => {
|
||||
if (err instanceof Error) return err.message;
|
||||
if (typeof err === 'string') return err;
|
||||
@@ -115,13 +98,11 @@ export function useModelDiscovery(
|
||||
const entryKey = (firstEntry?.apiKey ?? '').trim();
|
||||
const entryAuthIndex =
|
||||
(firstEntry?.authIndex ?? '').trim() || resolvedAuthIndex;
|
||||
const entryHeaders = parseHeadersText(firstEntry?.headersText ?? '');
|
||||
const headers = { ...baseHeaders, ...entryHeaders };
|
||||
try {
|
||||
next = await modelsApi.fetchModelsViaApiCall(
|
||||
baseUrl,
|
||||
entryKey,
|
||||
headers,
|
||||
baseHeaders,
|
||||
entryAuthIndex
|
||||
);
|
||||
} catch (firstErr) {
|
||||
@@ -167,7 +148,7 @@ export function useModelDiscovery(
|
||||
.map((h) => `${h.key}:${h.value}`)
|
||||
.join('|');
|
||||
const entriesSig = (apiKeyEntries ?? [])
|
||||
.map((e) => `${e.apiKey ?? ''}::${e.authIndex ?? ''}::${e.headersText ?? ''}`)
|
||||
.map((e) => `${e.apiKey ?? ''}::${e.authIndex ?? ''}`)
|
||||
.join('|');
|
||||
return [
|
||||
baseUrl,
|
||||
|
||||
@@ -91,7 +91,6 @@ export interface ModelEntryInput {
|
||||
export interface ApiKeyEntryInput {
|
||||
apiKey: string;
|
||||
proxyUrl: string;
|
||||
headersText: string;
|
||||
authIndex?: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,23 +74,6 @@ const parseTextList = (text: string): string[] =>
|
||||
.map((item) => item.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
const parseHeadersText = (text: string): Record<string, string> => {
|
||||
const result: Record<string, string> = {};
|
||||
text
|
||||
.split(/\n+/)
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean)
|
||||
.forEach((line) => {
|
||||
const sep = line.indexOf(':');
|
||||
if (sep <= 0) return;
|
||||
const key = line.slice(0, sep).trim();
|
||||
const value = line.slice(sep + 1).trim();
|
||||
if (!key) return;
|
||||
result[key] = value;
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
const headersFromEntries = (
|
||||
entries: Array<{ key: string; value: string }>
|
||||
): Record<string, string> => {
|
||||
@@ -177,9 +160,6 @@ const buildOpenAIConfig = (
|
||||
?.map((entry) => ({
|
||||
apiKey: entry.apiKey.trim(),
|
||||
proxyUrl: entry.proxyUrl.trim() || undefined,
|
||||
headers: Object.keys(parseHeadersText(entry.headersText)).length
|
||||
? parseHeadersText(entry.headersText)
|
||||
: undefined,
|
||||
authIndex: entry.authIndex?.trim() || undefined,
|
||||
}))
|
||||
.filter((entry) => entry.apiKey) ?? [];
|
||||
|
||||
@@ -265,8 +265,6 @@ const serializeModelAliases = (models?: ModelAlias[]) =>
|
||||
const serializeApiKeyEntry = (entry: ApiKeyEntry) => {
|
||||
const payload: Record<string, unknown> = { 'api-key': entry.apiKey };
|
||||
if (entry.proxyUrl) payload['proxy-url'] = entry.proxyUrl;
|
||||
const headers = serializeHeaders(entry.headers);
|
||||
if (headers) payload.headers = headers;
|
||||
return payload;
|
||||
};
|
||||
|
||||
|
||||
@@ -99,13 +99,11 @@ const normalizeApiKeyEntry = (entry: unknown): ApiKeyEntry | null => {
|
||||
if (!trimmed) return null;
|
||||
|
||||
const proxyUrl = record?.['proxy-url'];
|
||||
const headers = record ? normalizeHeaders(record.headers) : undefined;
|
||||
const authIndex = normalizeAuthIndex(record?.['auth-index']);
|
||||
|
||||
const result: ApiKeyEntry = {
|
||||
apiKey: trimmed,
|
||||
proxyUrl: proxyUrl ? String(proxyUrl) : undefined,
|
||||
headers
|
||||
proxyUrl: proxyUrl ? String(proxyUrl) : undefined
|
||||
};
|
||||
if (authIndex) result.authIndex = authIndex;
|
||||
return result;
|
||||
|
||||
@@ -13,7 +13,6 @@ export interface ModelAlias {
|
||||
export interface ApiKeyEntry {
|
||||
apiKey: string;
|
||||
proxyUrl?: string;
|
||||
headers?: Record<string, string>;
|
||||
authIndex?: string;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user