ai 7.0.142 → 7.0.144
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 +24 -0
- package/dist/index.d.ts +237 -204
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +211 -56
- 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 +28 -13
- package/docs/03-ai-sdk-harnesses/05-harness-adapters.mdx +12 -12
- package/docs/07-reference/01-ai-sdk-core/02-stream-text-low-memory.mdx +105 -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 +24 -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 +6 -4
- package/src/decide/decision-result.ts +6 -1
- package/src/decide/validate-decision.ts +39 -4
- package/src/generate-text/index.ts +1 -0
- 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 +219 -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,12 @@ 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
|
+
|
|
287
308
|
/**
|
|
288
309
|
* Generate a text and call tools for a given prompt using a language model.
|
|
289
310
|
*
|
|
@@ -356,6 +377,60 @@ export function streamText<
|
|
|
356
377
|
TOOLS extends ToolSet,
|
|
357
378
|
RUNTIME_CONTEXT extends Context = Context,
|
|
358
379
|
OUTPUT extends Output = Output<string, string, never>,
|
|
380
|
+
>(
|
|
381
|
+
options: StreamTextOptions<TOOLS, RUNTIME_CONTEXT, OUTPUT>,
|
|
382
|
+
): StreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
|
|
383
|
+
return streamTextInternal<TOOLS, RUNTIME_CONTEXT, OUTPUT>(options);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Stream text with a single consumer, without replay or final-content getters.
|
|
388
|
+
* Accepts the same options as streamText and uses the same execution engine.
|
|
389
|
+
*/
|
|
390
|
+
export function streamTextLowMemory<
|
|
391
|
+
TOOLS extends ToolSet,
|
|
392
|
+
RUNTIME_CONTEXT extends Context = Context,
|
|
393
|
+
OUTPUT extends Output = Output<string, string, never>,
|
|
394
|
+
>(
|
|
395
|
+
options: StreamTextOptions<TOOLS, RUNTIME_CONTEXT, OUTPUT>,
|
|
396
|
+
): StreamTextSingleConsumerResult<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
|
|
397
|
+
const telemetry = options.telemetry ?? options.experimental_telemetry;
|
|
398
|
+
const integrations =
|
|
399
|
+
telemetry?.integrations != null
|
|
400
|
+
? asArray(telemetry.integrations)
|
|
401
|
+
: getGlobalTelemetryIntegrations();
|
|
402
|
+
|
|
403
|
+
// Decide before execution so getter access cannot change collection.
|
|
404
|
+
const collectContent =
|
|
405
|
+
(options.tools != null && Object.keys(options.tools).length > 0) ||
|
|
406
|
+
options.toolChoice != null ||
|
|
407
|
+
options.output != null ||
|
|
408
|
+
options.prepareStep != null ||
|
|
409
|
+
options.stopWhen != null ||
|
|
410
|
+
options.onEnd != null ||
|
|
411
|
+
options.onFinish != null ||
|
|
412
|
+
options.onStepEnd != null ||
|
|
413
|
+
options.onStepFinish != null ||
|
|
414
|
+
options.onAbort != null ||
|
|
415
|
+
options.onLanguageModelCallEnd != null ||
|
|
416
|
+
options.experimental_onLanguageModelCallEnd != null ||
|
|
417
|
+
(telemetry?.isEnabled !== false && integrations.length > 0);
|
|
418
|
+
|
|
419
|
+
return createSingleConsumerStreamTextResult(
|
|
420
|
+
streamTextInternal<TOOLS, RUNTIME_CONTEXT, OUTPUT>({
|
|
421
|
+
...options,
|
|
422
|
+
_internal: {
|
|
423
|
+
...options._internal,
|
|
424
|
+
retention: { replay: false, collectContent },
|
|
425
|
+
},
|
|
426
|
+
}),
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function streamTextInternal<
|
|
431
|
+
TOOLS extends ToolSet,
|
|
432
|
+
RUNTIME_CONTEXT extends Context = Context,
|
|
433
|
+
OUTPUT extends Output = Output<string, string, never>,
|
|
359
434
|
>({
|
|
360
435
|
model,
|
|
361
436
|
tools,
|
|
@@ -416,6 +491,7 @@ export function streamText<
|
|
|
416
491
|
now = originalNow,
|
|
417
492
|
generateId = originalGenerateId,
|
|
418
493
|
generateCallId = originalGenerateCallId,
|
|
494
|
+
retention = { replay: true, collectContent: true },
|
|
419
495
|
} = {},
|
|
420
496
|
...settings
|
|
421
497
|
}: LanguageModelCallOptions &
|
|
@@ -781,6 +857,8 @@ export function streamText<
|
|
|
781
857
|
now?: () => number;
|
|
782
858
|
generateId?: IdGenerator;
|
|
783
859
|
generateCallId?: IdGenerator;
|
|
860
|
+
/** Internal policy used by the streaming-only facade. */
|
|
861
|
+
retention?: StreamTextRetention;
|
|
784
862
|
};
|
|
785
863
|
}): StreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT> {
|
|
786
864
|
const resolvedToolCallConcurrency =
|
|
@@ -812,6 +890,7 @@ export function streamText<
|
|
|
812
890
|
onToolExecutionEnd ?? experimental_onToolCallFinish;
|
|
813
891
|
const resolvedOnStepEnd = onStepEnd ?? onStepFinish;
|
|
814
892
|
return new DefaultStreamTextResult<TOOLS, RUNTIME_CONTEXT, OUTPUT>({
|
|
893
|
+
retention,
|
|
815
894
|
model: resolveLanguageModel(model),
|
|
816
895
|
telemetry,
|
|
817
896
|
headers,
|
|
@@ -922,6 +1001,7 @@ function createOutputTransformStream<
|
|
|
922
1001
|
OUTPUT extends Output,
|
|
923
1002
|
>(
|
|
924
1003
|
output: OUTPUT,
|
|
1004
|
+
collectOutput = true,
|
|
925
1005
|
): TransformStream<
|
|
926
1006
|
InternalTextStreamPart<TOOLS>,
|
|
927
1007
|
InternalEnrichedStreamPart<TOOLS, InferPartialOutput<OUTPUT>>
|
|
@@ -983,6 +1063,14 @@ function createOutputTransformStream<
|
|
|
983
1063
|
InternalEnrichedStreamPart<TOOLS, InferPartialOutput<OUTPUT>>
|
|
984
1064
|
>({
|
|
985
1065
|
async transform(chunk, controller) {
|
|
1066
|
+
if (!collectOutput) {
|
|
1067
|
+
controller.enqueue(
|
|
1068
|
+
isStreamRetryBoundaryPart(chunk)
|
|
1069
|
+
? chunk
|
|
1070
|
+
: { part: chunk, partialOutput: undefined },
|
|
1071
|
+
);
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
986
1074
|
if (isStreamRetryBoundaryPart(chunk)) {
|
|
987
1075
|
resetOutputState();
|
|
988
1076
|
controller.enqueue(chunk);
|
|
@@ -1204,7 +1292,11 @@ class DefaultStreamTextResult<
|
|
|
1204
1292
|
|
|
1205
1293
|
private tools: TOOLS | undefined;
|
|
1206
1294
|
|
|
1295
|
+
private readonly retention: StreamTextRetention;
|
|
1296
|
+
private streamClaimed = false;
|
|
1297
|
+
|
|
1207
1298
|
constructor({
|
|
1299
|
+
retention,
|
|
1208
1300
|
model,
|
|
1209
1301
|
telemetry,
|
|
1210
1302
|
headers,
|
|
@@ -1260,6 +1352,7 @@ class DefaultStreamTextResult<
|
|
|
1260
1352
|
download,
|
|
1261
1353
|
include,
|
|
1262
1354
|
}: {
|
|
1355
|
+
retention: StreamTextRetention;
|
|
1263
1356
|
model: LanguageModelV4;
|
|
1264
1357
|
telemetry: TelemetryOptions<RUNTIME_CONTEXT, TOOLS> | undefined;
|
|
1265
1358
|
headers: Record<string, string | undefined> | undefined;
|
|
@@ -1348,6 +1441,7 @@ class DefaultStreamTextResult<
|
|
|
1348
1441
|
onToolExecutionStart: undefined | OnToolExecutionStartCallback<TOOLS>;
|
|
1349
1442
|
onToolExecutionEnd: undefined | OnToolExecutionEndCallback<TOOLS>;
|
|
1350
1443
|
}) {
|
|
1444
|
+
this.retention = retention;
|
|
1351
1445
|
this.outputSpecification = output;
|
|
1352
1446
|
this.tools = tools;
|
|
1353
1447
|
const resolvedToolCallers = resolveToolCallerConfiguration({
|
|
@@ -1381,7 +1475,7 @@ class DefaultStreamTextResult<
|
|
|
1381
1475
|
let recordedRequest: Omit<LanguageModelRequestMetadata, 'messages'> = {};
|
|
1382
1476
|
let recordedRequestMessages: Array<ModelMessage> = [];
|
|
1383
1477
|
let recordedWarnings: Array<CallWarning> = [];
|
|
1384
|
-
|
|
1478
|
+
let recordedSteps: StepResult<TOOLS, RUNTIME_CONTEXT>[] = [];
|
|
1385
1479
|
const initialResponseMessages: Array<ResponseMessage> = [];
|
|
1386
1480
|
let stepMessagesForNextStep: Array<ModelMessage> | undefined;
|
|
1387
1481
|
let currentStepMessages: Array<ModelMessage> = [];
|
|
@@ -1499,7 +1593,7 @@ class DefaultStreamTextResult<
|
|
|
1499
1593
|
part.type === 'tool-approval-response' ||
|
|
1500
1594
|
part.type === 'tool-error'
|
|
1501
1595
|
) {
|
|
1502
|
-
recordedContent.push(part);
|
|
1596
|
+
if (retention.collectContent) recordedContent.push(part);
|
|
1503
1597
|
}
|
|
1504
1598
|
|
|
1505
1599
|
if (part.type === 'text-start') {
|
|
@@ -1509,7 +1603,8 @@ class DefaultStreamTextResult<
|
|
|
1509
1603
|
providerMetadata: part.providerMetadata,
|
|
1510
1604
|
};
|
|
1511
1605
|
|
|
1512
|
-
|
|
1606
|
+
if (retention.collectContent)
|
|
1607
|
+
recordedContent.push(activeTextContent[part.id]);
|
|
1513
1608
|
}
|
|
1514
1609
|
|
|
1515
1610
|
if (part.type === 'text-delta') {
|
|
@@ -1526,7 +1621,7 @@ class DefaultStreamTextResult<
|
|
|
1526
1621
|
return;
|
|
1527
1622
|
}
|
|
1528
1623
|
|
|
1529
|
-
activeText.text += part.text;
|
|
1624
|
+
if (retention.collectContent) activeText.text += part.text;
|
|
1530
1625
|
activeText.providerMetadata =
|
|
1531
1626
|
part.providerMetadata ?? activeText.providerMetadata;
|
|
1532
1627
|
}
|
|
@@ -1562,7 +1657,8 @@ class DefaultStreamTextResult<
|
|
|
1562
1657
|
providerMetadata: part.providerMetadata,
|
|
1563
1658
|
};
|
|
1564
1659
|
|
|
1565
|
-
|
|
1660
|
+
if (retention.collectContent)
|
|
1661
|
+
recordedContent.push(activeReasoningContent[part.id]);
|
|
1566
1662
|
}
|
|
1567
1663
|
|
|
1568
1664
|
if (part.type === 'reasoning-delta') {
|
|
@@ -1579,7 +1675,7 @@ class DefaultStreamTextResult<
|
|
|
1579
1675
|
return;
|
|
1580
1676
|
}
|
|
1581
1677
|
|
|
1582
|
-
activeReasoning.text += part.text;
|
|
1678
|
+
if (retention.collectContent) activeReasoning.text += part.text;
|
|
1583
1679
|
activeReasoning.providerMetadata =
|
|
1584
1680
|
part.providerMetadata ?? activeReasoning.providerMetadata;
|
|
1585
1681
|
}
|
|
@@ -1605,17 +1701,18 @@ class DefaultStreamTextResult<
|
|
|
1605
1701
|
}
|
|
1606
1702
|
|
|
1607
1703
|
if (part.type === 'file' || part.type === 'reasoning-file') {
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1704
|
+
if (retention.collectContent)
|
|
1705
|
+
recordedContent.push({
|
|
1706
|
+
type: part.type,
|
|
1707
|
+
file: part.file,
|
|
1708
|
+
...(part.providerMetadata != null
|
|
1709
|
+
? { providerMetadata: part.providerMetadata }
|
|
1710
|
+
: {}),
|
|
1711
|
+
});
|
|
1615
1712
|
}
|
|
1616
1713
|
|
|
1617
1714
|
if (part.type === 'tool-result' && !part.preliminary) {
|
|
1618
|
-
recordedContent.push(part);
|
|
1715
|
+
if (retention.collectContent) recordedContent.push(part);
|
|
1619
1716
|
}
|
|
1620
1717
|
|
|
1621
1718
|
if (part.type === 'start-step') {
|
|
@@ -1719,7 +1816,7 @@ class DefaultStreamTextResult<
|
|
|
1719
1816
|
self._totalUsage.resolve(totalUsage);
|
|
1720
1817
|
|
|
1721
1818
|
// aggregate results:
|
|
1722
|
-
self._steps.resolve(recordedSteps);
|
|
1819
|
+
self._steps.resolve(retention.replay ? recordedSteps : []);
|
|
1723
1820
|
|
|
1724
1821
|
if (isAborted) {
|
|
1725
1822
|
return;
|
|
@@ -1752,7 +1849,11 @@ class DefaultStreamTextResult<
|
|
|
1752
1849
|
const parsedOutput =
|
|
1753
1850
|
output == null
|
|
1754
1851
|
? undefined
|
|
1755
|
-
: await
|
|
1852
|
+
: await (
|
|
1853
|
+
retention.replay
|
|
1854
|
+
? self.getOutputPromise()
|
|
1855
|
+
: self.parseOutput(finalStep)
|
|
1856
|
+
).catch(() => undefined);
|
|
1756
1857
|
|
|
1757
1858
|
await onEnd({
|
|
1758
1859
|
...event,
|
|
@@ -1806,6 +1907,17 @@ class DefaultStreamTextResult<
|
|
|
1806
1907
|
]);
|
|
1807
1908
|
} catch (error) {
|
|
1808
1909
|
controller.error(error);
|
|
1910
|
+
} finally {
|
|
1911
|
+
if (!retention.replay) {
|
|
1912
|
+
// Replace our references; never mutate arrays delivered to callbacks.
|
|
1913
|
+
recordedSteps = [];
|
|
1914
|
+
recordedContent = [];
|
|
1915
|
+
recordedRequestMessages = [];
|
|
1916
|
+
currentStepMessages = [];
|
|
1917
|
+
stepMessagesForNextStep = undefined;
|
|
1918
|
+
activeTextContent = createIdMap();
|
|
1919
|
+
activeReasoningContent = createIdMap();
|
|
1920
|
+
}
|
|
1809
1921
|
}
|
|
1810
1922
|
},
|
|
1811
1923
|
});
|
|
@@ -1924,7 +2036,12 @@ class DefaultStreamTextResult<
|
|
|
1924
2036
|
});
|
|
1925
2037
|
|
|
1926
2038
|
this.baseStream = stream
|
|
1927
|
-
.pipeThrough(
|
|
2039
|
+
.pipeThrough(
|
|
2040
|
+
createOutputTransformStream(
|
|
2041
|
+
output ?? text(),
|
|
2042
|
+
retention.replay || output != null,
|
|
2043
|
+
),
|
|
2044
|
+
)
|
|
1928
2045
|
.pipeThrough(eventProcessor);
|
|
1929
2046
|
|
|
1930
2047
|
const { maxRetries } = prepareRetries({
|
|
@@ -2474,6 +2591,7 @@ class DefaultStreamTextResult<
|
|
|
2474
2591
|
},
|
|
2475
2592
|
_internal: {
|
|
2476
2593
|
now,
|
|
2594
|
+
collectContent: retention.collectContent,
|
|
2477
2595
|
},
|
|
2478
2596
|
...stepCallSettings,
|
|
2479
2597
|
}),
|
|
@@ -3179,7 +3297,7 @@ class DefaultStreamTextResult<
|
|
|
3179
3297
|
get steps() {
|
|
3180
3298
|
// when any of the promises are accessed, the stream is consumed
|
|
3181
3299
|
// so it resolves without needing to consume the stream separately
|
|
3182
|
-
this.consumeStream();
|
|
3300
|
+
if (this.retention.replay) this.consumeStream();
|
|
3183
3301
|
|
|
3184
3302
|
return this._steps.promise;
|
|
3185
3303
|
}
|
|
@@ -3279,7 +3397,7 @@ class DefaultStreamTextResult<
|
|
|
3279
3397
|
get totalUsage() {
|
|
3280
3398
|
// when any of the promises are accessed, the stream is consumed
|
|
3281
3399
|
// so it resolves without needing to consume the stream separately
|
|
3282
|
-
this.consumeStream();
|
|
3400
|
+
if (this.retention.replay) this.consumeStream();
|
|
3283
3401
|
|
|
3284
3402
|
return this._totalUsage.promise;
|
|
3285
3403
|
}
|
|
@@ -3287,7 +3405,7 @@ class DefaultStreamTextResult<
|
|
|
3287
3405
|
get finishReason() {
|
|
3288
3406
|
// when any of the promises are accessed, the stream is consumed
|
|
3289
3407
|
// so it resolves without needing to consume the stream separately
|
|
3290
|
-
this.consumeStream();
|
|
3408
|
+
if (this.retention.replay) this.consumeStream();
|
|
3291
3409
|
|
|
3292
3410
|
return this._finishReason.promise;
|
|
3293
3411
|
}
|
|
@@ -3295,7 +3413,7 @@ class DefaultStreamTextResult<
|
|
|
3295
3413
|
get rawFinishReason() {
|
|
3296
3414
|
// when any of the promises are accessed, the stream is consumed
|
|
3297
3415
|
// so it resolves without needing to consume the stream separately
|
|
3298
|
-
this.consumeStream();
|
|
3416
|
+
if (this.retention.replay) this.consumeStream();
|
|
3299
3417
|
|
|
3300
3418
|
return this._rawFinishReason.promise;
|
|
3301
3419
|
}
|
|
@@ -3309,17 +3427,69 @@ class DefaultStreamTextResult<
|
|
|
3309
3427
|
* However, the LLM results are expected to be small enough to not cause issues.
|
|
3310
3428
|
*/
|
|
3311
3429
|
private teeStream() {
|
|
3430
|
+
if (!this.retention.replay) {
|
|
3431
|
+
if (this.streamClaimed) {
|
|
3432
|
+
throw new AISDKError({
|
|
3433
|
+
name: 'AI_StreamAlreadyConsumedError',
|
|
3434
|
+
message:
|
|
3435
|
+
'This result supports one stream consumer. Choose one stream projection or response helper.',
|
|
3436
|
+
});
|
|
3437
|
+
}
|
|
3438
|
+
this.streamClaimed = true;
|
|
3439
|
+
const reader = this.baseStream.getReader();
|
|
3440
|
+
const rejectResults = (error: unknown) =>
|
|
3441
|
+
this.rejectResultPromises(error);
|
|
3442
|
+
return new ReadableStream(
|
|
3443
|
+
{
|
|
3444
|
+
async pull(controller) {
|
|
3445
|
+
try {
|
|
3446
|
+
const { done, value } = await reader.read();
|
|
3447
|
+
if (done) {
|
|
3448
|
+
reader.releaseLock();
|
|
3449
|
+
controller.close();
|
|
3450
|
+
} else {
|
|
3451
|
+
controller.enqueue(value);
|
|
3452
|
+
}
|
|
3453
|
+
} catch (error) {
|
|
3454
|
+
rejectResults(error);
|
|
3455
|
+
reader.releaseLock();
|
|
3456
|
+
controller.error(error);
|
|
3457
|
+
}
|
|
3458
|
+
},
|
|
3459
|
+
async cancel(reason) {
|
|
3460
|
+
rejectResults(
|
|
3461
|
+
reason ??
|
|
3462
|
+
new DOMException('The stream was cancelled.', 'AbortError'),
|
|
3463
|
+
);
|
|
3464
|
+
try {
|
|
3465
|
+
await reader.cancel(reason);
|
|
3466
|
+
} finally {
|
|
3467
|
+
reader.releaseLock();
|
|
3468
|
+
}
|
|
3469
|
+
},
|
|
3470
|
+
},
|
|
3471
|
+
{ highWaterMark: 0 },
|
|
3472
|
+
);
|
|
3473
|
+
}
|
|
3312
3474
|
const [stream1, stream2] = this.baseStream.tee();
|
|
3313
3475
|
this.baseStream = stream2;
|
|
3314
3476
|
return stream1;
|
|
3315
3477
|
}
|
|
3316
3478
|
|
|
3317
3479
|
get textStream(): AsyncIterableStream<string> {
|
|
3318
|
-
return
|
|
3480
|
+
return this.asIterableStream(toTextStream({ stream: this.stream }));
|
|
3481
|
+
}
|
|
3482
|
+
|
|
3483
|
+
private asIterableStream<T>(
|
|
3484
|
+
stream: ReadableStream<T>,
|
|
3485
|
+
): AsyncIterableStream<T> {
|
|
3486
|
+
return this.retention.replay
|
|
3487
|
+
? createAsyncIterableStream(stream)
|
|
3488
|
+
: asAsyncIterableStream(stream);
|
|
3319
3489
|
}
|
|
3320
3490
|
|
|
3321
3491
|
get stream(): AsyncIterableStream<TextStreamPart<TOOLS>> {
|
|
3322
|
-
return
|
|
3492
|
+
return this.asIterableStream(
|
|
3323
3493
|
this.teeStream().pipeThrough(
|
|
3324
3494
|
new TransformStream<
|
|
3325
3495
|
EnrichedStreamPart<TOOLS, InferPartialOutput<OUTPUT>>,
|
|
@@ -3362,9 +3532,11 @@ class DefaultStreamTextResult<
|
|
|
3362
3532
|
}
|
|
3363
3533
|
|
|
3364
3534
|
async consumeStream(options?: ConsumeStreamOptions): Promise<void> {
|
|
3535
|
+
// A second consumer must not reject the first consumer's result promises.
|
|
3536
|
+
const stream = this.stream;
|
|
3365
3537
|
try {
|
|
3366
3538
|
await consumeStream({
|
|
3367
|
-
stream
|
|
3539
|
+
stream,
|
|
3368
3540
|
onError: error => {
|
|
3369
3541
|
this.rejectResultPromises(error);
|
|
3370
3542
|
options?.onError?.(error);
|
|
@@ -3383,7 +3555,13 @@ class DefaultStreamTextResult<
|
|
|
3383
3555
|
}
|
|
3384
3556
|
|
|
3385
3557
|
get partialOutputStream(): AsyncIterableStream<InferPartialOutput<OUTPUT>> {
|
|
3386
|
-
|
|
3558
|
+
if (!this.retention.replay && this.outputSpecification == null) {
|
|
3559
|
+
throw new UnsupportedFunctionalityError({
|
|
3560
|
+
functionality:
|
|
3561
|
+
'partialOutputStream without an explicit output specification with experimental_streamTextLowMemory',
|
|
3562
|
+
});
|
|
3563
|
+
}
|
|
3564
|
+
return this.asIterableStream(
|
|
3387
3565
|
this.teeStream().pipeThrough(
|
|
3388
3566
|
new TransformStream<
|
|
3389
3567
|
EnrichedStreamPart<TOOLS, InferPartialOutput<OUTPUT>>,
|
|
@@ -3410,27 +3588,31 @@ class DefaultStreamTextResult<
|
|
|
3410
3588
|
});
|
|
3411
3589
|
}
|
|
3412
3590
|
|
|
3413
|
-
return
|
|
3591
|
+
return this.asIterableStream(this.teeStream().pipeThrough(transform));
|
|
3414
3592
|
}
|
|
3415
3593
|
|
|
3416
3594
|
private getOutputPromise(): Promise<InferCompleteOutput<OUTPUT>> {
|
|
3417
3595
|
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
|
-
});
|
|
3596
|
+
this.outputPromise = this.finalStep.then(step => this.parseOutput(step));
|
|
3429
3597
|
}
|
|
3430
3598
|
|
|
3431
3599
|
return this.outputPromise;
|
|
3432
3600
|
}
|
|
3433
3601
|
|
|
3602
|
+
private parseOutput(
|
|
3603
|
+
step: StepResult<TOOLS, RUNTIME_CONTEXT>,
|
|
3604
|
+
): Promise<InferCompleteOutput<OUTPUT>> {
|
|
3605
|
+
const output = this.outputSpecification ?? text();
|
|
3606
|
+
return output.parseCompleteOutput(
|
|
3607
|
+
{ text: step.text },
|
|
3608
|
+
{
|
|
3609
|
+
response: step.response,
|
|
3610
|
+
usage: step.usage,
|
|
3611
|
+
finishReason: step.finishReason,
|
|
3612
|
+
},
|
|
3613
|
+
);
|
|
3614
|
+
}
|
|
3615
|
+
|
|
3434
3616
|
get output(): Promise<InferCompleteOutput<OUTPUT>> {
|
|
3435
3617
|
return this.getOutputPromise();
|
|
3436
3618
|
}
|
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;
|