@mastra/react 0.0.0-monorepo-binary-20251013210052 → 0.0.0-netlify-no-bundle-20251127120354
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +244 -2
- package/dist/index.cjs +520 -143
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +521 -145
- package/dist/index.js.map +1 -1
- package/dist/react.css +1 -1
- package/dist/src/agent/hooks.d.ts +11 -3
- package/dist/src/agent/types.d.ts +1 -0
- package/dist/src/lib/ai-sdk/index.d.ts +1 -0
- package/dist/src/lib/ai-sdk/memory/resolveInitialMessages.d.ts +10 -0
- package/dist/src/lib/ai-sdk/memory/resolveInitialMessages.test.d.ts +1 -0
- package/dist/src/lib/ai-sdk/transformers/AISdkNetworkTransformer.d.ts +1 -0
- package/dist/src/lib/ai-sdk/transformers/AISdkNetworkTransformer.test.d.ts +1 -0
- package/dist/src/lib/ai-sdk/types.d.ts +17 -0
- package/dist/src/lib/ai-sdk/utils/fromCoreUserMessageToUIMessage.d.ts +10 -0
- package/dist/src/lib/ai-sdk/utils/fromCoreUserMessageToUIMessage.test.d.ts +1 -0
- package/dist/src/lib/ai-sdk/utils/toUIMessage.test.d.ts +1 -0
- package/package.json +22 -13
package/dist/index.cjs
CHANGED
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
5
5
|
const jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
const react = require('react');
|
|
7
7
|
const clientJs = require('@mastra/client-js');
|
|
8
|
-
const
|
|
8
|
+
const uuid = require('@lukeed/uuid');
|
|
9
9
|
const lucideReact = require('lucide-react');
|
|
10
10
|
const tailwindMerge = require('tailwind-merge');
|
|
11
11
|
const hastUtilToJsxRuntime = require('hast-util-to-jsx-runtime');
|
|
@@ -254,35 +254,48 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
254
254
|
}
|
|
255
255
|
];
|
|
256
256
|
}
|
|
257
|
+
case "tool-error":
|
|
257
258
|
case "tool-result": {
|
|
258
259
|
const lastMessage = result[result.length - 1];
|
|
259
260
|
if (!lastMessage || lastMessage.role !== "assistant") return result;
|
|
260
261
|
const parts = [...lastMessage.parts];
|
|
261
262
|
const toolPartIndex = parts.findIndex(
|
|
262
|
-
(part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
|
|
263
|
+
(part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
|
|
263
264
|
);
|
|
264
265
|
if (toolPartIndex !== -1) {
|
|
265
266
|
const toolPart = parts[toolPartIndex];
|
|
266
|
-
if (toolPart.type === "dynamic-tool") {
|
|
267
|
-
|
|
267
|
+
if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
|
|
268
|
+
const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
|
|
269
|
+
const toolCallId = toolPart.toolCallId;
|
|
270
|
+
if (chunk.type === "tool-result" && chunk.payload.isError || chunk.type === "tool-error") {
|
|
271
|
+
const error = chunk.type === "tool-error" ? chunk.payload.error : chunk.payload.result;
|
|
268
272
|
parts[toolPartIndex] = {
|
|
269
273
|
type: "dynamic-tool",
|
|
270
|
-
toolName
|
|
271
|
-
toolCallId
|
|
274
|
+
toolName,
|
|
275
|
+
toolCallId,
|
|
272
276
|
state: "output-error",
|
|
273
277
|
input: toolPart.input,
|
|
274
|
-
errorText: String(
|
|
278
|
+
errorText: String(error),
|
|
275
279
|
callProviderMetadata: chunk.payload.providerMetadata
|
|
276
280
|
};
|
|
277
281
|
} else {
|
|
278
282
|
const isWorkflow = Boolean(chunk.payload.result?.result?.steps);
|
|
283
|
+
const isAgent = chunk?.from === "AGENT";
|
|
284
|
+
let output;
|
|
285
|
+
if (isWorkflow) {
|
|
286
|
+
output = chunk.payload.result?.result;
|
|
287
|
+
} else if (isAgent) {
|
|
288
|
+
output = parts[toolPartIndex].output ?? chunk.payload.result;
|
|
289
|
+
} else {
|
|
290
|
+
output = chunk.payload.result;
|
|
291
|
+
}
|
|
279
292
|
parts[toolPartIndex] = {
|
|
280
293
|
type: "dynamic-tool",
|
|
281
|
-
toolName
|
|
282
|
-
toolCallId
|
|
294
|
+
toolName,
|
|
295
|
+
toolCallId,
|
|
283
296
|
state: "output-available",
|
|
284
297
|
input: toolPart.input,
|
|
285
|
-
output
|
|
298
|
+
output,
|
|
286
299
|
callProviderMetadata: chunk.payload.providerMetadata
|
|
287
300
|
};
|
|
288
301
|
}
|
|
@@ -301,11 +314,14 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
301
314
|
if (!lastMessage || lastMessage.role !== "assistant") return result;
|
|
302
315
|
const parts = [...lastMessage.parts];
|
|
303
316
|
const toolPartIndex = parts.findIndex(
|
|
304
|
-
(part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
|
|
317
|
+
(part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
|
|
305
318
|
);
|
|
306
319
|
if (toolPartIndex !== -1) {
|
|
307
320
|
const toolPart = parts[toolPartIndex];
|
|
308
|
-
if (toolPart.type === "dynamic-tool") {
|
|
321
|
+
if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
|
|
322
|
+
const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : typeof toolPart.type === "string" && toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
|
|
323
|
+
const toolCallId = toolPart.toolCallId;
|
|
324
|
+
const input = toolPart.input;
|
|
309
325
|
if (chunk.payload.output?.type?.startsWith("workflow-")) {
|
|
310
326
|
const existingWorkflowState = toolPart.output || {};
|
|
311
327
|
const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(
|
|
@@ -313,14 +329,24 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
313
329
|
chunk.payload.output
|
|
314
330
|
);
|
|
315
331
|
parts[toolPartIndex] = {
|
|
316
|
-
|
|
332
|
+
type: "dynamic-tool",
|
|
333
|
+
toolName,
|
|
334
|
+
toolCallId,
|
|
335
|
+
state: "input-streaming",
|
|
336
|
+
input,
|
|
317
337
|
output: updatedWorkflowState
|
|
318
338
|
};
|
|
339
|
+
} else if (chunk.payload.output?.from === "AGENT" || chunk.payload.output?.from === "USER" && chunk.payload.output?.payload?.output?.type?.startsWith("workflow-")) {
|
|
340
|
+
return toUIMessageFromAgent(chunk.payload.output, conversation);
|
|
319
341
|
} else {
|
|
320
342
|
const currentOutput = toolPart.output || [];
|
|
321
343
|
const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
|
|
322
344
|
parts[toolPartIndex] = {
|
|
323
|
-
|
|
345
|
+
type: "dynamic-tool",
|
|
346
|
+
toolName,
|
|
347
|
+
toolCallId,
|
|
348
|
+
state: "input-streaming",
|
|
349
|
+
input,
|
|
324
350
|
output: [...existingOutput, chunk.payload.output]
|
|
325
351
|
};
|
|
326
352
|
}
|
|
@@ -389,15 +415,37 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
389
415
|
}
|
|
390
416
|
];
|
|
391
417
|
}
|
|
418
|
+
case "tool-call-approval": {
|
|
419
|
+
const lastMessage = result[result.length - 1];
|
|
420
|
+
if (!lastMessage || lastMessage.role !== "assistant") return result;
|
|
421
|
+
const lastRequireApprovalMetadata = lastMessage.metadata?.mode === "stream" ? lastMessage.metadata?.requireApprovalMetadata : {};
|
|
422
|
+
return [
|
|
423
|
+
...result.slice(0, -1),
|
|
424
|
+
{
|
|
425
|
+
...lastMessage,
|
|
426
|
+
metadata: {
|
|
427
|
+
...lastMessage.metadata,
|
|
428
|
+
mode: "stream",
|
|
429
|
+
requireApprovalMetadata: {
|
|
430
|
+
...lastRequireApprovalMetadata,
|
|
431
|
+
[chunk.payload.toolCallId]: {
|
|
432
|
+
toolCallId: chunk.payload.toolCallId,
|
|
433
|
+
toolName: chunk.payload.toolName,
|
|
434
|
+
args: chunk.payload.args
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
];
|
|
440
|
+
}
|
|
392
441
|
case "finish": {
|
|
393
442
|
const lastMessage = result[result.length - 1];
|
|
394
443
|
if (!lastMessage || lastMessage.role !== "assistant") return result;
|
|
395
444
|
const parts = lastMessage.parts.map((part) => {
|
|
396
|
-
if (part
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
return { ...part, state: "done" };
|
|
445
|
+
if (typeof part === "object" && part !== null && "type" in part && "state" in part && part.state === "streaming") {
|
|
446
|
+
if (part.type === "text" || part.type === "reasoning") {
|
|
447
|
+
return { ...part, state: "done" };
|
|
448
|
+
}
|
|
401
449
|
}
|
|
402
450
|
return part;
|
|
403
451
|
});
|
|
@@ -431,6 +479,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
431
479
|
return result;
|
|
432
480
|
}
|
|
433
481
|
};
|
|
482
|
+
const toUIMessageFromAgent = (chunk, conversation, metadata) => {
|
|
483
|
+
const lastMessage = conversation[conversation.length - 1];
|
|
484
|
+
if (!lastMessage || lastMessage.role !== "assistant") return conversation;
|
|
485
|
+
const parts = [...lastMessage.parts];
|
|
486
|
+
if (chunk.type === "text-delta") {
|
|
487
|
+
const agentChunk = chunk.payload;
|
|
488
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
489
|
+
if (toolPartIndex === -1) return conversation;
|
|
490
|
+
const toolPart = parts[toolPartIndex];
|
|
491
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
492
|
+
const lastChildMessage = childMessages[childMessages.length - 1];
|
|
493
|
+
const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
|
|
494
|
+
const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
|
|
495
|
+
parts[toolPartIndex] = {
|
|
496
|
+
...toolPart,
|
|
497
|
+
output: {
|
|
498
|
+
childMessages: nextMessages
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
} else if (chunk.type === "tool-call") {
|
|
502
|
+
const agentChunk = chunk.payload;
|
|
503
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
504
|
+
if (toolPartIndex === -1) return conversation;
|
|
505
|
+
const toolPart = parts[toolPartIndex];
|
|
506
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
507
|
+
parts[toolPartIndex] = {
|
|
508
|
+
...toolPart,
|
|
509
|
+
output: {
|
|
510
|
+
...toolPart?.output,
|
|
511
|
+
childMessages: [
|
|
512
|
+
...childMessages,
|
|
513
|
+
{
|
|
514
|
+
type: "tool",
|
|
515
|
+
toolCallId: agentChunk.toolCallId,
|
|
516
|
+
toolName: agentChunk.toolName,
|
|
517
|
+
args: agentChunk.args
|
|
518
|
+
}
|
|
519
|
+
]
|
|
520
|
+
}
|
|
521
|
+
};
|
|
522
|
+
} else if (chunk.type === "tool-output") {
|
|
523
|
+
const agentChunk = chunk.payload;
|
|
524
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
525
|
+
if (toolPartIndex === -1) return conversation;
|
|
526
|
+
const toolPart = parts[toolPartIndex];
|
|
527
|
+
if (agentChunk?.output?.type?.startsWith("workflow-")) {
|
|
528
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
529
|
+
const lastToolIndex = childMessages.length - 1;
|
|
530
|
+
const currentMessage = childMessages[lastToolIndex];
|
|
531
|
+
const actualExistingWorkflowState = currentMessage?.toolOutput || {};
|
|
532
|
+
const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
|
|
533
|
+
if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
|
|
534
|
+
parts[toolPartIndex] = {
|
|
535
|
+
...toolPart,
|
|
536
|
+
output: {
|
|
537
|
+
...toolPart?.output,
|
|
538
|
+
childMessages: [
|
|
539
|
+
...childMessages.slice(0, -1),
|
|
540
|
+
{
|
|
541
|
+
...currentMessage,
|
|
542
|
+
toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
|
|
543
|
+
}
|
|
544
|
+
]
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
} else if (chunk.type === "tool-result") {
|
|
550
|
+
const agentChunk = chunk.payload;
|
|
551
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
552
|
+
if (toolPartIndex === -1) return conversation;
|
|
553
|
+
const toolPart = parts[toolPartIndex];
|
|
554
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
555
|
+
const lastToolIndex = childMessages.length - 1;
|
|
556
|
+
const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
|
|
557
|
+
if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
|
|
558
|
+
parts[toolPartIndex] = {
|
|
559
|
+
...toolPart,
|
|
560
|
+
output: {
|
|
561
|
+
...toolPart?.output,
|
|
562
|
+
childMessages: [
|
|
563
|
+
...childMessages.slice(0, -1),
|
|
564
|
+
{
|
|
565
|
+
...childMessages[lastToolIndex],
|
|
566
|
+
toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
|
|
567
|
+
}
|
|
568
|
+
]
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return [
|
|
574
|
+
...conversation.slice(0, -1),
|
|
575
|
+
{
|
|
576
|
+
...lastMessage,
|
|
577
|
+
parts
|
|
578
|
+
}
|
|
579
|
+
];
|
|
580
|
+
};
|
|
434
581
|
|
|
435
582
|
const toAssistantUIMessage = (message) => {
|
|
436
583
|
const extendedMessage = message;
|
|
@@ -470,13 +617,23 @@ const toAssistantUIMessage = (message) => {
|
|
|
470
617
|
};
|
|
471
618
|
}
|
|
472
619
|
if (part.type === "file") {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
620
|
+
const type = part.mediaType.includes("image/") ? "image" : "file";
|
|
621
|
+
if (type === "file") {
|
|
622
|
+
return {
|
|
623
|
+
type,
|
|
624
|
+
mimeType: part.mediaType,
|
|
625
|
+
data: part.url,
|
|
626
|
+
// Use URL as data source
|
|
627
|
+
metadata: message.metadata
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
if (type === "image") {
|
|
631
|
+
return {
|
|
632
|
+
type,
|
|
633
|
+
image: part.url,
|
|
634
|
+
metadata: message.metadata
|
|
635
|
+
};
|
|
636
|
+
}
|
|
480
637
|
}
|
|
481
638
|
if (part.type === "dynamic-tool") {
|
|
482
639
|
const baseToolCall = {
|
|
@@ -512,6 +669,20 @@ const toAssistantUIMessage = (message) => {
|
|
|
512
669
|
}
|
|
513
670
|
return baseToolCall;
|
|
514
671
|
}
|
|
672
|
+
const requireApprovalMetadata = extendedMessage.metadata?.requireApprovalMetadata;
|
|
673
|
+
const partToolCallId = "toolCallId" in part && typeof part.toolCallId === "string" ? part.toolCallId : void 0;
|
|
674
|
+
const suspensionData = partToolCallId ? requireApprovalMetadata?.[partToolCallId] : void 0;
|
|
675
|
+
if (suspensionData) {
|
|
676
|
+
const toolName = "toolName" in part && typeof part.toolName === "string" ? part.toolName : part.type.startsWith("tool-") ? part.type.substring(5) : "";
|
|
677
|
+
return {
|
|
678
|
+
type: "tool-call",
|
|
679
|
+
toolCallId: partToolCallId,
|
|
680
|
+
toolName,
|
|
681
|
+
argsText: "input" in part ? JSON.stringify(part.input) : "{}",
|
|
682
|
+
args: "input" in part ? part.input : {},
|
|
683
|
+
metadata: extendedMessage.metadata
|
|
684
|
+
};
|
|
685
|
+
}
|
|
515
686
|
return {
|
|
516
687
|
type: "text",
|
|
517
688
|
text: "",
|
|
@@ -551,9 +722,129 @@ const toAssistantUIMessage = (message) => {
|
|
|
551
722
|
return threadMessage;
|
|
552
723
|
};
|
|
553
724
|
|
|
725
|
+
const resolveInitialMessages = (messages) => {
|
|
726
|
+
return messages.map((message) => {
|
|
727
|
+
const networkPart = message.parts.find(
|
|
728
|
+
(part) => typeof part === "object" && part !== null && "type" in part && part.type === "text" && "text" in part && typeof part.text === "string" && part.text.includes('"isNetwork":true')
|
|
729
|
+
);
|
|
730
|
+
if (networkPart && networkPart.type === "text") {
|
|
731
|
+
try {
|
|
732
|
+
const json = JSON.parse(networkPart.text);
|
|
733
|
+
if (json.isNetwork === true) {
|
|
734
|
+
const selectionReason = json.selectionReason || "";
|
|
735
|
+
const primitiveType = json.primitiveType || "";
|
|
736
|
+
const primitiveId = json.primitiveId || "";
|
|
737
|
+
const finalResult = json.finalResult;
|
|
738
|
+
const toolCalls = finalResult?.toolCalls || [];
|
|
739
|
+
const childMessages = [];
|
|
740
|
+
for (const toolCall of toolCalls) {
|
|
741
|
+
if (toolCall.type === "tool-call" && toolCall.payload) {
|
|
742
|
+
const toolCallId = toolCall.payload.toolCallId;
|
|
743
|
+
let toolResult;
|
|
744
|
+
for (const message2 of finalResult?.messages || []) {
|
|
745
|
+
for (const part of message2.content || []) {
|
|
746
|
+
if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
|
|
747
|
+
toolResult = part;
|
|
748
|
+
break;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
const isWorkflow = Boolean(toolResult?.result?.result?.steps);
|
|
753
|
+
childMessages.push({
|
|
754
|
+
type: "tool",
|
|
755
|
+
toolCallId: toolCall.payload.toolCallId,
|
|
756
|
+
toolName: toolCall.payload.toolName,
|
|
757
|
+
args: toolCall.payload.args,
|
|
758
|
+
toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
if (finalResult && finalResult.text) {
|
|
763
|
+
childMessages.push({
|
|
764
|
+
type: "text",
|
|
765
|
+
content: finalResult.text
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
const result = {
|
|
769
|
+
childMessages,
|
|
770
|
+
result: finalResult?.text || ""
|
|
771
|
+
};
|
|
772
|
+
const nextMessage = {
|
|
773
|
+
role: "assistant",
|
|
774
|
+
parts: [
|
|
775
|
+
{
|
|
776
|
+
type: "dynamic-tool",
|
|
777
|
+
toolCallId: primitiveId,
|
|
778
|
+
toolName: primitiveId,
|
|
779
|
+
state: "output-available",
|
|
780
|
+
input: json.input,
|
|
781
|
+
output: result
|
|
782
|
+
}
|
|
783
|
+
],
|
|
784
|
+
id: message.id,
|
|
785
|
+
metadata: {
|
|
786
|
+
...message.metadata,
|
|
787
|
+
mode: "network",
|
|
788
|
+
selectionReason,
|
|
789
|
+
agentInput: json.input,
|
|
790
|
+
from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
return nextMessage;
|
|
794
|
+
}
|
|
795
|
+
} catch (error) {
|
|
796
|
+
return message;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
const extendedMessage = message;
|
|
800
|
+
const pendingToolApprovals = extendedMessage.metadata?.pendingToolApprovals;
|
|
801
|
+
if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
|
|
802
|
+
return {
|
|
803
|
+
...message,
|
|
804
|
+
metadata: {
|
|
805
|
+
...message.metadata,
|
|
806
|
+
mode: "stream",
|
|
807
|
+
requireApprovalMetadata: pendingToolApprovals
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
return message;
|
|
812
|
+
});
|
|
813
|
+
};
|
|
814
|
+
const resolveToChildMessages = (messages) => {
|
|
815
|
+
const assistantMessage = messages.find((message) => message.role === "assistant");
|
|
816
|
+
if (!assistantMessage) return [];
|
|
817
|
+
const parts = assistantMessage.parts;
|
|
818
|
+
let childMessages = [];
|
|
819
|
+
for (const part of parts) {
|
|
820
|
+
const toolPart = part;
|
|
821
|
+
if (part.type.startsWith("tool-")) {
|
|
822
|
+
const toolName = part.type.substring("tool-".length);
|
|
823
|
+
const isWorkflow = toolName.startsWith("workflow-");
|
|
824
|
+
childMessages.push({
|
|
825
|
+
type: "tool",
|
|
826
|
+
toolCallId: toolPart.toolCallId,
|
|
827
|
+
toolName,
|
|
828
|
+
args: toolPart.input,
|
|
829
|
+
toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
if (part.type === "text") {
|
|
833
|
+
childMessages.push({
|
|
834
|
+
type: "text",
|
|
835
|
+
content: toolPart.text
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
return childMessages;
|
|
840
|
+
};
|
|
841
|
+
|
|
554
842
|
class AISdkNetworkTransformer {
|
|
555
843
|
transform({ chunk, conversation, metadata }) {
|
|
556
844
|
const newConversation = [...conversation];
|
|
845
|
+
if (chunk.type === "routing-agent-text-delta") {
|
|
846
|
+
return this.handleRoutingAgentConversation(chunk, newConversation);
|
|
847
|
+
}
|
|
557
848
|
if (chunk.type.startsWith("agent-execution-")) {
|
|
558
849
|
return this.handleAgentConversation(chunk, newConversation, metadata);
|
|
559
850
|
}
|
|
@@ -564,22 +855,80 @@ class AISdkNetworkTransformer {
|
|
|
564
855
|
return this.handleToolConversation(chunk, newConversation, metadata);
|
|
565
856
|
}
|
|
566
857
|
if (chunk.type === "network-execution-event-step-finish") {
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
858
|
+
const lastMessage = newConversation[newConversation.length - 1];
|
|
859
|
+
if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
|
|
860
|
+
const agentChunk = chunk.payload;
|
|
861
|
+
const parts = [...lastMessage.parts];
|
|
862
|
+
const textPartIndex = parts.findIndex((part) => part.type === "text");
|
|
863
|
+
if (textPartIndex === -1) {
|
|
864
|
+
parts.push({
|
|
865
|
+
type: "text",
|
|
866
|
+
text: agentChunk.result,
|
|
867
|
+
state: "done"
|
|
868
|
+
});
|
|
869
|
+
return [
|
|
870
|
+
...newConversation.slice(0, -1),
|
|
571
871
|
{
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
state: "done"
|
|
872
|
+
...lastMessage,
|
|
873
|
+
parts
|
|
575
874
|
}
|
|
576
|
-
]
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
875
|
+
];
|
|
876
|
+
}
|
|
877
|
+
const textPart = parts[textPartIndex];
|
|
878
|
+
if (textPart.type === "text") {
|
|
879
|
+
parts[textPartIndex] = {
|
|
880
|
+
...textPart,
|
|
881
|
+
state: "done"
|
|
882
|
+
};
|
|
883
|
+
return [
|
|
884
|
+
...newConversation.slice(0, -1),
|
|
885
|
+
{
|
|
886
|
+
...lastMessage,
|
|
887
|
+
parts
|
|
888
|
+
}
|
|
889
|
+
];
|
|
890
|
+
}
|
|
891
|
+
return newConversation;
|
|
580
892
|
}
|
|
581
893
|
return newConversation;
|
|
582
894
|
}
|
|
895
|
+
handleRoutingAgentConversation = (chunk, newConversation) => {
|
|
896
|
+
const lastMessage = newConversation[newConversation.length - 1];
|
|
897
|
+
if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
|
|
898
|
+
const agentChunk = chunk.payload;
|
|
899
|
+
const parts = [...lastMessage.parts];
|
|
900
|
+
const textPartIndex = parts.findIndex((part) => part.type === "text");
|
|
901
|
+
if (textPartIndex === -1) {
|
|
902
|
+
parts.push({
|
|
903
|
+
type: "text",
|
|
904
|
+
text: agentChunk.text,
|
|
905
|
+
state: "streaming"
|
|
906
|
+
});
|
|
907
|
+
return [
|
|
908
|
+
...newConversation.slice(0, -1),
|
|
909
|
+
{
|
|
910
|
+
...lastMessage,
|
|
911
|
+
parts
|
|
912
|
+
}
|
|
913
|
+
];
|
|
914
|
+
}
|
|
915
|
+
const textPart = parts[textPartIndex];
|
|
916
|
+
if (textPart.type === "text") {
|
|
917
|
+
parts[textPartIndex] = {
|
|
918
|
+
...textPart,
|
|
919
|
+
text: textPart.text + agentChunk.text,
|
|
920
|
+
state: "streaming"
|
|
921
|
+
};
|
|
922
|
+
return [
|
|
923
|
+
...newConversation.slice(0, -1),
|
|
924
|
+
{
|
|
925
|
+
...lastMessage,
|
|
926
|
+
parts
|
|
927
|
+
}
|
|
928
|
+
];
|
|
929
|
+
}
|
|
930
|
+
return newConversation;
|
|
931
|
+
};
|
|
583
932
|
handleAgentConversation = (chunk, newConversation, metadata) => {
|
|
584
933
|
if (chunk.type === "agent-execution-start") {
|
|
585
934
|
const primitiveId = chunk.payload?.args?.primitiveId;
|
|
@@ -862,92 +1211,75 @@ class AISdkNetworkTransformer {
|
|
|
862
1211
|
};
|
|
863
1212
|
}
|
|
864
1213
|
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
if (finalResult && finalResult.text) {
|
|
901
|
-
childMessages.push({
|
|
902
|
-
type: "text",
|
|
903
|
-
content: finalResult.text
|
|
904
|
-
});
|
|
905
|
-
}
|
|
906
|
-
const result = {
|
|
907
|
-
childMessages,
|
|
908
|
-
result: finalResult?.text || ""
|
|
909
|
-
};
|
|
910
|
-
console.log("json", json);
|
|
911
|
-
const nextMessage = {
|
|
912
|
-
role: "assistant",
|
|
913
|
-
parts: [
|
|
914
|
-
{
|
|
915
|
-
type: "dynamic-tool",
|
|
916
|
-
toolCallId: primitiveId,
|
|
917
|
-
toolName: primitiveId,
|
|
918
|
-
state: "output-available",
|
|
919
|
-
input: json.input,
|
|
920
|
-
output: result
|
|
921
|
-
}
|
|
922
|
-
],
|
|
923
|
-
id: message.id,
|
|
924
|
-
metadata: {
|
|
925
|
-
...message.metadata,
|
|
926
|
-
mode: "network",
|
|
927
|
-
selectionReason,
|
|
928
|
-
agentInput: json.input,
|
|
929
|
-
from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
|
|
930
|
-
}
|
|
931
|
-
};
|
|
932
|
-
return nextMessage;
|
|
933
|
-
}
|
|
934
|
-
} catch (error) {
|
|
935
|
-
return message;
|
|
1214
|
+
const fromCoreUserMessageToUIMessage = (coreUserMessage) => {
|
|
1215
|
+
const id = `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
1216
|
+
const parts = typeof coreUserMessage.content === "string" ? [
|
|
1217
|
+
{
|
|
1218
|
+
type: "text",
|
|
1219
|
+
text: coreUserMessage.content
|
|
1220
|
+
}
|
|
1221
|
+
] : coreUserMessage.content.map((part) => {
|
|
1222
|
+
switch (part.type) {
|
|
1223
|
+
case "text": {
|
|
1224
|
+
return {
|
|
1225
|
+
type: "text",
|
|
1226
|
+
text: part.text
|
|
1227
|
+
};
|
|
1228
|
+
}
|
|
1229
|
+
case "image": {
|
|
1230
|
+
const url = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
|
|
1231
|
+
return {
|
|
1232
|
+
type: "file",
|
|
1233
|
+
mediaType: part.mimeType ?? "image/*",
|
|
1234
|
+
url
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
case "file": {
|
|
1238
|
+
const url = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
|
|
1239
|
+
return {
|
|
1240
|
+
type: "file",
|
|
1241
|
+
mediaType: part.mimeType,
|
|
1242
|
+
url,
|
|
1243
|
+
...part.filename !== void 0 ? { filename: part.filename } : {}
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
default: {
|
|
1247
|
+
const exhaustiveCheck = part;
|
|
1248
|
+
throw new Error(`Unhandled content part type: ${exhaustiveCheck.type}`);
|
|
936
1249
|
}
|
|
937
1250
|
}
|
|
938
|
-
return message;
|
|
939
1251
|
});
|
|
1252
|
+
return {
|
|
1253
|
+
id,
|
|
1254
|
+
role: "user",
|
|
1255
|
+
parts
|
|
1256
|
+
};
|
|
940
1257
|
};
|
|
941
1258
|
|
|
942
|
-
const useChat = ({ agentId, initializeMessages }) => {
|
|
943
|
-
const
|
|
944
|
-
(
|
|
945
|
-
|
|
1259
|
+
const useChat = ({ agentId, resourceId, initializeMessages }) => {
|
|
1260
|
+
const extractRunIdFromMessages = (messages2) => {
|
|
1261
|
+
for (const message of messages2) {
|
|
1262
|
+
const pendingToolApprovals = message.metadata?.pendingToolApprovals;
|
|
1263
|
+
if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
|
|
1264
|
+
const suspensionData = Object.values(pendingToolApprovals)[0];
|
|
1265
|
+
if (suspensionData?.runId) {
|
|
1266
|
+
return suspensionData.runId;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
return void 0;
|
|
1271
|
+
};
|
|
1272
|
+
const initialMessages = initializeMessages?.() || [];
|
|
1273
|
+
const initialRunId = extractRunIdFromMessages(initialMessages);
|
|
1274
|
+
const _currentRunId = react.useRef(initialRunId);
|
|
1275
|
+
const _onChunk = react.useRef(void 0);
|
|
1276
|
+
const [messages, setMessages] = react.useState(() => resolveInitialMessages(initialMessages));
|
|
1277
|
+
const [toolCallApprovals, setToolCallApprovals] = react.useState({});
|
|
946
1278
|
const baseClient = useMastraClient();
|
|
947
1279
|
const [isRunning, setIsRunning] = react.useState(false);
|
|
948
1280
|
const generate = async ({
|
|
949
1281
|
coreUserMessages,
|
|
950
|
-
|
|
1282
|
+
requestContext,
|
|
951
1283
|
threadId,
|
|
952
1284
|
modelSettings,
|
|
953
1285
|
signal,
|
|
@@ -973,7 +1305,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
973
1305
|
const agent = clientWithAbort.getAgent(agentId);
|
|
974
1306
|
const response = await agent.generate({
|
|
975
1307
|
messages: coreUserMessages,
|
|
976
|
-
runId:
|
|
1308
|
+
runId: uuid.v4(),
|
|
977
1309
|
maxSteps,
|
|
978
1310
|
modelSettings: {
|
|
979
1311
|
frequencyPenalty,
|
|
@@ -985,8 +1317,8 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
985
1317
|
topP
|
|
986
1318
|
},
|
|
987
1319
|
instructions,
|
|
988
|
-
|
|
989
|
-
...threadId ? { threadId, resourceId: agentId } : {},
|
|
1320
|
+
requestContext,
|
|
1321
|
+
...threadId ? { threadId, resourceId: resourceId || agentId } : {},
|
|
990
1322
|
providerOptions
|
|
991
1323
|
});
|
|
992
1324
|
setIsRunning(false);
|
|
@@ -1001,7 +1333,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1001
1333
|
setMessages((prev) => [...prev, ...mastraUIMessages]);
|
|
1002
1334
|
}
|
|
1003
1335
|
};
|
|
1004
|
-
const stream = async ({ coreUserMessages,
|
|
1336
|
+
const stream = async ({ coreUserMessages, requestContext, threadId, onChunk, modelSettings, signal }) => {
|
|
1005
1337
|
const {
|
|
1006
1338
|
frequencyPenalty,
|
|
1007
1339
|
presencePenalty,
|
|
@@ -1012,7 +1344,8 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1012
1344
|
topP,
|
|
1013
1345
|
instructions,
|
|
1014
1346
|
providerOptions,
|
|
1015
|
-
maxSteps
|
|
1347
|
+
maxSteps,
|
|
1348
|
+
requireToolApproval
|
|
1016
1349
|
} = modelSettings || {};
|
|
1017
1350
|
setIsRunning(true);
|
|
1018
1351
|
const clientWithAbort = new clientJs.MastraClient({
|
|
@@ -1020,9 +1353,10 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1020
1353
|
abortSignal: signal
|
|
1021
1354
|
});
|
|
1022
1355
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1356
|
+
const runId = uuid.v4();
|
|
1023
1357
|
const response = await agent.stream({
|
|
1024
1358
|
messages: coreUserMessages,
|
|
1025
|
-
runId
|
|
1359
|
+
runId,
|
|
1026
1360
|
maxSteps,
|
|
1027
1361
|
modelSettings: {
|
|
1028
1362
|
frequencyPenalty,
|
|
@@ -1034,19 +1368,16 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1034
1368
|
topP
|
|
1035
1369
|
},
|
|
1036
1370
|
instructions,
|
|
1037
|
-
|
|
1038
|
-
...threadId ? { threadId, resourceId: agentId } : {},
|
|
1039
|
-
providerOptions
|
|
1371
|
+
requestContext,
|
|
1372
|
+
...threadId ? { threadId, resourceId: resourceId || agentId } : {},
|
|
1373
|
+
providerOptions,
|
|
1374
|
+
requireToolApproval
|
|
1040
1375
|
});
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
throw new Error("[Stream] No response body");
|
|
1044
|
-
}
|
|
1376
|
+
_onChunk.current = onChunk;
|
|
1377
|
+
_currentRunId.current = runId;
|
|
1045
1378
|
await response.processDataStream({
|
|
1046
1379
|
onChunk: async (chunk) => {
|
|
1047
|
-
|
|
1048
|
-
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1049
|
-
});
|
|
1380
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1050
1381
|
onChunk?.(chunk);
|
|
1051
1382
|
}
|
|
1052
1383
|
});
|
|
@@ -1054,7 +1385,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1054
1385
|
};
|
|
1055
1386
|
const network = async ({
|
|
1056
1387
|
coreUserMessages,
|
|
1057
|
-
|
|
1388
|
+
requestContext,
|
|
1058
1389
|
threadId,
|
|
1059
1390
|
onNetworkChunk,
|
|
1060
1391
|
modelSettings,
|
|
@@ -1067,6 +1398,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1067
1398
|
abortSignal: signal
|
|
1068
1399
|
});
|
|
1069
1400
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1401
|
+
const runId = uuid.v4();
|
|
1070
1402
|
const response = await agent.network({
|
|
1071
1403
|
messages: coreUserMessages,
|
|
1072
1404
|
maxSteps,
|
|
@@ -1079,31 +1411,72 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1079
1411
|
topK,
|
|
1080
1412
|
topP
|
|
1081
1413
|
},
|
|
1082
|
-
runId
|
|
1083
|
-
|
|
1084
|
-
...threadId ? { thread: threadId, resourceId: agentId } : {}
|
|
1414
|
+
runId,
|
|
1415
|
+
requestContext,
|
|
1416
|
+
...threadId ? { thread: threadId, resourceId: resourceId || agentId } : {}
|
|
1085
1417
|
});
|
|
1086
1418
|
const transformer = new AISdkNetworkTransformer();
|
|
1087
1419
|
await response.processDataStream({
|
|
1088
1420
|
onChunk: async (chunk) => {
|
|
1089
|
-
|
|
1090
|
-
setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
|
|
1091
|
-
});
|
|
1421
|
+
setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
|
|
1092
1422
|
onNetworkChunk?.(chunk);
|
|
1093
1423
|
}
|
|
1094
1424
|
});
|
|
1095
1425
|
setIsRunning(false);
|
|
1096
1426
|
};
|
|
1427
|
+
const handleCancelRun = () => {
|
|
1428
|
+
setIsRunning(false);
|
|
1429
|
+
_currentRunId.current = void 0;
|
|
1430
|
+
_onChunk.current = void 0;
|
|
1431
|
+
};
|
|
1432
|
+
const approveToolCall = async (toolCallId) => {
|
|
1433
|
+
const onChunk = _onChunk.current;
|
|
1434
|
+
const currentRunId = _currentRunId.current;
|
|
1435
|
+
if (!currentRunId)
|
|
1436
|
+
return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
|
|
1437
|
+
setIsRunning(true);
|
|
1438
|
+
setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
|
|
1439
|
+
const agent = baseClient.getAgent(agentId);
|
|
1440
|
+
const response = await agent.approveToolCall({ runId: currentRunId, toolCallId });
|
|
1441
|
+
await response.processDataStream({
|
|
1442
|
+
onChunk: async (chunk) => {
|
|
1443
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1444
|
+
onChunk?.(chunk);
|
|
1445
|
+
}
|
|
1446
|
+
});
|
|
1447
|
+
setIsRunning(false);
|
|
1448
|
+
};
|
|
1449
|
+
const declineToolCall = async (toolCallId) => {
|
|
1450
|
+
const onChunk = _onChunk.current;
|
|
1451
|
+
const currentRunId = _currentRunId.current;
|
|
1452
|
+
if (!currentRunId)
|
|
1453
|
+
return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
|
|
1454
|
+
setIsRunning(true);
|
|
1455
|
+
setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
|
|
1456
|
+
const agent = baseClient.getAgent(agentId);
|
|
1457
|
+
const response = await agent.declineToolCall({ runId: currentRunId, toolCallId });
|
|
1458
|
+
await response.processDataStream({
|
|
1459
|
+
onChunk: async (chunk) => {
|
|
1460
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1461
|
+
onChunk?.(chunk);
|
|
1462
|
+
}
|
|
1463
|
+
});
|
|
1464
|
+
setIsRunning(false);
|
|
1465
|
+
};
|
|
1097
1466
|
const sendMessage = async ({ mode = "stream", ...args }) => {
|
|
1098
1467
|
const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
|
|
1099
|
-
const
|
|
1100
|
-
|
|
1468
|
+
const coreUserMessages = [nextMessage];
|
|
1469
|
+
if (args.coreUserMessages) {
|
|
1470
|
+
coreUserMessages.push(...args.coreUserMessages);
|
|
1471
|
+
}
|
|
1472
|
+
const uiMessages = coreUserMessages.map(fromCoreUserMessageToUIMessage);
|
|
1473
|
+
setMessages((s) => [...s, ...uiMessages]);
|
|
1101
1474
|
if (mode === "generate") {
|
|
1102
|
-
await generate({ ...args, coreUserMessages
|
|
1475
|
+
await generate({ ...args, coreUserMessages });
|
|
1103
1476
|
} else if (mode === "stream") {
|
|
1104
|
-
await stream({ ...args, coreUserMessages
|
|
1477
|
+
await stream({ ...args, coreUserMessages });
|
|
1105
1478
|
} else if (mode === "network") {
|
|
1106
|
-
await network({ ...args, coreUserMessages
|
|
1479
|
+
await network({ ...args, coreUserMessages });
|
|
1107
1480
|
}
|
|
1108
1481
|
};
|
|
1109
1482
|
return {
|
|
@@ -1111,7 +1484,10 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1111
1484
|
sendMessage,
|
|
1112
1485
|
isRunning,
|
|
1113
1486
|
messages,
|
|
1114
|
-
|
|
1487
|
+
approveToolCall,
|
|
1488
|
+
declineToolCall,
|
|
1489
|
+
cancelRun: handleCancelRun,
|
|
1490
|
+
toolCallApprovals
|
|
1115
1491
|
};
|
|
1116
1492
|
};
|
|
1117
1493
|
|
|
@@ -1485,6 +1861,7 @@ exports.TooltipContentClass = TooltipContentClass;
|
|
|
1485
1861
|
exports.TooltipTrigger = TooltipTrigger;
|
|
1486
1862
|
exports.WorkflowIcon = WorkflowIcon;
|
|
1487
1863
|
exports.mapWorkflowStreamChunkToWatchResult = mapWorkflowStreamChunkToWatchResult;
|
|
1864
|
+
exports.resolveToChildMessages = resolveToChildMessages;
|
|
1488
1865
|
exports.toAssistantUIMessage = toAssistantUIMessage;
|
|
1489
1866
|
exports.toUIMessage = toUIMessage;
|
|
1490
1867
|
exports.useChat = useChat;
|