@mastra/react 0.0.0-monorepo-binary-20251013210052 → 0.0.0-partial-response-backport-20251204204441
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 +347 -2
- package/dist/index.cjs +439 -122
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +440 -124
- package/dist/index.js.map +1 -1
- package/dist/react.css +1 -1
- package/dist/src/agent/hooks.d.ts +9 -1
- 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/toUIMessage.test.d.ts +1 -0
- package/package.json +22 -9
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,6 +415,29 @@ 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;
|
|
@@ -431,6 +480,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
431
480
|
return result;
|
|
432
481
|
}
|
|
433
482
|
};
|
|
483
|
+
const toUIMessageFromAgent = (chunk, conversation, metadata) => {
|
|
484
|
+
const lastMessage = conversation[conversation.length - 1];
|
|
485
|
+
if (!lastMessage || lastMessage.role !== "assistant") return conversation;
|
|
486
|
+
const parts = [...lastMessage.parts];
|
|
487
|
+
if (chunk.type === "text-delta") {
|
|
488
|
+
const agentChunk = chunk.payload;
|
|
489
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
490
|
+
if (toolPartIndex === -1) return conversation;
|
|
491
|
+
const toolPart = parts[toolPartIndex];
|
|
492
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
493
|
+
const lastChildMessage = childMessages[childMessages.length - 1];
|
|
494
|
+
const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
|
|
495
|
+
const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
|
|
496
|
+
parts[toolPartIndex] = {
|
|
497
|
+
...toolPart,
|
|
498
|
+
output: {
|
|
499
|
+
childMessages: nextMessages
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
} else if (chunk.type === "tool-call") {
|
|
503
|
+
const agentChunk = chunk.payload;
|
|
504
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
505
|
+
if (toolPartIndex === -1) return conversation;
|
|
506
|
+
const toolPart = parts[toolPartIndex];
|
|
507
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
508
|
+
parts[toolPartIndex] = {
|
|
509
|
+
...toolPart,
|
|
510
|
+
output: {
|
|
511
|
+
...toolPart?.output,
|
|
512
|
+
childMessages: [
|
|
513
|
+
...childMessages,
|
|
514
|
+
{
|
|
515
|
+
type: "tool",
|
|
516
|
+
toolCallId: agentChunk.toolCallId,
|
|
517
|
+
toolName: agentChunk.toolName,
|
|
518
|
+
args: agentChunk.args
|
|
519
|
+
}
|
|
520
|
+
]
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
} else if (chunk.type === "tool-output") {
|
|
524
|
+
const agentChunk = chunk.payload;
|
|
525
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
526
|
+
if (toolPartIndex === -1) return conversation;
|
|
527
|
+
const toolPart = parts[toolPartIndex];
|
|
528
|
+
if (agentChunk?.output?.type?.startsWith("workflow-")) {
|
|
529
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
530
|
+
const lastToolIndex = childMessages.length - 1;
|
|
531
|
+
const currentMessage = childMessages[lastToolIndex];
|
|
532
|
+
const actualExistingWorkflowState = currentMessage?.toolOutput || {};
|
|
533
|
+
const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
|
|
534
|
+
if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
|
|
535
|
+
parts[toolPartIndex] = {
|
|
536
|
+
...toolPart,
|
|
537
|
+
output: {
|
|
538
|
+
...toolPart?.output,
|
|
539
|
+
childMessages: [
|
|
540
|
+
...childMessages.slice(0, -1),
|
|
541
|
+
{
|
|
542
|
+
...currentMessage,
|
|
543
|
+
toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
|
|
544
|
+
}
|
|
545
|
+
]
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
} else if (chunk.type === "tool-result") {
|
|
551
|
+
const agentChunk = chunk.payload;
|
|
552
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
553
|
+
if (toolPartIndex === -1) return conversation;
|
|
554
|
+
const toolPart = parts[toolPartIndex];
|
|
555
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
556
|
+
const lastToolIndex = childMessages.length - 1;
|
|
557
|
+
const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
|
|
558
|
+
if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
|
|
559
|
+
parts[toolPartIndex] = {
|
|
560
|
+
...toolPart,
|
|
561
|
+
output: {
|
|
562
|
+
...toolPart?.output,
|
|
563
|
+
childMessages: [
|
|
564
|
+
...childMessages.slice(0, -1),
|
|
565
|
+
{
|
|
566
|
+
...childMessages[lastToolIndex],
|
|
567
|
+
toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
|
|
568
|
+
}
|
|
569
|
+
]
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return [
|
|
575
|
+
...conversation.slice(0, -1),
|
|
576
|
+
{
|
|
577
|
+
...lastMessage,
|
|
578
|
+
parts
|
|
579
|
+
}
|
|
580
|
+
];
|
|
581
|
+
};
|
|
434
582
|
|
|
435
583
|
const toAssistantUIMessage = (message) => {
|
|
436
584
|
const extendedMessage = message;
|
|
@@ -512,6 +660,20 @@ const toAssistantUIMessage = (message) => {
|
|
|
512
660
|
}
|
|
513
661
|
return baseToolCall;
|
|
514
662
|
}
|
|
663
|
+
const requireApprovalMetadata = extendedMessage.metadata?.requireApprovalMetadata;
|
|
664
|
+
const partToolCallId = "toolCallId" in part && typeof part.toolCallId === "string" ? part.toolCallId : void 0;
|
|
665
|
+
const suspensionData = partToolCallId ? requireApprovalMetadata?.[partToolCallId] : void 0;
|
|
666
|
+
if (suspensionData) {
|
|
667
|
+
const toolName = "toolName" in part && typeof part.toolName === "string" ? part.toolName : part.type.startsWith("tool-") ? part.type.substring(5) : "";
|
|
668
|
+
return {
|
|
669
|
+
type: "tool-call",
|
|
670
|
+
toolCallId: partToolCallId,
|
|
671
|
+
toolName,
|
|
672
|
+
argsText: "input" in part ? JSON.stringify(part.input) : "{}",
|
|
673
|
+
args: "input" in part ? part.input : {},
|
|
674
|
+
metadata: extendedMessage.metadata
|
|
675
|
+
};
|
|
676
|
+
}
|
|
515
677
|
return {
|
|
516
678
|
type: "text",
|
|
517
679
|
text: "",
|
|
@@ -551,9 +713,127 @@ const toAssistantUIMessage = (message) => {
|
|
|
551
713
|
return threadMessage;
|
|
552
714
|
};
|
|
553
715
|
|
|
716
|
+
const resolveInitialMessages = (messages) => {
|
|
717
|
+
return messages.map((message) => {
|
|
718
|
+
const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
|
|
719
|
+
if (networkPart && networkPart.type === "text") {
|
|
720
|
+
try {
|
|
721
|
+
const json = JSON.parse(networkPart.text);
|
|
722
|
+
if (json.isNetwork === true) {
|
|
723
|
+
const selectionReason = json.selectionReason || "";
|
|
724
|
+
const primitiveType = json.primitiveType || "";
|
|
725
|
+
const primitiveId = json.primitiveId || "";
|
|
726
|
+
const finalResult = json.finalResult;
|
|
727
|
+
const toolCalls = finalResult?.toolCalls || [];
|
|
728
|
+
const childMessages = [];
|
|
729
|
+
for (const toolCall of toolCalls) {
|
|
730
|
+
if (toolCall.type === "tool-call" && toolCall.payload) {
|
|
731
|
+
const toolCallId = toolCall.payload.toolCallId;
|
|
732
|
+
let toolResult;
|
|
733
|
+
for (const message2 of finalResult?.messages || []) {
|
|
734
|
+
for (const part of message2.content || []) {
|
|
735
|
+
if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
|
|
736
|
+
toolResult = part;
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
const isWorkflow = Boolean(toolResult?.result?.result?.steps);
|
|
742
|
+
childMessages.push({
|
|
743
|
+
type: "tool",
|
|
744
|
+
toolCallId: toolCall.payload.toolCallId,
|
|
745
|
+
toolName: toolCall.payload.toolName,
|
|
746
|
+
args: toolCall.payload.args,
|
|
747
|
+
toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (finalResult && finalResult.text) {
|
|
752
|
+
childMessages.push({
|
|
753
|
+
type: "text",
|
|
754
|
+
content: finalResult.text
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
const result = {
|
|
758
|
+
childMessages,
|
|
759
|
+
result: finalResult?.text || ""
|
|
760
|
+
};
|
|
761
|
+
const nextMessage = {
|
|
762
|
+
role: "assistant",
|
|
763
|
+
parts: [
|
|
764
|
+
{
|
|
765
|
+
type: "dynamic-tool",
|
|
766
|
+
toolCallId: primitiveId,
|
|
767
|
+
toolName: primitiveId,
|
|
768
|
+
state: "output-available",
|
|
769
|
+
input: json.input,
|
|
770
|
+
output: result
|
|
771
|
+
}
|
|
772
|
+
],
|
|
773
|
+
id: message.id,
|
|
774
|
+
metadata: {
|
|
775
|
+
...message.metadata,
|
|
776
|
+
mode: "network",
|
|
777
|
+
selectionReason,
|
|
778
|
+
agentInput: json.input,
|
|
779
|
+
from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
|
|
780
|
+
}
|
|
781
|
+
};
|
|
782
|
+
return nextMessage;
|
|
783
|
+
}
|
|
784
|
+
} catch (error) {
|
|
785
|
+
return message;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
const extendedMessage = message;
|
|
789
|
+
const pendingToolApprovals = extendedMessage.metadata?.pendingToolApprovals;
|
|
790
|
+
if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
|
|
791
|
+
return {
|
|
792
|
+
...message,
|
|
793
|
+
metadata: {
|
|
794
|
+
...message.metadata,
|
|
795
|
+
mode: "stream",
|
|
796
|
+
requireApprovalMetadata: pendingToolApprovals
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
return message;
|
|
801
|
+
});
|
|
802
|
+
};
|
|
803
|
+
const resolveToChildMessages = (messages) => {
|
|
804
|
+
const assistantMessage = messages.find((message) => message.role === "assistant");
|
|
805
|
+
if (!assistantMessage) return [];
|
|
806
|
+
const parts = assistantMessage.parts;
|
|
807
|
+
let childMessages = [];
|
|
808
|
+
for (const part of parts) {
|
|
809
|
+
const toolPart = part;
|
|
810
|
+
if (part.type.startsWith("tool-")) {
|
|
811
|
+
const toolName = part.type.substring("tool-".length);
|
|
812
|
+
const isWorkflow = toolName.startsWith("workflow-");
|
|
813
|
+
childMessages.push({
|
|
814
|
+
type: "tool",
|
|
815
|
+
toolCallId: toolPart.toolCallId,
|
|
816
|
+
toolName,
|
|
817
|
+
args: toolPart.input,
|
|
818
|
+
toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
if (part.type === "text") {
|
|
822
|
+
childMessages.push({
|
|
823
|
+
type: "text",
|
|
824
|
+
content: toolPart.text
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return childMessages;
|
|
829
|
+
};
|
|
830
|
+
|
|
554
831
|
class AISdkNetworkTransformer {
|
|
555
832
|
transform({ chunk, conversation, metadata }) {
|
|
556
833
|
const newConversation = [...conversation];
|
|
834
|
+
if (chunk.type === "routing-agent-text-delta") {
|
|
835
|
+
return this.handleRoutingAgentConversation(chunk, newConversation);
|
|
836
|
+
}
|
|
557
837
|
if (chunk.type.startsWith("agent-execution-")) {
|
|
558
838
|
return this.handleAgentConversation(chunk, newConversation, metadata);
|
|
559
839
|
}
|
|
@@ -564,22 +844,80 @@ class AISdkNetworkTransformer {
|
|
|
564
844
|
return this.handleToolConversation(chunk, newConversation, metadata);
|
|
565
845
|
}
|
|
566
846
|
if (chunk.type === "network-execution-event-step-finish") {
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
847
|
+
const lastMessage = newConversation[newConversation.length - 1];
|
|
848
|
+
if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
|
|
849
|
+
const agentChunk = chunk.payload;
|
|
850
|
+
const parts = [...lastMessage.parts];
|
|
851
|
+
const textPartIndex = parts.findIndex((part) => part.type === "text");
|
|
852
|
+
if (textPartIndex === -1) {
|
|
853
|
+
parts.push({
|
|
854
|
+
type: "text",
|
|
855
|
+
text: agentChunk.result,
|
|
856
|
+
state: "done"
|
|
857
|
+
});
|
|
858
|
+
return [
|
|
859
|
+
...newConversation.slice(0, -1),
|
|
571
860
|
{
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
state: "done"
|
|
861
|
+
...lastMessage,
|
|
862
|
+
parts
|
|
575
863
|
}
|
|
576
|
-
]
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
864
|
+
];
|
|
865
|
+
}
|
|
866
|
+
const textPart = parts[textPartIndex];
|
|
867
|
+
if (textPart.type === "text") {
|
|
868
|
+
parts[textPartIndex] = {
|
|
869
|
+
...textPart,
|
|
870
|
+
state: "done"
|
|
871
|
+
};
|
|
872
|
+
return [
|
|
873
|
+
...newConversation.slice(0, -1),
|
|
874
|
+
{
|
|
875
|
+
...lastMessage,
|
|
876
|
+
parts
|
|
877
|
+
}
|
|
878
|
+
];
|
|
879
|
+
}
|
|
880
|
+
return newConversation;
|
|
580
881
|
}
|
|
581
882
|
return newConversation;
|
|
582
883
|
}
|
|
884
|
+
handleRoutingAgentConversation = (chunk, newConversation) => {
|
|
885
|
+
const lastMessage = newConversation[newConversation.length - 1];
|
|
886
|
+
if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
|
|
887
|
+
const agentChunk = chunk.payload;
|
|
888
|
+
const parts = [...lastMessage.parts];
|
|
889
|
+
const textPartIndex = parts.findIndex((part) => part.type === "text");
|
|
890
|
+
if (textPartIndex === -1) {
|
|
891
|
+
parts.push({
|
|
892
|
+
type: "text",
|
|
893
|
+
text: agentChunk.text,
|
|
894
|
+
state: "streaming"
|
|
895
|
+
});
|
|
896
|
+
return [
|
|
897
|
+
...newConversation.slice(0, -1),
|
|
898
|
+
{
|
|
899
|
+
...lastMessage,
|
|
900
|
+
parts
|
|
901
|
+
}
|
|
902
|
+
];
|
|
903
|
+
}
|
|
904
|
+
const textPart = parts[textPartIndex];
|
|
905
|
+
if (textPart.type === "text") {
|
|
906
|
+
parts[textPartIndex] = {
|
|
907
|
+
...textPart,
|
|
908
|
+
text: textPart.text + agentChunk.text,
|
|
909
|
+
state: "streaming"
|
|
910
|
+
};
|
|
911
|
+
return [
|
|
912
|
+
...newConversation.slice(0, -1),
|
|
913
|
+
{
|
|
914
|
+
...lastMessage,
|
|
915
|
+
parts
|
|
916
|
+
}
|
|
917
|
+
];
|
|
918
|
+
}
|
|
919
|
+
return newConversation;
|
|
920
|
+
};
|
|
583
921
|
handleAgentConversation = (chunk, newConversation, metadata) => {
|
|
584
922
|
if (chunk.type === "agent-execution-start") {
|
|
585
923
|
const primitiveId = chunk.payload?.args?.primitiveId;
|
|
@@ -862,87 +1200,25 @@ class AISdkNetworkTransformer {
|
|
|
862
1200
|
};
|
|
863
1201
|
}
|
|
864
1202
|
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
const
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
const
|
|
871
|
-
if (
|
|
872
|
-
|
|
873
|
-
const primitiveType = json.primitiveType || "";
|
|
874
|
-
const primitiveId = json.primitiveId || "";
|
|
875
|
-
const finalResult = json.finalResult;
|
|
876
|
-
const toolCalls = finalResult?.toolCalls || [];
|
|
877
|
-
const childMessages = [];
|
|
878
|
-
for (const toolCall of toolCalls) {
|
|
879
|
-
if (toolCall.type === "tool-call" && toolCall.payload) {
|
|
880
|
-
const toolCallId = toolCall.payload.toolCallId;
|
|
881
|
-
let toolResult;
|
|
882
|
-
for (const message2 of finalResult?.messages || []) {
|
|
883
|
-
for (const part of message2.content || []) {
|
|
884
|
-
if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
|
|
885
|
-
toolResult = part;
|
|
886
|
-
break;
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
const isWorkflow = Boolean(toolResult?.result?.result?.steps);
|
|
891
|
-
childMessages.push({
|
|
892
|
-
type: "tool",
|
|
893
|
-
toolCallId: toolCall.payload.toolCallId,
|
|
894
|
-
toolName: toolCall.payload.toolName,
|
|
895
|
-
args: toolCall.payload.args,
|
|
896
|
-
toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
|
|
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;
|
|
1203
|
+
const useChat = ({ agentId, resourceId, initializeMessages }) => {
|
|
1204
|
+
const extractRunIdFromMessages = (messages2) => {
|
|
1205
|
+
for (const message of messages2) {
|
|
1206
|
+
const pendingToolApprovals = message.metadata?.pendingToolApprovals;
|
|
1207
|
+
if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
|
|
1208
|
+
const suspensionData = Object.values(pendingToolApprovals)[0];
|
|
1209
|
+
if (suspensionData?.runId) {
|
|
1210
|
+
return suspensionData.runId;
|
|
933
1211
|
}
|
|
934
|
-
} catch (error) {
|
|
935
|
-
return message;
|
|
936
1212
|
}
|
|
937
1213
|
}
|
|
938
|
-
return
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
const
|
|
943
|
-
const
|
|
944
|
-
|
|
945
|
-
);
|
|
1214
|
+
return void 0;
|
|
1215
|
+
};
|
|
1216
|
+
const initialMessages = initializeMessages?.() || [];
|
|
1217
|
+
const initialRunId = extractRunIdFromMessages(initialMessages);
|
|
1218
|
+
const _currentRunId = react.useRef(initialRunId);
|
|
1219
|
+
const _onChunk = react.useRef(void 0);
|
|
1220
|
+
const [messages, setMessages] = react.useState(() => resolveInitialMessages(initialMessages));
|
|
1221
|
+
const [toolCallApprovals, setToolCallApprovals] = react.useState({});
|
|
946
1222
|
const baseClient = useMastraClient();
|
|
947
1223
|
const [isRunning, setIsRunning] = react.useState(false);
|
|
948
1224
|
const generate = async ({
|
|
@@ -973,7 +1249,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
973
1249
|
const agent = clientWithAbort.getAgent(agentId);
|
|
974
1250
|
const response = await agent.generate({
|
|
975
1251
|
messages: coreUserMessages,
|
|
976
|
-
runId:
|
|
1252
|
+
runId: uuid.v4(),
|
|
977
1253
|
maxSteps,
|
|
978
1254
|
modelSettings: {
|
|
979
1255
|
frequencyPenalty,
|
|
@@ -986,7 +1262,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
986
1262
|
},
|
|
987
1263
|
instructions,
|
|
988
1264
|
runtimeContext,
|
|
989
|
-
...threadId ? { threadId, resourceId: agentId } : {},
|
|
1265
|
+
...threadId ? { threadId, resourceId: resourceId || agentId } : {},
|
|
990
1266
|
providerOptions
|
|
991
1267
|
});
|
|
992
1268
|
setIsRunning(false);
|
|
@@ -1012,7 +1288,8 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1012
1288
|
topP,
|
|
1013
1289
|
instructions,
|
|
1014
1290
|
providerOptions,
|
|
1015
|
-
maxSteps
|
|
1291
|
+
maxSteps,
|
|
1292
|
+
requireToolApproval
|
|
1016
1293
|
} = modelSettings || {};
|
|
1017
1294
|
setIsRunning(true);
|
|
1018
1295
|
const clientWithAbort = new clientJs.MastraClient({
|
|
@@ -1020,9 +1297,10 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1020
1297
|
abortSignal: signal
|
|
1021
1298
|
});
|
|
1022
1299
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1300
|
+
const runId = uuid.v4();
|
|
1023
1301
|
const response = await agent.stream({
|
|
1024
1302
|
messages: coreUserMessages,
|
|
1025
|
-
runId
|
|
1303
|
+
runId,
|
|
1026
1304
|
maxSteps,
|
|
1027
1305
|
modelSettings: {
|
|
1028
1306
|
frequencyPenalty,
|
|
@@ -1035,18 +1313,15 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1035
1313
|
},
|
|
1036
1314
|
instructions,
|
|
1037
1315
|
runtimeContext,
|
|
1038
|
-
...threadId ? { threadId, resourceId: agentId } : {},
|
|
1039
|
-
providerOptions
|
|
1316
|
+
...threadId ? { threadId, resourceId: resourceId || agentId } : {},
|
|
1317
|
+
providerOptions,
|
|
1318
|
+
requireToolApproval
|
|
1040
1319
|
});
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
throw new Error("[Stream] No response body");
|
|
1044
|
-
}
|
|
1320
|
+
_onChunk.current = onChunk;
|
|
1321
|
+
_currentRunId.current = runId;
|
|
1045
1322
|
await response.processDataStream({
|
|
1046
1323
|
onChunk: async (chunk) => {
|
|
1047
|
-
|
|
1048
|
-
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1049
|
-
});
|
|
1324
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1050
1325
|
onChunk?.(chunk);
|
|
1051
1326
|
}
|
|
1052
1327
|
});
|
|
@@ -1067,6 +1342,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1067
1342
|
abortSignal: signal
|
|
1068
1343
|
});
|
|
1069
1344
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1345
|
+
const runId = uuid.v4();
|
|
1070
1346
|
const response = await agent.network({
|
|
1071
1347
|
messages: coreUserMessages,
|
|
1072
1348
|
maxSteps,
|
|
@@ -1079,21 +1355,58 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1079
1355
|
topK,
|
|
1080
1356
|
topP
|
|
1081
1357
|
},
|
|
1082
|
-
runId
|
|
1358
|
+
runId,
|
|
1083
1359
|
runtimeContext,
|
|
1084
|
-
...threadId ? { thread: threadId, resourceId: agentId } : {}
|
|
1360
|
+
...threadId ? { thread: threadId, resourceId: resourceId || agentId } : {}
|
|
1085
1361
|
});
|
|
1086
1362
|
const transformer = new AISdkNetworkTransformer();
|
|
1087
1363
|
await response.processDataStream({
|
|
1088
1364
|
onChunk: async (chunk) => {
|
|
1089
|
-
|
|
1090
|
-
setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
|
|
1091
|
-
});
|
|
1365
|
+
setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
|
|
1092
1366
|
onNetworkChunk?.(chunk);
|
|
1093
1367
|
}
|
|
1094
1368
|
});
|
|
1095
1369
|
setIsRunning(false);
|
|
1096
1370
|
};
|
|
1371
|
+
const handleCancelRun = () => {
|
|
1372
|
+
setIsRunning(false);
|
|
1373
|
+
_currentRunId.current = void 0;
|
|
1374
|
+
_onChunk.current = void 0;
|
|
1375
|
+
};
|
|
1376
|
+
const approveToolCall = async (toolCallId) => {
|
|
1377
|
+
const onChunk = _onChunk.current;
|
|
1378
|
+
const currentRunId = _currentRunId.current;
|
|
1379
|
+
if (!currentRunId)
|
|
1380
|
+
return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
|
|
1381
|
+
setIsRunning(true);
|
|
1382
|
+
setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
|
|
1383
|
+
const agent = baseClient.getAgent(agentId);
|
|
1384
|
+
const response = await agent.approveToolCall({ runId: currentRunId, toolCallId });
|
|
1385
|
+
await response.processDataStream({
|
|
1386
|
+
onChunk: async (chunk) => {
|
|
1387
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1388
|
+
onChunk?.(chunk);
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
setIsRunning(false);
|
|
1392
|
+
};
|
|
1393
|
+
const declineToolCall = async (toolCallId) => {
|
|
1394
|
+
const onChunk = _onChunk.current;
|
|
1395
|
+
const currentRunId = _currentRunId.current;
|
|
1396
|
+
if (!currentRunId)
|
|
1397
|
+
return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
|
|
1398
|
+
setIsRunning(true);
|
|
1399
|
+
setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
|
|
1400
|
+
const agent = baseClient.getAgent(agentId);
|
|
1401
|
+
const response = await agent.declineToolCall({ runId: currentRunId, toolCallId });
|
|
1402
|
+
await response.processDataStream({
|
|
1403
|
+
onChunk: async (chunk) => {
|
|
1404
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1405
|
+
onChunk?.(chunk);
|
|
1406
|
+
}
|
|
1407
|
+
});
|
|
1408
|
+
setIsRunning(false);
|
|
1409
|
+
};
|
|
1097
1410
|
const sendMessage = async ({ mode = "stream", ...args }) => {
|
|
1098
1411
|
const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
|
|
1099
1412
|
const messages2 = args.coreUserMessages ? [nextMessage, ...args.coreUserMessages] : [nextMessage];
|
|
@@ -1111,7 +1424,10 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1111
1424
|
sendMessage,
|
|
1112
1425
|
isRunning,
|
|
1113
1426
|
messages,
|
|
1114
|
-
|
|
1427
|
+
approveToolCall,
|
|
1428
|
+
declineToolCall,
|
|
1429
|
+
cancelRun: handleCancelRun,
|
|
1430
|
+
toolCallApprovals
|
|
1115
1431
|
};
|
|
1116
1432
|
};
|
|
1117
1433
|
|
|
@@ -1485,6 +1801,7 @@ exports.TooltipContentClass = TooltipContentClass;
|
|
|
1485
1801
|
exports.TooltipTrigger = TooltipTrigger;
|
|
1486
1802
|
exports.WorkflowIcon = WorkflowIcon;
|
|
1487
1803
|
exports.mapWorkflowStreamChunkToWatchResult = mapWorkflowStreamChunkToWatchResult;
|
|
1804
|
+
exports.resolveToChildMessages = resolveToChildMessages;
|
|
1488
1805
|
exports.toAssistantUIMessage = toAssistantUIMessage;
|
|
1489
1806
|
exports.toUIMessage = toUIMessage;
|
|
1490
1807
|
exports.useChat = useChat;
|