ai 5.0.0-canary.21 → 5.0.0-canary.23

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/dist/index.mjs CHANGED
@@ -12,172 +12,6 @@ import {
12
12
  jsonSchema as jsonSchema2
13
13
  } from "@ai-sdk/provider-utils";
14
14
 
15
- // src/data-stream/create-data-stream.ts
16
- function createDataStream({
17
- execute,
18
- onError = () => "An error occurred."
19
- // mask error messages for safety by default
20
- }) {
21
- let controller;
22
- const ongoingStreamPromises = [];
23
- const stream = new ReadableStream({
24
- start(controllerArg) {
25
- controller = controllerArg;
26
- }
27
- });
28
- function safeEnqueue(data) {
29
- try {
30
- controller.enqueue(data);
31
- } catch (error) {
32
- }
33
- }
34
- try {
35
- const result = execute({
36
- write(part) {
37
- safeEnqueue(part);
38
- },
39
- merge(streamArg) {
40
- ongoingStreamPromises.push(
41
- (async () => {
42
- const reader = streamArg.getReader();
43
- while (true) {
44
- const { done, value } = await reader.read();
45
- if (done)
46
- break;
47
- safeEnqueue(value);
48
- }
49
- })().catch((error) => {
50
- safeEnqueue({ type: "error", value: onError(error) });
51
- })
52
- );
53
- },
54
- onError
55
- });
56
- if (result) {
57
- ongoingStreamPromises.push(
58
- result.catch((error) => {
59
- safeEnqueue({ type: "error", value: onError(error) });
60
- })
61
- );
62
- }
63
- } catch (error) {
64
- safeEnqueue({ type: "error", value: onError(error) });
65
- }
66
- const waitForStreams = new Promise(async (resolve) => {
67
- while (ongoingStreamPromises.length > 0) {
68
- await ongoingStreamPromises.shift();
69
- }
70
- resolve();
71
- });
72
- waitForStreams.finally(() => {
73
- try {
74
- controller.close();
75
- } catch (error) {
76
- }
77
- });
78
- return stream;
79
- }
80
-
81
- // src/util/prepare-headers.ts
82
- function prepareHeaders(headers, defaultHeaders) {
83
- const responseHeaders = new Headers(headers != null ? headers : {});
84
- for (const [key, value] of Object.entries(defaultHeaders)) {
85
- if (!responseHeaders.has(key)) {
86
- responseHeaders.set(key, value);
87
- }
88
- }
89
- return responseHeaders;
90
- }
91
-
92
- // src/data-stream/data-stream-headers.ts
93
- var dataStreamHeaders = {
94
- "content-type": "text/event-stream",
95
- "cache-control": "no-cache",
96
- connection: "keep-alive",
97
- "x-vercel-ai-data-stream": "v2",
98
- "x-accel-buffering": "no"
99
- // disable nginx buffering
100
- };
101
-
102
- // src/data-stream/json-to-sse-transform-stream.ts
103
- var JsonToSseTransformStream = class extends TransformStream {
104
- constructor() {
105
- super({
106
- transform(part, controller) {
107
- controller.enqueue(`data: ${JSON.stringify(part)}
108
-
109
- `);
110
- },
111
- flush(controller) {
112
- controller.enqueue("data: [DONE]\n\n");
113
- }
114
- });
115
- }
116
- };
117
-
118
- // src/data-stream/create-data-stream-response.ts
119
- function createDataStreamResponse({
120
- status,
121
- statusText,
122
- headers,
123
- dataStream
124
- }) {
125
- return new Response(
126
- dataStream.pipeThrough(new JsonToSseTransformStream()).pipeThrough(new TextEncoderStream()),
127
- {
128
- status,
129
- statusText,
130
- headers: prepareHeaders(headers, dataStreamHeaders)
131
- }
132
- );
133
- }
134
-
135
- // src/util/write-to-server-response.ts
136
- function writeToServerResponse({
137
- response,
138
- status,
139
- statusText,
140
- headers,
141
- stream
142
- }) {
143
- response.writeHead(status != null ? status : 200, statusText, headers);
144
- const reader = stream.getReader();
145
- const read = async () => {
146
- try {
147
- while (true) {
148
- const { done, value } = await reader.read();
149
- if (done)
150
- break;
151
- response.write(value);
152
- }
153
- } catch (error) {
154
- throw error;
155
- } finally {
156
- response.end();
157
- }
158
- };
159
- read();
160
- }
161
-
162
- // src/data-stream/pipe-data-stream-to-response.ts
163
- function pipeDataStreamToResponse({
164
- response,
165
- status,
166
- statusText,
167
- headers,
168
- dataStream
169
- }) {
170
- writeToServerResponse({
171
- response,
172
- status,
173
- statusText,
174
- headers: Object.fromEntries(
175
- prepareHeaders(headers, dataStreamHeaders).entries()
176
- ),
177
- stream: dataStream.pipeThrough(new JsonToSseTransformStream()).pipeThrough(new TextEncoderStream())
178
- });
179
- }
180
-
181
15
  // src/error/index.ts
182
16
  import {
183
17
  AISDKError as AISDKError16,
@@ -540,6 +374,17 @@ var RetryError = class extends AISDKError15 {
540
374
  };
541
375
  _a15 = symbol15;
542
376
 
377
+ // src/util/prepare-headers.ts
378
+ function prepareHeaders(headers, defaultHeaders) {
379
+ const responseHeaders = new Headers(headers != null ? headers : {});
380
+ for (const [key, value] of Object.entries(defaultHeaders)) {
381
+ if (!responseHeaders.has(key)) {
382
+ responseHeaders.set(key, value);
383
+ }
384
+ }
385
+ return responseHeaders;
386
+ }
387
+
543
388
  // src/text-stream/create-text-stream-response.ts
544
389
  function createTextStreamResponse({
545
390
  status,
@@ -556,6 +401,33 @@ function createTextStreamResponse({
556
401
  });
557
402
  }
558
403
 
404
+ // src/util/write-to-server-response.ts
405
+ function writeToServerResponse({
406
+ response,
407
+ status,
408
+ statusText,
409
+ headers,
410
+ stream
411
+ }) {
412
+ response.writeHead(status != null ? status : 200, statusText, headers);
413
+ const reader = stream.getReader();
414
+ const read = async () => {
415
+ try {
416
+ while (true) {
417
+ const { done, value } = await reader.read();
418
+ if (done)
419
+ break;
420
+ response.write(value);
421
+ }
422
+ } catch (error) {
423
+ throw error;
424
+ } finally {
425
+ response.end();
426
+ }
427
+ };
428
+ read();
429
+ }
430
+
559
431
  // src/text-stream/pipe-text-stream-to-response.ts
560
432
  function pipeTextStreamToResponse({
561
433
  response,
@@ -593,7 +465,7 @@ import {
593
465
  parseJsonEventStream
594
466
  } from "@ai-sdk/provider-utils";
595
467
 
596
- // src/data-stream/data-stream-parts.ts
468
+ // src/ui-message-stream/ui-message-stream-parts.ts
597
469
  import { z } from "zod";
598
470
  var toolCallSchema = z.object({
599
471
  toolCallId: z.string(),
@@ -614,7 +486,7 @@ var sourceSchema = z.object({
614
486
  providerMetadata: z.any().optional()
615
487
  // Use z.any() for generic metadata
616
488
  });
617
- var dataStreamPartSchema = z.discriminatedUnion("type", [
489
+ var uiMessageStreamPartSchema = z.discriminatedUnion("type", [
618
490
  z.object({
619
491
  type: z.literal("text"),
620
492
  value: z.string()
@@ -713,7 +585,7 @@ async function consumeStream({
713
585
  }
714
586
  }
715
587
 
716
- // src/ui/process-chat-response.ts
588
+ // src/ui/process-ui-message-stream.ts
717
589
  import { validateTypes } from "@ai-sdk/provider-utils";
718
590
 
719
591
  // src/util/merge-objects.ts
@@ -1101,305 +973,283 @@ function getToolInvocations(message) {
1101
973
  ).map((part) => part.toolInvocation);
1102
974
  }
1103
975
 
1104
- // src/ui/process-chat-response.ts
1105
- function processChatResponse({
1106
- stream,
1107
- onUpdate,
1108
- onToolCall,
1109
- onFinish,
976
+ // src/ui/process-ui-message-stream.ts
977
+ function createStreamingUIMessageState({
1110
978
  lastMessage,
1111
- newMessageId,
1112
- messageMetadataSchema
1113
- }) {
979
+ newMessageId = "no-id"
980
+ } = {}) {
1114
981
  var _a17;
1115
982
  const isContinuation = (lastMessage == null ? void 0 : lastMessage.role) === "assistant";
1116
- let step = isContinuation ? 1 + ((_a17 = extractMaxToolInvocationStep(getToolInvocations(lastMessage))) != null ? _a17 : 0) : 0;
983
+ const step = isContinuation ? 1 + ((_a17 = extractMaxToolInvocationStep(getToolInvocations(lastMessage))) != null ? _a17 : 0) : 0;
1117
984
  const message = isContinuation ? structuredClone(lastMessage) : {
1118
985
  id: newMessageId,
1119
986
  metadata: {},
1120
987
  role: "assistant",
1121
988
  parts: []
1122
989
  };
1123
- let currentTextPart = void 0;
1124
- let currentReasoningPart = void 0;
1125
- function updateToolInvocationPart(toolCallId, invocation) {
1126
- const part = message.parts.find(
1127
- (part2) => part2.type === "tool-invocation" && part2.toolInvocation.toolCallId === toolCallId
1128
- );
1129
- if (part != null) {
1130
- part.toolInvocation = invocation;
1131
- } else {
1132
- message.parts.push({
1133
- type: "tool-invocation",
1134
- toolInvocation: invocation
1135
- });
1136
- }
1137
- }
1138
- const partialToolCalls = {};
1139
- async function updateMessageMetadata(metadata) {
1140
- if (metadata != null) {
1141
- const mergedMetadata = message.metadata != null ? mergeObjects(message.metadata, metadata) : metadata;
1142
- if (messageMetadataSchema != null) {
1143
- await validateTypes({
1144
- value: mergedMetadata,
1145
- schema: messageMetadataSchema
1146
- });
1147
- }
1148
- message.metadata = mergedMetadata;
1149
- }
1150
- }
990
+ return {
991
+ message,
992
+ activeTextPart: void 0,
993
+ activeReasoningPart: void 0,
994
+ partialToolCalls: {},
995
+ step
996
+ };
997
+ }
998
+ function processUIMessageStream({
999
+ stream,
1000
+ onToolCall,
1001
+ messageMetadataSchema,
1002
+ runUpdateMessageJob
1003
+ }) {
1151
1004
  return stream.pipeThrough(
1152
1005
  new TransformStream({
1153
1006
  async transform(chunk, controller) {
1154
- const { type, value } = chunk;
1155
- switch (type) {
1156
- case "text": {
1157
- if (currentTextPart == null) {
1158
- currentTextPart = {
1159
- type: "text",
1160
- text: value
1161
- };
1162
- message.parts.push(currentTextPart);
1163
- } else {
1164
- currentTextPart.text += value;
1165
- }
1166
- onUpdate == null ? void 0 : onUpdate({ message });
1167
- break;
1168
- }
1169
- case "reasoning": {
1170
- if (currentReasoningPart == null) {
1171
- currentReasoningPart = {
1172
- type: "reasoning",
1173
- text: value.text,
1174
- providerMetadata: value.providerMetadata
1175
- };
1176
- message.parts.push(currentReasoningPart);
1007
+ await runUpdateMessageJob(async ({ state, write }) => {
1008
+ function updateToolInvocationPart(toolCallId, invocation) {
1009
+ const part = state.message.parts.find(
1010
+ (part2) => part2.type === "tool-invocation" && part2.toolInvocation.toolCallId === toolCallId
1011
+ );
1012
+ if (part != null) {
1013
+ part.toolInvocation = invocation;
1177
1014
  } else {
1178
- currentReasoningPart.text += value.text;
1179
- currentReasoningPart.providerMetadata = value.providerMetadata;
1180
- }
1181
- onUpdate == null ? void 0 : onUpdate({ message });
1182
- break;
1183
- }
1184
- case "reasoning-part-finish": {
1185
- if (currentReasoningPart != null) {
1186
- currentReasoningPart = void 0;
1015
+ state.message.parts.push({
1016
+ type: "tool-invocation",
1017
+ toolInvocation: invocation
1018
+ });
1187
1019
  }
1188
- break;
1189
- }
1190
- case "file": {
1191
- message.parts.push({
1192
- type: "file",
1193
- mediaType: value.mediaType,
1194
- url: value.url
1195
- });
1196
- onUpdate == null ? void 0 : onUpdate({ message });
1197
- break;
1198
- }
1199
- case "source": {
1200
- message.parts.push({
1201
- type: "source",
1202
- source: value
1203
- });
1204
- onUpdate == null ? void 0 : onUpdate({ message });
1205
- break;
1206
- }
1207
- case "tool-call-streaming-start": {
1208
- const toolInvocations = getToolInvocations(message);
1209
- partialToolCalls[value.toolCallId] = {
1210
- text: "",
1211
- step,
1212
- toolName: value.toolName,
1213
- index: toolInvocations.length
1214
- };
1215
- updateToolInvocationPart(value.toolCallId, {
1216
- state: "partial-call",
1217
- step,
1218
- toolCallId: value.toolCallId,
1219
- toolName: value.toolName,
1220
- args: void 0
1221
- });
1222
- onUpdate == null ? void 0 : onUpdate({ message });
1223
- break;
1224
- }
1225
- case "tool-call-delta": {
1226
- const partialToolCall = partialToolCalls[value.toolCallId];
1227
- partialToolCall.text += value.argsTextDelta;
1228
- const { value: partialArgs } = await parsePartialJson(
1229
- partialToolCall.text
1230
- );
1231
- updateToolInvocationPart(value.toolCallId, {
1232
- state: "partial-call",
1233
- step: partialToolCall.step,
1234
- toolCallId: value.toolCallId,
1235
- toolName: partialToolCall.toolName,
1236
- args: partialArgs
1237
- });
1238
- onUpdate == null ? void 0 : onUpdate({ message });
1239
- break;
1240
1020
  }
1241
- case "tool-call": {
1242
- const call = { args: value.args, ...value };
1243
- updateToolInvocationPart(value.toolCallId, {
1244
- state: "call",
1245
- step,
1246
- ...call
1247
- });
1248
- onUpdate == null ? void 0 : onUpdate({ message });
1249
- if (onToolCall) {
1250
- const result = await onToolCall({
1251
- toolCall: call
1252
- });
1253
- if (result != null) {
1254
- updateToolInvocationPart(value.toolCallId, {
1255
- state: "result",
1256
- step,
1257
- ...call,
1258
- result
1021
+ async function updateMessageMetadata(metadata) {
1022
+ if (metadata != null) {
1023
+ const mergedMetadata = state.message.metadata != null ? mergeObjects(state.message.metadata, metadata) : metadata;
1024
+ if (messageMetadataSchema != null) {
1025
+ await validateTypes({
1026
+ value: mergedMetadata,
1027
+ schema: messageMetadataSchema
1259
1028
  });
1260
- onUpdate == null ? void 0 : onUpdate({ message });
1261
1029
  }
1030
+ state.message.metadata = mergedMetadata;
1262
1031
  }
1263
- break;
1264
1032
  }
1265
- case "tool-result": {
1266
- const toolInvocations = getToolInvocations(message);
1267
- if (toolInvocations == null) {
1268
- throw new Error("tool_result must be preceded by a tool_call");
1033
+ const { type, value } = chunk;
1034
+ switch (type) {
1035
+ case "text": {
1036
+ if (state.activeTextPart == null) {
1037
+ state.activeTextPart = {
1038
+ type: "text",
1039
+ text: value
1040
+ };
1041
+ state.message.parts.push(state.activeTextPart);
1042
+ } else {
1043
+ state.activeTextPart.text += value;
1044
+ }
1045
+ write();
1046
+ break;
1269
1047
  }
1270
- const toolInvocationIndex = toolInvocations.findIndex(
1271
- (invocation) => invocation.toolCallId === value.toolCallId
1272
- );
1273
- if (toolInvocationIndex === -1) {
1274
- throw new Error(
1275
- "tool_result must be preceded by a tool_call with the same toolCallId"
1276
- );
1048
+ case "reasoning": {
1049
+ if (state.activeReasoningPart == null) {
1050
+ state.activeReasoningPart = {
1051
+ type: "reasoning",
1052
+ text: value.text,
1053
+ providerMetadata: value.providerMetadata
1054
+ };
1055
+ state.message.parts.push(state.activeReasoningPart);
1056
+ } else {
1057
+ state.activeReasoningPart.text += value.text;
1058
+ state.activeReasoningPart.providerMetadata = value.providerMetadata;
1059
+ }
1060
+ write();
1061
+ break;
1277
1062
  }
1278
- const result = { result: value.result, ...value };
1279
- updateToolInvocationPart(value.toolCallId, {
1280
- ...toolInvocations[toolInvocationIndex],
1281
- state: "result",
1282
- ...result
1283
- });
1284
- onUpdate == null ? void 0 : onUpdate({ message });
1285
- break;
1286
- }
1287
- case "start-step": {
1288
- message.parts.push({ type: "step-start" });
1289
- await updateMessageMetadata(value.metadata);
1290
- onUpdate == null ? void 0 : onUpdate({ message });
1291
- break;
1292
- }
1293
- case "finish-step": {
1294
- step += 1;
1295
- currentTextPart = void 0;
1296
- currentReasoningPart = void 0;
1297
- await updateMessageMetadata(value.metadata);
1298
- if (value.metadata != null) {
1299
- onUpdate == null ? void 0 : onUpdate({ message });
1063
+ case "reasoning-part-finish": {
1064
+ if (state.activeReasoningPart != null) {
1065
+ state.activeReasoningPart = void 0;
1066
+ }
1067
+ break;
1300
1068
  }
1301
- break;
1302
- }
1303
- case "start": {
1304
- if (value.messageId != null) {
1305
- message.id = value.messageId;
1069
+ case "file": {
1070
+ state.message.parts.push({
1071
+ type: "file",
1072
+ mediaType: value.mediaType,
1073
+ url: value.url
1074
+ });
1075
+ write();
1076
+ break;
1306
1077
  }
1307
- await updateMessageMetadata(value.metadata);
1308
- if (value.messageId != null || value.metadata != null) {
1309
- onUpdate == null ? void 0 : onUpdate({ message });
1078
+ case "source": {
1079
+ state.message.parts.push({
1080
+ type: "source",
1081
+ source: value
1082
+ });
1083
+ write();
1084
+ break;
1310
1085
  }
1311
- break;
1312
- }
1313
- case "finish": {
1314
- await updateMessageMetadata(value.metadata);
1315
- if (value.metadata != null) {
1316
- onUpdate == null ? void 0 : onUpdate({ message });
1086
+ case "tool-call-streaming-start": {
1087
+ const toolInvocations = getToolInvocations(state.message);
1088
+ state.partialToolCalls[value.toolCallId] = {
1089
+ text: "",
1090
+ step: state.step,
1091
+ toolName: value.toolName,
1092
+ index: toolInvocations.length
1093
+ };
1094
+ updateToolInvocationPart(value.toolCallId, {
1095
+ state: "partial-call",
1096
+ step: state.step,
1097
+ toolCallId: value.toolCallId,
1098
+ toolName: value.toolName,
1099
+ args: void 0
1100
+ });
1101
+ write();
1102
+ break;
1317
1103
  }
1318
- break;
1319
- }
1320
- case "metadata": {
1321
- await updateMessageMetadata(value.metadata);
1322
- if (value.metadata != null) {
1323
- onUpdate == null ? void 0 : onUpdate({ message });
1104
+ case "tool-call-delta": {
1105
+ const partialToolCall = state.partialToolCalls[value.toolCallId];
1106
+ partialToolCall.text += value.argsTextDelta;
1107
+ const { value: partialArgs } = await parsePartialJson(
1108
+ partialToolCall.text
1109
+ );
1110
+ updateToolInvocationPart(value.toolCallId, {
1111
+ state: "partial-call",
1112
+ step: partialToolCall.step,
1113
+ toolCallId: value.toolCallId,
1114
+ toolName: partialToolCall.toolName,
1115
+ args: partialArgs
1116
+ });
1117
+ write();
1118
+ break;
1119
+ }
1120
+ case "tool-call": {
1121
+ const call = { args: value.args, ...value };
1122
+ updateToolInvocationPart(value.toolCallId, {
1123
+ state: "call",
1124
+ step: state.step,
1125
+ ...call
1126
+ });
1127
+ write();
1128
+ if (onToolCall) {
1129
+ const result = await onToolCall({
1130
+ toolCall: call
1131
+ });
1132
+ if (result != null) {
1133
+ updateToolInvocationPart(value.toolCallId, {
1134
+ state: "result",
1135
+ step: state.step,
1136
+ ...call,
1137
+ result
1138
+ });
1139
+ write();
1140
+ }
1141
+ }
1142
+ break;
1143
+ }
1144
+ case "tool-result": {
1145
+ const toolInvocations = getToolInvocations(state.message);
1146
+ if (toolInvocations == null) {
1147
+ throw new Error("tool_result must be preceded by a tool_call");
1148
+ }
1149
+ const toolInvocationIndex = toolInvocations.findIndex(
1150
+ (invocation) => invocation.toolCallId === value.toolCallId
1151
+ );
1152
+ if (toolInvocationIndex === -1) {
1153
+ throw new Error(
1154
+ "tool_result must be preceded by a tool_call with the same toolCallId"
1155
+ );
1156
+ }
1157
+ const result = { result: value.result, ...value };
1158
+ updateToolInvocationPart(value.toolCallId, {
1159
+ ...toolInvocations[toolInvocationIndex],
1160
+ state: "result",
1161
+ ...result
1162
+ });
1163
+ write();
1164
+ break;
1165
+ }
1166
+ case "start-step": {
1167
+ state.message.parts.push({ type: "step-start" });
1168
+ await updateMessageMetadata(value.metadata);
1169
+ write();
1170
+ break;
1171
+ }
1172
+ case "finish-step": {
1173
+ state.step += 1;
1174
+ state.activeTextPart = void 0;
1175
+ state.activeReasoningPart = void 0;
1176
+ await updateMessageMetadata(value.metadata);
1177
+ if (value.metadata != null) {
1178
+ write();
1179
+ }
1180
+ break;
1181
+ }
1182
+ case "start": {
1183
+ if (value.messageId != null) {
1184
+ state.message.id = value.messageId;
1185
+ }
1186
+ await updateMessageMetadata(value.metadata);
1187
+ if (value.messageId != null || value.metadata != null) {
1188
+ write();
1189
+ }
1190
+ break;
1191
+ }
1192
+ case "finish": {
1193
+ await updateMessageMetadata(value.metadata);
1194
+ if (value.metadata != null) {
1195
+ write();
1196
+ }
1197
+ break;
1198
+ }
1199
+ case "metadata": {
1200
+ await updateMessageMetadata(value.metadata);
1201
+ if (value.metadata != null) {
1202
+ write();
1203
+ }
1204
+ break;
1205
+ }
1206
+ case "error": {
1207
+ throw new Error(value);
1208
+ }
1209
+ default: {
1210
+ const _exhaustiveCheck = type;
1211
+ throw new Error(`Unhandled stream part: ${_exhaustiveCheck}`);
1324
1212
  }
1325
- break;
1326
- }
1327
- case "error": {
1328
- throw new Error(value);
1329
- }
1330
- default: {
1331
- const _exhaustiveCheck = type;
1332
- throw new Error(`Unhandled stream part: ${_exhaustiveCheck}`);
1333
1213
  }
1334
- }
1335
- controller.enqueue(chunk);
1336
- },
1337
- flush() {
1338
- onFinish == null ? void 0 : onFinish({ message });
1214
+ controller.enqueue(chunk);
1215
+ });
1339
1216
  }
1340
1217
  })
1341
1218
  );
1342
1219
  }
1343
1220
 
1344
- // src/ui/process-chat-text-response.ts
1345
- import { generateId as generateIdFunction } from "@ai-sdk/provider-utils";
1346
-
1347
- // src/ui/process-text-stream.ts
1348
- async function processTextStream({
1349
- stream,
1350
- onTextPart
1351
- }) {
1352
- const reader = stream.pipeThrough(new TextDecoderStream()).getReader();
1353
- while (true) {
1354
- const { done, value } = await reader.read();
1355
- if (done) {
1356
- break;
1357
- }
1358
- await onTextPart(value);
1359
- }
1360
- }
1361
-
1362
- // src/ui/process-chat-text-response.ts
1363
- async function processChatTextResponse({
1364
- stream,
1365
- update,
1366
- onFinish,
1367
- generateId: generateId3 = generateIdFunction
1221
+ // src/ui/transform-text-to-ui-message-stream.ts
1222
+ function transformTextToUiMessageStream({
1223
+ stream
1368
1224
  }) {
1369
- const textPart = { type: "text", text: "" };
1370
- const resultMessage = {
1371
- id: generateId3(),
1372
- role: "assistant",
1373
- parts: [textPart]
1374
- };
1375
- await processTextStream({
1376
- stream,
1377
- onTextPart: (chunk) => {
1378
- textPart.text += chunk;
1379
- update({ message: { ...resultMessage } });
1380
- }
1381
- });
1382
- onFinish == null ? void 0 : onFinish({ message: resultMessage });
1225
+ return stream.pipeThrough(
1226
+ new TransformStream({
1227
+ start(controller) {
1228
+ controller.enqueue({ type: "start", value: {} });
1229
+ controller.enqueue({ type: "start-step", value: {} });
1230
+ },
1231
+ async transform(part, controller) {
1232
+ controller.enqueue({ type: "text", value: part });
1233
+ },
1234
+ async flush(controller) {
1235
+ controller.enqueue({ type: "finish-step", value: {} });
1236
+ controller.enqueue({ type: "finish", value: {} });
1237
+ }
1238
+ })
1239
+ );
1383
1240
  }
1384
1241
 
1385
1242
  // src/ui/call-chat-api.ts
1386
1243
  var getOriginalFetch = () => fetch;
1387
- async function callChatApi({
1244
+ async function fetchUIMessageStream({
1388
1245
  api,
1389
1246
  body,
1390
- streamProtocol = "data",
1247
+ streamProtocol = "ui-message",
1391
1248
  credentials,
1392
1249
  headers,
1393
1250
  abortController,
1394
- onResponse,
1395
- onUpdate,
1396
- onFinish,
1397
- onToolCall,
1398
- generateId: generateId3,
1399
1251
  fetch: fetch2 = getOriginalFetch(),
1400
- lastMessage,
1401
- requestType = "generate",
1402
- messageMetadataSchema
1252
+ requestType = "generate"
1403
1253
  }) {
1404
1254
  var _a17, _b, _c;
1405
1255
  const response = requestType === "resume" ? await fetch2(`${api}?chatId=${body.id}`, {
@@ -1420,9 +1270,6 @@ async function callChatApi({
1420
1270
  signal: (_b = abortController == null ? void 0 : abortController()) == null ? void 0 : _b.signal,
1421
1271
  credentials
1422
1272
  });
1423
- if (onResponse != null) {
1424
- await onResponse(response);
1425
- }
1426
1273
  if (!response.ok) {
1427
1274
  throw new Error(
1428
1275
  (_c = await response.text()) != null ? _c : "Failed to fetch the chat response."
@@ -1431,67 +1278,112 @@ async function callChatApi({
1431
1278
  if (!response.body) {
1432
1279
  throw new Error("The response body is empty.");
1433
1280
  }
1434
- switch (streamProtocol) {
1435
- case "text": {
1436
- await processChatTextResponse({
1437
- stream: response.body,
1438
- update: onUpdate,
1439
- onFinish,
1440
- generateId: generateId3
1441
- });
1442
- return;
1443
- }
1444
- case "data": {
1445
- await consumeStream({
1446
- stream: processChatResponse({
1447
- stream: parseJsonEventStream({
1448
- stream: response.body,
1449
- schema: dataStreamPartSchema
1450
- }).pipeThrough(
1451
- new TransformStream({
1452
- async transform(part, controller) {
1453
- if (!part.success) {
1454
- throw part.error;
1455
- }
1456
- controller.enqueue(part.value);
1457
- }
1458
- })
1459
- ),
1460
- onUpdate({ message }) {
1461
- const copiedMessage = {
1462
- // deep copy the message to ensure that deep changes (msg attachments) are updated
1463
- // with SolidJS. SolidJS uses referential integration of sub-objects to detect changes.
1464
- ...structuredClone(message),
1465
- // add a revision id to ensure that the message is updated with SWR. SWR uses a
1466
- // hashing approach by default to detect changes, but it only works for shallow
1467
- // changes. This is why we need to add a revision id to ensure that the message
1468
- // is updated with SWR (without it, the changes get stuck in SWR and are not
1469
- // forwarded to rendering):
1470
- revisionId: generateId3()
1471
- };
1472
- onUpdate({ message: copiedMessage });
1473
- },
1474
- lastMessage,
1475
- onToolCall,
1476
- onFinish,
1477
- newMessageId: generateId3(),
1478
- messageMetadataSchema
1479
- }),
1480
- onError: (error) => {
1481
- throw error;
1281
+ return streamProtocol === "text" ? transformTextToUiMessageStream({
1282
+ stream: response.body.pipeThrough(new TextDecoderStream())
1283
+ }) : parseJsonEventStream({
1284
+ stream: response.body,
1285
+ schema: uiMessageStreamPartSchema
1286
+ }).pipeThrough(
1287
+ new TransformStream({
1288
+ async transform(part, controller) {
1289
+ if (!part.success) {
1290
+ throw part.error;
1482
1291
  }
1483
- });
1484
- return;
1292
+ controller.enqueue(part.value);
1293
+ }
1294
+ })
1295
+ );
1296
+ }
1297
+ async function consumeUIMessageStream({
1298
+ stream,
1299
+ onUpdate,
1300
+ onFinish,
1301
+ onToolCall,
1302
+ generateId: generateId3,
1303
+ lastMessage,
1304
+ messageMetadataSchema
1305
+ }) {
1306
+ const state = createStreamingUIMessageState({
1307
+ lastMessage,
1308
+ newMessageId: generateId3()
1309
+ });
1310
+ const runUpdateMessageJob = async (job) => {
1311
+ await job({
1312
+ state,
1313
+ write: () => {
1314
+ onUpdate({ message: state.message });
1315
+ }
1316
+ });
1317
+ };
1318
+ await consumeStream({
1319
+ stream: processUIMessageStream({
1320
+ stream,
1321
+ onToolCall,
1322
+ messageMetadataSchema,
1323
+ runUpdateMessageJob
1324
+ }),
1325
+ onError: (error) => {
1326
+ throw error;
1485
1327
  }
1486
- default: {
1487
- const exhaustiveCheck = streamProtocol;
1488
- throw new Error(`Unknown stream protocol: ${exhaustiveCheck}`);
1328
+ });
1329
+ onFinish == null ? void 0 : onFinish({ message: state.message });
1330
+ }
1331
+ async function callChatApi({
1332
+ api,
1333
+ body,
1334
+ streamProtocol = "ui-message",
1335
+ credentials,
1336
+ headers,
1337
+ abortController,
1338
+ onUpdate,
1339
+ onFinish,
1340
+ onToolCall,
1341
+ generateId: generateId3,
1342
+ fetch: fetch2 = getOriginalFetch(),
1343
+ lastMessage,
1344
+ requestType = "generate",
1345
+ messageMetadataSchema
1346
+ }) {
1347
+ const stream = await fetchUIMessageStream({
1348
+ api,
1349
+ body,
1350
+ streamProtocol,
1351
+ credentials,
1352
+ headers,
1353
+ abortController,
1354
+ fetch: fetch2,
1355
+ requestType
1356
+ });
1357
+ await consumeUIMessageStream({
1358
+ stream,
1359
+ onUpdate,
1360
+ onFinish,
1361
+ onToolCall,
1362
+ generateId: generateId3,
1363
+ lastMessage,
1364
+ messageMetadataSchema
1365
+ });
1366
+ }
1367
+
1368
+ // src/ui/call-completion-api.ts
1369
+ import { parseJsonEventStream as parseJsonEventStream2 } from "@ai-sdk/provider-utils";
1370
+
1371
+ // src/ui/process-text-stream.ts
1372
+ async function processTextStream({
1373
+ stream,
1374
+ onTextPart
1375
+ }) {
1376
+ const reader = stream.pipeThrough(new TextDecoderStream()).getReader();
1377
+ while (true) {
1378
+ const { done, value } = await reader.read();
1379
+ if (done) {
1380
+ break;
1489
1381
  }
1382
+ await onTextPart(value);
1490
1383
  }
1491
1384
  }
1492
1385
 
1493
1386
  // src/ui/call-completion-api.ts
1494
- import { parseJsonEventStream as parseJsonEventStream2 } from "@ai-sdk/provider-utils";
1495
1387
  var getOriginalFetch2 = () => fetch;
1496
1388
  async function callCompletionApi({
1497
1389
  api,
@@ -1504,7 +1396,6 @@ async function callCompletionApi({
1504
1396
  setLoading,
1505
1397
  setError,
1506
1398
  setAbortController,
1507
- onResponse,
1508
1399
  onFinish,
1509
1400
  onError,
1510
1401
  fetch: fetch2 = getOriginalFetch2()
@@ -1531,13 +1422,6 @@ async function callCompletionApi({
1531
1422
  }).catch((err) => {
1532
1423
  throw err;
1533
1424
  });
1534
- if (onResponse) {
1535
- try {
1536
- await onResponse(response);
1537
- } catch (err) {
1538
- throw err;
1539
- }
1540
- }
1541
1425
  if (!response.ok) {
1542
1426
  throw new Error(
1543
1427
  (_a17 = await response.text()) != null ? _a17 : "Failed to fetch the chat response."
@@ -1562,7 +1446,7 @@ async function callCompletionApi({
1562
1446
  await consumeStream({
1563
1447
  stream: parseJsonEventStream2({
1564
1448
  stream: response.body,
1565
- schema: dataStreamPartSchema
1449
+ schema: uiMessageStreamPartSchema
1566
1450
  }).pipeThrough(
1567
1451
  new TransformStream({
1568
1452
  async transform(part) {
@@ -1585,31 +1469,490 @@ async function callCompletionApi({
1585
1469
  });
1586
1470
  break;
1587
1471
  }
1588
- default: {
1589
- const exhaustiveCheck = streamProtocol;
1590
- throw new Error(`Unknown stream protocol: ${exhaustiveCheck}`);
1472
+ default: {
1473
+ const exhaustiveCheck = streamProtocol;
1474
+ throw new Error(`Unknown stream protocol: ${exhaustiveCheck}`);
1475
+ }
1476
+ }
1477
+ if (onFinish) {
1478
+ onFinish(prompt, result);
1479
+ }
1480
+ setAbortController(null);
1481
+ return result;
1482
+ } catch (err) {
1483
+ if (err.name === "AbortError") {
1484
+ setAbortController(null);
1485
+ return null;
1486
+ }
1487
+ if (err instanceof Error) {
1488
+ if (onError) {
1489
+ onError(err);
1490
+ }
1491
+ }
1492
+ setError(err);
1493
+ } finally {
1494
+ setLoading(false);
1495
+ }
1496
+ }
1497
+
1498
+ // src/ui/chat-store.ts
1499
+ import {
1500
+ generateId as generateIdFunc
1501
+ } from "@ai-sdk/provider-utils";
1502
+
1503
+ // src/util/serial-job-executor.ts
1504
+ var SerialJobExecutor = class {
1505
+ constructor() {
1506
+ this.queue = [];
1507
+ this.isProcessing = false;
1508
+ }
1509
+ async processQueue() {
1510
+ if (this.isProcessing) {
1511
+ return;
1512
+ }
1513
+ this.isProcessing = true;
1514
+ while (this.queue.length > 0) {
1515
+ await this.queue[0]();
1516
+ this.queue.shift();
1517
+ }
1518
+ this.isProcessing = false;
1519
+ }
1520
+ async run(job) {
1521
+ return new Promise((resolve, reject) => {
1522
+ this.queue.push(async () => {
1523
+ try {
1524
+ await job();
1525
+ resolve();
1526
+ } catch (error) {
1527
+ reject(error);
1528
+ }
1529
+ });
1530
+ void this.processQueue();
1531
+ });
1532
+ }
1533
+ };
1534
+
1535
+ // src/ui/should-resubmit-messages.ts
1536
+ function shouldResubmitMessages({
1537
+ originalMaxToolInvocationStep,
1538
+ originalMessageCount,
1539
+ maxSteps,
1540
+ messages
1541
+ }) {
1542
+ var _a17;
1543
+ const lastMessage = messages[messages.length - 1];
1544
+ return (
1545
+ // check if the feature is enabled:
1546
+ maxSteps > 1 && // ensure there is a last message:
1547
+ lastMessage != null && // ensure we actually have new steps (to prevent infinite loops in case of errors):
1548
+ (messages.length > originalMessageCount || extractMaxToolInvocationStep(getToolInvocations(lastMessage)) !== originalMaxToolInvocationStep) && // check that next step is possible:
1549
+ isAssistantMessageWithCompletedToolCalls(lastMessage) && // limit the number of automatic steps:
1550
+ ((_a17 = extractMaxToolInvocationStep(getToolInvocations(lastMessage))) != null ? _a17 : 0) < maxSteps
1551
+ );
1552
+ }
1553
+ function isAssistantMessageWithCompletedToolCalls(message) {
1554
+ if (message.role !== "assistant") {
1555
+ return false;
1556
+ }
1557
+ const lastStepStartIndex = message.parts.reduce((lastIndex, part, index) => {
1558
+ return part.type === "step-start" ? index : lastIndex;
1559
+ }, -1);
1560
+ const lastStepToolInvocations = message.parts.slice(lastStepStartIndex + 1).filter((part) => part.type === "tool-invocation");
1561
+ return lastStepToolInvocations.length > 0 && lastStepToolInvocations.every((part) => "result" in part.toolInvocation);
1562
+ }
1563
+
1564
+ // src/ui/update-tool-call-result.ts
1565
+ function updateToolCallResult({
1566
+ messages,
1567
+ toolCallId,
1568
+ toolResult: result
1569
+ }) {
1570
+ const lastMessage = messages[messages.length - 1];
1571
+ const invocationPart = lastMessage.parts.find(
1572
+ (part) => part.type === "tool-invocation" && part.toolInvocation.toolCallId === toolCallId
1573
+ );
1574
+ if (invocationPart == null) {
1575
+ return;
1576
+ }
1577
+ invocationPart.toolInvocation = {
1578
+ ...invocationPart.toolInvocation,
1579
+ state: "result",
1580
+ result
1581
+ };
1582
+ }
1583
+
1584
+ // src/ui/chat-store.ts
1585
+ var ChatStore = class {
1586
+ constructor({
1587
+ chats = {},
1588
+ generateId: generateId3,
1589
+ messageMetadataSchema,
1590
+ transport,
1591
+ maxSteps = 1
1592
+ }) {
1593
+ this.chats = new Map(
1594
+ Object.entries(chats).map(([id, state]) => [
1595
+ id,
1596
+ {
1597
+ messages: [...state.messages],
1598
+ status: "ready",
1599
+ activeResponse: void 0,
1600
+ error: void 0,
1601
+ jobExecutor: new SerialJobExecutor()
1602
+ }
1603
+ ])
1604
+ );
1605
+ this.maxSteps = maxSteps;
1606
+ this.transport = transport;
1607
+ this.subscribers = /* @__PURE__ */ new Set();
1608
+ this.generateId = generateId3 != null ? generateId3 : generateIdFunc;
1609
+ this.messageMetadataSchema = messageMetadataSchema;
1610
+ }
1611
+ hasChat(id) {
1612
+ return this.chats.has(id);
1613
+ }
1614
+ addChat(id, messages) {
1615
+ this.chats.set(id, {
1616
+ messages,
1617
+ status: "ready",
1618
+ jobExecutor: new SerialJobExecutor()
1619
+ });
1620
+ }
1621
+ getChats() {
1622
+ return Array.from(this.chats.entries());
1623
+ }
1624
+ get chatCount() {
1625
+ return this.chats.size;
1626
+ }
1627
+ getStatus(id) {
1628
+ return this.getChat(id).status;
1629
+ }
1630
+ setStatus({
1631
+ id,
1632
+ status,
1633
+ error
1634
+ }) {
1635
+ const chat = this.getChat(id);
1636
+ if (chat.status === status)
1637
+ return;
1638
+ chat.status = status;
1639
+ chat.error = error;
1640
+ this.emit({ type: "chat-status-changed", chatId: id, error });
1641
+ }
1642
+ getError(id) {
1643
+ return this.getChat(id).error;
1644
+ }
1645
+ getMessages(id) {
1646
+ return this.getChat(id).messages;
1647
+ }
1648
+ getLastMessage(id) {
1649
+ const chat = this.getChat(id);
1650
+ return chat.messages[chat.messages.length - 1];
1651
+ }
1652
+ subscribe(subscriber) {
1653
+ this.subscribers.add(subscriber);
1654
+ return () => this.subscribers.delete(subscriber);
1655
+ }
1656
+ setMessages({
1657
+ id,
1658
+ messages
1659
+ }) {
1660
+ this.getChat(id).messages = [...messages];
1661
+ this.emit({ type: "chat-messages-changed", chatId: id });
1662
+ }
1663
+ appendMessage({
1664
+ id,
1665
+ message
1666
+ }) {
1667
+ const chat = this.getChat(id);
1668
+ chat.messages = [...chat.messages, { ...message }];
1669
+ this.emit({ type: "chat-messages-changed", chatId: id });
1670
+ }
1671
+ removeAssistantResponse(id) {
1672
+ const chat = this.getChat(id);
1673
+ const lastMessage = chat.messages[chat.messages.length - 1];
1674
+ if (lastMessage == null) {
1675
+ throw new Error("Cannot remove assistant response from empty chat");
1676
+ }
1677
+ if (lastMessage.role !== "assistant") {
1678
+ throw new Error("Last message is not an assistant message");
1679
+ }
1680
+ this.setMessages({ id, messages: chat.messages.slice(0, -1) });
1681
+ }
1682
+ async submitMessage({
1683
+ chatId,
1684
+ message,
1685
+ headers,
1686
+ body,
1687
+ onError,
1688
+ onToolCall,
1689
+ onFinish
1690
+ }) {
1691
+ var _a17;
1692
+ const chat = this.getChat(chatId);
1693
+ const currentMessages = chat.messages;
1694
+ await this.triggerRequest({
1695
+ chatId,
1696
+ messages: currentMessages.concat({
1697
+ ...message,
1698
+ id: (_a17 = message.id) != null ? _a17 : this.generateId()
1699
+ }),
1700
+ headers,
1701
+ body,
1702
+ requestType: "generate",
1703
+ onError,
1704
+ onToolCall,
1705
+ onFinish
1706
+ });
1707
+ }
1708
+ async resubmitLastUserMessage({
1709
+ chatId,
1710
+ headers,
1711
+ body,
1712
+ onError,
1713
+ onToolCall,
1714
+ onFinish
1715
+ }) {
1716
+ const messages = this.getChat(chatId).messages;
1717
+ const messagesToSubmit = messages[messages.length - 1].role === "assistant" ? messages.slice(0, -1) : messages;
1718
+ if (messagesToSubmit.length === 0) {
1719
+ return;
1720
+ }
1721
+ return this.triggerRequest({
1722
+ chatId,
1723
+ requestType: "generate",
1724
+ messages: messagesToSubmit,
1725
+ headers,
1726
+ body,
1727
+ onError,
1728
+ onToolCall,
1729
+ onFinish
1730
+ });
1731
+ }
1732
+ async resumeStream({
1733
+ chatId,
1734
+ headers,
1735
+ body,
1736
+ onError,
1737
+ onToolCall,
1738
+ onFinish
1739
+ }) {
1740
+ const chat = this.getChat(chatId);
1741
+ const currentMessages = chat.messages;
1742
+ return this.triggerRequest({
1743
+ chatId,
1744
+ messages: currentMessages,
1745
+ requestType: "resume",
1746
+ headers,
1747
+ body,
1748
+ onError,
1749
+ onToolCall,
1750
+ onFinish
1751
+ });
1752
+ }
1753
+ async addToolResult({
1754
+ chatId,
1755
+ toolCallId,
1756
+ result
1757
+ }) {
1758
+ const chat = this.getChat(chatId);
1759
+ chat.jobExecutor.run(async () => {
1760
+ const currentMessages = chat.messages;
1761
+ updateToolCallResult({
1762
+ messages: currentMessages,
1763
+ toolCallId,
1764
+ toolResult: result
1765
+ });
1766
+ this.setMessages({ id: chatId, messages: currentMessages });
1767
+ if (chat.status === "submitted" || chat.status === "streaming") {
1768
+ return;
1769
+ }
1770
+ const lastMessage = currentMessages[currentMessages.length - 1];
1771
+ if (isAssistantMessageWithCompletedToolCalls(lastMessage)) {
1772
+ await this.triggerRequest({
1773
+ messages: currentMessages,
1774
+ requestType: "generate",
1775
+ chatId
1776
+ });
1591
1777
  }
1778
+ });
1779
+ }
1780
+ async stopStream({ chatId }) {
1781
+ var _a17;
1782
+ const chat = this.getChat(chatId);
1783
+ if (chat.status !== "streaming" && chat.status !== "submitted")
1784
+ return;
1785
+ if ((_a17 = chat.activeResponse) == null ? void 0 : _a17.abortController) {
1786
+ chat.activeResponse.abortController.abort();
1787
+ chat.activeResponse.abortController = void 0;
1592
1788
  }
1593
- if (onFinish) {
1594
- onFinish(prompt, result);
1789
+ }
1790
+ emit(event) {
1791
+ for (const subscriber of this.subscribers) {
1792
+ subscriber.onChatChanged(event);
1595
1793
  }
1596
- setAbortController(null);
1597
- return result;
1598
- } catch (err) {
1599
- if (err.name === "AbortError") {
1600
- setAbortController(null);
1601
- return null;
1794
+ }
1795
+ getChat(id) {
1796
+ if (!this.hasChat(id)) {
1797
+ throw new Error(`chat '${id}' not found`);
1602
1798
  }
1603
- if (err instanceof Error) {
1604
- if (onError) {
1799
+ return this.chats.get(id);
1800
+ }
1801
+ async triggerRequest({
1802
+ chatId,
1803
+ messages: chatMessages,
1804
+ requestType,
1805
+ headers,
1806
+ body,
1807
+ onError,
1808
+ onToolCall,
1809
+ onFinish
1810
+ }) {
1811
+ const self = this;
1812
+ const chat = this.getChat(chatId);
1813
+ this.setStatus({ id: chatId, status: "submitted", error: void 0 });
1814
+ const messageCount = chatMessages.length;
1815
+ const maxStep = extractMaxToolInvocationStep(
1816
+ getToolInvocations(chatMessages[chatMessages.length - 1])
1817
+ );
1818
+ try {
1819
+ const activeResponse = {
1820
+ state: createStreamingUIMessageState({
1821
+ lastMessage: chatMessages[chatMessages.length - 1],
1822
+ newMessageId: self.generateId()
1823
+ }),
1824
+ abortController: new AbortController()
1825
+ };
1826
+ chat.activeResponse = activeResponse;
1827
+ const stream = await self.transport.submitMessages({
1828
+ chatId,
1829
+ messages: chatMessages,
1830
+ body,
1831
+ headers,
1832
+ abortController: activeResponse.abortController,
1833
+ requestType
1834
+ });
1835
+ const runUpdateMessageJob = (job) => (
1836
+ // serialize the job execution to avoid race conditions:
1837
+ chat.jobExecutor.run(
1838
+ () => job({
1839
+ state: activeResponse.state,
1840
+ write: () => {
1841
+ self.setStatus({ id: chatId, status: "streaming" });
1842
+ const replaceLastMessage = activeResponse.state.message.id === chatMessages[chatMessages.length - 1].id;
1843
+ const newMessages = [
1844
+ ...replaceLastMessage ? chatMessages.slice(0, chatMessages.length - 1) : chatMessages,
1845
+ activeResponse.state.message
1846
+ ];
1847
+ self.setMessages({
1848
+ id: chatId,
1849
+ messages: newMessages
1850
+ });
1851
+ }
1852
+ })
1853
+ )
1854
+ );
1855
+ await consumeStream({
1856
+ stream: processUIMessageStream({
1857
+ stream,
1858
+ onToolCall,
1859
+ messageMetadataSchema: self.messageMetadataSchema,
1860
+ runUpdateMessageJob
1861
+ }),
1862
+ onError: (error) => {
1863
+ throw error;
1864
+ }
1865
+ });
1866
+ onFinish == null ? void 0 : onFinish({ message: activeResponse.state.message });
1867
+ this.setStatus({ id: chatId, status: "ready" });
1868
+ } catch (err) {
1869
+ if (err.name === "AbortError") {
1870
+ this.setStatus({ id: chatId, status: "ready" });
1871
+ return null;
1872
+ }
1873
+ if (onError && err instanceof Error) {
1605
1874
  onError(err);
1606
1875
  }
1876
+ this.setStatus({ id: chatId, status: "error", error: err });
1877
+ } finally {
1878
+ chat.activeResponse = void 0;
1879
+ }
1880
+ const currentMessages = self.getMessages(chatId);
1881
+ if (shouldResubmitMessages({
1882
+ originalMaxToolInvocationStep: maxStep,
1883
+ originalMessageCount: messageCount,
1884
+ maxSteps: self.maxSteps,
1885
+ messages: currentMessages
1886
+ })) {
1887
+ await self.triggerRequest({
1888
+ chatId,
1889
+ requestType,
1890
+ onError,
1891
+ onToolCall,
1892
+ onFinish,
1893
+ headers,
1894
+ body,
1895
+ messages: currentMessages
1896
+ });
1607
1897
  }
1608
- setError(err);
1609
- } finally {
1610
- setLoading(false);
1611
1898
  }
1612
- }
1899
+ };
1900
+
1901
+ // src/ui/chat-transport.ts
1902
+ var DefaultChatTransport = class {
1903
+ constructor({
1904
+ api,
1905
+ credentials,
1906
+ headers,
1907
+ body,
1908
+ streamProtocol,
1909
+ fetch: fetch2,
1910
+ prepareRequestBody
1911
+ }) {
1912
+ this.api = api;
1913
+ this.credentials = credentials;
1914
+ this.headers = headers;
1915
+ this.body = body;
1916
+ this.streamProtocol = streamProtocol;
1917
+ this.fetch = fetch2;
1918
+ this.prepareRequestBody = prepareRequestBody;
1919
+ }
1920
+ submitMessages({
1921
+ chatId,
1922
+ messages,
1923
+ abortController,
1924
+ body,
1925
+ headers,
1926
+ requestType
1927
+ }) {
1928
+ var _a17, _b;
1929
+ return fetchUIMessageStream({
1930
+ api: this.api,
1931
+ headers: {
1932
+ ...this.headers,
1933
+ ...headers
1934
+ },
1935
+ body: (_b = (_a17 = this.prepareRequestBody) == null ? void 0 : _a17.call(this, {
1936
+ id: chatId,
1937
+ // TODO change to chatId
1938
+ messages,
1939
+ ...this.body,
1940
+ ...body
1941
+ })) != null ? _b : {
1942
+ id: chatId,
1943
+ // TODO change to chatId
1944
+ messages,
1945
+ ...this.body,
1946
+ ...body
1947
+ },
1948
+ streamProtocol: this.streamProtocol,
1949
+ credentials: this.credentials,
1950
+ abortController: () => abortController,
1951
+ fetch: this.fetch,
1952
+ requestType
1953
+ });
1954
+ }
1955
+ };
1613
1956
 
1614
1957
  // src/ui/convert-file-list-to-file-ui-parts.ts
1615
1958
  async function convertFileListToFileUIParts(files) {
@@ -1797,53 +2140,166 @@ function convertToModelMessages(messages, options) {
1797
2140
  }
1798
2141
  var convertToCoreMessages = convertToModelMessages;
1799
2142
 
1800
- // src/ui/should-resubmit-messages.ts
1801
- function shouldResubmitMessages({
1802
- originalMaxToolInvocationStep,
1803
- originalMessageCount,
1804
- maxSteps,
1805
- messages
2143
+ // src/ui/default-chat-store.ts
2144
+ import {
2145
+ generateId as generateIdFunc2
2146
+ } from "@ai-sdk/provider-utils";
2147
+ function defaultChatStore({
2148
+ api,
2149
+ fetch: fetch2,
2150
+ streamProtocol = "ui-message",
2151
+ credentials,
2152
+ headers,
2153
+ body,
2154
+ prepareRequestBody,
2155
+ generateId: generateId3 = generateIdFunc2,
2156
+ messageMetadataSchema,
2157
+ maxSteps = 1,
2158
+ chats
1806
2159
  }) {
1807
- var _a17;
1808
- const lastMessage = messages[messages.length - 1];
1809
- return (
1810
- // check if the feature is enabled:
1811
- maxSteps > 1 && // ensure there is a last message:
1812
- lastMessage != null && // ensure we actually have new steps (to prevent infinite loops in case of errors):
1813
- (messages.length > originalMessageCount || extractMaxToolInvocationStep(getToolInvocations(lastMessage)) !== originalMaxToolInvocationStep) && // check that next step is possible:
1814
- isAssistantMessageWithCompletedToolCalls(lastMessage) && // limit the number of automatic steps:
1815
- ((_a17 = extractMaxToolInvocationStep(getToolInvocations(lastMessage))) != null ? _a17 : 0) < maxSteps
1816
- );
2160
+ return new ChatStore({
2161
+ transport: new DefaultChatTransport({
2162
+ api,
2163
+ fetch: fetch2,
2164
+ streamProtocol,
2165
+ credentials,
2166
+ headers,
2167
+ body,
2168
+ prepareRequestBody
2169
+ }),
2170
+ generateId: generateId3,
2171
+ messageMetadataSchema,
2172
+ maxSteps,
2173
+ chats
2174
+ });
1817
2175
  }
1818
- function isAssistantMessageWithCompletedToolCalls(message) {
1819
- if (message.role !== "assistant") {
1820
- return false;
2176
+
2177
+ // src/ui-message-stream/create-ui-message-stream.ts
2178
+ function createUIMessageStream({
2179
+ execute,
2180
+ onError = () => "An error occurred."
2181
+ // mask error messages for safety by default
2182
+ }) {
2183
+ let controller;
2184
+ const ongoingStreamPromises = [];
2185
+ const stream = new ReadableStream({
2186
+ start(controllerArg) {
2187
+ controller = controllerArg;
2188
+ }
2189
+ });
2190
+ function safeEnqueue(data) {
2191
+ try {
2192
+ controller.enqueue(data);
2193
+ } catch (error) {
2194
+ }
1821
2195
  }
1822
- const lastStepStartIndex = message.parts.reduce((lastIndex, part, index) => {
1823
- return part.type === "step-start" ? index : lastIndex;
1824
- }, -1);
1825
- const lastStepToolInvocations = message.parts.slice(lastStepStartIndex + 1).filter((part) => part.type === "tool-invocation");
1826
- return lastStepToolInvocations.length > 0 && lastStepToolInvocations.every((part) => "result" in part.toolInvocation);
2196
+ try {
2197
+ const result = execute({
2198
+ write(part) {
2199
+ safeEnqueue(part);
2200
+ },
2201
+ merge(streamArg) {
2202
+ ongoingStreamPromises.push(
2203
+ (async () => {
2204
+ const reader = streamArg.getReader();
2205
+ while (true) {
2206
+ const { done, value } = await reader.read();
2207
+ if (done)
2208
+ break;
2209
+ safeEnqueue(value);
2210
+ }
2211
+ })().catch((error) => {
2212
+ safeEnqueue({ type: "error", value: onError(error) });
2213
+ })
2214
+ );
2215
+ },
2216
+ onError
2217
+ });
2218
+ if (result) {
2219
+ ongoingStreamPromises.push(
2220
+ result.catch((error) => {
2221
+ safeEnqueue({ type: "error", value: onError(error) });
2222
+ })
2223
+ );
2224
+ }
2225
+ } catch (error) {
2226
+ safeEnqueue({ type: "error", value: onError(error) });
2227
+ }
2228
+ const waitForStreams = new Promise(async (resolve) => {
2229
+ while (ongoingStreamPromises.length > 0) {
2230
+ await ongoingStreamPromises.shift();
2231
+ }
2232
+ resolve();
2233
+ });
2234
+ waitForStreams.finally(() => {
2235
+ try {
2236
+ controller.close();
2237
+ } catch (error) {
2238
+ }
2239
+ });
2240
+ return stream;
1827
2241
  }
1828
2242
 
1829
- // src/ui/update-tool-call-result.ts
1830
- function updateToolCallResult({
1831
- messages,
1832
- toolCallId,
1833
- toolResult: result
2243
+ // src/ui-message-stream/ui-message-stream-headers.ts
2244
+ var uiMessageStreamHeaders = {
2245
+ "content-type": "text/event-stream",
2246
+ "cache-control": "no-cache",
2247
+ connection: "keep-alive",
2248
+ "x-vercel-ai-ui-message-stream": "v1",
2249
+ "x-accel-buffering": "no"
2250
+ // disable nginx buffering
2251
+ };
2252
+
2253
+ // src/ui-message-stream/json-to-sse-transform-stream.ts
2254
+ var JsonToSseTransformStream = class extends TransformStream {
2255
+ constructor() {
2256
+ super({
2257
+ transform(part, controller) {
2258
+ controller.enqueue(`data: ${JSON.stringify(part)}
2259
+
2260
+ `);
2261
+ },
2262
+ flush(controller) {
2263
+ controller.enqueue("data: [DONE]\n\n");
2264
+ }
2265
+ });
2266
+ }
2267
+ };
2268
+
2269
+ // src/ui-message-stream/create-ui-message-stream-response.ts
2270
+ function createUIMessageStreamResponse({
2271
+ status,
2272
+ statusText,
2273
+ headers,
2274
+ stream
1834
2275
  }) {
1835
- const lastMessage = messages[messages.length - 1];
1836
- const invocationPart = lastMessage.parts.find(
1837
- (part) => part.type === "tool-invocation" && part.toolInvocation.toolCallId === toolCallId
2276
+ return new Response(
2277
+ stream.pipeThrough(new JsonToSseTransformStream()).pipeThrough(new TextEncoderStream()),
2278
+ {
2279
+ status,
2280
+ statusText,
2281
+ headers: prepareHeaders(headers, uiMessageStreamHeaders)
2282
+ }
1838
2283
  );
1839
- if (invocationPart == null) {
1840
- return;
1841
- }
1842
- invocationPart.toolInvocation = {
1843
- ...invocationPart.toolInvocation,
1844
- state: "result",
1845
- result
1846
- };
2284
+ }
2285
+
2286
+ // src/ui-message-stream/pipe-ui-message-stream-to-response.ts
2287
+ function pipeUIMessageStreamToResponse({
2288
+ response,
2289
+ status,
2290
+ statusText,
2291
+ headers,
2292
+ stream
2293
+ }) {
2294
+ writeToServerResponse({
2295
+ response,
2296
+ status,
2297
+ statusText,
2298
+ headers: Object.fromEntries(
2299
+ prepareHeaders(headers, uiMessageStreamHeaders).entries()
2300
+ ),
2301
+ stream: stream.pipeThrough(new JsonToSseTransformStream()).pipeThrough(new TextEncoderStream())
2302
+ });
1847
2303
  }
1848
2304
 
1849
2305
  // src/util/data-url.ts
@@ -6709,7 +7165,7 @@ var DefaultStreamTextResult = class {
6709
7165
  )
6710
7166
  );
6711
7167
  }
6712
- toDataStream({
7168
+ toUIMessageStream({
6713
7169
  newMessageId,
6714
7170
  originalMessages = [],
6715
7171
  onFinish,
@@ -6861,24 +7317,40 @@ var DefaultStreamTextResult = class {
6861
7317
  }
6862
7318
  })
6863
7319
  );
6864
- return onFinish == null ? baseStream : processChatResponse({
6865
- stream: baseStream,
7320
+ if (onFinish == null) {
7321
+ return baseStream;
7322
+ }
7323
+ const state = createStreamingUIMessageState({
6866
7324
  lastMessage,
6867
- newMessageId: messageId != null ? messageId : this.generateId(),
6868
- onFinish: ({ message }) => {
6869
- const isContinuation2 = message.id === (lastMessage == null ? void 0 : lastMessage.id);
6870
- onFinish({
6871
- isContinuation: isContinuation2,
6872
- responseMessage: message,
6873
- messages: [
6874
- ...isContinuation2 ? originalMessages.slice(0, -1) : originalMessages,
6875
- message
6876
- ]
6877
- });
6878
- }
7325
+ newMessageId: messageId != null ? messageId : this.generateId()
6879
7326
  });
7327
+ const runUpdateMessageJob = async (job) => {
7328
+ await job({ state, write: () => {
7329
+ } });
7330
+ };
7331
+ return processUIMessageStream({
7332
+ stream: baseStream,
7333
+ runUpdateMessageJob
7334
+ }).pipeThrough(
7335
+ new TransformStream({
7336
+ transform(chunk, controller) {
7337
+ controller.enqueue(chunk);
7338
+ },
7339
+ flush() {
7340
+ const isContinuation2 = state.message.id === (lastMessage == null ? void 0 : lastMessage.id);
7341
+ onFinish({
7342
+ isContinuation: isContinuation2,
7343
+ responseMessage: state.message,
7344
+ messages: [
7345
+ ...isContinuation2 ? originalMessages.slice(0, -1) : originalMessages,
7346
+ state.message
7347
+ ]
7348
+ });
7349
+ }
7350
+ })
7351
+ );
6880
7352
  }
6881
- pipeDataStreamToResponse(response, {
7353
+ pipeUIMessageStreamToResponse(response, {
6882
7354
  newMessageId,
6883
7355
  originalMessages,
6884
7356
  onFinish,
@@ -6890,9 +7362,9 @@ var DefaultStreamTextResult = class {
6890
7362
  onError,
6891
7363
  ...init
6892
7364
  } = {}) {
6893
- pipeDataStreamToResponse({
7365
+ pipeUIMessageStreamToResponse({
6894
7366
  response,
6895
- dataStream: this.toDataStream({
7367
+ stream: this.toUIMessageStream({
6896
7368
  newMessageId,
6897
7369
  originalMessages,
6898
7370
  onFinish,
@@ -6913,7 +7385,7 @@ var DefaultStreamTextResult = class {
6913
7385
  ...init
6914
7386
  });
6915
7387
  }
6916
- toDataStreamResponse({
7388
+ toUIMessageStreamResponse({
6917
7389
  newMessageId,
6918
7390
  originalMessages,
6919
7391
  onFinish,
@@ -6925,8 +7397,8 @@ var DefaultStreamTextResult = class {
6925
7397
  onError,
6926
7398
  ...init
6927
7399
  } = {}) {
6928
- return createDataStreamResponse({
6929
- dataStream: this.toDataStream({
7400
+ return createUIMessageStreamResponse({
7401
+ stream: this.toUIMessageStream({
6930
7402
  newMessageId,
6931
7403
  originalMessages,
6932
7404
  onFinish,
@@ -7956,6 +8428,8 @@ var DefaultTranscriptionResult = class {
7956
8428
  export {
7957
8429
  AISDKError16 as AISDKError,
7958
8430
  APICallError,
8431
+ ChatStore,
8432
+ DefaultChatTransport,
7959
8433
  DownloadError,
7960
8434
  EmptyResponseBodyError,
7961
8435
  InvalidArgumentError,
@@ -7997,12 +8471,13 @@ export {
7997
8471
  coreToolMessageSchema,
7998
8472
  coreUserMessageSchema,
7999
8473
  cosineSimilarity,
8000
- createDataStream,
8001
- createDataStreamResponse,
8002
8474
  createIdGenerator5 as createIdGenerator,
8003
8475
  createProviderRegistry,
8004
8476
  createTextStreamResponse,
8477
+ createUIMessageStream,
8478
+ createUIMessageStreamResponse,
8005
8479
  customProvider,
8480
+ defaultChatStore,
8006
8481
  defaultSettingsMiddleware,
8007
8482
  embed,
8008
8483
  embedMany,
@@ -8024,9 +8499,8 @@ export {
8024
8499
  jsonSchema2 as jsonSchema,
8025
8500
  modelMessageSchema,
8026
8501
  parsePartialJson,
8027
- pipeDataStreamToResponse,
8028
8502
  pipeTextStreamToResponse,
8029
- processTextStream,
8503
+ pipeUIMessageStreamToResponse,
8030
8504
  shouldResubmitMessages,
8031
8505
  simulateReadableStream,
8032
8506
  simulateStreamingMiddleware,