@tanstack/ai 0.23.0 → 0.24.0
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.
- package/README.md +1 -1
- package/dist/esm/activities/chat/index.d.ts +33 -9
- package/dist/esm/activities/chat/index.js +19 -9
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/messages.js +2 -1
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/middleware/compose.d.ts +14 -14
- package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
- package/dist/esm/activities/chat/middleware/types.d.ts +16 -16
- package/dist/esm/activities/chat/runtime-context-types.d.ts +43 -0
- package/dist/esm/activities/chat/stream/message-updaters.d.ts +2 -2
- package/dist/esm/activities/chat/stream/message-updaters.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +1 -0
- package/dist/esm/activities/chat/stream/processor.js +35 -12
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/tools/schema-converter.js +10 -3
- package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.d.ts +15 -5
- package/dist/esm/activities/chat/tools/tool-calls.js +59 -19
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-definition.d.ts +12 -8
- package/dist/esm/activities/chat/tools/tool-definition.js.map +1 -1
- package/dist/esm/activities/error-payload.d.ts +26 -0
- package/dist/esm/activities/error-payload.js +12 -1
- package/dist/esm/activities/error-payload.js.map +1 -1
- package/dist/esm/adapter-internals.d.ts +1 -1
- package/dist/esm/adapter-internals.js +3 -2
- package/dist/esm/client.d.ts +1 -1
- package/dist/esm/client.js +3 -1
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +7 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/tool-registry.d.ts +7 -7
- package/dist/esm/tool-registry.js +1 -1
- package/dist/esm/tool-registry.js.map +1 -1
- package/dist/esm/types.d.ts +40 -8
- package/dist/esm/utilities/ag-ui-wire.js +1 -1
- package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
- package/dist/esm/utilities/chat-params.d.ts +8 -3
- package/dist/esm/utilities/chat-params.js +6 -2
- package/dist/esm/utilities/chat-params.js.map +1 -1
- package/dist/esm/utilities/tool-result.d.ts +21 -0
- package/dist/esm/utilities/tool-result.js +37 -0
- package/dist/esm/utilities/tool-result.js.map +1 -0
- package/package.json +3 -2
- package/src/activities/chat/index.ts +219 -47
- package/src/activities/chat/messages.ts +2 -1
- package/src/activities/chat/middleware/compose.ts +23 -17
- package/src/activities/chat/middleware/types.ts +16 -16
- package/src/activities/chat/runtime-context-types.ts +68 -0
- package/src/activities/chat/stream/message-updaters.ts +2 -1
- package/src/activities/chat/stream/processor.ts +48 -8
- package/src/activities/chat/tools/schema-converter.ts +32 -14
- package/src/activities/chat/tools/tool-calls.ts +138 -43
- package/src/activities/chat/tools/tool-definition.ts +25 -31
- package/src/activities/error-payload.ts +44 -0
- package/src/adapter-internals.ts +4 -1
- package/src/client.ts +5 -1
- package/src/index.ts +7 -0
- package/src/tool-registry.ts +16 -14
- package/src/types.ts +86 -29
- package/src/utilities/ag-ui-wire.ts +4 -1
- package/src/utilities/chat-params.ts +22 -7
- package/src/utilities/tool-result.ts +60 -0
package/src/types.ts
CHANGED
|
@@ -50,6 +50,8 @@ export type ToolResultState =
|
|
|
50
50
|
| 'complete' // Result is complete
|
|
51
51
|
| 'error' // Error occurred
|
|
52
52
|
|
|
53
|
+
export type ToolOutputState = 'output-available' | 'output-error'
|
|
54
|
+
|
|
53
55
|
/**
|
|
54
56
|
* JSON Schema type for defining tool input/output schemas as raw JSON Schema objects.
|
|
55
57
|
* This allows tools to be defined without schema libraries when you have JSON Schema definitions available.
|
|
@@ -355,7 +357,7 @@ export interface ToolCallPart<TMetadata = unknown> {
|
|
|
355
357
|
export interface ToolResultPart {
|
|
356
358
|
type: 'tool-result'
|
|
357
359
|
toolCallId: string
|
|
358
|
-
content: string
|
|
360
|
+
content: string | Array<ContentPart>
|
|
359
361
|
state: ToolResultState
|
|
360
362
|
error?: string // Error message if state is "error"
|
|
361
363
|
}
|
|
@@ -443,33 +445,75 @@ export type ConstrainedModelMessage<
|
|
|
443
445
|
content: ConstrainedContent<TInputModalitiesTypes>
|
|
444
446
|
}
|
|
445
447
|
|
|
448
|
+
type IsUnknown<T> = unknown extends T
|
|
449
|
+
? [T] extends [unknown]
|
|
450
|
+
? true
|
|
451
|
+
: false
|
|
452
|
+
: false
|
|
453
|
+
|
|
454
|
+
type RuntimeContextField<TContext> =
|
|
455
|
+
IsUnknown<TContext> extends true
|
|
456
|
+
? {
|
|
457
|
+
/**
|
|
458
|
+
* Runtime context provided by the caller.
|
|
459
|
+
*
|
|
460
|
+
* This is request-local application state for tool and middleware
|
|
461
|
+
* implementations, not the AG-UI `Context[]` protocol field.
|
|
462
|
+
*/
|
|
463
|
+
context?: TContext
|
|
464
|
+
}
|
|
465
|
+
: {
|
|
466
|
+
/**
|
|
467
|
+
* Runtime context provided by the caller.
|
|
468
|
+
*
|
|
469
|
+
* This is request-local application state for tool and middleware
|
|
470
|
+
* implementations, not the AG-UI `Context[]` protocol field.
|
|
471
|
+
*/
|
|
472
|
+
context: TContext
|
|
473
|
+
}
|
|
474
|
+
|
|
446
475
|
/**
|
|
447
476
|
* Context passed to tool execute functions, providing capabilities like
|
|
448
477
|
* emitting custom events during execution.
|
|
449
478
|
*/
|
|
450
|
-
export
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
479
|
+
export type ToolExecutionContext<TContext = unknown> =
|
|
480
|
+
RuntimeContextField<TContext> & {
|
|
481
|
+
/** The ID of the tool call being executed */
|
|
482
|
+
toolCallId?: string
|
|
483
|
+
/**
|
|
484
|
+
* Emit a custom event during tool execution.
|
|
485
|
+
* Events are streamed to the client in real-time as AG-UI CUSTOM events.
|
|
486
|
+
*
|
|
487
|
+
* @param eventName - Name of the custom event
|
|
488
|
+
* @param value - Event payload value
|
|
489
|
+
*
|
|
490
|
+
* @example
|
|
491
|
+
* ```ts
|
|
492
|
+
* const tool = toolDefinition({ ... }).server(async (args, context) => {
|
|
493
|
+
* context?.emitCustomEvent('progress', { step: 1, total: 3 })
|
|
494
|
+
* // ... do work ...
|
|
495
|
+
* context?.emitCustomEvent('progress', { step: 2, total: 3 })
|
|
496
|
+
* // ... do more work ...
|
|
497
|
+
* return result
|
|
498
|
+
* })
|
|
499
|
+
* ```
|
|
500
|
+
*/
|
|
501
|
+
emitCustomEvent: (eventName: string, value: Record<string, any>) => void
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
export type ToolExecuteFunction<
|
|
505
|
+
TInput extends SchemaInput = SchemaInput,
|
|
506
|
+
TOutput extends SchemaInput = SchemaInput,
|
|
507
|
+
TContext = unknown,
|
|
508
|
+
> = undefined extends TContext
|
|
509
|
+
? (
|
|
510
|
+
args: InferSchemaType<TInput>,
|
|
511
|
+
context?: ToolExecutionContext<TContext>,
|
|
512
|
+
) => Promise<InferSchemaType<TOutput>> | InferSchemaType<TOutput>
|
|
513
|
+
: (
|
|
514
|
+
args: InferSchemaType<TInput>,
|
|
515
|
+
context: ToolExecutionContext<TContext>,
|
|
516
|
+
) => Promise<InferSchemaType<TOutput>> | InferSchemaType<TOutput>
|
|
473
517
|
|
|
474
518
|
/**
|
|
475
519
|
* Tool/Function definition for function calling.
|
|
@@ -488,6 +532,7 @@ export interface Tool<
|
|
|
488
532
|
TInput extends SchemaInput = SchemaInput,
|
|
489
533
|
TOutput extends SchemaInput = SchemaInput,
|
|
490
534
|
TName extends string = string,
|
|
535
|
+
TContext = unknown,
|
|
491
536
|
> {
|
|
492
537
|
/**
|
|
493
538
|
* Unique name of the tool (used by the model to call it).
|
|
@@ -587,9 +632,7 @@ export interface Tool<
|
|
|
587
632
|
* return weather; // Can return object or string
|
|
588
633
|
* }
|
|
589
634
|
*/
|
|
590
|
-
execute?:
|
|
591
|
-
| ((args: any, context?: ToolExecutionContext) => Promise<any> | any)
|
|
592
|
-
| undefined
|
|
635
|
+
execute?: ToolExecuteFunction<TInput, TOutput, TContext> | undefined
|
|
593
636
|
|
|
594
637
|
/** If true, tool execution requires user approval before running. Works with both server and client tools. */
|
|
595
638
|
needsApproval?: boolean
|
|
@@ -601,6 +644,10 @@ export interface Tool<
|
|
|
601
644
|
metadata?: Record<string, any> | undefined
|
|
602
645
|
}
|
|
603
646
|
|
|
647
|
+
export type AnyTool = Omit<Tool<any, any, any, any>, 'execute'> & {
|
|
648
|
+
execute?: ((args: any, context?: any) => any) | undefined
|
|
649
|
+
}
|
|
650
|
+
|
|
604
651
|
export interface ToolConfig {
|
|
605
652
|
[key: string]: Tool
|
|
606
653
|
}
|
|
@@ -729,10 +776,16 @@ export type AgentLoopStrategy = (state: AgentLoopState) => boolean
|
|
|
729
776
|
export interface TextOptions<
|
|
730
777
|
TProviderOptionsSuperset extends Record<string, any> = Record<string, any>,
|
|
731
778
|
TProviderOptionsForModel = TProviderOptionsSuperset,
|
|
779
|
+
TContext = unknown,
|
|
732
780
|
> {
|
|
733
781
|
model: string
|
|
734
782
|
messages: Array<ModelMessage>
|
|
735
|
-
tools?: Array<
|
|
783
|
+
tools?: Array<AnyTool> | undefined
|
|
784
|
+
/**
|
|
785
|
+
* Runtime context provided by the caller and passed to middleware and
|
|
786
|
+
* server-side tool implementations.
|
|
787
|
+
*/
|
|
788
|
+
context?: TContext
|
|
736
789
|
/**
|
|
737
790
|
* System prompts to include with the request.
|
|
738
791
|
*
|
|
@@ -1084,7 +1137,9 @@ export interface ToolCallEndEvent extends AGUIToolCallEndEvent {
|
|
|
1084
1137
|
/** Final parsed input arguments (TanStack AI internal) */
|
|
1085
1138
|
input?: unknown
|
|
1086
1139
|
/** Tool execution result (TanStack AI internal) */
|
|
1087
|
-
result?: string
|
|
1140
|
+
result?: string | Array<ContentPart>
|
|
1141
|
+
/** Tool execution output state (TanStack AI internal) */
|
|
1142
|
+
state?: ToolOutputState
|
|
1088
1143
|
}
|
|
1089
1144
|
|
|
1090
1145
|
/**
|
|
@@ -1096,6 +1151,8 @@ export interface ToolCallEndEvent extends AGUIToolCallEndEvent {
|
|
|
1096
1151
|
export interface ToolCallResultEvent extends AGUIToolCallResultEvent {
|
|
1097
1152
|
/** Model identifier for multi-model support */
|
|
1098
1153
|
model?: string
|
|
1154
|
+
/** Tool execution output state (TanStack AI internal) */
|
|
1155
|
+
state?: ToolOutputState
|
|
1099
1156
|
}
|
|
1100
1157
|
|
|
1101
1158
|
/**
|
|
@@ -103,7 +103,10 @@ export function uiMessagesToWire(
|
|
|
103
103
|
role: 'tool',
|
|
104
104
|
id: deriveToolMessageId(part.toolCallId),
|
|
105
105
|
toolCallId: part.toolCallId,
|
|
106
|
-
content:
|
|
106
|
+
content:
|
|
107
|
+
typeof part.content === 'string'
|
|
108
|
+
? part.content
|
|
109
|
+
: JSON.stringify(part.content),
|
|
107
110
|
...(part.error !== undefined && { error: part.error }),
|
|
108
111
|
})
|
|
109
112
|
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { AGUIError, RunAgentInputSchema } from '@ag-ui/core'
|
|
2
2
|
import type { Context as AGUIContext } from '@ag-ui/core'
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
JSONSchema,
|
|
5
|
+
ModelMessage,
|
|
6
|
+
SchemaInput,
|
|
7
|
+
Tool,
|
|
8
|
+
UIMessage,
|
|
9
|
+
} from '../types'
|
|
4
10
|
|
|
5
11
|
const KNOWN_PART_TYPES = new Set([
|
|
6
12
|
'text',
|
|
@@ -43,7 +49,12 @@ export function chatParamsFromRequestBody(body: unknown): Promise<{
|
|
|
43
49
|
tools: Array<{ name: string; description: string; parameters: JSONSchema }>
|
|
44
50
|
forwardedProps: Record<string, unknown>
|
|
45
51
|
state: unknown
|
|
52
|
+
/**
|
|
53
|
+
* @deprecated Use `aguiContext` instead. This alias will be removed in a
|
|
54
|
+
* future release.
|
|
55
|
+
*/
|
|
46
56
|
context: Array<AGUIContext>
|
|
57
|
+
aguiContext: Array<AGUIContext>
|
|
47
58
|
}> {
|
|
48
59
|
const parseResult = RunAgentInputSchema.safeParse(body)
|
|
49
60
|
if (!parseResult.success) {
|
|
@@ -58,6 +69,7 @@ export function chatParamsFromRequestBody(body: unknown): Promise<{
|
|
|
58
69
|
}
|
|
59
70
|
|
|
60
71
|
const parsed = parseResult.data
|
|
72
|
+
const aguiContext = parsed.context
|
|
61
73
|
|
|
62
74
|
// AG-UI Zod uses `.strip()` so extra fields like `parts` on messages are
|
|
63
75
|
// dropped during parse. We re-attach them from the original body so the
|
|
@@ -89,7 +101,8 @@ export function chatParamsFromRequestBody(body: unknown): Promise<{
|
|
|
89
101
|
}>,
|
|
90
102
|
forwardedProps: (parsed.forwardedProps ?? {}) as Record<string, unknown>,
|
|
91
103
|
state: parsed.state,
|
|
92
|
-
context:
|
|
104
|
+
context: aguiContext,
|
|
105
|
+
aguiContext,
|
|
93
106
|
})
|
|
94
107
|
}
|
|
95
108
|
|
|
@@ -171,16 +184,18 @@ export async function chatParamsFromRequest(
|
|
|
171
184
|
* `chatParamsFromRequest(...)` / `chatParamsFromRequestBody(...)`.
|
|
172
185
|
* @returns A merged array suitable for `chat({ tools })`.
|
|
173
186
|
*/
|
|
174
|
-
export function mergeAgentTools(
|
|
175
|
-
serverTools: ReadonlyArray<Tool
|
|
187
|
+
export function mergeAgentTools<TContext = unknown>(
|
|
188
|
+
serverTools: ReadonlyArray<Tool<SchemaInput, SchemaInput, string, TContext>>,
|
|
176
189
|
clientTools: ReadonlyArray<{
|
|
177
190
|
name: string
|
|
178
191
|
description: string
|
|
179
192
|
parameters: JSONSchema
|
|
180
193
|
}>,
|
|
181
|
-
): Array<Tool
|
|
194
|
+
): Array<Tool<SchemaInput, SchemaInput, string, TContext>> {
|
|
182
195
|
const seen = new Set(serverTools.map((t) => t.name))
|
|
183
|
-
const merged: Array<Tool
|
|
196
|
+
const merged: Array<Tool<SchemaInput, SchemaInput, string, TContext>> = [
|
|
197
|
+
...serverTools,
|
|
198
|
+
]
|
|
184
199
|
for (const ct of clientTools) {
|
|
185
200
|
if (seen.has(ct.name)) {
|
|
186
201
|
// Server wins on name collision.
|
|
@@ -193,7 +208,7 @@ export function mergeAgentTools(
|
|
|
193
208
|
inputSchema: ct.parameters,
|
|
194
209
|
// No `execute` — runtime treats this as a client-side tool and
|
|
195
210
|
// emits ClientToolRequest events.
|
|
196
|
-
} as Tool)
|
|
211
|
+
} as Tool<SchemaInput, SchemaInput, string, TContext>)
|
|
197
212
|
}
|
|
198
213
|
return merged
|
|
199
214
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ContentPart } from '../types'
|
|
2
|
+
|
|
3
|
+
const CONTENT_PART_TYPES = new Set([
|
|
4
|
+
'text',
|
|
5
|
+
'image',
|
|
6
|
+
'audio',
|
|
7
|
+
'video',
|
|
8
|
+
'document',
|
|
9
|
+
])
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Structural check for a single `ContentPart`. A text part must carry a string
|
|
13
|
+
* `content`; every other modality must carry a `source` with `type` of
|
|
14
|
+
* `'url' | 'data'` and a string `value`.
|
|
15
|
+
*/
|
|
16
|
+
export function isContentPart(value: unknown): value is ContentPart {
|
|
17
|
+
if (typeof value !== 'object' || value === null) return false
|
|
18
|
+
const part = value as Record<string, unknown>
|
|
19
|
+
if (typeof part.type !== 'string' || !CONTENT_PART_TYPES.has(part.type)) {
|
|
20
|
+
return false
|
|
21
|
+
}
|
|
22
|
+
if (part.type === 'text') {
|
|
23
|
+
return typeof part.content === 'string'
|
|
24
|
+
}
|
|
25
|
+
const source = part.source
|
|
26
|
+
if (typeof source !== 'object' || source === null) return false
|
|
27
|
+
const src = source as Record<string, unknown>
|
|
28
|
+
if (typeof src.value !== 'string') return false
|
|
29
|
+
// `data` sources require a mimeType (matches ContentPartDataSource); `url`
|
|
30
|
+
// sources don't. Requiring it here keeps the runtime guard consistent with
|
|
31
|
+
// the type and avoids emitting `data:undefined;base64,...` downstream.
|
|
32
|
+
if (src.type === 'data') return typeof src.mimeType === 'string'
|
|
33
|
+
return src.type === 'url'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* True iff `value` is a NON-EMPTY array whose every element is a valid
|
|
38
|
+
* `ContentPart`. Empty arrays and mixed arrays return false so they continue
|
|
39
|
+
* to be treated as ordinary (stringified) data — this keeps the auto-detection
|
|
40
|
+
* footgun narrow.
|
|
41
|
+
*/
|
|
42
|
+
export function isContentPartArray(
|
|
43
|
+
value: unknown,
|
|
44
|
+
): value is Array<ContentPart> {
|
|
45
|
+
return Array.isArray(value) && value.length > 0 && value.every(isContentPart)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Normalize a tool's return value for transport:
|
|
50
|
+
* - string → unchanged
|
|
51
|
+
* - ContentPart array → unchanged (multimodal, passed through to the adapter)
|
|
52
|
+
* - anything else → `JSON.stringify`
|
|
53
|
+
*/
|
|
54
|
+
export function normalizeToolResult(
|
|
55
|
+
result: unknown,
|
|
56
|
+
): string | Array<ContentPart> {
|
|
57
|
+
if (typeof result === 'string') return result
|
|
58
|
+
if (isContentPartArray(result)) return result
|
|
59
|
+
return JSON.stringify(result)
|
|
60
|
+
}
|