mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-04-05 15:27:20 +02:00
🪆 fix: Allow Nested addParams in Config Schema (#12526)
* fix: allow nested addParams in config schema * Respect no-op task constraint Constraint: Task 2 explicitly forbids code changes Directive: Keep this worker branch code-identical to the assigned base for this task Confidence: high Scope-risk: narrow Tested: git status --short (clean) * fix: align addParams web_search validation with runtime * test: cover addParams edge cases * chore: ignore .codex directory
This commit is contained in:
parent
6ecd1b510f
commit
ed02fe40e0
3 changed files with 199 additions and 3 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -137,6 +137,7 @@ helm/**/.values.yaml
|
|||
|
||||
# AI Assistants
|
||||
/.claude/
|
||||
/.codex/
|
||||
/.cursor/
|
||||
/.copilot/
|
||||
/.aider/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import {
|
||||
endpointSchema,
|
||||
paramDefinitionSchema,
|
||||
agentsEndpointSchema,
|
||||
azureEndpointSchema,
|
||||
endpointSchema,
|
||||
configSchema,
|
||||
} from '../src/config';
|
||||
import { tModelSpecPresetSchema, EModelEndpoint } from '../src/schemas';
|
||||
|
||||
|
|
@ -222,6 +223,109 @@ describe('endpointSchema deprecated fields', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('endpointSchema addParams validation', () => {
|
||||
const validEndpoint = {
|
||||
name: 'CustomEndpoint',
|
||||
apiKey: 'test-key',
|
||||
baseURL: 'https://api.example.com',
|
||||
models: { default: ['model-1'] },
|
||||
};
|
||||
const nestedAddParams = {
|
||||
provider: {
|
||||
only: ['z-ai'],
|
||||
quantizations: ['int4'],
|
||||
},
|
||||
};
|
||||
|
||||
it('accepts nested addParams objects and arrays', () => {
|
||||
const result = endpointSchema.safeParse({
|
||||
...validEndpoint,
|
||||
addParams: nestedAddParams,
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) {
|
||||
expect(result.data.addParams).toEqual(nestedAddParams);
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps configSchema validation intact with nested custom addParams', () => {
|
||||
const result = configSchema.safeParse({
|
||||
version: '1.0.0',
|
||||
endpoints: {
|
||||
custom: [
|
||||
{
|
||||
...validEndpoint,
|
||||
addParams: nestedAddParams,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('accepts boolean web_search in addParams', () => {
|
||||
const result = endpointSchema.safeParse({
|
||||
...validEndpoint,
|
||||
addParams: {
|
||||
provider: {
|
||||
only: ['z-ai'],
|
||||
},
|
||||
web_search: true,
|
||||
},
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('accepts scalar addParams values', () => {
|
||||
const result = endpointSchema.safeParse({
|
||||
...validEndpoint,
|
||||
addParams: {
|
||||
model: 'custom-model',
|
||||
retries: 2,
|
||||
metadata: null,
|
||||
},
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects non-boolean web_search objects in addParams', () => {
|
||||
const result = endpointSchema.safeParse({
|
||||
...validEndpoint,
|
||||
addParams: {
|
||||
provider: {
|
||||
only: ['z-ai'],
|
||||
},
|
||||
web_search: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects configSchema entries with non-boolean web_search objects in custom addParams', () => {
|
||||
const result = configSchema.safeParse({
|
||||
version: '1.0.0',
|
||||
endpoints: {
|
||||
custom: [
|
||||
{
|
||||
...validEndpoint,
|
||||
addParams: {
|
||||
provider: {
|
||||
only: ['z-ai'],
|
||||
},
|
||||
web_search: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('agentsEndpointSchema', () => {
|
||||
it('does not accept baseURL', () => {
|
||||
const result = agentsEndpointSchema.safeParse({
|
||||
|
|
@ -251,4 +355,69 @@ describe('azureEndpointSchema', () => {
|
|||
expect(result.data).not.toHaveProperty('plugins');
|
||||
}
|
||||
});
|
||||
|
||||
it('accepts nested addParams in azure groups', () => {
|
||||
const result = azureEndpointSchema.safeParse({
|
||||
groups: [
|
||||
{
|
||||
group: 'test-group',
|
||||
apiKey: 'test-key',
|
||||
models: { 'gpt-4': true },
|
||||
addParams: {
|
||||
provider: {
|
||||
only: ['z-ai'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
if (result.success) {
|
||||
expect(result.data.groups[0].addParams).toEqual({
|
||||
provider: {
|
||||
only: ['z-ai'],
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it('accepts boolean web_search in azure addParams', () => {
|
||||
const result = azureEndpointSchema.safeParse({
|
||||
groups: [
|
||||
{
|
||||
group: 'test-group',
|
||||
apiKey: 'test-key',
|
||||
models: { 'gpt-4': true },
|
||||
addParams: {
|
||||
provider: {
|
||||
only: ['z-ai'],
|
||||
},
|
||||
web_search: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects non-boolean web_search objects in azure addParams', () => {
|
||||
const result = azureEndpointSchema.safeParse({
|
||||
groups: [
|
||||
{
|
||||
group: 'test-group',
|
||||
apiKey: 'test-key',
|
||||
models: { 'gpt-4': true },
|
||||
addParams: {
|
||||
provider: {
|
||||
only: ['z-ai'],
|
||||
},
|
||||
web_search: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(result.success).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -115,13 +115,39 @@ export const modelConfigSchema = z
|
|||
|
||||
export type TAzureModelConfig = z.infer<typeof modelConfigSchema>;
|
||||
|
||||
const paramValueSchema: z.ZodType<unknown> = z.lazy(() =>
|
||||
z.union([
|
||||
z.string(),
|
||||
z.number(),
|
||||
z.boolean(),
|
||||
z.null(),
|
||||
z.array(paramValueSchema),
|
||||
z.record(z.string(), paramValueSchema),
|
||||
]),
|
||||
);
|
||||
|
||||
/** Validates addParams while keeping web_search aligned with current runtime boolean handling. */
|
||||
const addParamsSchema: z.ZodType<Record<string, unknown>> = z
|
||||
.record(z.string(), paramValueSchema)
|
||||
.superRefine((params, ctx) => {
|
||||
if (params.web_search === undefined || typeof params.web_search === 'boolean') {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
path: ['web_search'],
|
||||
message: '`web_search` must be a boolean in addParams',
|
||||
});
|
||||
});
|
||||
|
||||
export const azureBaseSchema = z.object({
|
||||
apiKey: z.string(),
|
||||
serverless: z.boolean().optional(),
|
||||
instanceName: z.string().optional(),
|
||||
deploymentName: z.string().optional(),
|
||||
assistants: z.boolean().optional(),
|
||||
addParams: z.record(z.union([z.string(), z.number(), z.boolean(), z.null()])).optional(),
|
||||
addParams: addParamsSchema.optional(),
|
||||
dropParams: z.array(z.string()).optional(),
|
||||
version: z.string().optional(),
|
||||
baseURL: z.string().optional(),
|
||||
|
|
@ -361,7 +387,7 @@ export const endpointSchema = baseEndpointSchema.merge(
|
|||
iconURL: z.string().optional(),
|
||||
modelDisplayLabel: z.string().optional(),
|
||||
headers: z.record(z.string()).optional(),
|
||||
addParams: z.record(z.union([z.string(), z.number(), z.boolean(), z.null()])).optional(),
|
||||
addParams: addParamsSchema.optional(),
|
||||
dropParams: z.array(z.string()).optional(),
|
||||
customParams: z
|
||||
.object({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue