@tanstack/ai 0.49.1 → 0.50.0

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.
@@ -5,6 +5,13 @@ export declare function safeJsonStringify(value: unknown): string;
5
5
  * Convert UIMessages or ModelMessages to ModelMessages
6
6
  */
7
7
  export declare function convertMessagesToModelMessages(messages: Array<UIMessage | ModelMessage>): Array<ModelMessage>;
8
+ export declare function restoreToolResultOwnership<T extends object>(message: T): T;
9
+ /**
10
+ * Rebuild a `Date` from a live `Date` or from an ISO string.
11
+ * `JSON.stringify` turns `Date` into a string, so persistence reload
12
+ * and AG-UI wire both land here as strings.
13
+ */
14
+ export declare function coerceCreatedAt(value: unknown): Date | undefined;
8
15
  /**
9
16
  * Convert a UIMessage to ModelMessage(s)
10
17
  *
@@ -1,7 +1,10 @@
1
1
  import { tanstackMetadata } from "../../utilities/merge-metadata.js";
2
- import { normalizeToolResult } from "../../utilities/tool-result.js";
2
+ import { isContentPartArray, normalizeToolResult } from "../../utilities/tool-result.js";
3
3
  import { isProviderExecutedToolCall } from "../../utilities/provider-executed.js";
4
4
  //#region src/activities/chat/messages.ts
5
+ function isRecord(value) {
6
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7
+ }
5
8
  /**
6
9
  * Check if a MessagePart is a content part (text, image, audio, video, document)
7
10
  * that maps directly to a ModelMessage ContentPart.
@@ -29,6 +32,10 @@ function encryptedValueFrom(value) {
29
32
  function toolCallFromWire(toolCall, bag) {
30
33
  const fromBag = bag != null && typeof bag === "object" && !Array.isArray(bag) ? bag : void 0;
31
34
  const encrypted = encryptedValueFrom(toolCall);
35
+ if (bag === null && encrypted === void 0) return {
36
+ ...toolCall,
37
+ metadata: null
38
+ };
32
39
  if (fromBag === void 0 && encrypted === void 0) return toolCall;
33
40
  return {
34
41
  ...toolCall,
@@ -65,6 +72,9 @@ function getTextContent(content) {
65
72
  if (typeof content === "string") return content;
66
73
  return content.filter((part) => part.type === "text").map((part) => part.content).join("");
67
74
  }
75
+ function toolResultContent(content) {
76
+ return Array.isArray(content) ? content : getTextContent(content);
77
+ }
68
78
  /**
69
79
  * Convert UIMessages or ModelMessages to ModelMessages
70
80
  */
@@ -80,8 +90,9 @@ function convertMessagesToModelMessages(messages) {
80
90
  modelMessages.push(...uiMessageToModelMessages(msg));
81
91
  continue;
82
92
  }
83
- const role = msg.role;
84
- if (role === "tool" && msg.toolCallId && anchoredToolCallIds.has(msg.toolCallId)) continue;
93
+ const modelMessage = restoreModelMessageCreatedAt(restoreToolResultOwnership(msg));
94
+ const role = modelMessage.role;
95
+ if (role === "tool" && modelMessage.toolCallId && anchoredToolCallIds.has(modelMessage.toolCallId)) continue;
85
96
  if (role === "reasoning") {
86
97
  const content = msg.content;
87
98
  if (content) {
@@ -97,26 +108,32 @@ function convertMessagesToModelMessages(messages) {
97
108
  if (role === "developer") {
98
109
  modelMessages.push({
99
110
  role: "system",
100
- content: msg.content
111
+ content: msg.content,
112
+ ...optionalName(modelMessage),
113
+ ...optionalCreatedAt(modelMessage),
114
+ ...modelMessage.metadata !== void 0 && { metadata: modelMessage.metadata }
101
115
  });
102
116
  continue;
103
117
  }
104
118
  if (role === "user" && Array.isArray(msg.content)) {
105
119
  const content = msg.content;
106
120
  if (!content.some((part) => part.type === "text" && "text" in part && !("content" in part))) {
107
- modelMessages.push(msg);
121
+ modelMessages.push(modelMessage);
108
122
  continue;
109
123
  }
110
124
  const contentParts = aguiUserContentToParts(content).filter(isContentPart);
111
125
  modelMessages.push({
112
126
  role: "user",
113
127
  content: collapseContentParts(contentParts),
114
- ...msg.id !== void 0 && { id: msg.id }
128
+ ...msg.id !== void 0 && { id: msg.id },
129
+ ...optionalName(modelMessage),
130
+ ...optionalCreatedAt(modelMessage),
131
+ ...modelMessage.metadata !== void 0 && { metadata: modelMessage.metadata }
115
132
  });
116
133
  continue;
117
134
  }
118
135
  if (role === "assistant") {
119
- const source = msg;
136
+ const source = modelMessage;
120
137
  const toolCallMetadata = tanstackMetadata(msg)?.toolCallMetadata;
121
138
  const toolCalls = source.toolCalls?.map((toolCall) => toolCallFromWire(toolCall, toolCallMetadata?.[toolCall.id]));
122
139
  modelMessages.push({
@@ -127,10 +144,116 @@ function convertMessagesToModelMessages(messages) {
127
144
  pendingThinking = [];
128
145
  continue;
129
146
  }
130
- modelMessages.push(msg);
147
+ modelMessages.push(modelMessage);
131
148
  }
132
149
  return modelMessages;
133
150
  }
151
+ function restoreModelMessageCreatedAt(message) {
152
+ const createdAt = coerceCreatedAt(message.createdAt) ?? createdAtFromMetadata(message);
153
+ if (createdAt === void 0) {
154
+ if (message.createdAt === void 0) return message;
155
+ const { createdAt: _invalid, ...rest } = message;
156
+ return rest;
157
+ }
158
+ return Object.is(message.createdAt, createdAt) ? message : {
159
+ ...message,
160
+ createdAt
161
+ };
162
+ }
163
+ function restoreToolResultOwnership(message) {
164
+ if (!("role" in message) || message.role !== "tool") return message;
165
+ const source = message;
166
+ const owned = tanstackMetadata(source)?.toolResult;
167
+ if (!isRecord(owned)) return message;
168
+ if ("content" in owned && !isContentPartArray(owned.content)) return message;
169
+ const next = { ...message };
170
+ if (!("id" in owned)) Reflect.deleteProperty(next, "id");
171
+ if (!("createdAt" in owned)) Reflect.deleteProperty(next, "createdAt");
172
+ if (typeof owned.id === "string") Reflect.set(next, "id", owned.id);
173
+ if (typeof owned.createdAt === "string") {
174
+ const createdAt = coerceCreatedAt(owned.createdAt);
175
+ if (createdAt) Reflect.set(next, "createdAt", createdAt);
176
+ }
177
+ if (isContentPartArray(owned.content)) Reflect.set(next, "content", owned.content);
178
+ const sourceMetadata = Reflect.get(source, "metadata");
179
+ if (isRecord(sourceMetadata)) {
180
+ const tanstack = sourceMetadata.tanstack;
181
+ if (isRecord(tanstack)) {
182
+ const { toolResult: _toolResult, ...restTanstack } = tanstack;
183
+ const restMetadata = { ...sourceMetadata };
184
+ if (Object.keys(restTanstack).length) restMetadata.tanstack = restTanstack;
185
+ else delete restMetadata.tanstack;
186
+ if (Object.keys(restMetadata).length) Reflect.set(next, "metadata", restMetadata);
187
+ else Reflect.deleteProperty(next, "metadata");
188
+ }
189
+ }
190
+ return next;
191
+ }
192
+ /**
193
+ * Rebuild a `Date` from a live `Date` or from an ISO string.
194
+ * `JSON.stringify` turns `Date` into a string, so persistence reload
195
+ * and AG-UI wire both land here as strings.
196
+ */
197
+ function coerceCreatedAt(value) {
198
+ if (value instanceof Date) return Number.isNaN(value.getTime()) ? void 0 : value;
199
+ if (typeof value !== "string") return void 0;
200
+ const createdAt = new Date(value);
201
+ return Number.isNaN(createdAt.getTime()) ? void 0 : createdAt;
202
+ }
203
+ function normalizeMessagePart(part) {
204
+ if (part.type !== "tool-result") return part;
205
+ const createdAt = coerceCreatedAt(part.createdAt);
206
+ const { createdAt: _createdAt, ...rest } = part;
207
+ return createdAt === void 0 ? rest : {
208
+ ...rest,
209
+ createdAt
210
+ };
211
+ }
212
+ function createdAtFromMetadata(source) {
213
+ return coerceCreatedAt(tanstackMetadata(source)?.createdAt);
214
+ }
215
+ function optionalCreatedAt(source) {
216
+ const createdAt = coerceCreatedAt(source.createdAt);
217
+ return createdAt !== void 0 ? { createdAt } : {};
218
+ }
219
+ function optionalName(source) {
220
+ return source.name !== void 0 ? { name: source.name } : {};
221
+ }
222
+ function isUiResourcePart(value) {
223
+ if (value == null || typeof value !== "object" || Array.isArray(value)) return false;
224
+ if (!("type" in value) || value.type !== "ui-resource") return false;
225
+ if (!("toolCallId" in value) || typeof value.toolCallId !== "string") return false;
226
+ if (!("toolName" in value) || typeof value.toolName !== "string") return false;
227
+ if (!("resource" in value) || value.resource == null || typeof value.resource !== "object" || Array.isArray(value.resource)) return false;
228
+ const resource = value.resource;
229
+ return "uri" in resource && typeof resource.uri === "string" && "mimeType" in resource && typeof resource.mimeType === "string";
230
+ }
231
+ function uiResourceKey(part) {
232
+ return `${part.toolCallId}\0${part.toolName}\0${part.resource.uri}`;
233
+ }
234
+ function appendUiResources(ui, resources) {
235
+ if (resources.length === 0) return ui;
236
+ const seen = new Set(ui.parts.filter(isUiResourcePart).map((part) => uiResourceKey(part)));
237
+ const extra = resources.filter((part) => !seen.has(uiResourceKey(part)));
238
+ if (extra.length === 0) return ui;
239
+ return {
240
+ ...ui,
241
+ parts: [...ui.parts, ...extra]
242
+ };
243
+ }
244
+ function assistantMetadata(uiMessage) {
245
+ const fromParts = uiMessage.parts.filter(isUiResourcePart);
246
+ const current = uiMessage.metadata ?? {};
247
+ const previous = tanstackMetadata(uiMessage);
248
+ const tanstack = {};
249
+ if (previous?.model !== void 0) tanstack.model = previous.model;
250
+ if (previous?.signature !== void 0) tanstack.signature = previous.signature;
251
+ if (fromParts.length > 0) tanstack.uiResources = fromParts;
252
+ const result = { ...current };
253
+ if (Object.keys(tanstack).length > 0) result.tanstack = tanstack;
254
+ else delete result.tanstack;
255
+ return Object.keys(result).length > 0 ? result : void 0;
256
+ }
134
257
  /**
135
258
  * Convert a UIMessage to ModelMessage(s)
136
259
  *
@@ -166,7 +289,9 @@ function buildUserOrToolMessage(uiMessage) {
166
289
  id: uiMessage.id,
167
290
  role: uiMessage.role,
168
291
  content: collapseContentParts(contentParts),
169
- ...uiMessage.createdAt !== void 0 && { createdAt: uiMessage.createdAt }
292
+ ...optionalName(uiMessage),
293
+ ...optionalCreatedAt(uiMessage),
294
+ ...uiMessage.metadata !== void 0 && { metadata: uiMessage.metadata }
170
295
  };
171
296
  }
172
297
  function createSegment() {
@@ -192,20 +317,29 @@ function buildAssistantMessages(uiMessage) {
192
317
  let current = createSegment();
193
318
  let pendingThinking = [];
194
319
  const emittedToolResultIds = /* @__PURE__ */ new Set();
195
- function flushSegment() {
320
+ const identityFields = {
321
+ id: uiMessage.id,
322
+ ...optionalName(uiMessage),
323
+ ...optionalCreatedAt(uiMessage)
324
+ };
325
+ const metadata = assistantMetadata(uiMessage);
326
+ const assistantFields = {
327
+ ...identityFields,
328
+ ...metadata !== void 0 && { metadata }
329
+ };
330
+ function flushSegment(force = false) {
196
331
  const content = collapseContentParts(current.contentParts);
197
332
  const hasContent = content !== null;
198
333
  const hasToolCalls = current.toolCalls.length > 0;
199
334
  const hasThinking = pendingThinking.length > 0;
200
- if (hasContent || hasToolCalls || hasThinking) {
335
+ if (force || hasContent || hasToolCalls || hasThinking) {
201
336
  messageList.push({
202
- id: uiMessage.id,
337
+ ...assistantFields,
203
338
  role: "assistant",
204
339
  content,
205
340
  ...hasToolCalls && { toolCalls: current.toolCalls },
206
341
  ...hasThinking && { thinking: pendingThinking },
207
- ...current.structuredOutput && { structuredOutput: current.structuredOutput },
208
- ...uiMessage.createdAt !== void 0 && { createdAt: uiMessage.createdAt }
342
+ ...current.structuredOutput && { structuredOutput: current.structuredOutput }
209
343
  });
210
344
  pendingThinking = [];
211
345
  }
@@ -231,14 +365,17 @@ function buildAssistantMessages(uiMessage) {
231
365
  });
232
366
  break;
233
367
  case "tool-result":
234
- flushSegment();
368
+ flushSegment(messageList.length === 0);
235
369
  if ((part.state === "complete" || part.state === "error") && !emittedToolResultIds.has(part.toolCallId)) {
236
370
  messageList.push({
237
- id: uiMessage.id,
371
+ ...part.id !== void 0 && { id: part.id },
372
+ ...optionalCreatedAt(part),
238
373
  role: "tool",
239
374
  content: part.content,
240
375
  toolCallId: part.toolCallId,
241
- ...uiMessage.createdAt !== void 0 && { createdAt: uiMessage.createdAt }
376
+ ...part.name !== void 0 && { name: part.name },
377
+ ...part.metadata !== void 0 && { metadata: part.metadata },
378
+ ...part.error !== void 0 && { error: part.error }
242
379
  });
243
380
  emittedToolResultIds.add(part.toolCallId);
244
381
  }
@@ -268,35 +405,30 @@ function buildAssistantMessages(uiMessage) {
268
405
  if (part.type !== "tool-call") continue;
269
406
  if (part.output !== void 0 && !emittedToolResultIds.has(part.id)) {
270
407
  messageList.push({
271
- id: uiMessage.id,
272
408
  role: "tool",
273
409
  content: normalizeToolResult(part.output),
274
- toolCallId: part.id,
275
- ...uiMessage.createdAt !== void 0 && { createdAt: uiMessage.createdAt }
410
+ toolCallId: part.id
276
411
  });
277
412
  emittedToolResultIds.add(part.id);
278
413
  }
279
414
  if (part.output === void 0 && part.state === "approval-responded" && part.approval?.approved !== void 0 && !emittedToolResultIds.has(part.id)) {
280
415
  const approved = part.approval.approved;
281
416
  messageList.push({
282
- id: uiMessage.id,
283
417
  role: "tool",
284
418
  content: JSON.stringify({
285
419
  approved,
286
420
  ...approved && { pendingExecution: true },
287
421
  message: approved ? "User approved this action" : "User denied this action"
288
422
  }),
289
- toolCallId: part.id,
290
- ...uiMessage.createdAt !== void 0 && { createdAt: uiMessage.createdAt }
423
+ toolCallId: part.id
291
424
  });
292
425
  emittedToolResultIds.add(part.id);
293
426
  }
294
427
  }
295
428
  if (messageList.length === 0) messageList.push({
296
- id: uiMessage.id,
429
+ ...assistantFields,
297
430
  role: "assistant",
298
- content: null,
299
- ...uiMessage.createdAt !== void 0 && { createdAt: uiMessage.createdAt }
431
+ content: null
300
432
  });
301
433
  return messageList;
302
434
  }
@@ -314,6 +446,7 @@ function buildAssistantMessages(uiMessage) {
314
446
  */
315
447
  function modelMessageToUIMessage(modelMessage, id) {
316
448
  const parts = [];
449
+ const createdAt = coerceCreatedAt(modelMessage.createdAt);
317
450
  if (modelMessage.role === "assistant" && modelMessage.thinking?.length) for (const thinking of modelMessage.thinking) {
318
451
  if (!thinking.content) continue;
319
452
  parts.push({
@@ -322,12 +455,27 @@ function modelMessageToUIMessage(modelMessage, id) {
322
455
  ...thinking.signature && { signature: thinking.signature }
323
456
  });
324
457
  }
325
- if (modelMessage.role === "assistant" && modelMessage.structuredOutput) parts.push(modelMessage.structuredOutput);
326
- else if (modelMessage.role === "tool" && modelMessage.toolCallId) parts.push({
458
+ const structuredOutput = modelMessage.structuredOutput ?? snapshotStructuredOutput(tanstackMetadata(modelMessage)?.structuredOutput);
459
+ if (modelMessage.role === "assistant" && structuredOutput) {
460
+ if (typeof modelMessage.content === "string" && modelMessage.content && modelMessage.content !== structuredOutput.raw) {
461
+ const suffix = structuredOutput.raw;
462
+ const text = suffix !== "" && modelMessage.content.endsWith(suffix) ? modelMessage.content.slice(0, -suffix.length) : modelMessage.content;
463
+ if (text) parts.push({
464
+ type: "text",
465
+ content: text
466
+ });
467
+ }
468
+ parts.push(structuredOutput);
469
+ } else if (modelMessage.role === "tool" && modelMessage.toolCallId) parts.push({
327
470
  type: "tool-result",
328
471
  toolCallId: modelMessage.toolCallId,
329
- content: getTextContent(modelMessage.content),
330
- state: "complete"
472
+ content: toolResultContent(modelMessage.content),
473
+ state: modelMessage.error === void 0 ? "complete" : "error",
474
+ ...modelMessage.id !== void 0 && { id: modelMessage.id },
475
+ ...modelMessage.name !== void 0 && { name: modelMessage.name },
476
+ ...modelMessage.metadata !== void 0 && { metadata: modelMessage.metadata },
477
+ ...createdAt !== void 0 && { createdAt },
478
+ ...modelMessage.error !== void 0 && { error: modelMessage.error }
331
479
  });
332
480
  else if (Array.isArray(modelMessage.content)) for (const part of modelMessage.content) parts.push(part);
333
481
  else {
@@ -354,12 +502,16 @@ function modelMessageToUIMessage(modelMessage, id) {
354
502
  ...toolCall.metadata !== void 0 && { metadata: toolCall.metadata }
355
503
  });
356
504
  }
357
- return {
505
+ const ui = {
358
506
  id: id || generateMessageId(),
359
507
  role: modelMessage.role === "tool" ? "assistant" : modelMessage.role,
360
508
  parts,
361
- ...modelMessage.createdAt !== void 0 && { createdAt: modelMessage.createdAt }
509
+ ...optionalName(modelMessage),
510
+ ...createdAt !== void 0 && { createdAt },
511
+ ...modelMessage.metadata !== void 0 && { metadata: modelMessage.metadata }
362
512
  };
513
+ const storedResources = tanstackMetadata(modelMessage)?.uiResources;
514
+ return appendUiResources(ui, Array.isArray(storedResources) ? storedResources.filter(isUiResourcePart) : []);
363
515
  }
364
516
  /**
365
517
  * Normalize a single AG-UI `MESSAGES_SNAPSHOT` message into a `UIMessage`.
@@ -390,25 +542,38 @@ function aguiSnapshotMessageToUIMessage(message) {
390
542
  parts: aguiUserContentToParts(message.content)
391
543
  });
392
544
  case "assistant": {
393
- const toolCallMetadata = tanstackMetadata(message)?.toolCallMetadata;
545
+ const metadata = tanstackMetadata(message);
546
+ const toolCallMetadata = metadata?.toolCallMetadata;
547
+ const structuredOutput = snapshotStructuredOutput(metadata?.structuredOutput);
394
548
  const toolCalls = message.toolCalls?.map((toolCall) => {
395
- const metadata = toolCallMetadata != null && typeof toolCallMetadata === "object" ? toolCallMetadata[toolCall.id] : void 0;
396
- return metadata !== void 0 ? {
549
+ const callMetadata = toolCallMetadata != null && typeof toolCallMetadata === "object" ? toolCallMetadata[toolCall.id] : void 0;
550
+ return callMetadata !== void 0 ? {
397
551
  ...toolCall,
398
- metadata
552
+ metadata: callMetadata
399
553
  } : toolCall;
400
554
  });
401
555
  return applySnapshotMetadata(message, modelMessageToUIMessage({
402
556
  role: "assistant",
403
557
  content: message.content ?? null,
404
- ...toolCalls && { toolCalls }
558
+ ...optionalName(message),
559
+ ...toolCalls && { toolCalls },
560
+ ...structuredOutput && { structuredOutput }
561
+ }, id));
562
+ }
563
+ case "tool": {
564
+ message = restoreToolResultOwnership(message);
565
+ const createdAt = coerceCreatedAt("createdAt" in message ? message.createdAt : void 0) ?? createdAtFromMetadata(message);
566
+ return applySnapshotMetadata(message, modelMessageToUIMessage({
567
+ role: "tool",
568
+ content: message.content,
569
+ toolCallId: message.toolCallId,
570
+ ..."name" in message && typeof message.name === "string" ? { name: message.name } : {},
571
+ ..."id" in message && typeof message.id === "string" ? { id: message.id } : {},
572
+ ..."metadata" in message && message.metadata != null ? { metadata: message.metadata } : {},
573
+ ...createdAt !== void 0 ? { createdAt } : {},
574
+ ...message.error !== void 0 && { error: message.error }
405
575
  }, id));
406
576
  }
407
- case "tool": return applySnapshotMetadata(message, modelMessageToUIMessage({
408
- role: "tool",
409
- content: message.content,
410
- toolCallId: message.toolCallId
411
- }, id));
412
577
  case "system":
413
578
  case "developer": return applySnapshotMetadata(message, {
414
579
  id,
@@ -439,17 +604,50 @@ function aguiSnapshotMessageToUIMessage(message) {
439
604
  }
440
605
  /** Copy snapshot metadata when it is a record. Rebuild createdAt from tanstack.createdAt. */
441
606
  function applySnapshotMetadata(source, ui) {
442
- if (!("metadata" in source)) return ui;
443
- const raw = source.metadata;
444
- if (raw == null || typeof raw !== "object" || Array.isArray(raw)) return ui;
445
- const metadata = raw;
446
- const createdAtRaw = tanstackMetadata(metadata)?.createdAt;
447
- const createdAt = typeof createdAtRaw === "string" ? new Date(createdAtRaw) : void 0;
448
- const createdAtValid = createdAt !== void 0 && !Number.isNaN(createdAt.getTime());
449
- return {
607
+ const normalizedParts = ui.parts.map((part) => normalizeMessagePart(part));
608
+ if (normalizedParts !== ui.parts) ui = {
609
+ ...ui,
610
+ parts: normalizedParts
611
+ };
612
+ const name = "name" in source && typeof source.name === "string" ? source.name : void 0;
613
+ let next = name !== void 0 ? {
450
614
  ...ui,
451
- metadata,
452
- ...createdAtValid ? { createdAt } : {}
615
+ name
616
+ } : ui;
617
+ let metadata;
618
+ if ("metadata" in source) {
619
+ const raw = source.metadata;
620
+ if (raw != null && typeof raw === "object" && !Array.isArray(raw)) {
621
+ metadata = raw;
622
+ next = {
623
+ ...next,
624
+ metadata
625
+ };
626
+ }
627
+ }
628
+ const createdAt = coerceCreatedAt(next.createdAt) ?? (metadata !== void 0 ? createdAtFromMetadata(metadata) : void 0);
629
+ if (createdAt !== void 0 && !Object.is(createdAt, next.createdAt)) next = {
630
+ ...next,
631
+ createdAt
632
+ };
633
+ else if (createdAt === void 0 && next.createdAt !== void 0) {
634
+ const { createdAt: _invalid, ...rest } = next;
635
+ next = rest;
636
+ }
637
+ const uiResources = tanstackMetadata(metadata)?.uiResources;
638
+ const resources = Array.isArray(uiResources) ? uiResources.filter(isUiResourcePart) : [];
639
+ return appendUiResources(next, resources);
640
+ }
641
+ function snapshotStructuredOutput(value) {
642
+ if (value == null || value.status !== "streaming" && value.status !== "complete" && value.status !== "error" || typeof value.raw !== "string") return;
643
+ return {
644
+ type: "structured-output",
645
+ status: value.status,
646
+ raw: value.raw,
647
+ ...value.partial !== void 0 ? { partial: value.partial } : {},
648
+ ...value.data !== void 0 ? { data: value.data } : {},
649
+ ...value.reasoning ? { reasoning: value.reasoning } : {},
650
+ ...value.errorMessage !== void 0 ? { errorMessage: value.errorMessage } : {}
453
651
  };
454
652
  }
455
653
  /**
@@ -487,17 +685,22 @@ function modelMessagesToUIMessages(modelMessages) {
487
685
  let currentAssistantMessage = null;
488
686
  for (const msg of modelMessages) if (msg.role === "tool") {
489
687
  if (msg.toolCallId !== void 0 && currentAssistantMessage && currentAssistantMessage.role === "assistant") {
490
- const content = getTextContent(msg.content);
688
+ const content = toolResultContent(msg.content);
491
689
  const toolCallPart = currentAssistantMessage.parts.find((part) => part.type === "tool-call" && part.id === msg.toolCallId);
492
690
  if (toolCallPart) {
493
- toolCallPart.output = parseToolResultContent(content);
494
- toolCallPart.state = "complete";
691
+ toolCallPart.output = typeof content === "string" ? parseToolResultContent(content) : content;
692
+ toolCallPart.state = msg.error === void 0 ? "complete" : "error";
495
693
  }
496
694
  currentAssistantMessage.parts.push({
497
695
  type: "tool-result",
498
696
  toolCallId: msg.toolCallId,
499
697
  content,
500
- state: "complete"
698
+ state: msg.error === void 0 ? "complete" : "error",
699
+ ...msg.id !== void 0 && msg.id !== currentAssistantMessage.id && { id: msg.id },
700
+ ...msg.name !== void 0 && { name: msg.name },
701
+ ...msg.metadata !== void 0 && { metadata: msg.metadata },
702
+ ...optionalCreatedAt(msg),
703
+ ...msg.error !== void 0 && { error: msg.error }
501
704
  });
502
705
  } else {
503
706
  const toolResultUIMessage = modelMessageToUIMessage(msg, msg.id);
@@ -520,14 +723,17 @@ function modelMessagesToUIMessages(modelMessages) {
520
723
  * @returns A UIMessage with guaranteed id and createdAt
521
724
  */
522
725
  function normalizeToUIMessage(message, generateId) {
523
- if ("parts" in message) return {
524
- ...message,
525
- id: message.id || generateId(),
526
- createdAt: message.createdAt || /* @__PURE__ */ new Date()
527
- };
528
- else return {
726
+ if ("parts" in message) {
727
+ const parts = message.parts.map((part) => normalizeMessagePart(part));
728
+ return {
729
+ ...message,
730
+ parts,
731
+ id: message.id || generateId(),
732
+ createdAt: coerceCreatedAt(message.createdAt) ?? /* @__PURE__ */ new Date()
733
+ };
734
+ } else return {
529
735
  ...modelMessageToUIMessage(message, generateId()),
530
- createdAt: message.createdAt ?? /* @__PURE__ */ new Date()
736
+ createdAt: coerceCreatedAt(message.createdAt) ?? /* @__PURE__ */ new Date()
531
737
  };
532
738
  }
533
739
  /**
@@ -537,6 +743,6 @@ function generateMessageId() {
537
743
  return `msg-${Date.now()}-${Math.random().toString(36).substring(7)}`;
538
744
  }
539
745
  //#endregion
540
- export { aguiSnapshotMessageToUIMessage, convertMessagesToModelMessages, generateMessageId, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, safeJsonStringify, uiMessageToModelMessages };
746
+ export { aguiSnapshotMessageToUIMessage, coerceCreatedAt, convertMessagesToModelMessages, generateMessageId, modelMessageToUIMessage, modelMessagesToUIMessages, normalizeToUIMessage, restoreToolResultOwnership, safeJsonStringify, uiMessageToModelMessages };
541
747
 
542
748
  //# sourceMappingURL=messages.js.map