@tanstack/ai 0.1.0 → 0.2.1

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 (29) hide show
  1. package/README.md +0 -25
  2. package/dist/esm/activities/chat/index.d.ts +11 -10
  3. package/dist/esm/activities/chat/index.js +9 -9
  4. package/dist/esm/activities/chat/index.js.map +1 -1
  5. package/dist/esm/activities/chat/tools/schema-converter.d.ts +116 -0
  6. package/dist/esm/activities/chat/tools/schema-converter.js +115 -0
  7. package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -0
  8. package/dist/esm/activities/chat/tools/tool-calls.js +23 -34
  9. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  10. package/dist/esm/activities/chat/tools/tool-definition.d.ts +18 -14
  11. package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
  12. package/dist/esm/index.d.ts +2 -2
  13. package/dist/esm/index.js +5 -4
  14. package/dist/esm/stream-to-response.d.ts +28 -21
  15. package/dist/esm/stream-to-response.js +24 -17
  16. package/dist/esm/stream-to-response.js.map +1 -1
  17. package/dist/esm/types.d.ts +44 -25
  18. package/package.json +3 -6
  19. package/src/activities/chat/index.ts +36 -28
  20. package/src/activities/chat/tools/schema-converter.ts +332 -0
  21. package/src/activities/chat/tools/tool-calls.ts +47 -53
  22. package/src/activities/chat/tools/tool-definition.ts +33 -29
  23. package/src/index.ts +5 -2
  24. package/src/stream-to-response.ts +59 -44
  25. package/src/types.ts +47 -26
  26. package/dist/esm/activities/chat/tools/zod-converter.d.ts +0 -69
  27. package/dist/esm/activities/chat/tools/zod-converter.js +0 -99
  28. package/dist/esm/activities/chat/tools/zod-converter.js.map +0 -1
  29. package/src/activities/chat/tools/zod-converter.ts +0 -235
@@ -0,0 +1,332 @@
1
+ /* eslint-disable @typescript-eslint/no-unnecessary-condition */
2
+
3
+ import type {
4
+ StandardJSONSchemaV1,
5
+ StandardSchemaV1,
6
+ } from '@standard-schema/spec'
7
+ import type { JSONSchema, SchemaInput } from '../../../types'
8
+
9
+ /**
10
+ * Check if a value is a Standard JSON Schema compliant schema.
11
+ * Standard JSON Schema compliant libraries (Zod v4+, ArkType, Valibot with toStandardJsonSchema, etc.)
12
+ * implement the '~standard' property with jsonSchema converter methods.
13
+ */
14
+ export function isStandardJSONSchema(
15
+ schema: unknown,
16
+ ): schema is StandardJSONSchemaV1 {
17
+ return (
18
+ typeof schema === 'object' &&
19
+ schema !== null &&
20
+ '~standard' in schema &&
21
+ typeof (schema as StandardJSONSchemaV1)['~standard'] === 'object' &&
22
+ (schema as StandardJSONSchemaV1)['~standard'].version === 1 &&
23
+ typeof (schema as StandardJSONSchemaV1)['~standard'].jsonSchema ===
24
+ 'object' &&
25
+ typeof (schema as StandardJSONSchemaV1)['~standard'].jsonSchema.input ===
26
+ 'function'
27
+ )
28
+ }
29
+
30
+ /**
31
+ * Check if a value is a Standard Schema compliant schema (for validation).
32
+ * Standard Schema compliant libraries implement the '~standard' property with a validate function.
33
+ */
34
+ export function isStandardSchema(schema: unknown): schema is StandardSchemaV1 {
35
+ return (
36
+ typeof schema === 'object' &&
37
+ schema !== null &&
38
+ '~standard' in schema &&
39
+ typeof schema['~standard'] === 'object' &&
40
+ schema !== null &&
41
+ schema['~standard'] !== null &&
42
+ 'version' in schema['~standard'] &&
43
+ schema['~standard'].version === 1 &&
44
+ 'validate' in schema['~standard'] &&
45
+ typeof schema['~standard'].validate === 'function'
46
+ )
47
+ }
48
+
49
+ /**
50
+ * Transform a JSON schema to be compatible with OpenAI's structured output requirements.
51
+ * OpenAI requires:
52
+ * - All properties must be in the `required` array
53
+ * - Optional fields should have null added to their type union
54
+ * - additionalProperties must be false for objects
55
+ *
56
+ * @param schema - JSON schema to transform
57
+ * @param originalRequired - Original required array (to know which fields were optional)
58
+ * @returns Transformed schema compatible with OpenAI structured output
59
+ */
60
+ function makeStructuredOutputCompatible(
61
+ schema: Record<string, any>,
62
+ originalRequired: Array<string> = [],
63
+ ): Record<string, any> {
64
+ const result = { ...schema }
65
+
66
+ // Handle object types
67
+ if (result.type === 'object' && result.properties) {
68
+ const properties = { ...result.properties }
69
+ const allPropertyNames = Object.keys(properties)
70
+
71
+ // Transform each property
72
+ for (const propName of allPropertyNames) {
73
+ const prop = properties[propName]
74
+ const wasOptional = !originalRequired.includes(propName)
75
+
76
+ // Recursively transform nested objects/arrays
77
+ if (prop.type === 'object' && prop.properties) {
78
+ properties[propName] = makeStructuredOutputCompatible(
79
+ prop,
80
+ prop.required || [],
81
+ )
82
+ } else if (prop.type === 'array' && prop.items) {
83
+ properties[propName] = {
84
+ ...prop,
85
+ items: makeStructuredOutputCompatible(
86
+ prop.items,
87
+ prop.items.required || [],
88
+ ),
89
+ }
90
+ } else if (wasOptional) {
91
+ // Make optional fields nullable by adding null to the type
92
+ if (prop.type && !Array.isArray(prop.type)) {
93
+ properties[propName] = {
94
+ ...prop,
95
+ type: [prop.type, 'null'],
96
+ }
97
+ } else if (Array.isArray(prop.type) && !prop.type.includes('null')) {
98
+ properties[propName] = {
99
+ ...prop,
100
+ type: [...prop.type, 'null'],
101
+ }
102
+ }
103
+ }
104
+ }
105
+
106
+ result.properties = properties
107
+ // ALL properties must be required for OpenAI structured output
108
+ result.required = allPropertyNames
109
+ // additionalProperties must be false
110
+ result.additionalProperties = false
111
+ }
112
+
113
+ // Handle array types with object items
114
+ if (result.type === 'array' && result.items) {
115
+ result.items = makeStructuredOutputCompatible(
116
+ result.items,
117
+ result.items.required || [],
118
+ )
119
+ }
120
+
121
+ return result
122
+ }
123
+
124
+ /**
125
+ * Options for schema conversion
126
+ */
127
+ export interface ConvertSchemaOptions {
128
+ /**
129
+ * When true, transforms the schema to be compatible with OpenAI's structured output requirements:
130
+ * - All properties are added to the `required` array
131
+ * - Optional fields get null added to their type union
132
+ * - additionalProperties is set to false for all objects
133
+ *
134
+ * @default false
135
+ */
136
+ forStructuredOutput?: boolean
137
+ }
138
+
139
+ /**
140
+ * Converts a Standard JSON Schema compliant schema or plain JSONSchema to JSON Schema format
141
+ * compatible with LLM providers.
142
+ *
143
+ * Supports any schema library that implements the Standard JSON Schema spec (v1):
144
+ * - Zod v4+ (natively supports StandardJSONSchemaV1)
145
+ * - ArkType (natively supports StandardJSONSchemaV1)
146
+ * - Valibot (via `toStandardJsonSchema()` from `@valibot/to-json-schema`)
147
+ *
148
+ * If the input is already a plain JSONSchema object, it is returned as-is.
149
+ *
150
+ * @param schema - Standard JSON Schema compliant schema or plain JSONSchema object to convert
151
+ * @param options - Conversion options
152
+ * @returns JSON Schema object that can be sent to LLM providers
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * // Using Zod v4+ (natively supports Standard JSON Schema)
157
+ * import * as z from 'zod';
158
+ *
159
+ * const zodSchema = z.object({
160
+ * location: z.string().describe('City name'),
161
+ * unit: z.enum(['celsius', 'fahrenheit']).optional()
162
+ * });
163
+ *
164
+ * const jsonSchema = convertSchemaToJsonSchema(zodSchema);
165
+ *
166
+ * @example
167
+ * // Using ArkType (natively supports Standard JSON Schema)
168
+ * import { type } from 'arktype';
169
+ *
170
+ * const arkSchema = type({
171
+ * location: 'string',
172
+ * unit: "'celsius' | 'fahrenheit'"
173
+ * });
174
+ *
175
+ * const jsonSchema = convertSchemaToJsonSchema(arkSchema);
176
+ *
177
+ * @example
178
+ * // Using Valibot (via toStandardJsonSchema)
179
+ * import * as v from 'valibot';
180
+ * import { toStandardJsonSchema } from '@valibot/to-json-schema';
181
+ *
182
+ * const valibotSchema = toStandardJsonSchema(v.object({
183
+ * location: v.string(),
184
+ * unit: v.optional(v.picklist(['celsius', 'fahrenheit']))
185
+ * }));
186
+ *
187
+ * const jsonSchema = convertSchemaToJsonSchema(valibotSchema);
188
+ *
189
+ * @example
190
+ * // Using JSONSchema directly (passes through unchanged)
191
+ * const rawSchema = {
192
+ * type: 'object',
193
+ * properties: { location: { type: 'string' } },
194
+ * required: ['location']
195
+ * };
196
+ * const result = convertSchemaToJsonSchema(rawSchema);
197
+ * ```
198
+ */
199
+ export function convertSchemaToJsonSchema(
200
+ schema: SchemaInput | undefined,
201
+ options: ConvertSchemaOptions = {},
202
+ ): JSONSchema | undefined {
203
+ if (!schema) return undefined
204
+
205
+ const { forStructuredOutput = false } = options
206
+
207
+ // If it's a Standard JSON Schema compliant schema, use the standard interface
208
+ if (isStandardJSONSchema(schema)) {
209
+ const jsonSchema = schema['~standard'].jsonSchema.input({
210
+ target: 'draft-07',
211
+ })
212
+
213
+ let result = jsonSchema
214
+
215
+ if (typeof result === 'object' && '$schema' in result) {
216
+ // Remove $schema property as it's not needed for LLM providers
217
+ const { $schema, ...rest } = result
218
+ result = rest
219
+ }
220
+
221
+ // Ensure object schemas always have type: "object"
222
+
223
+ if (typeof result === 'object') {
224
+ // If it has properties (even empty), it should be an object type
225
+ if ('properties' in result && !result.type) {
226
+ result.type = 'object'
227
+ }
228
+
229
+ // Ensure properties exists for object types (even if empty)
230
+ if (result.type === 'object' && !('properties' in result)) {
231
+ result.properties = {}
232
+ }
233
+
234
+ // Ensure required exists for object types (even if empty array)
235
+ if (result.type === 'object' && !('required' in result)) {
236
+ result.required = []
237
+ }
238
+
239
+ // Apply structured output transformation if requested
240
+ if (forStructuredOutput) {
241
+ result = makeStructuredOutputCompatible(
242
+ result,
243
+ (result.required as Array<string>) || [],
244
+ )
245
+ }
246
+ }
247
+
248
+ return result as JSONSchema
249
+ }
250
+
251
+ // If it's not a Standard JSON Schema, assume it's already a JSONSchema and pass through
252
+ // Still apply structured output transformation if requested
253
+
254
+ if (forStructuredOutput && typeof schema === 'object') {
255
+ return makeStructuredOutputCompatible(
256
+ schema as Record<string, any>,
257
+ ((schema as JSONSchema).required as Array<string>) || [],
258
+ ) as JSONSchema
259
+ }
260
+
261
+ return schema as JSONSchema
262
+ }
263
+
264
+ /**
265
+ * Validates data against a Standard Schema compliant schema.
266
+ *
267
+ * @param schema - Standard Schema compliant schema
268
+ * @param data - Data to validate
269
+ * @returns Validation result with success status, data or issues
270
+ */
271
+ export async function validateWithStandardSchema<T>(
272
+ schema: unknown,
273
+ data: unknown,
274
+ ): Promise<
275
+ | { success: true; data: T }
276
+ | { success: false; issues: Array<{ message: string; path?: Array<string> }> }
277
+ > {
278
+ if (!isStandardSchema(schema)) {
279
+ // If it's not a Standard Schema, just return the data as-is
280
+ return { success: true, data: data as T }
281
+ }
282
+
283
+ const result = await schema['~standard'].validate(data)
284
+
285
+ if (!result.issues) {
286
+ return { success: true, data: result.value as T }
287
+ }
288
+
289
+ return {
290
+ success: false,
291
+ issues: result.issues.map((issue) => ({
292
+ message: issue.message || 'Validation failed',
293
+ path: issue.path?.map(String),
294
+ })),
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Synchronously validates data against a Standard Schema compliant schema.
300
+ * Note: Some Standard Schema implementations may only support async validation.
301
+ * In those cases, this function will throw.
302
+ *
303
+ * @param schema - Standard Schema compliant schema
304
+ * @param data - Data to validate
305
+ * @returns Parsed/validated data
306
+ * @throws Error if validation fails or if the schema only supports async validation
307
+ */
308
+ export function parseWithStandardSchema<T>(schema: unknown, data: unknown): T {
309
+ if (!isStandardSchema(schema)) {
310
+ // If it's not a Standard Schema, just return the data as-is
311
+ return data as T
312
+ }
313
+
314
+ const result = schema['~standard'].validate(data)
315
+
316
+ // Handle async result (Promise)
317
+ if (result instanceof Promise) {
318
+ throw new Error(
319
+ 'Schema validation returned a Promise. Use validateWithStandardSchema for async validation.',
320
+ )
321
+ }
322
+ // Standard Schema validation returns { value } for success or { issues } for failure
323
+ if (!result.issues) {
324
+ return result.value as T
325
+ }
326
+
327
+ // invalid validation, throw error with all issues
328
+ const errorMessages = result.issues
329
+ .map((issue) => issue.message || 'Validation failed')
330
+ .join(', ')
331
+ throw new Error(`Validation failed: ${errorMessages}`)
332
+ }
@@ -1,20 +1,11 @@
1
+ import { isStandardSchema, parseWithStandardSchema } from './schema-converter'
1
2
  import type {
2
3
  DoneStreamChunk,
3
4
  ModelMessage,
4
- SchemaInput,
5
5
  Tool,
6
6
  ToolCall,
7
7
  ToolResultStreamChunk,
8
8
  } from '../../../types'
9
- import type { z } from 'zod'
10
-
11
- /**
12
- * Check if a value is a Zod schema by looking for Zod-specific internals.
13
- */
14
- function isZodSchema(schema: SchemaInput | undefined): schema is z.ZodType {
15
- if (!schema) return false
16
- return '_zod' in schema && typeof (schema as any)._zod === 'object'
17
- }
18
9
 
19
10
  /**
20
11
  * Manages tool call accumulation and execution for the chat() method's automatic tool execution loop.
@@ -131,7 +122,7 @@ export class ToolCallManager {
131
122
  if (tool?.execute) {
132
123
  try {
133
124
  // Parse arguments
134
- let args: any
125
+ let args: unknown
135
126
  try {
136
127
  args = JSON.parse(toolCall.function.arguments)
137
128
  } catch (parseError) {
@@ -140,13 +131,17 @@ export class ToolCallManager {
140
131
  )
141
132
  }
142
133
 
143
- // Validate input against inputSchema (only for Zod schemas)
144
- if (tool.inputSchema && isZodSchema(tool.inputSchema)) {
134
+ // Validate input against inputSchema (for Standard Schema compliant schemas)
135
+ if (tool.inputSchema && isStandardSchema(tool.inputSchema)) {
145
136
  try {
146
- args = tool.inputSchema.parse(args)
147
- } catch (validationError: any) {
137
+ args = parseWithStandardSchema(tool.inputSchema, args)
138
+ } catch (validationError: unknown) {
139
+ const message =
140
+ validationError instanceof Error
141
+ ? validationError.message
142
+ : 'Validation failed'
148
143
  throw new Error(
149
- `Input validation failed for tool ${tool.name}: ${validationError.message}`,
144
+ `Input validation failed for tool ${tool.name}: ${message}`,
150
145
  )
151
146
  }
152
147
  }
@@ -154,27 +149,33 @@ export class ToolCallManager {
154
149
  // Execute the tool
155
150
  let result = await tool.execute(args)
156
151
 
157
- // Validate output against outputSchema if provided (only for Zod schemas)
152
+ // Validate output against outputSchema if provided (for Standard Schema compliant schemas)
158
153
  if (
159
154
  tool.outputSchema &&
160
- isZodSchema(tool.outputSchema) &&
155
+ isStandardSchema(tool.outputSchema) &&
161
156
  result !== undefined &&
162
157
  result !== null
163
158
  ) {
164
159
  try {
165
- result = tool.outputSchema.parse(result)
166
- } catch (validationError: any) {
160
+ result = parseWithStandardSchema(tool.outputSchema, result)
161
+ } catch (validationError: unknown) {
162
+ const message =
163
+ validationError instanceof Error
164
+ ? validationError.message
165
+ : 'Validation failed'
167
166
  throw new Error(
168
- `Output validation failed for tool ${tool.name}: ${validationError.message}`,
167
+ `Output validation failed for tool ${tool.name}: ${message}`,
169
168
  )
170
169
  }
171
170
  }
172
171
 
173
172
  toolResultContent =
174
173
  typeof result === 'string' ? result : JSON.stringify(result)
175
- } catch (error: any) {
174
+ } catch (error: unknown) {
176
175
  // If tool execution fails, add error message
177
- toolResultContent = `Error executing tool: ${error.message}`
176
+ const message =
177
+ error instanceof Error ? error.message : 'Unknown error'
178
+ toolResultContent = `Error executing tool: ${message}`
178
179
  }
179
180
  } else {
180
181
  // Tool doesn't have execute function, add placeholder
@@ -286,7 +287,7 @@ export async function executeToolCalls(
286
287
  }
287
288
 
288
289
  // Parse arguments, throwing error if invalid JSON
289
- let input: any = {}
290
+ let input: unknown = {}
290
291
  const argsStr = toolCall.function.arguments.trim() || '{}'
291
292
  if (argsStr) {
292
293
  try {
@@ -297,16 +298,20 @@ export async function executeToolCalls(
297
298
  }
298
299
  }
299
300
 
300
- // Validate input against inputSchema (only for Zod schemas)
301
- if (tool.inputSchema && isZodSchema(tool.inputSchema)) {
301
+ // Validate input against inputSchema (for Standard Schema compliant schemas)
302
+ if (tool.inputSchema && isStandardSchema(tool.inputSchema)) {
302
303
  try {
303
- input = tool.inputSchema.parse(input)
304
- } catch (validationError: any) {
304
+ input = parseWithStandardSchema(tool.inputSchema, input)
305
+ } catch (validationError: unknown) {
306
+ const message =
307
+ validationError instanceof Error
308
+ ? validationError.message
309
+ : 'Validation failed'
305
310
  results.push({
306
311
  toolCallId: toolCall.id,
307
312
  toolName,
308
313
  result: {
309
- error: `Input validation failed for tool ${tool.name}: ${validationError.message}`,
314
+ error: `Input validation failed for tool ${tool.name}: ${message}`,
310
315
  },
311
316
  state: 'output-error',
312
317
  })
@@ -393,21 +398,14 @@ export async function executeToolCalls(
393
398
  let result = await tool.execute(input)
394
399
  const duration = Date.now() - startTime
395
400
 
396
- // Validate output against outputSchema if provided (only for Zod schemas)
401
+ // Validate output against outputSchema if provided (for Standard Schema compliant schemas)
397
402
  if (
398
403
  tool.outputSchema &&
399
- isZodSchema(tool.outputSchema) &&
404
+ isStandardSchema(tool.outputSchema) &&
400
405
  result !== undefined &&
401
406
  result !== null
402
407
  ) {
403
- const parsed = tool.outputSchema.safeParse(result)
404
- if (parsed.success) {
405
- result = parsed.data
406
- } else {
407
- throw new Error(
408
- `Output validation failed for tool ${tool.name}: ${parsed.error.message}`,
409
- )
410
- }
408
+ result = parseWithStandardSchema(tool.outputSchema, result)
411
409
  }
412
410
 
413
411
  results.push({
@@ -419,12 +417,14 @@ export async function executeToolCalls(
419
417
  : result || null,
420
418
  duration,
421
419
  })
422
- } catch (error: any) {
420
+ } catch (error: unknown) {
423
421
  const duration = Date.now() - startTime
422
+ const message =
423
+ error instanceof Error ? error.message : 'Unknown error'
424
424
  results.push({
425
425
  toolCallId: toolCall.id,
426
426
  toolName,
427
- result: { error: error.message },
427
+ result: { error: message },
428
428
  state: 'output-error',
429
429
  duration,
430
430
  })
@@ -456,21 +456,14 @@ export async function executeToolCalls(
456
456
  let result = await tool.execute(input)
457
457
  const duration = Date.now() - startTime
458
458
 
459
- // Validate output against outputSchema if provided (only for Zod schemas)
459
+ // Validate output against outputSchema if provided (for Standard Schema compliant schemas)
460
460
  if (
461
461
  tool.outputSchema &&
462
- isZodSchema(tool.outputSchema) &&
462
+ isStandardSchema(tool.outputSchema) &&
463
463
  result !== undefined &&
464
464
  result !== null
465
465
  ) {
466
- const parsed = tool.outputSchema.safeParse(result)
467
- if (parsed.success) {
468
- result = parsed.data
469
- } else {
470
- throw new Error(
471
- `Output validation failed for tool ${tool.name}: ${parsed.error.message}`,
472
- )
473
- }
466
+ result = parseWithStandardSchema(tool.outputSchema, result)
474
467
  }
475
468
 
476
469
  results.push({
@@ -480,12 +473,13 @@ export async function executeToolCalls(
480
473
  typeof result === 'string' ? JSON.parse(result) : result || null,
481
474
  duration,
482
475
  })
483
- } catch (error: any) {
476
+ } catch (error: unknown) {
484
477
  const duration = Date.now() - startTime
478
+ const message = error instanceof Error ? error.message : 'Unknown error'
485
479
  results.push({
486
480
  toolCallId: toolCall.id,
487
481
  toolName,
488
- result: { error: error.message },
482
+ result: { error: message },
489
483
  state: 'output-error',
490
484
  duration,
491
485
  })
@@ -1,4 +1,4 @@
1
- import type { z } from 'zod'
1
+ import type { StandardJSONSchemaV1 } from '@standard-schema/spec'
2
2
  import type {
3
3
  InferSchemaType,
4
4
  JSONSchema,
@@ -10,8 +10,8 @@ import type {
10
10
  * Marker type for server-side tools
11
11
  */
12
12
  export interface ServerTool<
13
- TInput extends SchemaInput = z.ZodType,
14
- TOutput extends SchemaInput = z.ZodType,
13
+ TInput extends SchemaInput = SchemaInput,
14
+ TOutput extends SchemaInput = SchemaInput,
15
15
  TName extends string = string,
16
16
  > extends Tool<TInput, TOutput, TName> {
17
17
  __toolSide: 'server'
@@ -21,8 +21,8 @@ export interface ServerTool<
21
21
  * Marker type for client-side tools
22
22
  */
23
23
  export interface ClientTool<
24
- TInput extends SchemaInput = z.ZodType,
25
- TOutput extends SchemaInput = z.ZodType,
24
+ TInput extends SchemaInput = SchemaInput,
25
+ TOutput extends SchemaInput = SchemaInput,
26
26
  TName extends string = string,
27
27
  > {
28
28
  __toolSide: 'client'
@@ -31,7 +31,7 @@ export interface ClientTool<
31
31
  inputSchema?: TInput
32
32
  outputSchema?: TOutput
33
33
  needsApproval?: boolean
34
- metadata?: Record<string, any>
34
+ metadata?: Record<string, unknown>
35
35
  execute?: (
36
36
  args: InferSchemaType<TInput>,
37
37
  ) => Promise<InferSchemaType<TOutput>> | InferSchemaType<TOutput>
@@ -41,8 +41,8 @@ export interface ClientTool<
41
41
  * Tool definition that can be used directly or instantiated for server/client
42
42
  */
43
43
  export interface ToolDefinitionInstance<
44
- TInput extends SchemaInput = z.ZodType,
45
- TOutput extends SchemaInput = z.ZodType,
44
+ TInput extends SchemaInput = SchemaInput,
45
+ TOutput extends SchemaInput = SchemaInput,
46
46
  TName extends string = string,
47
47
  > extends Tool<TInput, TOutput, TName> {
48
48
  __toolSide: 'definition'
@@ -52,8 +52,8 @@ export interface ToolDefinitionInstance<
52
52
  * Union type for any kind of client-side tool (client tool or definition)
53
53
  */
54
54
  export type AnyClientTool =
55
- | ClientTool<any, any>
56
- | ToolDefinitionInstance<any, any>
55
+ | ClientTool<SchemaInput, SchemaInput>
56
+ | ToolDefinitionInstance<SchemaInput, SchemaInput>
57
57
 
58
58
  /**
59
59
  * Extract the tool name as a literal type
@@ -61,33 +61,33 @@ export type AnyClientTool =
61
61
  export type InferToolName<T> = T extends { name: infer N } ? N : never
62
62
 
63
63
  /**
64
- * Extract the input type from a tool (inferred from Zod schema, or `any` for JSONSchema)
64
+ * Extract the input type from a tool (inferred from Standard JSON Schema, or `unknown` for plain JSONSchema)
65
65
  */
66
66
  export type InferToolInput<T> = T extends { inputSchema?: infer TInput }
67
- ? TInput extends z.ZodType
68
- ? z.infer<TInput>
67
+ ? TInput extends StandardJSONSchemaV1<infer TInferred, unknown>
68
+ ? TInferred
69
69
  : TInput extends JSONSchema
70
- ? any
71
- : any
72
- : any
70
+ ? unknown
71
+ : unknown
72
+ : unknown
73
73
 
74
74
  /**
75
- * Extract the output type from a tool (inferred from Zod schema, or `any` for JSONSchema)
75
+ * Extract the output type from a tool (inferred from Standard JSON Schema, or `unknown` for plain JSONSchema)
76
76
  */
77
77
  export type InferToolOutput<T> = T extends { outputSchema?: infer TOutput }
78
- ? TOutput extends z.ZodType
79
- ? z.infer<TOutput>
78
+ ? TOutput extends StandardJSONSchemaV1<infer TInferred, unknown>
79
+ ? TInferred
80
80
  : TOutput extends JSONSchema
81
- ? any
82
- : any
83
- : any
81
+ ? unknown
82
+ : unknown
83
+ : unknown
84
84
 
85
85
  /**
86
86
  * Tool definition configuration
87
87
  */
88
88
  export interface ToolDefinitionConfig<
89
- TInput extends SchemaInput = z.ZodType,
90
- TOutput extends SchemaInput = z.ZodType,
89
+ TInput extends SchemaInput = SchemaInput,
90
+ TOutput extends SchemaInput = SchemaInput,
91
91
  TName extends string = string,
92
92
  > {
93
93
  name: TName
@@ -95,15 +95,15 @@ export interface ToolDefinitionConfig<
95
95
  inputSchema?: TInput
96
96
  outputSchema?: TOutput
97
97
  needsApproval?: boolean
98
- metadata?: Record<string, any>
98
+ metadata?: Record<string, unknown>
99
99
  }
100
100
 
101
101
  /**
102
102
  * Tool definition builder that allows creating server or client tools from a shared definition
103
103
  */
104
104
  export interface ToolDefinition<
105
- TInput extends SchemaInput = z.ZodType,
106
- TOutput extends SchemaInput = z.ZodType,
105
+ TInput extends SchemaInput = SchemaInput,
106
+ TOutput extends SchemaInput = SchemaInput,
107
107
  TName extends string = string,
108
108
  > extends ToolDefinitionInstance<TInput, TOutput, TName> {
109
109
  /**
@@ -133,11 +133,15 @@ export interface ToolDefinition<
133
133
  * 2. Instantiated as a server tool with .server()
134
134
  * 3. Instantiated as a client tool with .client()
135
135
  *
136
+ * Supports any Standard JSON Schema compliant library (Zod v4+, ArkType, Valibot, etc.)
137
+ * or plain JSON Schema objects.
138
+ *
136
139
  * @example
137
140
  * ```typescript
138
141
  * import { toolDefinition } from '@tanstack/ai';
139
142
  * import { z } from 'zod';
140
143
  *
144
+ * // Using Zod (natively supports Standard JSON Schema)
141
145
  * const addToCartTool = toolDefinition({
142
146
  * name: 'addToCart',
143
147
  * description: 'Add a guitar to the shopping cart (requires approval)',
@@ -177,8 +181,8 @@ export interface ToolDefinition<
177
181
  * ```
178
182
  */
179
183
  export function toolDefinition<
180
- TInput extends SchemaInput = z.ZodAny,
181
- TOutput extends SchemaInput = z.ZodAny,
184
+ TInput extends SchemaInput = SchemaInput,
185
+ TOutput extends SchemaInput = SchemaInput,
182
186
  TName extends string = string,
183
187
  >(
184
188
  config: ToolDefinitionConfig<TInput, TOutput, TName>,