ai-stream-utils 2.1.0 → 2.2.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 +22 -0
- package/dist/index.d.mts +72 -4
- package/dist/index.mjs +30 -1
- package/dist/{types-B4nePmEd.d.mts → types-CNApJ39t.d.mts} +2 -2
- package/dist/utils/index.d.mts +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -170,6 +170,15 @@ const stream = pipe(result.toUIMessageStream())
|
|
|
170
170
|
|
|
171
171
|
- `chunkType("text-delta")` or `chunkType(["start", "finish"])`: Observe specific chunk types
|
|
172
172
|
- `partType("text")` or `partType(["text", "reasoning"])`: Observe chunks belonging to specific part types
|
|
173
|
+
- `toolCall()` or `toolCall({ tool: "weather" })` or `toolCall({ state: "output-available" })`: Observe tool state transitions
|
|
174
|
+
|
|
175
|
+
The `toolCall()` guard matches tool chunks representing state transitions (not streaming events):
|
|
176
|
+
|
|
177
|
+
- `input-available`: Tool input fully parsed
|
|
178
|
+
- `approval-requested`: Tool awaiting user approval
|
|
179
|
+
- `output-available`: Tool execution completed
|
|
180
|
+
- `output-error`: Tool execution failed
|
|
181
|
+
- `output-denied`: User denied approval
|
|
173
182
|
|
|
174
183
|
> [!NOTE]
|
|
175
184
|
> 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`.
|
|
@@ -195,6 +204,19 @@ const stream = pipe(result.toUIMessageStream())
|
|
|
195
204
|
.toStream();
|
|
196
205
|
```
|
|
197
206
|
|
|
207
|
+
Observe tool state transitions.
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
const stream = pipe(result.toUIMessageStream())
|
|
211
|
+
.on(toolCall({ tool: "weather", state: "approval-requested" }), ({ chunk }) => {
|
|
212
|
+
console.log("Weather tool needs approval");
|
|
213
|
+
})
|
|
214
|
+
.toStream();
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
> [!NOTE]
|
|
218
|
+
> The `tool` option filters by part type (`tool-{name}`). Dynamic tools have part type `dynamic-tool`, so `toolCall({ tool: "myTool" })` will not match dynamic tools. Use `toolCall()` without the `tool` option to observe all tools including dynamic ones.
|
|
219
|
+
|
|
198
220
|
### `.toStream()`
|
|
199
221
|
|
|
200
222
|
Convert the pipeline back to a `AsyncIterableStream<InferUIMessageChunk<UI_MESSAGE>>` that can be returned to the client or consumed.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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
3
|
import { AsyncIterableStream as AsyncIterableStream$1, InferUIMessageChunk, UIDataTypes, UIMessage, UITools } from "ai";
|
|
4
4
|
|
|
@@ -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
|
/**
|
|
@@ -576,8 +591,8 @@ declare class ChunkPipeline<UI_MESSAGE extends UIMessage, CHUNK extends InferUIM
|
|
|
576
591
|
* Content chunks include a part object with the type, while meta chunks have undefined part.
|
|
577
592
|
* All chunks pass through regardless of whether the callback is invoked.
|
|
578
593
|
*/
|
|
579
|
-
on<NARROWED_CHUNK extends
|
|
580
|
-
type:
|
|
594
|
+
on<NARROWED_CHUNK extends InferUIMessageChunk<UI_MESSAGE>, NARROWED_PART extends {
|
|
595
|
+
type: string;
|
|
581
596
|
} | undefined>(guard: ObserveGuard<UI_MESSAGE, NARROWED_CHUNK, NARROWED_PART>, callback: ChunkObserveFn<NARROWED_CHUNK, NARROWED_PART>): ChunkPipeline<UI_MESSAGE, CHUNK, PART>;
|
|
582
597
|
/**
|
|
583
598
|
* Observes chunks matching a predicate without filtering them.
|
|
@@ -790,5 +805,58 @@ declare function excludeTools<UI_MESSAGE extends UIMessage>(): FilterGuard<UI_ME
|
|
|
790
805
|
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
806
|
type: Exclude<InferUIMessagePartType<UI_MESSAGE>, `tool-${TOOL_NAME}`>;
|
|
792
807
|
}>;
|
|
808
|
+
/**
|
|
809
|
+
* Creates an observe guard that matches tool call chunks by tool name and/or state.
|
|
810
|
+
* Use with `.on()` to observe tool call state transitions without filtering.
|
|
811
|
+
*
|
|
812
|
+
* @example
|
|
813
|
+
* ```typescript
|
|
814
|
+
* // Match all tool state transitions (any tool, any state)
|
|
815
|
+
* pipe<MyUIMessage>(stream)
|
|
816
|
+
* .on(toolCall(), ({ chunk, part }) => {
|
|
817
|
+
* // Observes: tool-input-available, tool-approval-request,
|
|
818
|
+
* // tool-output-available, tool-output-error, tool-output-denied
|
|
819
|
+
* });
|
|
820
|
+
*
|
|
821
|
+
* // Match specific tool (any state)
|
|
822
|
+
* pipe<MyUIMessage>(stream)
|
|
823
|
+
* .on(toolCall({ tool: "weather" }), ({ chunk, part }) => {
|
|
824
|
+
* // part.type is 'tool-weather'
|
|
825
|
+
* });
|
|
826
|
+
*
|
|
827
|
+
* // Match specific state (all tools)
|
|
828
|
+
* pipe<MyUIMessage>(stream)
|
|
829
|
+
* .on(toolCall({ state: "output-available" }), ({ chunk, part }) => {
|
|
830
|
+
* // chunk.type is 'tool-output-available'
|
|
831
|
+
* });
|
|
832
|
+
*
|
|
833
|
+
* // Match specific tool AND state
|
|
834
|
+
* pipe<MyUIMessage>(stream)
|
|
835
|
+
* .on(toolCall({ tool: "weather", state: "output-available" }), ({ chunk, part }) => {
|
|
836
|
+
* // chunk.type is 'tool-output-available', part.type is 'tool-weather'
|
|
837
|
+
* });
|
|
838
|
+
* ```
|
|
839
|
+
*/
|
|
840
|
+
declare function toolCall<UI_MESSAGE extends UIMessage>(): ObserveGuard<UI_MESSAGE, ExtractChunk<UI_MESSAGE, ToolStateToChunkType[ToolCallState]>, {
|
|
841
|
+
type: `tool-${InferToolName<UI_MESSAGE>}` | "dynamic-tool";
|
|
842
|
+
}>;
|
|
843
|
+
declare function toolCall<UI_MESSAGE extends UIMessage, TOOL_NAME extends InferToolName<UI_MESSAGE>, STATE extends ToolCallState>(options: {
|
|
844
|
+
tool: TOOL_NAME;
|
|
845
|
+
state: STATE;
|
|
846
|
+
}): ObserveGuard<UI_MESSAGE, ExtractChunk<UI_MESSAGE, ToolStateToChunkType[STATE]>, {
|
|
847
|
+
type: `tool-${TOOL_NAME}`;
|
|
848
|
+
}>;
|
|
849
|
+
declare function toolCall<UI_MESSAGE extends UIMessage, TOOL_NAME extends InferToolName<UI_MESSAGE>>(options: {
|
|
850
|
+
tool: TOOL_NAME;
|
|
851
|
+
state?: undefined;
|
|
852
|
+
}): ObserveGuard<UI_MESSAGE, ExtractChunk<UI_MESSAGE, ToolStateToChunkType[ToolCallState]>, {
|
|
853
|
+
type: `tool-${TOOL_NAME}`;
|
|
854
|
+
}>;
|
|
855
|
+
declare function toolCall<UI_MESSAGE extends UIMessage, STATE extends ToolCallState>(options: {
|
|
856
|
+
tool?: undefined;
|
|
857
|
+
state: STATE;
|
|
858
|
+
}): ObserveGuard<UI_MESSAGE, ExtractChunk<UI_MESSAGE, ToolStateToChunkType[STATE]>, {
|
|
859
|
+
type: `tool-${InferToolName<UI_MESSAGE>}` | "dynamic-tool";
|
|
860
|
+
}>;
|
|
793
861
|
//#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 };
|
|
862
|
+
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 };
|
package/dist/index.mjs
CHANGED
|
@@ -937,6 +937,35 @@ function excludeTools(toolNames) {
|
|
|
937
937
|
};
|
|
938
938
|
return guard;
|
|
939
939
|
}
|
|
940
|
+
/**
|
|
941
|
+
* Reverse mapping from chunk type to state.
|
|
942
|
+
*/
|
|
943
|
+
const chunkTypeToState = Object.fromEntries(Object.entries({
|
|
944
|
+
"input-available": "tool-input-available",
|
|
945
|
+
"approval-requested": "tool-approval-request",
|
|
946
|
+
"output-available": "tool-output-available",
|
|
947
|
+
"output-error": "tool-output-error",
|
|
948
|
+
"output-denied": "tool-output-denied"
|
|
949
|
+
}).map(([state, chunkType]) => [chunkType, state]));
|
|
950
|
+
function toolCall(options) {
|
|
951
|
+
const toolName = options?.tool;
|
|
952
|
+
const state = options?.state;
|
|
953
|
+
const guard = (input) => {
|
|
954
|
+
const chunkType = input.chunk.type;
|
|
955
|
+
const partType = input.part?.type;
|
|
956
|
+
/** Must be a tool chunk type that maps to a state */
|
|
957
|
+
const matchingState = chunkTypeToState[chunkType];
|
|
958
|
+
if (!matchingState) return false;
|
|
959
|
+
/** Check state match */
|
|
960
|
+
if (state && matchingState !== state) return false;
|
|
961
|
+
/** Check tool name match */
|
|
962
|
+
if (toolName && partType) {
|
|
963
|
+
if (partType !== `tool-${toolName}`) return false;
|
|
964
|
+
}
|
|
965
|
+
return true;
|
|
966
|
+
};
|
|
967
|
+
return guard;
|
|
968
|
+
}
|
|
940
969
|
|
|
941
970
|
//#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 };
|
|
971
|
+
export { chunkType, consumeUIMessageStream, convertArrayToAsyncIterable, convertArrayToStream, convertAsyncIterableToArray, convertAsyncIterableToStream, convertSSEToUIMessageStream, convertStreamToArray, convertUIMessageToSSEStream, createAsyncIterableStream, excludeChunks, excludeParts, excludeTools, filterUIMessageStream, flatMapUIMessageStream, includeChunks, includeParts, includeTools, mapUIMessageStream, partType, partTypeIs, pipe, toolCall };
|
|
@@ -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.2.0",
|
|
4
4
|
"description": "AI SDK: Filter and transform UI messages while streaming to the client",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -41,6 +41,7 @@
|
|
|
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",
|