@tanstack/ai 0.49.1 → 0.51.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.
- package/dist/esm/activities/chat/index.js +4 -4
- package/dist/esm/activities/chat/index.js.map +1 -1
- package/dist/esm/activities/chat/messages.d.ts +7 -0
- package/dist/esm/activities/chat/messages.js +270 -64
- package/dist/esm/activities/chat/messages.js.map +1 -1
- package/dist/esm/activities/chat/stream/processor.d.ts +2 -0
- package/dist/esm/activities/chat/stream/processor.js +46 -19
- package/dist/esm/activities/chat/stream/processor.js.map +1 -1
- package/dist/esm/client.js +1 -1
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +4 -3
- package/dist/esm/types.d.ts +18 -0
- package/dist/esm/utilities/ag-ui-wire.d.ts +20 -44
- package/dist/esm/utilities/ag-ui-wire.js +143 -34
- package/dist/esm/utilities/ag-ui-wire.js.map +1 -1
- package/dist/esm/utilities/errors.d.ts +27 -0
- package/dist/esm/utilities/errors.js +19 -1
- package/dist/esm/utilities/errors.js.map +1 -1
- package/package.json +2 -2
- package/skills/ai-core/SKILL.md +17 -0
- package/src/activities/chat/index.ts +3 -4
- package/src/activities/chat/messages.ts +344 -61
- package/src/activities/chat/stream/processor.ts +70 -16
- package/src/index.ts +2 -0
- package/src/types.ts +18 -0
- package/src/utilities/ag-ui-wire.ts +278 -73
- package/src/utilities/errors.ts +42 -0
|
@@ -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
|
|
84
|
-
|
|
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(
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
...
|
|
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
|
-
|
|
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
|
-
|
|
326
|
-
|
|
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:
|
|
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
|
-
|
|
505
|
+
const ui = {
|
|
358
506
|
id: id || generateMessageId(),
|
|
359
507
|
role: modelMessage.role === "tool" ? "assistant" : modelMessage.role,
|
|
360
508
|
parts,
|
|
361
|
-
...modelMessage
|
|
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
|
|
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
|
|
396
|
-
return
|
|
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
|
-
...
|
|
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
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
const
|
|
448
|
-
|
|
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
|
-
|
|
452
|
-
|
|
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 =
|
|
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)
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
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
|