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