UNPKG

@mastra/schema-compat

Version:

Tool schema compatibility layer for Mastra.ai

258 lines (257 loc) • 10 kB
import { patchRecordSchemas } from "./zod-to-json.js"; import { toStandardSchema as toStandardSchema$2 } from "./standard-schema/adapters/ai-sdk.js"; import { n as toStandardSchema$3 } from "./json-schema-BstKYbJi.js"; import { toStandardSchema as toStandardSchema$4 } from "./standard-schema/adapters/zod-v3.js"; import z3 from "zod/v3"; import { toJSONSchema } from "zod/v4"; //#region src/standard-schema/adapters/zod-v4.ts /** * Supported JSON Schema targets for z.toJSONSchema(). * Works with both real Zod v4 and Zod 3.25's v4 compat layer. */ const SUPPORTED_TARGETS = /* @__PURE__ */ new Set([ "draft-07", "draft-04", "draft-2020-12" ]); /** * Maps Mastra's target names to Zod v4's expected format. * Zod v4's z.toJSONSchema() expects "draft-7" instead of "draft-07", * and "draft-4" instead of "draft-04". */ const ZOD_V4_TARGET_MAP = { "draft-07": "draft-7", "draft-04": "draft-4" }; /** * Converts a Zod v4 schema to JSON Schema using z.toJSONSchema(). * * Works with both real Zod v4 and Zod 3.25's v4 compat layer. * * @internal */ function convertToJsonSchema(zodSchema, options, adapterOptions) { patchRecordSchemas(zodSchema); const target = SUPPORTED_TARGETS.has(options.target) ? options.target : "draft-07"; const jsonSchemaOptions = { target: ZOD_V4_TARGET_MAP[target] ?? target }; if (adapterOptions.unrepresentable) jsonSchemaOptions.unrepresentable = adapterOptions.unrepresentable; if (adapterOptions.override) jsonSchemaOptions.override = adapterOptions.override; return toJSONSchema(zodSchema, jsonSchemaOptions); } /** * Wraps a Zod v4 schema to implement the full @standard-schema/spec interface. * * Zod v4 schemas (and Zod 3.25's v4 compat layer) implement `StandardSchemaV1` * (validation) but may not implement `StandardJSONSchemaV1` (JSON Schema conversion) * on the `~standard` property. This adapter adds the `jsonSchema` property using * `z.toJSONSchema()` to provide JSON Schema conversion capabilities. * * @param zodSchema - A Zod v4 schema (has `_zod` property) * @param adapterOptions - Options passed to z.toJSONSchema() * @returns The schema wrapped with StandardSchemaWithJSON support */ function toStandardSchema$1(zodSchema, adapterOptions = {}) { const wrapper = Object.create(zodSchema); const existingStandard = zodSchema["~standard"]; const jsonSchemaConverter = { input: (options) => { return convertToJsonSchema(zodSchema, options, adapterOptions); }, output: (options) => { return convertToJsonSchema(zodSchema, options, adapterOptions); } }; Object.defineProperty(wrapper, "~standard", { value: { ...existingStandard, jsonSchema: jsonSchemaConverter }, writable: false, enumerable: true, configurable: false }); return wrapper; } //#endregion //#region src/standard-schema/standard-schema.ts /** * Override function for JSON Schema conversion. * Handles types that Zod v4 cannot natively represent in JSON Schema: * - z.date() -> { type: 'string', format: 'date-time' } */ function jsonSchemaOverride(ctx) { const zodSchema = ctx.zodSchema; if (ctx.jsonSchema.type === "object" && ctx.jsonSchema.properties !== void 0 && !ctx.jsonSchema.additionalProperties) ctx.jsonSchema.additionalProperties = false; if (zodSchema) { if (zodSchema?.type === "date" || zodSchema?._def?.typeName === "ZodDate") { if (zodSchema?.type === "date") { ctx.jsonSchema.type = "string"; ctx.jsonSchema.format = "date-time"; } ctx.jsonSchema["x-date"] = !zodSchema._zod?.def?.coerce; } else if (zodSchema?.type === "object" && zodSchema._zod?.def?.catchall?.type === "unknown") ctx.jsonSchema.additionalProperties = true; } } /** * Library options for JSON Schema conversion. * - unrepresentable: 'any' allows z.custom() and other unrepresentable types to be converted to {} * instead of throwing "Custom types cannot be represented in JSON Schema" * - override: converts z.date() to { type: 'string', format: 'date-time' } */ const JSON_SCHEMA_LIBRARY_OPTIONS = { unrepresentable: "any", override: jsonSchemaOverride }; function isVercelSchema(schema) { return typeof schema === "object" && schema !== null && "_type" in schema && "jsonSchema" in schema && typeof schema.jsonSchema === "object"; } /** * Check if a schema is Zod v4 (has _zod property which is v4-only) */ function isZodV4(schema) { return typeof schema === "object" && schema !== null && "_zod" in schema; } /** * Check if a schema is Zod v3. * * Zod v3 can come from: * 1. The old standalone 'zod-v3' package * 2. The 'zod/v3' compat export from modern zod * * We detect Zod v3 by checking: * - Has ~standard.vendor === 'zod' (both v3 and v4 have this) * - Does NOT have ~standard.jsonSchema (only Zod v4 has native JSON Schema support) * - Does NOT have _zod property (only Zod v4 has this) * * Note: We can't use instanceof z3.ZodType because the old 'zod-v3' package * has a different prototype chain than 'zod/v3'. */ function isZodV3(schema) { if (schema === null || typeof schema !== "object") return false; if (isZodV4(schema)) return false; if ("~standard" in schema) { const std = schema["~standard"]; if (typeof std === "object" && std !== null && std.vendor === "zod" && !("jsonSchema" in std)) return true; } return schema instanceof z3.ZodType; } function toStandardSchema(schema) { if (isZodV4(schema)) patchRecordSchemas(schema); if (isStandardSchemaWithJSON(schema)) return schema; if (isZodV4(schema)) return toStandardSchema$1(schema, { unrepresentable: JSON_SCHEMA_LIBRARY_OPTIONS.unrepresentable, override: JSON_SCHEMA_LIBRARY_OPTIONS.override }); if (isZodV3(schema)) return toStandardSchema$4(schema); if (isVercelSchema(schema)) return toStandardSchema$2(schema); if (schema === null || typeof schema !== "object" && typeof schema !== "function") throw new Error(`Unsupported schema type: ${typeof schema}`); if (typeof schema === "function") throw new Error(`Unsupported schema type: function (schema libraries should implement StandardSchemaWithJSON)`); return toStandardSchema$3(schema); } /** * Type guard to check if a value implements the StandardSchemaV1 interface. * * @param value - The value to check * @returns True if the value implements StandardSchemaV1 * * @example * ```typescript * import { isStandardSchema } from '@mastra/schema-compat'; * * if (isStandardSchema(someValue)) { * const result = someValue['~standard'].validate(input); * } * ``` */ function isStandardSchema(value) { if (value === null || typeof value !== "object" && typeof value !== "function") return false; if (!("~standard" in value)) return false; const std = value["~standard"]; return typeof std === "object" && std !== null && "version" in std && std.version === 1 && "vendor" in std && "validate" in std && typeof std.validate === "function"; } /** * Type guard to check if a value implements the StandardJSONSchemaV1 interface. * * @param value - The value to check * @returns True if the value implements StandardJSONSchemaV1 * * @example * ```typescript * import { isStandardJSONSchema } from '@mastra/schema-compat'; * * if (isStandardJSONSchema(someValue)) { * const jsonSchema = someValue['~standard'].jsonSchema.output({ target: 'draft-07' }); * } * ``` */ function isStandardJSONSchema(value) { if (value === null || typeof value !== "object" && typeof value !== "function") return false; if (!("~standard" in value)) return false; const std = value["~standard"]; if (typeof std !== "object" || std === null) return false; if (!("version" in std) || std.version !== 1 || !("vendor" in std)) return false; if (!("jsonSchema" in std) || typeof std.jsonSchema !== "object") return false; return typeof std.jsonSchema.input === "function" && typeof std.jsonSchema.output === "function"; } /** * Type guard to check if a value implements both StandardSchemaV1 and StandardJSONSchemaV1. * * @param value - The value to check * @returns True if the value implements both interfaces * * @example * ```typescript * import { isStandardSchemaWithJSON } from '@mastra/schema-compat'; * * if (isStandardSchemaWithJSON(someValue)) { * // Can use both validation and JSON Schema conversion * const result = someValue['~standard'].validate(input); * const jsonSchema = someValue['~standard'].jsonSchema.output({ target: 'draft-07' }); * } * ``` */ function isStandardSchemaWithJSON(value) { return isStandardSchema(value) && isStandardJSONSchema(value); } /** * Converts a StandardSchemaWithJSON to a JSON Schema. * * @param schema - The StandardSchemaWithJSON schema to convert * @param options - Conversion options * @param options.target - The JSON Schema target version (default: 'draft-07') * @param options.io - Whether to use input or output schema (default: 'output') * - 'input': Use for tool parameters, function arguments, request bodies * - 'output': Use for return types, response bodies * @returns The JSON Schema representation * * @example * ```typescript * import { standardSchemaToJSONSchema, toStandardSchema } from '@mastra/schema-compat'; * import { z } from 'zod'; * * const zodSchema = z.object({ name: z.string() }); * const standardSchema = toStandardSchema(zodSchema); * * // For output types (default) * const outputSchema = standardSchemaToJSONSchema(standardSchema); * * // For input types (tool parameters) * const inputSchema = standardSchemaToJSONSchema(standardSchema, { io: 'input' }); * ``` */ function standardSchemaToJSONSchema(schema, options = {}) { const { target = "draft-07", io = "output", override = JSON_SCHEMA_LIBRARY_OPTIONS.override } = options; const jsonSchemaFn = schema["~standard"].jsonSchema[io]; let jsonSchema = jsonSchemaFn({ target, libraryOptions: { ...JSON_SCHEMA_LIBRARY_OPTIONS, override } }); jsonSchema = JSON.parse(JSON.stringify(jsonSchema)); return jsonSchema; } //#endregion export { standardSchemaToJSONSchema as a, isStandardSchemaWithJSON as i, isStandardJSONSchema as n, toStandardSchema as o, isStandardSchema as r, JSON_SCHEMA_LIBRARY_OPTIONS as t }; //# sourceMappingURL=schema-Bv9OdW1f.js.map