mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-27 04:07:05 +00:00
🛟 fix: Allow Empty modelSpecs.list to Unstick Admin-Panel Saves (#13036)
* 🛟 fix: Allow empty modelSpecs.list to unstick admin-panel saves The unconditional `.min(1)` on `specsConfigSchema.list` rejected an empty list even when `enforce: false`, leaving admin panels (which save fields path-granularly) with no atomic way to clear the list once it had been populated. Once an admin reached `list: [entry]` and deleted the only entry, every subsequent save failed schema validation and the section became stuck. Relax the schema to `.default([])`. The `.min(1)` was added in #5218 as part of bundled cleanup, not as a deliberate rule. Every consumer of `modelSpecs.list` already handles the empty/undefined case (`?.list`, `?? []`, length-checked), and `processModelSpecs` short-circuits to `undefined` when the list is empty so the runtime treats it as "no specs configured." No call site is load-bearing on length >= 1. Tighten the `buildEndpointOption.js` enforce guard from `?.list && ?.enforce` to `?.list?.length && ?.enforce`. Empty arrays are truthy in JS, so the existing guard would have entered the enforce branch on `list: []` and returned "No model spec selected" or "Invalid model spec" had `processModelSpecs` ever been bypassed. Add a runtime warn in `processModelSpecs` when `enforce: true` is configured alongside an empty list, so operators see the resulting "enforcement disabled" state in logs rather than silently getting a permissive runtime. Add coverage for the empty-list parse path in `config-schemas.spec.ts` and for the empty-list-with-enforce branch in `buildEndpointOption.spec.js`. * chore: update import order in config-schemas.spec.ts
This commit is contained in:
parent
ac3600cdd7
commit
0d5c2b339a
5 changed files with 77 additions and 2 deletions
|
|
@ -48,7 +48,7 @@ async function buildEndpointOption(req, res, next) {
|
|||
}
|
||||
|
||||
const appConfig = req.config;
|
||||
if (appConfig.modelSpecs?.list && appConfig.modelSpecs?.enforce) {
|
||||
if (appConfig.modelSpecs?.list?.length && appConfig.modelSpecs?.enforce) {
|
||||
/** @type {{ list: TModelSpec[] }}*/
|
||||
const { list } = appConfig.modelSpecs;
|
||||
const { spec } = parsedBody;
|
||||
|
|
|
|||
|
|
@ -234,4 +234,34 @@ describe('buildEndpointOption - defaultParamsEndpoint parsing', () => {
|
|||
expect(parsedResult.maxOutputTokens).toBeUndefined();
|
||||
expect(parsedResult.max_tokens).toBe(4096);
|
||||
});
|
||||
|
||||
it('should not enter the enforce branch when modelSpecs.list is empty', async () => {
|
||||
mockGetEndpointsConfig.mockResolvedValue({});
|
||||
|
||||
const req = createReq(
|
||||
{
|
||||
endpoint: EModelEndpoint.openAI,
|
||||
model: 'gpt-4',
|
||||
},
|
||||
{
|
||||
modelSpecs: {
|
||||
enforce: true,
|
||||
list: [],
|
||||
},
|
||||
},
|
||||
);
|
||||
const res = createRes();
|
||||
const { handleError } = require('@librechat/api');
|
||||
|
||||
await buildEndpointOption(req, res, jest.fn());
|
||||
|
||||
expect(handleError).not.toHaveBeenCalledWith(
|
||||
res,
|
||||
expect.objectContaining({ text: 'No model spec selected' }),
|
||||
);
|
||||
expect(handleError).not.toHaveBeenCalledWith(
|
||||
res,
|
||||
expect.objectContaining({ text: 'Invalid model spec' }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue