@tanstack/ai 0.6.3 → 0.8.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 (68) hide show
  1. package/README.md +6 -6
  2. package/dist/esm/activities/chat/index.d.ts +20 -0
  3. package/dist/esm/activities/chat/index.js +248 -213
  4. package/dist/esm/activities/chat/index.js.map +1 -1
  5. package/dist/esm/activities/chat/middleware/compose.d.ts +66 -0
  6. package/dist/esm/activities/chat/middleware/compose.js +327 -0
  7. package/dist/esm/activities/chat/middleware/compose.js.map +1 -0
  8. package/dist/esm/activities/chat/middleware/index.d.ts +2 -0
  9. package/dist/esm/activities/chat/middleware/tool-cache-middleware.d.ts +89 -0
  10. package/dist/esm/activities/chat/middleware/tool-cache-middleware.js +76 -0
  11. package/dist/esm/activities/chat/middleware/tool-cache-middleware.js.map +1 -0
  12. package/dist/esm/activities/chat/middleware/types.d.ts +307 -0
  13. package/dist/esm/activities/chat/stream/processor.d.ts +64 -40
  14. package/dist/esm/activities/chat/stream/processor.js +466 -218
  15. package/dist/esm/activities/chat/stream/processor.js.map +1 -1
  16. package/dist/esm/activities/chat/stream/types.d.ts +17 -0
  17. package/dist/esm/activities/chat/tools/tool-calls.d.ts +16 -1
  18. package/dist/esm/activities/chat/tools/tool-calls.js +148 -64
  19. package/dist/esm/activities/chat/tools/tool-calls.js.map +1 -1
  20. package/dist/esm/activities/generateImage/index.js +1 -1
  21. package/dist/esm/activities/generateImage/index.js.map +1 -1
  22. package/dist/esm/activities/generateSpeech/index.js +1 -1
  23. package/dist/esm/activities/generateSpeech/index.js.map +1 -1
  24. package/dist/esm/activities/generateTranscription/index.js +1 -1
  25. package/dist/esm/activities/generateTranscription/index.js.map +1 -1
  26. package/dist/esm/activities/generateVideo/index.js +1 -1
  27. package/dist/esm/activities/generateVideo/index.js.map +1 -1
  28. package/dist/esm/activities/summarize/index.js +1 -1
  29. package/dist/esm/activities/summarize/index.js.map +1 -1
  30. package/dist/esm/index.d.ts +3 -1
  31. package/dist/esm/index.js +2 -2
  32. package/dist/esm/middlewares/content-guard.d.ts +77 -0
  33. package/dist/esm/middlewares/content-guard.js +155 -0
  34. package/dist/esm/middlewares/content-guard.js.map +1 -0
  35. package/dist/esm/middlewares/index.d.ts +2 -0
  36. package/dist/esm/middlewares/index.js +7 -0
  37. package/dist/esm/middlewares/index.js.map +1 -0
  38. package/dist/esm/middlewares/tool-cache.d.ts +1 -0
  39. package/dist/esm/realtime/index.d.ts +30 -0
  40. package/dist/esm/realtime/index.js +8 -0
  41. package/dist/esm/realtime/index.js.map +1 -0
  42. package/dist/esm/realtime/types.d.ts +234 -0
  43. package/dist/esm/types.d.ts +18 -4
  44. package/package.json +6 -6
  45. package/src/activities/chat/index.ts +322 -256
  46. package/src/activities/chat/middleware/compose.ts +392 -0
  47. package/src/activities/chat/middleware/index.ts +17 -0
  48. package/src/activities/chat/middleware/tool-cache-middleware.ts +189 -0
  49. package/src/activities/chat/middleware/types.ts +419 -0
  50. package/src/activities/chat/stream/processor.ts +630 -259
  51. package/src/activities/chat/stream/types.ts +18 -0
  52. package/src/activities/chat/tools/tool-calls.ts +225 -87
  53. package/src/activities/generateImage/index.ts +1 -1
  54. package/src/activities/generateSpeech/index.ts +1 -1
  55. package/src/activities/generateTranscription/index.ts +1 -1
  56. package/src/activities/generateVideo/index.ts +1 -1
  57. package/src/activities/summarize/index.ts +1 -1
  58. package/src/index.ts +41 -2
  59. package/src/middlewares/content-guard.ts +285 -0
  60. package/src/middlewares/index.ts +13 -0
  61. package/src/middlewares/tool-cache.ts +6 -0
  62. package/src/realtime/index.ts +38 -0
  63. package/src/realtime/types.ts +294 -0
  64. package/src/types.ts +19 -2
  65. package/dist/esm/event-client.d.ts +0 -394
  66. package/dist/esm/event-client.js +0 -13
  67. package/dist/esm/event-client.js.map +0 -1
  68. package/src/event-client.ts +0 -497
@@ -0,0 +1,419 @@
1
+ import type { ModelMessage, StreamChunk, Tool, ToolCall } from '../../../types'
2
+
3
+ // ===========================
4
+ // Middleware Context
5
+ // ===========================
6
+
7
+ /**
8
+ * Phase of the chat middleware lifecycle.
9
+ * - 'init': Initial config transform before the chat engine starts
10
+ * - 'beforeModel': Before each adapter chatStream call (per agent iteration)
11
+ * - 'modelStream': During model streaming
12
+ * - 'beforeTools': Before tool execution phase
13
+ * - 'afterTools': After tool execution phase
14
+ */
15
+ export type ChatMiddlewarePhase =
16
+ | 'init'
17
+ | 'beforeModel'
18
+ | 'modelStream'
19
+ | 'beforeTools'
20
+ | 'afterTools'
21
+
22
+ /**
23
+ * Stable context object passed to all middleware hooks.
24
+ * Created once per chat() invocation and shared across all hooks.
25
+ */
26
+ export interface ChatMiddlewareContext {
27
+ /** Unique identifier for this chat request */
28
+ requestId: string
29
+ /** Unique identifier for this stream */
30
+ streamId: string
31
+ /** Conversation identifier, if provided by the caller */
32
+ conversationId?: string
33
+ /** Current lifecycle phase */
34
+ phase: ChatMiddlewarePhase
35
+ /** Current agent loop iteration (0-indexed) */
36
+ iteration: number
37
+ /** Running count of chunks yielded so far */
38
+ chunkIndex: number
39
+ /** Abort signal from the chat request */
40
+ signal?: AbortSignal
41
+ /** Abort the chat run with a reason */
42
+ abort: (reason?: string) => void
43
+ /** Opaque user-provided value from chat() options */
44
+ context: unknown
45
+ /**
46
+ * Defer a non-blocking side-effect promise.
47
+ * Deferred promises do not block streaming and are awaited
48
+ * after the terminal hook (onFinish/onAbort/onError).
49
+ */
50
+ defer: (promise: Promise<unknown>) => void
51
+
52
+ // --- Provider / adapter info (immutable for the lifetime of the request) ---
53
+
54
+ /** Provider name (e.g., 'openai', 'anthropic') */
55
+ provider: string
56
+ /** Model identifier (e.g., 'gpt-4o') */
57
+ model: string
58
+ /** Source of the chat invocation — always 'server' for server-side chat */
59
+ source: 'client' | 'server'
60
+ /** Whether the chat is streaming */
61
+ streaming: boolean
62
+
63
+ // --- Config-derived info (may update per-iteration via onConfig) ---
64
+
65
+ /** System prompts configured for this chat */
66
+ systemPrompts: Array<string>
67
+ /** Names of configured tools, if any */
68
+ toolNames?: Array<string>
69
+ /** Flattened generation options (temperature, topP, maxTokens, metadata) */
70
+ options?: Record<string, unknown>
71
+ /** Provider-specific model options */
72
+ modelOptions?: Record<string, unknown>
73
+
74
+ // --- Computed info ---
75
+
76
+ /** Number of messages at the start of the request */
77
+ messageCount: number
78
+ /** Whether tools are configured */
79
+ hasTools: boolean
80
+
81
+ // --- Mutable per-iteration state ---
82
+
83
+ /** Current assistant message ID (changes per iteration) */
84
+ currentMessageId: string | null
85
+ /** Accumulated text content for the current iteration */
86
+ accumulatedContent: string
87
+
88
+ // --- References ---
89
+
90
+ /** Current messages array (read-only view) */
91
+ messages: ReadonlyArray<ModelMessage>
92
+ /** Generate a unique ID with the given prefix */
93
+ createId: (prefix: string) => string
94
+ }
95
+
96
+ // ===========================
97
+ // Config passed to onConfig
98
+ // ===========================
99
+
100
+ /**
101
+ * Chat configuration that middleware can observe or transform.
102
+ * This is a subset of the chat engine's effective configuration
103
+ * that middleware is allowed to modify.
104
+ */
105
+ export interface ChatMiddlewareConfig {
106
+ messages: Array<ModelMessage>
107
+ systemPrompts: Array<string>
108
+ tools: Array<Tool>
109
+ temperature?: number
110
+ topP?: number
111
+ maxTokens?: number
112
+ metadata?: Record<string, unknown>
113
+ modelOptions?: Record<string, unknown>
114
+ }
115
+
116
+ // ===========================
117
+ // Tool Call Hook Context
118
+ // ===========================
119
+
120
+ /**
121
+ * Context provided to tool call hooks (onBeforeToolCall / onAfterToolCall).
122
+ */
123
+ export interface ToolCallHookContext {
124
+ /** The tool call being executed */
125
+ toolCall: ToolCall
126
+ /** The resolved tool definition, if found */
127
+ tool: Tool | undefined
128
+ /** Parsed arguments for the tool call */
129
+ args: unknown
130
+ /** Name of the tool */
131
+ toolName: string
132
+ /** ID of the tool call */
133
+ toolCallId: string
134
+ }
135
+
136
+ /**
137
+ * Decision returned from onBeforeToolCall.
138
+ * - undefined/void: continue with normal execution
139
+ * - { type: 'transformArgs', args }: replace args used for execution
140
+ * - { type: 'skip', result }: skip execution, use provided result
141
+ * - { type: 'abort', reason }: abort the entire chat run
142
+ */
143
+ export type BeforeToolCallDecision =
144
+ | void
145
+ | undefined
146
+ | null
147
+ | { type: 'transformArgs'; args: unknown }
148
+ | { type: 'skip'; result: unknown }
149
+ | { type: 'abort'; reason?: string }
150
+
151
+ /**
152
+ * Outcome information provided to onAfterToolCall.
153
+ */
154
+ export interface AfterToolCallInfo {
155
+ /** The tool call that was executed */
156
+ toolCall: ToolCall
157
+ /** The resolved tool definition */
158
+ tool: Tool | undefined
159
+ /** Name of the tool */
160
+ toolName: string
161
+ /** ID of the tool call */
162
+ toolCallId: string
163
+ /** Whether the execution succeeded */
164
+ ok: boolean
165
+ /** Duration of tool execution in milliseconds */
166
+ duration: number
167
+ /** The result (if ok) or error (if not ok) */
168
+ result?: unknown
169
+ error?: unknown
170
+ }
171
+
172
+ // ===========================
173
+ // Iteration Info
174
+ // ===========================
175
+
176
+ /**
177
+ * Information passed to onIteration at the start of each agent loop iteration.
178
+ */
179
+ export interface IterationInfo {
180
+ /** 0-based iteration index */
181
+ iteration: number
182
+ /** The assistant message ID created for this iteration */
183
+ messageId: string
184
+ }
185
+
186
+ // ===========================
187
+ // Tool Phase Complete Info
188
+ // ===========================
189
+
190
+ /**
191
+ * Aggregate information passed to onToolPhaseComplete after all tool calls
192
+ * in an iteration have been processed.
193
+ */
194
+ export interface ToolPhaseCompleteInfo {
195
+ /** Tool calls that were assigned to the assistant message */
196
+ toolCalls: Array<ToolCall>
197
+ /** Completed tool results */
198
+ results: Array<{
199
+ toolCallId: string
200
+ toolName: string
201
+ result: unknown
202
+ duration?: number
203
+ }>
204
+ /** Tools that need user approval */
205
+ needsApproval: Array<{
206
+ toolCallId: string
207
+ toolName: string
208
+ input: unknown
209
+ approvalId: string
210
+ }>
211
+ /** Tools that need client-side execution */
212
+ needsClientExecution: Array<{
213
+ toolCallId: string
214
+ toolName: string
215
+ input: unknown
216
+ }>
217
+ }
218
+
219
+ // ===========================
220
+ // Usage Info
221
+ // ===========================
222
+
223
+ /**
224
+ * Token usage statistics passed to the onUsage hook.
225
+ * Extracted from the RUN_FINISHED chunk when usage data is present.
226
+ */
227
+ export interface UsageInfo {
228
+ promptTokens: number
229
+ completionTokens: number
230
+ totalTokens: number
231
+ }
232
+
233
+ // ===========================
234
+ // Terminal Hook Info
235
+ // ===========================
236
+
237
+ /**
238
+ * Information passed to onFinish.
239
+ */
240
+ export interface FinishInfo {
241
+ /** The finish reason from the last model response */
242
+ finishReason: string | null
243
+ /** Total duration of the chat run in milliseconds */
244
+ duration: number
245
+ /** Final accumulated text content */
246
+ content: string
247
+ /** Final usage totals, if available */
248
+ usage?: {
249
+ promptTokens: number
250
+ completionTokens: number
251
+ totalTokens: number
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Information passed to onAbort.
257
+ */
258
+ export interface AbortInfo {
259
+ /** The reason for the abort, if provided */
260
+ reason?: string
261
+ /** Duration until abort in milliseconds */
262
+ duration: number
263
+ }
264
+
265
+ /**
266
+ * Information passed to onError.
267
+ */
268
+ export interface ErrorInfo {
269
+ /** The error that caused the failure */
270
+ error: unknown
271
+ /** Duration until error in milliseconds */
272
+ duration: number
273
+ }
274
+
275
+ // ===========================
276
+ // Middleware Interface
277
+ // ===========================
278
+
279
+ /**
280
+ * Chat middleware interface.
281
+ *
282
+ * All hooks are optional. Middleware is composed in array order:
283
+ * - `onConfig`: config piped through middlewares in order (first transform influences later)
284
+ * - `onChunk`: each output chunk is fed into the next middleware in order
285
+ *
286
+ * @example Logging middleware
287
+ * ```ts
288
+ * const loggingMiddleware: ChatMiddleware = {
289
+ * name: 'logging',
290
+ * onStart(ctx) { console.log('Chat started', ctx.requestId) },
291
+ * onChunk(ctx, chunk) { console.log('Chunk:', chunk.type) },
292
+ * onFinish(ctx, info) { console.log('Done:', info.duration, 'ms') },
293
+ * }
294
+ * ```
295
+ *
296
+ * @example Redaction middleware
297
+ * ```ts
298
+ * const redactionMiddleware: ChatMiddleware = {
299
+ * name: 'redaction',
300
+ * onChunk(ctx, chunk) {
301
+ * if (chunk.type === 'TEXT_MESSAGE_CONTENT') {
302
+ * return { ...chunk, delta: redact(chunk.delta) }
303
+ * }
304
+ * },
305
+ * }
306
+ * ```
307
+ */
308
+ export interface ChatMiddleware {
309
+ /** Optional name for debugging and identification */
310
+ name?: string
311
+
312
+ /**
313
+ * Called to observe or transform the chat configuration.
314
+ * Called at init and at the beginning of each agent iteration.
315
+ *
316
+ * Return a partial config to merge with the current config, or void to pass through.
317
+ * Only the fields you return are overwritten — everything else is preserved.
318
+ */
319
+ onConfig?: (
320
+ ctx: ChatMiddlewareContext,
321
+ config: ChatMiddlewareConfig,
322
+ ) =>
323
+ | void
324
+ | null
325
+ | Partial<ChatMiddlewareConfig>
326
+ | Promise<void | Partial<ChatMiddlewareConfig>>
327
+
328
+ /**
329
+ * Called when the chat run starts (after initial onConfig).
330
+ */
331
+ onStart?: (ctx: ChatMiddlewareContext) => void | Promise<void>
332
+
333
+ /**
334
+ * Called at the start of each agent loop iteration, after a new assistant message ID
335
+ * is created. Use this to observe iteration boundaries.
336
+ */
337
+ onIteration?: (
338
+ ctx: ChatMiddlewareContext,
339
+ info: IterationInfo,
340
+ ) => void | Promise<void>
341
+
342
+ /**
343
+ * Called for every chunk yielded by chat().
344
+ * Can observe, transform, expand, or drop chunks.
345
+ *
346
+ * @returns void (pass through), chunk (replace), chunk[] (expand), null (drop)
347
+ */
348
+ onChunk?: (
349
+ ctx: ChatMiddlewareContext,
350
+ chunk: StreamChunk,
351
+ ) =>
352
+ | void
353
+ | StreamChunk
354
+ | Array<StreamChunk>
355
+ | null
356
+ | Promise<void | StreamChunk | Array<StreamChunk> | null>
357
+
358
+ /**
359
+ * Called before a tool is executed.
360
+ * Can observe, transform args, skip execution, or abort the run.
361
+ */
362
+ onBeforeToolCall?: (
363
+ ctx: ChatMiddlewareContext,
364
+ hookCtx: ToolCallHookContext,
365
+ ) => BeforeToolCallDecision | Promise<BeforeToolCallDecision>
366
+
367
+ /**
368
+ * Called after a tool execution completes (success or failure).
369
+ */
370
+ onAfterToolCall?: (
371
+ ctx: ChatMiddlewareContext,
372
+ info: AfterToolCallInfo,
373
+ ) => void | Promise<void>
374
+
375
+ /**
376
+ * Called after all tool calls in an iteration have been processed.
377
+ * Provides aggregate data about tool execution results, approvals, and client tools.
378
+ */
379
+ onToolPhaseComplete?: (
380
+ ctx: ChatMiddlewareContext,
381
+ info: ToolPhaseCompleteInfo,
382
+ ) => void | Promise<void>
383
+
384
+ /**
385
+ * Called when usage data is available from a RUN_FINISHED chunk.
386
+ * Called once per model iteration that reports usage.
387
+ */
388
+ onUsage?: (
389
+ ctx: ChatMiddlewareContext,
390
+ usage: UsageInfo,
391
+ ) => void | Promise<void>
392
+
393
+ /**
394
+ * Called when the chat run completes normally.
395
+ * Exactly one of onFinish/onAbort/onError will be called per run.
396
+ */
397
+ onFinish?: (
398
+ ctx: ChatMiddlewareContext,
399
+ info: FinishInfo,
400
+ ) => void | Promise<void>
401
+
402
+ /**
403
+ * Called when the chat run is aborted.
404
+ * Exactly one of onFinish/onAbort/onError will be called per run.
405
+ */
406
+ onAbort?: (
407
+ ctx: ChatMiddlewareContext,
408
+ info: AbortInfo,
409
+ ) => void | Promise<void>
410
+
411
+ /**
412
+ * Called when the chat run encounters an unhandled error.
413
+ * Exactly one of onFinish/onAbort/onError will be called per run.
414
+ */
415
+ onError?: (
416
+ ctx: ChatMiddlewareContext,
417
+ info: ErrorInfo,
418
+ ) => void | Promise<void>
419
+ }