feat(core): Add support for custom aliases for model configs. (#13546)

This commit is contained in:
joshualitt
2025-11-21 16:13:10 -08:00
committed by GitHub
parent 1e715d1e5c
commit 42c2e1b217
5 changed files with 151 additions and 2 deletions

View File

@@ -494,6 +494,11 @@ their corresponding top-level category object in your `settings.json` file.
}
```
- **`modelConfigs.customAliases`** (object):
- **Description:** Custom named presets for model configs. These are merged
with (and override) the built-in aliases.
- **Default:** `{}`
- **`modelConfigs.overrides`** (array):
- **Description:** Apply specific configuration overrides based on matches,
with a primary key of model (or alias). The most specific match will be

View File

@@ -729,6 +729,16 @@ const SETTINGS_SCHEMA = {
'Named presets for model configs. Can be used in place of a model name and can inherit from other aliases using an `extends` property.',
showInDialog: false,
},
customAliases: {
type: 'object',
label: 'Custom Model Config Aliases',
category: 'Model',
requiresRestart: false,
default: {},
description:
'Custom named presets for model configs. These are merged with (and override) the built-in aliases.',
showInDialog: false,
},
overrides: {
type: 'array',
label: 'Model Config Overrides',

View File

@@ -576,4 +576,125 @@ describe('ModelConfigService', () => {
});
});
});
describe('custom aliases', () => {
it('should resolve a custom alias', () => {
const config: ModelConfigServiceConfig = {
aliases: {},
customAliases: {
'my-custom-alias': {
modelConfig: {
model: 'gemini-custom',
generateContentConfig: {
temperature: 0.9,
},
},
},
},
overrides: [],
};
const service = new ModelConfigService(config);
const resolved = service.getResolvedConfig({ model: 'my-custom-alias' });
expect(resolved.model).toBe('gemini-custom');
expect(resolved.generateContentConfig).toEqual({
temperature: 0.9,
});
});
it('should allow custom aliases to override built-in aliases', () => {
const config: ModelConfigServiceConfig = {
aliases: {
'standard-alias': {
modelConfig: {
model: 'gemini-standard',
generateContentConfig: {
temperature: 0.5,
},
},
},
},
customAliases: {
'standard-alias': {
modelConfig: {
model: 'gemini-custom-override',
generateContentConfig: {
temperature: 0.1,
},
},
},
},
overrides: [],
};
const service = new ModelConfigService(config);
const resolved = service.getResolvedConfig({ model: 'standard-alias' });
expect(resolved.model).toBe('gemini-custom-override');
expect(resolved.generateContentConfig).toEqual({
temperature: 0.1,
});
});
});
describe('unrecognized models', () => {
it('should apply overrides to unrecognized model names', () => {
const unregisteredModelName = 'my-unregistered-model-v1';
const config: ModelConfigServiceConfig = {
aliases: {}, // No aliases defined
overrides: [
{
match: { model: unregisteredModelName },
modelConfig: {
generateContentConfig: {
temperature: 0.01,
},
},
},
],
};
const service = new ModelConfigService(config);
// Request the unregistered model directly
const resolved = service.getResolvedConfig({
model: unregisteredModelName,
});
// It should preserve the model name and apply the override
expect(resolved.model).toBe(unregisteredModelName);
expect(resolved.generateContentConfig).toEqual({
temperature: 0.01,
});
});
it('should apply scoped overrides to unrecognized model names', () => {
const unregisteredModelName = 'my-unregistered-model-v1';
const config: ModelConfigServiceConfig = {
aliases: {},
overrides: [
{
match: {
model: unregisteredModelName,
overrideScope: 'special-agent',
},
modelConfig: {
generateContentConfig: {
temperature: 0.99,
},
},
},
],
};
const service = new ModelConfigService(config);
const resolved = service.getResolvedConfig({
model: unregisteredModelName,
overrideScope: 'special-agent',
});
expect(resolved.model).toBe(unregisteredModelName);
expect(resolved.generateContentConfig).toEqual({
temperature: 0.99,
});
});
});
});

View File

@@ -43,6 +43,7 @@ export interface ModelConfigAlias {
export interface ModelConfigServiceConfig {
aliases?: Record<string, ModelConfigAlias>;
customAliases?: Record<string, ModelConfigAlias>;
overrides?: ModelConfigOverride[];
}
@@ -104,8 +105,12 @@ export class ModelConfigService {
generateContentConfig: GenerateContentConfig;
} {
const config = this.config || {};
const { aliases = {}, overrides = [] } = config;
const allAliases = { ...aliases, ...this.runtimeAliases };
const { aliases = {}, customAliases = {}, overrides = [] } = config;
const allAliases = {
...aliases,
...customAliases,
...this.runtimeAliases,
};
let baseModel: string | undefined = context.model;
let resolvedConfig: GenerateContentConfig = {};

View File

@@ -794,6 +794,14 @@
"type": "object",
"additionalProperties": true
},
"customAliases": {
"title": "Custom Model Config Aliases",
"description": "Custom named presets for model configs. These are merged with (and override) the built-in aliases.",
"markdownDescription": "Custom named presets for model configs. These are merged with (and override) the built-in aliases.\n\n- Category: `Model`\n- Requires restart: `no`\n- Default: `{}`",
"default": {},
"type": "object",
"additionalProperties": true
},
"overrides": {
"title": "Model Config Overrides",
"description": "Apply specific configuration overrides based on matches, with a primary key of model (or alias). The most specific match will be used.",