mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 08:50:15 +01:00
🐋 fix: Improve Deepseek Compatbility (#7132)
* refactor: Update schema conversion to allow nullable optional fields * feat: Add support for 'Deepseek' model in response sender logic * fix: Normalize endpoint case for legacy content handling in AgentClient (fixes `deepseek-chat` followup issues)
This commit is contained in:
parent
55f5f2d11a
commit
a89a3f4146
3 changed files with 27 additions and 24 deletions
|
|
@ -673,7 +673,7 @@ class AgentClient extends BaseClient {
|
||||||
this.indexTokenCountMap,
|
this.indexTokenCountMap,
|
||||||
toolSet,
|
toolSet,
|
||||||
);
|
);
|
||||||
if (legacyContentEndpoints.has(this.options.agent.endpoint)) {
|
if (legacyContentEndpoints.has(this.options.agent.endpoint?.toLowerCase())) {
|
||||||
initialMessages = formatContentStrings(initialMessages);
|
initialMessages = formatContentStrings(initialMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -253,6 +253,8 @@ export const getResponseSender = (endpointOption: t.TEndpointOption): string =>
|
||||||
return extractOmniVersion(model);
|
return extractOmniVersion(model);
|
||||||
} else if (model && (model.includes('mistral') || model.includes('codestral'))) {
|
} else if (model && (model.includes('mistral') || model.includes('codestral'))) {
|
||||||
return 'Mistral';
|
return 'Mistral';
|
||||||
|
} else if (model && model.includes('deepseek')) {
|
||||||
|
return 'Deepseek';
|
||||||
} else if (model && model.includes('gpt-')) {
|
} else if (model && model.includes('gpt-')) {
|
||||||
const gptVersion = extractGPTVersion(model);
|
const gptVersion = extractGPTVersion(model);
|
||||||
return gptVersion || 'GPT';
|
return gptVersion || 'GPT';
|
||||||
|
|
@ -289,6 +291,8 @@ export const getResponseSender = (endpointOption: t.TEndpointOption): string =>
|
||||||
return extractOmniVersion(model);
|
return extractOmniVersion(model);
|
||||||
} else if (model && (model.includes('mistral') || model.includes('codestral'))) {
|
} else if (model && (model.includes('mistral') || model.includes('codestral'))) {
|
||||||
return 'Mistral';
|
return 'Mistral';
|
||||||
|
} else if (model && model.includes('deepseek')) {
|
||||||
|
return 'Deepseek';
|
||||||
} else if (model && model.includes('gpt-')) {
|
} else if (model && model.includes('gpt-')) {
|
||||||
const gptVersion = extractGPTVersion(model);
|
const gptVersion = extractGPTVersion(model);
|
||||||
return gptVersion || 'GPT';
|
return gptVersion || 'GPT';
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,9 @@ function dropSchemaFields(
|
||||||
schema: JsonSchemaType | undefined,
|
schema: JsonSchemaType | undefined,
|
||||||
fields: string[],
|
fields: string[],
|
||||||
): JsonSchemaType | undefined {
|
): JsonSchemaType | undefined {
|
||||||
if (schema == null || typeof schema !== 'object') {return schema;}
|
if (schema == null || typeof schema !== 'object') {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
// Handle arrays (should only occur for enum, required, etc.)
|
// Handle arrays (should only occur for enum, required, etc.)
|
||||||
if (Array.isArray(schema)) {
|
if (Array.isArray(schema)) {
|
||||||
// This should not happen for the root schema, but for completeness:
|
// This should not happen for the root schema, but for completeness:
|
||||||
|
|
@ -37,33 +39,25 @@ function dropSchemaFields(
|
||||||
}
|
}
|
||||||
const result: Record<string, unknown> = {};
|
const result: Record<string, unknown> = {};
|
||||||
for (const [key, value] of Object.entries(schema)) {
|
for (const [key, value] of Object.entries(schema)) {
|
||||||
if (fields.includes(key)) {continue;}
|
if (fields.includes(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Recursively process nested schemas
|
// Recursively process nested schemas
|
||||||
if (
|
if (key === 'items' || key === 'additionalProperties' || key === 'properties') {
|
||||||
key === 'items' ||
|
|
||||||
key === 'additionalProperties' ||
|
|
||||||
key === 'properties'
|
|
||||||
) {
|
|
||||||
if (key === 'properties' && value && typeof value === 'object') {
|
if (key === 'properties' && value && typeof value === 'object') {
|
||||||
// properties is a record of string -> JsonSchemaType
|
// properties is a record of string -> JsonSchemaType
|
||||||
const newProps: Record<string, JsonSchemaType> = {};
|
const newProps: Record<string, JsonSchemaType> = {};
|
||||||
for (const [propKey, propValue] of Object.entries(
|
for (const [propKey, propValue] of Object.entries(
|
||||||
value as Record<string, JsonSchemaType>,
|
value as Record<string, JsonSchemaType>,
|
||||||
)) {
|
)) {
|
||||||
const dropped = dropSchemaFields(
|
const dropped = dropSchemaFields(propValue, fields);
|
||||||
propValue,
|
|
||||||
fields,
|
|
||||||
);
|
|
||||||
if (dropped !== undefined) {
|
if (dropped !== undefined) {
|
||||||
newProps[propKey] = dropped;
|
newProps[propKey] = dropped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result[key] = newProps;
|
result[key] = newProps;
|
||||||
} else if (key === 'items' || key === 'additionalProperties') {
|
} else if (key === 'items' || key === 'additionalProperties') {
|
||||||
const dropped = dropSchemaFields(
|
const dropped = dropSchemaFields(value as JsonSchemaType, fields);
|
||||||
value as JsonSchemaType,
|
|
||||||
fields,
|
|
||||||
);
|
|
||||||
if (dropped !== undefined) {
|
if (dropped !== undefined) {
|
||||||
result[key] = dropped;
|
result[key] = dropped;
|
||||||
}
|
}
|
||||||
|
|
@ -141,9 +135,11 @@ function convertToZodUnion(
|
||||||
// For the special case of { optional: true }
|
// For the special case of { optional: true }
|
||||||
if ('optional' in (subSchema.properties as Record<string, unknown>)) {
|
if ('optional' in (subSchema.properties as Record<string, unknown>)) {
|
||||||
// Create a custom schema that preserves the optional property
|
// Create a custom schema that preserves the optional property
|
||||||
const customSchema = z.object({
|
const customSchema = z
|
||||||
|
.object({
|
||||||
optional: z.boolean(),
|
optional: z.boolean(),
|
||||||
}).passthrough();
|
})
|
||||||
|
.passthrough();
|
||||||
|
|
||||||
return customSchema;
|
return customSchema;
|
||||||
}
|
}
|
||||||
|
|
@ -362,12 +358,15 @@ export function convertJsonSchemaToZod(
|
||||||
const partial = Object.fromEntries(
|
const partial = Object.fromEntries(
|
||||||
Object.entries(shape).map(([key, value]) => [
|
Object.entries(shape).map(([key, value]) => [
|
||||||
key,
|
key,
|
||||||
schema.required?.includes(key) === true ? value : value.optional(),
|
schema.required?.includes(key) === true ? value : value.optional().nullable(),
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
objectSchema = z.object(partial);
|
objectSchema = z.object(partial);
|
||||||
} else {
|
} else {
|
||||||
objectSchema = objectSchema.partial();
|
const partialNullable = Object.fromEntries(
|
||||||
|
Object.entries(shape).map(([key, value]) => [key, value.optional().nullable()]),
|
||||||
|
);
|
||||||
|
objectSchema = z.object(partialNullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle additionalProperties for open-ended objects
|
// Handle additionalProperties for open-ended objects
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue