ai-stream-utils 1.6.0 → 2.0.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/dist/index.d.mts CHANGED
@@ -1,6 +1,8 @@
1
- import { AsyncIterableStream, InferUIMessageChunk, UIMessage } from "ai";
1
+ import { a as convertSSEToUIMessageStream, c as convertArrayToStream, i as convertStreamToArray, l as convertArrayToAsyncIterable, n as createAsyncIterableStream, o as convertAsyncIterableToStream, r as convertUIMessageToSSEStream, s as convertAsyncIterableToArray, t as AsyncIterableStream } from "./types-B4nePmEd.mjs";
2
+ import "./utils/index.mjs";
3
+ import { AsyncIterableStream as AsyncIterableStream$1, InferUIMessageChunk, UIMessage } from "ai";
2
4
 
3
- //#region src/consume-ui-message-stream.d.ts
5
+ //#region src/consume/consume-ui-message-stream.d.ts
4
6
  /**
5
7
  * Consumes a UIMessageStream by fully reading it and returning the final UI message.
6
8
  *
@@ -23,123 +25,121 @@ import { AsyncIterableStream, InferUIMessageChunk, UIMessage } from "ai";
23
25
  */
24
26
  declare function consumeUIMessageStream<UI_MESSAGE extends UIMessage>(stream: ReadableStream<InferUIMessageChunk<UI_MESSAGE>>): Promise<UI_MESSAGE>;
25
27
  //#endregion
26
- //#region src/types.d.ts
27
- type InferUIMessagePart<UI_MESSAGE extends UIMessage> = UI_MESSAGE['parts'][number];
28
- type InferUIMessagePartType<UI_MESSAGE extends UIMessage> = InferUIMessagePart<UI_MESSAGE>['type'];
28
+ //#region src/pipe/base-pipeline.d.ts
29
+ /**
30
+ * Internal chunk representation used within the pipeline.
31
+ * Includes the original chunk and the part type (or undefined for meta chunks).
32
+ */
33
+ type InternalChunk<UI_MESSAGE extends UIMessage> = {
34
+ chunk: InferUIMessageChunk<UI_MESSAGE>;
35
+ partType: string | undefined;
36
+ };
37
+ /**
38
+ * Base interface for all pipeline types.
39
+ */
40
+ interface BasePipeline<UI_MESSAGE extends UIMessage> {
41
+ toStream(): AsyncIterableStream$1<InferUIMessageChunk<UI_MESSAGE>>;
42
+ }
29
43
  //#endregion
30
- //#region src/map-ui-message-stream.d.ts
44
+ //#region src/pipe/types.d.ts
31
45
  /**
32
- * Input object provided to the chunk map function.
46
+ * Input for chunk-based operations.
33
47
  */
34
- type MapInput<UI_MESSAGE extends UIMessage> = {
35
- /** The current chunk */chunk: InferUIMessageChunk<UI_MESSAGE>;
36
- /**
37
- * The assembled part this chunk belongs to (from readUIMessageStream).
38
- * Use `part.type` to determine the part type.
39
- */
40
- part: InferUIMessagePart<UI_MESSAGE>;
48
+ type ChunkInput<CHUNK, PART extends {
49
+ type: string;
50
+ }> = {
51
+ chunk: CHUNK;
52
+ part: Pick<PART, `type`>;
41
53
  };
42
54
  /**
43
- * Map function for chunk-level transformation.
44
- * Return:
45
- * - A single chunk (possibly transformed) to include it
46
- * - An array of chunks to emit multiple chunks
47
- * - An empty array or null to filter out the chunk
55
+ * Filter predicate for chunk-based operations.
56
+ * Returns true to include the chunk, false to exclude.
57
+ * The __brand exclusion prevents type guards from matching this type.
48
58
  */
49
- type MapUIMessageStreamFn<UI_MESSAGE extends UIMessage> = (input: MapInput<UI_MESSAGE>) => InferUIMessageChunk<UI_MESSAGE> | InferUIMessageChunk<UI_MESSAGE>[] | null;
59
+ type ChunkFilterFn<CHUNK, PART extends {
60
+ type: string;
61
+ }> = ((input: ChunkInput<CHUNK, PART>) => boolean) & {
62
+ __brand?: never;
63
+ };
50
64
  /**
51
- * Maps/filters a UIMessageStream at the chunk level using readUIMessageStream.
52
- *
53
- * This function processes each chunk as it arrives and allows you to:
54
- * - Transform chunks by returning a modified chunk
55
- * - Filter out chunks by returning null or an empty array
56
- * - Emit multiple chunks by returning an array
57
- *
58
- * Meta chunks (start, finish, abort, message-metadata, error) always pass through.
59
- * Step boundaries (start-step, finish-step) are handled automatically:
60
- * - start-step is buffered and only emitted if subsequent content is included
61
- * - finish-step is only emitted if the corresponding start-step was emitted
62
- *
63
- * @example
64
- * ```typescript
65
- * // Filter out reasoning chunks using part.type
66
- * const stream = mapUIMessageStream(
67
- * inputStream,
68
- * ({ chunk, part }) => part.type === 'reasoning' ? null : chunk
69
- * );
70
- *
71
- * // Transform text chunks
72
- * const stream = mapUIMessageStream(
73
- * inputStream,
74
- * ({ chunk, part }) => {
75
- * if (chunk.type === 'text-delta') {
76
- * return { ...chunk, delta: chunk.delta.toUpperCase() };
77
- * }
78
- * return chunk;
79
- * }
80
- * );
81
- *
82
- * // Buffer text deltas and split into word-by-word chunks (smooth streaming)
83
- * let buffer = '';
84
- * let textStartChunk = null;
85
- * const stream = mapUIMessageStream(
86
- * inputStream,
87
- * ({ chunk }) => {
88
- * if (chunk.type === 'text-start') {
89
- * textStartChunk = chunk;
90
- * return []; // Buffer, don't emit yet
91
- * }
92
- * if (chunk.type === 'text-delta') {
93
- * buffer += chunk.delta;
94
- * return []; // Buffer, don't emit yet
95
- * }
96
- * if (chunk.type === 'text-end') {
97
- * // Emit buffered content as word chunks
98
- * const words = buffer.split(' ');
99
- * const wordChunks = words.map((word, i) => ({
100
- * type: 'text-delta' as const,
101
- * id: chunk.id,
102
- * delta: i === 0 ? word : ` ${word}`,
103
- * }));
104
- * buffer = '';
105
- * const result = [...wordChunks, chunk];
106
- * if (textStartChunk) {
107
- * result.unshift(textStartChunk);
108
- * textStartChunk = null;
109
- * }
110
- * return result;
111
- * }
112
- * return chunk;
113
- * }
114
- * );
115
- * ```
65
+ * Map function for chunk-based operations.
66
+ * Returns transformed chunk(s) or null to remove.
116
67
  */
117
- declare function mapUIMessageStream<UI_MESSAGE extends UIMessage>(stream: ReadableStream<InferUIMessageChunk<UI_MESSAGE>>, mapFn: MapUIMessageStreamFn<UI_MESSAGE>): AsyncIterableStream<InferUIMessageChunk<UI_MESSAGE>>;
118
- //#endregion
119
- //#region src/filter-ui-message-stream.d.ts
68
+ type ChunkMapFn<UI_MESSAGE extends UIMessage, CHUNK extends InferUIMessageChunk<UI_MESSAGE>, PART extends {
69
+ type: string;
70
+ }> = (input: ChunkInput<CHUNK, PART>) => InferUIMessageChunk<UI_MESSAGE> | Array<InferUIMessageChunk<UI_MESSAGE>> | null;
120
71
  /**
121
- * Filter function that receives the same input as mapUIMessageStream.
122
- * Return true to include the chunk, false to filter it out.
72
+ * Input for observer operations.
73
+ * Part is optional since meta chunks don't have a part type.
123
74
  */
124
- type FilterUIMessageStreamPredicate<UI_MESSAGE extends UIMessage> = (input: MapInput<UI_MESSAGE>) => boolean;
75
+ type ChunkObserveInput<CHUNK, PART extends {
76
+ type: string;
77
+ } | undefined = {
78
+ type: string;
79
+ } | undefined> = {
80
+ chunk: CHUNK;
81
+ part: PART;
82
+ };
125
83
  /**
126
- * Creates a filter predicate that includes only the specified part types.
127
- *
128
- * @example
129
- * ```typescript
130
- * filterUIMessageStream(stream, includeParts(['text', 'tool-weather']));
131
- * ```
84
+ * Callback function for observer operations.
85
+ * Called for each matching chunk. Can be sync or async.
132
86
  */
133
- declare function includeParts<UI_MESSAGE extends UIMessage>(includePartTypes: Array<InferUIMessagePartType<UI_MESSAGE>>): FilterUIMessageStreamPredicate<UI_MESSAGE>;
87
+ type ChunkObserveFn<CHUNK, PART extends {
88
+ type: string;
89
+ } | undefined = undefined> = (input: ChunkObserveInput<CHUNK, PART>) => void | Promise<void>;
134
90
  /**
135
- * Creates a filter predicate that excludes the specified part types.
136
- *
137
- * @example
138
- * ```typescript
139
- * filterUIMessageStream(stream, excludeParts(['reasoning', 'tool-calculator']));
140
- * ```
91
+ * Builder function for ChunkPipeline operations.
141
92
  */
142
- declare function excludeParts<UI_MESSAGE extends UIMessage>(excludePartTypes: Array<InferUIMessagePartType<UI_MESSAGE>>): FilterUIMessageStreamPredicate<UI_MESSAGE>;
93
+ type ChunkBuilder<UI_MESSAGE extends UIMessage> = (iterable: AsyncIterable<InternalChunk<UI_MESSAGE>>) => AsyncIterable<InternalChunk<UI_MESSAGE>>;
94
+ /**
95
+ * Generic guard for filter() that carries pre-computed narrowed types.
96
+ * The __brand property distinguishes this from plain predicates.
97
+ */
98
+ type FilterGuard<UI_MESSAGE extends UIMessage, NARROWED_CHUNK extends InferUIMessageChunk<UI_MESSAGE>, NARROWED_PART extends {
99
+ type: string;
100
+ }> = {
101
+ <T extends {
102
+ chunk: InferUIMessageChunk<UI_MESSAGE>;
103
+ part?: {
104
+ type: string;
105
+ } | undefined;
106
+ }>(input: T): input is T & {
107
+ chunk: NARROWED_CHUNK;
108
+ part: NARROWED_PART;
109
+ }; /** @internal Type brand - never exists at runtime */
110
+ readonly __brand: `FilterGuard`;
111
+ };
112
+ /**
113
+ * Generic guard for on() that carries pre-computed narrowed types.
114
+ * Part can be undefined for meta chunks.
115
+ * The __brand property distinguishes this from plain predicates.
116
+ */
117
+ type ObserveGuard<UI_MESSAGE extends UIMessage, NARROWED_CHUNK extends InferUIMessageChunk<UI_MESSAGE>, NARROWED_PART extends {
118
+ type: string;
119
+ } | undefined> = {
120
+ <T extends {
121
+ chunk: InferUIMessageChunk<UI_MESSAGE>;
122
+ part?: {
123
+ type: string;
124
+ } | undefined;
125
+ }>(input: T): input is T & {
126
+ chunk: NARROWED_CHUNK;
127
+ part: NARROWED_PART;
128
+ }; /** @internal Type brand - never exists at runtime */
129
+ readonly __brand: `ObserveGuard`;
130
+ };
131
+ //#endregion
132
+ //#region src/filter/filter-ui-message-stream.d.ts
133
+ /**
134
+ * Filter function type for filterUIMessageStream.
135
+ * Can be either a FilterGuard (from includeParts/excludeParts) or a plain predicate.
136
+ */
137
+ type FilterFn<UI_MESSAGE extends UIMessage> = FilterGuard<UI_MESSAGE, any, any> | ((input: {
138
+ chunk: InferUIMessageChunk<UI_MESSAGE>;
139
+ part: {
140
+ type: string;
141
+ };
142
+ }) => boolean);
143
143
  /**
144
144
  * Filters a UIMessageStream to include or exclude specific chunks.
145
145
  *
@@ -175,9 +175,151 @@ declare function excludeParts<UI_MESSAGE extends UIMessage>(excludePartTypes: Ar
175
175
  * );
176
176
  * ```
177
177
  */
178
- declare function filterUIMessageStream<UI_MESSAGE extends UIMessage>(stream: ReadableStream<InferUIMessageChunk<UI_MESSAGE>>, predicate: FilterUIMessageStreamPredicate<UI_MESSAGE>): AsyncIterableStream<InferUIMessageChunk<UI_MESSAGE>>;
178
+ declare function filterUIMessageStream<UI_MESSAGE extends UIMessage>(stream: ReadableStream<InferUIMessageChunk<UI_MESSAGE>>, predicate: FilterFn<UI_MESSAGE>): AsyncIterableStream$1<InferUIMessageChunk<UI_MESSAGE>>;
179
179
  //#endregion
180
- //#region src/flat-map-ui-message-stream.d.ts
180
+ //#region src/types.d.ts
181
+ type InferUIMessagePart<UI_MESSAGE extends UIMessage> = UI_MESSAGE["parts"][number];
182
+ type InferUIMessagePartType<UI_MESSAGE extends UIMessage> = InferUIMessagePart<UI_MESSAGE>["type"];
183
+ type InferUIMessageChunkType<UI_MESSAGE extends UIMessage> = InferUIMessageChunk<UI_MESSAGE>["type"];
184
+ /**
185
+ * Extracts chunk type strings that match the prefix exactly or as `${PREFIX}-*`.
186
+ * Dynamically derives chunk types from the actual UIMessageChunk union.
187
+ *
188
+ * @example
189
+ * ```typescript
190
+ * type TextChunks = ExtractChunkTypesByPrefix<MyUIMessage, 'text'>;
191
+ * // => 'text-start' | 'text-delta' | 'text-end'
192
+ *
193
+ * type FileChunks = ExtractChunkTypesByPrefix<MyUIMessage, 'file'>;
194
+ * // => 'file' (exact match)
195
+ * ```
196
+ */
197
+ type ExtractChunkTypesByPrefix<UI_MESSAGE extends UIMessage, PREFIX extends string> = InferUIMessageChunk<UI_MESSAGE> extends infer CHUNK ? CHUNK extends {
198
+ type: infer T extends string;
199
+ } ? T extends PREFIX | `${PREFIX}-${string}` ? T : never : never : never;
200
+ /**
201
+ * Maps a part type string to its corresponding chunk type(s).
202
+ * Dynamically extracts from UIMessageChunk.
203
+ *
204
+ * Special handling:
205
+ * - `tool-{NAME}` parts map to all `tool-*` chunk types (tool-input-start, tool-output-available, etc.)
206
+ * - `dynamic-tool` parts also map to all `tool-*` chunk types
207
+ * - `step-start` part maps to `start-step` chunk (naming inconsistency in AI SDK)
208
+ *
209
+ * @example
210
+ * ```typescript
211
+ * type TextChunkTypes = PartTypeToChunkTypes<MyUIMessage, 'text'>;
212
+ * // => 'text-start' | 'text-delta' | 'text-end'
213
+ *
214
+ * type ToolChunkTypes = PartTypeToChunkTypes<MyUIMessage, 'tool-weather'>;
215
+ * // => 'tool-input-start' | 'tool-input-delta' | ... (all tool chunk types)
216
+ * ```
217
+ */
218
+ type PartTypeToChunkTypes<UI_MESSAGE extends UIMessage, PART_TYPE extends string> = PART_TYPE extends `tool-${string}` | "dynamic-tool" ? ExtractChunkTypesByPrefix<UI_MESSAGE, "tool"> : PART_TYPE extends "step-start" ? "start-step" : ExtractChunkTypesByPrefix<UI_MESSAGE, PART_TYPE>;
219
+ /**
220
+ * Extracts the chunk type(s) for a given part or part union.
221
+ *
222
+ * @example
223
+ * ```typescript
224
+ * type TextChunk = ExtractChunkForPart<MyUIMessage, TextPart>;
225
+ * // => { type: 'text-start'; ... } | { type: 'text-delta'; ... } | { type: 'text-end'; ... }
226
+ * ```
227
+ */
228
+ type ExtractChunkForPart<UI_MESSAGE extends UIMessage, PART extends InferUIMessagePart<UI_MESSAGE>> = Extract<InferUIMessageChunk<UI_MESSAGE>, {
229
+ type: PartTypeToChunkTypes<UI_MESSAGE, PART["type"]>;
230
+ }>;
231
+ /**
232
+ * Extract a specific part type from UIMessage
233
+ */
234
+ type ExtractPart<UI_MESSAGE extends UIMessage, PART_TYPE extends string> = Extract<InferUIMessagePart<UI_MESSAGE>, {
235
+ type: PART_TYPE;
236
+ }>;
237
+ /**
238
+ * Extract a specific chunk type from UIMessage
239
+ */
240
+ type ExtractChunk<UI_MESSAGE extends UIMessage, CHUNK_TYPE extends string> = Extract<InferUIMessageChunk<UI_MESSAGE>, {
241
+ type: CHUNK_TYPE;
242
+ }>;
243
+ /**
244
+ * Maps chunk type string(s) back to the corresponding part type string(s).
245
+ * Reverse of `PartTypeToChunkTypes`.
246
+ *
247
+ * @example
248
+ * ```typescript
249
+ * type TextPartType = ChunkTypeToPartType<MyUIMessage, 'text-delta'>;
250
+ * // => 'text'
251
+ *
252
+ * type ToolPartType = ChunkTypeToPartType<MyUIMessage, 'tool-input-delta'>;
253
+ * // => 'tool-weather' | 'dynamic-tool' (all tool part types)
254
+ * ```
255
+ */
256
+ type ChunkTypeToPartType<UI_MESSAGE extends UIMessage, CHUNK_TYPE extends string> = InferUIMessagePart<UI_MESSAGE> extends infer PART ? PART extends {
257
+ type: infer PT extends string;
258
+ } ? CHUNK_TYPE extends PartTypeToChunkTypes<UI_MESSAGE, PT> ? PT : never : never : never;
259
+ /**
260
+ * Extracts content chunk types (chunks that have a corresponding part type).
261
+ * Excludes meta chunks like 'start', 'finish', etc.
262
+ */
263
+ type ContentChunkType<UI_MESSAGE extends UIMessage> = { [CT in InferUIMessageChunkType<UI_MESSAGE>]: [ChunkTypeToPartType<UI_MESSAGE, CT>] extends [never] ? never : CT }[InferUIMessageChunkType<UI_MESSAGE>];
264
+ /**
265
+ * Distributing helper to collect all part types for chunk types.
266
+ * Distributes over union chunk types to get all corresponding part types.
267
+ */
268
+ type CollectPartTypesForChunk<UI_MESSAGE extends UIMessage, CHUNK_TYPE extends string> = CHUNK_TYPE extends string ? ChunkTypeToPartType<UI_MESSAGE, CHUNK_TYPE> : never;
269
+ /**
270
+ * Detects if any chunk type in the union is a meta chunk (has no corresponding part type).
271
+ * Returns `true` for meta chunks, `never` otherwise.
272
+ */
273
+ type HasMetaChunk<UI_MESSAGE extends UIMessage, CHUNK_TYPE extends string> = CHUNK_TYPE extends string ? [ChunkTypeToPartType<UI_MESSAGE, CHUNK_TYPE>] extends [never] ? true : never : never;
274
+ /**
275
+ * Infer part type from chunk type for .on() callback.
276
+ * Returns { type: PART_TYPE } for content chunks, undefined for meta chunks.
277
+ * For union chunk types, returns union of their part types.
278
+ * When mixing content and meta chunks, includes undefined in the union.
279
+ *
280
+ * @example
281
+ * ```typescript
282
+ * // Content chunk: part is { type: 'text' }
283
+ * type TextPart = InferPartForChunk<MyUIMessage, 'text-delta'>;
284
+ * // => { type: 'text' }
285
+ *
286
+ * // Meta chunk: part is undefined
287
+ * type MetaPart = InferPartForChunk<MyUIMessage, 'start'>;
288
+ * // => undefined
289
+ *
290
+ * // Union of content chunks: part type is union
291
+ * type UnionPart = InferPartForChunk<MyUIMessage, 'text-delta' | 'reasoning-delta'>;
292
+ * // => { type: 'text' | 'reasoning' }
293
+ *
294
+ * // Mixed content and meta chunks: includes undefined
295
+ * type MixedPart = InferPartForChunk<MyUIMessage, 'text-delta' | 'start'>;
296
+ * // => { type: 'text' } | undefined
297
+ * ```
298
+ */
299
+ type InferPartForChunk<UI_MESSAGE extends UIMessage, CHUNK_TYPE extends string> = [CollectPartTypesForChunk<UI_MESSAGE, CHUNK_TYPE>] extends [never] ? undefined : [HasMetaChunk<UI_MESSAGE, CHUNK_TYPE>] extends [never] ? {
300
+ type: CollectPartTypesForChunk<UI_MESSAGE, CHUNK_TYPE>;
301
+ } : {
302
+ type: CollectPartTypesForChunk<UI_MESSAGE, CHUNK_TYPE>;
303
+ } | undefined;
304
+ /**
305
+ * Computes which part types remain after excluding specific chunk types.
306
+ * A part type is excluded only if ALL its chunk types are excluded.
307
+ *
308
+ * @example
309
+ * ```typescript
310
+ * // Excluding 'text-delta' still leaves 'text-start' and 'text-end'
311
+ * // So 'text' part type is NOT excluded
312
+ * type RemainingParts = ExcludePartForChunks<MyUIMessage, 'text-delta'>;
313
+ * // => 'text' | 'reasoning' | ... (all part types)
314
+ *
315
+ * // Excluding all text chunks removes 'text' part type
316
+ * type RemainingParts2 = ExcludePartForChunks<MyUIMessage, 'text-start' | 'text-delta' | 'text-end'>;
317
+ * // => 'reasoning' | ... (all part types except 'text')
318
+ * ```
319
+ */
320
+ type ExcludePartForChunks<UI_MESSAGE extends UIMessage, EXCLUDED_CHUNK_TYPE extends string> = { [PT in InferUIMessagePartType<UI_MESSAGE>]: [Exclude<PartTypeToChunkTypes<UI_MESSAGE, PT>, EXCLUDED_CHUNK_TYPE>] extends [never] ? never : PT }[InferUIMessagePartType<UI_MESSAGE>];
321
+ //#endregion
322
+ //#region src/flat-map/flat-map-ui-message-stream.d.ts
181
323
  /**
182
324
  * Input object provided to the part flatMap function.
183
325
  */
@@ -277,7 +419,293 @@ declare function partTypeIs<UI_MESSAGE extends UIMessage, PART_TYPE extends Infe
277
419
  * );
278
420
  * ```
279
421
  */
280
- declare function flatMapUIMessageStream<UI_MESSAGE extends UIMessage, PART extends InferUIMessagePart<UI_MESSAGE>>(stream: ReadableStream<InferUIMessageChunk<UI_MESSAGE>>, predicate: FlatMapUIMessageStreamPredicate<UI_MESSAGE, PART>, flatMapFn: FlatMapUIMessageStreamFn<UI_MESSAGE, PART>): AsyncIterableStream<InferUIMessageChunk<UI_MESSAGE>>;
281
- declare function flatMapUIMessageStream<UI_MESSAGE extends UIMessage>(stream: ReadableStream<InferUIMessageChunk<UI_MESSAGE>>, flatMapFn: FlatMapUIMessageStreamFn<UI_MESSAGE>): AsyncIterableStream<InferUIMessageChunk<UI_MESSAGE>>;
422
+ declare function flatMapUIMessageStream<UI_MESSAGE extends UIMessage, PART extends InferUIMessagePart<UI_MESSAGE>>(stream: ReadableStream<InferUIMessageChunk<UI_MESSAGE>>, predicate: FlatMapUIMessageStreamPredicate<UI_MESSAGE, PART>, flatMapFn: FlatMapUIMessageStreamFn<UI_MESSAGE, PART>): AsyncIterableStream$1<InferUIMessageChunk<UI_MESSAGE>>;
423
+ declare function flatMapUIMessageStream<UI_MESSAGE extends UIMessage>(stream: ReadableStream<InferUIMessageChunk<UI_MESSAGE>>, flatMapFn: FlatMapUIMessageStreamFn<UI_MESSAGE>): AsyncIterableStream$1<InferUIMessageChunk<UI_MESSAGE>>;
424
+ //#endregion
425
+ //#region src/map/map-ui-message-stream.d.ts
426
+ /**
427
+ * Input object provided to the chunk map function.
428
+ */
429
+ type MapInput<UI_MESSAGE extends UIMessage> = {
430
+ /** The current chunk */chunk: InferUIMessageChunk<UI_MESSAGE>;
431
+ /**
432
+ * The assembled part this chunk belongs to (from readUIMessageStream).
433
+ * Use `part.type` to determine the part type.
434
+ */
435
+ part: InferUIMessagePart<UI_MESSAGE>;
436
+ };
437
+ /**
438
+ * Map function for chunk-level transformation.
439
+ * Return:
440
+ * - A single chunk (possibly transformed) to include it
441
+ * - An array of chunks to emit multiple chunks
442
+ * - An empty array or null to filter out the chunk
443
+ */
444
+ type MapUIMessageStreamFn<UI_MESSAGE extends UIMessage> = (input: MapInput<UI_MESSAGE>) => InferUIMessageChunk<UI_MESSAGE> | InferUIMessageChunk<UI_MESSAGE>[] | null;
445
+ /**
446
+ * Maps/filters a UIMessageStream at the chunk level using readUIMessageStream.
447
+ *
448
+ * This function processes each chunk as it arrives and allows you to:
449
+ * - Transform chunks by returning a modified chunk
450
+ * - Filter out chunks by returning null or an empty array
451
+ * - Emit multiple chunks by returning an array
452
+ *
453
+ * Meta chunks (start, finish, abort, message-metadata, error) always pass through.
454
+ * Step boundaries (start-step, finish-step) are handled automatically:
455
+ * - start-step is buffered and only emitted if subsequent content is included
456
+ * - finish-step is only emitted if the corresponding start-step was emitted
457
+ *
458
+ * @example
459
+ * ```typescript
460
+ * // Filter out reasoning chunks using part.type
461
+ * const stream = mapUIMessageStream(
462
+ * inputStream,
463
+ * ({ chunk, part }) => part.type === 'reasoning' ? null : chunk
464
+ * );
465
+ *
466
+ * // Transform text chunks
467
+ * const stream = mapUIMessageStream(
468
+ * inputStream,
469
+ * ({ chunk, part }) => {
470
+ * if (chunk.type === 'text-delta') {
471
+ * return { ...chunk, delta: chunk.delta.toUpperCase() };
472
+ * }
473
+ * return chunk;
474
+ * }
475
+ * );
476
+ *
477
+ * // Buffer text deltas and split into word-by-word chunks (smooth streaming)
478
+ * let buffer = '';
479
+ * let textStartChunk = null;
480
+ * const stream = mapUIMessageStream(
481
+ * inputStream,
482
+ * ({ chunk }) => {
483
+ * if (chunk.type === 'text-start') {
484
+ * textStartChunk = chunk;
485
+ * return []; // Buffer, don't emit yet
486
+ * }
487
+ * if (chunk.type === 'text-delta') {
488
+ * buffer += chunk.delta;
489
+ * return []; // Buffer, don't emit yet
490
+ * }
491
+ * if (chunk.type === 'text-end') {
492
+ * // Emit buffered content as word chunks
493
+ * const words = buffer.split(' ');
494
+ * const wordChunks = words.map((word, i) => ({
495
+ * type: 'text-delta' as const,
496
+ * id: chunk.id,
497
+ * delta: i === 0 ? word : ` ${word}`,
498
+ * }));
499
+ * buffer = '';
500
+ * const result = [...wordChunks, chunk];
501
+ * if (textStartChunk) {
502
+ * result.unshift(textStartChunk);
503
+ * textStartChunk = null;
504
+ * }
505
+ * return result;
506
+ * }
507
+ * return chunk;
508
+ * }
509
+ * );
510
+ * ```
511
+ */
512
+ declare function mapUIMessageStream<UI_MESSAGE extends UIMessage>(stream: ReadableStream<InferUIMessageChunk<UI_MESSAGE>>, mapFn: MapUIMessageStreamFn<UI_MESSAGE>): AsyncIterableStream$1<InferUIMessageChunk<UI_MESSAGE>>;
513
+ //#endregion
514
+ //#region src/pipe/chunk-pipeline.d.ts
515
+ /**
516
+ * Pipeline for chunk-based operations.
517
+ * Operations receive individual chunks with their associated part type.
518
+ */
519
+ declare class ChunkPipeline<UI_MESSAGE extends UIMessage, CHUNK extends InferUIMessageChunk<UI_MESSAGE>, PART extends {
520
+ type: string;
521
+ }> implements BasePipeline<UI_MESSAGE>, AsyncIterable<InferUIMessageChunk<UI_MESSAGE>> {
522
+ private consumed;
523
+ private sourceIterable;
524
+ private prevBuilder;
525
+ constructor(sourceIterable: AsyncIterable<InternalChunk<UI_MESSAGE>>, prevBuilder?: ChunkBuilder<UI_MESSAGE>);
526
+ private assertNotConsumed;
527
+ /**
528
+ * Filters chunks using a type guard and narrows both chunk and part types.
529
+ * Use with includeChunks(), includeParts(), excludeChunks(), or excludeParts().
530
+ * The callback only receives content chunks because meta chunks pass through unchanged.
531
+ */
532
+ filter<NARROWED_CHUNK extends InferUIMessageChunk<UI_MESSAGE>, NARROWED_PART extends {
533
+ type: string;
534
+ }>(guard: FilterGuard<UI_MESSAGE, NARROWED_CHUNK, NARROWED_PART>): ChunkPipeline<UI_MESSAGE, NARROWED_CHUNK, NARROWED_PART>;
535
+ /**
536
+ * Filters chunks using a generic predicate function.
537
+ * The callback only receives content chunks because meta chunks pass through unchanged.
538
+ */
539
+ filter(predicate: ChunkFilterFn<CHUNK & ExtractChunk<UI_MESSAGE, ContentChunkType<UI_MESSAGE>>, PART>): ChunkPipeline<UI_MESSAGE, CHUNK, PART>;
540
+ /**
541
+ * Transforms chunks by applying a mapping function.
542
+ * The callback only receives content chunks because meta chunks pass through unchanged.
543
+ * Returning null filters out the chunk, while returning an array yields multiple chunks.
544
+ */
545
+ map(fn: ChunkMapFn<UI_MESSAGE, CHUNK & ExtractChunk<UI_MESSAGE, ContentChunkType<UI_MESSAGE>>, PART>): ChunkPipeline<UI_MESSAGE, CHUNK, PART>;
546
+ /**
547
+ * Observes chunks matching a type guard without filtering them.
548
+ * The callback receives a narrowed chunk type and inferred part type.
549
+ * Content chunks include a part object with the type, while meta chunks have undefined part.
550
+ * All chunks pass through regardless of whether the callback is invoked.
551
+ */
552
+ on<NARROWED_CHUNK extends InferUIMessageChunk<UI_MESSAGE>, NARROWED_PART extends {
553
+ type: string;
554
+ } | undefined>(guard: ObserveGuard<UI_MESSAGE, NARROWED_CHUNK, NARROWED_PART>, callback: ChunkObserveFn<NARROWED_CHUNK, NARROWED_PART>): ChunkPipeline<UI_MESSAGE, CHUNK, PART>;
555
+ /**
556
+ * Observes chunks matching a predicate without filtering them.
557
+ * Uses the current pipeline types without type narrowing.
558
+ * All chunks pass through regardless of whether the callback is invoked.
559
+ */
560
+ on(predicate: (input: ChunkObserveInput<CHUNK>) => boolean, callback: ChunkObserveFn<CHUNK, {
561
+ type: PART[`type`];
562
+ } | undefined>): ChunkPipeline<UI_MESSAGE, CHUNK, PART>;
563
+ /**
564
+ * Executes the pipeline and returns the resulting stream.
565
+ * All chunks pass through including step boundaries and meta chunks.
566
+ */
567
+ toStream(): AsyncIterableStream$1<InferUIMessageChunk<UI_MESSAGE>>;
568
+ [Symbol.asyncIterator](): AsyncIterator<InferUIMessageChunk<UI_MESSAGE>>;
569
+ }
570
+ //#endregion
571
+ //#region src/pipe/pipe.d.ts
572
+ /**
573
+ * Input type for `pipe()` that accepts either a ReadableStream or an AsyncIterable.
574
+ */
575
+ type PipeInput<UI_MESSAGE extends UIMessage> = ReadableStream<InferUIMessageChunk<UI_MESSAGE>> | AsyncIterable<InferUIMessageChunk<UI_MESSAGE>>;
576
+ /**
577
+ * Creates a type-safe pipeline for UIMessageStream operations.
578
+ *
579
+ * @example
580
+ * ```typescript
581
+ * pipe<MyUIMessage>(stream)
582
+ * .filter(isPartType('text'))
583
+ * .map(({ chunk }) => chunk)
584
+ * .toStream();
585
+ * ```
586
+ */
587
+ declare function pipe<UI_MESSAGE extends UIMessage>(input: PipeInput<UI_MESSAGE>): ChunkPipeline<UI_MESSAGE, InferUIMessageChunk<UI_MESSAGE>, InferUIMessagePart<UI_MESSAGE>>;
588
+ //#endregion
589
+ //#region src/pipe/type-guards.d.ts
590
+ /**
591
+ * Creates a filter guard that includes specific content chunk types.
592
+ * Use with `.filter()` to narrow to specific chunks.
593
+ *
594
+ * @example
595
+ * ```typescript
596
+ * pipe<MyUIMessage>(stream)
597
+ * .filter(includeChunks('text-delta'))
598
+ * .map(({ chunk }) => chunk); // chunk is narrowed to text-delta chunk
599
+ *
600
+ * pipe<MyUIMessage>(stream)
601
+ * .filter(includeChunks(['text-delta', 'text-end']))
602
+ * .map(({ chunk }) => chunk); // chunk is narrowed to text-delta | text-end
603
+ * ```
604
+ */
605
+ declare function includeChunks<UI_MESSAGE extends UIMessage, CHUNK_TYPE extends ContentChunkType<UI_MESSAGE>>(types: CHUNK_TYPE | Array<CHUNK_TYPE>): FilterGuard<UI_MESSAGE, ExtractChunk<UI_MESSAGE, CHUNK_TYPE>, {
606
+ type: ChunkTypeToPartType<UI_MESSAGE, CHUNK_TYPE>;
607
+ }>;
608
+ /**
609
+ * Creates a filter guard that includes specific part types.
610
+ * Use with `.filter()` to narrow to chunks belonging to specific parts.
611
+ *
612
+ * @example
613
+ * ```typescript
614
+ * pipe<MyUIMessage>(stream)
615
+ * .filter(includeParts('text'))
616
+ * .map(({ chunk, part }) => chunk); // chunk is narrowed to text chunks
617
+ *
618
+ * pipe<MyUIMessage>(stream)
619
+ * .filter(includeParts(['text', 'reasoning']))
620
+ * .map(({ chunk }) => chunk); // chunk is text or reasoning chunks
621
+ * ```
622
+ */
623
+ declare function includeParts<UI_MESSAGE extends UIMessage, PART_TYPE extends InferUIMessagePartType<UI_MESSAGE>>(types: PART_TYPE | Array<PART_TYPE>): FilterGuard<UI_MESSAGE, ExtractChunkForPart<UI_MESSAGE, ExtractPart<UI_MESSAGE, PART_TYPE>>, {
624
+ type: PART_TYPE;
625
+ }>;
626
+ /**
627
+ * Creates a filter guard that excludes specific content chunk types.
628
+ * Use with `.filter()` to keep all chunks except the specified types.
629
+ *
630
+ * @example
631
+ * ```typescript
632
+ * pipe<MyUIMessage>(stream)
633
+ * .filter(excludeChunks('text-delta'))
634
+ * .map(({ chunk }) => chunk); // chunk is all content chunks except text-delta
635
+ *
636
+ * pipe<MyUIMessage>(stream)
637
+ * .filter(excludeChunks(['text-start', 'text-end']))
638
+ * .map(({ chunk }) => chunk); // excludes text-start and text-end
639
+ * ```
640
+ */
641
+ declare function excludeChunks<UI_MESSAGE extends UIMessage, CHUNK_TYPE extends ContentChunkType<UI_MESSAGE>>(types: CHUNK_TYPE | Array<CHUNK_TYPE>): FilterGuard<UI_MESSAGE, Exclude<ExtractChunk<UI_MESSAGE, ContentChunkType<UI_MESSAGE>>, ExtractChunk<UI_MESSAGE, CHUNK_TYPE>>, {
642
+ type: ExcludePartForChunks<UI_MESSAGE, CHUNK_TYPE>;
643
+ }>;
644
+ /**
645
+ * Creates a filter guard that excludes specific part types.
646
+ * Use with `.filter()` to keep all chunks except those belonging to specified parts.
647
+ *
648
+ * @example
649
+ * ```typescript
650
+ * pipe<MyUIMessage>(stream)
651
+ * .filter(excludeParts('text'))
652
+ * .map(({ chunk }) => chunk); // excludes all text chunks
653
+ *
654
+ * pipe<MyUIMessage>(stream)
655
+ * .filter(excludeParts(['text', 'reasoning']))
656
+ * .map(({ chunk }) => chunk); // excludes text and reasoning chunks
657
+ * ```
658
+ */
659
+ declare function excludeParts<UI_MESSAGE extends UIMessage, PART_TYPE extends InferUIMessagePartType<UI_MESSAGE>>(types: PART_TYPE | Array<PART_TYPE>): FilterGuard<UI_MESSAGE, Exclude<ExtractChunk<UI_MESSAGE, ContentChunkType<UI_MESSAGE>>, ExtractChunkForPart<UI_MESSAGE, ExtractPart<UI_MESSAGE, PART_TYPE>>>, {
660
+ type: Exclude<InferUIMessagePartType<UI_MESSAGE>, PART_TYPE>;
661
+ }>;
662
+ /**
663
+ * Creates an observe guard that matches specific chunk types, including meta chunks.
664
+ * Use with `.on()` to observe specific chunks without filtering.
665
+ *
666
+ * @example
667
+ * ```typescript
668
+ * // Observe content chunks
669
+ * pipe<MyUIMessage>(stream)
670
+ * .on(chunkType('text-delta'), ({ chunk, part }) => {
671
+ * // chunk is text-delta, part is { type: 'text' }
672
+ * });
673
+ *
674
+ * // Observe meta chunks
675
+ * pipe<MyUIMessage>(stream)
676
+ * .on(chunkType('start'), ({ chunk, part }) => {
677
+ * // chunk is start chunk, part is undefined
678
+ * });
679
+ *
680
+ * // Observe multiple chunk types
681
+ * pipe<MyUIMessage>(stream)
682
+ * .on(chunkType(['text-delta', 'start']), ({ chunk, part }) => {
683
+ * // chunk is text-delta | start, part is { type: 'text' } | undefined
684
+ * });
685
+ * ```
686
+ */
687
+ declare function chunkType<UI_MESSAGE extends UIMessage, CHUNK_TYPE extends InferUIMessageChunkType<UI_MESSAGE>>(types: CHUNK_TYPE | Array<CHUNK_TYPE>): ObserveGuard<UI_MESSAGE, ExtractChunk<UI_MESSAGE, CHUNK_TYPE>, InferPartForChunk<UI_MESSAGE, CHUNK_TYPE>>;
688
+ /**
689
+ * Creates an observe guard that matches specific part types.
690
+ * Use with `.on()` to observe chunks belonging to specific parts without filtering.
691
+ *
692
+ * @example
693
+ * ```typescript
694
+ * // Observe text parts
695
+ * pipe<MyUIMessage>(stream)
696
+ * .on(partType('text'), ({ chunk, part }) => {
697
+ * // chunk is text chunk, part is { type: 'text' }
698
+ * });
699
+ *
700
+ * // Observe multiple part types
701
+ * pipe<MyUIMessage>(stream)
702
+ * .on(partType(['text', 'reasoning']), ({ chunk, part }) => {
703
+ * // chunk is text | reasoning chunk, part is { type: 'text' | 'reasoning' }
704
+ * });
705
+ * ```
706
+ */
707
+ declare function partType<UI_MESSAGE extends UIMessage, PART_TYPE extends InferUIMessagePartType<UI_MESSAGE>>(types: PART_TYPE | Array<PART_TYPE>): ObserveGuard<UI_MESSAGE, ExtractChunkForPart<UI_MESSAGE, ExtractPart<UI_MESSAGE, PART_TYPE>>, {
708
+ type: PART_TYPE;
709
+ }>;
282
710
  //#endregion
283
- export { type FilterUIMessageStreamPredicate, type FlatMapContext, type FlatMapInput, type FlatMapUIMessageStreamFn, type FlatMapUIMessageStreamPredicate, type InferUIMessagePart, type InferUIMessagePartType, type MapInput, type MapUIMessageStreamFn, consumeUIMessageStream, excludeParts, filterUIMessageStream, flatMapUIMessageStream, includeParts, mapUIMessageStream, partTypeIs };
711
+ export { AsyncIterableStream, type FlatMapContext, type FlatMapInput, type FlatMapUIMessageStreamFn, type FlatMapUIMessageStreamPredicate, type MapInput, type MapUIMessageStreamFn, chunkType, consumeUIMessageStream, convertArrayToAsyncIterable, convertArrayToStream, convertAsyncIterableToArray, convertAsyncIterableToStream, convertSSEToUIMessageStream, convertStreamToArray, convertUIMessageToSSEStream, createAsyncIterableStream, excludeChunks, excludeParts, filterUIMessageStream, flatMapUIMessageStream, includeChunks, includeParts, mapUIMessageStream, partType, partTypeIs, pipe };