feat: support zod v4 & v3 (#2186)

Co-authored-by: Marcus Schiesser <mail@marcusschiesser.de>
This commit is contained in:
Thuc Pham
2025-09-11 09:34:45 +07:00
committed by GitHub
parent 1285e381bd
commit 5da1cda939
55 changed files with 735 additions and 330 deletions
+10
View File
@@ -0,0 +1,10 @@
---
"@llamaindex/core": patch
"@llamaindex/tools": patch
"@llamaindex/workflow": patch
"@llamaindex/ollama": patch
"@llamaindex/openai": patch
"@llamaindex/vercel": patch
---
feat: support zod v4 & v3
+3 -2
View File
@@ -105,6 +105,7 @@ jobs:
run: |
pnpm pack --pack-destination ${{ runner.temp }} -C packages/llamaindex
pnpm pack --pack-destination ${{ runner.temp }} -C packages/workflow
pnpm pack --pack-destination ${{ runner.temp }} -C packages/core
- name: Install packed packages
run: npm add ${{ runner.temp }}/*.tgz
working-directory: e2e/npm
@@ -162,7 +163,7 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }}
directory: e2e/examples/vite-import-llamaindex
skip_step: "install"
build_script: build
build_script: ci-build
package_manager: pnpm
typecheck-examples:
@@ -203,7 +204,7 @@ jobs:
fi
done
- name: Install
run: npm add ${{ runner.temp }}/*.tgz
run: npm add ${{ runner.temp }}/*.tgz --legacy-peer-deps
working-directory: ${{ runner.temp }}/examples
- name: Run Type Check
run: npx tsc --project ./tsconfig.json
+1 -3
View File
@@ -44,9 +44,7 @@ export const getWeatherTool = FunctionTool.from(
name: "getWeather",
description: "Get the weather for a city",
parameters: z.object({
city: z.string({
description: "The city to get the weather for",
}),
city: z.string().describe("The city to get the weather for"),
}),
},
);
+1 -3
View File
@@ -20,9 +20,7 @@ const saveFileTool = tool({
description:
"Save the written content into a file that can be downloaded by the user",
parameters: z.object({
content: z.string({
description: "The content to save into a file",
}),
content: z.string().describe("The content to save into a file"),
}),
execute: ({ content }: { content: string }) => {
const filePath = os.tmpdir() + "/report.md";
+1 -3
View File
@@ -17,9 +17,7 @@ const userQuestion = "which are the best comedies after 2010?";
description:
"Execute python code in a Jupyter notebook cell and return any result, stdout, stderr, display_data, and error.",
parameters: z.object({
code: z.string({
description: "The python code to execute in a single cell.",
}),
code: z.string().describe("The python code to execute in a single cell."),
}),
execute: ({ code }) => {
console.log(
+2 -6
View File
@@ -26,9 +26,7 @@ const temperatureConverterTool = tool({
description: "Convert a temperature from Fahrenheit to Celsius",
name: "fahrenheitToCelsius",
parameters: z.object({
temperature: z.number({
description: "The temperature in Fahrenheit",
}),
temperature: z.number().describe("The temperature in Fahrenheit"),
}),
execute: ({ temperature }) => {
return ((temperature - 32) * 5) / 9;
@@ -39,9 +37,7 @@ const temperatureFetcherTool = tool({
description: "Fetch the temperature (in Fahrenheit) for a city",
name: "fetchTemperature",
parameters: z.object({
city: z.string({
description: "The city to fetch the temperature for",
}),
city: z.string().describe("The city to fetch the temperature for"),
}),
execute: ({ city }) => {
const temperature = Math.floor(Math.random() * 58) + 32;
+3 -9
View File
@@ -14,9 +14,7 @@ const weatherTool = tool({
name: "weather",
description: "Get the weather",
parameters: z.object({
location: z.string({
description: "The location to get the weather for",
}),
location: z.string().describe("The location to get the weather for"),
}),
execute: ({ location }) => {
return `The weather in ${location} is sunny`;
@@ -27,9 +25,7 @@ const inflationTool = tool({
name: "inflation",
description: "Get the inflation",
parameters: z.object({
location: z.string({
description: "The location to get the inflation for",
}),
location: z.string().describe("The location to get the inflation for"),
}),
execute: ({ location }) => {
return `The inflation in ${location} is 2%`;
@@ -41,9 +37,7 @@ const saveFileTool = tool({
description:
"Save the written content into a file that can be downloaded by the user",
parameters: z.object({
content: z.string({
description: "The content to save into a file",
}),
content: z.string().describe("The content to save into a file"),
}),
execute: ({ content }) => {
const filePath = "./report.md";
+2 -5
View File
@@ -14,11 +14,8 @@ const writeJokeSchema = z.object({
.describe("The topic to write a joke or describe the joke to improve."),
writtenJoke: z.optional(z.string()).describe("The written joke."),
retriedTimes: z
.number()
.default(0)
.describe(
"The retried times for writing the joke. Always increase this from the input retriedTimes.",
),
.optional(z.number().default(0))
.describe("The retried times for writing the joke."),
});
const critiqueSchema = z.object({
@@ -29,9 +29,9 @@ async function callLLM(init: { model: string }) {
description:
"Execute python code in a Jupyter notebook cell and return any result, stdout, stderr, display_data, and error.",
parameters: z.object({
code: z.string({
description: "The python code to execute in a single cell.",
}),
code: z
.string()
.describe("The python code to execute in a single cell."),
}),
},
);
+1 -3
View File
@@ -8,9 +8,7 @@ const weatherTool = tool({
name: "weather",
description: "Get the weather",
parameters: z.object({
location: z.string({
description: "The location to get the weather for",
}),
location: z.string().describe("The location to get the weather for"),
}),
execute: ({ location }) => {
return `The weather in ${location} is rainy`;
@@ -7,9 +7,7 @@ async function main() {
name: "weather",
description: "Get the weather",
parameters: z.object({
location: z.string({
description: "The location to get the weather for",
}),
location: z.string().describe("The location to get the weather for"),
}),
execute: ({ location }) => {
return `The weather in ${location} is sunny`;
+2 -2
View File
@@ -1,6 +1,6 @@
import { openai } from "@ai-sdk/openai";
import { llamaindex } from "@llamaindex/vercel";
import { streamText } from "ai";
import { stepCountIs, streamText } from "ai";
import { Document, LlamaCloudIndex } from "llamaindex";
import fs from "node:fs/promises";
@@ -28,7 +28,7 @@ async function main() {
"get information from your knowledge base to answer questions.", // optional description
}),
},
maxSteps: 5,
stopWhen: stepCountIs(5),
});
for await (const textPart of result.textStream) {
+2 -2
View File
@@ -1,6 +1,6 @@
import { openai } from "@ai-sdk/openai";
import { llamaindex } from "@llamaindex/vercel";
import { streamText } from "ai";
import { stepCountIs, streamText } from "ai";
import { Document, VectorStoreIndex } from "llamaindex";
import fs from "node:fs/promises";
@@ -24,7 +24,7 @@ async function main() {
"get information from your knowledge base to answer questions.", // optional description
}),
},
maxSteps: 5,
stopWhen: stepCountIs(5),
});
for await (const textPart of result.textStream) {
+3 -3
View File
@@ -7,7 +7,7 @@
"start": "echo 'To get started, run `npx tsx <path to example>`'"
},
"dependencies": {
"@ai-sdk/openai": "^1.0.5",
"@ai-sdk/openai": "^2.0.27",
"@azure/cosmos": "^4.1.1",
"@azure/identity": "^4.4.1",
"@azure/search-documents": "^12.1.0",
@@ -60,7 +60,7 @@
"@notionhq/client": "^4.0.0",
"@pinecone-database/pinecone": "^4.0.0",
"@vercel/postgres": "^0.10.0",
"ai": "^4.3.17",
"ai": "^5.0.39",
"ajv": "^8.17.1",
"commander": "^12.1.0",
"dotenv": "^17.2.0",
@@ -69,7 +69,7 @@
"mongodb": "6.7.0",
"postgres": "^3.4.4",
"wikipedia": "^2.1.2",
"zod": "^3.25.76"
"zod": "^4.1.5"
},
"devDependencies": {
"@types/express": "^5.0.3",
+15 -3
View File
@@ -278,6 +278,17 @@
"default": "./postprocessor/dist/index.js"
},
"default": "./postprocessor/dist/index.js"
},
"./zod": {
"require": {
"types": "./zod/dist/index.d.cts",
"default": "./zod/dist/index.cjs"
},
"import": {
"types": "./zod/dist/index.d.ts",
"default": "./zod/dist/index.js"
},
"default": "./zod/dist/index.js"
}
},
"files": [
@@ -302,7 +313,8 @@
"./vector-store",
"./tools",
"./data-structs",
"./postprocessor"
"./postprocessor",
"./zod"
],
"scripts": {
"dev": "bunchee --watch",
@@ -321,9 +333,9 @@
},
"dependencies": {
"@llamaindex/env": "workspace:*",
"@finom/zod-to-json-schema": "3.24.11",
"@types/node": "^24.0.13",
"magic-bytes.js": "^1.10.0",
"zod": "^3.25.76",
"zod-to-json-schema": "^3.24.6"
"zod": "^4.1.5"
}
}
+2 -3
View File
@@ -1,5 +1,4 @@
import type { Logger } from "@llamaindex/env";
import { z } from "zod";
import { type JSONObject, type JSONValue, Settings } from "../global";
import type {
BaseTool,
@@ -13,7 +12,7 @@ import type {
ToolCallLLMMessageOptions,
ToolOutput,
} from "../llms";
import { baseToolWithCallSchema } from "../schema";
import { agentParamsSchema } from "../schema";
import {
assertIsJSONValue,
isAsyncIterable,
@@ -305,7 +304,7 @@ export function validateAgentParams<AI extends LLM>(
params: AgentParamsBase<AI>,
) {
if ("tools" in params) {
z.array(baseToolWithCallSchema).parse(params.tools);
agentParamsSchema.parse(params.tools);
} else {
// todo: check `params.toolRetriever` when migrate to @llamaindex/core
}
+2 -2
View File
@@ -3,6 +3,7 @@ import type { JSONObject } from "../global";
import { tool } from "../tools/";
import { extractText } from "../utils/llms";
import { streamConverter } from "../utils/stream";
import { isZodSchema, safeParseSchema } from "../zod";
import { callToolToMessage, getToolCallsFromResponse } from "./tool-call";
import type {
ChatMessage,
@@ -20,7 +21,6 @@ import type {
PartialToolCall,
ToolCallLLMMessageOptions,
} from "./type";
import { isZodSchema } from "./utils";
export abstract class BaseLLM<
AdditionalChatOptions extends object = object,
@@ -107,7 +107,7 @@ export abstract class BaseLLM<
description: "Respond with a JSON object",
parameters: responseFormat,
execute: (args) => {
const result = responseFormat.safeParse(args);
const result = safeParseSchema(responseFormat, args);
if (!result.success) {
console.error("Invalid input from LLM:", result.error);
return JSON.stringify({
+4 -3
View File
@@ -1,9 +1,10 @@
import type { Logger } from "@llamaindex/env";
import type { Tokenizers } from "@llamaindex/env/tokenizers";
import type { JSONSchemaType } from "ajv";
import { z } from "zod";
import type { JSONObject, JSONValue } from "../global";
import type { ModalityType } from "../schema";
import type { ZodSchema } from "../zod";
/**
* @internal
*/
@@ -139,7 +140,7 @@ export interface LLMChatParamsBase<
messages: ChatMessage<AdditionalMessageOptions>[];
additionalChatOptions?: AdditionalChatOptions | undefined;
tools?: BaseTool[] | undefined;
responseFormat?: z.ZodType | object | undefined;
responseFormat?: ZodSchema | object | undefined;
logger?: Logger | undefined;
}
@@ -159,7 +160,7 @@ export interface LLMChatParamsNonStreaming<
export interface LLMCompletionParamsBase {
prompt: MessageContent;
responseFormat?: z.ZodType | object;
responseFormat?: ZodSchema | object;
}
export interface LLMCompletionParamsStreaming extends LLMCompletionParamsBase {
-13
View File
@@ -1,4 +1,3 @@
import { z } from "zod";
import type {
ChatMessage,
MessageContentImageDataDetail,
@@ -27,15 +26,3 @@ export function addContentPart<AdditionalMessageOptions extends object>(
}
}
}
export function isZodSchema(obj: unknown): obj is z.ZodType {
return (
obj !== null &&
typeof obj === "object" &&
"parse" in obj &&
typeof (obj as { parse: unknown }).parse === "function" &&
"safeParse" in obj &&
typeof (obj as { safeParse: unknown }).safeParse === "function" &&
"_def" in obj
);
}
@@ -1,10 +1,9 @@
import { consoleLogger, type Logger } from "@llamaindex/env";
import type { Tokenizer } from "@llamaindex/env/tokenizers";
import { z } from "zod";
import { Settings } from "../global";
import { sentenceSplitterSchema } from "../schema";
import { sentenceSplitterSchema, type SentenceSplitterParams } from "../schema";
import { MetadataAwareTextSplitter } from "./base";
import type { SplitterParams } from "./type";
import type { PartialWithUndefined, SplitterParams } from "./type";
import {
splitByChar,
splitByRegex,
@@ -52,7 +51,7 @@ export class SentenceSplitter extends MetadataAwareTextSplitter {
#logger: Logger;
constructor(
params?: z.input<typeof sentenceSplitterSchema> &
params?: PartialWithUndefined<SentenceSplitterParams> &
SplitterParams & { logger?: Logger },
) {
super();
@@ -1,12 +1,13 @@
import { randomUUID } from "@llamaindex/env";
import { z } from "zod";
import {
buildNodeFromSplits,
Document,
sentenceWindowNodeParserSchema,
TextNode,
type SentenceWindowNodeParserParams,
} from "../schema";
import { NodeParser } from "./base";
import type { PartialWithUndefined } from "./type";
import { splitBySentenceTokenizer, type TextSplitterFn } from "./utils";
export class SentenceWindowNodeParser extends NodeParser<TextNode[]> {
@@ -20,7 +21,7 @@ export class SentenceWindowNodeParser extends NodeParser<TextNode[]> {
sentenceSplitter: TextSplitterFn = splitBySentenceTokenizer([], true);
idGenerator: () => string = () => randomUUID();
constructor(params?: z.input<typeof sentenceWindowNodeParserSchema>) {
constructor(params?: PartialWithUndefined<SentenceWindowNodeParserParams>) {
super();
if (params) {
const parsedParams = sentenceWindowNodeParserSchema.parse(params);
@@ -1,20 +1,16 @@
import { consoleLogger, type Logger } from "@llamaindex/env";
import type { Tokenizer } from "@llamaindex/env/tokenizers";
import { z } from "zod";
import { DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE, Settings } from "../global";
import {
tokenTextSplitterSchema,
type TokenTextSplitterParams,
} from "../schema";
import { MetadataAwareTextSplitter } from "./base";
import type { SplitterParams } from "./type";
import type { PartialWithUndefined, SplitterParams } from "./type";
import { splitByChar, splitBySep } from "./utils";
const DEFAULT_METADATA_FORMAT_LEN = 2;
const tokenTextSplitterSchema = z.object({
chunkSize: z.number().positive().default(DEFAULT_CHUNK_SIZE),
chunkOverlap: z.number().nonnegative().default(DEFAULT_CHUNK_OVERLAP),
separator: z.string().default(" "),
backupSeparators: z.array(z.string()).default(["\n"]),
});
export class TokenTextSplitter extends MetadataAwareTextSplitter {
chunkSize: number = DEFAULT_CHUNK_SIZE;
chunkOverlap: number = DEFAULT_CHUNK_OVERLAP;
@@ -26,7 +22,7 @@ export class TokenTextSplitter extends MetadataAwareTextSplitter {
constructor(
params?: SplitterParams &
Partial<z.infer<typeof tokenTextSplitterSchema>> & { logger?: Logger },
PartialWithUndefined<TokenTextSplitterParams> & { logger?: Logger },
) {
super();
+4
View File
@@ -3,3 +3,7 @@ import type { Tokenizer } from "@llamaindex/env/tokenizers";
export type SplitterParams = {
tokenizer?: Tokenizer;
};
export type PartialWithUndefined<T> = {
[P in keyof T]?: T[P] | undefined;
};
+17 -2
View File
@@ -1,5 +1,5 @@
import { z } from "zod";
import { Settings } from "../global";
import { z } from "zod/v3"; // use zod v3 to keep schemas as it is
import { DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE, Settings } from "../global";
export const anyFunctionSchema = z.function(z.tuple([]).rest(z.any()), z.any());
@@ -18,6 +18,8 @@ export const baseToolWithCallSchema = baseToolSchema.extend({
call: z.function(),
});
export const agentParamsSchema = z.array(baseToolWithCallSchema);
export const sentenceSplitterSchema = z
.object({
chunkSize: z
@@ -83,3 +85,16 @@ export const sentenceWindowNodeParserSchema = z.object({
})
.default("originalText"),
});
export const tokenTextSplitterSchema = z.object({
chunkSize: z.number().positive().default(DEFAULT_CHUNK_SIZE),
chunkOverlap: z.number().nonnegative().default(DEFAULT_CHUNK_OVERLAP),
separator: z.string().default(" "),
backupSeparators: z.array(z.string()).default(["\n"]),
});
export type SentenceSplitterParams = z.infer<typeof sentenceSplitterSchema>;
export type TokenTextSplitterParams = z.infer<typeof tokenTextSplitterSchema>;
export type SentenceWindowNodeParserParams = z.infer<
typeof sentenceWindowNodeParserSchema
>;
+63 -35
View File
@@ -1,10 +1,15 @@
import { consoleLogger, type Logger } from "@llamaindex/env";
import type { JSONSchemaType } from "ajv";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
import type * as z3 from "zod/v3";
import type * as z4 from "zod/v4/core";
import type { JSONValue } from "../global";
import type { BaseTool, ToolMetadata } from "../llms";
import { isZodSchema } from "../llms/utils";
import {
isZodSchema,
safeParseSchema,
type ZodSchema,
zodToJsonSchema,
} from "../zod";
export class FunctionTool<
T,
@@ -15,12 +20,13 @@ export class FunctionTool<
#fn: (input: T, additionalArg?: AdditionalToolArgument) => R;
#additionalArg: AdditionalToolArgument | undefined;
readonly #metadata: ToolMetadata<JSONSchemaType<T>>;
readonly #zodType: z.ZodType<T> | null = null;
readonly #zodType: ZodSchema<T> | null = null;
readonly #logger: Logger;
constructor(
fn: (input: T, additionalArg?: AdditionalToolArgument) => R,
metadata: ToolMetadata<JSONSchemaType<T>>,
zodType?: z.ZodType<T>,
zodType?: ZodSchema<T>,
additionalArg?: AdditionalToolArgument,
logger?: Logger,
) {
@@ -33,6 +39,9 @@ export class FunctionTool<
this.#logger = logger ?? consoleLogger;
}
// ----------------- OVERLOAD -----------------
// Plain JSON schema
static from<T, AdditionalToolArgument extends object = object>(
fn: (
input: T,
@@ -40,54 +49,74 @@ export class FunctionTool<
) => JSONValue | Promise<JSONValue>,
schema: ToolMetadata<JSONSchemaType<T>>,
): FunctionTool<T, JSONValue | Promise<JSONValue>, AdditionalToolArgument>;
static from<
R extends z.ZodType,
AdditionalToolArgument extends object = object,
>(
// Function + Object configs + Zod v3 schema
static from<R, AdditionalToolArgument extends object = object>(
fn: (
input: z.infer<R>,
// @ts-expect-error <R> should extend z3.ZodTypeAny
// but we remove that to fix type instantiation is excessively deep and possibly infinite
input: z3.infer<R>,
additionalArg?: AdditionalToolArgument,
) => JSONValue | Promise<JSONValue>,
schema: Omit<ToolMetadata, "parameters"> & {
parameters: R;
},
schema: Omit<ToolMetadata, "parameters"> & { parameters: R },
): FunctionTool<
z.infer<R>,
// @ts-expect-error <R> should extend z3.ZodTypeAny
// but we remove that to fix type instantiation is excessively deep and possibly infinite
z3.infer<R>,
JSONValue | Promise<JSONValue>,
AdditionalToolArgument
>;
static from<
T,
R extends z.ZodType<T>,
AdditionalToolArgument extends object = object,
>(
// Function + Object configs + Zod v4 schema
static from<R, AdditionalToolArgument extends object = object>(
fn: (
input: T,
input: z4.infer<R>,
additionalArg?: AdditionalToolArgument,
) => JSONValue | Promise<JSONValue>,
schema: Omit<ToolMetadata, "parameters"> & {
parameters: R;
},
): FunctionTool<T, JSONValue, AdditionalToolArgument>;
static from<
R extends z.ZodType,
AdditionalToolArgument extends object = object,
>(
schema: Omit<ToolMetadata, "parameters"> & { parameters: R },
): FunctionTool<
z4.infer<R>,
JSONValue | Promise<JSONValue>,
AdditionalToolArgument
>;
// Object configs + Zod v3 schema
static from<R, AdditionalToolArgument extends object = object>(
config: Omit<ToolMetadata, "parameters"> & {
parameters: R;
execute: (
input: z.infer<R>,
// @ts-expect-error <R> should extend z3.ZodTypeAny
// but we remove that to fix type instantiation is excessively deep and possibly infinite
input: z3.infer<R>,
additionalArg?: AdditionalToolArgument,
) => JSONValue | Promise<JSONValue>;
},
): FunctionTool<
z.infer<R>,
// @ts-expect-error <R> should extend z3.ZodTypeAny
// but we remove that to fix type instantiation is excessively deep and possibly infinite
z3.infer<R>,
JSONValue | Promise<JSONValue>,
AdditionalToolArgument
>;
// Object configs + Zod v4 schema
static from<R, AdditionalToolArgument extends object = object>(
config: Omit<ToolMetadata, "parameters"> & {
parameters: R;
execute: (
input: z4.infer<R>,
additionalArg?: AdditionalToolArgument,
) => JSONValue | Promise<JSONValue>;
},
): FunctionTool<
z4.infer<R>,
JSONValue | Promise<JSONValue>,
AdditionalToolArgument
>;
// ----------------- IMPLEMENTATION -----------------
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static from(fnOrConfig: any, schema?: any): any {
// Handle the case where an object with execute function is passed
if (
typeof schema === "undefined" &&
typeof fnOrConfig === "object" &&
@@ -109,8 +138,7 @@ export class FunctionTool<
return new FunctionTool(execute, fnOrConfig);
}
// Handle the original cases
if (schema && schema.parameters instanceof z.ZodSchema) {
if (schema && isZodSchema(schema.parameters)) {
const jsonSchema = zodToJsonSchema(schema.parameters);
return new FunctionTool(
fnOrConfig,
@@ -140,11 +168,11 @@ export class FunctionTool<
call = (input: T) => {
let params = input;
if (this.#zodType) {
const result = this.#zodType.safeParse(input);
const result = safeParseSchema(this.#zodType, input);
if (result.success) {
params = result.data;
} else {
this.#logger.warn(result.error.errors);
this.#logger.warn(result.error);
}
}
return this.#fn.call(null, params, this.#additionalArg);
+71
View File
@@ -0,0 +1,71 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { zodToJsonSchema as zodToJsonSchemaV3 } from "@finom/zod-to-json-schema";
import * as z from "zod";
import * as z3 from "zod/v3";
import * as z4 from "zod/v4/core";
export type ZodSchema<T = any> = z3.ZodType<T> | z4.$ZodType<T>;
export type ZodInfer<T extends ZodSchema> =
T extends z3.ZodType<any>
? z3.infer<T>
: T extends z4.$ZodType<any>
? z4.infer<T>
: never;
// support parsing both Zod 3 schemas and Zod 4 schemas
export function parseSchema<T>(schema: ZodSchema<T>, data: unknown): T {
if ("_zod" in schema) {
// Zod 4 schema
return z4.parse(schema as z4.$ZodType<T>, data);
} else {
// Zod 3 schema
return (schema as z3.ZodType<T>).parse(data);
}
}
// safe parse schema
export function safeParseSchema<T>(schema: ZodSchema<T>, data: unknown) {
if ("_zod" in schema) {
// Zod 4 schema
return z4.safeParse(schema as z4.$ZodType<T>, data);
} else {
// Zod 3 schema
return (schema as z3.ZodType<T>).safeParse(data);
}
}
export function isZodSchema(obj: unknown): obj is ZodSchema {
return (
obj !== null &&
typeof obj === "object" &&
"parse" in obj &&
typeof (obj as { parse: unknown }).parse === "function" &&
"safeParse" in obj &&
typeof (obj as { safeParse: unknown }).safeParse === "function"
);
}
// zod 3 schema does not have _zod property
export function isZodV3Schema(obj: unknown): obj is z3.ZodTypeAny {
return isZodSchema(obj) && !("_zod" in obj);
}
// zod 4 schema has _zod property
export function isZodV4Schema(obj: unknown): obj is z4.$ZodType {
return isZodSchema(obj) && "_zod" in obj;
}
export function zodToJsonSchema(obj: ZodSchema) {
if (isZodV4Schema(obj)) {
// if schema is created from zod v4, use native toJSONSchema
return z4.toJSONSchema(obj);
}
// otherwise, use zod-to-json-schema
return zodToJsonSchemaV3(obj as any); // FIXME: use any to avoid type instantiation excessively
}
// re-export zod
export { z, z3, z4 };
+1 -1
View File
@@ -1,7 +1,7 @@
import { LLMAgent, validateAgentParams } from "@llamaindex/core/agent";
import { MockLLM } from "@llamaindex/core/llms/mock";
import { expect, test } from "vitest";
import { ZodError } from "zod";
import { ZodError } from "zod/v3";
test("validate agent params", () => {
validateAgentParams({
+2 -1
View File
@@ -7,6 +7,7 @@
},
"devDependencies": {
"@llamaindex/core": "workspace:*",
"vitest": "^2.1.5"
"vitest": "^2.1.5",
"zod": "^4.1.5"
}
}
+65 -1
View File
@@ -1,6 +1,7 @@
import { FunctionTool, tool } from "@llamaindex/core/tools";
import { describe, expect, test, vi } from "vitest";
import { z } from "zod";
import { z } from "zod/v3";
import { z as z4 } from "zod/v4";
describe("FunctionTool", () => {
test("type system", () => {
@@ -95,4 +96,67 @@ describe("FunctionTool", () => {
expect(hello).to.toHaveBeenCalledOnce();
expect(hello).to.toHaveBeenCalledWith("Bob", additionalArg);
});
test("works with Zod v4 schema", async () => {
const mockFn = vi.fn().mockImplementation(({ age }: { age: number }) => {
return `Age is ${age}`;
});
const schema = z4.object({
age: z4.number().int().min(0),
});
const toolV4 = FunctionTool.from(mockFn, {
name: "checkAge",
description: "Checks age",
parameters: schema,
});
const result = await toolV4.call({ age: 25 });
expect(result).toBe("Age is 25");
expect(mockFn).toHaveBeenCalledWith({ age: 25 }, undefined);
});
test("validates input with safeParseSchema (valid + invalid)", async () => {
const mockFn = vi.fn().mockImplementation(({ num }: { num: number }) => {
return num * 2;
});
const schema = z.object({
num: z.number(),
});
const toolWithValidation = FunctionTool.from(mockFn, {
name: "double",
description: "Doubles a number",
parameters: schema,
});
// valid input
const result = await toolWithValidation.call({ num: 10 });
expect(result).toBe(20);
// invalid input (string instead of number)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
await toolWithValidation.call({ num: "oops" } as any);
});
test("works with plain JSON schema", async () => {
const mockFn = vi.fn().mockImplementation(({ msg }: { msg: string }) => {
return msg.toUpperCase();
});
const toolWithJson = FunctionTool.from(mockFn, {
name: "shout",
description: "Shouts the message",
parameters: {
type: "object",
properties: { msg: { type: "string" } },
required: ["msg"],
},
});
const result = await toolWithJson.call({ msg: "hi" });
expect(result).toBe("HI");
});
});
+160
View File
@@ -0,0 +1,160 @@
import {
isZodSchema,
isZodV3Schema,
isZodV4Schema,
parseSchema,
safeParseSchema,
zodToJsonSchema,
} from "@llamaindex/core/zod";
import { describe, expect, it } from "vitest";
import { z as z3 } from "zod/v3";
import { z as z4 } from "zod/v4";
describe("Zod schema utils", () => {
describe("parseSchema / safeParseSchema", () => {
it("parses valid data with Zod v3 schema", () => {
const schema = z3.object({ name: z3.string() });
const result = parseSchema(schema, { name: "Alice" });
expect(result).toEqual({ name: "Alice" });
});
it("parses valid data with Zod v4 schema", () => {
const schema = z4.object({ age: z4.number() });
const result = parseSchema(schema, { age: 42 });
expect(result).toEqual({ age: 42 });
});
it("safeParse works with invalid data (v3)", () => {
const schema = z3.object({ name: z3.string() });
const res = safeParseSchema(schema, { name: 123 });
expect(res.success).toBe(false);
});
it("safeParse works with invalid data (v4)", () => {
const schema = z4.object({ age: z4.number() });
const res = safeParseSchema(schema, { age: "oops" });
expect(res.success).toBe(false);
});
});
describe("isZodV3Schema / isZodV4Schema / isZodSchema", () => {
it("detects a v3 schema", () => {
const schema = z3.string();
expect(isZodV3Schema(schema)).toBe(true);
expect(isZodSchema(schema)).toBe(true);
expect(isZodV4Schema(schema)).toBe(false);
});
it("detects a v4 schema", () => {
const schema = z4.string();
expect(isZodV4Schema(schema)).toBe(true);
expect(isZodSchema(schema)).toBe(true);
expect(isZodV3Schema(schema)).toBe(false);
});
it("returns false for non-schemas", () => {
expect(isZodSchema(123)).toBe(false);
expect(isZodSchema({})).toBe(false);
});
});
describe("zodToJsonSchema", () => {
it("converts v3 string schema", () => {
const schema = z3.string().min(2).max(5).describe("A short string");
const json = zodToJsonSchema(schema);
expect(json).toMatchObject({
type: "string",
minLength: 2,
maxLength: 5,
description: "A short string",
});
});
it("converts v3 object schema", () => {
const schema = z3.object({
id: z3.number(),
name: z3.string().optional(),
});
const json = zodToJsonSchema(schema);
expect(json).toMatchObject({
type: "object",
properties: {
id: { type: "number" },
name: { type: "string" },
},
required: ["id"],
});
});
it("converts v4 array schema", () => {
const schema = z4.array(z4.boolean());
const json = zodToJsonSchema(schema);
expect(json).toMatchObject({
type: "array",
items: { type: "boolean" },
});
});
it("converts v4 enum schema", () => {
const schema = z4.enum(["red", "green", "blue"]);
const json = zodToJsonSchema(schema);
expect(json).toMatchObject({
type: "string",
enum: ["red", "green", "blue"],
});
});
it("handles nested v3 objects", () => {
const schema = z3.object({
user: z3.object({
id: z3.number(),
tags: z3.array(z3.string()),
}),
});
const json = zodToJsonSchema(schema);
expect(json).toMatchObject({
type: "object",
properties: {
user: {
type: "object",
properties: {
id: { type: "number" },
tags: {
type: "array",
items: { type: "string" },
},
},
required: ["id", "tags"],
},
},
required: ["user"],
});
});
it("handles nested v4 objects", () => {
const schema = z4.object({
profile: z4.object({
email: z4.string(),
active: z4.boolean(),
}),
});
const json = zodToJsonSchema(schema);
expect(json).toMatchObject({
type: "object",
properties: {
profile: {
type: "object",
properties: {
email: { type: "string" },
active: { type: "boolean" },
},
required: ["email", "active"],
additionalProperties: false,
},
},
required: ["profile"],
additionalProperties: false,
});
});
});
});
+8
View File
@@ -0,0 +1,8 @@
{
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": "./dist/index.js",
"private": true
}
+1 -11
View File
@@ -39,16 +39,6 @@
},
"peerDependencies": {
"@llamaindex/core": "workspace:*",
"@llamaindex/env": "workspace:*",
"zod": "^3.25.67",
"zod-to-json-schema": "^3.24.6"
},
"peerDependenciesMeta": {
"zod": {
"optional": true
},
"zod-to-json-schema": {
"optional": true
}
"@llamaindex/env": "workspace:*"
}
}
+2 -21
View File
@@ -13,6 +13,7 @@ import {
type ToolCallLLMMessageOptions,
} from "@llamaindex/core/llms";
import { extractText, streamConverter } from "@llamaindex/core/utils";
import { isZodSchema, zodToJsonSchema } from "@llamaindex/core/zod";
import { randomUUID } from "@llamaindex/env";
import type { ChatRequest, GenerateRequest, Tool } from "ollama";
import {
@@ -57,22 +58,6 @@ export type OllamaParams = {
options?: Partial<Options>;
};
async function getZod() {
try {
return await import("zod");
} catch (e) {
throw new Error("zod is required for structured output");
}
}
async function getZodToJsonSchema() {
try {
return await import("zod-to-json-schema");
} catch (e) {
throw new Error("zod-to-json-schema is required for structured output");
}
}
export class Ollama extends ToolCallLLM {
supportToolCall: boolean = true;
public readonly ollama: OllamaBase;
@@ -153,11 +138,7 @@ export class Ollama extends ToolCallLLM {
}
if (responseFormat && this.metadata.structuredOutput) {
const [{ zodToJsonSchema }, { z }] = await Promise.all([
getZodToJsonSchema(),
getZod(),
]);
if (responseFormat instanceof z.ZodType)
if (isZodSchema(responseFormat))
payload.format = zodToJsonSchema(responseFormat);
}
+1 -1
View File
@@ -33,7 +33,7 @@
"devDependencies": {
"@llamaindex/core": "workspace:*",
"@llamaindex/env": "workspace:*",
"zod": "^3.25.76"
"zod": "^4.1.5"
},
"peerDependencies": {
"@llamaindex/core": "workspace:*",
+38 -4
View File
@@ -13,13 +13,23 @@ import {
type ToolCallLLMMessageOptions,
} from "@llamaindex/core/llms";
import { extractText } from "@llamaindex/core/utils";
import {
isZodSchema,
parseSchema,
zodToJsonSchema,
type ZodInfer,
type ZodSchema,
} from "@llamaindex/core/zod";
import { getEnv } from "@llamaindex/env";
import { Tokenizers } from "@llamaindex/env/tokenizers";
import type {
ClientOptions as OpenAIClientOptions,
OpenAI as OpenAILLM,
} from "openai";
import { zodResponseFormat } from "openai/helpers/zod";
import {
makeParseableResponseFormat,
type AutoParseableResponseFormat,
} from "openai/lib/parser";
import type { ChatModel } from "openai/resources/chat/chat";
import type {
ChatCompletionAssistantMessageParam,
@@ -308,13 +318,12 @@ export class OpenAI extends ToolCallLLM<OpenAIAdditionalChatOptions> {
//add response format for the structured output
if (responseFormat && this.metadata.structuredOutput) {
// Check if it's a ZodType by looking for its parse and safeParse methods
if ("parse" in responseFormat && "safeParse" in responseFormat)
if (isZodSchema(responseFormat)) {
baseRequestParams.response_format = zodResponseFormat(
responseFormat,
"response_format",
);
else {
} else {
baseRequestParams.response_format = responseFormat as
| ResponseFormatJSONObject
| ResponseFormatJSONSchema;
@@ -461,3 +470,28 @@ export class OpenAI extends ToolCallLLM<OpenAIAdditionalChatOptions> {
*/
export const openai = (init?: ConstructorParameters<typeof OpenAI>[0]) =>
new OpenAI(init);
/**
* Rewrite zodResponseFormat from openai with zod v4 support
*/
function zodResponseFormat<ZodInput extends ZodSchema>(
zodObject: ZodInput,
name: string,
props?: Omit<
ResponseFormatJSONSchema.JSONSchema,
"schema" | "strict" | "name"
>,
): AutoParseableResponseFormat<ZodInfer<ZodInput>> {
return makeParseableResponseFormat(
{
type: "json_schema",
json_schema: {
...props,
name,
strict: true,
schema: zodToJsonSchema(zodObject),
},
},
(content) => parseSchema(zodObject, JSON.parse(content)),
);
}
+40 -5
View File
@@ -4,7 +4,8 @@ import {
ToolCallLLMMessageOptions,
} from "@llamaindex/core/llms";
import { describe, expect, it, vi } from "vitest";
import { z } from "zod";
import { z as z3 } from "zod/v3";
import { z as z4 } from "zod/v4";
import { OpenAI } from "../src/llm";
const API_KEY = process.env.OPENAI_API_KEY;
@@ -16,10 +17,10 @@ describe("OpenAI Chat Tests", () => {
}
describe("responseFormat with Zod schema", () => {
it("should handle zod schema as responseFormat", async () => {
it("should handle zod schema as responseFormat (zod v3)", async () => {
// Define a zod schema for the response format
const exampleSchema = z.object({
name: z.string(),
const zod3Schema = z3.object({
name: z3.string(),
});
const llm = new OpenAI({
@@ -35,7 +36,7 @@ describe("OpenAI Chat Tests", () => {
content: "Extract my name: Bernd",
},
],
responseFormat: exampleSchema,
responseFormat: zod3Schema,
});
// Verify the response
@@ -47,6 +48,40 @@ describe("OpenAI Chat Tests", () => {
// Verify the structure matches our schema
expect(parsedContent).toHaveProperty("name");
});
it("should handle zod schema as responseFormat (zod v4)", async () => {
// Define a zod schema for the response format
const zod4Schema = z4.object({
name: z4.string(),
age: z4.number(),
});
const llm = new OpenAI({
model: "gpt-4o-mini",
apiKey: API_KEY,
});
// Call the chat method with the zod schema as responseFormat
const response = await llm.chat({
messages: [
{
role: "user",
content: "Extract my name: Bernd, my age: 30",
},
],
responseFormat: zod4Schema,
});
// Verify the response
expect(response.message.content).toBeDefined();
// Parse the response content as JSON
const parsedContent = JSON.parse(response.message.content as string);
// Verify the structure matches our schema
expect(parsedContent).toHaveProperty("name");
expect(parsedContent).toHaveProperty("age");
});
});
});
@@ -1,4 +1,4 @@
import type { BaseNode } from "@llamaindex/core/schema";
import { MetadataMode, type BaseNode } from "@llamaindex/core/schema";
import {
BaseVectorStore,
metadataDictToNode,
@@ -10,7 +10,6 @@ import {
} from "@llamaindex/core/vector-store";
import { getEnv } from "@llamaindex/env";
import { createClient, type SupabaseClient } from "@supabase/supabase-js";
import { MetadataMode } from "../../../../core/schema/dist/index.cjs";
export interface SupabaseVectorStoreInit extends VectorStoreBaseParams {
client?: SupabaseClient;
+2 -5
View File
@@ -40,14 +40,11 @@
},
"devDependencies": {
"@llamaindex/core": "workspace:*",
"ai": "^4.3.17",
"ai": "^5.0.39",
"vitest": "^2.1.5"
},
"dependencies": {
"zod": "^3.25.76"
},
"peerDependencies": {
"@llamaindex/core": "workspace:*",
"ai": "^4.0.0"
"ai": "^5.0.39"
}
}
+25 -18
View File
@@ -13,30 +13,30 @@ import { extractText } from "@llamaindex/core/utils";
import {
generateText,
streamText,
type CoreAssistantMessage,
type CoreMessage,
type CoreSystemMessage,
type CoreToolMessage,
type AssistantModelMessage,
type CoreUserMessage,
type ImagePart,
type LanguageModelV1,
type LanguageModel,
type ModelMessage,
type SystemModelMessage,
type TextPart,
type ToolModelMessage,
} from "ai";
export type VercelAdditionalChatOptions = ToolCallLLMMessageOptions;
export class VercelLLM extends ToolCallLLM<VercelAdditionalChatOptions> {
supportToolCall: boolean = true;
private model: LanguageModelV1;
private model: LanguageModel;
constructor({ model }: { model: LanguageModelV1 }) {
constructor({ model }: { model: LanguageModel }) {
super();
this.model = model;
}
get metadata(): LLMMetadata {
return {
model: this.model.modelId,
model: this.model.toString(),
temperature: 1,
topP: 1,
contextWindow: 128000,
@@ -47,7 +47,7 @@ export class VercelLLM extends ToolCallLLM<VercelAdditionalChatOptions> {
private toVercelMessages(
messages: ChatMessage<ToolCallLLMMessageOptions>[],
): CoreMessage[] {
): ModelMessage[] {
return messages.map((message) => {
const options = message.options ?? {};
@@ -59,11 +59,18 @@ export class VercelLLM extends ToolCallLLM<VercelAdditionalChatOptions> {
type: "tool-result",
toolCallId: options.toolResult.id,
toolName: "", // XXX: tool result doesn't name
isError: options.toolResult.isError,
result: options.toolResult.result,
output: options.toolResult.isError
? {
type: "error-text",
value: options.toolResult.result,
}
: {
type: "text",
value: options.toolResult.result,
},
},
],
} satisfies CoreToolMessage;
} satisfies ToolModelMessage;
} else if ("toolCall" in options) {
return {
role: "assistant",
@@ -71,16 +78,16 @@ export class VercelLLM extends ToolCallLLM<VercelAdditionalChatOptions> {
type: "tool-call",
toolName: toolCall.name,
toolCallId: toolCall.id,
args: toolCall.input,
input: toolCall.input,
})),
} satisfies CoreAssistantMessage;
} satisfies AssistantModelMessage;
}
if (message.role === "system" || message.role === "assistant") {
return {
role: message.role,
content: extractText(message.content),
} satisfies CoreSystemMessage | CoreAssistantMessage;
} satisfies SystemModelMessage | AssistantModelMessage;
}
if (message.role === "user") {
@@ -157,7 +164,7 @@ export class VercelLLM extends ToolCallLLM<VercelAdditionalChatOptions> {
async transform(message, controller): Promise<void> {
switch (message.type) {
case "text-delta":
controller.enqueue({ raw: message, delta: message.textDelta });
controller.enqueue({ raw: message, delta: message.text });
}
},
}),
@@ -178,10 +185,10 @@ export class VercelLLM extends ToolCallLLM<VercelAdditionalChatOptions> {
options: result.toolCalls?.length
? {
toolCall: result.toolCalls.map(
({ toolCallId, toolName, args }) => ({
({ toolCallId, toolName, input }) => ({
id: toolCallId,
name: toolName,
input: args,
input,
}),
),
}
+4 -4
View File
@@ -1,8 +1,8 @@
import { Settings } from "@llamaindex/core/global";
import type { BaseQueryEngine } from "@llamaindex/core/query-engine";
import { EngineResponse } from "@llamaindex/core/schema";
import { type LanguageModelV1, type Tool, tool } from "ai";
import { z } from "zod";
import { z } from "@llamaindex/core/zod";
import { type LanguageModel, type Tool, tool } from "ai";
import { VercelLLM } from "./llm";
interface DatasourceIndex {
@@ -17,7 +17,7 @@ export function llamaindex({
description,
options,
}: {
model: LanguageModelV1;
model: LanguageModel;
index: DatasourceIndex;
description?: string;
options?: {
@@ -29,7 +29,7 @@ export function llamaindex({
const queryEngine = index.asQueryEngine();
return tool({
description: description ?? "Get information about your documents.",
parameters: z.object({
inputSchema: z.object({
query: z
.string()
.describe("The query to get information about your documents."),
+1 -2
View File
@@ -53,7 +53,6 @@
"got": "^14.4.1",
"marked": "^14.1.2",
"papaparse": "^5.4.1",
"wikipedia": "^2.1.2",
"zod": "^3.25.76"
"wikipedia": "^2.1.2"
}
}
@@ -1,7 +1,7 @@
import { Settings, type JSONValue } from "@llamaindex/core/global";
import type { ChatMessage, LLM } from "@llamaindex/core/llms";
import { tool } from "@llamaindex/core/tools";
import { z } from "zod";
import { z } from "@llamaindex/core/zod";
const CODE_ARTIFACT_GENERATION_PROMPT = `You are a highly skilled software engineer. Your task is to generate a code artifact based on the user's request.
Follow these instructions exactly:
+1 -1
View File
@@ -1,7 +1,7 @@
import { Settings, type JSONValue } from "@llamaindex/core/global";
import type { ChatMessage } from "@llamaindex/core/llms";
import { tool } from "@llamaindex/core/tools";
import { z } from "zod";
import { z } from "@llamaindex/core/zod";
// prompt based on https://github.com/e2b-dev/ai-artifacts
const CODE_GENERATION_PROMPT = `You are a skilled software engineer. You do not make mistakes. Generate an artifact. You can install additional dependencies. You can use one of the following templates:\n
@@ -1,7 +1,7 @@
import { Settings, type JSONValue } from "@llamaindex/core/global";
import type { ChatMessage, LLM } from "@llamaindex/core/llms";
import { tool } from "@llamaindex/core/tools";
import { z } from "zod";
import { z } from "@llamaindex/core/zod";
const DOCUMENT_ARTIFACT_GENERATION_PROMPT = `You are a highly skilled content creator. Your task is to generate a document artifact based on the user's request.
Follow these instructions exactly:
@@ -1,7 +1,7 @@
import { tool } from "@llamaindex/core/tools";
import { z } from "@llamaindex/core/zod";
import { marked } from "marked";
import path from "node:path";
import { z } from "zod";
import { getFileUrl, saveDocument } from "../helper";
const COMMON_STYLES = `
+1 -1
View File
@@ -1,6 +1,6 @@
import { tool } from "@llamaindex/core/tools";
import { z } from "@llamaindex/core/zod";
import { search } from "duck-duck-scrape";
import { z } from "zod";
export type DuckDuckGoToolOutput = Array<{
title: string;
+1 -1
View File
@@ -1,9 +1,9 @@
import { Settings } from "@llamaindex/core/global";
import { tool } from "@llamaindex/core/tools";
import { z } from "@llamaindex/core/zod";
import fs from "fs";
import Papa from "papaparse";
import path from "path";
import { z } from "zod";
import { getFileUrl, saveDocument } from "../helper";
export type MissingCell = {
+1 -1
View File
@@ -1,10 +1,10 @@
import { tool } from "@llamaindex/core/tools";
import { z } from "@llamaindex/core/zod";
import { randomUUID } from "@llamaindex/env";
import { FormData } from "formdata-node";
import got from "got";
import path from "path";
import { Readable } from "stream";
import { z } from "zod";
import { getFileUrl, saveDocument } from "../helper";
export type ImgGeneratorToolOutput = {
+1 -1
View File
@@ -1,9 +1,9 @@
import { type Logs, Result, Sandbox } from "@e2b/code-interpreter";
import { tool } from "@llamaindex/core/tools";
import { z } from "@llamaindex/core/zod";
import { randomUUID } from "@llamaindex/env";
import fs from "fs";
import path from "node:path";
import { z } from "zod";
import { getFileUrl, saveDocument } from "../helper";
export type InterpreterExtraType =
+1 -1
View File
@@ -1,5 +1,5 @@
import { tool } from "@llamaindex/core/tools";
import { z } from "zod";
import { z } from "@llamaindex/core/zod";
export type WeatherToolOutput = {
latitude: number;
+1 -1
View File
@@ -1,6 +1,6 @@
import { tool } from "@llamaindex/core/tools";
import { z } from "@llamaindex/core/zod";
import { default as wikipedia } from "wikipedia";
import { z } from "zod";
export type WikiToolOutput = {
title: string;
+4 -5
View File
@@ -40,15 +40,14 @@
"@llamaindex/core": "workspace:*",
"@llamaindex/env": "workspace:*",
"@types/node": "^24.0.13",
"vitest": "^2.1.5"
"vitest": "^2.1.5",
"zod": "^4.1.5"
},
"peerDependencies": {
"@llamaindex/core": "workspace:*",
"@llamaindex/env": "workspace:*",
"zod": "^3.25.67",
"zod-to-json-schema": "^3.24.6"
"@llamaindex/env": "workspace:*"
},
"dependencies": {
"@llamaindex/workflow-core": "^1.3.0"
"@llamaindex/workflow-core": "^1.3.2"
}
}
@@ -5,6 +5,7 @@ import { createMemory, Memory } from "@llamaindex/core/memory";
import { PromptTemplate } from "@llamaindex/core/prompts";
import { tool } from "@llamaindex/core/tools";
import { stringifyJSONToMessageContent } from "@llamaindex/core/utils";
import { z } from "@llamaindex/core/zod";
import { consoleLogger, emptyLogger, type Logger } from "@llamaindex/env";
import {
createWorkflow,
@@ -19,7 +20,6 @@ import {
createStatefulMiddleware,
type StatefulContext,
} from "@llamaindex/workflow-core/middleware/state";
import { z } from "zod";
import type { AgentWorkflowState, BaseWorkflowAgent } from "./base";
import {
agentInputEvent,
@@ -690,12 +690,8 @@ export class AgentWorkflow implements Workflow {
agent_info: JSON.stringify(agentInfo),
}),
parameters: z.object({
toAgent: z.string({
description: "The name of the agent to hand off to",
}),
reason: z.string({
description: "The reason for handing off to the agent",
}),
toAgent: z.string().describe("The name of the agent to hand off to"),
reason: z.string().describe("The reason for handing off to the agent"),
}),
execute: (
{
+10 -12
View File
@@ -7,12 +7,12 @@ import {
type ChatResponseChunk,
} from "@llamaindex/core/llms";
import { tool } from "@llamaindex/core/tools";
import { isZodV3Schema, z, zodToJsonSchema } from "@llamaindex/core/zod";
import {
type WorkflowContext,
type WorkflowEvent,
} from "@llamaindex/workflow-core";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
import { zodEvent } from "@llamaindex/workflow-core/util/zod";
import { AgentWorkflow } from "./agent-workflow";
import { type AgentWorkflowState, type BaseWorkflowAgent } from "./base";
import {
@@ -39,9 +39,7 @@ Your task is to handle the step using the provided tools and finally send an out
{instructions}
`;
export type ZodEvent = WorkflowEvent<unknown> & {
schema: z.ZodType<unknown>;
};
export type ZodEvent = ReturnType<typeof zodEvent>;
export type StepHandlerParams = {
/**
@@ -100,7 +98,7 @@ export type FunctionAgentParams = {
};
export type EmitEvent = {
event: WorkflowEvent<unknown> & { schema: z.ZodType<unknown> };
event: WorkflowEvent<unknown> & { schema: ZodEvent["schema"] };
name: string;
};
@@ -404,16 +402,19 @@ export class FunctionAgent implements BaseWorkflowAgent {
*/
const createEventEmitterTool = (
name: string,
event: WorkflowEvent<unknown> & { schema: z.ZodType<unknown> },
event: WorkflowEvent<unknown> & { schema: ZodEvent["schema"] },
workflowContext: WorkflowContext,
description?: string,
) => {
// To ensure the model correctly interprets the event data, including the schema in the tool description is crucial.
// This is particularly important for special types like literals and enums, which the model might struggle with otherwise.
// By incorporating the schema into the tool description, we can facilitate the model's understanding of the event data.
const eventSchemaDescription = isZodV3Schema(event.schema)
? event.schema.description
: null;
const toolDescriptionWithSchema =
(description ??
event.schema.description ??
eventSchemaDescription ??
"Use this tool to send the event to the workflow.") +
`\n\nPlease provide the event data in the following JSON schema: ${JSON.stringify(
zodToJsonSchema(z.object({ eventData: event.schema })),
@@ -424,10 +425,7 @@ const createEventEmitterTool = (
parameters: z.object({
eventData: event.schema,
}),
execute: (
{ eventData }: { eventData?: z.infer<typeof event.schema> },
getContext?: () => WorkflowContext,
) => {
execute: ({ eventData }, getContext?: () => WorkflowContext) => {
if (!getContext) {
throw new Error("Workflow context is not provided.");
}
+132 -96
View File
@@ -440,7 +440,7 @@ importers:
dependencies:
ai:
specifier: ^4.3.17
version: 4.3.17(react@19.0.0)(zod@3.25.76)
version: 4.3.17(react@19.0.0)(zod@4.1.5)
llamaindex:
specifier: workspace:*
version: link:../../../packages/llamaindex
@@ -603,8 +603,8 @@ importers:
examples:
dependencies:
'@ai-sdk/openai':
specifier: ^1.0.5
version: 1.3.12(zod@3.25.76)
specifier: ^2.0.27
version: 2.0.27(zod@4.1.5)
'@azure/cosmos':
specifier: ^4.1.1
version: 4.3.0
@@ -762,8 +762,8 @@ importers:
specifier: ^0.10.0
version: 0.10.0
ai:
specifier: ^4.3.17
version: 4.3.17(react@19.1.0)(zod@3.25.76)
specifier: ^5.0.39
version: 5.0.39(zod@4.1.5)
ajv:
specifier: ^8.17.1
version: 8.17.1
@@ -789,8 +789,8 @@ importers:
specifier: ^2.1.2
version: 2.1.2
zod:
specifier: ^3.25.76
version: 3.25.76
specifier: ^4.1.5
version: 4.1.5
devDependencies:
'@types/express':
specifier: ^5.0.3
@@ -1014,6 +1014,9 @@ importers:
packages/core:
dependencies:
'@finom/zod-to-json-schema':
specifier: 3.24.11
version: 3.24.11(zod@4.1.5)
'@llamaindex/env':
specifier: workspace:*
version: link:../env
@@ -1024,11 +1027,8 @@ importers:
specifier: ^1.10.0
version: 1.10.0
zod:
specifier: ^3.25.76
version: 3.25.76
zod-to-json-schema:
specifier: ^3.24.6
version: 3.24.6(zod@3.25.76)
specifier: ^4.1.5
version: 4.1.5
devDependencies:
'@edge-runtime/vm':
specifier: ^4.0.4
@@ -1051,6 +1051,9 @@ importers:
vitest:
specifier: ^2.1.5
version: 2.1.5(@edge-runtime/vm@5.0.0)(@types/node@24.0.13)(happy-dom@17.4.4)(lightningcss@1.29.3)(msw@2.7.4(@types/node@24.0.13)(typescript@5.9.2))(terser@5.39.0)
zod:
specifier: ^4.1.5
version: 4.1.5
packages/env:
dependencies:
@@ -1382,7 +1385,7 @@ importers:
dependencies:
'@mistralai/mistralai':
specifier: ^1.5.1
version: 1.5.2(zod@3.25.76)
version: 1.5.2(zod@4.1.5)
devDependencies:
'@llamaindex/core':
specifier: workspace:*
@@ -1431,12 +1434,6 @@ importers:
remeda:
specifier: ^2.17.3
version: 2.21.3
zod:
specifier: ^3.25.67
version: 3.25.67
zod-to-json-schema:
specifier: ^3.24.6
version: 3.24.6(zod@3.25.67)
devDependencies:
'@llamaindex/core':
specifier: workspace:*
@@ -1449,7 +1446,7 @@ importers:
dependencies:
openai:
specifier: ^5.12.0
version: 5.12.0(ws@8.18.1(bufferutil@4.0.9))(zod@3.25.76)
version: 5.12.0(ws@8.18.1(bufferutil@4.0.9))(zod@4.1.5)
devDependencies:
'@llamaindex/core':
specifier: workspace:*
@@ -1458,8 +1455,8 @@ importers:
specifier: workspace:*
version: link:../../env
zod:
specifier: ^3.25.76
version: 3.25.76
specifier: ^4.1.5
version: 4.1.5
packages/providers/perplexity:
dependencies:
@@ -1773,17 +1770,13 @@ importers:
version: link:../openai
packages/providers/vercel:
dependencies:
zod:
specifier: ^3.25.76
version: 3.25.76
devDependencies:
'@llamaindex/core':
specifier: workspace:*
version: link:../../core
ai:
specifier: ^4.3.17
version: 4.3.17(react@19.1.0)(zod@3.25.76)
specifier: ^5.0.39
version: 5.0.39(zod@4.1.5)
vitest:
specifier: ^2.1.5
version: 2.1.5(@edge-runtime/vm@5.0.0)(@types/node@24.0.13)(happy-dom@17.4.4)(lightningcss@1.29.3)(msw@2.7.4(@types/node@24.0.13)(typescript@5.9.2))(terser@5.39.0)
@@ -1879,9 +1872,6 @@ importers:
wikipedia:
specifier: ^2.1.2
version: 2.1.2
zod:
specifier: ^3.25.76
version: 3.25.76
devDependencies:
'@llamaindex/core':
specifier: workspace:*
@@ -1930,14 +1920,8 @@ importers:
packages/workflow:
dependencies:
'@llamaindex/workflow-core':
specifier: ^1.3.0
version: 1.3.0(@modelcontextprotocol/sdk@1.13.0)(hono@4.7.7)(next@15.3.3(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.76)
zod:
specifier: ^3.25.67
version: 3.25.76
zod-to-json-schema:
specifier: ^3.24.6
version: 3.24.6(zod@3.25.76)
specifier: ^1.3.2
version: 1.3.2(@modelcontextprotocol/sdk@1.13.0)(hono@4.7.7)(next@15.3.3(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@4.1.5)
devDependencies:
'@llamaindex/core':
specifier: workspace:*
@@ -1951,6 +1935,9 @@ importers:
vitest:
specifier: ^2.1.5
version: 2.1.5(@edge-runtime/vm@5.0.0)(@types/node@24.0.13)(happy-dom@17.4.4)(lightningcss@1.29.3)(msw@2.7.4(@types/node@24.0.13)(typescript@5.9.2))(terser@5.39.0)
zod:
specifier: ^4.1.5
version: 4.1.5
resolution-tests:
devDependencies:
@@ -2033,17 +2020,17 @@ importers:
packages:
'@ai-sdk/openai@1.3.12':
resolution: {integrity: sha512-ueAP69p8a/ZR2ns+pmlr9h/nyV2/DAwzfnPUGZiLpXbxWnLXd2g3a7l38CuEhBydH/nOfDb/byMgpS8+bnJHTg==}
'@ai-sdk/gateway@1.0.20':
resolution: {integrity: sha512-2K0kGnHyLfT1v2+3xXbLqohfWBJ/vmIh1FTWnrvZfvuUuBdOi2DMgnSQzkLvFVLyM8mhOcx+ZwU6IOOsuyOv/w==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
zod: ^3.25.76 || ^4
'@ai-sdk/provider-utils@2.2.7':
resolution: {integrity: sha512-kM0xS3GWg3aMChh9zfeM+80vEZfXzR3JEUBdycZLtbRZ2TRT8xOj3WodGHPb06sUK5yD7pAXC/P7ctsi2fvUGQ==}
'@ai-sdk/openai@2.0.27':
resolution: {integrity: sha512-5fUFBlE9qGFgezVIVkzQk87qZYkxsn5PsedtCFPoGxHK6c2QVYHuD1UcrVIKt0elr043Vx17Xo/gS5oJAR5YEQ==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.23.8
zod: ^3.25.76 || ^4
'@ai-sdk/provider-utils@2.2.8':
resolution: {integrity: sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==}
@@ -2051,10 +2038,20 @@ packages:
peerDependencies:
zod: ^3.23.8
'@ai-sdk/provider-utils@3.0.8':
resolution: {integrity: sha512-cDj1iigu7MW2tgAQeBzOiLhjHOUM9vENsgh4oAVitek0d//WdgfPCsKO3euP7m7LyO/j9a1vr/So+BGNdpFXYw==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.76 || ^4
'@ai-sdk/provider@1.1.3':
resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==}
engines: {node: '>=18'}
'@ai-sdk/provider@2.0.0':
resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==}
engines: {node: '>=18'}
'@ai-sdk/react@1.2.12':
resolution: {integrity: sha512-jK1IZZ22evPZoQW3vlkZ7wvjYGYF+tRBKXtrcolduIkQ/m/sOAVcVeVDUDvh1T91xCnWCdUGCPZg2avZ90mv3g==}
engines: {node: '>=18'}
@@ -3690,6 +3687,11 @@ packages:
'@fastify/deepmerge@1.3.0':
resolution: {integrity: sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==}
'@finom/zod-to-json-schema@3.24.11':
resolution: {integrity: sha512-fL656yBPiWebtfGItvtXLWrFNGlF1NcDFS0WdMQXMs9LluVg0CfT5E2oXYp0pidl0vVG53XkW55ysijNkU5/hA==}
peerDependencies:
zod: ^4.0.14
'@floating-ui/core@1.6.9':
resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==}
@@ -4279,15 +4281,15 @@ packages:
'@llamaindex/chat-ui-docs@0.1.0':
resolution: {integrity: sha512-+DwnLSWDOJk2d6lGDhLYtmpeGHho4AjKE2aQMz8J0ZF29RlSqp/Z5HmhQoYIjK0neIM1S9eF7ubuM1zpVpZqrg==}
'@llamaindex/workflow-core@1.3.0':
resolution: {integrity: sha512-5HsIuDpeiXZUTsy5nJ+F7PUnStQdzEoEmc6/0IDlL4eqK3svBEitbOGlxCTPMYasoVni2XsEL1ox1QtVrtrzpw==}
'@llamaindex/workflow-core@1.3.2':
resolution: {integrity: sha512-RlUJ2zvCySLdXiRc5UinGxRzhZ64puWwswyO36ucLQ8bjeRyY1PHm6ZZbmJcqI9XsJHF/23+guNh2b9f4zTRMQ==}
peerDependencies:
'@modelcontextprotocol/sdk': ^1.7.0
hono: ^4.7.4
next: ^15.2.2
p-retry: ^6.2.1
rxjs: ^7.8.2
zod: ^3.24.2
zod: ^3.25.0 || ^4.0.0
peerDependenciesMeta:
'@modelcontextprotocol/sdk':
optional: true
@@ -6854,9 +6856,6 @@ packages:
'@types/node@12.20.55':
resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==}
'@types/node@18.19.118':
resolution: {integrity: sha512-hIPK0hSrrcaoAu/gJMzN3QClXE4QdCdFvaenJ0JsjIbExP1JFFVH+RHcBt25c9n8bx5dkIfqKE+uw6BmBns7ug==}
'@types/node@18.19.124':
resolution: {integrity: sha512-hY4YWZFLs3ku6D2Gqo3RchTd9VRCcrjqp/I0mmohYeUVA5Y8eCXKJEasHxLAJVZRJuQogfd1GiJ9lgogBgKeuQ==}
@@ -7570,6 +7569,12 @@ packages:
react:
optional: true
ai@5.0.39:
resolution: {integrity: sha512-1AOjTHY8MUY4T/X/I+otGTbvKmMQCCGWffuVDyQ21l/2Vv/QoLZcw+ZZHVvp+wvQcPOsfXjURGSFZtin7rnghA==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.25.76 || ^4
ajv-draft-04@1.0.0:
resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
peerDependencies:
@@ -9047,8 +9052,8 @@ packages:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
eventsource-parser@3.0.1:
resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==}
eventsource-parser@3.0.6:
resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==}
engines: {node: '>=18.0.0'}
eventsource@3.0.6:
@@ -14348,29 +14353,28 @@ packages:
zod@3.22.4:
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
zod@3.25.67:
resolution: {integrity: sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw==}
zod@3.25.76:
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
zod@4.1.5:
resolution: {integrity: sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg==}
zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
snapshots:
'@ai-sdk/openai@1.3.12(zod@3.25.76)':
'@ai-sdk/gateway@1.0.20(zod@4.1.5)':
dependencies:
'@ai-sdk/provider': 1.1.3
'@ai-sdk/provider-utils': 2.2.7(zod@3.25.76)
zod: 3.25.76
'@ai-sdk/provider': 2.0.0
'@ai-sdk/provider-utils': 3.0.8(zod@4.1.5)
zod: 4.1.5
'@ai-sdk/provider-utils@2.2.7(zod@3.25.76)':
'@ai-sdk/openai@2.0.27(zod@4.1.5)':
dependencies:
'@ai-sdk/provider': 1.1.3
nanoid: 3.3.11
secure-json-parse: 2.7.0
zod: 3.25.76
'@ai-sdk/provider': 2.0.0
'@ai-sdk/provider-utils': 3.0.8(zod@4.1.5)
zod: 4.1.5
'@ai-sdk/provider-utils@2.2.8(zod@3.25.76)':
dependencies:
@@ -14379,19 +14383,37 @@ snapshots:
secure-json-parse: 2.7.0
zod: 3.25.76
'@ai-sdk/provider-utils@2.2.8(zod@4.1.5)':
dependencies:
'@ai-sdk/provider': 1.1.3
nanoid: 3.3.11
secure-json-parse: 2.7.0
zod: 4.1.5
'@ai-sdk/provider-utils@3.0.8(zod@4.1.5)':
dependencies:
'@ai-sdk/provider': 2.0.0
'@standard-schema/spec': 1.0.0
eventsource-parser: 3.0.6
zod: 4.1.5
'@ai-sdk/provider@1.1.3':
dependencies:
json-schema: 0.4.0
'@ai-sdk/react@1.2.12(react@19.0.0)(zod@3.25.76)':
'@ai-sdk/provider@2.0.0':
dependencies:
'@ai-sdk/provider-utils': 2.2.8(zod@3.25.76)
'@ai-sdk/ui-utils': 1.2.11(zod@3.25.76)
json-schema: 0.4.0
'@ai-sdk/react@1.2.12(react@19.0.0)(zod@4.1.5)':
dependencies:
'@ai-sdk/provider-utils': 2.2.8(zod@4.1.5)
'@ai-sdk/ui-utils': 1.2.11(zod@4.1.5)
react: 19.0.0
swr: 2.3.3(react@19.0.0)
throttleit: 2.1.0
optionalDependencies:
zod: 3.25.76
zod: 4.1.5
'@ai-sdk/react@1.2.12(react@19.1.0)(zod@3.25.76)':
dependencies:
@@ -14410,6 +14432,13 @@ snapshots:
zod: 3.25.76
zod-to-json-schema: 3.24.6(zod@3.25.76)
'@ai-sdk/ui-utils@1.2.11(zod@4.1.5)':
dependencies:
'@ai-sdk/provider': 1.1.3
'@ai-sdk/provider-utils': 2.2.8(zod@4.1.5)
zod: 4.1.5
zod-to-json-schema: 3.24.6(zod@4.1.5)
'@alloc/quick-lru@5.2.0': {}
'@ampproject/remapping@2.3.0':
@@ -16851,6 +16880,10 @@ snapshots:
'@fastify/deepmerge@1.3.0': {}
'@finom/zod-to-json-schema@3.24.11(zod@4.1.5)':
dependencies:
zod: 4.1.5
'@floating-ui/core@1.6.9':
dependencies:
'@floating-ui/utils': 0.2.9
@@ -17394,13 +17427,13 @@ snapshots:
'@llamaindex/chat-ui-docs@0.1.0': {}
'@llamaindex/workflow-core@1.3.0(@modelcontextprotocol/sdk@1.13.0)(hono@4.7.7)(next@15.3.3(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.76)':
'@llamaindex/workflow-core@1.3.2(@modelcontextprotocol/sdk@1.13.0)(hono@4.7.7)(next@15.3.3(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@4.1.5)':
optionalDependencies:
'@modelcontextprotocol/sdk': 1.13.0
hono: 4.7.7
next: 15.3.3(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
p-retry: 6.2.1
zod: 3.25.76
zod: 4.1.5
'@llamaindex/workflow-docs@0.1.1': {}
@@ -17499,10 +17532,10 @@ snapshots:
- supports-color
optional: true
'@mistralai/mistralai@1.5.2(zod@3.25.76)':
'@mistralai/mistralai@1.5.2(zod@4.1.5)':
dependencies:
zod: 3.25.76
zod-to-json-schema: 3.24.6(zod@3.25.76)
zod: 4.1.5
zod-to-json-schema: 3.24.6(zod@4.1.5)
'@mixedbread-ai/sdk@2.2.11':
dependencies:
@@ -20325,14 +20358,9 @@ snapshots:
'@types/node@12.20.55': {}
'@types/node@18.19.118':
dependencies:
undici-types: 5.26.5
'@types/node@18.19.124':
dependencies:
undici-types: 5.26.5
optional: true
'@types/node@20.19.7':
dependencies:
@@ -21204,15 +21232,15 @@ snapshots:
dependencies:
humanize-ms: 1.2.1
ai@4.3.17(react@19.0.0)(zod@3.25.76):
ai@4.3.17(react@19.0.0)(zod@4.1.5):
dependencies:
'@ai-sdk/provider': 1.1.3
'@ai-sdk/provider-utils': 2.2.8(zod@3.25.76)
'@ai-sdk/react': 1.2.12(react@19.0.0)(zod@3.25.76)
'@ai-sdk/ui-utils': 1.2.11(zod@3.25.76)
'@ai-sdk/provider-utils': 2.2.8(zod@4.1.5)
'@ai-sdk/react': 1.2.12(react@19.0.0)(zod@4.1.5)
'@ai-sdk/ui-utils': 1.2.11(zod@4.1.5)
'@opentelemetry/api': 1.9.0
jsondiffpatch: 0.6.0
zod: 3.25.76
zod: 4.1.5
optionalDependencies:
react: 19.0.0
@@ -21228,6 +21256,14 @@ snapshots:
optionalDependencies:
react: 19.1.0
ai@5.0.39(zod@4.1.5):
dependencies:
'@ai-sdk/gateway': 1.0.20(zod@4.1.5)
'@ai-sdk/provider': 2.0.0
'@ai-sdk/provider-utils': 3.0.8(zod@4.1.5)
'@opentelemetry/api': 1.9.0
zod: 4.1.5
ajv-draft-04@1.0.0(ajv@8.17.1):
optionalDependencies:
ajv: 8.17.1
@@ -23013,11 +23049,11 @@ snapshots:
events@3.3.0: {}
eventsource-parser@3.0.1: {}
eventsource-parser@3.0.6: {}
eventsource@3.0.6:
dependencies:
eventsource-parser: 3.0.1
eventsource-parser: 3.0.6
execa@5.1.1:
dependencies:
@@ -23854,7 +23890,7 @@ snapshots:
groq-sdk@0.8.0:
dependencies:
'@types/node': 18.19.118
'@types/node': 18.19.124
'@types/node-fetch': 2.6.12
abort-controller: 3.0.0
agentkeepalive: 4.6.0
@@ -26185,7 +26221,7 @@ snapshots:
openai@4.94.0(ws@8.18.1(bufferutil@4.0.9))(zod@3.25.76):
dependencies:
'@types/node': 18.19.118
'@types/node': 18.19.124
'@types/node-fetch': 2.6.12
abort-controller: 3.0.0
agentkeepalive: 4.6.0
@@ -26198,10 +26234,10 @@ snapshots:
transitivePeerDependencies:
- encoding
openai@5.12.0(ws@8.18.1(bufferutil@4.0.9))(zod@3.25.76):
openai@5.12.0(ws@8.18.1(bufferutil@4.0.9))(zod@4.1.5):
optionalDependencies:
ws: 8.18.1(bufferutil@4.0.9)
zod: 3.25.76
zod: 4.1.5
openapi-fetch@0.9.8:
dependencies:
@@ -29653,20 +29689,20 @@ snapshots:
zimmerframe@1.1.4:
optional: true
zod-to-json-schema@3.24.6(zod@3.25.67):
dependencies:
zod: 3.25.67
zod-to-json-schema@3.24.6(zod@3.25.76):
dependencies:
zod: 3.25.76
zod-to-json-schema@3.24.6(zod@4.1.5):
dependencies:
zod: 4.1.5
zod@3.22.3: {}
zod@3.22.4: {}
zod@3.25.67: {}
zod@3.25.76: {}
zod@4.1.5: {}
zwitch@2.0.4: {}