LibreChat/packages/data-provider/src/zod.ts
Danny Avila 63afb317c6
🚀 fix: Resolve Google Client Issues, CDN Screenshots, Update Models (#5703)
* 🤖 refactor: streamline model selection logic for title model in GoogleClient

* refactor: add options for empty object schemas in convertJsonSchemaToZod

* refactor: add utility function to check for empty object schemas in convertJsonSchemaToZod

* fix: Google MCP Tool errors, and remove Object Unescaping as Google fixed this

* fix: google safetySettings

* feat: add safety settings exclusion via GOOGLE_EXCLUDE_SAFETY_SETTINGS environment variable

* fix: rename environment variable for console JSON string length

* fix: disable portal for dropdown in ExportModal component

* fix: screenshot functionality to use image placeholder for remote images

* feat: add visionMode property to BaseClient and initialize in GoogleClient to fix resendFiles issue

* fix: enhance formatMessages to include image URLs in message content for Vertex AI

* fix: safety settings for titleChatCompletion

* fix: remove deprecated model assignment in GoogleClient and streamline title model retrieval

* fix: remove unused image preloading logic in ScreenshotContext

* chore: update default google models to latest models shared by vertex ai and gen ai

* refactor: enhance Google error messaging

* fix: update token values and model limits for Gemini models

* ci: fix model matching

* chore: bump version of librechat-data-provider to 0.7.699
2025-02-06 18:13:18 -05:00

86 lines
2.6 KiB
TypeScript

import { z } from 'zod';
export type JsonSchemaType = {
type: 'string' | 'number' | 'boolean' | 'array' | 'object';
enum?: string[];
items?: JsonSchemaType;
properties?: Record<string, JsonSchemaType>;
required?: string[];
description?: string;
};
function isEmptyObjectSchema(jsonSchema?: JsonSchemaType): boolean {
return (
jsonSchema != null &&
typeof jsonSchema === 'object' &&
jsonSchema.type === 'object' &&
(jsonSchema.properties == null || Object.keys(jsonSchema.properties).length === 0)
);
}
export function convertJsonSchemaToZod(
schema: JsonSchemaType,
options: { allowEmptyObject?: boolean } = {},
): z.ZodType | undefined {
const { allowEmptyObject = true } = options;
if (!allowEmptyObject && isEmptyObjectSchema(schema)) {
return undefined;
}
let zodSchema: z.ZodType;
// Handle primitive types
if (schema.type === 'string') {
if (Array.isArray(schema.enum) && schema.enum.length > 0) {
const [first, ...rest] = schema.enum;
zodSchema = z.enum([first, ...rest] as [string, ...string[]]);
} else {
zodSchema = z.string();
}
} else if (schema.type === 'number') {
zodSchema = z.number();
} else if (schema.type === 'boolean') {
zodSchema = z.boolean();
} else if (schema.type === 'array' && schema.items !== undefined) {
const itemSchema = convertJsonSchemaToZod(schema.items);
zodSchema = z.array(itemSchema as z.ZodType);
} else if (schema.type === 'object') {
const shape: Record<string, z.ZodType> = {};
const properties = schema.properties ?? {};
for (const [key, value] of Object.entries(properties)) {
let fieldSchema = convertJsonSchemaToZod(value);
if (!fieldSchema) {
continue;
}
if (value.description != null && value.description !== '') {
fieldSchema = fieldSchema.describe(value.description);
}
shape[key] = fieldSchema;
}
let objectSchema = z.object(shape);
if (Array.isArray(schema.required) && schema.required.length > 0) {
const partial = Object.fromEntries(
Object.entries(shape).map(([key, value]) => [
key,
schema.required?.includes(key) === true ? value : value.optional(),
]),
);
objectSchema = z.object(partial);
} else {
objectSchema = objectSchema.partial();
}
zodSchema = objectSchema;
} else {
zodSchema = z.unknown();
}
// Add description if present
if (schema.description != null && schema.description !== '') {
zodSchema = zodSchema.describe(schema.description);
}
return zodSchema;
}