@ai-sdk/rsc 3.0.122 → 3.0.123
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/CHANGELOG.md +14 -0
- package/dist/index.d.ts +250 -254
- package/dist/index.d.ts.map +1 -0
- package/dist/rsc-client.d.ts +2 -1
- package/dist/rsc-client.js +2 -18
- package/dist/rsc-server.d.ts +213 -213
- package/dist/rsc-server.d.ts.map +1 -0
- package/dist/rsc-server.js +573 -715
- package/dist/rsc-server.js.map +1 -1
- package/dist/rsc-shared.d.ts +33 -35
- package/dist/rsc-shared.d.ts.map +1 -0
- package/dist/rsc-shared.js +246 -286
- package/dist/rsc-shared.js.map +1 -1
- package/package.json +6 -7
- package/dist/index.js +0 -0
- package/dist/rsc-client.js.map +0 -1
package/dist/rsc-server.js
CHANGED
|
@@ -1,748 +1,606 @@
|
|
|
1
|
-
// src/ai-state.tsx
|
|
2
1
|
import * as jsondiffpatch from "jsondiffpatch";
|
|
3
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Suspense } from "react";
|
|
5
|
+
import { InternalAIProvider } from "./rsc-shared.js";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { safeParseJSON } from "@ai-sdk/provider-utils";
|
|
8
|
+
import { InvalidToolInputError, NoSuchToolError } from "ai";
|
|
9
|
+
import { asLanguageModelUsage, convertToLanguageModelPrompt, prepareLanguageModelCallOptions, prepareRetries, prepareToolChoice, prepareTools, standardizePrompt } from "ai/internal";
|
|
10
|
+
//#region src/util/create-resolvable-promise.ts
|
|
11
|
+
/**
|
|
12
|
+
* Creates a Promise with externally accessible resolve and reject functions.
|
|
13
|
+
*
|
|
14
|
+
* @template T - The type of the value that the Promise will resolve to.
|
|
15
|
+
* @returns An object containing:
|
|
16
|
+
* - promise: A Promise that can be resolved or rejected externally.
|
|
17
|
+
* - resolve: A function to resolve the Promise with a value of type T.
|
|
18
|
+
* - reject: A function to reject the Promise with an error.
|
|
19
|
+
*/
|
|
6
20
|
function createResolvablePromise() {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
};
|
|
21
|
+
let resolve;
|
|
22
|
+
let reject;
|
|
23
|
+
return {
|
|
24
|
+
promise: new Promise((res, rej) => {
|
|
25
|
+
resolve = res;
|
|
26
|
+
reject = rej;
|
|
27
|
+
}),
|
|
28
|
+
resolve,
|
|
29
|
+
reject
|
|
30
|
+
};
|
|
18
31
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/util/is-function.ts
|
|
34
|
+
/**
|
|
35
|
+
* Checks if the given value is a function.
|
|
36
|
+
*
|
|
37
|
+
* @param {unknown} value - The value to check.
|
|
38
|
+
* @returns {boolean} True if the value is a function, false otherwise.
|
|
39
|
+
*/
|
|
40
|
+
const isFunction = (value) => typeof value === "function";
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/ai-state.tsx
|
|
43
|
+
const asyncAIStateStorage = new AsyncLocalStorage();
|
|
25
44
|
function getAIStateStoreOrThrow(message) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
return store;
|
|
45
|
+
const store = asyncAIStateStorage.getStore();
|
|
46
|
+
if (!store) throw new Error(message);
|
|
47
|
+
return store;
|
|
31
48
|
}
|
|
32
49
|
function withAIState({ state, options }, fn) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
options
|
|
40
|
-
},
|
|
41
|
-
fn
|
|
42
|
-
);
|
|
50
|
+
return asyncAIStateStorage.run({
|
|
51
|
+
currentState: JSON.parse(JSON.stringify(state)),
|
|
52
|
+
originalState: state,
|
|
53
|
+
sealed: false,
|
|
54
|
+
options
|
|
55
|
+
}, fn);
|
|
43
56
|
}
|
|
44
57
|
function getAIStateDeltaPromise() {
|
|
45
|
-
|
|
46
|
-
return store.mutationDeltaPromise;
|
|
58
|
+
return getAIStateStoreOrThrow("Internal error occurred.").mutationDeltaPromise;
|
|
47
59
|
}
|
|
48
60
|
function sealMutableAIState() {
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
const store = getAIStateStoreOrThrow("Internal error occurred.");
|
|
62
|
+
store.sealed = true;
|
|
51
63
|
}
|
|
52
64
|
function getAIState(...args) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
`You can't get the "${String(
|
|
61
|
-
key
|
|
62
|
-
)}" field from the AI state because it's not an object.`
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
return store.currentState[key];
|
|
66
|
-
}
|
|
67
|
-
return store.currentState;
|
|
65
|
+
const store = getAIStateStoreOrThrow("`getAIState` must be called within an AI Action.");
|
|
66
|
+
if (args.length > 0) {
|
|
67
|
+
const key = args[0];
|
|
68
|
+
if (typeof store.currentState !== "object") throw new Error(`You can't get the "${String(key)}" field from the AI state because it's not an object.`);
|
|
69
|
+
return store.currentState[key];
|
|
70
|
+
}
|
|
71
|
+
return store.currentState;
|
|
68
72
|
}
|
|
69
73
|
function getMutableAIState(...args) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const mutableState = {
|
|
114
|
-
get: () => {
|
|
115
|
-
if (args.length > 0) {
|
|
116
|
-
const key = args[0];
|
|
117
|
-
if (typeof store.currentState !== "object") {
|
|
118
|
-
throw new Error(
|
|
119
|
-
`You can't get the "${String(
|
|
120
|
-
key
|
|
121
|
-
)}" field from the AI state because it's not an object.`
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
return store.currentState[key];
|
|
125
|
-
}
|
|
126
|
-
return store.currentState;
|
|
127
|
-
},
|
|
128
|
-
update: function update(newAIState) {
|
|
129
|
-
doUpdate(newAIState, false);
|
|
130
|
-
},
|
|
131
|
-
done: function done(...doneArgs) {
|
|
132
|
-
if (doneArgs.length > 0) {
|
|
133
|
-
doUpdate(doneArgs[0], true);
|
|
134
|
-
}
|
|
135
|
-
const delta = jsondiffpatch.diff(store.originalState, store.currentState);
|
|
136
|
-
store.mutationDeltaResolve(delta);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
return mutableState;
|
|
74
|
+
const store = getAIStateStoreOrThrow("`getMutableAIState` must be called within an AI Action.");
|
|
75
|
+
if (store.sealed) throw new Error("`getMutableAIState` must be called before returning from an AI Action. Please move it to the top level of the Action's function body.");
|
|
76
|
+
if (!store.mutationDeltaPromise) {
|
|
77
|
+
const { promise, resolve } = createResolvablePromise();
|
|
78
|
+
store.mutationDeltaPromise = promise;
|
|
79
|
+
store.mutationDeltaResolve = resolve;
|
|
80
|
+
}
|
|
81
|
+
function doUpdate(newState, done) {
|
|
82
|
+
if (args.length > 0) {
|
|
83
|
+
if (typeof store.currentState !== "object") {
|
|
84
|
+
const key = args[0];
|
|
85
|
+
throw new Error(`You can't modify the "${String(key)}" field of the AI state because it's not an object.`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (isFunction(newState)) {
|
|
89
|
+
if (args.length > 0) store.currentState[args[0]] = newState(store.currentState[args[0]]);
|
|
90
|
+
else store.currentState = newState(store.currentState);
|
|
91
|
+
} else if (args.length > 0) store.currentState[args[0]] = newState;
|
|
92
|
+
else store.currentState = newState;
|
|
93
|
+
store.options.onSetAIState?.({
|
|
94
|
+
key: args.length > 0 ? args[0] : void 0,
|
|
95
|
+
state: store.currentState,
|
|
96
|
+
done
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
get: () => {
|
|
101
|
+
if (args.length > 0) {
|
|
102
|
+
const key = args[0];
|
|
103
|
+
if (typeof store.currentState !== "object") throw new Error(`You can't get the "${String(key)}" field from the AI state because it's not an object.`);
|
|
104
|
+
return store.currentState[key];
|
|
105
|
+
}
|
|
106
|
+
return store.currentState;
|
|
107
|
+
},
|
|
108
|
+
update: function update(newAIState) {
|
|
109
|
+
doUpdate(newAIState, false);
|
|
110
|
+
},
|
|
111
|
+
done: function done(...doneArgs) {
|
|
112
|
+
if (doneArgs.length > 0) doUpdate(doneArgs[0], true);
|
|
113
|
+
const delta = jsondiffpatch.diff(store.originalState, store.currentState);
|
|
114
|
+
store.mutationDeltaResolve(delta);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
140
117
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
state,
|
|
154
|
-
options
|
|
155
|
-
},
|
|
156
|
-
async () => {
|
|
157
|
-
const result = await action(...args);
|
|
158
|
-
sealMutableAIState();
|
|
159
|
-
return [getAIStateDeltaPromise(), result];
|
|
160
|
-
}
|
|
161
|
-
);
|
|
118
|
+
//#endregion
|
|
119
|
+
//#region src/provider.tsx
|
|
120
|
+
async function innerAction({ action, options }, state, ...args) {
|
|
121
|
+
"use server";
|
|
122
|
+
return await withAIState({
|
|
123
|
+
state,
|
|
124
|
+
options
|
|
125
|
+
}, async () => {
|
|
126
|
+
const result = await action(...args);
|
|
127
|
+
sealMutableAIState();
|
|
128
|
+
return [getAIStateDeltaPromise(), result];
|
|
129
|
+
});
|
|
162
130
|
}
|
|
163
131
|
function wrapAction(action, options) {
|
|
164
|
-
|
|
132
|
+
return innerAction.bind(null, {
|
|
133
|
+
action,
|
|
134
|
+
options
|
|
135
|
+
});
|
|
165
136
|
}
|
|
166
|
-
function createAI({
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
aiStateDelta = newAIStateDelta;
|
|
193
|
-
uiState = newUIState;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return /* @__PURE__ */ jsx(
|
|
197
|
-
InternalAIProvider,
|
|
198
|
-
{
|
|
199
|
-
wrappedActions,
|
|
200
|
-
wrappedSyncUIState,
|
|
201
|
-
initialUIState: uiState,
|
|
202
|
-
initialAIState: aiState,
|
|
203
|
-
initialAIStatePatch: aiStateDelta,
|
|
204
|
-
children: props.children
|
|
205
|
-
}
|
|
206
|
-
);
|
|
207
|
-
};
|
|
208
|
-
return AI;
|
|
137
|
+
function createAI({ actions, initialAIState, initialUIState, onSetAIState, onGetUIState }) {
|
|
138
|
+
const wrappedActions = {};
|
|
139
|
+
for (const name in actions) wrappedActions[name] = wrapAction(actions[name], { onSetAIState });
|
|
140
|
+
const wrappedSyncUIState = onGetUIState ? wrapAction(onGetUIState, {}) : void 0;
|
|
141
|
+
const AI = async (props) => {
|
|
142
|
+
if ("useState" in React) throw new Error("This component can only be used inside Server Components.");
|
|
143
|
+
let uiState = props.initialUIState ?? initialUIState;
|
|
144
|
+
let aiState = props.initialAIState ?? initialAIState;
|
|
145
|
+
let aiStateDelta = void 0;
|
|
146
|
+
if (wrappedSyncUIState) {
|
|
147
|
+
const [newAIStateDelta, newUIState] = await wrappedSyncUIState(aiState);
|
|
148
|
+
if (newUIState !== void 0) {
|
|
149
|
+
aiStateDelta = newAIStateDelta;
|
|
150
|
+
uiState = newUIState;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return /* @__PURE__ */ jsx(InternalAIProvider, {
|
|
154
|
+
wrappedActions,
|
|
155
|
+
wrappedSyncUIState,
|
|
156
|
+
initialUIState: uiState,
|
|
157
|
+
initialAIState: aiState,
|
|
158
|
+
initialAIStatePatch: aiStateDelta,
|
|
159
|
+
children: props.children
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
return AI;
|
|
209
163
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
250
|
-
return /* @__PURE__ */ jsx2(Suspense, { fallback: chunk.value, children: /* @__PURE__ */ jsx2(R, { c: chunk.value, n: chunk.next }) });
|
|
251
|
-
}
|
|
252
|
-
][0];
|
|
164
|
+
//#endregion
|
|
165
|
+
//#region src/util/constants.ts
|
|
166
|
+
/**
|
|
167
|
+
* Warning time for notifying developers that a stream is hanging in dev mode
|
|
168
|
+
* using a console.warn.
|
|
169
|
+
*/
|
|
170
|
+
const HANGING_STREAM_WARNING_TIME_MS = 15e3;
|
|
171
|
+
//#endregion
|
|
172
|
+
//#region src/streamable-ui/create-suspended-chunk.tsx
|
|
173
|
+
const R = [(async ({ c: current, n: next }) => {
|
|
174
|
+
const chunk = await next;
|
|
175
|
+
if (chunk.done) return chunk.value;
|
|
176
|
+
if (chunk.append) return /* @__PURE__ */ jsxs(Fragment, { children: [current, /* @__PURE__ */ jsx(Suspense, {
|
|
177
|
+
fallback: chunk.value,
|
|
178
|
+
children: /* @__PURE__ */ jsx(R, {
|
|
179
|
+
c: chunk.value,
|
|
180
|
+
n: chunk.next
|
|
181
|
+
})
|
|
182
|
+
})] });
|
|
183
|
+
return /* @__PURE__ */ jsx(Suspense, {
|
|
184
|
+
fallback: chunk.value,
|
|
185
|
+
children: /* @__PURE__ */ jsx(R, {
|
|
186
|
+
c: chunk.value,
|
|
187
|
+
n: chunk.next
|
|
188
|
+
})
|
|
189
|
+
});
|
|
190
|
+
})][0];
|
|
191
|
+
/**
|
|
192
|
+
* Creates a suspended chunk for React Server Components.
|
|
193
|
+
*
|
|
194
|
+
* This function generates a suspenseful React component that can be dynamically updated.
|
|
195
|
+
* It's useful for streaming updates to the client in a React Server Components context.
|
|
196
|
+
*
|
|
197
|
+
* @param {React.ReactNode} initialValue - The initial value to render while the promise is pending.
|
|
198
|
+
* @returns {Object} An object containing:
|
|
199
|
+
* - row: A React node that renders the suspenseful content.
|
|
200
|
+
* - resolve: A function to resolve the promise with a new value.
|
|
201
|
+
* - reject: A function to reject the promise with an error.
|
|
202
|
+
*/
|
|
253
203
|
function createSuspendedChunk(initialValue) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
204
|
+
const { promise, resolve, reject } = createResolvablePromise();
|
|
205
|
+
return {
|
|
206
|
+
row: /* @__PURE__ */ jsx(Suspense, {
|
|
207
|
+
fallback: initialValue,
|
|
208
|
+
children: /* @__PURE__ */ jsx(R, {
|
|
209
|
+
c: initialValue,
|
|
210
|
+
n: promise
|
|
211
|
+
})
|
|
212
|
+
}),
|
|
213
|
+
resolve,
|
|
214
|
+
reject
|
|
215
|
+
};
|
|
260
216
|
}
|
|
261
|
-
|
|
262
|
-
|
|
217
|
+
//#endregion
|
|
218
|
+
//#region src/streamable-ui/create-streamable-ui.tsx
|
|
219
|
+
/**
|
|
220
|
+
* Create a piece of changeable UI that can be streamed to the client.
|
|
221
|
+
* On the client side, it can be rendered as a normal React node.
|
|
222
|
+
*/
|
|
263
223
|
function createStreamableUI(initialValue) {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
224
|
+
let currentValue = initialValue;
|
|
225
|
+
let closed = false;
|
|
226
|
+
let { row, resolve, reject } = createSuspendedChunk(initialValue);
|
|
227
|
+
function assertStream(method) {
|
|
228
|
+
if (closed) throw new Error(method + ": UI stream is already closed.");
|
|
229
|
+
}
|
|
230
|
+
let warningTimeout;
|
|
231
|
+
function warnUnclosedStream() {
|
|
232
|
+
if (process.env.NODE_ENV === "development") {
|
|
233
|
+
if (warningTimeout) clearTimeout(warningTimeout);
|
|
234
|
+
warningTimeout = setTimeout(() => {
|
|
235
|
+
console.warn("The streamable UI has been slow to update. This may be a bug or a performance issue or you forgot to call `.done()`.");
|
|
236
|
+
}, HANGING_STREAM_WARNING_TIME_MS);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
warnUnclosedStream();
|
|
240
|
+
const streamable = {
|
|
241
|
+
value: row,
|
|
242
|
+
update(value) {
|
|
243
|
+
assertStream(".update()");
|
|
244
|
+
if (value === currentValue) {
|
|
245
|
+
warnUnclosedStream();
|
|
246
|
+
return streamable;
|
|
247
|
+
}
|
|
248
|
+
const resolvable = createResolvablePromise();
|
|
249
|
+
currentValue = value;
|
|
250
|
+
resolve({
|
|
251
|
+
value: currentValue,
|
|
252
|
+
done: false,
|
|
253
|
+
next: resolvable.promise
|
|
254
|
+
});
|
|
255
|
+
resolve = resolvable.resolve;
|
|
256
|
+
reject = resolvable.reject;
|
|
257
|
+
warnUnclosedStream();
|
|
258
|
+
return streamable;
|
|
259
|
+
},
|
|
260
|
+
append(value) {
|
|
261
|
+
assertStream(".append()");
|
|
262
|
+
const resolvable = createResolvablePromise();
|
|
263
|
+
currentValue = value;
|
|
264
|
+
resolve({
|
|
265
|
+
value,
|
|
266
|
+
done: false,
|
|
267
|
+
append: true,
|
|
268
|
+
next: resolvable.promise
|
|
269
|
+
});
|
|
270
|
+
resolve = resolvable.resolve;
|
|
271
|
+
reject = resolvable.reject;
|
|
272
|
+
warnUnclosedStream();
|
|
273
|
+
return streamable;
|
|
274
|
+
},
|
|
275
|
+
error(error) {
|
|
276
|
+
assertStream(".error()");
|
|
277
|
+
if (warningTimeout) clearTimeout(warningTimeout);
|
|
278
|
+
closed = true;
|
|
279
|
+
reject(error);
|
|
280
|
+
return streamable;
|
|
281
|
+
},
|
|
282
|
+
done(...args) {
|
|
283
|
+
assertStream(".done()");
|
|
284
|
+
if (warningTimeout) clearTimeout(warningTimeout);
|
|
285
|
+
closed = true;
|
|
286
|
+
if (args.length) {
|
|
287
|
+
resolve({
|
|
288
|
+
value: args[0],
|
|
289
|
+
done: true
|
|
290
|
+
});
|
|
291
|
+
return streamable;
|
|
292
|
+
}
|
|
293
|
+
resolve({
|
|
294
|
+
value: currentValue,
|
|
295
|
+
done: true
|
|
296
|
+
});
|
|
297
|
+
return streamable;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
return streamable;
|
|
336
301
|
}
|
|
337
|
-
|
|
338
|
-
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region src/util/is-async-generator.ts
|
|
339
304
|
function isAsyncGenerator(value) {
|
|
340
|
-
|
|
305
|
+
return value != null && typeof value === "object" && Symbol.asyncIterator in value;
|
|
341
306
|
}
|
|
342
|
-
|
|
343
|
-
|
|
307
|
+
//#endregion
|
|
308
|
+
//#region src/util/is-generator.ts
|
|
344
309
|
function isGenerator(value) {
|
|
345
|
-
|
|
310
|
+
return value != null && typeof value === "object" && Symbol.iterator in value;
|
|
346
311
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
const parseResult = await safeParseJSON({
|
|
504
|
-
text: value.input,
|
|
505
|
-
schema: tool.inputSchema
|
|
506
|
-
});
|
|
507
|
-
if (parseResult.success === false) {
|
|
508
|
-
throw new InvalidToolInputError({
|
|
509
|
-
toolName,
|
|
510
|
-
toolInput: value.input,
|
|
511
|
-
cause: parseResult.error
|
|
512
|
-
});
|
|
513
|
-
}
|
|
514
|
-
render({
|
|
515
|
-
renderer: tool.generate,
|
|
516
|
-
args: [
|
|
517
|
-
parseResult.value,
|
|
518
|
-
{
|
|
519
|
-
toolName,
|
|
520
|
-
toolCallId: value.toolCallId
|
|
521
|
-
}
|
|
522
|
-
],
|
|
523
|
-
streamableUI: ui,
|
|
524
|
-
isLastCall: true
|
|
525
|
-
});
|
|
526
|
-
break;
|
|
527
|
-
}
|
|
528
|
-
case "error": {
|
|
529
|
-
throw value.error;
|
|
530
|
-
}
|
|
531
|
-
case "finish": {
|
|
532
|
-
finishEvent = {
|
|
533
|
-
finishReason: value.finishReason?.unified,
|
|
534
|
-
usage: value.usage,
|
|
535
|
-
warnings,
|
|
536
|
-
response: result.response
|
|
537
|
-
};
|
|
538
|
-
break;
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
if (!hasToolCall) {
|
|
543
|
-
render({
|
|
544
|
-
renderer: textRender,
|
|
545
|
-
args: [{ content, done: true }],
|
|
546
|
-
streamableUI: ui,
|
|
547
|
-
isLastCall: true
|
|
548
|
-
});
|
|
549
|
-
}
|
|
550
|
-
await finished;
|
|
551
|
-
if (finishEvent && onFinish) {
|
|
552
|
-
await onFinish({
|
|
553
|
-
...finishEvent,
|
|
554
|
-
usage: asLanguageModelUsage(finishEvent.usage),
|
|
555
|
-
value: ui.value
|
|
556
|
-
});
|
|
557
|
-
}
|
|
558
|
-
} catch (error) {
|
|
559
|
-
ui.error(error);
|
|
560
|
-
}
|
|
561
|
-
})();
|
|
562
|
-
return {
|
|
563
|
-
...result,
|
|
564
|
-
stream,
|
|
565
|
-
value: ui.value
|
|
566
|
-
};
|
|
312
|
+
//#endregion
|
|
313
|
+
//#region src/stream-ui/stream-ui.tsx
|
|
314
|
+
const defaultTextRenderer = ({ content }) => content;
|
|
315
|
+
/**
|
|
316
|
+
* `streamUI` is a helper function to create a streamable UI from LLMs.
|
|
317
|
+
*/
|
|
318
|
+
async function streamUI({ model, tools, toolChoice, instructions, system, prompt, messages, allowSystemInMessages, maxRetries, abortSignal, headers, initial, text, providerOptions, onFinish, ...settings }) {
|
|
319
|
+
if (typeof model === "string") throw new Error("`model` cannot be a string in `streamUI`. Use the actual model instance instead.");
|
|
320
|
+
if ("functions" in settings) throw new Error("`functions` is not supported in `streamUI`, use `tools` instead.");
|
|
321
|
+
if ("provider" in settings) throw new Error("`provider` is no longer needed in `streamUI`. Use `model` instead.");
|
|
322
|
+
if (tools) {
|
|
323
|
+
for (const [name, tool] of Object.entries(tools)) if ("render" in tool) throw new Error("Tool definition in `streamUI` should not have `render` property. Use `generate` instead. Found in tool: " + name);
|
|
324
|
+
}
|
|
325
|
+
const ui = createStreamableUI(initial);
|
|
326
|
+
const textRender = text || defaultTextRenderer;
|
|
327
|
+
let finished;
|
|
328
|
+
let finishEvent = null;
|
|
329
|
+
async function render({ args, renderer, streamableUI, isLastCall = false }) {
|
|
330
|
+
if (!renderer) return;
|
|
331
|
+
const renderFinished = createResolvablePromise();
|
|
332
|
+
finished = finished ? finished.then(() => renderFinished.promise) : renderFinished.promise;
|
|
333
|
+
const rendererResult = renderer(...args);
|
|
334
|
+
if (isAsyncGenerator(rendererResult) || isGenerator(rendererResult)) while (true) {
|
|
335
|
+
const { done, value } = await rendererResult.next();
|
|
336
|
+
const node = await value;
|
|
337
|
+
if (isLastCall && done) streamableUI.done(node);
|
|
338
|
+
else streamableUI.update(node);
|
|
339
|
+
if (done) break;
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
const node = await rendererResult;
|
|
343
|
+
if (isLastCall) streamableUI.done(node);
|
|
344
|
+
else streamableUI.update(node);
|
|
345
|
+
}
|
|
346
|
+
renderFinished.resolve(void 0);
|
|
347
|
+
}
|
|
348
|
+
const { retry } = prepareRetries({
|
|
349
|
+
maxRetries,
|
|
350
|
+
abortSignal
|
|
351
|
+
});
|
|
352
|
+
const validatedPrompt = await standardizePrompt({
|
|
353
|
+
instructions,
|
|
354
|
+
system,
|
|
355
|
+
prompt,
|
|
356
|
+
messages,
|
|
357
|
+
allowSystemInMessages
|
|
358
|
+
});
|
|
359
|
+
const languageModelTools = await prepareTools({ tools });
|
|
360
|
+
const languageModelToolChoice = prepareToolChoice({ toolChoice });
|
|
361
|
+
const result = await retry(async () => model.doStream({
|
|
362
|
+
...prepareLanguageModelCallOptions(settings),
|
|
363
|
+
tools: languageModelTools,
|
|
364
|
+
toolChoice: languageModelToolChoice,
|
|
365
|
+
prompt: await convertToLanguageModelPrompt({
|
|
366
|
+
prompt: validatedPrompt,
|
|
367
|
+
supportedUrls: await model.supportedUrls,
|
|
368
|
+
download: void 0,
|
|
369
|
+
provider: model.provider.split(".")[0]
|
|
370
|
+
}),
|
|
371
|
+
providerOptions,
|
|
372
|
+
abortSignal,
|
|
373
|
+
headers,
|
|
374
|
+
includeRawChunks: false
|
|
375
|
+
}));
|
|
376
|
+
const [stream, forkedStream] = result.stream.tee();
|
|
377
|
+
(async () => {
|
|
378
|
+
try {
|
|
379
|
+
let content = "";
|
|
380
|
+
let hasToolCall = false;
|
|
381
|
+
let warnings;
|
|
382
|
+
const reader = forkedStream.getReader();
|
|
383
|
+
while (true) {
|
|
384
|
+
const { done, value } = await reader.read();
|
|
385
|
+
if (done) break;
|
|
386
|
+
switch (value.type) {
|
|
387
|
+
case "stream-start":
|
|
388
|
+
warnings = value.warnings;
|
|
389
|
+
break;
|
|
390
|
+
case "text-delta":
|
|
391
|
+
content += value.delta;
|
|
392
|
+
render({
|
|
393
|
+
renderer: textRender,
|
|
394
|
+
args: [{
|
|
395
|
+
content,
|
|
396
|
+
done: false,
|
|
397
|
+
delta: value.delta
|
|
398
|
+
}],
|
|
399
|
+
streamableUI: ui
|
|
400
|
+
});
|
|
401
|
+
break;
|
|
402
|
+
case "tool-input-start":
|
|
403
|
+
case "tool-input-delta":
|
|
404
|
+
hasToolCall = true;
|
|
405
|
+
break;
|
|
406
|
+
case "tool-call": {
|
|
407
|
+
const toolName = value.toolName;
|
|
408
|
+
if (!tools) throw new NoSuchToolError({ toolName });
|
|
409
|
+
const tool = tools[toolName];
|
|
410
|
+
if (!tool) throw new NoSuchToolError({
|
|
411
|
+
toolName,
|
|
412
|
+
availableTools: Object.keys(tools)
|
|
413
|
+
});
|
|
414
|
+
hasToolCall = true;
|
|
415
|
+
const parseResult = await safeParseJSON({
|
|
416
|
+
text: value.input,
|
|
417
|
+
schema: tool.inputSchema
|
|
418
|
+
});
|
|
419
|
+
if (parseResult.success === false) throw new InvalidToolInputError({
|
|
420
|
+
toolName,
|
|
421
|
+
toolInput: value.input,
|
|
422
|
+
cause: parseResult.error
|
|
423
|
+
});
|
|
424
|
+
render({
|
|
425
|
+
renderer: tool.generate,
|
|
426
|
+
args: [parseResult.value, {
|
|
427
|
+
toolName,
|
|
428
|
+
toolCallId: value.toolCallId
|
|
429
|
+
}],
|
|
430
|
+
streamableUI: ui,
|
|
431
|
+
isLastCall: true
|
|
432
|
+
});
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
case "error": throw value.error;
|
|
436
|
+
case "finish": finishEvent = {
|
|
437
|
+
finishReason: value.finishReason?.unified,
|
|
438
|
+
usage: value.usage,
|
|
439
|
+
warnings,
|
|
440
|
+
response: result.response
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
if (!hasToolCall) render({
|
|
445
|
+
renderer: textRender,
|
|
446
|
+
args: [{
|
|
447
|
+
content,
|
|
448
|
+
done: true
|
|
449
|
+
}],
|
|
450
|
+
streamableUI: ui,
|
|
451
|
+
isLastCall: true
|
|
452
|
+
});
|
|
453
|
+
await finished;
|
|
454
|
+
if (finishEvent && onFinish) await onFinish({
|
|
455
|
+
...finishEvent,
|
|
456
|
+
usage: asLanguageModelUsage(finishEvent.usage),
|
|
457
|
+
value: ui.value
|
|
458
|
+
});
|
|
459
|
+
} catch (error) {
|
|
460
|
+
ui.error(error);
|
|
461
|
+
}
|
|
462
|
+
})();
|
|
463
|
+
return {
|
|
464
|
+
...result,
|
|
465
|
+
stream,
|
|
466
|
+
value: ui.value
|
|
467
|
+
};
|
|
567
468
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
469
|
+
//#endregion
|
|
470
|
+
//#region src/streamable-value/streamable-value.ts
|
|
471
|
+
const STREAMABLE_VALUE_TYPE = Symbol.for("ui.streamable.value");
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region src/streamable-value/create-streamable-value.ts
|
|
474
|
+
const STREAMABLE_VALUE_INTERNAL_LOCK = Symbol("streamable.value.lock");
|
|
475
|
+
/**
|
|
476
|
+
* Create a wrapped, changeable value that can be streamed to the client.
|
|
477
|
+
* On the client side, the value can be accessed via the readStreamableValue() API.
|
|
478
|
+
*/
|
|
574
479
|
function createStreamableValue(initialValue) {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
streamableValue[STREAMABLE_VALUE_INTERNAL_LOCK] = false;
|
|
598
|
-
streamableValue.done();
|
|
599
|
-
} catch (e) {
|
|
600
|
-
streamableValue[STREAMABLE_VALUE_INTERNAL_LOCK] = false;
|
|
601
|
-
streamableValue.error(e);
|
|
602
|
-
}
|
|
603
|
-
})();
|
|
604
|
-
return streamableValue;
|
|
480
|
+
if (!(initialValue instanceof ReadableStream || typeof initialValue === "object" && initialValue !== null && "getReader" in initialValue && typeof initialValue.getReader === "function" && "locked" in initialValue && typeof initialValue.locked === "boolean")) return createStreamableValueImpl(initialValue);
|
|
481
|
+
const streamableValue = createStreamableValueImpl();
|
|
482
|
+
streamableValue[STREAMABLE_VALUE_INTERNAL_LOCK] = true;
|
|
483
|
+
(async () => {
|
|
484
|
+
try {
|
|
485
|
+
const reader = initialValue.getReader();
|
|
486
|
+
while (true) {
|
|
487
|
+
const { value, done } = await reader.read();
|
|
488
|
+
if (done) break;
|
|
489
|
+
streamableValue[STREAMABLE_VALUE_INTERNAL_LOCK] = false;
|
|
490
|
+
if (typeof value === "string") streamableValue.append(value);
|
|
491
|
+
else streamableValue.update(value);
|
|
492
|
+
streamableValue[STREAMABLE_VALUE_INTERNAL_LOCK] = true;
|
|
493
|
+
}
|
|
494
|
+
streamableValue[STREAMABLE_VALUE_INTERNAL_LOCK] = false;
|
|
495
|
+
streamableValue.done();
|
|
496
|
+
} catch (e) {
|
|
497
|
+
streamableValue[STREAMABLE_VALUE_INTERNAL_LOCK] = false;
|
|
498
|
+
streamableValue.error(e);
|
|
499
|
+
}
|
|
500
|
+
})();
|
|
501
|
+
return streamableValue;
|
|
605
502
|
}
|
|
606
503
|
function createStreamableValueImpl(initialValue) {
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
}
|
|
706
|
-
currentPromise = resolvable.promise;
|
|
707
|
-
resolvePrevious(createWrapped());
|
|
708
|
-
warnUnclosedStream();
|
|
709
|
-
return streamable;
|
|
710
|
-
},
|
|
711
|
-
error(error) {
|
|
712
|
-
assertStream(".error()");
|
|
713
|
-
if (warningTimeout) {
|
|
714
|
-
clearTimeout(warningTimeout);
|
|
715
|
-
}
|
|
716
|
-
closed = true;
|
|
717
|
-
currentError = error;
|
|
718
|
-
currentPromise = void 0;
|
|
719
|
-
resolvable.resolve({ error });
|
|
720
|
-
return streamable;
|
|
721
|
-
},
|
|
722
|
-
done(...args) {
|
|
723
|
-
assertStream(".done()");
|
|
724
|
-
if (warningTimeout) {
|
|
725
|
-
clearTimeout(warningTimeout);
|
|
726
|
-
}
|
|
727
|
-
closed = true;
|
|
728
|
-
currentPromise = void 0;
|
|
729
|
-
if (args.length) {
|
|
730
|
-
updateValueStates(args[0]);
|
|
731
|
-
resolvable.resolve(createWrapped());
|
|
732
|
-
return streamable;
|
|
733
|
-
}
|
|
734
|
-
resolvable.resolve({});
|
|
735
|
-
return streamable;
|
|
736
|
-
}
|
|
737
|
-
};
|
|
738
|
-
return streamable;
|
|
504
|
+
let closed = false;
|
|
505
|
+
let locked = false;
|
|
506
|
+
let resolvable = createResolvablePromise();
|
|
507
|
+
let currentValue = initialValue;
|
|
508
|
+
let currentError;
|
|
509
|
+
let currentPromise = resolvable.promise;
|
|
510
|
+
let currentPatchValue;
|
|
511
|
+
function assertStream(method) {
|
|
512
|
+
if (closed) throw new Error(method + ": Value stream is already closed.");
|
|
513
|
+
if (locked) throw new Error(method + ": Value stream is locked and cannot be updated.");
|
|
514
|
+
}
|
|
515
|
+
let warningTimeout;
|
|
516
|
+
function warnUnclosedStream() {
|
|
517
|
+
if (process.env.NODE_ENV === "development") {
|
|
518
|
+
if (warningTimeout) clearTimeout(warningTimeout);
|
|
519
|
+
warningTimeout = setTimeout(() => {
|
|
520
|
+
console.warn("The streamable value has been slow to update. This may be a bug or a performance issue or you forgot to call `.done()`.");
|
|
521
|
+
}, HANGING_STREAM_WARNING_TIME_MS);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
warnUnclosedStream();
|
|
525
|
+
function createWrapped(initialChunk) {
|
|
526
|
+
let init;
|
|
527
|
+
if (currentError !== void 0) init = { error: currentError };
|
|
528
|
+
else if (currentPatchValue && !initialChunk) init = { diff: currentPatchValue };
|
|
529
|
+
else init = { curr: currentValue };
|
|
530
|
+
if (currentPromise) init.next = currentPromise;
|
|
531
|
+
if (initialChunk) init.type = STREAMABLE_VALUE_TYPE;
|
|
532
|
+
return init;
|
|
533
|
+
}
|
|
534
|
+
function updateValueStates(value) {
|
|
535
|
+
currentPatchValue = void 0;
|
|
536
|
+
if (typeof value === "string") {
|
|
537
|
+
if (typeof currentValue === "string") {
|
|
538
|
+
if (value.startsWith(currentValue)) currentPatchValue = [0, value.slice(currentValue.length)];
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
currentValue = value;
|
|
542
|
+
}
|
|
543
|
+
const streamable = {
|
|
544
|
+
set [STREAMABLE_VALUE_INTERNAL_LOCK](state) {
|
|
545
|
+
locked = state;
|
|
546
|
+
},
|
|
547
|
+
get value() {
|
|
548
|
+
return createWrapped(true);
|
|
549
|
+
},
|
|
550
|
+
update(value) {
|
|
551
|
+
assertStream(".update()");
|
|
552
|
+
const resolvePrevious = resolvable.resolve;
|
|
553
|
+
resolvable = createResolvablePromise();
|
|
554
|
+
updateValueStates(value);
|
|
555
|
+
currentPromise = resolvable.promise;
|
|
556
|
+
resolvePrevious(createWrapped());
|
|
557
|
+
warnUnclosedStream();
|
|
558
|
+
return streamable;
|
|
559
|
+
},
|
|
560
|
+
append(value) {
|
|
561
|
+
assertStream(".append()");
|
|
562
|
+
if (typeof currentValue !== "string" && typeof currentValue !== "undefined") throw new Error(`.append(): The current value is not a string. Received: ${typeof currentValue}`);
|
|
563
|
+
if (typeof value !== "string") throw new Error(`.append(): The value is not a string. Received: ${typeof value}`);
|
|
564
|
+
const resolvePrevious = resolvable.resolve;
|
|
565
|
+
resolvable = createResolvablePromise();
|
|
566
|
+
if (typeof currentValue === "string") {
|
|
567
|
+
currentPatchValue = [0, value];
|
|
568
|
+
currentValue = currentValue + value;
|
|
569
|
+
} else {
|
|
570
|
+
currentPatchValue = void 0;
|
|
571
|
+
currentValue = value;
|
|
572
|
+
}
|
|
573
|
+
currentPromise = resolvable.promise;
|
|
574
|
+
resolvePrevious(createWrapped());
|
|
575
|
+
warnUnclosedStream();
|
|
576
|
+
return streamable;
|
|
577
|
+
},
|
|
578
|
+
error(error) {
|
|
579
|
+
assertStream(".error()");
|
|
580
|
+
if (warningTimeout) clearTimeout(warningTimeout);
|
|
581
|
+
closed = true;
|
|
582
|
+
currentError = error;
|
|
583
|
+
currentPromise = void 0;
|
|
584
|
+
resolvable.resolve({ error });
|
|
585
|
+
return streamable;
|
|
586
|
+
},
|
|
587
|
+
done(...args) {
|
|
588
|
+
assertStream(".done()");
|
|
589
|
+
if (warningTimeout) clearTimeout(warningTimeout);
|
|
590
|
+
closed = true;
|
|
591
|
+
currentPromise = void 0;
|
|
592
|
+
if (args.length) {
|
|
593
|
+
updateValueStates(args[0]);
|
|
594
|
+
resolvable.resolve(createWrapped());
|
|
595
|
+
return streamable;
|
|
596
|
+
}
|
|
597
|
+
resolvable.resolve({});
|
|
598
|
+
return streamable;
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
return streamable;
|
|
739
602
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
createStreamableValue,
|
|
744
|
-
getAIState,
|
|
745
|
-
getMutableAIState,
|
|
746
|
-
streamUI
|
|
747
|
-
};
|
|
603
|
+
//#endregion
|
|
604
|
+
export { createAI, createStreamableUI, createStreamableValue, getAIState, getMutableAIState, streamUI };
|
|
605
|
+
|
|
748
606
|
//# sourceMappingURL=rsc-server.js.map
|