fix(api-access): preserve model aliases when saving providers
Keep same-source alias entries and their metadata when rebuilding provider models, preventing API connection edits from deleting aliases created in Advanced Settings. Fixes #271
This commit is contained in:
1 parent
911a20a91a
commit
93525f0ac7
2 files changed
+66
-8
No files matched your search
@@ -372,18 +372,34 @@ export const stripResponseFields = (record: Record<string, unknown>) => {
|
||||
|
||||
const mergeModelRecords = (current: unknown, selected: ModelOption[]) => {
|
||||
const existing = Array.isArray(current) ? current : [];
|
||||
const consumedExistingIndexes = new Set<number>();
|
||||
const selectedNames = new Set<string>();
|
||||
const seen = new Set<string>();
|
||||
return selected.reduce<Record<string, unknown>[]>((models, model) => {
|
||||
const models = selected.reduce<Record<string, unknown>[]>((result, model) => {
|
||||
const name = model.name.trim();
|
||||
const key = name.toLowerCase();
|
||||
if (!name || seen.has(key)) return models;
|
||||
if (!name || seen.has(key)) return result;
|
||||
seen.add(key);
|
||||
const matched = existing.find(
|
||||
(item) => isRecord(item) && readString(item, 'name').toLowerCase() === name.toLowerCase(),
|
||||
);
|
||||
selectedNames.add(key);
|
||||
const requested = (model.alias ?? '').trim();
|
||||
const requestedAlias = requested.toLowerCase();
|
||||
let matchedIndex = existing.findIndex((item, index) => (
|
||||
!consumedExistingIndexes.has(index)
|
||||
&& isRecord(item)
|
||||
&& readString(item, 'name').toLowerCase() === key
|
||||
&& readString(item, 'alias').toLowerCase() === requestedAlias
|
||||
));
|
||||
if (matchedIndex < 0) {
|
||||
matchedIndex = existing.findIndex((item, index) => (
|
||||
!consumedExistingIndexes.has(index)
|
||||
&& isRecord(item)
|
||||
&& readString(item, 'name').toLowerCase() === key
|
||||
));
|
||||
}
|
||||
if (matchedIndex >= 0) consumedExistingIndexes.add(matchedIndex);
|
||||
const matched = matchedIndex >= 0 ? existing[matchedIndex] : undefined;
|
||||
const next: Record<string, unknown> = isRecord(matched) ? { ...matched } : {};
|
||||
next.name = name;
|
||||
const requested = (model.alias ?? '').trim();
|
||||
const storedAlias = readString(next, 'alias');
|
||||
const alias = usableModelAlias(requested);
|
||||
if (alias && alias !== name) {
|
||||
@@ -401,9 +417,20 @@ const mergeModelRecords = (current: unknown, selected: ModelOption[]) => {
|
||||
delete next.alias;
|
||||
}
|
||||
if (model.thinking) next.thinking = { ...model.thinking };
|
||||
models.push(next);
|
||||
return models;
|
||||
result.push(next);
|
||||
return result;
|
||||
}, []);
|
||||
|
||||
existing.forEach((item, index) => {
|
||||
if (
|
||||
consumedExistingIndexes.has(index)
|
||||
|| !isRecord(item)
|
||||
|| !selectedNames.has(readString(item, 'name').toLowerCase())
|
||||
) return;
|
||||
models.push({ ...item });
|
||||
});
|
||||
|
||||
return models;
|
||||
};
|
||||
|
||||
export const exclusionsForModelSelection = (
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
sectionRecordsFromConfig,
|
||||
stripResponseFields,
|
||||
} from '../src/pages/ApiAccessPage';
|
||||
import { modelsFromRecord } from '../src/services/modelService';
|
||||
|
||||
it('saves non-empty custom model names and removes duplicate or blank entries', () => {
|
||||
const result = buildProviderRecord('openai-compatibility', {
|
||||
@@ -104,6 +105,36 @@ it('keeps an existing spaced alias when only the letter case changes', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('preserves aliases added in advanced settings when saving an API connection', () => {
|
||||
const current = {
|
||||
'api-key': 'codex-key',
|
||||
'base-url': 'https://foobar.com/v1',
|
||||
headers: { 'User-Agent': '$User-Agent' },
|
||||
models: [
|
||||
{ name: 'gpt-5.6-luna' },
|
||||
{
|
||||
name: 'gpt-5.6-luna',
|
||||
alias: 'claude-sonnet-5-luna',
|
||||
custom: { keep: true },
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = buildProviderRecord(
|
||||
'codex-api-key',
|
||||
{
|
||||
name: '',
|
||||
apiKey: 'codex-key',
|
||||
baseUrl: 'https://foobar.com/v1',
|
||||
priority: '',
|
||||
models: modelsFromRecord(current.models),
|
||||
headersText: 'User-Agent: $User-Agent',
|
||||
},
|
||||
current,
|
||||
);
|
||||
|
||||
expect(result.models).toEqual(current.models);
|
||||
});
|
||||
|
||||
it('parses multiline API keys into unique trimmed entries', () => {
|
||||
expect(parseProviderApiKeys(' key-a\n\nkey-b\r\nkey-a ')).toEqual(['key-a', 'key-b']);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user