@livekit/agents 1.0.14 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/dist/cli.cjs +12 -12
  2. package/dist/cli.cjs.map +1 -1
  3. package/dist/cli.d.cts +3 -3
  4. package/dist/cli.d.ts +3 -3
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +13 -13
  7. package/dist/cli.js.map +1 -1
  8. package/dist/inference/stt.cjs.map +1 -1
  9. package/dist/inference/stt.d.ts.map +1 -1
  10. package/dist/inference/stt.js +1 -1
  11. package/dist/inference/stt.js.map +1 -1
  12. package/dist/inference/tts.cjs.map +1 -1
  13. package/dist/inference/tts.d.cts +2 -1
  14. package/dist/inference/tts.d.ts +2 -1
  15. package/dist/inference/tts.d.ts.map +1 -1
  16. package/dist/inference/tts.js +1 -5
  17. package/dist/inference/tts.js.map +1 -1
  18. package/dist/llm/chat_context.cjs +78 -0
  19. package/dist/llm/chat_context.cjs.map +1 -1
  20. package/dist/llm/chat_context.d.cts +16 -0
  21. package/dist/llm/chat_context.d.ts +16 -0
  22. package/dist/llm/chat_context.d.ts.map +1 -1
  23. package/dist/llm/chat_context.js +78 -0
  24. package/dist/llm/chat_context.js.map +1 -1
  25. package/dist/llm/chat_context.test.cjs +531 -0
  26. package/dist/llm/chat_context.test.cjs.map +1 -1
  27. package/dist/llm/chat_context.test.js +531 -0
  28. package/dist/llm/chat_context.test.js.map +1 -1
  29. package/dist/llm/tool_context.cjs +43 -2
  30. package/dist/llm/tool_context.cjs.map +1 -1
  31. package/dist/llm/tool_context.d.cts +39 -11
  32. package/dist/llm/tool_context.d.ts +39 -11
  33. package/dist/llm/tool_context.d.ts.map +1 -1
  34. package/dist/llm/tool_context.js +42 -3
  35. package/dist/llm/tool_context.js.map +1 -1
  36. package/dist/llm/tool_context.test.cjs +197 -0
  37. package/dist/llm/tool_context.test.cjs.map +1 -1
  38. package/dist/llm/tool_context.test.js +175 -0
  39. package/dist/llm/tool_context.test.js.map +1 -1
  40. package/dist/llm/utils.cjs +17 -11
  41. package/dist/llm/utils.cjs.map +1 -1
  42. package/dist/llm/utils.d.cts +1 -2
  43. package/dist/llm/utils.d.ts +1 -2
  44. package/dist/llm/utils.d.ts.map +1 -1
  45. package/dist/llm/utils.js +17 -11
  46. package/dist/llm/utils.js.map +1 -1
  47. package/dist/llm/zod-utils.cjs +99 -0
  48. package/dist/llm/zod-utils.cjs.map +1 -0
  49. package/dist/llm/zod-utils.d.cts +65 -0
  50. package/dist/llm/zod-utils.d.ts +65 -0
  51. package/dist/llm/zod-utils.d.ts.map +1 -0
  52. package/dist/llm/zod-utils.js +61 -0
  53. package/dist/llm/zod-utils.js.map +1 -0
  54. package/dist/llm/zod-utils.test.cjs +389 -0
  55. package/dist/llm/zod-utils.test.cjs.map +1 -0
  56. package/dist/llm/zod-utils.test.js +372 -0
  57. package/dist/llm/zod-utils.test.js.map +1 -0
  58. package/dist/metrics/base.cjs.map +1 -1
  59. package/dist/metrics/base.d.cts +7 -0
  60. package/dist/metrics/base.d.ts +7 -0
  61. package/dist/metrics/base.d.ts.map +1 -1
  62. package/dist/stt/stt.cjs +1 -0
  63. package/dist/stt/stt.cjs.map +1 -1
  64. package/dist/stt/stt.d.cts +7 -1
  65. package/dist/stt/stt.d.ts +7 -1
  66. package/dist/stt/stt.d.ts.map +1 -1
  67. package/dist/stt/stt.js +1 -0
  68. package/dist/stt/stt.js.map +1 -1
  69. package/dist/vad.cjs +16 -0
  70. package/dist/vad.cjs.map +1 -1
  71. package/dist/vad.d.cts +6 -0
  72. package/dist/vad.d.ts +6 -0
  73. package/dist/vad.d.ts.map +1 -1
  74. package/dist/vad.js +16 -0
  75. package/dist/vad.js.map +1 -1
  76. package/dist/voice/agent_activity.cjs +83 -8
  77. package/dist/voice/agent_activity.cjs.map +1 -1
  78. package/dist/voice/agent_activity.d.cts +6 -2
  79. package/dist/voice/agent_activity.d.ts +6 -2
  80. package/dist/voice/agent_activity.d.ts.map +1 -1
  81. package/dist/voice/agent_activity.js +83 -8
  82. package/dist/voice/agent_activity.js.map +1 -1
  83. package/dist/voice/agent_session.cjs +3 -2
  84. package/dist/voice/agent_session.cjs.map +1 -1
  85. package/dist/voice/agent_session.d.cts +2 -1
  86. package/dist/voice/agent_session.d.ts +2 -1
  87. package/dist/voice/agent_session.d.ts.map +1 -1
  88. package/dist/voice/agent_session.js +3 -2
  89. package/dist/voice/agent_session.js.map +1 -1
  90. package/dist/voice/audio_recognition.cjs +138 -16
  91. package/dist/voice/audio_recognition.cjs.map +1 -1
  92. package/dist/voice/audio_recognition.d.cts +11 -0
  93. package/dist/voice/audio_recognition.d.ts +11 -0
  94. package/dist/voice/audio_recognition.d.ts.map +1 -1
  95. package/dist/voice/audio_recognition.js +138 -16
  96. package/dist/voice/audio_recognition.js.map +1 -1
  97. package/dist/voice/generation.cjs +8 -3
  98. package/dist/voice/generation.cjs.map +1 -1
  99. package/dist/voice/generation.d.ts.map +1 -1
  100. package/dist/voice/generation.js +8 -3
  101. package/dist/voice/generation.js.map +1 -1
  102. package/dist/voice/room_io/_input.cjs.map +1 -1
  103. package/dist/voice/room_io/_input.d.ts.map +1 -1
  104. package/dist/voice/room_io/_input.js +0 -1
  105. package/dist/voice/room_io/_input.js.map +1 -1
  106. package/dist/worker.cjs +17 -11
  107. package/dist/worker.cjs.map +1 -1
  108. package/dist/worker.d.cts +16 -9
  109. package/dist/worker.d.ts +16 -9
  110. package/dist/worker.d.ts.map +1 -1
  111. package/dist/worker.js +16 -12
  112. package/dist/worker.js.map +1 -1
  113. package/package.json +5 -4
  114. package/src/cli.ts +17 -17
  115. package/src/inference/stt.ts +2 -1
  116. package/src/inference/tts.ts +2 -5
  117. package/src/llm/__snapshots__/zod-utils.test.ts.snap +341 -0
  118. package/src/llm/chat_context.test.ts +607 -0
  119. package/src/llm/chat_context.ts +106 -0
  120. package/src/llm/tool_context.test.ts +210 -1
  121. package/src/llm/tool_context.ts +101 -17
  122. package/src/llm/utils.ts +18 -15
  123. package/src/llm/zod-utils.test.ts +476 -0
  124. package/src/llm/zod-utils.ts +144 -0
  125. package/src/metrics/base.ts +7 -0
  126. package/src/stt/stt.ts +6 -0
  127. package/src/vad.ts +18 -0
  128. package/src/voice/agent_activity.ts +119 -9
  129. package/src/voice/agent_session.ts +3 -1
  130. package/src/voice/audio_recognition.ts +235 -57
  131. package/src/voice/generation.ts +8 -3
  132. package/src/voice/room_io/_input.ts +1 -1
  133. package/src/worker.ts +29 -18
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/llm/utils.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { VideoBufferType, VideoFrame } from '@livekit/rtc-node';\nimport type { JSONSchema7 } from 'json-schema';\nimport sharp from 'sharp';\nimport { ZodObject } from 'zod';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport type { UnknownUserData } from '../voice/run_context.js';\nimport type { ChatContext } from './chat_context.js';\nimport {\n type ChatItem,\n FunctionCall,\n FunctionCallOutput,\n type ImageContent,\n} from './chat_context.js';\nimport type { ToolContext, ToolInputSchema, ToolOptions } from './tool_context.js';\n\nexport interface SerializedImage {\n inferenceDetail: 'auto' | 'high' | 'low';\n mimeType?: string;\n base64Data?: string;\n externalUrl?: string;\n}\n\nfunction getChannelsFromVideoBufferType(type: VideoBufferType): 3 | 4 {\n switch (type) {\n case VideoBufferType.RGBA:\n case VideoBufferType.ABGR:\n case VideoBufferType.ARGB:\n case VideoBufferType.BGRA:\n return 4;\n case VideoBufferType.RGB24:\n return 3;\n default:\n // YUV formats (I420, I420A, I422, I444, I010, NV12) need conversion\n throw new Error(`Unsupported VideoBufferType: ${type}. Only RGB/RGBA formats are supported.`);\n }\n}\n\nfunction ensureRGBCompatible(frame: VideoFrame): VideoFrame {\n // If the frame is already in an RGB/RGBA-compatible format, return it directly\n if (\n frame.type === VideoBufferType.RGBA ||\n frame.type === VideoBufferType.BGRA ||\n frame.type === VideoBufferType.ARGB ||\n frame.type === VideoBufferType.ABGR ||\n frame.type === VideoBufferType.RGB24\n ) {\n return frame;\n }\n\n // Otherwise, attempt conversion for other formats (like YUV)\n try {\n return frame.convert(VideoBufferType.RGBA);\n } catch (error) {\n throw new Error(\n `Failed to convert format ${frame.type} to RGB: ${error}. ` +\n `Consider using RGB/RGBA formats or converting on the client side.`,\n );\n }\n}\n\nexport async function serializeImage(image: ImageContent): Promise<SerializedImage> {\n if (typeof image.image === 'string') {\n if (image.image.startsWith('data:')) {\n const [header, base64Data] = image.image.split(',', 2) as [string, string];\n const headerParts = header.split(';');\n const mimeParts = headerParts[0]?.split(':');\n const headerMime = mimeParts?.[1];\n\n if (!headerMime) {\n throw new Error('Invalid data URL format');\n }\n\n let mimeType: string;\n if (image.mimeType && image.mimeType !== headerMime) {\n console.warn(\n `Provided mimeType '${image.mimeType}' does not match data URL mime type '${headerMime}'. Using provided mimeType.`,\n );\n mimeType = image.mimeType;\n } else {\n mimeType = headerMime;\n }\n\n const supportedTypes = new Set(['image/jpeg', 'image/png', 'image/webp', 'image/gif']);\n if (!supportedTypes.has(mimeType)) {\n throw new Error(`Unsupported mimeType ${mimeType}. Must be jpeg, png, webp, or gif`);\n }\n\n return {\n base64Data,\n mimeType: mimeType,\n inferenceDetail: image.inferenceDetail,\n };\n }\n\n // External URL\n return {\n mimeType: image.mimeType,\n inferenceDetail: image.inferenceDetail,\n externalUrl: image.image,\n };\n } else if (image.image instanceof VideoFrame) {\n const frame = ensureRGBCompatible(image.image);\n const channels = getChannelsFromVideoBufferType(frame.type);\n\n // Sharp needs to know the format of raw pixel data\n let encoded = sharp(frame.data, {\n raw: {\n width: frame.width,\n height: frame.height,\n channels,\n },\n });\n\n if (image.inferenceWidth && image.inferenceHeight) {\n encoded = encoded.resize(image.inferenceWidth, image.inferenceHeight);\n }\n\n const base64Data = await encoded\n .png()\n .toBuffer()\n .then((buffer) => buffer.toString('base64'));\n\n return {\n base64Data,\n mimeType: 'image/png',\n inferenceDetail: image.inferenceDetail,\n };\n } else {\n throw new Error('Unsupported image type');\n }\n}\n\n/** Raw OpenAI-adherent function parameters. */\nexport type OpenAIFunctionParameters = {\n type: 'object';\n properties: { [id: string]: any }; // eslint-disable-line @typescript-eslint/no-explicit-any\n required: string[];\n additionalProperties?: boolean;\n};\n\n// TODO(brian): remove this helper once we have the real RunContext user data\nexport const createToolOptions = <UserData extends UnknownUserData>(\n toolCallId: string,\n userData: UserData = {} as UserData,\n): ToolOptions<UserData> => {\n return { ctx: { userData }, toolCallId } as unknown as ToolOptions<UserData>;\n};\n\n/** @internal */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const oaiParams = (\n p: ZodObject<any>,\n isOpenai: boolean = true,\n): OpenAIFunctionParameters => {\n // Adapted from https://github.com/vercel/ai/blob/56eb0ee9/packages/provider-utils/src/zod-schema.ts\n const { properties, required, additionalProperties } = zodToJsonSchema(p, {\n // note: openai mode breaks various gemini conversions\n target: isOpenai ? 'openAi' : 'jsonSchema7',\n }) as OpenAIFunctionParameters;\n\n return {\n type: 'object',\n properties,\n required,\n additionalProperties,\n };\n};\n\n/** @internal */\nexport const oaiBuildFunctionInfo = (\n toolCtx: ToolContext,\n toolCallId: string,\n toolName: string,\n rawArgs: string,\n): FunctionCall => {\n const tool = toolCtx[toolName];\n if (!tool) {\n throw new Error(`AI tool ${toolName} not found`);\n }\n\n return FunctionCall.create({\n callId: toolCallId,\n name: toolName,\n args: rawArgs,\n });\n};\n\nexport async function executeToolCall(\n toolCall: FunctionCall,\n toolCtx: ToolContext,\n): Promise<FunctionCallOutput> {\n const tool = toolCtx[toolCall.name]!;\n let args: object | undefined;\n let params: object | undefined;\n\n // Ensure valid JSON\n try {\n args = JSON.parse(toolCall.args);\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Invalid JSON: ${error}`,\n isError: true,\n });\n }\n\n // Ensure valid arguments schema\n try {\n if (tool.parameters instanceof ZodObject) {\n params = tool.parameters.parse(args);\n } else {\n params = args;\n }\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Arguments parsing failed: ${error}`,\n isError: true,\n });\n }\n\n try {\n const result = await tool.execute(params, createToolOptions(toolCall.callId));\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: JSON.stringify(result),\n isError: false,\n });\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Tool execution failed: ${error}`,\n isError: true,\n });\n }\n}\n\n/**\n * Standard dynamic-programming LCS to get the common subsequence\n * of IDs (in order) that appear in both old_ids and new_ids.\n *\n * @param oldIds - The old list of IDs.\n * @param newIds - The new list of IDs.\n * @returns The longest common subsequence of the two lists of IDs.\n */\nfunction computeLCS(oldIds: string[], newIds: string[]): string[] {\n const n = oldIds.length;\n const m = newIds.length;\n const dp: number[][] = Array(n + 1)\n .fill(null)\n .map(() => Array(m + 1).fill(0));\n\n // Fill DP table\n for (let i = 1; i <= n; i++) {\n for (let j = 1; j <= m; j++) {\n if (oldIds[i - 1] === newIds[j - 1]) {\n dp[i]![j] = dp[i - 1]![j - 1]! + 1;\n } else {\n dp[i]![j] = Math.max(dp[i - 1]![j]!, dp[i]![j - 1]!);\n }\n }\n }\n\n // Backtrack to find the actual LCS sequence\n const lcsIds: string[] = [];\n let i = n;\n let j = m;\n while (i > 0 && j > 0) {\n if (oldIds[i - 1] === newIds[j - 1]) {\n lcsIds.push(oldIds[i - 1]!);\n i--;\n j--;\n } else if (dp[i - 1]![j]! > dp[i]![j - 1]!) {\n i--;\n } else {\n j--;\n }\n }\n\n return lcsIds.reverse();\n}\n\ninterface DiffOps {\n toRemove: string[];\n toCreate: Array<[string | null, string]>; // (previous_item_id, id), if previous_item_id is null, add to the root\n}\n\n/**\n * Compute the minimal list of create/remove operations to transform oldCtx into newCtx.\n *\n * @param oldCtx - The old chat context.\n * @param newCtx - The new chat context.\n * @returns The minimal list of create/remove operations to transform oldCtx into newCtx.\n */\nexport function computeChatCtxDiff(oldCtx: ChatContext, newCtx: ChatContext): DiffOps {\n const oldIds = oldCtx.items.map((item: ChatItem) => item.id);\n const newIds = newCtx.items.map((item: ChatItem) => item.id);\n const lcsIds = new Set(computeLCS(oldIds, newIds));\n\n const toRemove = oldCtx.items.filter((msg) => !lcsIds.has(msg.id)).map((msg) => msg.id);\n const toCreate: Array<[string | null, string]> = [];\n\n let lastIdInSequence: string | null = null;\n for (const newItem of newCtx.items) {\n if (lcsIds.has(newItem.id)) {\n lastIdInSequence = newItem.id;\n } else {\n const prevId = lastIdInSequence; // null if root\n toCreate.push([prevId, newItem.id]);\n lastIdInSequence = newItem.id;\n }\n }\n\n return {\n toRemove,\n toCreate,\n };\n}\n\nexport function toJsonSchema(schema: ToolInputSchema<any>, isOpenai: boolean = true): JSONSchema7 {\n if (schema instanceof ZodObject) {\n return oaiParams(schema, isOpenai);\n }\n return schema;\n}\n"],"mappings":"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","names":["sharp","i","j"]}
1
+ {"version":3,"sources":["../../src/llm/utils.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { VideoBufferType, VideoFrame } from '@livekit/rtc-node';\nimport type { JSONSchema7 } from 'json-schema';\nimport sharp from 'sharp';\nimport type { UnknownUserData } from '../voice/run_context.js';\nimport type { ChatContext } from './chat_context.js';\nimport {\n type ChatItem,\n FunctionCall,\n FunctionCallOutput,\n type ImageContent,\n} from './chat_context.js';\nimport type { ToolContext, ToolInputSchema, ToolOptions } from './tool_context.js';\nimport { isZodSchema, parseZodSchema, zodSchemaToJsonSchema } from './zod-utils.js';\n\nexport interface SerializedImage {\n inferenceDetail: 'auto' | 'high' | 'low';\n mimeType?: string;\n base64Data?: string;\n externalUrl?: string;\n}\n\nfunction getChannelsFromVideoBufferType(type: VideoBufferType): 3 | 4 {\n switch (type) {\n case VideoBufferType.RGBA:\n case VideoBufferType.ABGR:\n case VideoBufferType.ARGB:\n case VideoBufferType.BGRA:\n return 4;\n case VideoBufferType.RGB24:\n return 3;\n default:\n // YUV formats (I420, I420A, I422, I444, I010, NV12) need conversion\n throw new Error(`Unsupported VideoBufferType: ${type}. Only RGB/RGBA formats are supported.`);\n }\n}\n\nfunction ensureRGBCompatible(frame: VideoFrame): VideoFrame {\n // If the frame is already in an RGB/RGBA-compatible format, return it directly\n if (\n frame.type === VideoBufferType.RGBA ||\n frame.type === VideoBufferType.BGRA ||\n frame.type === VideoBufferType.ARGB ||\n frame.type === VideoBufferType.ABGR ||\n frame.type === VideoBufferType.RGB24\n ) {\n return frame;\n }\n\n // Otherwise, attempt conversion for other formats (like YUV)\n try {\n return frame.convert(VideoBufferType.RGBA);\n } catch (error) {\n throw new Error(\n `Failed to convert format ${frame.type} to RGB: ${error}. ` +\n `Consider using RGB/RGBA formats or converting on the client side.`,\n );\n }\n}\n\nexport async function serializeImage(image: ImageContent): Promise<SerializedImage> {\n if (typeof image.image === 'string') {\n if (image.image.startsWith('data:')) {\n const [header, base64Data] = image.image.split(',', 2) as [string, string];\n const headerParts = header.split(';');\n const mimeParts = headerParts[0]?.split(':');\n const headerMime = mimeParts?.[1];\n\n if (!headerMime) {\n throw new Error('Invalid data URL format');\n }\n\n let mimeType: string;\n if (image.mimeType && image.mimeType !== headerMime) {\n console.warn(\n `Provided mimeType '${image.mimeType}' does not match data URL mime type '${headerMime}'. Using provided mimeType.`,\n );\n mimeType = image.mimeType;\n } else {\n mimeType = headerMime;\n }\n\n const supportedTypes = new Set(['image/jpeg', 'image/png', 'image/webp', 'image/gif']);\n if (!supportedTypes.has(mimeType)) {\n throw new Error(`Unsupported mimeType ${mimeType}. Must be jpeg, png, webp, or gif`);\n }\n\n return {\n base64Data,\n mimeType: mimeType,\n inferenceDetail: image.inferenceDetail,\n };\n }\n\n // External URL\n return {\n mimeType: image.mimeType,\n inferenceDetail: image.inferenceDetail,\n externalUrl: image.image,\n };\n } else if (image.image instanceof VideoFrame) {\n const frame = ensureRGBCompatible(image.image);\n const channels = getChannelsFromVideoBufferType(frame.type);\n\n // Sharp needs to know the format of raw pixel data\n let encoded = sharp(frame.data, {\n raw: {\n width: frame.width,\n height: frame.height,\n channels,\n },\n });\n\n if (image.inferenceWidth && image.inferenceHeight) {\n encoded = encoded.resize(image.inferenceWidth, image.inferenceHeight);\n }\n\n const base64Data = await encoded\n .png()\n .toBuffer()\n .then((buffer) => buffer.toString('base64'));\n\n return {\n base64Data,\n mimeType: 'image/png',\n inferenceDetail: image.inferenceDetail,\n };\n } else {\n throw new Error('Unsupported image type');\n }\n}\n\n/** Raw OpenAI-adherent function parameters. */\nexport type OpenAIFunctionParameters = {\n type: 'object';\n properties: { [id: string]: any }; // eslint-disable-line @typescript-eslint/no-explicit-any\n required: string[];\n additionalProperties?: boolean;\n};\n\n// TODO(brian): remove this helper once we have the real RunContext user data\nexport const createToolOptions = <UserData extends UnknownUserData>(\n toolCallId: string,\n userData: UserData = {} as UserData,\n): ToolOptions<UserData> => {\n return { ctx: { userData }, toolCallId } as unknown as ToolOptions<UserData>;\n};\n\n/** @internal */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const oaiParams = (schema: any, isOpenai: boolean = true): OpenAIFunctionParameters => {\n // Adapted from https://github.com/vercel/ai/blob/56eb0ee9/packages/provider-utils/src/zod-schema.ts\n const jsonSchema = zodSchemaToJsonSchema(schema, isOpenai);\n const { properties, required, additionalProperties } = jsonSchema as OpenAIFunctionParameters;\n\n return {\n type: 'object',\n properties,\n required,\n additionalProperties,\n };\n};\n\n/** @internal */\nexport const oaiBuildFunctionInfo = (\n toolCtx: ToolContext,\n toolCallId: string,\n toolName: string,\n rawArgs: string,\n): FunctionCall => {\n const tool = toolCtx[toolName];\n if (!tool) {\n throw new Error(`AI tool ${toolName} not found`);\n }\n\n return FunctionCall.create({\n callId: toolCallId,\n name: toolName,\n args: rawArgs,\n });\n};\n\nexport async function executeToolCall(\n toolCall: FunctionCall,\n toolCtx: ToolContext,\n): Promise<FunctionCallOutput> {\n const tool = toolCtx[toolCall.name]!;\n let args: object | undefined;\n let params: object | undefined;\n\n // Ensure valid JSON\n try {\n args = JSON.parse(toolCall.args);\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Invalid JSON: ${error}`,\n isError: true,\n });\n }\n\n // Ensure valid arguments schema\n try {\n if (isZodSchema(tool.parameters)) {\n const result = await parseZodSchema<object>(tool.parameters, args);\n if (result.success) {\n params = result.data;\n } else {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Arguments parsing failed: ${result.error}`,\n isError: true,\n });\n }\n } else {\n params = args;\n }\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Arguments parsing failed: ${error}`,\n isError: true,\n });\n }\n\n try {\n const result = await tool.execute(params, createToolOptions(toolCall.callId));\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: JSON.stringify(result),\n isError: false,\n });\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Tool execution failed: ${error}`,\n isError: true,\n });\n }\n}\n\n/**\n * Standard dynamic-programming LCS to get the common subsequence\n * of IDs (in order) that appear in both old_ids and new_ids.\n *\n * @param oldIds - The old list of IDs.\n * @param newIds - The new list of IDs.\n * @returns The longest common subsequence of the two lists of IDs.\n */\nfunction computeLCS(oldIds: string[], newIds: string[]): string[] {\n const n = oldIds.length;\n const m = newIds.length;\n const dp: number[][] = Array(n + 1)\n .fill(null)\n .map(() => Array(m + 1).fill(0));\n\n // Fill DP table\n for (let i = 1; i <= n; i++) {\n for (let j = 1; j <= m; j++) {\n if (oldIds[i - 1] === newIds[j - 1]) {\n dp[i]![j] = dp[i - 1]![j - 1]! + 1;\n } else {\n dp[i]![j] = Math.max(dp[i - 1]![j]!, dp[i]![j - 1]!);\n }\n }\n }\n\n // Backtrack to find the actual LCS sequence\n const lcsIds: string[] = [];\n let i = n;\n let j = m;\n while (i > 0 && j > 0) {\n if (oldIds[i - 1] === newIds[j - 1]) {\n lcsIds.push(oldIds[i - 1]!);\n i--;\n j--;\n } else if (dp[i - 1]![j]! > dp[i]![j - 1]!) {\n i--;\n } else {\n j--;\n }\n }\n\n return lcsIds.reverse();\n}\n\ninterface DiffOps {\n toRemove: string[];\n toCreate: Array<[string | null, string]>; // (previous_item_id, id), if previous_item_id is null, add to the root\n}\n\n/**\n * Compute the minimal list of create/remove operations to transform oldCtx into newCtx.\n *\n * @param oldCtx - The old chat context.\n * @param newCtx - The new chat context.\n * @returns The minimal list of create/remove operations to transform oldCtx into newCtx.\n */\nexport function computeChatCtxDiff(oldCtx: ChatContext, newCtx: ChatContext): DiffOps {\n const oldIds = oldCtx.items.map((item: ChatItem) => item.id);\n const newIds = newCtx.items.map((item: ChatItem) => item.id);\n const lcsIds = new Set(computeLCS(oldIds, newIds));\n\n const toRemove = oldCtx.items.filter((msg) => !lcsIds.has(msg.id)).map((msg) => msg.id);\n const toCreate: Array<[string | null, string]> = [];\n\n let lastIdInSequence: string | null = null;\n for (const newItem of newCtx.items) {\n if (lcsIds.has(newItem.id)) {\n lastIdInSequence = newItem.id;\n } else {\n const prevId = lastIdInSequence; // null if root\n toCreate.push([prevId, newItem.id]);\n lastIdInSequence = newItem.id;\n }\n }\n\n return {\n toRemove,\n toCreate,\n };\n}\n\nexport function toJsonSchema(schema: ToolInputSchema<any>, isOpenai: boolean = true): JSONSchema7 {\n if (isZodSchema(schema)) {\n return zodSchemaToJsonSchema(schema, isOpenai);\n }\n return schema as JSONSchema7;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,sBAA4C;AAE5C,mBAAkB;AAGlB,0BAKO;AAEP,uBAAmE;AASnE,SAAS,+BAA+B,MAA8B;AACpE,UAAQ,MAAM;AAAA,IACZ,KAAK,gCAAgB;AAAA,IACrB,KAAK,gCAAgB;AAAA,IACrB,KAAK,gCAAgB;AAAA,IACrB,KAAK,gCAAgB;AACnB,aAAO;AAAA,IACT,KAAK,gCAAgB;AACnB,aAAO;AAAA,IACT;AAEE,YAAM,IAAI,MAAM,gCAAgC,IAAI,wCAAwC;AAAA,EAChG;AACF;AAEA,SAAS,oBAAoB,OAA+B;AAE1D,MACE,MAAM,SAAS,gCAAgB,QAC/B,MAAM,SAAS,gCAAgB,QAC/B,MAAM,SAAS,gCAAgB,QAC/B,MAAM,SAAS,gCAAgB,QAC/B,MAAM,SAAS,gCAAgB,OAC/B;AACA,WAAO;AAAA,EACT;AAGA,MAAI;AACF,WAAO,MAAM,QAAQ,gCAAgB,IAAI;AAAA,EAC3C,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,4BAA4B,MAAM,IAAI,YAAY,KAAK;AAAA,IAEzD;AAAA,EACF;AACF;AAEA,eAAsB,eAAe,OAA+C;AA9DpF;AA+DE,MAAI,OAAO,MAAM,UAAU,UAAU;AACnC,QAAI,MAAM,MAAM,WAAW,OAAO,GAAG;AACnC,YAAM,CAAC,QAAQ,UAAU,IAAI,MAAM,MAAM,MAAM,KAAK,CAAC;AACrD,YAAM,cAAc,OAAO,MAAM,GAAG;AACpC,YAAM,aAAY,iBAAY,CAAC,MAAb,mBAAgB,MAAM;AACxC,YAAM,aAAa,uCAAY;AAE/B,UAAI,CAAC,YAAY;AACf,cAAM,IAAI,MAAM,yBAAyB;AAAA,MAC3C;AAEA,UAAI;AACJ,UAAI,MAAM,YAAY,MAAM,aAAa,YAAY;AACnD,gBAAQ;AAAA,UACN,sBAAsB,MAAM,QAAQ,wCAAwC,UAAU;AAAA,QACxF;AACA,mBAAW,MAAM;AAAA,MACnB,OAAO;AACL,mBAAW;AAAA,MACb;AAEA,YAAM,iBAAiB,oBAAI,IAAI,CAAC,cAAc,aAAa,cAAc,WAAW,CAAC;AACrF,UAAI,CAAC,eAAe,IAAI,QAAQ,GAAG;AACjC,cAAM,IAAI,MAAM,wBAAwB,QAAQ,mCAAmC;AAAA,MACrF;AAEA,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,iBAAiB,MAAM;AAAA,MACzB;AAAA,IACF;AAGA,WAAO;AAAA,MACL,UAAU,MAAM;AAAA,MAChB,iBAAiB,MAAM;AAAA,MACvB,aAAa,MAAM;AAAA,IACrB;AAAA,EACF,WAAW,MAAM,iBAAiB,4BAAY;AAC5C,UAAM,QAAQ,oBAAoB,MAAM,KAAK;AAC7C,UAAM,WAAW,+BAA+B,MAAM,IAAI;AAG1D,QAAI,cAAU,aAAAA,SAAM,MAAM,MAAM;AAAA,MAC9B,KAAK;AAAA,QACH,OAAO,MAAM;AAAA,QACb,QAAQ,MAAM;AAAA,QACd;AAAA,MACF;AAAA,IACF,CAAC;AAED,QAAI,MAAM,kBAAkB,MAAM,iBAAiB;AACjD,gBAAU,QAAQ,OAAO,MAAM,gBAAgB,MAAM,eAAe;AAAA,IACtE;AAEA,UAAM,aAAa,MAAM,QACtB,IAAI,EACJ,SAAS,EACT,KAAK,CAAC,WAAW,OAAO,SAAS,QAAQ,CAAC;AAE7C,WAAO;AAAA,MACL;AAAA,MACA,UAAU;AAAA,MACV,iBAAiB,MAAM;AAAA,IACzB;AAAA,EACF,OAAO;AACL,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AACF;AAWO,MAAM,oBAAoB,CAC/B,YACA,WAAqB,CAAC,MACI;AAC1B,SAAO,EAAE,KAAK,EAAE,SAAS,GAAG,WAAW;AACzC;AAIO,MAAM,YAAY,CAAC,QAAa,WAAoB,SAAmC;AAE5F,QAAM,iBAAa,wCAAsB,QAAQ,QAAQ;AACzD,QAAM,EAAE,YAAY,UAAU,qBAAqB,IAAI;AAEvD,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAGO,MAAM,uBAAuB,CAClC,SACA,YACA,UACA,YACiB;AACjB,QAAM,OAAO,QAAQ,QAAQ;AAC7B,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,WAAW,QAAQ,YAAY;AAAA,EACjD;AAEA,SAAO,iCAAa,OAAO;AAAA,IACzB,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,MAAM;AAAA,EACR,CAAC;AACH;AAEA,eAAsB,gBACpB,UACA,SAC6B;AAC7B,QAAM,OAAO,QAAQ,SAAS,IAAI;AAClC,MAAI;AACJ,MAAI;AAGJ,MAAI;AACF,WAAO,KAAK,MAAM,SAAS,IAAI;AAAA,EACjC,SAAS,OAAO;AACd,WAAO,uCAAmB,OAAO;AAAA,MAC/B,QAAQ,SAAS;AAAA,MACjB,QAAQ,iBAAiB,KAAK;AAAA,MAC9B,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAGA,MAAI;AACF,YAAI,8BAAY,KAAK,UAAU,GAAG;AAChC,YAAM,SAAS,UAAM,iCAAuB,KAAK,YAAY,IAAI;AACjE,UAAI,OAAO,SAAS;AAClB,iBAAS,OAAO;AAAA,MAClB,OAAO;AACL,eAAO,uCAAmB,OAAO;AAAA,UAC/B,QAAQ,SAAS;AAAA,UACjB,QAAQ,6BAA6B,OAAO,KAAK;AAAA,UACjD,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF,OAAO;AACL,eAAS;AAAA,IACX;AAAA,EACF,SAAS,OAAO;AACd,WAAO,uCAAmB,OAAO;AAAA,MAC/B,QAAQ,SAAS;AAAA,MACjB,QAAQ,6BAA6B,KAAK;AAAA,MAC1C,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,MAAI;AACF,UAAM,SAAS,MAAM,KAAK,QAAQ,QAAQ,kBAAkB,SAAS,MAAM,CAAC;AAC5E,WAAO,uCAAmB,OAAO;AAAA,MAC/B,QAAQ,SAAS;AAAA,MACjB,QAAQ,KAAK,UAAU,MAAM;AAAA,MAC7B,SAAS;AAAA,IACX,CAAC;AAAA,EACH,SAAS,OAAO;AACd,WAAO,uCAAmB,OAAO;AAAA,MAC/B,QAAQ,SAAS;AAAA,MACjB,QAAQ,0BAA0B,KAAK;AAAA,MACvC,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF;AAUA,SAAS,WAAW,QAAkB,QAA4B;AAChE,QAAM,IAAI,OAAO;AACjB,QAAM,IAAI,OAAO;AACjB,QAAM,KAAiB,MAAM,IAAI,CAAC,EAC/B,KAAK,IAAI,EACT,IAAI,MAAM,MAAM,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;AAGjC,WAASC,KAAI,GAAGA,MAAK,GAAGA,MAAK;AAC3B,aAASC,KAAI,GAAGA,MAAK,GAAGA,MAAK;AAC3B,UAAI,OAAOD,KAAI,CAAC,MAAM,OAAOC,KAAI,CAAC,GAAG;AACnC,WAAGD,EAAC,EAAGC,EAAC,IAAI,GAAGD,KAAI,CAAC,EAAGC,KAAI,CAAC,IAAK;AAAA,MACnC,OAAO;AACL,WAAGD,EAAC,EAAGC,EAAC,IAAI,KAAK,IAAI,GAAGD,KAAI,CAAC,EAAGC,EAAC,GAAI,GAAGD,EAAC,EAAGC,KAAI,CAAC,CAAE;AAAA,MACrD;AAAA,IACF;AAAA,EACF;AAGA,QAAM,SAAmB,CAAC;AAC1B,MAAI,IAAI;AACR,MAAI,IAAI;AACR,SAAO,IAAI,KAAK,IAAI,GAAG;AACrB,QAAI,OAAO,IAAI,CAAC,MAAM,OAAO,IAAI,CAAC,GAAG;AACnC,aAAO,KAAK,OAAO,IAAI,CAAC,CAAE;AAC1B;AACA;AAAA,IACF,WAAW,GAAG,IAAI,CAAC,EAAG,CAAC,IAAK,GAAG,CAAC,EAAG,IAAI,CAAC,GAAI;AAC1C;AAAA,IACF,OAAO;AACL;AAAA,IACF;AAAA,EACF;AAEA,SAAO,OAAO,QAAQ;AACxB;AAcO,SAAS,mBAAmB,QAAqB,QAA8B;AACpF,QAAM,SAAS,OAAO,MAAM,IAAI,CAAC,SAAmB,KAAK,EAAE;AAC3D,QAAM,SAAS,OAAO,MAAM,IAAI,CAAC,SAAmB,KAAK,EAAE;AAC3D,QAAM,SAAS,IAAI,IAAI,WAAW,QAAQ,MAAM,CAAC;AAEjD,QAAM,WAAW,OAAO,MAAM,OAAO,CAAC,QAAQ,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;AACtF,QAAM,WAA2C,CAAC;AAElD,MAAI,mBAAkC;AACtC,aAAW,WAAW,OAAO,OAAO;AAClC,QAAI,OAAO,IAAI,QAAQ,EAAE,GAAG;AAC1B,yBAAmB,QAAQ;AAAA,IAC7B,OAAO;AACL,YAAM,SAAS;AACf,eAAS,KAAK,CAAC,QAAQ,QAAQ,EAAE,CAAC;AAClC,yBAAmB,QAAQ;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,aAAa,QAA8B,WAAoB,MAAmB;AAChG,UAAI,8BAAY,MAAM,GAAG;AACvB,eAAO,wCAAsB,QAAQ,QAAQ;AAAA,EAC/C;AACA,SAAO;AACT;","names":["sharp","i","j"]}
@@ -1,5 +1,4 @@
1
1
  import type { JSONSchema7 } from 'json-schema';
2
- import { ZodObject } from 'zod';
3
2
  import type { ChatContext } from './chat_context.js';
4
3
  import { FunctionCall, FunctionCallOutput, type ImageContent } from './chat_context.js';
5
4
  import type { ToolContext, ToolInputSchema, ToolOptions } from './tool_context.js';
@@ -21,7 +20,7 @@ export type OpenAIFunctionParameters = {
21
20
  };
22
21
  export declare const createToolOptions: <UserData extends unknown>(toolCallId: string, userData?: UserData) => ToolOptions<UserData>;
23
22
  /** @internal */
24
- export declare const oaiParams: (p: ZodObject<any>, isOpenai?: boolean) => OpenAIFunctionParameters;
23
+ export declare const oaiParams: (schema: any, isOpenai?: boolean) => OpenAIFunctionParameters;
25
24
  /** @internal */
26
25
  export declare const oaiBuildFunctionInfo: (toolCtx: ToolContext, toolCallId: string, toolName: string, rawArgs: string) => FunctionCall;
27
26
  export declare function executeToolCall(toolCall: FunctionCall, toolCtx: ToolContext): Promise<FunctionCallOutput>;
@@ -1,5 +1,4 @@
1
1
  import type { JSONSchema7 } from 'json-schema';
2
- import { ZodObject } from 'zod';
3
2
  import type { ChatContext } from './chat_context.js';
4
3
  import { FunctionCall, FunctionCallOutput, type ImageContent } from './chat_context.js';
5
4
  import type { ToolContext, ToolInputSchema, ToolOptions } from './tool_context.js';
@@ -21,7 +20,7 @@ export type OpenAIFunctionParameters = {
21
20
  };
22
21
  export declare const createToolOptions: <UserData extends unknown>(toolCallId: string, userData?: UserData) => ToolOptions<UserData>;
23
22
  /** @internal */
24
- export declare const oaiParams: (p: ZodObject<any>, isOpenai?: boolean) => OpenAIFunctionParameters;
23
+ export declare const oaiParams: (schema: any, isOpenai?: boolean) => OpenAIFunctionParameters;
25
24
  /** @internal */
26
25
  export declare const oaiBuildFunctionInfo: (toolCtx: ToolContext, toolCallId: string, toolName: string, rawArgs: string) => FunctionCall;
27
26
  export declare function executeToolCall(toolCall: FunctionCall, toolCtx: ToolContext): Promise<FunctionCallOutput>;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/llm/utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAGhC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAEL,YAAY,EACZ,kBAAkB,EAClB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEnF,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAwCD,wBAAsB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAsElF;AAED,+CAA+C;AAC/C,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAGF,eAAO,MAAM,iBAAiB,yCAChB,MAAM,aACR,QAAQ,KACjB,YAAY,QAAQ,CAEtB,CAAC;AAEF,gBAAgB;AAEhB,eAAO,MAAM,SAAS,MACjB,UAAU,GAAG,CAAC,aACP,OAAO,KAChB,wBAaF,CAAC;AAEF,gBAAgB;AAChB,eAAO,MAAM,oBAAoB,YACtB,WAAW,cACR,MAAM,YACR,MAAM,WACP,MAAM,KACd,YAWF,CAAC;AAEF,wBAAsB,eAAe,CACnC,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,kBAAkB,CAAC,CA6C7B;AA+CD,UAAU,OAAO;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAuBpF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,QAAQ,GAAE,OAAc,GAAG,WAAW,CAKhG"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/llm/utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAEL,YAAY,EACZ,kBAAkB,EAClB,KAAK,YAAY,EAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGnF,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAwCD,wBAAsB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAsElF;AAED,+CAA+C;AAC/C,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AAGF,eAAO,MAAM,iBAAiB,yCAChB,MAAM,aACR,QAAQ,KACjB,YAAY,QAAQ,CAEtB,CAAC;AAEF,gBAAgB;AAEhB,eAAO,MAAM,SAAS,WAAY,GAAG,aAAY,OAAO,KAAU,wBAWjE,CAAC;AAEF,gBAAgB;AAChB,eAAO,MAAM,oBAAoB,YACtB,WAAW,cACR,MAAM,YACR,MAAM,WACP,MAAM,KACd,YAWF,CAAC;AAEF,wBAAsB,eAAe,CACnC,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAsD7B;AA+CD,UAAU,OAAO;IACf,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;CAC1C;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAuBpF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,QAAQ,GAAE,OAAc,GAAG,WAAW,CAKhG"}
package/dist/llm/utils.js CHANGED
@@ -1,11 +1,10 @@
1
1
  import { VideoBufferType, VideoFrame } from "@livekit/rtc-node";
2
2
  import sharp from "sharp";
3
- import { ZodObject } from "zod";
4
- import { zodToJsonSchema } from "zod-to-json-schema";
5
3
  import {
6
4
  FunctionCall,
7
5
  FunctionCallOutput
8
6
  } from "./chat_context.js";
7
+ import { isZodSchema, parseZodSchema, zodSchemaToJsonSchema } from "./zod-utils.js";
9
8
  function getChannelsFromVideoBufferType(type) {
10
9
  switch (type) {
11
10
  case VideoBufferType.RGBA:
@@ -92,11 +91,9 @@ async function serializeImage(image) {
92
91
  const createToolOptions = (toolCallId, userData = {}) => {
93
92
  return { ctx: { userData }, toolCallId };
94
93
  };
95
- const oaiParams = (p, isOpenai = true) => {
96
- const { properties, required, additionalProperties } = zodToJsonSchema(p, {
97
- // note: openai mode breaks various gemini conversions
98
- target: isOpenai ? "openAi" : "jsonSchema7"
99
- });
94
+ const oaiParams = (schema, isOpenai = true) => {
95
+ const jsonSchema = zodSchemaToJsonSchema(schema, isOpenai);
96
+ const { properties, required, additionalProperties } = jsonSchema;
100
97
  return {
101
98
  type: "object",
102
99
  properties,
@@ -129,8 +126,17 @@ async function executeToolCall(toolCall, toolCtx) {
129
126
  });
130
127
  }
131
128
  try {
132
- if (tool.parameters instanceof ZodObject) {
133
- params = tool.parameters.parse(args);
129
+ if (isZodSchema(tool.parameters)) {
130
+ const result = await parseZodSchema(tool.parameters, args);
131
+ if (result.success) {
132
+ params = result.data;
133
+ } else {
134
+ return FunctionCallOutput.create({
135
+ callId: toolCall.callId,
136
+ output: `Arguments parsing failed: ${result.error}`,
137
+ isError: true
138
+ });
139
+ }
134
140
  } else {
135
141
  params = args;
136
142
  }
@@ -207,8 +213,8 @@ function computeChatCtxDiff(oldCtx, newCtx) {
207
213
  };
208
214
  }
209
215
  function toJsonSchema(schema, isOpenai = true) {
210
- if (schema instanceof ZodObject) {
211
- return oaiParams(schema, isOpenai);
216
+ if (isZodSchema(schema)) {
217
+ return zodSchemaToJsonSchema(schema, isOpenai);
212
218
  }
213
219
  return schema;
214
220
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/llm/utils.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { VideoBufferType, VideoFrame } from '@livekit/rtc-node';\nimport type { JSONSchema7 } from 'json-schema';\nimport sharp from 'sharp';\nimport { ZodObject } from 'zod';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport type { UnknownUserData } from '../voice/run_context.js';\nimport type { ChatContext } from './chat_context.js';\nimport {\n type ChatItem,\n FunctionCall,\n FunctionCallOutput,\n type ImageContent,\n} from './chat_context.js';\nimport type { ToolContext, ToolInputSchema, ToolOptions } from './tool_context.js';\n\nexport interface SerializedImage {\n inferenceDetail: 'auto' | 'high' | 'low';\n mimeType?: string;\n base64Data?: string;\n externalUrl?: string;\n}\n\nfunction getChannelsFromVideoBufferType(type: VideoBufferType): 3 | 4 {\n switch (type) {\n case VideoBufferType.RGBA:\n case VideoBufferType.ABGR:\n case VideoBufferType.ARGB:\n case VideoBufferType.BGRA:\n return 4;\n case VideoBufferType.RGB24:\n return 3;\n default:\n // YUV formats (I420, I420A, I422, I444, I010, NV12) need conversion\n throw new Error(`Unsupported VideoBufferType: ${type}. Only RGB/RGBA formats are supported.`);\n }\n}\n\nfunction ensureRGBCompatible(frame: VideoFrame): VideoFrame {\n // If the frame is already in an RGB/RGBA-compatible format, return it directly\n if (\n frame.type === VideoBufferType.RGBA ||\n frame.type === VideoBufferType.BGRA ||\n frame.type === VideoBufferType.ARGB ||\n frame.type === VideoBufferType.ABGR ||\n frame.type === VideoBufferType.RGB24\n ) {\n return frame;\n }\n\n // Otherwise, attempt conversion for other formats (like YUV)\n try {\n return frame.convert(VideoBufferType.RGBA);\n } catch (error) {\n throw new Error(\n `Failed to convert format ${frame.type} to RGB: ${error}. ` +\n `Consider using RGB/RGBA formats or converting on the client side.`,\n );\n }\n}\n\nexport async function serializeImage(image: ImageContent): Promise<SerializedImage> {\n if (typeof image.image === 'string') {\n if (image.image.startsWith('data:')) {\n const [header, base64Data] = image.image.split(',', 2) as [string, string];\n const headerParts = header.split(';');\n const mimeParts = headerParts[0]?.split(':');\n const headerMime = mimeParts?.[1];\n\n if (!headerMime) {\n throw new Error('Invalid data URL format');\n }\n\n let mimeType: string;\n if (image.mimeType && image.mimeType !== headerMime) {\n console.warn(\n `Provided mimeType '${image.mimeType}' does not match data URL mime type '${headerMime}'. Using provided mimeType.`,\n );\n mimeType = image.mimeType;\n } else {\n mimeType = headerMime;\n }\n\n const supportedTypes = new Set(['image/jpeg', 'image/png', 'image/webp', 'image/gif']);\n if (!supportedTypes.has(mimeType)) {\n throw new Error(`Unsupported mimeType ${mimeType}. Must be jpeg, png, webp, or gif`);\n }\n\n return {\n base64Data,\n mimeType: mimeType,\n inferenceDetail: image.inferenceDetail,\n };\n }\n\n // External URL\n return {\n mimeType: image.mimeType,\n inferenceDetail: image.inferenceDetail,\n externalUrl: image.image,\n };\n } else if (image.image instanceof VideoFrame) {\n const frame = ensureRGBCompatible(image.image);\n const channels = getChannelsFromVideoBufferType(frame.type);\n\n // Sharp needs to know the format of raw pixel data\n let encoded = sharp(frame.data, {\n raw: {\n width: frame.width,\n height: frame.height,\n channels,\n },\n });\n\n if (image.inferenceWidth && image.inferenceHeight) {\n encoded = encoded.resize(image.inferenceWidth, image.inferenceHeight);\n }\n\n const base64Data = await encoded\n .png()\n .toBuffer()\n .then((buffer) => buffer.toString('base64'));\n\n return {\n base64Data,\n mimeType: 'image/png',\n inferenceDetail: image.inferenceDetail,\n };\n } else {\n throw new Error('Unsupported image type');\n }\n}\n\n/** Raw OpenAI-adherent function parameters. */\nexport type OpenAIFunctionParameters = {\n type: 'object';\n properties: { [id: string]: any }; // eslint-disable-line @typescript-eslint/no-explicit-any\n required: string[];\n additionalProperties?: boolean;\n};\n\n// TODO(brian): remove this helper once we have the real RunContext user data\nexport const createToolOptions = <UserData extends UnknownUserData>(\n toolCallId: string,\n userData: UserData = {} as UserData,\n): ToolOptions<UserData> => {\n return { ctx: { userData }, toolCallId } as unknown as ToolOptions<UserData>;\n};\n\n/** @internal */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const oaiParams = (\n p: ZodObject<any>,\n isOpenai: boolean = true,\n): OpenAIFunctionParameters => {\n // Adapted from https://github.com/vercel/ai/blob/56eb0ee9/packages/provider-utils/src/zod-schema.ts\n const { properties, required, additionalProperties } = zodToJsonSchema(p, {\n // note: openai mode breaks various gemini conversions\n target: isOpenai ? 'openAi' : 'jsonSchema7',\n }) as OpenAIFunctionParameters;\n\n return {\n type: 'object',\n properties,\n required,\n additionalProperties,\n };\n};\n\n/** @internal */\nexport const oaiBuildFunctionInfo = (\n toolCtx: ToolContext,\n toolCallId: string,\n toolName: string,\n rawArgs: string,\n): FunctionCall => {\n const tool = toolCtx[toolName];\n if (!tool) {\n throw new Error(`AI tool ${toolName} not found`);\n }\n\n return FunctionCall.create({\n callId: toolCallId,\n name: toolName,\n args: rawArgs,\n });\n};\n\nexport async function executeToolCall(\n toolCall: FunctionCall,\n toolCtx: ToolContext,\n): Promise<FunctionCallOutput> {\n const tool = toolCtx[toolCall.name]!;\n let args: object | undefined;\n let params: object | undefined;\n\n // Ensure valid JSON\n try {\n args = JSON.parse(toolCall.args);\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Invalid JSON: ${error}`,\n isError: true,\n });\n }\n\n // Ensure valid arguments schema\n try {\n if (tool.parameters instanceof ZodObject) {\n params = tool.parameters.parse(args);\n } else {\n params = args;\n }\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Arguments parsing failed: ${error}`,\n isError: true,\n });\n }\n\n try {\n const result = await tool.execute(params, createToolOptions(toolCall.callId));\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: JSON.stringify(result),\n isError: false,\n });\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Tool execution failed: ${error}`,\n isError: true,\n });\n }\n}\n\n/**\n * Standard dynamic-programming LCS to get the common subsequence\n * of IDs (in order) that appear in both old_ids and new_ids.\n *\n * @param oldIds - The old list of IDs.\n * @param newIds - The new list of IDs.\n * @returns The longest common subsequence of the two lists of IDs.\n */\nfunction computeLCS(oldIds: string[], newIds: string[]): string[] {\n const n = oldIds.length;\n const m = newIds.length;\n const dp: number[][] = Array(n + 1)\n .fill(null)\n .map(() => Array(m + 1).fill(0));\n\n // Fill DP table\n for (let i = 1; i <= n; i++) {\n for (let j = 1; j <= m; j++) {\n if (oldIds[i - 1] === newIds[j - 1]) {\n dp[i]![j] = dp[i - 1]![j - 1]! + 1;\n } else {\n dp[i]![j] = Math.max(dp[i - 1]![j]!, dp[i]![j - 1]!);\n }\n }\n }\n\n // Backtrack to find the actual LCS sequence\n const lcsIds: string[] = [];\n let i = n;\n let j = m;\n while (i > 0 && j > 0) {\n if (oldIds[i - 1] === newIds[j - 1]) {\n lcsIds.push(oldIds[i - 1]!);\n i--;\n j--;\n } else if (dp[i - 1]![j]! > dp[i]![j - 1]!) {\n i--;\n } else {\n j--;\n }\n }\n\n return lcsIds.reverse();\n}\n\ninterface DiffOps {\n toRemove: string[];\n toCreate: Array<[string | null, string]>; // (previous_item_id, id), if previous_item_id is null, add to the root\n}\n\n/**\n * Compute the minimal list of create/remove operations to transform oldCtx into newCtx.\n *\n * @param oldCtx - The old chat context.\n * @param newCtx - The new chat context.\n * @returns The minimal list of create/remove operations to transform oldCtx into newCtx.\n */\nexport function computeChatCtxDiff(oldCtx: ChatContext, newCtx: ChatContext): DiffOps {\n const oldIds = oldCtx.items.map((item: ChatItem) => item.id);\n const newIds = newCtx.items.map((item: ChatItem) => item.id);\n const lcsIds = new Set(computeLCS(oldIds, newIds));\n\n const toRemove = oldCtx.items.filter((msg) => !lcsIds.has(msg.id)).map((msg) => msg.id);\n const toCreate: Array<[string | null, string]> = [];\n\n let lastIdInSequence: string | null = null;\n for (const newItem of newCtx.items) {\n if (lcsIds.has(newItem.id)) {\n lastIdInSequence = newItem.id;\n } else {\n const prevId = lastIdInSequence; // null if root\n toCreate.push([prevId, newItem.id]);\n lastIdInSequence = newItem.id;\n }\n }\n\n return {\n toRemove,\n toCreate,\n };\n}\n\nexport function toJsonSchema(schema: ToolInputSchema<any>, isOpenai: boolean = true): JSONSchema7 {\n if (schema instanceof ZodObject) {\n return oaiParams(schema, isOpenai);\n }\n return schema;\n}\n"],"mappings":"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","names":["i","j"]}
1
+ {"version":3,"sources":["../../src/llm/utils.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { VideoBufferType, VideoFrame } from '@livekit/rtc-node';\nimport type { JSONSchema7 } from 'json-schema';\nimport sharp from 'sharp';\nimport type { UnknownUserData } from '../voice/run_context.js';\nimport type { ChatContext } from './chat_context.js';\nimport {\n type ChatItem,\n FunctionCall,\n FunctionCallOutput,\n type ImageContent,\n} from './chat_context.js';\nimport type { ToolContext, ToolInputSchema, ToolOptions } from './tool_context.js';\nimport { isZodSchema, parseZodSchema, zodSchemaToJsonSchema } from './zod-utils.js';\n\nexport interface SerializedImage {\n inferenceDetail: 'auto' | 'high' | 'low';\n mimeType?: string;\n base64Data?: string;\n externalUrl?: string;\n}\n\nfunction getChannelsFromVideoBufferType(type: VideoBufferType): 3 | 4 {\n switch (type) {\n case VideoBufferType.RGBA:\n case VideoBufferType.ABGR:\n case VideoBufferType.ARGB:\n case VideoBufferType.BGRA:\n return 4;\n case VideoBufferType.RGB24:\n return 3;\n default:\n // YUV formats (I420, I420A, I422, I444, I010, NV12) need conversion\n throw new Error(`Unsupported VideoBufferType: ${type}. Only RGB/RGBA formats are supported.`);\n }\n}\n\nfunction ensureRGBCompatible(frame: VideoFrame): VideoFrame {\n // If the frame is already in an RGB/RGBA-compatible format, return it directly\n if (\n frame.type === VideoBufferType.RGBA ||\n frame.type === VideoBufferType.BGRA ||\n frame.type === VideoBufferType.ARGB ||\n frame.type === VideoBufferType.ABGR ||\n frame.type === VideoBufferType.RGB24\n ) {\n return frame;\n }\n\n // Otherwise, attempt conversion for other formats (like YUV)\n try {\n return frame.convert(VideoBufferType.RGBA);\n } catch (error) {\n throw new Error(\n `Failed to convert format ${frame.type} to RGB: ${error}. ` +\n `Consider using RGB/RGBA formats or converting on the client side.`,\n );\n }\n}\n\nexport async function serializeImage(image: ImageContent): Promise<SerializedImage> {\n if (typeof image.image === 'string') {\n if (image.image.startsWith('data:')) {\n const [header, base64Data] = image.image.split(',', 2) as [string, string];\n const headerParts = header.split(';');\n const mimeParts = headerParts[0]?.split(':');\n const headerMime = mimeParts?.[1];\n\n if (!headerMime) {\n throw new Error('Invalid data URL format');\n }\n\n let mimeType: string;\n if (image.mimeType && image.mimeType !== headerMime) {\n console.warn(\n `Provided mimeType '${image.mimeType}' does not match data URL mime type '${headerMime}'. Using provided mimeType.`,\n );\n mimeType = image.mimeType;\n } else {\n mimeType = headerMime;\n }\n\n const supportedTypes = new Set(['image/jpeg', 'image/png', 'image/webp', 'image/gif']);\n if (!supportedTypes.has(mimeType)) {\n throw new Error(`Unsupported mimeType ${mimeType}. Must be jpeg, png, webp, or gif`);\n }\n\n return {\n base64Data,\n mimeType: mimeType,\n inferenceDetail: image.inferenceDetail,\n };\n }\n\n // External URL\n return {\n mimeType: image.mimeType,\n inferenceDetail: image.inferenceDetail,\n externalUrl: image.image,\n };\n } else if (image.image instanceof VideoFrame) {\n const frame = ensureRGBCompatible(image.image);\n const channels = getChannelsFromVideoBufferType(frame.type);\n\n // Sharp needs to know the format of raw pixel data\n let encoded = sharp(frame.data, {\n raw: {\n width: frame.width,\n height: frame.height,\n channels,\n },\n });\n\n if (image.inferenceWidth && image.inferenceHeight) {\n encoded = encoded.resize(image.inferenceWidth, image.inferenceHeight);\n }\n\n const base64Data = await encoded\n .png()\n .toBuffer()\n .then((buffer) => buffer.toString('base64'));\n\n return {\n base64Data,\n mimeType: 'image/png',\n inferenceDetail: image.inferenceDetail,\n };\n } else {\n throw new Error('Unsupported image type');\n }\n}\n\n/** Raw OpenAI-adherent function parameters. */\nexport type OpenAIFunctionParameters = {\n type: 'object';\n properties: { [id: string]: any }; // eslint-disable-line @typescript-eslint/no-explicit-any\n required: string[];\n additionalProperties?: boolean;\n};\n\n// TODO(brian): remove this helper once we have the real RunContext user data\nexport const createToolOptions = <UserData extends UnknownUserData>(\n toolCallId: string,\n userData: UserData = {} as UserData,\n): ToolOptions<UserData> => {\n return { ctx: { userData }, toolCallId } as unknown as ToolOptions<UserData>;\n};\n\n/** @internal */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const oaiParams = (schema: any, isOpenai: boolean = true): OpenAIFunctionParameters => {\n // Adapted from https://github.com/vercel/ai/blob/56eb0ee9/packages/provider-utils/src/zod-schema.ts\n const jsonSchema = zodSchemaToJsonSchema(schema, isOpenai);\n const { properties, required, additionalProperties } = jsonSchema as OpenAIFunctionParameters;\n\n return {\n type: 'object',\n properties,\n required,\n additionalProperties,\n };\n};\n\n/** @internal */\nexport const oaiBuildFunctionInfo = (\n toolCtx: ToolContext,\n toolCallId: string,\n toolName: string,\n rawArgs: string,\n): FunctionCall => {\n const tool = toolCtx[toolName];\n if (!tool) {\n throw new Error(`AI tool ${toolName} not found`);\n }\n\n return FunctionCall.create({\n callId: toolCallId,\n name: toolName,\n args: rawArgs,\n });\n};\n\nexport async function executeToolCall(\n toolCall: FunctionCall,\n toolCtx: ToolContext,\n): Promise<FunctionCallOutput> {\n const tool = toolCtx[toolCall.name]!;\n let args: object | undefined;\n let params: object | undefined;\n\n // Ensure valid JSON\n try {\n args = JSON.parse(toolCall.args);\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Invalid JSON: ${error}`,\n isError: true,\n });\n }\n\n // Ensure valid arguments schema\n try {\n if (isZodSchema(tool.parameters)) {\n const result = await parseZodSchema<object>(tool.parameters, args);\n if (result.success) {\n params = result.data;\n } else {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Arguments parsing failed: ${result.error}`,\n isError: true,\n });\n }\n } else {\n params = args;\n }\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Arguments parsing failed: ${error}`,\n isError: true,\n });\n }\n\n try {\n const result = await tool.execute(params, createToolOptions(toolCall.callId));\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: JSON.stringify(result),\n isError: false,\n });\n } catch (error) {\n return FunctionCallOutput.create({\n callId: toolCall.callId,\n output: `Tool execution failed: ${error}`,\n isError: true,\n });\n }\n}\n\n/**\n * Standard dynamic-programming LCS to get the common subsequence\n * of IDs (in order) that appear in both old_ids and new_ids.\n *\n * @param oldIds - The old list of IDs.\n * @param newIds - The new list of IDs.\n * @returns The longest common subsequence of the two lists of IDs.\n */\nfunction computeLCS(oldIds: string[], newIds: string[]): string[] {\n const n = oldIds.length;\n const m = newIds.length;\n const dp: number[][] = Array(n + 1)\n .fill(null)\n .map(() => Array(m + 1).fill(0));\n\n // Fill DP table\n for (let i = 1; i <= n; i++) {\n for (let j = 1; j <= m; j++) {\n if (oldIds[i - 1] === newIds[j - 1]) {\n dp[i]![j] = dp[i - 1]![j - 1]! + 1;\n } else {\n dp[i]![j] = Math.max(dp[i - 1]![j]!, dp[i]![j - 1]!);\n }\n }\n }\n\n // Backtrack to find the actual LCS sequence\n const lcsIds: string[] = [];\n let i = n;\n let j = m;\n while (i > 0 && j > 0) {\n if (oldIds[i - 1] === newIds[j - 1]) {\n lcsIds.push(oldIds[i - 1]!);\n i--;\n j--;\n } else if (dp[i - 1]![j]! > dp[i]![j - 1]!) {\n i--;\n } else {\n j--;\n }\n }\n\n return lcsIds.reverse();\n}\n\ninterface DiffOps {\n toRemove: string[];\n toCreate: Array<[string | null, string]>; // (previous_item_id, id), if previous_item_id is null, add to the root\n}\n\n/**\n * Compute the minimal list of create/remove operations to transform oldCtx into newCtx.\n *\n * @param oldCtx - The old chat context.\n * @param newCtx - The new chat context.\n * @returns The minimal list of create/remove operations to transform oldCtx into newCtx.\n */\nexport function computeChatCtxDiff(oldCtx: ChatContext, newCtx: ChatContext): DiffOps {\n const oldIds = oldCtx.items.map((item: ChatItem) => item.id);\n const newIds = newCtx.items.map((item: ChatItem) => item.id);\n const lcsIds = new Set(computeLCS(oldIds, newIds));\n\n const toRemove = oldCtx.items.filter((msg) => !lcsIds.has(msg.id)).map((msg) => msg.id);\n const toCreate: Array<[string | null, string]> = [];\n\n let lastIdInSequence: string | null = null;\n for (const newItem of newCtx.items) {\n if (lcsIds.has(newItem.id)) {\n lastIdInSequence = newItem.id;\n } else {\n const prevId = lastIdInSequence; // null if root\n toCreate.push([prevId, newItem.id]);\n lastIdInSequence = newItem.id;\n }\n }\n\n return {\n toRemove,\n toCreate,\n };\n}\n\nexport function toJsonSchema(schema: ToolInputSchema<any>, isOpenai: boolean = true): JSONSchema7 {\n if (isZodSchema(schema)) {\n return zodSchemaToJsonSchema(schema, isOpenai);\n }\n return schema as JSONSchema7;\n}\n"],"mappings":"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","names":["i","j"]}
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var zod_utils_exports = {};
30
+ __export(zod_utils_exports, {
31
+ isZod4Schema: () => isZod4Schema,
32
+ isZodObjectSchema: () => isZodObjectSchema,
33
+ isZodSchema: () => isZodSchema,
34
+ parseZodSchema: () => parseZodSchema,
35
+ zodSchemaToJsonSchema: () => zodSchemaToJsonSchema
36
+ });
37
+ module.exports = __toCommonJS(zod_utils_exports);
38
+ var import_zod_to_json_schema = require("zod-to-json-schema");
39
+ var z4 = __toESM(require("zod/v4"), 1);
40
+ function isZod4Schema(schema) {
41
+ return "_zod" in schema;
42
+ }
43
+ function isZodSchema(value) {
44
+ if (typeof value !== "object" || value === null) {
45
+ return false;
46
+ }
47
+ if ("_zod" in value) {
48
+ return true;
49
+ }
50
+ if ("_def" in value && typeof value._def === "object" && value._def !== null) {
51
+ const def = value._def;
52
+ if ("typeName" in def) {
53
+ return true;
54
+ }
55
+ }
56
+ return false;
57
+ }
58
+ function isZodObjectSchema(schema) {
59
+ var _a, _b, _c, _d;
60
+ const schemaWithInternals = schema;
61
+ if (isZod4Schema(schema)) {
62
+ return ((_a = schemaWithInternals._def) == null ? void 0 : _a.type) === "object" || ((_c = (_b = schemaWithInternals._zod) == null ? void 0 : _b.traits) == null ? void 0 : _c.has("ZodObject")) || false;
63
+ }
64
+ return ((_d = schemaWithInternals._def) == null ? void 0 : _d.typeName) === "ZodObject";
65
+ }
66
+ function zodSchemaToJsonSchema(schema, isOpenai = true) {
67
+ if (isZod4Schema(schema)) {
68
+ return z4.toJSONSchema(schema, {
69
+ target: "draft-7",
70
+ io: "output",
71
+ reused: "inline"
72
+ // Don't use references by default (to support openapi conversion for google)
73
+ });
74
+ } else {
75
+ return (0, import_zod_to_json_schema.zodToJsonSchema)(schema, {
76
+ target: isOpenai ? "openAi" : "jsonSchema7",
77
+ $refStrategy: "none"
78
+ // Don't use references by default (to support openapi conversion for google)
79
+ });
80
+ }
81
+ }
82
+ async function parseZodSchema(schema, value) {
83
+ if (isZod4Schema(schema)) {
84
+ const result = await z4.safeParseAsync(schema, value);
85
+ return result;
86
+ } else {
87
+ const result = await schema.safeParseAsync(value);
88
+ return result;
89
+ }
90
+ }
91
+ // Annotate the CommonJS export names for ESM import in node:
92
+ 0 && (module.exports = {
93
+ isZod4Schema,
94
+ isZodObjectSchema,
95
+ isZodSchema,
96
+ parseZodSchema,
97
+ zodSchemaToJsonSchema
98
+ });
99
+ //# sourceMappingURL=zod-utils.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/llm/zod-utils.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { JSONSchema7 } from 'json-schema';\nimport { zodToJsonSchema as zodToJsonSchemaV3 } from 'zod-to-json-schema';\nimport type * as z3 from 'zod/v3';\nimport * as z4 from 'zod/v4';\n\n/**\n * Result type from Zod schema parsing.\n */\nexport type ZodParseResult<T = unknown> =\n | { success: true; data: T }\n | { success: false; error: unknown };\n\n/**\n * Type definition for Zod schemas that works with both v3 and v4.\n * Uses a union type of both Zod v3 and v4 schema types.\n *\n * Adapted from Vercel AI SDK's zodSchema function signature.\n * Source: https://github.com/vercel/ai/blob/main/packages/provider-utils/src/schema.ts#L278-L281\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ZodSchema = z4.core.$ZodType<any, any> | z3.Schema<any, z3.ZodTypeDef, any>;\n\n/**\n * Detects if a schema is a Zod v4 schema.\n * Zod v4 schemas have a `_zod` property that v3 schemas don't have.\n *\n * @param schema - The schema to check\n * @returns True if the schema is a Zod v4 schema\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Required to match Zod v4's type signature\nexport function isZod4Schema(schema: ZodSchema): schema is z4.core.$ZodType<any, any> {\n // https://zod.dev/library-authors?id=how-to-support-zod-3-and-zod-4-simultaneously\n return '_zod' in schema;\n}\n\n/**\n * Checks if a value is a Zod schema (either v3 or v4).\n *\n * @param value - The value to check\n * @returns True if the value is a Zod schema\n */\nexport function isZodSchema(value: unknown): value is ZodSchema {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n // Check for v4 schema (_zod property)\n if ('_zod' in value) {\n return true;\n }\n\n // Check for v3 schema (_def property with typeName)\n if ('_def' in value && typeof value._def === 'object' && value._def !== null) {\n const def = value._def as Record<string, unknown>;\n if ('typeName' in def) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Checks if a Zod schema is an object schema.\n *\n * @param schema - The schema to check\n * @returns True if the schema is an object schema\n */\nexport function isZodObjectSchema(schema: ZodSchema): boolean {\n // Need to access internal Zod properties to check schema type\n const schemaWithInternals = schema as {\n _def?: { type?: string; typeName?: string };\n _zod?: { traits?: Set<string> };\n };\n\n // Check for v4 schema first\n if (isZod4Schema(schema)) {\n // v4 uses _def.type and _zod.traits\n return (\n schemaWithInternals._def?.type === 'object' ||\n schemaWithInternals._zod?.traits?.has('ZodObject') ||\n false\n );\n }\n\n // v3 uses _def.typeName\n return schemaWithInternals._def?.typeName === 'ZodObject';\n}\n\n/**\n * Converts a Zod schema to JSON Schema format.\n * Handles both Zod v3 and v4 schemas automatically.\n *\n * Adapted from Vercel AI SDK's zod3Schema and zod4Schema functions.\n * Source: https://github.com/vercel/ai/blob/main/packages/provider-utils/src/schema.ts#L237-L269\n *\n * @param schema - The Zod schema to convert\n * @param isOpenai - Whether to use OpenAI-specific formatting (default: true)\n * @returns A JSON Schema representation of the Zod schema\n */\nexport function zodSchemaToJsonSchema(schema: ZodSchema, isOpenai: boolean = true): JSONSchema7 {\n if (isZod4Schema(schema)) {\n // Zod v4 has native toJSONSchema support\n // Configuration adapted from Vercel AI SDK to support OpenAPI conversion for Google\n // Source: https://github.com/vercel/ai/blob/main/packages/provider-utils/src/schema.ts#L255-L258\n return z4.toJSONSchema(schema, {\n target: 'draft-7',\n io: 'output',\n reused: 'inline', // Don't use references by default (to support openapi conversion for google)\n }) as JSONSchema7;\n } else {\n // Zod v3 requires the zod-to-json-schema library\n // Configuration adapted from Vercel AI SDK\n // $refStrategy: 'none' is equivalent to v4's reused: 'inline'\n return zodToJsonSchemaV3(schema, {\n target: isOpenai ? 'openAi' : 'jsonSchema7',\n $refStrategy: 'none', // Don't use references by default (to support openapi conversion for google)\n }) as JSONSchema7;\n }\n}\n\n/**\n * Parses a value against a Zod schema.\n * Handles both Zod v3 and v4 parse APIs automatically.\n *\n * @param schema - The Zod schema to parse against\n * @param value - The value to parse\n * @returns A promise that resolves to the parse result\n */\nexport async function parseZodSchema<T = unknown>(\n schema: ZodSchema,\n value: unknown,\n): Promise<ZodParseResult<T>> {\n if (isZod4Schema(schema)) {\n const result = await z4.safeParseAsync(schema, value);\n return result as ZodParseResult<T>;\n } else {\n const result = await schema.safeParseAsync(value);\n return result as ZodParseResult<T>;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,gCAAqD;AAErD,SAAoB;AA2Bb,SAAS,aAAa,QAAyD;AAEpF,SAAO,UAAU;AACnB;AAQO,SAAS,YAAY,OAAoC;AAC9D,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,OAAO;AACnB,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,SAAS,OAAO,MAAM,SAAS,YAAY,MAAM,SAAS,MAAM;AAC5E,UAAM,MAAM,MAAM;AAClB,QAAI,cAAc,KAAK;AACrB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,kBAAkB,QAA4B;AAvE9D;AAyEE,QAAM,sBAAsB;AAM5B,MAAI,aAAa,MAAM,GAAG;AAExB,aACE,yBAAoB,SAApB,mBAA0B,UAAS,cACnC,+BAAoB,SAApB,mBAA0B,WAA1B,mBAAkC,IAAI,iBACtC;AAAA,EAEJ;AAGA,WAAO,yBAAoB,SAApB,mBAA0B,cAAa;AAChD;AAaO,SAAS,sBAAsB,QAAmB,WAAoB,MAAmB;AAC9F,MAAI,aAAa,MAAM,GAAG;AAIxB,WAAO,GAAG,aAAa,QAAQ;AAAA,MAC7B,QAAQ;AAAA,MACR,IAAI;AAAA,MACJ,QAAQ;AAAA;AAAA,IACV,CAAC;AAAA,EACH,OAAO;AAIL,eAAO,0BAAAA,iBAAkB,QAAQ;AAAA,MAC/B,QAAQ,WAAW,WAAW;AAAA,MAC9B,cAAc;AAAA;AAAA,IAChB,CAAC;AAAA,EACH;AACF;AAUA,eAAsB,eACpB,QACA,OAC4B;AAC5B,MAAI,aAAa,MAAM,GAAG;AACxB,UAAM,SAAS,MAAM,GAAG,eAAe,QAAQ,KAAK;AACpD,WAAO;AAAA,EACT,OAAO;AACL,UAAM,SAAS,MAAM,OAAO,eAAe,KAAK;AAChD,WAAO;AAAA,EACT;AACF;","names":["zodToJsonSchemaV3"]}
@@ -0,0 +1,65 @@
1
+ import type { JSONSchema7 } from 'json-schema';
2
+ import type * as z3 from 'zod/v3';
3
+ import * as z4 from 'zod/v4';
4
+ /**
5
+ * Result type from Zod schema parsing.
6
+ */
7
+ export type ZodParseResult<T = unknown> = {
8
+ success: true;
9
+ data: T;
10
+ } | {
11
+ success: false;
12
+ error: unknown;
13
+ };
14
+ /**
15
+ * Type definition for Zod schemas that works with both v3 and v4.
16
+ * Uses a union type of both Zod v3 and v4 schema types.
17
+ *
18
+ * Adapted from Vercel AI SDK's zodSchema function signature.
19
+ * Source: https://github.com/vercel/ai/blob/main/packages/provider-utils/src/schema.ts#L278-L281
20
+ */
21
+ export type ZodSchema = z4.core.$ZodType<any, any> | z3.Schema<any, z3.ZodTypeDef, any>;
22
+ /**
23
+ * Detects if a schema is a Zod v4 schema.
24
+ * Zod v4 schemas have a `_zod` property that v3 schemas don't have.
25
+ *
26
+ * @param schema - The schema to check
27
+ * @returns True if the schema is a Zod v4 schema
28
+ */
29
+ export declare function isZod4Schema(schema: ZodSchema): schema is z4.core.$ZodType<any, any>;
30
+ /**
31
+ * Checks if a value is a Zod schema (either v3 or v4).
32
+ *
33
+ * @param value - The value to check
34
+ * @returns True if the value is a Zod schema
35
+ */
36
+ export declare function isZodSchema(value: unknown): value is ZodSchema;
37
+ /**
38
+ * Checks if a Zod schema is an object schema.
39
+ *
40
+ * @param schema - The schema to check
41
+ * @returns True if the schema is an object schema
42
+ */
43
+ export declare function isZodObjectSchema(schema: ZodSchema): boolean;
44
+ /**
45
+ * Converts a Zod schema to JSON Schema format.
46
+ * Handles both Zod v3 and v4 schemas automatically.
47
+ *
48
+ * Adapted from Vercel AI SDK's zod3Schema and zod4Schema functions.
49
+ * Source: https://github.com/vercel/ai/blob/main/packages/provider-utils/src/schema.ts#L237-L269
50
+ *
51
+ * @param schema - The Zod schema to convert
52
+ * @param isOpenai - Whether to use OpenAI-specific formatting (default: true)
53
+ * @returns A JSON Schema representation of the Zod schema
54
+ */
55
+ export declare function zodSchemaToJsonSchema(schema: ZodSchema, isOpenai?: boolean): JSONSchema7;
56
+ /**
57
+ * Parses a value against a Zod schema.
58
+ * Handles both Zod v3 and v4 parse APIs automatically.
59
+ *
60
+ * @param schema - The Zod schema to parse against
61
+ * @param value - The value to parse
62
+ * @returns A promise that resolves to the parse result
63
+ */
64
+ export declare function parseZodSchema<T = unknown>(schema: ZodSchema, value: unknown): Promise<ZodParseResult<T>>;
65
+ //# sourceMappingURL=zod-utils.d.ts.map
@@ -0,0 +1,65 @@
1
+ import type { JSONSchema7 } from 'json-schema';
2
+ import type * as z3 from 'zod/v3';
3
+ import * as z4 from 'zod/v4';
4
+ /**
5
+ * Result type from Zod schema parsing.
6
+ */
7
+ export type ZodParseResult<T = unknown> = {
8
+ success: true;
9
+ data: T;
10
+ } | {
11
+ success: false;
12
+ error: unknown;
13
+ };
14
+ /**
15
+ * Type definition for Zod schemas that works with both v3 and v4.
16
+ * Uses a union type of both Zod v3 and v4 schema types.
17
+ *
18
+ * Adapted from Vercel AI SDK's zodSchema function signature.
19
+ * Source: https://github.com/vercel/ai/blob/main/packages/provider-utils/src/schema.ts#L278-L281
20
+ */
21
+ export type ZodSchema = z4.core.$ZodType<any, any> | z3.Schema<any, z3.ZodTypeDef, any>;
22
+ /**
23
+ * Detects if a schema is a Zod v4 schema.
24
+ * Zod v4 schemas have a `_zod` property that v3 schemas don't have.
25
+ *
26
+ * @param schema - The schema to check
27
+ * @returns True if the schema is a Zod v4 schema
28
+ */
29
+ export declare function isZod4Schema(schema: ZodSchema): schema is z4.core.$ZodType<any, any>;
30
+ /**
31
+ * Checks if a value is a Zod schema (either v3 or v4).
32
+ *
33
+ * @param value - The value to check
34
+ * @returns True if the value is a Zod schema
35
+ */
36
+ export declare function isZodSchema(value: unknown): value is ZodSchema;
37
+ /**
38
+ * Checks if a Zod schema is an object schema.
39
+ *
40
+ * @param schema - The schema to check
41
+ * @returns True if the schema is an object schema
42
+ */
43
+ export declare function isZodObjectSchema(schema: ZodSchema): boolean;
44
+ /**
45
+ * Converts a Zod schema to JSON Schema format.
46
+ * Handles both Zod v3 and v4 schemas automatically.
47
+ *
48
+ * Adapted from Vercel AI SDK's zod3Schema and zod4Schema functions.
49
+ * Source: https://github.com/vercel/ai/blob/main/packages/provider-utils/src/schema.ts#L237-L269
50
+ *
51
+ * @param schema - The Zod schema to convert
52
+ * @param isOpenai - Whether to use OpenAI-specific formatting (default: true)
53
+ * @returns A JSON Schema representation of the Zod schema
54
+ */
55
+ export declare function zodSchemaToJsonSchema(schema: ZodSchema, isOpenai?: boolean): JSONSchema7;
56
+ /**
57
+ * Parses a value against a Zod schema.
58
+ * Handles both Zod v3 and v4 parse APIs automatically.
59
+ *
60
+ * @param schema - The Zod schema to parse against
61
+ * @param value - The value to parse
62
+ * @returns A promise that resolves to the parse result
63
+ */
64
+ export declare function parseZodSchema<T = unknown>(schema: ZodSchema, value: unknown): Promise<ZodParseResult<T>>;
65
+ //# sourceMappingURL=zod-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod-utils.d.ts","sourceRoot":"","sources":["../../src/llm/zod-utils.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE7B;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,OAAO,IAClC;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAC1B;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAEvC;;;;;;GAMG;AAEH,MAAM,MAAM,SAAS,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;AAExF;;;;;;GAMG;AAEH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAGpF;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAmB9D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAmB5D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,GAAE,OAAc,GAAG,WAAW,CAmB9F;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,CAAC,GAAG,OAAO,EAC9C,MAAM,EAAE,SAAS,EACjB,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAQ5B"}
@@ -0,0 +1,61 @@
1
+ import { zodToJsonSchema as zodToJsonSchemaV3 } from "zod-to-json-schema";
2
+ import * as z4 from "zod/v4";
3
+ function isZod4Schema(schema) {
4
+ return "_zod" in schema;
5
+ }
6
+ function isZodSchema(value) {
7
+ if (typeof value !== "object" || value === null) {
8
+ return false;
9
+ }
10
+ if ("_zod" in value) {
11
+ return true;
12
+ }
13
+ if ("_def" in value && typeof value._def === "object" && value._def !== null) {
14
+ const def = value._def;
15
+ if ("typeName" in def) {
16
+ return true;
17
+ }
18
+ }
19
+ return false;
20
+ }
21
+ function isZodObjectSchema(schema) {
22
+ var _a, _b, _c, _d;
23
+ const schemaWithInternals = schema;
24
+ if (isZod4Schema(schema)) {
25
+ return ((_a = schemaWithInternals._def) == null ? void 0 : _a.type) === "object" || ((_c = (_b = schemaWithInternals._zod) == null ? void 0 : _b.traits) == null ? void 0 : _c.has("ZodObject")) || false;
26
+ }
27
+ return ((_d = schemaWithInternals._def) == null ? void 0 : _d.typeName) === "ZodObject";
28
+ }
29
+ function zodSchemaToJsonSchema(schema, isOpenai = true) {
30
+ if (isZod4Schema(schema)) {
31
+ return z4.toJSONSchema(schema, {
32
+ target: "draft-7",
33
+ io: "output",
34
+ reused: "inline"
35
+ // Don't use references by default (to support openapi conversion for google)
36
+ });
37
+ } else {
38
+ return zodToJsonSchemaV3(schema, {
39
+ target: isOpenai ? "openAi" : "jsonSchema7",
40
+ $refStrategy: "none"
41
+ // Don't use references by default (to support openapi conversion for google)
42
+ });
43
+ }
44
+ }
45
+ async function parseZodSchema(schema, value) {
46
+ if (isZod4Schema(schema)) {
47
+ const result = await z4.safeParseAsync(schema, value);
48
+ return result;
49
+ } else {
50
+ const result = await schema.safeParseAsync(value);
51
+ return result;
52
+ }
53
+ }
54
+ export {
55
+ isZod4Schema,
56
+ isZodObjectSchema,
57
+ isZodSchema,
58
+ parseZodSchema,
59
+ zodSchemaToJsonSchema
60
+ };
61
+ //# sourceMappingURL=zod-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/llm/zod-utils.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { JSONSchema7 } from 'json-schema';\nimport { zodToJsonSchema as zodToJsonSchemaV3 } from 'zod-to-json-schema';\nimport type * as z3 from 'zod/v3';\nimport * as z4 from 'zod/v4';\n\n/**\n * Result type from Zod schema parsing.\n */\nexport type ZodParseResult<T = unknown> =\n | { success: true; data: T }\n | { success: false; error: unknown };\n\n/**\n * Type definition for Zod schemas that works with both v3 and v4.\n * Uses a union type of both Zod v3 and v4 schema types.\n *\n * Adapted from Vercel AI SDK's zodSchema function signature.\n * Source: https://github.com/vercel/ai/blob/main/packages/provider-utils/src/schema.ts#L278-L281\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type ZodSchema = z4.core.$ZodType<any, any> | z3.Schema<any, z3.ZodTypeDef, any>;\n\n/**\n * Detects if a schema is a Zod v4 schema.\n * Zod v4 schemas have a `_zod` property that v3 schemas don't have.\n *\n * @param schema - The schema to check\n * @returns True if the schema is a Zod v4 schema\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Required to match Zod v4's type signature\nexport function isZod4Schema(schema: ZodSchema): schema is z4.core.$ZodType<any, any> {\n // https://zod.dev/library-authors?id=how-to-support-zod-3-and-zod-4-simultaneously\n return '_zod' in schema;\n}\n\n/**\n * Checks if a value is a Zod schema (either v3 or v4).\n *\n * @param value - The value to check\n * @returns True if the value is a Zod schema\n */\nexport function isZodSchema(value: unknown): value is ZodSchema {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n // Check for v4 schema (_zod property)\n if ('_zod' in value) {\n return true;\n }\n\n // Check for v3 schema (_def property with typeName)\n if ('_def' in value && typeof value._def === 'object' && value._def !== null) {\n const def = value._def as Record<string, unknown>;\n if ('typeName' in def) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Checks if a Zod schema is an object schema.\n *\n * @param schema - The schema to check\n * @returns True if the schema is an object schema\n */\nexport function isZodObjectSchema(schema: ZodSchema): boolean {\n // Need to access internal Zod properties to check schema type\n const schemaWithInternals = schema as {\n _def?: { type?: string; typeName?: string };\n _zod?: { traits?: Set<string> };\n };\n\n // Check for v4 schema first\n if (isZod4Schema(schema)) {\n // v4 uses _def.type and _zod.traits\n return (\n schemaWithInternals._def?.type === 'object' ||\n schemaWithInternals._zod?.traits?.has('ZodObject') ||\n false\n );\n }\n\n // v3 uses _def.typeName\n return schemaWithInternals._def?.typeName === 'ZodObject';\n}\n\n/**\n * Converts a Zod schema to JSON Schema format.\n * Handles both Zod v3 and v4 schemas automatically.\n *\n * Adapted from Vercel AI SDK's zod3Schema and zod4Schema functions.\n * Source: https://github.com/vercel/ai/blob/main/packages/provider-utils/src/schema.ts#L237-L269\n *\n * @param schema - The Zod schema to convert\n * @param isOpenai - Whether to use OpenAI-specific formatting (default: true)\n * @returns A JSON Schema representation of the Zod schema\n */\nexport function zodSchemaToJsonSchema(schema: ZodSchema, isOpenai: boolean = true): JSONSchema7 {\n if (isZod4Schema(schema)) {\n // Zod v4 has native toJSONSchema support\n // Configuration adapted from Vercel AI SDK to support OpenAPI conversion for Google\n // Source: https://github.com/vercel/ai/blob/main/packages/provider-utils/src/schema.ts#L255-L258\n return z4.toJSONSchema(schema, {\n target: 'draft-7',\n io: 'output',\n reused: 'inline', // Don't use references by default (to support openapi conversion for google)\n }) as JSONSchema7;\n } else {\n // Zod v3 requires the zod-to-json-schema library\n // Configuration adapted from Vercel AI SDK\n // $refStrategy: 'none' is equivalent to v4's reused: 'inline'\n return zodToJsonSchemaV3(schema, {\n target: isOpenai ? 'openAi' : 'jsonSchema7',\n $refStrategy: 'none', // Don't use references by default (to support openapi conversion for google)\n }) as JSONSchema7;\n }\n}\n\n/**\n * Parses a value against a Zod schema.\n * Handles both Zod v3 and v4 parse APIs automatically.\n *\n * @param schema - The Zod schema to parse against\n * @param value - The value to parse\n * @returns A promise that resolves to the parse result\n */\nexport async function parseZodSchema<T = unknown>(\n schema: ZodSchema,\n value: unknown,\n): Promise<ZodParseResult<T>> {\n if (isZod4Schema(schema)) {\n const result = await z4.safeParseAsync(schema, value);\n return result as ZodParseResult<T>;\n } else {\n const result = await schema.safeParseAsync(value);\n return result as ZodParseResult<T>;\n }\n}\n"],"mappings":"AAIA,SAAS,mBAAmB,yBAAyB;AAErD,YAAY,QAAQ;AA2Bb,SAAS,aAAa,QAAyD;AAEpF,SAAO,UAAU;AACnB;AAQO,SAAS,YAAY,OAAoC;AAC9D,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,OAAO;AACnB,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,SAAS,OAAO,MAAM,SAAS,YAAY,MAAM,SAAS,MAAM;AAC5E,UAAM,MAAM,MAAM;AAClB,QAAI,cAAc,KAAK;AACrB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,kBAAkB,QAA4B;AAvE9D;AAyEE,QAAM,sBAAsB;AAM5B,MAAI,aAAa,MAAM,GAAG;AAExB,aACE,yBAAoB,SAApB,mBAA0B,UAAS,cACnC,+BAAoB,SAApB,mBAA0B,WAA1B,mBAAkC,IAAI,iBACtC;AAAA,EAEJ;AAGA,WAAO,yBAAoB,SAApB,mBAA0B,cAAa;AAChD;AAaO,SAAS,sBAAsB,QAAmB,WAAoB,MAAmB;AAC9F,MAAI,aAAa,MAAM,GAAG;AAIxB,WAAO,GAAG,aAAa,QAAQ;AAAA,MAC7B,QAAQ;AAAA,MACR,IAAI;AAAA,MACJ,QAAQ;AAAA;AAAA,IACV,CAAC;AAAA,EACH,OAAO;AAIL,WAAO,kBAAkB,QAAQ;AAAA,MAC/B,QAAQ,WAAW,WAAW;AAAA,MAC9B,cAAc;AAAA;AAAA,IAChB,CAAC;AAAA,EACH;AACF;AAUA,eAAsB,eACpB,QACA,OAC4B;AAC5B,MAAI,aAAa,MAAM,GAAG;AACxB,UAAM,SAAS,MAAM,GAAG,eAAe,QAAQ,KAAK;AACpD,WAAO;AAAA,EACT,OAAO;AACL,UAAM,SAAS,MAAM,OAAO,eAAe,KAAK;AAChD,WAAO;AAAA,EACT;AACF;","names":[]}