UNPKG

@openai/agents-core

Version:

The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.

916 lines • 37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isJsonSchemaDepthError = isJsonSchemaDepthError; exports.toOpenAIStrictToolSchema = toOpenAIStrictToolSchema; exports.prepareOpenAIStrictToolSchema = prepareOpenAIStrictToolSchema; exports.assertOpenAIStrictToolSchemaPreservesOpenObjects = assertOpenAIStrictToolSchemaPreservesOpenObjects; exports.stripStrictNullsForJsonSchema = stripStrictNullsForJsonSchema; exports.stripStrictNullsForZodSchema = stripStrictNullsForZodSchema; const errors_1 = require("../errors.js"); const zodCompat_1 = require("./zodCompat.js"); const MAX_JSON_SCHEMA_DEPTH = 100; const JSON_SCHEMA_DEPTH_ERROR = 'JSON schema is too deeply nested to process safely. Simplify or flatten the schema, or disable strict mode.'; class JsonSchemaDepthError extends errors_1.UserError { } function assertSafeJsonSchemaDepth(depth) { if (depth > MAX_JSON_SCHEMA_DEPTH) { throw new JsonSchemaDepthError(JSON_SCHEMA_DEPTH_ERROR); } } function createJsonSchemaTraversalState() { return { activeSchemas: new WeakSet(), visitedDepths: new WeakMap(), }; } function enterJsonSchemaTraversal(schema, state, depth) { if (state.activeSchemas.has(schema)) { return false; } const visitedDepth = state.visitedDepths.get(schema); if (typeof visitedDepth === 'number' && visitedDepth >= depth) { return false; } assertSafeJsonSchemaDepth(depth); state.visitedDepths.set(schema, depth); state.activeSchemas.add(schema); return true; } function leaveJsonSchemaTraversal(schema, state) { state.activeSchemas.delete(schema); } function assertJsonSchemaDepth(schema) { assertJsonSchemaPhysicalDepth(schema); } function assertJsonSchemaPhysicalDepth(schema) { const pending = []; const visitedDepths = new WeakMap(); if (typeof schema === 'object' && schema !== null) { pending.push({ value: schema, depth: 1 }); } while (pending.length > 0) { const { value, depth } = pending.pop(); assertSafeJsonSchemaDepth(depth); const visitedDepth = visitedDepths.get(value); if (typeof visitedDepth === 'number' && visitedDepth >= depth) { continue; } visitedDepths.set(value, depth); for (const child of Object.values(value)) { if (typeof child === 'object' && child !== null) { pending.push({ value: child, depth: depth + 1 }); } } } } function isJsonSchemaDepthError(error) { return error instanceof JsonSchemaDepthError; } function toOpenAIStrictToolSchema(schema) { return prepareOpenAIStrictToolSchemaInternal(schema, false).schema; } function prepareOpenAIStrictToolSchema(schema) { return prepareOpenAIStrictToolSchemaInternal(schema, true); } function assertOpenAIStrictToolSchemaPreservesOpenObjects(schema) { assertJsonSchemaDepth(schema); validateOpenAIStrictJsonSchema(schema, schema, createJsonSchemaTraversalState(), true, true); } function prepareOpenAIStrictToolSchemaInternal(schema, requireUnambiguousNormalization) { assertJsonSchemaDepth(schema); validateOpenAIStrictProviderSchema(schema, schema); validateOpenAIStrictJsonSchema(schema, schema, createJsonSchemaTraversalState(), requireUnambiguousNormalization); const preparedSchemas = new WeakMap(); const syntheticNullableSchemas = new WeakMap(); const context = { originalRoot: schema, preparedRoot: undefined, preparedSchemas, references: [], syntheticNullableSchemas, }; const strictSchema = ensureStrictSchemaEntry(structuredClone(schema), schema, context, true); stabilizeLocalJsonSchemaReferences(strictSchema, context); context.preparedRoot = strictSchema; return { schema: strictSchema, normalizeInput: (value) => normalizeStrictJsonSchemaValue(strictSchema, value, context), }; } function ensureStrictSchemaEntry(entry, originalEntry, context, isRoot = false) { if (typeof entry !== 'object' || entry === null) { return entry; } const record = entry; const originalRecord = isRecord(originalEntry) ? originalEntry : undefined; if (originalRecord) { const preparedRecord = context.preparedSchemas.get(originalRecord); if (preparedRecord) { return preparedRecord; } context.preparedSchemas.set(originalRecord, record); } if (typeof originalRecord?.$ref === 'string') { context.references.push({ originalReference: originalRecord.$ref, preparedSchema: record, }); } const properties = isRecord(record.properties) ? record.properties : undefined; const originalProperties = isRecord(originalRecord?.properties) ? originalRecord.properties : undefined; const hasObjectKeywords = properties !== undefined || 'additionalProperties' in record; if (record.type === undefined && hasObjectKeywords && record.additionalProperties !== false) { throw new errors_1.UserError('Cannot convert a typeless open JSON schema to strict mode. Set `type: "object"` with `additionalProperties: false`, or disable strict mode.'); } if (!isRoot && record.type === undefined && properties !== undefined) { record.type = 'object'; } if (schemaConvertsObjectProperties(record) && properties !== undefined) { const preparedProperties = { ...properties }; record.properties = preparedProperties; const originalRequired = new Set(Array.isArray(originalRecord?.required) ? originalRecord.required.map(String) : []); for (const [key, value] of Object.entries(preparedProperties)) { const originalValue = originalProperties?.[key] ?? value; const optional = !originalRequired.has(key); const nullability = optional ? getKnownJsonSchemaNullability(originalValue, context.originalRoot) : undefined; const normalized = ensureStrictSchemaEntry(value, originalValue, context); preparedProperties[key] = nullability === 'disallows' ? wrapNullableSchema(normalized, context.syntheticNullableSchemas) : normalized; } record.required = Object.keys(preparedProperties); record.additionalProperties = false; } for (const key of ['$defs', 'definitions']) { const nested = record[key]; const originalNested = isRecord(originalRecord?.[key]) ? originalRecord[key] : undefined; if (typeof nested === 'object' && nested !== null && !Array.isArray(nested)) { for (const [nestedKey, nestedValue] of Object.entries(nested)) { nested[nestedKey] = ensureStrictSchemaEntry(nestedValue, originalNested?.[nestedKey] ?? nestedValue, context); } } } for (const key of ['anyOf']) { const nested = record[key]; const originalNested = Array.isArray(originalRecord?.[key]) ? originalRecord[key] : []; if (Array.isArray(nested)) { record[key] = nested.map((value, index) => ensureStrictSchemaEntry(value, originalNested[index] ?? value, context)); } } const items = record.items; const originalItems = originalRecord?.items; if (Array.isArray(items)) { const originalItemEntries = Array.isArray(originalItems) ? originalItems : []; record.items = items.map((value, index) => ensureStrictSchemaEntry(value, originalItemEntries[index] ?? value, context)); } else if (typeof items === 'object' && items !== null) { record.items = ensureStrictSchemaEntry(items, originalItems ?? items, context); } if (record.default === null) { delete record.default; } return record; } function schemaConvertsObjectProperties(schema) { return (isRecord(schema.properties) && (schema.type === 'object' || (Array.isArray(schema.type) && schema.type.includes('object')) || typeof schema.type === 'undefined')); } function stabilizeLocalJsonSchemaReferences(preparedRoot, context) { if (!isRecord(preparedRoot)) { return; } // Strict conversion can wrap an optional property, replace // `additionalProperties`, or leave an inapplicable subschema untouched. A // local pointer into one of those locations would no longer identify the // target that was classified and normalized. Hoist only those unstable // targets so the provider schema and invocation normalizer share one // context-independent prepared node. const hoistedReferences = new WeakMap(); let nextDefinitionIndex = 0; for (let index = 0; index < context.references.length; index += 1) { const { originalReference, preparedSchema } = context.references[index]; const originalTarget = resolveLocalJsonSchemaReference(originalReference, context.originalRoot); if (typeof originalTarget === 'undefined') { continue; } const preparedTarget = isRecord(originalTarget) ? (context.preparedSchemas.get(originalTarget) ?? ensureStrictSchemaEntry(structuredClone(originalTarget), originalTarget, context)) : originalTarget; const pointerTarget = resolveLocalJsonSchemaReference(originalReference, preparedRoot); if (pointerTarget === preparedTarget) { continue; } let definitionName = isRecord(originalTarget) ? hoistedReferences.get(originalTarget) : undefined; if (!definitionName) { const existingDefinitions = preparedRoot.$defs; if (typeof existingDefinitions !== 'undefined' && !isRecord(existingDefinitions)) { throw new errors_1.UserError('Cannot stabilize local JSON schema references because the root `$defs` value is not an object. Use an object-valued `$defs` or disable strict mode.'); } const definitions = isRecord(existingDefinitions) ? existingDefinitions : {}; preparedRoot.$defs = definitions; do { definitionName = `__openai_strict_ref_${nextDefinitionIndex}`; nextDefinitionIndex += 1; } while (Object.prototype.hasOwnProperty.call(definitions, definitionName)); definitions[definitionName] = preparedTarget; if (isRecord(originalTarget)) { hoistedReferences.set(originalTarget, definitionName); } } preparedSchema.$ref = `#/$defs/${definitionName}`; } } function wrapNullableSchema(schema, syntheticNullableSchemas) { if (schema === false) { const nullableSchema = { anyOf: [false, { type: 'null' }], }; syntheticNullableSchemas.set(nullableSchema, { schema }); return nullableSchema; } if (typeof schema !== 'object' || schema === null) { return schema; } const description = typeof schema.description === 'string' ? { description: schema.description } : {}; const nullableSchema = { ...description, anyOf: [schema, { type: 'null' }], }; syntheticNullableSchemas.set(nullableSchema, { schema, }); return nullableSchema; } function stripStrictNullsForJsonSchema(schema, value) { if (!isRecord(schema)) { return value; } return prepareOpenAIStrictToolSchema(schema).normalizeInput(value); } function normalizeStrictJsonSchemaValue(schema, value, context) { if (value === undefined) { return undefined; } let currentSchema = schema; if (isRecord(currentSchema)) { const syntheticNullableSchema = context.syntheticNullableSchemas.get(currentSchema); if (syntheticNullableSchema) { if (value === null) { return undefined; } currentSchema = syntheticNullableSchema.schema; } } const resolvedSchema = resolveLocalJsonSchema(currentSchema, context); if (resolvedSchema !== currentSchema) { return normalizeStrictJsonSchemaValue(resolvedSchema, value, context); } if (value === null) { return value; } if (Array.isArray(value)) { const schemaRecord = isRecord(currentSchema) ? currentSchema : undefined; const items = schemaRecord?.items; if (Array.isArray(items)) { return value.map((entry, index) => normalizeStrictJsonSchemaValue(items[index], entry, context)); } if (items && typeof items === 'object') { return value.map((entry) => normalizeStrictJsonSchemaValue(items, entry, context)); } return value; } if (!isRecord(value) || !isRecord(currentSchema) || !schemaConvertsObjectProperties(currentSchema)) { return value; } const properties = isRecord(currentSchema.properties) ? currentSchema.properties : {}; const normalized = { ...value }; for (const [key, propertySchema] of Object.entries(properties)) { const nextValue = normalizeStrictJsonSchemaValue(propertySchema, normalized[key], context); if (typeof nextValue === 'undefined') { delete normalized[key]; } else { normalized[key] = nextValue; } } return normalized; } // This guard defines the local argument normalizer's supported boundary; it is // not a complete validator for every provider-specific JSON Schema keyword. // Reject composition and reference forms whose nullability cannot be mapped // without widening the caller's schema. Local `$ref` values must resolve within // the root document and cannot carry assertion siblings. Plain `anyOf` branches // that contain optional object fields are also rejected below, even when they // have a discriminator, because this path has no runtime schema validator to // select a branch. Nested `$id` resources are rejected because local pointers // are resolved only within the root resource. Use Zod for branch-aware // validation, make the affected fields required, move sibling constraints into // the branch or target, or disable strict mode. // Provider compatibility is checked across every retained schema location, // including properties that the local null normalizer does not traverse. // Schema applicators outside the traversal below are rejected rather than // partially interpreted, even when a provider model may accept a subset. const unsupportedStrictNormalizationKeywords = [ '$dynamicRef', '$recursiveRef', 'additionalItems', 'allOf', 'contains', 'contentSchema', 'dependencies', 'dependentRequired', 'dependentSchemas', 'else', 'if', 'maxContains', 'minContains', 'not', 'oneOf', 'patternProperties', 'prefixItems', 'propertyNames', 'then', 'unevaluatedItems', 'unevaluatedProperties', ]; const referenceMetadataKeywords = new Set([ '$anchor', '$comment', '$defs', '$id', '$ref', '$schema', 'default', 'deprecated', 'description', 'definitions', 'examples', 'readOnly', 'title', 'writeOnly', ]); const anyOfMetadataKeywords = new Set([...referenceMetadataKeywords, 'anyOf']); function validateOpenAIStrictProviderSchema(schema, rootSchema, state = createJsonSchemaTraversalState(), depth = 1) { if (typeof schema === 'boolean') { assertSafeJsonSchemaDepth(depth); return; } if (!isRecord(schema)) { throw new errors_1.UserError('Cannot convert a JSON schema containing a non-boolean, non-object schema node to strict mode. Replace the invalid node with a JSON schema object or boolean, or disable strict mode.'); } if (!enterJsonSchemaTraversal(schema, state, depth)) { return; } if (schema !== rootSchema && '$id' in schema) { throw new errors_1.UserError('Cannot convert a JSON schema with a nested `$id` resource to strict mode because local references are resolved only within the root resource. Remove the nested `$id` or disable strict mode.'); } for (const keyword of unsupportedStrictNormalizationKeywords) { if (keyword in schema) { throw new errors_1.UserError(`Cannot convert a JSON schema using unsupported keyword \`${keyword}\` to strict mode. Remove the keyword or disable strict mode.`); } } if ('$ref' in schema) { if (typeof schema.$ref !== 'string') { throw new errors_1.UserError('Cannot convert a JSON schema with a non-string `$ref` to strict mode.'); } const resolved = resolveLocalJsonSchemaReference(schema.$ref, rootSchema); if (typeof resolved === 'undefined') { throw new errors_1.UserError(`Cannot convert unresolved or external JSON schema reference \`${schema.$ref}\` to strict mode. Use a local reference or disable strict mode.`); } validateOpenAIStrictProviderSchema(resolved, rootSchema, state, depth + 1); } if ('anyOf' in schema) { if (!Array.isArray(schema.anyOf) || schema.anyOf.length === 0) { throw new errors_1.UserError('Cannot convert a JSON schema with an invalid `anyOf` to strict mode.'); } for (const branch of schema.anyOf) { validateOpenAIStrictProviderSchema(branch, rootSchema, state, depth + 1); } } const properties = isRecord(schema.properties) ? schema.properties : undefined; if (properties) { for (const propertySchema of Object.values(properties)) { validateOpenAIStrictProviderSchema(propertySchema, rootSchema, state, depth + 1); } } const items = schema.items; if (Array.isArray(items)) { for (const item of items) { validateOpenAIStrictProviderSchema(item, rootSchema, state, depth + 1); } } else if (typeof items !== 'undefined') { validateOpenAIStrictProviderSchema(items, rootSchema, state, depth + 1); } if ('additionalProperties' in schema) { validateOpenAIStrictProviderSchema(schema.additionalProperties, rootSchema, state, depth + 1); } for (const key of ['$defs', 'definitions']) { const definitions = schema[key]; if (!isRecord(definitions)) { continue; } for (const definition of Object.values(definitions)) { validateOpenAIStrictProviderSchema(definition, rootSchema, state, depth + 1); } } leaveJsonSchemaTraversal(schema, state); } function validateOpenAIStrictJsonSchema(schema, rootSchema, state = createJsonSchemaTraversalState(), requireUnambiguousNormalization = true, rejectOpenObjects = false, depth = 1) { if (typeof schema === 'boolean') { assertSafeJsonSchemaDepth(depth); return; } if (!isRecord(schema) || !enterJsonSchemaTraversal(schema, state, depth)) { return; } if ('$ref' in schema) { if (typeof schema.$ref !== 'string') { throw new errors_1.UserError('Cannot convert a JSON schema with a non-string `$ref` to strict mode.'); } const unsupportedSibling = Object.keys(schema).find((key) => !referenceMetadataKeywords.has(key)); if (unsupportedSibling) { throw new errors_1.UserError(`Cannot convert a JSON schema combining \`$ref\` with sibling keyword \`${unsupportedSibling}\` to strict mode. Move the constraint into the referenced schema or disable strict mode.`); } const resolved = resolveLocalJsonSchemaReference(schema.$ref, rootSchema); if (typeof resolved === 'undefined') { throw new errors_1.UserError(`Cannot convert unresolved or external JSON schema reference \`${schema.$ref}\` to strict mode. Use a local reference or disable strict mode.`); } validateOpenAIStrictJsonSchema(resolved, rootSchema, state, requireUnambiguousNormalization, rejectOpenObjects, depth + 1); } if ('anyOf' in schema) { if (!Array.isArray(schema.anyOf) || schema.anyOf.length === 0) { throw new errors_1.UserError('Cannot convert a JSON schema with an invalid `anyOf` to strict mode.'); } const unsupportedSibling = Object.keys(schema).find((key) => !anyOfMetadataKeywords.has(key)); if (unsupportedSibling) { throw new errors_1.UserError(`Cannot convert a JSON schema combining \`anyOf\` with sibling keyword \`${unsupportedSibling}\` to strict mode. Move the constraint into each branch or disable strict mode.`); } for (const branch of schema.anyOf) { validateOpenAIStrictJsonSchema(branch, rootSchema, state, requireUnambiguousNormalization, rejectOpenObjects, depth + 1); } // Plain JSON Schema tools do not have a runtime validator that selects the // matching branch. Supporting even discriminated branches here would add a // second partial schema interpreter alongside the Zod validation path. if (requireUnambiguousNormalization && schema.anyOf.some((branch) => jsonSchemaRequiresSyntheticNullStripping(branch, rootSchema, createJsonSchemaTraversalState(), depth + 1))) { throw new errors_1.UserError('Cannot convert an `anyOf` branch containing optional object properties to strict mode because plain JSON Schema tools do not select a branch during input normalization. Use a Zod schema, make the branch properties required, or disable strict mode.'); } } const properties = isRecord(schema.properties) ? schema.properties : undefined; const hasObjectType = schema.type === 'object' || (Array.isArray(schema.type) && schema.type.includes('object')); const hasDeclaredProperties = properties !== undefined && Object.keys(properties).length > 0; if (rejectOpenObjects && hasObjectType && schema.additionalProperties !== false && (!hasDeclaredProperties || 'additionalProperties' in schema)) { throw new errors_1.UserError('Cannot convert an open JSON schema object to strict mode without changing its accepted values. Set `additionalProperties: false`, declare at least one property, or disable strict mode.'); } if (schemaConvertsObjectProperties(schema) && properties) { const required = new Set(Array.isArray(schema.required) ? schema.required.map(String) : []); for (const [key, propertySchema] of Object.entries(properties)) { validateOpenAIStrictJsonSchema(propertySchema, rootSchema, state, requireUnambiguousNormalization, rejectOpenObjects, depth + 1); if (!required.has(key)) { getKnownJsonSchemaNullability(propertySchema, rootSchema, depth + 1); } } } const items = schema.items; if (Array.isArray(items)) { for (const item of items) { validateOpenAIStrictJsonSchema(item, rootSchema, state, requireUnambiguousNormalization, rejectOpenObjects, depth + 1); } } else if (typeof items !== 'undefined') { validateOpenAIStrictJsonSchema(items, rootSchema, state, requireUnambiguousNormalization, rejectOpenObjects, depth + 1); } for (const key of ['$defs', 'definitions']) { const definitions = schema[key]; if (!isRecord(definitions)) { continue; } for (const definition of Object.values(definitions)) { validateOpenAIStrictJsonSchema(definition, rootSchema, state, requireUnambiguousNormalization, rejectOpenObjects, depth + 1); } } leaveJsonSchemaTraversal(schema, state); } function getKnownJsonSchemaNullability(schema, rootSchema, depth = 1) { const nullability = getJsonSchemaNullability(schema, rootSchema, new Set(), depth); if (nullability === 'unknown') { throw new errors_1.UserError('Cannot determine whether an optional JSON schema property accepts `null`. Make its nullability explicit with a supported schema form, make the property required, or disable strict mode.'); } return nullability; } function getJsonSchemaNullability(schema, rootSchema, visitedReferences = new Set(), depth = 1) { assertSafeJsonSchemaDepth(depth); if (schema === true) { return 'allows'; } if (schema === false) { return 'disallows'; } if (!isRecord(schema)) { return 'unknown'; } const type = schema.type; if ('type' in schema) { if (typeof type !== 'string' && !Array.isArray(type)) { return 'unknown'; } if (type !== 'null' && !(Array.isArray(type) && type.includes('null'))) { return 'disallows'; } } if ('enum' in schema) { if (!Array.isArray(schema.enum)) { return 'unknown'; } if (!schema.enum.includes(null)) { return 'disallows'; } } if ('const' in schema && schema.const !== null) { return 'disallows'; } if ('$ref' in schema) { const referencedNullability = getReferencedJsonSchemaNullability(schema.$ref, rootSchema, visitedReferences, depth + 1); if (referencedNullability !== 'allows') { return referencedNullability; } } if ('anyOf' in schema) { if (!Array.isArray(schema.anyOf)) { return 'unknown'; } const entries = schema.anyOf.map((entry) => getJsonSchemaNullability(entry, rootSchema, visitedReferences, depth + 1)); if (entries.includes('allows')) { return 'allows'; } return entries.every((entry) => entry === 'disallows') ? 'disallows' : 'unknown'; } // Strict conversion infers an object type for nested schemas that declare // properties. Preserve that released interpretation when deciding whether an // optional property needs a synthetic nullable wrapper. if (!('type' in schema) && isRecord(schema.properties)) { return 'disallows'; } return 'allows'; } function jsonSchemaRequiresSyntheticNullStripping(schema, rootSchema, state = createJsonSchemaTraversalState(), depth = 1) { if (!isRecord(schema) || !enterJsonSchemaTraversal(schema, state, depth)) { return false; } try { if (typeof schema.$ref === 'string') { const resolved = resolveLocalJsonSchemaReference(schema.$ref, rootSchema); return jsonSchemaRequiresSyntheticNullStripping(resolved, rootSchema, state, depth + 1); } if (Array.isArray(schema.anyOf)) { return schema.anyOf.some((branch) => jsonSchemaRequiresSyntheticNullStripping(branch, rootSchema, state, depth + 1)); } const properties = schemaConvertsObjectProperties(schema) && isRecord(schema.properties) ? schema.properties : {}; const required = new Set(Array.isArray(schema.required) ? schema.required.map(String) : []); for (const [key, propertySchema] of Object.entries(properties)) { if ((!required.has(key) && getKnownJsonSchemaNullability(propertySchema, rootSchema, depth + 1) === 'disallows') || jsonSchemaRequiresSyntheticNullStripping(propertySchema, rootSchema, state, depth + 1)) { return true; } } const items = schema.items; return Array.isArray(items) ? items.some((item) => jsonSchemaRequiresSyntheticNullStripping(item, rootSchema, state, depth + 1)) : jsonSchemaRequiresSyntheticNullStripping(items, rootSchema, state, depth + 1); } finally { leaveJsonSchemaTraversal(schema, state); } } function getReferencedJsonSchemaNullability(reference, rootSchema, visitedReferences, depth) { if (typeof reference !== 'string' || visitedReferences.has(reference)) { return 'unknown'; } const resolved = resolveLocalJsonSchemaReference(reference, rootSchema); if (typeof resolved === 'undefined') { return 'unknown'; } return getJsonSchemaNullability(resolved, rootSchema, new Set([...visitedReferences, reference]), depth); } function resolveLocalJsonSchema(schema, context) { let current = schema; const visitedReferences = new Set(); while (isRecord(current) && typeof current.$ref === 'string') { const reference = current.$ref; if (visitedReferences.has(reference)) { return schema; } visitedReferences.add(reference); const resolved = resolveLocalJsonSchemaReference(reference, context.preparedRoot); if (typeof resolved === 'undefined') { return schema; } current = resolved; } return current; } function resolveLocalJsonSchemaReference(reference, rootSchema) { if (!reference.startsWith('#')) { return undefined; } return reference === '#' ? rootSchema : resolveJsonPointer(rootSchema, reference); } function resolveJsonPointer(root, reference) { let current = root; let pointer; try { pointer = decodeURIComponent(reference.slice(1)); } catch { return undefined; } if (!pointer.startsWith('/')) { return undefined; } for (const rawToken of pointer.slice(1).split('/')) { if (/~(?:[^01]|$)/.test(rawToken)) { return undefined; } const token = rawToken.replace(/~1/g, '/').replace(/~0/g, '~'); if (typeof current !== 'object' || current === null || !Object.prototype.hasOwnProperty.call(current, token)) { return undefined; } current = current[token]; } return current; } function stripStrictNullsForZodSchema(schema, value) { const { inner, optional, nullable } = unwrapZodOptionalNullable(schema); if (value === undefined) { return undefined; } if (value === null) { if (optional && !nullable && !zodSchemaAccepts(inner, null)) { return undefined; } return value; } const type = (0, zodCompat_1.readZodType)(inner); const def = (0, zodCompat_1.readZodDefinition)(inner); if ((type === 'union' || type === 'discriminatedunion') && value !== null) { for (const option of readZodUnionOptions(def)) { const normalized = stripStrictNullsForZodSchema(option, value); if (zodSchemaAccepts(option, normalized)) { return normalized; } } } if (type === 'intersection') { const left = stripStrictNullsForZodSchema(def?.left, value); return stripStrictNullsForZodSchema(def?.right, left); } if (type === 'object' && isRecord(value)) { const shape = readShape(inner); if (!shape) { return value; } const normalized = { ...value }; for (const [key, field] of Object.entries(shape)) { const nextValue = stripStrictNullsForZodSchema(field, normalized[key]); if (typeof nextValue === 'undefined') { delete normalized[key]; } else { normalized[key] = nextValue; } } return normalized; } if (type === 'array' && Array.isArray(value)) { const itemSchema = extractFirst(def, 'element', 'items', 'type'); return value.map((entry) => stripStrictNullsForZodSchema(itemSchema, entry)); } if (type === 'tuple' && Array.isArray(value)) { const items = coerceArray(def?.items); return value.map((entry, index) => stripStrictNullsForZodSchema(items[index], entry)); } if (type === 'record' && isRecord(value)) { const valueSchema = def?.valueType ?? def?.values; return Object.fromEntries(Object.entries(value).flatMap(([key, entry]) => { const normalized = stripStrictNullsForZodSchema(valueSchema, entry); return typeof normalized === 'undefined' ? [] : [[key, normalized]]; })); } if (type === 'set' && Array.isArray(value)) { const valueSchema = def?.valueType; return value.map((entry) => stripStrictNullsForZodSchema(valueSchema, entry)); } return value; } function unwrapZodOptionalNullable(schema) { let current = unwrapDecorators(schema); let optional = false; let nullable = false; const visited = new Set(); while (current && typeof current === 'object' && !visited.has(current)) { visited.add(current); const type = (0, zodCompat_1.readZodType)(current); const def = (0, zodCompat_1.readZodDefinition)(current); if (type === 'optional') { optional = true; const next = unwrapDecorators(def?.innerType); if (!next || next === current) { break; } current = next; continue; } if (type === 'nullable') { nullable = true; const next = unwrapDecorators(def?.innerType ?? def?.type); if (!next || next === current) { break; } current = next; continue; } break; } return { inner: current, optional, nullable }; } function unwrapDecorators(schema) { let current = schema; const visited = new Set(); while (current && typeof current === 'object' && !visited.has(current)) { visited.add(current); const type = (0, zodCompat_1.readZodType)(current); if (!type || !new Set([ 'brand', 'branded', 'catch', 'default', 'effects', 'pipeline', 'pipe', 'prefault', 'readonly', 'refinement', 'transform', ]).has(type)) { break; } const def = (0, zodCompat_1.readZodDefinition)(current); const next = def?.innerType ?? def?.schema ?? def?.base ?? def?.type ?? def?.wrapped ?? def?.underlying; if (!next || next === current) { break; } current = next; } return current; } function extractFirst(def, ...keys) { if (!def) { return undefined; } for (const key of keys) { if (key in def && def[key] !== undefined) { return def[key]; } } return undefined; } function coerceArray(value) { if (Array.isArray(value)) { return value; } return value === undefined ? [] : [value]; } function readZodUnionOptions(def) { const options = def?.options; if (Array.isArray(options)) { return options; } if (options instanceof Map) { return [...options.values()]; } if (options && typeof options === 'object') { return Object.values(options); } const optionsMap = def?.optionsMap; if (optionsMap instanceof Map) { return [...optionsMap.values()]; } if (optionsMap && typeof optionsMap === 'object') { return Object.values(optionsMap); } return []; } function zodSchemaAccepts(schema, value) { const candidate = unwrapDecorators(schema); if (typeof candidate?.safeParse === 'function') { try { return candidate.safeParse(value).success; } catch { return false; } } if (typeof candidate?.parse === 'function') { try { candidate.parse(value); return true; } catch { return false; } } return false; } function readShape(input) { if (typeof input !== 'object' || input === null) { return undefined; } const candidate = input; if (candidate.shape && typeof candidate.shape === 'object') { return candidate.shape; } if (typeof candidate.shape === 'function') { try { return candidate.shape(); } catch { return undefined; } } const def = (0, zodCompat_1.readZodDefinition)(candidate); const shape = def?.shape; if (shape && typeof shape === 'object') { return shape; } if (typeof shape === 'function') { try { return shape(); } catch { return undefined; } } return undefined; } function isRecord(value) { return typeof value === 'object' && value !== null && !Array.isArray(value); } //# sourceMappingURL=strictToolSchema.js.map