streamfold 0.1.4 → 0.1.6
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 +25 -0
- package/package.json +5 -1
- package/src/adapter.js +161 -0
- package/src/ag-ui.d.ts +6 -4
- package/src/ag-ui.js +17 -9
- package/src/anthropic.d.ts +6 -4
- package/src/anthropic.js +38 -24
- package/src/assistant-ui.d.ts +6 -4
- package/src/assistant-ui.js +29 -18
- package/src/gemini.d.ts +6 -4
- package/src/gemini.js +8 -5
- package/src/index.d.ts +141 -8
- package/src/index.js +89 -24
- package/src/internal/abortable-source.js +82 -0
- package/src/internal/diagnostics.js +9 -0
- package/src/internal/errors.js +14 -0
- package/src/internal/integration.js +105 -15
- package/src/internal/snapshots.js +58 -0
- package/src/internal/wasm-runtime.js +31 -5
- package/src/langchain.d.ts +6 -4
- package/src/langchain.js +8 -4
- package/src/openai.d.ts +6 -4
- package/src/openai.js +22 -15
- package/src/read-structured.js +74 -0
- package/src/testing.d.ts +13 -0
- package/src/testing.js +121 -0
- package/src/vercel-ai.d.ts +6 -4
- package/src/vercel-ai.js +34 -16
package/README.md
CHANGED
|
@@ -29,11 +29,36 @@ stream.finish();
|
|
|
29
29
|
stream.dispose();
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
Values are live by default. Use `createStructuredStream({ snapshots: "immutable" })`
|
|
33
|
+
for frozen snapshots that preserve earlier values and share unchanged branches.
|
|
34
|
+
Pools and custom adapter factories accept the same option; managed readers
|
|
35
|
+
forward it through `limits`.
|
|
36
|
+
|
|
32
37
|
Use `streamfold/assistant-ui`, `streamfold/vercel-ai`, `streamfold/openai`,
|
|
33
38
|
`streamfold/anthropic`, `streamfold/gemini`, `streamfold/langchain`, or
|
|
34
39
|
`streamfold/ag-ui` for decoded SDK events. Integrations use structural event
|
|
35
40
|
types and do not load provider SDKs.
|
|
36
41
|
|
|
42
|
+
For custom protocols, import `defineAdapter` from `streamfold`. Translate each
|
|
43
|
+
event into an array of `start`, `delta`, `end`, or `abort` operations. The returned
|
|
44
|
+
factory creates an independent session with `pushAll(event)`, `finish()`, and
|
|
45
|
+
`dispose()`. See the API reference for a complete switch-based example.
|
|
46
|
+
|
|
47
|
+
For automatic lifecycle management, use
|
|
48
|
+
`readStructured(events, { adapter, limits })` in a `for await` loop. It wraps the
|
|
49
|
+
same batch adapter, finalizes remaining calls at the end of the source, and
|
|
50
|
+
disposes on completion, failure, or early exit. `limits` is optional.
|
|
51
|
+
For a built-in SDK factory, use `{ integration: assistantUI, limits }` instead.
|
|
52
|
+
Both paths yield the same lifecycle updates without replaying completions.
|
|
53
|
+
|
|
54
|
+
Every built-in adapter supports `pushAll(event)`, returning all ordered
|
|
55
|
+
`start`, `update`, and `complete` updates, including multiple calls in one event.
|
|
56
|
+
Existing `push(event)` remains available. Call `finish()` at the stream boundary.
|
|
57
|
+
|
|
58
|
+
Pass `onDiagnostic` in a custom factory's options, as an SDK factory's second
|
|
59
|
+
argument, or beside the factory in `readStructured`. Errors preserve their
|
|
60
|
+
native categories and include structured codes and call context where known.
|
|
61
|
+
|
|
37
62
|
See the repository for the [API reference](https://github.com/assistant-ui/streamfold/blob/main/API.md),
|
|
38
63
|
[integration guide](https://github.com/assistant-ui/streamfold/blob/main/MIGRATION.md),
|
|
39
64
|
and [benchmarks](https://github.com/assistant-ui/streamfold#performance).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "streamfold",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Protocol-neutral incremental state for structured AI streams",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
"!src/**/*.test.js"
|
|
13
13
|
],
|
|
14
14
|
"exports": {
|
|
15
|
+
"./testing": {
|
|
16
|
+
"types": "./src/testing.d.ts",
|
|
17
|
+
"default": "./src/testing.js"
|
|
18
|
+
},
|
|
15
19
|
".": {
|
|
16
20
|
"types": "./src/index.d.ts",
|
|
17
21
|
"default": "./src/index.js"
|
package/src/adapter.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { createStructuredStreamPool } from "./index.js";
|
|
2
|
+
import {
|
|
3
|
+
annotateError,
|
|
4
|
+
isStructuredStreamError,
|
|
5
|
+
streamError,
|
|
6
|
+
} from "./internal/errors.js";
|
|
7
|
+
import { emitDiagnostic } from "./internal/diagnostics.js";
|
|
8
|
+
|
|
9
|
+
export function defineAdapter(mapEvent) {
|
|
10
|
+
if (typeof mapEvent !== "function") {
|
|
11
|
+
throw streamError(
|
|
12
|
+
new TypeError("An adapter mapper must be a function"),
|
|
13
|
+
"INVALID_OPTIONS",
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return (options) => {
|
|
18
|
+
const pool = createStructuredStreamPool(options);
|
|
19
|
+
let status = "active";
|
|
20
|
+
let failure;
|
|
21
|
+
let eventType;
|
|
22
|
+
let operationContext;
|
|
23
|
+
let receivedEvents = false;
|
|
24
|
+
let matched = false;
|
|
25
|
+
|
|
26
|
+
const diagnose = (diagnostic) =>
|
|
27
|
+
emitDiagnostic(options, { adapter: "custom", eventType, ...diagnostic });
|
|
28
|
+
const disposeActive = () => {
|
|
29
|
+
for (const id of pool.activeIds) pool.abort(id);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const fail = (error) => {
|
|
33
|
+
const original =
|
|
34
|
+
error instanceof Error
|
|
35
|
+
? error
|
|
36
|
+
: new Error("Adapter stream failed", { cause: error });
|
|
37
|
+
const context = { adapter: "custom", eventType };
|
|
38
|
+
failure = isStructuredStreamError(original)
|
|
39
|
+
? annotateError(original, context)
|
|
40
|
+
: streamError(original, "INTEGRATION_ERROR", {
|
|
41
|
+
...context,
|
|
42
|
+
...operationContext,
|
|
43
|
+
});
|
|
44
|
+
disposeActive();
|
|
45
|
+
diagnose({
|
|
46
|
+
code: "STREAM_ERROR",
|
|
47
|
+
message: failure.message,
|
|
48
|
+
error: failure,
|
|
49
|
+
id: failure.id,
|
|
50
|
+
});
|
|
51
|
+
return failure;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const assertActive = () => {
|
|
55
|
+
if (failure !== undefined) throw failure;
|
|
56
|
+
if (status !== "active") {
|
|
57
|
+
throw streamError(
|
|
58
|
+
new Error(`Adapter stream has been ${status}`),
|
|
59
|
+
status === "disposed" ? "STREAM_DISPOSED" : "INTEGRATION_ERROR",
|
|
60
|
+
{ adapter: "custom" },
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
pushAll(event) {
|
|
67
|
+
assertActive();
|
|
68
|
+
receivedEvents = true;
|
|
69
|
+
try {
|
|
70
|
+
const type = event?.type ?? event?.event_type ?? event?.kind;
|
|
71
|
+
eventType =
|
|
72
|
+
typeof type === "string"
|
|
73
|
+
? type
|
|
74
|
+
: Array.isArray(event)
|
|
75
|
+
? "operations"
|
|
76
|
+
: undefined;
|
|
77
|
+
const operations = mapEvent(event);
|
|
78
|
+
if (!Array.isArray(operations)) {
|
|
79
|
+
throw new TypeError("An adapter mapper must return an array");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const updates = [];
|
|
83
|
+
for (const operation of operations) {
|
|
84
|
+
operationContext = undefined;
|
|
85
|
+
if (
|
|
86
|
+
operation === null ||
|
|
87
|
+
typeof operation !== "object" ||
|
|
88
|
+
!("id" in operation)
|
|
89
|
+
) {
|
|
90
|
+
throw new TypeError("An adapter operation must include an id");
|
|
91
|
+
}
|
|
92
|
+
operationContext = { id: operation.id };
|
|
93
|
+
switch (operation.type) {
|
|
94
|
+
case "start":
|
|
95
|
+
operationContext.operation = "start";
|
|
96
|
+
updates.push({ type: "start", ...pool.start(operation.id) });
|
|
97
|
+
break;
|
|
98
|
+
case "delta":
|
|
99
|
+
operationContext.operation = "push";
|
|
100
|
+
if (typeof operation.text !== "string") {
|
|
101
|
+
throw new TypeError("An adapter delta must include text");
|
|
102
|
+
}
|
|
103
|
+
updates.push({
|
|
104
|
+
type: "update",
|
|
105
|
+
...pool.push(operation.id, operation.text),
|
|
106
|
+
});
|
|
107
|
+
break;
|
|
108
|
+
case "end":
|
|
109
|
+
operationContext.operation = "finish";
|
|
110
|
+
updates.push({
|
|
111
|
+
type: "complete",
|
|
112
|
+
...pool.finish(operation.id),
|
|
113
|
+
});
|
|
114
|
+
break;
|
|
115
|
+
case "abort":
|
|
116
|
+
pool.abort(operation.id);
|
|
117
|
+
break;
|
|
118
|
+
default:
|
|
119
|
+
throw new TypeError("Unknown adapter operation type");
|
|
120
|
+
}
|
|
121
|
+
matched = true;
|
|
122
|
+
}
|
|
123
|
+
return updates;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
throw fail(error);
|
|
126
|
+
} finally {
|
|
127
|
+
eventType = undefined;
|
|
128
|
+
operationContext = undefined;
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
finish() {
|
|
133
|
+
if (failure !== undefined) throw failure;
|
|
134
|
+
if (status === "finished") return [];
|
|
135
|
+
assertActive();
|
|
136
|
+
try {
|
|
137
|
+
const completed = pool.activeIds.map((id) => ({
|
|
138
|
+
type: "complete",
|
|
139
|
+
...pool.finish(id),
|
|
140
|
+
}));
|
|
141
|
+
status = "finished";
|
|
142
|
+
if (receivedEvents && !matched) {
|
|
143
|
+
diagnose({
|
|
144
|
+
code: "NO_TOOL_EVENTS",
|
|
145
|
+
message:
|
|
146
|
+
"No tool operations were mapped; text-only streams are valid, otherwise check the event mapper",
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return completed;
|
|
150
|
+
} catch (error) {
|
|
151
|
+
throw fail(error);
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
dispose() {
|
|
156
|
+
disposeActive();
|
|
157
|
+
if (status === "active") status = "disposed";
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
}
|
package/src/ag-ui.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
BatchEventStructuredStream,
|
|
3
|
+
BatchStructuredStreamIntegration,
|
|
4
|
+
StructuredStreamIntegrationOptions,
|
|
4
5
|
StructuredStreamPool,
|
|
5
6
|
} from "./index.js";
|
|
6
7
|
|
|
@@ -24,8 +25,9 @@ export type AgUiToolCallEvent =
|
|
|
24
25
|
readonly [key: string]: unknown;
|
|
25
26
|
};
|
|
26
27
|
|
|
27
|
-
export const agUI:
|
|
28
|
+
export const agUI: BatchStructuredStreamIntegration<AgUiToolCallEvent, string>;
|
|
28
29
|
|
|
29
30
|
export function createStructuredStream(
|
|
30
31
|
pool?: StructuredStreamPool<string>,
|
|
31
|
-
|
|
32
|
+
options?: StructuredStreamIntegrationOptions,
|
|
33
|
+
): BatchEventStructuredStream<AgUiToolCallEvent, string>;
|
package/src/ag-ui.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { createStructuredStreamPool } from "./index.js";
|
|
2
2
|
import { createIntegration } from "./internal/integration.js";
|
|
3
3
|
|
|
4
|
-
export const agUI = (pool = createStructuredStreamPool()) =>
|
|
5
|
-
createIntegration(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
export const agUI = (pool = createStructuredStreamPool(), options) =>
|
|
5
|
+
createIntegration(
|
|
6
|
+
pool,
|
|
7
|
+
(event, calls) => {
|
|
8
|
+
if (event.type === "TOOL_CALL_START")
|
|
9
|
+
return calls.start(event.toolCallId);
|
|
10
|
+
if (event.type === "TOOL_CALL_ARGS") {
|
|
11
|
+
return calls.push(event.toolCallId, event.delta);
|
|
12
|
+
}
|
|
13
|
+
if (event.type === "TOOL_CALL_END")
|
|
14
|
+
return calls.complete(event.toolCallId);
|
|
15
|
+
return undefined;
|
|
16
|
+
},
|
|
17
|
+
undefined,
|
|
18
|
+
"ag-ui",
|
|
19
|
+
options,
|
|
20
|
+
);
|
|
13
21
|
|
|
14
22
|
export { agUI as createStructuredStream };
|
package/src/anthropic.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
BatchEventStructuredStream,
|
|
3
|
+
BatchStructuredStreamIntegration,
|
|
4
|
+
StructuredStreamIntegrationOptions,
|
|
4
5
|
StructuredStreamPool,
|
|
5
6
|
} from "./index.js";
|
|
6
7
|
|
|
@@ -33,11 +34,12 @@ export type AnthropicToolInputEvent =
|
|
|
33
34
|
readonly [key: string]: unknown;
|
|
34
35
|
};
|
|
35
36
|
|
|
36
|
-
export const anthropic:
|
|
37
|
+
export const anthropic: BatchStructuredStreamIntegration<
|
|
37
38
|
AnthropicToolInputEvent,
|
|
38
39
|
string
|
|
39
40
|
>;
|
|
40
41
|
|
|
41
42
|
export function createStructuredStream(
|
|
42
43
|
pool?: StructuredStreamPool<string>,
|
|
43
|
-
|
|
44
|
+
options?: StructuredStreamIntegrationOptions,
|
|
45
|
+
): BatchEventStructuredStream<AnthropicToolInputEvent, string>;
|
package/src/anthropic.js
CHANGED
|
@@ -1,34 +1,48 @@
|
|
|
1
1
|
import { createStructuredStreamPool } from "./index.js";
|
|
2
2
|
import { createIntegration } from "./internal/integration.js";
|
|
3
3
|
|
|
4
|
-
export const anthropic = (pool = createStructuredStreamPool()) => {
|
|
4
|
+
export const anthropic = (pool = createStructuredStreamPool(), options) => {
|
|
5
5
|
const idsByIndex = new Map();
|
|
6
6
|
|
|
7
|
-
return createIntegration(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
(
|
|
11
|
-
event.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
return createIntegration(
|
|
8
|
+
pool,
|
|
9
|
+
(event, calls) => {
|
|
10
|
+
if (
|
|
11
|
+
event.type === "content_block_start" &&
|
|
12
|
+
(event.content_block.type === "tool_use" ||
|
|
13
|
+
event.content_block.type === "server_tool_use")
|
|
14
|
+
) {
|
|
15
|
+
idsByIndex.set(event.index, event.content_block.id);
|
|
16
|
+
return calls.start(event.content_block.id);
|
|
17
|
+
}
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
const id = idsByIndex.get(event.index);
|
|
20
|
+
if (id === undefined) {
|
|
21
|
+
if (
|
|
22
|
+
event.type === "content_block_delta" &&
|
|
23
|
+
event.delta.type === "input_json_delta"
|
|
24
|
+
) {
|
|
25
|
+
calls.unmatched("Arguments delta has no matching tool block index");
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
19
29
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
if (
|
|
31
|
+
event.type === "content_block_delta" &&
|
|
32
|
+
event.delta.type === "input_json_delta"
|
|
33
|
+
) {
|
|
34
|
+
return calls.push(id, event.delta.partial_json);
|
|
35
|
+
}
|
|
36
|
+
if (event.type === "content_block_stop") {
|
|
37
|
+
idsByIndex.delete(event.index);
|
|
38
|
+
return calls.complete(id);
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
},
|
|
42
|
+
undefined,
|
|
43
|
+
"anthropic",
|
|
44
|
+
options,
|
|
45
|
+
);
|
|
32
46
|
};
|
|
33
47
|
|
|
34
48
|
export { anthropic as createStructuredStream };
|
package/src/assistant-ui.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
BatchEventStructuredStream,
|
|
3
|
+
BatchStructuredStreamIntegration,
|
|
4
|
+
StructuredStreamIntegrationOptions,
|
|
4
5
|
StructuredStreamPool,
|
|
5
6
|
} from "./index.js";
|
|
6
7
|
|
|
@@ -31,11 +32,12 @@ export type AssistantUiStreamEvent =
|
|
|
31
32
|
readonly [key: string]: unknown;
|
|
32
33
|
};
|
|
33
34
|
|
|
34
|
-
export const assistantUI:
|
|
35
|
+
export const assistantUI: BatchStructuredStreamIntegration<
|
|
35
36
|
AssistantUiStreamEvent,
|
|
36
37
|
string
|
|
37
38
|
>;
|
|
38
39
|
|
|
39
40
|
export function createStructuredStream(
|
|
40
41
|
pool?: StructuredStreamPool<string>,
|
|
41
|
-
|
|
42
|
+
options?: StructuredStreamIntegrationOptions,
|
|
43
|
+
): BatchEventStructuredStream<AssistantUiStreamEvent, string>;
|
package/src/assistant-ui.js
CHANGED
|
@@ -3,29 +3,40 @@ import { createIntegration } from "./internal/integration.js";
|
|
|
3
3
|
|
|
4
4
|
const pathKey = (path) => path.join("/");
|
|
5
5
|
|
|
6
|
-
export const assistantUI = (pool = createStructuredStreamPool()) => {
|
|
6
|
+
export const assistantUI = (pool = createStructuredStreamPool(), options) => {
|
|
7
7
|
const idsByPath = new Map();
|
|
8
8
|
|
|
9
|
-
return createIntegration(
|
|
10
|
-
|
|
9
|
+
return createIntegration(
|
|
10
|
+
pool,
|
|
11
|
+
(event, calls) => {
|
|
12
|
+
const key = pathKey(event.path);
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
if (event.type === "part-start" && event.part.type === "tool-call") {
|
|
15
|
+
idsByPath.set(key, event.part.toolCallId);
|
|
16
|
+
return calls.start(event.part.toolCallId);
|
|
17
|
+
}
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
const id = idsByPath.get(key);
|
|
20
|
+
if (id === undefined) {
|
|
21
|
+
if (event.type === "tool-call-args-text-finish") {
|
|
22
|
+
calls.unmatched("Tool completion has no matching part path");
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
19
26
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
if (event.type === "text-delta") {
|
|
28
|
+
return calls.push(id, event.textDelta);
|
|
29
|
+
}
|
|
30
|
+
if (event.type === "tool-call-args-text-finish") {
|
|
31
|
+
idsByPath.delete(key);
|
|
32
|
+
return calls.complete(id);
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
},
|
|
36
|
+
undefined,
|
|
37
|
+
"assistant-ui",
|
|
38
|
+
options,
|
|
39
|
+
);
|
|
29
40
|
};
|
|
30
41
|
|
|
31
42
|
export { assistantUI as createStructuredStream };
|
package/src/gemini.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
BatchEventStructuredStream,
|
|
3
|
+
BatchStructuredStreamIntegration,
|
|
4
|
+
StructuredStreamIntegrationOptions,
|
|
4
5
|
StructuredStreamPool,
|
|
5
6
|
} from "./index.js";
|
|
6
7
|
|
|
@@ -32,11 +33,12 @@ export type GeminiToolCallEvent =
|
|
|
32
33
|
readonly [key: string]: unknown;
|
|
33
34
|
};
|
|
34
35
|
|
|
35
|
-
export const gemini:
|
|
36
|
+
export const gemini: BatchStructuredStreamIntegration<
|
|
36
37
|
GeminiToolCallEvent,
|
|
37
38
|
string
|
|
38
39
|
>;
|
|
39
40
|
|
|
40
41
|
export function createStructuredStream(
|
|
41
42
|
pool?: StructuredStreamPool<string>,
|
|
42
|
-
|
|
43
|
+
options?: StructuredStreamIntegrationOptions,
|
|
44
|
+
): BatchEventStructuredStream<GeminiToolCallEvent, string>;
|
package/src/gemini.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createStructuredStreamPool } from "./index.js";
|
|
2
2
|
import { createIntegration } from "./internal/integration.js";
|
|
3
3
|
|
|
4
|
-
export const gemini = (pool = createStructuredStreamPool()) => {
|
|
4
|
+
export const gemini = (pool = createStructuredStreamPool(), options) => {
|
|
5
5
|
const idsByIndex = new Map();
|
|
6
6
|
|
|
7
7
|
return createIntegration(
|
|
8
8
|
pool,
|
|
9
|
-
(event,
|
|
9
|
+
(event, calls) => {
|
|
10
10
|
if (
|
|
11
11
|
event.event_type === "step.start" &&
|
|
12
12
|
event.step.type === "function_call"
|
|
@@ -18,7 +18,7 @@ export const gemini = (pool = createStructuredStreamPool()) => {
|
|
|
18
18
|
: event.step.arguments
|
|
19
19
|
? JSON.stringify(event.step.arguments)
|
|
20
20
|
: "";
|
|
21
|
-
return
|
|
21
|
+
return calls.start(event.step.id, initial);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
if (
|
|
@@ -27,15 +27,16 @@ export const gemini = (pool = createStructuredStreamPool()) => {
|
|
|
27
27
|
) {
|
|
28
28
|
const id = idsByIndex.get(event.index);
|
|
29
29
|
if (id !== undefined) {
|
|
30
|
-
return
|
|
30
|
+
return calls.push(id, event.delta.partial_arguments);
|
|
31
31
|
}
|
|
32
|
+
calls.unmatched("Arguments delta has no matching function call index");
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
if (
|
|
35
36
|
event.event_type === "interaction.completed" ||
|
|
36
37
|
event.event_type === "interaction.complete"
|
|
37
38
|
) {
|
|
38
|
-
for (const id of idsByIndex.values()) complete(id);
|
|
39
|
+
for (const id of idsByIndex.values()) calls.complete(id);
|
|
39
40
|
idsByIndex.clear();
|
|
40
41
|
}
|
|
41
42
|
return undefined;
|
|
@@ -44,6 +45,8 @@ export const gemini = (pool = createStructuredStreamPool()) => {
|
|
|
44
45
|
for (const id of idsByIndex.values()) complete(id);
|
|
45
46
|
idsByIndex.clear();
|
|
46
47
|
},
|
|
48
|
+
"gemini",
|
|
49
|
+
options,
|
|
47
50
|
);
|
|
48
51
|
};
|
|
49
52
|
|