ai 7.0.142 → 7.0.143
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 +12 -0
- package/dist/index.d.ts +248 -203
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +203 -122
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +26 -16
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +1 -1
- package/docs/03-ai-sdk-core/17-mcp-events.mdx +50 -0
- package/docs/03-ai-sdk-core/32-decisions.mdx +2 -1
- package/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx +1 -1
- package/docs/07-reference/01-ai-sdk-core/02-stream-text-low-memory.mdx +107 -0
- package/docs/07-reference/01-ai-sdk-core/02-stream-text.mdx +6 -0
- package/docs/07-reference/01-ai-sdk-core/14-decide.mdx +1 -1
- package/docs/07-reference/02-ai-sdk-ui/01-use-chat.mdx +1 -1
- package/package.json +12 -12
- package/src/agent/tool-loop-agent.ts +7 -4
- package/src/decide/decision-result.ts +6 -1
- package/src/decide/validate-decision.ts +21 -1
- package/src/generate-text/stream-language-model-call.ts +32 -16
- package/src/generate-text/stream-text-single-consumer-result.ts +75 -0
- package/src/generate-text/stream-text.ts +250 -37
- package/src/ui/chat.ts +9 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AISDKError,
|
|
2
3
|
getErrorMessage,
|
|
3
4
|
UnsupportedFunctionalityError,
|
|
4
5
|
type LanguageModelV4,
|
|
@@ -44,6 +45,7 @@ import { standardizePrompt } from '../prompt/standardize-prompt';
|
|
|
44
45
|
import { wrapGatewayError } from '../prompt/wrap-gateway-error';
|
|
45
46
|
import type { TelemetryDispatcher } from '../telemetry/telemetry';
|
|
46
47
|
import type { TelemetryOptions } from '../telemetry/telemetry-options';
|
|
48
|
+
import { getGlobalTelemetryIntegrations } from '../telemetry/telemetry-registry';
|
|
47
49
|
import { createTextStreamResponse } from '../text-stream/create-text-stream-response';
|
|
48
50
|
import { pipeTextStreamToResponse } from '../text-stream/pipe-text-stream-to-response';
|
|
49
51
|
import { toTextStream } from '../text-stream/to-text-stream';
|
|
@@ -68,6 +70,7 @@ import { toUIMessageStream as toUIMessageStreamHelper } from '../ui-message-stre
|
|
|
68
70
|
import type { InferUIMessageChunk } from '../ui-message-stream/ui-message-chunks';
|
|
69
71
|
import type { UIMessageStreamResponseInit } from '../ui-message-stream/ui-message-stream-response-init';
|
|
70
72
|
import {
|
|
73
|
+
asAsyncIterableStream,
|
|
71
74
|
createAsyncIterableStream,
|
|
72
75
|
type AsyncIterableStream,
|
|
73
76
|
} from '../util/async-iterable-stream';
|
|
@@ -111,6 +114,10 @@ import type {
|
|
|
111
114
|
OnLanguageModelCallStartCallback,
|
|
112
115
|
} from './language-model-events';
|
|
113
116
|
import { text, type Output } from './output';
|
|
117
|
+
import {
|
|
118
|
+
createSingleConsumerStreamTextResult,
|
|
119
|
+
type StreamTextSingleConsumerResult,
|
|
120
|
+
} from './stream-text-single-consumer-result';
|
|
114
121
|
import type {
|
|
115
122
|
InferCompleteOutput,
|
|
116
123
|
InferElementOutput,
|
|
@@ -171,6 +178,14 @@ import {
|
|
|
171
178
|
prepareToolCallConcurrency,
|
|
172
179
|
} from './tool-call-concurrency';
|
|
173
180
|
|
|
181
|
+
/** Internal policy, fixed before the model request starts. */
|
|
182
|
+
type StreamTextRetention = {
|
|
183
|
+
/** Keep a replay branch for independently consumed stream projections. */
|
|
184
|
+
replay: boolean;
|
|
185
|
+
/** Collect complete content for results, callbacks, or subsequent steps. */
|
|
186
|
+
collectContent: boolean;
|
|
187
|
+
};
|
|
188
|
+
|
|
174
189
|
const originalGenerateId = createIdGenerator({
|
|
175
190
|
prefix: 'aitxt',
|
|
176
191
|
size: 24,
|
|
@@ -284,6 +299,21 @@ export type StreamTextOnAbortCallback<
|
|
|
284
299
|
RUNTIME_CONTEXT extends Context,
|
|
285
300
|
> = Callback<GenerateTextAbortEvent<TOOLS, RUNTIME_CONTEXT>>;
|
|
286
301
|
|
|
302
|
+
type StreamTextOptions<
|
|
303
|
+
TOOLS extends ToolSet,
|
|
304
|
+
RUNTIME_CONTEXT extends Context,
|
|
305
|
+
OUTPUT extends Output,
|
|
306
|
+
> = Parameters<typeof streamTextInternal<TOOLS, RUNTIME_CONTEXT, OUTPUT>>[0] & {
|
|
307
|
+
/**
|
|
308
|
+
* Consume the stream once without replay or final-content getters.
|
|
309
|
+
* Content is collected only when required by tools, output parsing,
|
|
310
|
+
* full-content callbacks, or telemetry integrations.
|
|
311
|
+
*
|
|
312
|
+
* @default false
|
|
313
|
+
*/
|
|
314
|
+
experimental_lowMemory?: boolean;
|
|
315
|
+
};
|
|
316
|
+
|
|
287
317
|
/**
|
|
288
318
|
* Generate a text and call tools for a given prompt using a language model.
|
|
289
319
|
*
|
|
@@ -330,6 +360,8 @@ export type StreamTextOnAbortCallback<
|
|
|
330
360
|
* @param runtimeContext - User-defined runtime context that flows through the entire generation lifecycle.
|
|
331
361
|
* @param experimental_refineToolInput - Optional mapping of tool names to functions that refine parsed tool inputs before tools are executed and before outputs, callbacks, and telemetry are recorded.
|
|
332
362
|
*
|
|
363
|
+
* @param experimental_lowMemory - Consume the stream once without replay or final-content getters. Default: false.
|
|
364
|
+
*
|
|
333
365
|
* @param onChunk - Callback that is called for each chunk of the stream. The stream processing will pause until the callback promise is resolved.
|
|
334
366
|
* @param onError - Callback that is called when an error occurs during streaming. You can use it to log errors.
|
|
335
367
|
* @param onStart - Callback invoked when generation begins, before any LLM calls.
|
|
@@ -356,6 +388,80 @@ export function streamText<
|
|
|
356
388
|
TOOLS extends ToolSet,
|
|
357
389
|
RUNTIME_CONTEXT extends Context = Context,
|
|
358
390
|
OUTPUT extends Output = Output<string, string, never>,
|
|
391
|
+
>(
|
|
392
|
+
options: StreamTextOptions<TOOLS, RUNTIME_CONTEXT, OUTPUT> & {
|
|
393
|
+
experimental_lowMemory?: false;
|
|
394
|
+
},
|
|
395
|
+
): StreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>;
|
|
396
|
+
export function streamText<
|
|
397
|
+
TOOLS extends ToolSet,
|
|
398
|
+
RUNTIME_CONTEXT extends Context = Context,
|
|
399
|
+
OUTPUT extends Output = Output<string, string, never>,
|
|
400
|
+
>(
|
|
401
|
+
options: StreamTextOptions<TOOLS, RUNTIME_CONTEXT, OUTPUT> & {
|
|
402
|
+
experimental_lowMemory: true;
|
|
403
|
+
},
|
|
404
|
+
): StreamTextSingleConsumerResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>;
|
|
405
|
+
export function streamText<
|
|
406
|
+
TOOLS extends ToolSet,
|
|
407
|
+
RUNTIME_CONTEXT extends Context = Context,
|
|
408
|
+
OUTPUT extends Output = Output<string, string, never>,
|
|
409
|
+
>(
|
|
410
|
+
options: StreamTextOptions<TOOLS, RUNTIME_CONTEXT, OUTPUT>,
|
|
411
|
+
):
|
|
412
|
+
| StreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>
|
|
413
|
+
| StreamTextSingleConsumerResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>;
|
|
414
|
+
export function streamText<
|
|
415
|
+
TOOLS extends ToolSet,
|
|
416
|
+
RUNTIME_CONTEXT extends Context = Context,
|
|
417
|
+
OUTPUT extends Output = Output<string, string, never>,
|
|
418
|
+
>({
|
|
419
|
+
experimental_lowMemory = false,
|
|
420
|
+
...options
|
|
421
|
+
}: StreamTextOptions<TOOLS, RUNTIME_CONTEXT, OUTPUT>):
|
|
422
|
+
| StreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>
|
|
423
|
+
| StreamTextSingleConsumerResult<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
|
|
424
|
+
if (!experimental_lowMemory) {
|
|
425
|
+
return streamTextInternal<TOOLS, RUNTIME_CONTEXT, OUTPUT>({ ...options });
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const telemetry = options.telemetry ?? options.experimental_telemetry;
|
|
429
|
+
const integrations =
|
|
430
|
+
telemetry?.integrations != null
|
|
431
|
+
? asArray(telemetry.integrations)
|
|
432
|
+
: getGlobalTelemetryIntegrations();
|
|
433
|
+
|
|
434
|
+
// Decide before execution so getter access cannot change collection.
|
|
435
|
+
const collectContent =
|
|
436
|
+
(options.tools != null && Object.keys(options.tools).length > 0) ||
|
|
437
|
+
options.toolChoice != null ||
|
|
438
|
+
options.output != null ||
|
|
439
|
+
options.prepareStep != null ||
|
|
440
|
+
options.stopWhen != null ||
|
|
441
|
+
options.onEnd != null ||
|
|
442
|
+
options.onFinish != null ||
|
|
443
|
+
options.onStepEnd != null ||
|
|
444
|
+
options.onStepFinish != null ||
|
|
445
|
+
options.onAbort != null ||
|
|
446
|
+
options.onLanguageModelCallEnd != null ||
|
|
447
|
+
options.experimental_onLanguageModelCallEnd != null ||
|
|
448
|
+
(telemetry?.isEnabled !== false && integrations.length > 0);
|
|
449
|
+
|
|
450
|
+
return createSingleConsumerStreamTextResult(
|
|
451
|
+
streamTextInternal<TOOLS, RUNTIME_CONTEXT, OUTPUT>({
|
|
452
|
+
...options,
|
|
453
|
+
_internal: {
|
|
454
|
+
...options._internal,
|
|
455
|
+
retention: { replay: false, collectContent },
|
|
456
|
+
},
|
|
457
|
+
}),
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function streamTextInternal<
|
|
462
|
+
TOOLS extends ToolSet,
|
|
463
|
+
RUNTIME_CONTEXT extends Context = Context,
|
|
464
|
+
OUTPUT extends Output = Output<string, string, never>,
|
|
359
465
|
>({
|
|
360
466
|
model,
|
|
361
467
|
tools,
|
|
@@ -416,6 +522,7 @@ export function streamText<
|
|
|
416
522
|
now = originalNow,
|
|
417
523
|
generateId = originalGenerateId,
|
|
418
524
|
generateCallId = originalGenerateCallId,
|
|
525
|
+
retention = { replay: true, collectContent: true },
|
|
419
526
|
} = {},
|
|
420
527
|
...settings
|
|
421
528
|
}: LanguageModelCallOptions &
|
|
@@ -781,6 +888,8 @@ export function streamText<
|
|
|
781
888
|
now?: () => number;
|
|
782
889
|
generateId?: IdGenerator;
|
|
783
890
|
generateCallId?: IdGenerator;
|
|
891
|
+
/** Internal policy used by the streaming-only facade. */
|
|
892
|
+
retention?: StreamTextRetention;
|
|
784
893
|
};
|
|
785
894
|
}): StreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
|
|
786
895
|
const resolvedToolCallConcurrency =
|
|
@@ -812,6 +921,7 @@ export function streamText<
|
|
|
812
921
|
onToolExecutionEnd ?? experimental_onToolCallFinish;
|
|
813
922
|
const resolvedOnStepEnd = onStepEnd ?? onStepFinish;
|
|
814
923
|
return new DefaultStreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>({
|
|
924
|
+
retention,
|
|
815
925
|
model: resolveLanguageModel(model),
|
|
816
926
|
telemetry,
|
|
817
927
|
headers,
|
|
@@ -922,6 +1032,7 @@ function createOutputTransformStream<
|
|
|
922
1032
|
OUTPUT extends Output,
|
|
923
1033
|
>(
|
|
924
1034
|
output: OUTPUT,
|
|
1035
|
+
collectOutput = true,
|
|
925
1036
|
): TransformStream<
|
|
926
1037
|
InternalTextStreamPart<TOOLS>,
|
|
927
1038
|
InternalEnrichedStreamPart<TOOLS, InferPartialOutput<OUTPUT>>
|
|
@@ -983,6 +1094,14 @@ function createOutputTransformStream<
|
|
|
983
1094
|
InternalEnrichedStreamPart<TOOLS, InferPartialOutput<OUTPUT>>
|
|
984
1095
|
>({
|
|
985
1096
|
async transform(chunk, controller) {
|
|
1097
|
+
if (!collectOutput) {
|
|
1098
|
+
controller.enqueue(
|
|
1099
|
+
isStreamRetryBoundaryPart(chunk)
|
|
1100
|
+
? chunk
|
|
1101
|
+
: { part: chunk, partialOutput: undefined },
|
|
1102
|
+
);
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
986
1105
|
if (isStreamRetryBoundaryPart(chunk)) {
|
|
987
1106
|
resetOutputState();
|
|
988
1107
|
controller.enqueue(chunk);
|
|
@@ -1204,7 +1323,11 @@ class DefaultStreamTextResult<
|
|
|
1204
1323
|
|
|
1205
1324
|
private tools: TOOLS | undefined;
|
|
1206
1325
|
|
|
1326
|
+
private readonly retention: StreamTextRetention;
|
|
1327
|
+
private streamClaimed = false;
|
|
1328
|
+
|
|
1207
1329
|
constructor({
|
|
1330
|
+
retention,
|
|
1208
1331
|
model,
|
|
1209
1332
|
telemetry,
|
|
1210
1333
|
headers,
|
|
@@ -1260,6 +1383,7 @@ class DefaultStreamTextResult<
|
|
|
1260
1383
|
download,
|
|
1261
1384
|
include,
|
|
1262
1385
|
}: {
|
|
1386
|
+
retention: StreamTextRetention;
|
|
1263
1387
|
model: LanguageModelV4;
|
|
1264
1388
|
telemetry: TelemetryOptions<RUNTIME_CONTEXT, TOOLS> | undefined;
|
|
1265
1389
|
headers: Record<string, string | undefined> | undefined;
|
|
@@ -1348,6 +1472,7 @@ class DefaultStreamTextResult<
|
|
|
1348
1472
|
onToolExecutionStart: undefined | OnToolExecutionStartCallback<TOOLS>;
|
|
1349
1473
|
onToolExecutionEnd: undefined | OnToolExecutionEndCallback<TOOLS>;
|
|
1350
1474
|
}) {
|
|
1475
|
+
this.retention = retention;
|
|
1351
1476
|
this.outputSpecification = output;
|
|
1352
1477
|
this.tools = tools;
|
|
1353
1478
|
const resolvedToolCallers = resolveToolCallerConfiguration({
|
|
@@ -1381,7 +1506,7 @@ class DefaultStreamTextResult<
|
|
|
1381
1506
|
let recordedRequest: Omit<LanguageModelRequestMetadata, 'messages'> = {};
|
|
1382
1507
|
let recordedRequestMessages: Array<ModelMessage> = [];
|
|
1383
1508
|
let recordedWarnings: Array<CallWarning> = [];
|
|
1384
|
-
|
|
1509
|
+
let recordedSteps: StepResult<TOOLS, RUNTIME_CONTEXT>[] = [];
|
|
1385
1510
|
const initialResponseMessages: Array<ResponseMessage> = [];
|
|
1386
1511
|
let stepMessagesForNextStep: Array<ModelMessage> | undefined;
|
|
1387
1512
|
let currentStepMessages: Array<ModelMessage> = [];
|
|
@@ -1499,7 +1624,7 @@ class DefaultStreamTextResult<
|
|
|
1499
1624
|
part.type === 'tool-approval-response' ||
|
|
1500
1625
|
part.type === 'tool-error'
|
|
1501
1626
|
) {
|
|
1502
|
-
recordedContent.push(part);
|
|
1627
|
+
if (retention.collectContent) recordedContent.push(part);
|
|
1503
1628
|
}
|
|
1504
1629
|
|
|
1505
1630
|
if (part.type === 'text-start') {
|
|
@@ -1509,7 +1634,8 @@ class DefaultStreamTextResult<
|
|
|
1509
1634
|
providerMetadata: part.providerMetadata,
|
|
1510
1635
|
};
|
|
1511
1636
|
|
|
1512
|
-
|
|
1637
|
+
if (retention.collectContent)
|
|
1638
|
+
recordedContent.push(activeTextContent[part.id]);
|
|
1513
1639
|
}
|
|
1514
1640
|
|
|
1515
1641
|
if (part.type === 'text-delta') {
|
|
@@ -1526,7 +1652,7 @@ class DefaultStreamTextResult<
|
|
|
1526
1652
|
return;
|
|
1527
1653
|
}
|
|
1528
1654
|
|
|
1529
|
-
activeText.text += part.text;
|
|
1655
|
+
if (retention.collectContent) activeText.text += part.text;
|
|
1530
1656
|
activeText.providerMetadata =
|
|
1531
1657
|
part.providerMetadata ?? activeText.providerMetadata;
|
|
1532
1658
|
}
|
|
@@ -1562,7 +1688,8 @@ class DefaultStreamTextResult<
|
|
|
1562
1688
|
providerMetadata: part.providerMetadata,
|
|
1563
1689
|
};
|
|
1564
1690
|
|
|
1565
|
-
|
|
1691
|
+
if (retention.collectContent)
|
|
1692
|
+
recordedContent.push(activeReasoningContent[part.id]);
|
|
1566
1693
|
}
|
|
1567
1694
|
|
|
1568
1695
|
if (part.type === 'reasoning-delta') {
|
|
@@ -1579,7 +1706,7 @@ class DefaultStreamTextResult<
|
|
|
1579
1706
|
return;
|
|
1580
1707
|
}
|
|
1581
1708
|
|
|
1582
|
-
activeReasoning.text += part.text;
|
|
1709
|
+
if (retention.collectContent) activeReasoning.text += part.text;
|
|
1583
1710
|
activeReasoning.providerMetadata =
|
|
1584
1711
|
part.providerMetadata ?? activeReasoning.providerMetadata;
|
|
1585
1712
|
}
|
|
@@ -1605,17 +1732,18 @@ class DefaultStreamTextResult<
|
|
|
1605
1732
|
}
|
|
1606
1733
|
|
|
1607
1734
|
if (part.type === 'file' || part.type === 'reasoning-file') {
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1735
|
+
if (retention.collectContent)
|
|
1736
|
+
recordedContent.push({
|
|
1737
|
+
type: part.type,
|
|
1738
|
+
file: part.file,
|
|
1739
|
+
...(part.providerMetadata != null
|
|
1740
|
+
? { providerMetadata: part.providerMetadata }
|
|
1741
|
+
: {}),
|
|
1742
|
+
});
|
|
1615
1743
|
}
|
|
1616
1744
|
|
|
1617
1745
|
if (part.type === 'tool-result' && !part.preliminary) {
|
|
1618
|
-
recordedContent.push(part);
|
|
1746
|
+
if (retention.collectContent) recordedContent.push(part);
|
|
1619
1747
|
}
|
|
1620
1748
|
|
|
1621
1749
|
if (part.type === 'start-step') {
|
|
@@ -1719,7 +1847,7 @@ class DefaultStreamTextResult<
|
|
|
1719
1847
|
self._totalUsage.resolve(totalUsage);
|
|
1720
1848
|
|
|
1721
1849
|
// aggregate results:
|
|
1722
|
-
self._steps.resolve(recordedSteps);
|
|
1850
|
+
self._steps.resolve(retention.replay ? recordedSteps : []);
|
|
1723
1851
|
|
|
1724
1852
|
if (isAborted) {
|
|
1725
1853
|
return;
|
|
@@ -1752,7 +1880,11 @@ class DefaultStreamTextResult<
|
|
|
1752
1880
|
const parsedOutput =
|
|
1753
1881
|
output == null
|
|
1754
1882
|
? undefined
|
|
1755
|
-
: await
|
|
1883
|
+
: await (
|
|
1884
|
+
retention.replay
|
|
1885
|
+
? self.getOutputPromise()
|
|
1886
|
+
: self.parseOutput(finalStep)
|
|
1887
|
+
).catch(() => undefined);
|
|
1756
1888
|
|
|
1757
1889
|
await onEnd({
|
|
1758
1890
|
...event,
|
|
@@ -1806,6 +1938,17 @@ class DefaultStreamTextResult<
|
|
|
1806
1938
|
]);
|
|
1807
1939
|
} catch (error) {
|
|
1808
1940
|
controller.error(error);
|
|
1941
|
+
} finally {
|
|
1942
|
+
if (!retention.replay) {
|
|
1943
|
+
// Replace our references; never mutate arrays delivered to callbacks.
|
|
1944
|
+
recordedSteps = [];
|
|
1945
|
+
recordedContent = [];
|
|
1946
|
+
recordedRequestMessages = [];
|
|
1947
|
+
currentStepMessages = [];
|
|
1948
|
+
stepMessagesForNextStep = undefined;
|
|
1949
|
+
activeTextContent = createIdMap();
|
|
1950
|
+
activeReasoningContent = createIdMap();
|
|
1951
|
+
}
|
|
1809
1952
|
}
|
|
1810
1953
|
},
|
|
1811
1954
|
});
|
|
@@ -1924,7 +2067,12 @@ class DefaultStreamTextResult<
|
|
|
1924
2067
|
});
|
|
1925
2068
|
|
|
1926
2069
|
this.baseStream = stream
|
|
1927
|
-
.pipeThrough(
|
|
2070
|
+
.pipeThrough(
|
|
2071
|
+
createOutputTransformStream(
|
|
2072
|
+
output ?? text(),
|
|
2073
|
+
retention.replay || output != null,
|
|
2074
|
+
),
|
|
2075
|
+
)
|
|
1928
2076
|
.pipeThrough(eventProcessor);
|
|
1929
2077
|
|
|
1930
2078
|
const { maxRetries } = prepareRetries({
|
|
@@ -2474,6 +2622,7 @@ class DefaultStreamTextResult<
|
|
|
2474
2622
|
},
|
|
2475
2623
|
_internal: {
|
|
2476
2624
|
now,
|
|
2625
|
+
collectContent: retention.collectContent,
|
|
2477
2626
|
},
|
|
2478
2627
|
...stepCallSettings,
|
|
2479
2628
|
}),
|
|
@@ -3179,7 +3328,7 @@ class DefaultStreamTextResult<
|
|
|
3179
3328
|
get steps() {
|
|
3180
3329
|
// when any of the promises are accessed, the stream is consumed
|
|
3181
3330
|
// so it resolves without needing to consume the stream separately
|
|
3182
|
-
this.consumeStream();
|
|
3331
|
+
if (this.retention.replay) this.consumeStream();
|
|
3183
3332
|
|
|
3184
3333
|
return this._steps.promise;
|
|
3185
3334
|
}
|
|
@@ -3279,7 +3428,7 @@ class DefaultStreamTextResult<
|
|
|
3279
3428
|
get totalUsage() {
|
|
3280
3429
|
// when any of the promises are accessed, the stream is consumed
|
|
3281
3430
|
// so it resolves without needing to consume the stream separately
|
|
3282
|
-
this.consumeStream();
|
|
3431
|
+
if (this.retention.replay) this.consumeStream();
|
|
3283
3432
|
|
|
3284
3433
|
return this._totalUsage.promise;
|
|
3285
3434
|
}
|
|
@@ -3287,7 +3436,7 @@ class DefaultStreamTextResult<
|
|
|
3287
3436
|
get finishReason() {
|
|
3288
3437
|
// when any of the promises are accessed, the stream is consumed
|
|
3289
3438
|
// so it resolves without needing to consume the stream separately
|
|
3290
|
-
this.consumeStream();
|
|
3439
|
+
if (this.retention.replay) this.consumeStream();
|
|
3291
3440
|
|
|
3292
3441
|
return this._finishReason.promise;
|
|
3293
3442
|
}
|
|
@@ -3295,7 +3444,7 @@ class DefaultStreamTextResult<
|
|
|
3295
3444
|
get rawFinishReason() {
|
|
3296
3445
|
// when any of the promises are accessed, the stream is consumed
|
|
3297
3446
|
// so it resolves without needing to consume the stream separately
|
|
3298
|
-
this.consumeStream();
|
|
3447
|
+
if (this.retention.replay) this.consumeStream();
|
|
3299
3448
|
|
|
3300
3449
|
return this._rawFinishReason.promise;
|
|
3301
3450
|
}
|
|
@@ -3309,17 +3458,69 @@ class DefaultStreamTextResult<
|
|
|
3309
3458
|
* However, the LLM results are expected to be small enough to not cause issues.
|
|
3310
3459
|
*/
|
|
3311
3460
|
private teeStream() {
|
|
3461
|
+
if (!this.retention.replay) {
|
|
3462
|
+
if (this.streamClaimed) {
|
|
3463
|
+
throw new AISDKError({
|
|
3464
|
+
name: 'AI_StreamAlreadyConsumedError',
|
|
3465
|
+
message:
|
|
3466
|
+
'This result supports one stream consumer. Choose one stream projection or response helper.',
|
|
3467
|
+
});
|
|
3468
|
+
}
|
|
3469
|
+
this.streamClaimed = true;
|
|
3470
|
+
const reader = this.baseStream.getReader();
|
|
3471
|
+
const rejectResults = (error: unknown) =>
|
|
3472
|
+
this.rejectResultPromises(error);
|
|
3473
|
+
return new ReadableStream(
|
|
3474
|
+
{
|
|
3475
|
+
async pull(controller) {
|
|
3476
|
+
try {
|
|
3477
|
+
const { done, value } = await reader.read();
|
|
3478
|
+
if (done) {
|
|
3479
|
+
reader.releaseLock();
|
|
3480
|
+
controller.close();
|
|
3481
|
+
} else {
|
|
3482
|
+
controller.enqueue(value);
|
|
3483
|
+
}
|
|
3484
|
+
} catch (error) {
|
|
3485
|
+
rejectResults(error);
|
|
3486
|
+
reader.releaseLock();
|
|
3487
|
+
controller.error(error);
|
|
3488
|
+
}
|
|
3489
|
+
},
|
|
3490
|
+
async cancel(reason) {
|
|
3491
|
+
rejectResults(
|
|
3492
|
+
reason ??
|
|
3493
|
+
new DOMException('The stream was cancelled.', 'AbortError'),
|
|
3494
|
+
);
|
|
3495
|
+
try {
|
|
3496
|
+
await reader.cancel(reason);
|
|
3497
|
+
} finally {
|
|
3498
|
+
reader.releaseLock();
|
|
3499
|
+
}
|
|
3500
|
+
},
|
|
3501
|
+
},
|
|
3502
|
+
{ highWaterMark: 0 },
|
|
3503
|
+
);
|
|
3504
|
+
}
|
|
3312
3505
|
const [stream1, stream2] = this.baseStream.tee();
|
|
3313
3506
|
this.baseStream = stream2;
|
|
3314
3507
|
return stream1;
|
|
3315
3508
|
}
|
|
3316
3509
|
|
|
3317
3510
|
get textStream(): AsyncIterableStream<string> {
|
|
3318
|
-
return
|
|
3511
|
+
return this.asIterableStream(toTextStream({ stream: this.stream }));
|
|
3512
|
+
}
|
|
3513
|
+
|
|
3514
|
+
private asIterableStream<T>(
|
|
3515
|
+
stream: ReadableStream<T>,
|
|
3516
|
+
): AsyncIterableStream<T> {
|
|
3517
|
+
return this.retention.replay
|
|
3518
|
+
? createAsyncIterableStream(stream)
|
|
3519
|
+
: asAsyncIterableStream(stream);
|
|
3319
3520
|
}
|
|
3320
3521
|
|
|
3321
3522
|
get stream(): AsyncIterableStream<TextStreamPart<TOOLS>> {
|
|
3322
|
-
return
|
|
3523
|
+
return this.asIterableStream(
|
|
3323
3524
|
this.teeStream().pipeThrough(
|
|
3324
3525
|
new TransformStream<
|
|
3325
3526
|
EnrichedStreamPart<TOOLS, InferPartialOutput<OUTPUT>>,
|
|
@@ -3362,9 +3563,11 @@ class DefaultStreamTextResult<
|
|
|
3362
3563
|
}
|
|
3363
3564
|
|
|
3364
3565
|
async consumeStream(options?: ConsumeStreamOptions): Promise<void> {
|
|
3566
|
+
// A second consumer must not reject the first consumer's result promises.
|
|
3567
|
+
const stream = this.stream;
|
|
3365
3568
|
try {
|
|
3366
3569
|
await consumeStream({
|
|
3367
|
-
stream
|
|
3570
|
+
stream,
|
|
3368
3571
|
onError: error => {
|
|
3369
3572
|
this.rejectResultPromises(error);
|
|
3370
3573
|
options?.onError?.(error);
|
|
@@ -3383,7 +3586,13 @@ class DefaultStreamTextResult<
|
|
|
3383
3586
|
}
|
|
3384
3587
|
|
|
3385
3588
|
get partialOutputStream(): AsyncIterableStream<InferPartialOutput<OUTPUT>> {
|
|
3386
|
-
|
|
3589
|
+
if (!this.retention.replay && this.outputSpecification == null) {
|
|
3590
|
+
throw new UnsupportedFunctionalityError({
|
|
3591
|
+
functionality:
|
|
3592
|
+
'partialOutputStream without an explicit output specification with experimental_lowMemory enabled',
|
|
3593
|
+
});
|
|
3594
|
+
}
|
|
3595
|
+
return this.asIterableStream(
|
|
3387
3596
|
this.teeStream().pipeThrough(
|
|
3388
3597
|
new TransformStream<
|
|
3389
3598
|
EnrichedStreamPart<TOOLS, InferPartialOutput<OUTPUT>>,
|
|
@@ -3410,27 +3619,31 @@ class DefaultStreamTextResult<
|
|
|
3410
3619
|
});
|
|
3411
3620
|
}
|
|
3412
3621
|
|
|
3413
|
-
return
|
|
3622
|
+
return this.asIterableStream(this.teeStream().pipeThrough(transform));
|
|
3414
3623
|
}
|
|
3415
3624
|
|
|
3416
3625
|
private getOutputPromise(): Promise<InferCompleteOutput<OUTPUT>> {
|
|
3417
3626
|
if (this.outputPromise == null) {
|
|
3418
|
-
this.outputPromise = this.finalStep.then(step =>
|
|
3419
|
-
const output = this.outputSpecification ?? text();
|
|
3420
|
-
return output.parseCompleteOutput(
|
|
3421
|
-
{ text: step.text },
|
|
3422
|
-
{
|
|
3423
|
-
response: step.response,
|
|
3424
|
-
usage: step.usage,
|
|
3425
|
-
finishReason: step.finishReason,
|
|
3426
|
-
},
|
|
3427
|
-
);
|
|
3428
|
-
});
|
|
3627
|
+
this.outputPromise = this.finalStep.then(step => this.parseOutput(step));
|
|
3429
3628
|
}
|
|
3430
3629
|
|
|
3431
3630
|
return this.outputPromise;
|
|
3432
3631
|
}
|
|
3433
3632
|
|
|
3633
|
+
private parseOutput(
|
|
3634
|
+
step: StepResult<TOOLS, RUNTIME_CONTEXT>,
|
|
3635
|
+
): Promise<InferCompleteOutput<OUTPUT>> {
|
|
3636
|
+
const output = this.outputSpecification ?? text();
|
|
3637
|
+
return output.parseCompleteOutput(
|
|
3638
|
+
{ text: step.text },
|
|
3639
|
+
{
|
|
3640
|
+
response: step.response,
|
|
3641
|
+
usage: step.usage,
|
|
3642
|
+
finishReason: step.finishReason,
|
|
3643
|
+
},
|
|
3644
|
+
);
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3434
3647
|
get output(): Promise<InferCompleteOutput<OUTPUT>> {
|
|
3435
3648
|
return this.getOutputPromise();
|
|
3436
3649
|
}
|
package/src/ui/chat.ts
CHANGED
|
@@ -196,7 +196,7 @@ export type ChatOnFinishCallback<UI_MESSAGE extends UIMessage> = (options: {
|
|
|
196
196
|
export interface ChatInit<UI_MESSAGE extends UIMessage> {
|
|
197
197
|
/**
|
|
198
198
|
* A unique identifier for the chat. If not provided, a random one will be
|
|
199
|
-
* generated.
|
|
199
|
+
* generated when first accessed.
|
|
200
200
|
*/
|
|
201
201
|
id?: string;
|
|
202
202
|
|
|
@@ -249,7 +249,12 @@ export interface ChatInit<UI_MESSAGE extends UIMessage> {
|
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
|
|
252
|
-
|
|
252
|
+
private _id: string | undefined;
|
|
253
|
+
|
|
254
|
+
get id(): string {
|
|
255
|
+
return (this._id ??= this.generateId());
|
|
256
|
+
}
|
|
257
|
+
|
|
253
258
|
readonly generateId: IdGenerator;
|
|
254
259
|
|
|
255
260
|
protected state: ChatState<UI_MESSAGE>;
|
|
@@ -280,7 +285,7 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
|
|
|
280
285
|
|
|
281
286
|
constructor({
|
|
282
287
|
generateId = generateIdFunc,
|
|
283
|
-
id
|
|
288
|
+
id,
|
|
284
289
|
transport = new DefaultChatTransport(),
|
|
285
290
|
messageMetadataSchema,
|
|
286
291
|
dataPartSchemas,
|
|
@@ -293,7 +298,7 @@ export abstract class AbstractChat<UI_MESSAGE extends UIMessage> {
|
|
|
293
298
|
}: Omit<ChatInit<UI_MESSAGE>, 'messages'> & {
|
|
294
299
|
state: ChatState<UI_MESSAGE>;
|
|
295
300
|
}) {
|
|
296
|
-
this.
|
|
301
|
+
this._id = id;
|
|
297
302
|
this.transport = transport;
|
|
298
303
|
this.generateId = generateId;
|
|
299
304
|
this.messageMetadataSchema = messageMetadataSchema;
|