ai-stream-utils 2.1.0 → 2.3.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 +75 -4
- package/dist/index.d.mts +115 -5
- package/dist/index.mjs +86 -1
- package/dist/{types-B4nePmEd.d.mts → types-CNApJ39t.d.mts} +2 -2
- package/dist/utils/index.d.mts +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -145,6 +145,31 @@ const stream = pipe(result.toUIMessageStream())
|
|
|
145
145
|
.toStream();
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
+
#### Helpers
|
|
149
|
+
|
|
150
|
+
`transformProviderMetadata()` changes `providerMetadata` on the chunks that carry it (`text-*`, `reasoning-*`, `tool-input-*`, `source-*`, `file`). Every other chunk passes through untouched, so you don't have to narrow by chunk type yourself.
|
|
151
|
+
|
|
152
|
+
The callback receives the current `metadata` (may be `undefined`) and returns one of three things:
|
|
153
|
+
|
|
154
|
+
- an **object** to set/replace the metadata (merge by spreading `metadata`)
|
|
155
|
+
- **`undefined`** to leave the chunk unchanged
|
|
156
|
+
- **`null`** to remove the `providerMetadata` field entirely (the chunk still passes through)
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
const stream = pipe(result.toUIMessageStream())
|
|
160
|
+
.map(
|
|
161
|
+
transformProviderMetadata(({ chunk, part, metadata }) => {
|
|
162
|
+
if (chunk.type === "tool-input-available")
|
|
163
|
+
return { ...metadata, app: { toolCallId: chunk.toolCallId } }; // add to tool input chunks
|
|
164
|
+
|
|
165
|
+
if (part.type === "text") return null; // delete for text parts
|
|
166
|
+
|
|
167
|
+
return undefined; // leave everything else unchanged
|
|
168
|
+
}),
|
|
169
|
+
)
|
|
170
|
+
.toStream();
|
|
171
|
+
```
|
|
172
|
+
|
|
148
173
|
### `.on()`
|
|
149
174
|
|
|
150
175
|
Observe chunks without modifying the stream. The callback is invoked for matching chunks.
|
|
@@ -152,11 +177,13 @@ Observe chunks without modifying the stream. The callback is invoked for matchin
|
|
|
152
177
|
```typescript
|
|
153
178
|
const stream = pipe(result.toUIMessageStream())
|
|
154
179
|
.on(
|
|
155
|
-
(
|
|
180
|
+
(predicate) => {
|
|
181
|
+
const { chunk, part } = predicate;
|
|
156
182
|
// return true to invoke callback, false to skip
|
|
157
183
|
return chunk.type === "text-delta";
|
|
158
184
|
},
|
|
159
|
-
(
|
|
185
|
+
(callback) => {
|
|
186
|
+
const { chunk, part } = callback;
|
|
160
187
|
// callback invoked for matching chunks
|
|
161
188
|
console.log(chunk, part);
|
|
162
189
|
},
|
|
@@ -170,10 +197,19 @@ const stream = pipe(result.toUIMessageStream())
|
|
|
170
197
|
|
|
171
198
|
- `chunkType("text-delta")` or `chunkType(["start", "finish"])`: Observe specific chunk types
|
|
172
199
|
- `partType("text")` or `partType(["text", "reasoning"])`: Observe chunks belonging to specific part types
|
|
200
|
+
- `toolCall()` or `toolCall({ tool: "weather" })` or `toolCall({ state: "output-available" })`: Observe tool state transitions
|
|
173
201
|
|
|
174
202
|
> [!NOTE]
|
|
175
203
|
> The `partType` type guard still operates on chunks. That means `partType("text")` will match any text chunks such as `text-start`, `text-delta`, and `text-end`.
|
|
176
204
|
|
|
205
|
+
The `toolCall()` type guard matches tool chunks representing state transitions (not streaming events):
|
|
206
|
+
|
|
207
|
+
- `input-available`: Tool input fully parsed
|
|
208
|
+
- `approval-requested`: Tool awaiting user approval
|
|
209
|
+
- `output-available`: Tool execution completed
|
|
210
|
+
- `output-error`: Tool execution failed
|
|
211
|
+
- `output-denied`: User denied approval
|
|
212
|
+
|
|
177
213
|
#### Examples
|
|
178
214
|
|
|
179
215
|
Log stream lifecycle events.
|
|
@@ -187,10 +223,45 @@ const stream = pipe(result.toUIMessageStream())
|
|
|
187
223
|
console.log("Stream finished:", chunk.finishReason);
|
|
188
224
|
})
|
|
189
225
|
.on(chunkType("tool-input-available"), ({ chunk }) => {
|
|
190
|
-
console.log("Tool input:", chunk.
|
|
226
|
+
console.log("Tool input:", chunk.input);
|
|
191
227
|
})
|
|
192
228
|
.on(chunkType("tool-output-available"), ({ chunk }) => {
|
|
193
|
-
console.log("Tool output:", chunk.
|
|
229
|
+
console.log("Tool output:", chunk.output);
|
|
230
|
+
})
|
|
231
|
+
.toStream();
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Observe tool state transitions for a specific tool.
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
const stream = pipe(result.toUIMessageStream())
|
|
238
|
+
.on(toolCall({ tool: "weather", state: "approval-requested" }), ({ chunk }) => {
|
|
239
|
+
console.log("Weather tool needs approval");
|
|
240
|
+
})
|
|
241
|
+
.on(toolCall({ tool: "weather", state: "output-available" }), ({ chunk }) => {
|
|
242
|
+
console.log("Weather output:", chunk.output);
|
|
243
|
+
})
|
|
244
|
+
.on(toolCall({ tool: "weather", state: "input-available" }), ({ chunk }) => {
|
|
245
|
+
console.log("Weather input:", chunk.input);
|
|
246
|
+
})
|
|
247
|
+
.toStream();
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Observe all tool calls.
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
const stream = pipe(result.toUIMessageStream())
|
|
254
|
+
// on
|
|
255
|
+
.on(toolCall({ state: `input-available` }), ({ chunk, part }) => {
|
|
256
|
+
console.log(`Tool call ${part.type} (${chunk.toolCallId}) input=`, chunk.input);
|
|
257
|
+
})
|
|
258
|
+
/** onResult */
|
|
259
|
+
.on(toolCall({ state: `output-available` }), ({ chunk, part }) => {
|
|
260
|
+
console.log(`Tool result ${part.type} (${chunk.toolCallId}) output=`, chunk.output);
|
|
261
|
+
})
|
|
262
|
+
/** onError */
|
|
263
|
+
.on(toolCall({ state: `output-error` }), ({ chunk, part }) => {
|
|
264
|
+
console.log(`Tool error ${part.type} (${chunk.toolCallId}) error=`, chunk.errorText);
|
|
194
265
|
})
|
|
195
266
|
.toStream();
|
|
196
267
|
```
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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-
|
|
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-CNApJ39t.mjs";
|
|
2
2
|
import "./utils/index.mjs";
|
|
3
|
-
import { AsyncIterableStream as AsyncIterableStream$1, InferUIMessageChunk, UIDataTypes, UIMessage, UITools } from "ai";
|
|
3
|
+
import { AsyncIterableStream as AsyncIterableStream$1, InferUIMessageChunk, ProviderMetadata, UIDataTypes, UIMessage, UITools } from "ai";
|
|
4
4
|
|
|
5
5
|
//#region src/consume/consume-ui-message-stream.d.ts
|
|
6
6
|
/**
|
|
@@ -345,6 +345,21 @@ type ToolChunkTypes<UI_MESSAGE extends UIMessage> = Extract<InferUIMessageChunkT
|
|
|
345
345
|
* Content chunk types remaining after excluding all tool chunks.
|
|
346
346
|
*/
|
|
347
347
|
type ExcludeToolChunkTypes<UI_MESSAGE extends UIMessage> = Exclude<ContentChunkType<UI_MESSAGE>, ToolChunkTypes<UI_MESSAGE>>;
|
|
348
|
+
/**
|
|
349
|
+
* Tool states that have corresponding stream chunks.
|
|
350
|
+
* These are the "final" states from UIToolInvocation, not streaming events.
|
|
351
|
+
*/
|
|
352
|
+
type ToolCallState = "input-available" | "approval-requested" | "output-available" | "output-error" | "output-denied";
|
|
353
|
+
/**
|
|
354
|
+
* Map tool states to their corresponding chunk types.
|
|
355
|
+
*/
|
|
356
|
+
type ToolStateToChunkType = {
|
|
357
|
+
"input-available": "tool-input-available";
|
|
358
|
+
"approval-requested": "tool-approval-request";
|
|
359
|
+
"output-available": "tool-output-available";
|
|
360
|
+
"output-error": "tool-output-error";
|
|
361
|
+
"output-denied": "tool-output-denied";
|
|
362
|
+
};
|
|
348
363
|
//#endregion
|
|
349
364
|
//#region src/flat-map/flat-map-ui-message-stream.d.ts
|
|
350
365
|
/**
|
|
@@ -538,6 +553,48 @@ type MapUIMessageStreamFn<UI_MESSAGE extends UIMessage> = (input: MapInput<UI_ME
|
|
|
538
553
|
*/
|
|
539
554
|
declare function mapUIMessageStream<UI_MESSAGE extends UIMessage>(stream: ReadableStream<InferUIMessageChunk<UI_MESSAGE>>, mapFn: MapUIMessageStreamFn<UI_MESSAGE>): AsyncIterableStream$1<InferUIMessageChunk<UI_MESSAGE>>;
|
|
540
555
|
//#endregion
|
|
556
|
+
//#region src/pipe/transform-provider-metadata.d.ts
|
|
557
|
+
/**
|
|
558
|
+
* A composable helper that plugs into the `.map()` operator to change provider
|
|
559
|
+
* metadata on the chunks that carry it:
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* ```typescript
|
|
563
|
+
* pipe<MyUIMessage>(stream)
|
|
564
|
+
* .map(transformProviderMetadata(({ metadata }) => ({ ...metadata, app: { id } })))
|
|
565
|
+
* .toStream();
|
|
566
|
+
* ```
|
|
567
|
+
*/
|
|
568
|
+
/**
|
|
569
|
+
* Chunk variants in UI_MESSAGE that actually carry a `providerMetadata` field.
|
|
570
|
+
* Optional keys are still present in `keyof`, so this discriminates correctly:
|
|
571
|
+
* variants without the field (error, tool-output-*, start, finish, ...) drop to never.
|
|
572
|
+
*/
|
|
573
|
+
type ProviderMetadataChunk<UI_MESSAGE extends UIMessage> = InferUIMessageChunk<UI_MESSAGE> extends infer CHUNK ? CHUNK extends unknown ? "providerMetadata" extends keyof CHUNK ? CHUNK : never : never : never;
|
|
574
|
+
/**
|
|
575
|
+
* Mapper invoked for every metadata-bearing chunk. Receives the chunk, its part
|
|
576
|
+
* type, and the current `providerMetadata` (may be undefined). Return value:
|
|
577
|
+
* - an object to set/replace `providerMetadata` (merge by spreading `metadata`)
|
|
578
|
+
* - `undefined` to leave the chunk unchanged
|
|
579
|
+
* - `null` to remove the `providerMetadata` field entirely
|
|
580
|
+
*
|
|
581
|
+
* `null` removes the field, not the chunk: the chunk always passes through.
|
|
582
|
+
*/
|
|
583
|
+
type ProviderMetadataTransformFn<UI_MESSAGE extends UIMessage> = (input: {
|
|
584
|
+
chunk: ProviderMetadataChunk<UI_MESSAGE>;
|
|
585
|
+
part: {
|
|
586
|
+
type: string;
|
|
587
|
+
};
|
|
588
|
+
metadata: ProviderMetadata | undefined;
|
|
589
|
+
}) => ProviderMetadata | null | undefined;
|
|
590
|
+
/**
|
|
591
|
+
* Creates a `.map()` callback that rewrites `providerMetadata` on metadata-bearing
|
|
592
|
+
* chunks and passes every other chunk through unchanged.
|
|
593
|
+
*/
|
|
594
|
+
declare function transformProviderMetadata<UI_MESSAGE extends UIMessage>(fn: ProviderMetadataTransformFn<UI_MESSAGE>): ChunkMapFn<UI_MESSAGE, InferUIMessageChunk<UI_MESSAGE>, {
|
|
595
|
+
type: string;
|
|
596
|
+
}>;
|
|
597
|
+
//#endregion
|
|
541
598
|
//#region src/pipe/chunk-pipeline.d.ts
|
|
542
599
|
/**
|
|
543
600
|
* Pipeline for chunk-based operations.
|
|
@@ -576,8 +633,8 @@ declare class ChunkPipeline<UI_MESSAGE extends UIMessage, CHUNK extends InferUIM
|
|
|
576
633
|
* Content chunks include a part object with the type, while meta chunks have undefined part.
|
|
577
634
|
* All chunks pass through regardless of whether the callback is invoked.
|
|
578
635
|
*/
|
|
579
|
-
on<NARROWED_CHUNK extends
|
|
580
|
-
type:
|
|
636
|
+
on<NARROWED_CHUNK extends InferUIMessageChunk<UI_MESSAGE>, NARROWED_PART extends {
|
|
637
|
+
type: string;
|
|
581
638
|
} | undefined>(guard: ObserveGuard<UI_MESSAGE, NARROWED_CHUNK, NARROWED_PART>, callback: ChunkObserveFn<NARROWED_CHUNK, NARROWED_PART>): ChunkPipeline<UI_MESSAGE, CHUNK, PART>;
|
|
582
639
|
/**
|
|
583
640
|
* Observes chunks matching a predicate without filtering them.
|
|
@@ -790,5 +847,58 @@ declare function excludeTools<UI_MESSAGE extends UIMessage>(): FilterGuard<UI_ME
|
|
|
790
847
|
declare function excludeTools<UI_MESSAGE extends UIMessage, TOOL_NAME extends InferToolName<UI_MESSAGE>>(toolNames: TOOL_NAME | Array<TOOL_NAME>): FilterGuard<UI_MESSAGE, InferUIMessageChunk<UI_MESSAGE>, {
|
|
791
848
|
type: Exclude<InferUIMessagePartType<UI_MESSAGE>, `tool-${TOOL_NAME}`>;
|
|
792
849
|
}>;
|
|
850
|
+
/**
|
|
851
|
+
* Creates an observe guard that matches tool call chunks by tool name and/or state.
|
|
852
|
+
* Use with `.on()` to observe tool call state transitions without filtering.
|
|
853
|
+
*
|
|
854
|
+
* @example
|
|
855
|
+
* ```typescript
|
|
856
|
+
* // Match all tool state transitions (any tool, any state)
|
|
857
|
+
* pipe<MyUIMessage>(stream)
|
|
858
|
+
* .on(toolCall(), ({ chunk, part }) => {
|
|
859
|
+
* // Observes: tool-input-available, tool-approval-request,
|
|
860
|
+
* // tool-output-available, tool-output-error, tool-output-denied
|
|
861
|
+
* });
|
|
862
|
+
*
|
|
863
|
+
* // Match specific tool (any state)
|
|
864
|
+
* pipe<MyUIMessage>(stream)
|
|
865
|
+
* .on(toolCall({ tool: "weather" }), ({ chunk, part }) => {
|
|
866
|
+
* // part.type is 'tool-weather'
|
|
867
|
+
* });
|
|
868
|
+
*
|
|
869
|
+
* // Match specific state (all tools)
|
|
870
|
+
* pipe<MyUIMessage>(stream)
|
|
871
|
+
* .on(toolCall({ state: "output-available" }), ({ chunk, part }) => {
|
|
872
|
+
* // chunk.type is 'tool-output-available'
|
|
873
|
+
* });
|
|
874
|
+
*
|
|
875
|
+
* // Match specific tool AND state
|
|
876
|
+
* pipe<MyUIMessage>(stream)
|
|
877
|
+
* .on(toolCall({ tool: "weather", state: "output-available" }), ({ chunk, part }) => {
|
|
878
|
+
* // chunk.type is 'tool-output-available', part.type is 'tool-weather'
|
|
879
|
+
* });
|
|
880
|
+
* ```
|
|
881
|
+
*/
|
|
882
|
+
declare function toolCall<UI_MESSAGE extends UIMessage>(): ObserveGuard<UI_MESSAGE, ExtractChunk<UI_MESSAGE, ToolStateToChunkType[ToolCallState]>, {
|
|
883
|
+
type: `tool-${InferToolName<UI_MESSAGE>}` | "dynamic-tool";
|
|
884
|
+
}>;
|
|
885
|
+
declare function toolCall<UI_MESSAGE extends UIMessage, TOOL_NAME extends InferToolName<UI_MESSAGE>, STATE extends ToolCallState>(options: {
|
|
886
|
+
tool: TOOL_NAME;
|
|
887
|
+
state: STATE;
|
|
888
|
+
}): ObserveGuard<UI_MESSAGE, ExtractChunk<UI_MESSAGE, ToolStateToChunkType[STATE]>, {
|
|
889
|
+
type: `tool-${TOOL_NAME}`;
|
|
890
|
+
}>;
|
|
891
|
+
declare function toolCall<UI_MESSAGE extends UIMessage, TOOL_NAME extends InferToolName<UI_MESSAGE>>(options: {
|
|
892
|
+
tool: TOOL_NAME;
|
|
893
|
+
state?: undefined;
|
|
894
|
+
}): ObserveGuard<UI_MESSAGE, ExtractChunk<UI_MESSAGE, ToolStateToChunkType[ToolCallState]>, {
|
|
895
|
+
type: `tool-${TOOL_NAME}`;
|
|
896
|
+
}>;
|
|
897
|
+
declare function toolCall<UI_MESSAGE extends UIMessage, STATE extends ToolCallState>(options: {
|
|
898
|
+
tool?: undefined;
|
|
899
|
+
state: STATE;
|
|
900
|
+
}): ObserveGuard<UI_MESSAGE, ExtractChunk<UI_MESSAGE, ToolStateToChunkType[STATE]>, {
|
|
901
|
+
type: `tool-${InferToolName<UI_MESSAGE>}` | "dynamic-tool";
|
|
902
|
+
}>;
|
|
793
903
|
//#endregion
|
|
794
|
-
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, excludeTools, filterUIMessageStream, flatMapUIMessageStream, includeChunks, includeParts, includeTools, mapUIMessageStream, partType, partTypeIs, pipe };
|
|
904
|
+
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, excludeTools, filterUIMessageStream, flatMapUIMessageStream, includeChunks, includeParts, includeTools, mapUIMessageStream, partType, partTypeIs, pipe, toolCall, transformProviderMetadata };
|
package/dist/index.mjs
CHANGED
|
@@ -606,6 +606,62 @@ function flatMapUIMessageStream(...args) {
|
|
|
606
606
|
return createAsyncIterableStream(convertAsyncIterableToStream(processChunks()));
|
|
607
607
|
}
|
|
608
608
|
|
|
609
|
+
//#endregion
|
|
610
|
+
//#region src/pipe/transform-provider-metadata.ts
|
|
611
|
+
/**
|
|
612
|
+
* Runtime allow-list whose keys are pinned to `ProviderMetadataChunkType` by the
|
|
613
|
+
* compiler. The AI SDK does not expose its zod chunk union for runtime
|
|
614
|
+
* introspection (`uiMessageChunkSchema` is an async, non-introspectable `Schema`
|
|
615
|
+
* wrapper), so completeness is enforced at the type level instead: if the SDK
|
|
616
|
+
* adds or removes a metadata-bearing chunk, `ProviderMetadataChunkType` changes
|
|
617
|
+
* and this literal stops compiling (missing key, or unknown key) until updated.
|
|
618
|
+
*/
|
|
619
|
+
const PROVIDER_METADATA_CHUNK_TYPES = {
|
|
620
|
+
"text-start": true,
|
|
621
|
+
"text-delta": true,
|
|
622
|
+
"text-end": true,
|
|
623
|
+
"reasoning-start": true,
|
|
624
|
+
"reasoning-delta": true,
|
|
625
|
+
"reasoning-end": true,
|
|
626
|
+
"tool-input-start": true,
|
|
627
|
+
"tool-input-available": true,
|
|
628
|
+
"tool-input-error": true,
|
|
629
|
+
"source-url": true,
|
|
630
|
+
"source-document": true,
|
|
631
|
+
file: true
|
|
632
|
+
};
|
|
633
|
+
/** Narrows any chunk to the metadata-bearing union via the pinned allow-list. */
|
|
634
|
+
function isProviderMetadataChunk(chunk) {
|
|
635
|
+
return Object.hasOwn(PROVIDER_METADATA_CHUNK_TYPES, chunk.type);
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Creates a `.map()` callback that rewrites `providerMetadata` on metadata-bearing
|
|
639
|
+
* chunks and passes every other chunk through unchanged.
|
|
640
|
+
*/
|
|
641
|
+
function transformProviderMetadata(fn) {
|
|
642
|
+
return ({ chunk, part }) => {
|
|
643
|
+
if (!isProviderMetadataChunk(chunk)) return chunk;
|
|
644
|
+
const metadata = chunk.providerMetadata;
|
|
645
|
+
const next = fn({
|
|
646
|
+
chunk,
|
|
647
|
+
part,
|
|
648
|
+
metadata
|
|
649
|
+
});
|
|
650
|
+
/** undefined leaves the chunk unchanged. */
|
|
651
|
+
if (next === void 0) return chunk;
|
|
652
|
+
/** null removes the field while keeping the chunk. */
|
|
653
|
+
if (next === null) {
|
|
654
|
+
const { providerMetadata: _omit, ...rest } = chunk;
|
|
655
|
+
return rest;
|
|
656
|
+
}
|
|
657
|
+
/** an object sets/replaces the field. */
|
|
658
|
+
return {
|
|
659
|
+
...chunk,
|
|
660
|
+
providerMetadata: next
|
|
661
|
+
};
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
|
|
609
665
|
//#endregion
|
|
610
666
|
//#region src/pipe/chunk-pipeline.ts
|
|
611
667
|
/**
|
|
@@ -937,6 +993,35 @@ function excludeTools(toolNames) {
|
|
|
937
993
|
};
|
|
938
994
|
return guard;
|
|
939
995
|
}
|
|
996
|
+
/**
|
|
997
|
+
* Reverse mapping from chunk type to state.
|
|
998
|
+
*/
|
|
999
|
+
const chunkTypeToState = Object.fromEntries(Object.entries({
|
|
1000
|
+
"input-available": "tool-input-available",
|
|
1001
|
+
"approval-requested": "tool-approval-request",
|
|
1002
|
+
"output-available": "tool-output-available",
|
|
1003
|
+
"output-error": "tool-output-error",
|
|
1004
|
+
"output-denied": "tool-output-denied"
|
|
1005
|
+
}).map(([state, chunkType]) => [chunkType, state]));
|
|
1006
|
+
function toolCall(options) {
|
|
1007
|
+
const toolName = options?.tool;
|
|
1008
|
+
const state = options?.state;
|
|
1009
|
+
const guard = (input) => {
|
|
1010
|
+
const chunkType = input.chunk.type;
|
|
1011
|
+
const partType = input.part?.type;
|
|
1012
|
+
/** Must be a tool chunk type that maps to a state */
|
|
1013
|
+
const matchingState = chunkTypeToState[chunkType];
|
|
1014
|
+
if (!matchingState) return false;
|
|
1015
|
+
/** Check state match */
|
|
1016
|
+
if (state && matchingState !== state) return false;
|
|
1017
|
+
/** Check tool name match */
|
|
1018
|
+
if (toolName && partType) {
|
|
1019
|
+
if (partType !== `tool-${toolName}`) return false;
|
|
1020
|
+
}
|
|
1021
|
+
return true;
|
|
1022
|
+
};
|
|
1023
|
+
return guard;
|
|
1024
|
+
}
|
|
940
1025
|
|
|
941
1026
|
//#endregion
|
|
942
|
-
export { chunkType, consumeUIMessageStream, convertArrayToAsyncIterable, convertArrayToStream, convertAsyncIterableToArray, convertAsyncIterableToStream, convertSSEToUIMessageStream, convertStreamToArray, convertUIMessageToSSEStream, createAsyncIterableStream, excludeChunks, excludeParts, excludeTools, filterUIMessageStream, flatMapUIMessageStream, includeChunks, includeParts, includeTools, mapUIMessageStream, partType, partTypeIs, pipe };
|
|
1027
|
+
export { chunkType, consumeUIMessageStream, convertArrayToAsyncIterable, convertArrayToStream, convertAsyncIterableToArray, convertAsyncIterableToStream, convertSSEToUIMessageStream, convertStreamToArray, convertUIMessageToSSEStream, createAsyncIterableStream, excludeChunks, excludeParts, excludeTools, filterUIMessageStream, flatMapUIMessageStream, includeChunks, includeParts, includeTools, mapUIMessageStream, partType, partTypeIs, pipe, toolCall, transformProviderMetadata };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AsyncIterableStream, AsyncIterableStream as AsyncIterableStream$1, UIMessageChunk } from "ai";
|
|
1
|
+
import { AsyncIterableStream, AsyncIterableStream as AsyncIterableStream$1, InferUIMessageChunk, UIMessage, UIMessageChunk } from "ai";
|
|
2
2
|
|
|
3
3
|
//#region src/utils/convert-array-to-async-iterable.d.ts
|
|
4
4
|
/**
|
|
@@ -29,7 +29,7 @@ declare function convertAsyncIterableToStream<T>(iterable: AsyncIterable<T>): Re
|
|
|
29
29
|
/**
|
|
30
30
|
* Converts an SSE stream to a UI message stream.
|
|
31
31
|
*/
|
|
32
|
-
declare function convertSSEToUIMessageStream(stream: ReadableStream<string>): ReadableStream<
|
|
32
|
+
declare function convertSSEToUIMessageStream<UI_MESSAGE extends UIMessage = UIMessage>(stream: ReadableStream<string>): ReadableStream<InferUIMessageChunk<UI_MESSAGE>>;
|
|
33
33
|
//#endregion
|
|
34
34
|
//#region src/utils/convert-stream-to-array.d.ts
|
|
35
35
|
/**
|
package/dist/utils/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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-
|
|
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-CNApJ39t.mjs";
|
|
2
2
|
export { type AsyncIterableStream, convertArrayToAsyncIterable, convertArrayToStream, convertAsyncIterableToArray, convertAsyncIterableToStream, convertSSEToUIMessageStream, convertStreamToArray, convertUIMessageToSSEStream, createAsyncIterableStream };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-stream-utils",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "AI SDK: Filter and transform UI messages while streaming to the client",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -41,10 +41,12 @@
|
|
|
41
41
|
"@ai-sdk/openai": "^3.0.29",
|
|
42
42
|
"@ai-sdk/provider": "^3.0.8",
|
|
43
43
|
"@ai-sdk/provider-utils": "^4.0.15",
|
|
44
|
+
"@ai-sdk/react": "^3.0.110",
|
|
44
45
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
45
46
|
"@total-typescript/tsconfig": "^1.0.4",
|
|
46
47
|
"@types/node": "^25.2.3",
|
|
47
48
|
"ai": "^6.0.86",
|
|
49
|
+
"dotenv": "^17.4.2",
|
|
48
50
|
"husky": "^9.1.7",
|
|
49
51
|
"lint-staged": "^16.2.7",
|
|
50
52
|
"msw": "^2.12.10",
|