@tanstack/ai 0.10.3 → 0.11.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.
- package/dist/esm/activities/chat/index.d.ts +4 -0
- package/dist/esm/activities/chat/index.js +50 -16
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/middleware/compose.js +5 -4
- package/dist/esm/activities/chat/middleware/compose.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +16 -1
- package/dist/esm/activities/chat/stream/processor.js +120 -21
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/activities/chat/stream/types.d.ts +1 -0
- package/dist/esm/activities/chat/tools/schema-converter.js +4 -2
- package/dist/esm/activities/chat/tools/schema-converter.js.map +1 -1
- package/dist/esm/activities/chat/tools/tool-calls.js +3 -1
- package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
- package/dist/esm/activities/generateVideo/index.js +6 -0
- package/dist/esm/activities/generateVideo/index.js.map +1 -1
- package/dist/esm/activities/stream-generation-result.d.ts +3 -2
- package/dist/esm/activities/stream-generation-result.js +12 -4
- package/dist/esm/activities/stream-generation-result.js.map +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/stream-to-response.d.ts +2 -2
- package/dist/esm/stream-to-response.js +0 -1
- package/dist/esm/stream-to-response.js.map +1 -1
- package/dist/esm/strip-to-spec-middleware.d.ts +18 -0
- package/dist/esm/strip-to-spec-middleware.js +20 -0
- package/dist/esm/strip-to-spec-middleware.js.map +1 -0
- package/dist/esm/types.d.ts +229 -95
- package/package.json +3 -2
- package/src/activities/chat/index.ts +90 -25
- package/src/activities/chat/middleware/compose.ts +6 -4
- package/src/activities/chat/stream/processor.ts +152 -25
- package/src/activities/chat/stream/types.ts +1 -0
- package/src/activities/chat/tools/schema-converter.ts +8 -2
- package/src/activities/chat/tools/tool-calls.ts +4 -2
- package/src/activities/generateVideo/index.ts +13 -6
- package/src/activities/stream-generation-result.ts +19 -11
- package/src/stream-to-response.ts +2 -4
- package/src/strip-to-spec-middleware.ts +37 -0
- package/src/types.ts +276 -109
|
@@ -93,11 +93,12 @@ export class ToolCallManager {
|
|
|
93
93
|
*/
|
|
94
94
|
addToolCallStartEvent(event: ToolCallStartEvent): void {
|
|
95
95
|
const index = event.index ?? this.toolCallsMap.size
|
|
96
|
+
const name = event.toolCallName
|
|
96
97
|
this.toolCallsMap.set(index, {
|
|
97
98
|
id: event.toolCallId,
|
|
98
99
|
type: 'function',
|
|
99
100
|
function: {
|
|
100
|
-
name
|
|
101
|
+
name,
|
|
101
102
|
arguments: '',
|
|
102
103
|
},
|
|
103
104
|
...(event.providerMetadata && {
|
|
@@ -237,11 +238,12 @@ export class ToolCallManager {
|
|
|
237
238
|
yield {
|
|
238
239
|
type: 'TOOL_CALL_END',
|
|
239
240
|
toolCallId: toolCall.id,
|
|
241
|
+
toolCallName: toolCall.function.name,
|
|
240
242
|
toolName: toolCall.function.name,
|
|
241
243
|
model: finishEvent.model,
|
|
242
244
|
timestamp: Date.now(),
|
|
243
245
|
result: toolResultContent,
|
|
244
|
-
}
|
|
246
|
+
} as ToolCallEndEvent
|
|
245
247
|
|
|
246
248
|
// Add tool result message
|
|
247
249
|
toolResults.push({
|
|
@@ -268,11 +268,14 @@ async function* runStreamingVideoGeneration<
|
|
|
268
268
|
const pollingInterval = options.pollingInterval ?? 2000
|
|
269
269
|
const maxDuration = options.maxDuration ?? 600_000
|
|
270
270
|
|
|
271
|
+
const threadId = createId('thread')
|
|
272
|
+
|
|
271
273
|
yield {
|
|
272
274
|
type: 'RUN_STARTED',
|
|
273
275
|
runId,
|
|
276
|
+
threadId,
|
|
274
277
|
timestamp: Date.now(),
|
|
275
|
-
}
|
|
278
|
+
} as StreamChunk
|
|
276
279
|
|
|
277
280
|
try {
|
|
278
281
|
// Create the video generation job
|
|
@@ -289,7 +292,7 @@ async function* runStreamingVideoGeneration<
|
|
|
289
292
|
name: 'video:job:created',
|
|
290
293
|
value: { jobId: jobResult.jobId },
|
|
291
294
|
timestamp: Date.now(),
|
|
292
|
-
}
|
|
295
|
+
} as StreamChunk
|
|
293
296
|
|
|
294
297
|
// Poll for completion
|
|
295
298
|
const startTime = Date.now()
|
|
@@ -308,7 +311,7 @@ async function* runStreamingVideoGeneration<
|
|
|
308
311
|
error: statusResult.error,
|
|
309
312
|
},
|
|
310
313
|
timestamp: Date.now(),
|
|
311
|
-
}
|
|
314
|
+
} as StreamChunk
|
|
312
315
|
|
|
313
316
|
if (statusResult.status === 'completed') {
|
|
314
317
|
const urlResult = await adapter.getVideoUrl(jobResult.jobId)
|
|
@@ -323,14 +326,15 @@ async function* runStreamingVideoGeneration<
|
|
|
323
326
|
expiresAt: urlResult.expiresAt,
|
|
324
327
|
},
|
|
325
328
|
timestamp: Date.now(),
|
|
326
|
-
}
|
|
329
|
+
} as StreamChunk
|
|
327
330
|
|
|
328
331
|
yield {
|
|
329
332
|
type: 'RUN_FINISHED',
|
|
330
333
|
runId,
|
|
334
|
+
threadId,
|
|
331
335
|
finishReason: 'stop',
|
|
332
336
|
timestamp: Date.now(),
|
|
333
|
-
}
|
|
337
|
+
} as StreamChunk
|
|
334
338
|
return
|
|
335
339
|
}
|
|
336
340
|
|
|
@@ -344,12 +348,15 @@ async function* runStreamingVideoGeneration<
|
|
|
344
348
|
yield {
|
|
345
349
|
type: 'RUN_ERROR',
|
|
346
350
|
runId,
|
|
351
|
+
threadId,
|
|
352
|
+
message: error.message || 'Video generation failed',
|
|
353
|
+
code: error.code,
|
|
347
354
|
error: {
|
|
348
355
|
message: error.message || 'Video generation failed',
|
|
349
356
|
code: error.code,
|
|
350
357
|
},
|
|
351
358
|
timestamp: Date.now(),
|
|
352
|
-
}
|
|
359
|
+
} as StreamChunk
|
|
353
360
|
}
|
|
354
361
|
}
|
|
355
362
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* implementations to support `stream: true`.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { EventType } from '@ag-ui/core'
|
|
7
8
|
import type { StreamChunk } from '../types'
|
|
8
9
|
|
|
9
10
|
function createId(prefix: string): string {
|
|
@@ -17,46 +18,53 @@ function createId(prefix: string): string {
|
|
|
17
18
|
* to be sent over the same streaming transport as chat.
|
|
18
19
|
*
|
|
19
20
|
* @param generator - An async function that performs the generation and returns the result
|
|
20
|
-
* @param options - Optional configuration (runId)
|
|
21
|
-
* @returns An AsyncIterable of StreamChunks with RUN_STARTED, CUSTOM(generation:result), and RUN_FINISHED events
|
|
21
|
+
* @param options - Optional configuration (runId, threadId)
|
|
22
|
+
* @returns An AsyncIterable of StreamChunks with RUN_STARTED, CUSTOM(generation:result), and RUN_FINISHED events on success, or RUN_STARTED and RUN_ERROR on failure
|
|
22
23
|
*/
|
|
23
24
|
export async function* streamGenerationResult<TResult>(
|
|
24
25
|
generator: () => Promise<TResult>,
|
|
25
|
-
options?: { runId?: string },
|
|
26
|
+
options?: { runId?: string; threadId?: string },
|
|
26
27
|
): AsyncIterable<StreamChunk> {
|
|
27
28
|
const runId = options?.runId ?? createId('run')
|
|
29
|
+
const threadId = options?.threadId ?? createId('thread')
|
|
28
30
|
|
|
29
31
|
yield {
|
|
30
|
-
type:
|
|
32
|
+
type: EventType.RUN_STARTED,
|
|
31
33
|
runId,
|
|
34
|
+
threadId,
|
|
32
35
|
timestamp: Date.now(),
|
|
33
|
-
}
|
|
36
|
+
} as StreamChunk
|
|
34
37
|
|
|
35
38
|
try {
|
|
36
39
|
const result = await generator()
|
|
37
40
|
|
|
38
41
|
yield {
|
|
39
|
-
type:
|
|
42
|
+
type: EventType.CUSTOM,
|
|
40
43
|
name: 'generation:result',
|
|
41
44
|
value: result as unknown,
|
|
42
45
|
timestamp: Date.now(),
|
|
43
|
-
}
|
|
46
|
+
} as StreamChunk
|
|
44
47
|
|
|
45
48
|
yield {
|
|
46
|
-
type:
|
|
49
|
+
type: EventType.RUN_FINISHED,
|
|
47
50
|
runId,
|
|
51
|
+
threadId,
|
|
48
52
|
finishReason: 'stop',
|
|
49
53
|
timestamp: Date.now(),
|
|
50
|
-
}
|
|
54
|
+
} as StreamChunk
|
|
51
55
|
} catch (error: any) {
|
|
52
56
|
yield {
|
|
53
|
-
type:
|
|
57
|
+
type: EventType.RUN_ERROR,
|
|
54
58
|
runId,
|
|
59
|
+
threadId,
|
|
60
|
+
message: error.message || 'Generation failed',
|
|
61
|
+
code: error.code,
|
|
62
|
+
// Deprecated nested form for backward compatibility
|
|
55
63
|
error: {
|
|
56
64
|
message: error.message || 'Generation failed',
|
|
57
65
|
code: error.code,
|
|
58
66
|
},
|
|
59
67
|
timestamp: Date.now(),
|
|
60
|
-
}
|
|
68
|
+
} as StreamChunk
|
|
61
69
|
}
|
|
62
70
|
}
|
|
@@ -40,7 +40,7 @@ export async function streamToText(
|
|
|
40
40
|
* This creates a ReadableStream that emits chunks in SSE format:
|
|
41
41
|
* - Each chunk is prefixed with "data: "
|
|
42
42
|
* - Each chunk is followed by "\n\n"
|
|
43
|
-
* - Stream ends
|
|
43
|
+
* - Stream ends when the underlying iterable is exhausted (RUN_FINISHED is the terminal event)
|
|
44
44
|
*
|
|
45
45
|
* @param stream - AsyncIterable of StreamChunks from chat()
|
|
46
46
|
* @param abortController - Optional AbortController to abort when stream is cancelled
|
|
@@ -67,8 +67,6 @@ export function toServerSentEventsStream(
|
|
|
67
67
|
)
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
// Send completion marker
|
|
71
|
-
controller.enqueue(encoder.encode('data: [DONE]\n\n'))
|
|
72
70
|
controller.close()
|
|
73
71
|
} catch (error: any) {
|
|
74
72
|
// Don't send error if aborted
|
|
@@ -109,7 +107,7 @@ export function toServerSentEventsStream(
|
|
|
109
107
|
* This creates a Response that emits chunks in SSE format:
|
|
110
108
|
* - Each chunk is prefixed with "data: "
|
|
111
109
|
* - Each chunk is followed by "\n\n"
|
|
112
|
-
* - Stream ends
|
|
110
|
+
* - Stream ends when the underlying iterable is exhausted (RUN_FINISHED is the terminal event)
|
|
113
111
|
*
|
|
114
112
|
* @param stream - AsyncIterable of StreamChunks from chat()
|
|
115
113
|
* @param init - Optional Response initialization options (including `abortController`)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ChatMiddleware } from './activities/chat/middleware/types'
|
|
2
|
+
import type { StreamChunk } from './types'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Strip only the deprecated nested `error` object from RUN_ERROR events.
|
|
6
|
+
* The flat `message`/`code` fields are the spec-compliant form.
|
|
7
|
+
*
|
|
8
|
+
* All other fields pass through unchanged. @ag-ui/core's BaseEventSchema
|
|
9
|
+
* uses `.passthrough()`, so extra fields (model, content, usage,
|
|
10
|
+
* finishReason, toolName, stepId, etc.) are allowed and won't break
|
|
11
|
+
* spec validation or verifyEvents.
|
|
12
|
+
*/
|
|
13
|
+
export function stripToSpec(chunk: StreamChunk): StreamChunk {
|
|
14
|
+
// Only strip the deprecated nested error object from RUN_ERROR
|
|
15
|
+
if (
|
|
16
|
+
(chunk as StreamChunk & { type: string }).type === 'RUN_ERROR' &&
|
|
17
|
+
'error' in chunk
|
|
18
|
+
) {
|
|
19
|
+
const { error: _deprecated, ...rest } = chunk as Record<string, unknown>
|
|
20
|
+
return rest as StreamChunk
|
|
21
|
+
}
|
|
22
|
+
return chunk
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Middleware that ensures events are AG-UI spec compliant.
|
|
27
|
+
* Currently only strips the deprecated nested `error` object from RUN_ERROR.
|
|
28
|
+
* All other fields pass through unchanged (passthrough allowed by spec).
|
|
29
|
+
*/
|
|
30
|
+
export function stripToSpecMiddleware(): ChatMiddleware {
|
|
31
|
+
return {
|
|
32
|
+
name: 'strip-to-spec',
|
|
33
|
+
onChunk(_ctx, chunk) {
|
|
34
|
+
return stripToSpec(chunk)
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
}
|