@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.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
-
import { createContext, useContext, useState, Fragment, useLayoutEffect,
|
|
2
|
+
import { createContext, useContext, useRef, useState, Fragment, useLayoutEffect, useEffect } from 'react';
|
|
3
3
|
import { MastraClient } from '@mastra/client-js';
|
|
4
|
-
import {
|
|
4
|
+
import { v4 } from '@lukeed/uuid';
|
|
5
5
|
import { ChevronDownIcon, CheckIcon, CopyIcon } from 'lucide-react';
|
|
6
6
|
import { twMerge } from 'tailwind-merge';
|
|
7
7
|
import { toJsxRuntime } from 'hast-util-to-jsx-runtime';
|
|
@@ -250,35 +250,48 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
250
250
|
}
|
|
251
251
|
];
|
|
252
252
|
}
|
|
253
|
+
case "tool-error":
|
|
253
254
|
case "tool-result": {
|
|
254
255
|
const lastMessage = result[result.length - 1];
|
|
255
256
|
if (!lastMessage || lastMessage.role !== "assistant") return result;
|
|
256
257
|
const parts = [...lastMessage.parts];
|
|
257
258
|
const toolPartIndex = parts.findIndex(
|
|
258
|
-
(part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
|
|
259
|
+
(part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
|
|
259
260
|
);
|
|
260
261
|
if (toolPartIndex !== -1) {
|
|
261
262
|
const toolPart = parts[toolPartIndex];
|
|
262
|
-
if (toolPart.type === "dynamic-tool") {
|
|
263
|
-
|
|
263
|
+
if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
|
|
264
|
+
const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
|
|
265
|
+
const toolCallId = toolPart.toolCallId;
|
|
266
|
+
if (chunk.type === "tool-result" && chunk.payload.isError || chunk.type === "tool-error") {
|
|
267
|
+
const error = chunk.type === "tool-error" ? chunk.payload.error : chunk.payload.result;
|
|
264
268
|
parts[toolPartIndex] = {
|
|
265
269
|
type: "dynamic-tool",
|
|
266
|
-
toolName
|
|
267
|
-
toolCallId
|
|
270
|
+
toolName,
|
|
271
|
+
toolCallId,
|
|
268
272
|
state: "output-error",
|
|
269
273
|
input: toolPart.input,
|
|
270
|
-
errorText: String(
|
|
274
|
+
errorText: String(error),
|
|
271
275
|
callProviderMetadata: chunk.payload.providerMetadata
|
|
272
276
|
};
|
|
273
277
|
} else {
|
|
274
278
|
const isWorkflow = Boolean(chunk.payload.result?.result?.steps);
|
|
279
|
+
const isAgent = chunk?.from === "AGENT";
|
|
280
|
+
let output;
|
|
281
|
+
if (isWorkflow) {
|
|
282
|
+
output = chunk.payload.result?.result;
|
|
283
|
+
} else if (isAgent) {
|
|
284
|
+
output = parts[toolPartIndex].output ?? chunk.payload.result;
|
|
285
|
+
} else {
|
|
286
|
+
output = chunk.payload.result;
|
|
287
|
+
}
|
|
275
288
|
parts[toolPartIndex] = {
|
|
276
289
|
type: "dynamic-tool",
|
|
277
|
-
toolName
|
|
278
|
-
toolCallId
|
|
290
|
+
toolName,
|
|
291
|
+
toolCallId,
|
|
279
292
|
state: "output-available",
|
|
280
293
|
input: toolPart.input,
|
|
281
|
-
output
|
|
294
|
+
output,
|
|
282
295
|
callProviderMetadata: chunk.payload.providerMetadata
|
|
283
296
|
};
|
|
284
297
|
}
|
|
@@ -297,11 +310,14 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
297
310
|
if (!lastMessage || lastMessage.role !== "assistant") return result;
|
|
298
311
|
const parts = [...lastMessage.parts];
|
|
299
312
|
const toolPartIndex = parts.findIndex(
|
|
300
|
-
(part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
|
|
313
|
+
(part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
|
|
301
314
|
);
|
|
302
315
|
if (toolPartIndex !== -1) {
|
|
303
316
|
const toolPart = parts[toolPartIndex];
|
|
304
|
-
if (toolPart.type === "dynamic-tool") {
|
|
317
|
+
if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
|
|
318
|
+
const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : typeof toolPart.type === "string" && toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
|
|
319
|
+
const toolCallId = toolPart.toolCallId;
|
|
320
|
+
const input = toolPart.input;
|
|
305
321
|
if (chunk.payload.output?.type?.startsWith("workflow-")) {
|
|
306
322
|
const existingWorkflowState = toolPart.output || {};
|
|
307
323
|
const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(
|
|
@@ -309,14 +325,24 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
309
325
|
chunk.payload.output
|
|
310
326
|
);
|
|
311
327
|
parts[toolPartIndex] = {
|
|
312
|
-
|
|
328
|
+
type: "dynamic-tool",
|
|
329
|
+
toolName,
|
|
330
|
+
toolCallId,
|
|
331
|
+
state: "input-streaming",
|
|
332
|
+
input,
|
|
313
333
|
output: updatedWorkflowState
|
|
314
334
|
};
|
|
335
|
+
} else if (chunk.payload.output?.from === "AGENT" || chunk.payload.output?.from === "USER" && chunk.payload.output?.payload?.output?.type?.startsWith("workflow-")) {
|
|
336
|
+
return toUIMessageFromAgent(chunk.payload.output, conversation);
|
|
315
337
|
} else {
|
|
316
338
|
const currentOutput = toolPart.output || [];
|
|
317
339
|
const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
|
|
318
340
|
parts[toolPartIndex] = {
|
|
319
|
-
|
|
341
|
+
type: "dynamic-tool",
|
|
342
|
+
toolName,
|
|
343
|
+
toolCallId,
|
|
344
|
+
state: "input-streaming",
|
|
345
|
+
input,
|
|
320
346
|
output: [...existingOutput, chunk.payload.output]
|
|
321
347
|
};
|
|
322
348
|
}
|
|
@@ -385,6 +411,29 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
385
411
|
}
|
|
386
412
|
];
|
|
387
413
|
}
|
|
414
|
+
case "tool-call-approval": {
|
|
415
|
+
const lastMessage = result[result.length - 1];
|
|
416
|
+
if (!lastMessage || lastMessage.role !== "assistant") return result;
|
|
417
|
+
const lastRequireApprovalMetadata = lastMessage.metadata?.mode === "stream" ? lastMessage.metadata?.requireApprovalMetadata : {};
|
|
418
|
+
return [
|
|
419
|
+
...result.slice(0, -1),
|
|
420
|
+
{
|
|
421
|
+
...lastMessage,
|
|
422
|
+
metadata: {
|
|
423
|
+
...lastMessage.metadata,
|
|
424
|
+
mode: "stream",
|
|
425
|
+
requireApprovalMetadata: {
|
|
426
|
+
...lastRequireApprovalMetadata,
|
|
427
|
+
[chunk.payload.toolCallId]: {
|
|
428
|
+
toolCallId: chunk.payload.toolCallId,
|
|
429
|
+
toolName: chunk.payload.toolName,
|
|
430
|
+
args: chunk.payload.args
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
];
|
|
436
|
+
}
|
|
388
437
|
case "finish": {
|
|
389
438
|
const lastMessage = result[result.length - 1];
|
|
390
439
|
if (!lastMessage || lastMessage.role !== "assistant") return result;
|
|
@@ -427,6 +476,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
427
476
|
return result;
|
|
428
477
|
}
|
|
429
478
|
};
|
|
479
|
+
const toUIMessageFromAgent = (chunk, conversation, metadata) => {
|
|
480
|
+
const lastMessage = conversation[conversation.length - 1];
|
|
481
|
+
if (!lastMessage || lastMessage.role !== "assistant") return conversation;
|
|
482
|
+
const parts = [...lastMessage.parts];
|
|
483
|
+
if (chunk.type === "text-delta") {
|
|
484
|
+
const agentChunk = chunk.payload;
|
|
485
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
486
|
+
if (toolPartIndex === -1) return conversation;
|
|
487
|
+
const toolPart = parts[toolPartIndex];
|
|
488
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
489
|
+
const lastChildMessage = childMessages[childMessages.length - 1];
|
|
490
|
+
const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
|
|
491
|
+
const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
|
|
492
|
+
parts[toolPartIndex] = {
|
|
493
|
+
...toolPart,
|
|
494
|
+
output: {
|
|
495
|
+
childMessages: nextMessages
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
} else if (chunk.type === "tool-call") {
|
|
499
|
+
const agentChunk = chunk.payload;
|
|
500
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
501
|
+
if (toolPartIndex === -1) return conversation;
|
|
502
|
+
const toolPart = parts[toolPartIndex];
|
|
503
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
504
|
+
parts[toolPartIndex] = {
|
|
505
|
+
...toolPart,
|
|
506
|
+
output: {
|
|
507
|
+
...toolPart?.output,
|
|
508
|
+
childMessages: [
|
|
509
|
+
...childMessages,
|
|
510
|
+
{
|
|
511
|
+
type: "tool",
|
|
512
|
+
toolCallId: agentChunk.toolCallId,
|
|
513
|
+
toolName: agentChunk.toolName,
|
|
514
|
+
args: agentChunk.args
|
|
515
|
+
}
|
|
516
|
+
]
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
} else if (chunk.type === "tool-output") {
|
|
520
|
+
const agentChunk = chunk.payload;
|
|
521
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
522
|
+
if (toolPartIndex === -1) return conversation;
|
|
523
|
+
const toolPart = parts[toolPartIndex];
|
|
524
|
+
if (agentChunk?.output?.type?.startsWith("workflow-")) {
|
|
525
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
526
|
+
const lastToolIndex = childMessages.length - 1;
|
|
527
|
+
const currentMessage = childMessages[lastToolIndex];
|
|
528
|
+
const actualExistingWorkflowState = currentMessage?.toolOutput || {};
|
|
529
|
+
const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
|
|
530
|
+
if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
|
|
531
|
+
parts[toolPartIndex] = {
|
|
532
|
+
...toolPart,
|
|
533
|
+
output: {
|
|
534
|
+
...toolPart?.output,
|
|
535
|
+
childMessages: [
|
|
536
|
+
...childMessages.slice(0, -1),
|
|
537
|
+
{
|
|
538
|
+
...currentMessage,
|
|
539
|
+
toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
|
|
540
|
+
}
|
|
541
|
+
]
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
} else if (chunk.type === "tool-result") {
|
|
547
|
+
const agentChunk = chunk.payload;
|
|
548
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
549
|
+
if (toolPartIndex === -1) return conversation;
|
|
550
|
+
const toolPart = parts[toolPartIndex];
|
|
551
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
552
|
+
const lastToolIndex = childMessages.length - 1;
|
|
553
|
+
const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
|
|
554
|
+
if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
|
|
555
|
+
parts[toolPartIndex] = {
|
|
556
|
+
...toolPart,
|
|
557
|
+
output: {
|
|
558
|
+
...toolPart?.output,
|
|
559
|
+
childMessages: [
|
|
560
|
+
...childMessages.slice(0, -1),
|
|
561
|
+
{
|
|
562
|
+
...childMessages[lastToolIndex],
|
|
563
|
+
toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
|
|
564
|
+
}
|
|
565
|
+
]
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return [
|
|
571
|
+
...conversation.slice(0, -1),
|
|
572
|
+
{
|
|
573
|
+
...lastMessage,
|
|
574
|
+
parts
|
|
575
|
+
}
|
|
576
|
+
];
|
|
577
|
+
};
|
|
430
578
|
|
|
431
579
|
const toAssistantUIMessage = (message) => {
|
|
432
580
|
const extendedMessage = message;
|
|
@@ -508,6 +656,20 @@ const toAssistantUIMessage = (message) => {
|
|
|
508
656
|
}
|
|
509
657
|
return baseToolCall;
|
|
510
658
|
}
|
|
659
|
+
const requireApprovalMetadata = extendedMessage.metadata?.requireApprovalMetadata;
|
|
660
|
+
const partToolCallId = "toolCallId" in part && typeof part.toolCallId === "string" ? part.toolCallId : void 0;
|
|
661
|
+
const suspensionData = partToolCallId ? requireApprovalMetadata?.[partToolCallId] : void 0;
|
|
662
|
+
if (suspensionData) {
|
|
663
|
+
const toolName = "toolName" in part && typeof part.toolName === "string" ? part.toolName : part.type.startsWith("tool-") ? part.type.substring(5) : "";
|
|
664
|
+
return {
|
|
665
|
+
type: "tool-call",
|
|
666
|
+
toolCallId: partToolCallId,
|
|
667
|
+
toolName,
|
|
668
|
+
argsText: "input" in part ? JSON.stringify(part.input) : "{}",
|
|
669
|
+
args: "input" in part ? part.input : {},
|
|
670
|
+
metadata: extendedMessage.metadata
|
|
671
|
+
};
|
|
672
|
+
}
|
|
511
673
|
return {
|
|
512
674
|
type: "text",
|
|
513
675
|
text: "",
|
|
@@ -547,9 +709,127 @@ const toAssistantUIMessage = (message) => {
|
|
|
547
709
|
return threadMessage;
|
|
548
710
|
};
|
|
549
711
|
|
|
712
|
+
const resolveInitialMessages = (messages) => {
|
|
713
|
+
return messages.map((message) => {
|
|
714
|
+
const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
|
|
715
|
+
if (networkPart && networkPart.type === "text") {
|
|
716
|
+
try {
|
|
717
|
+
const json = JSON.parse(networkPart.text);
|
|
718
|
+
if (json.isNetwork === true) {
|
|
719
|
+
const selectionReason = json.selectionReason || "";
|
|
720
|
+
const primitiveType = json.primitiveType || "";
|
|
721
|
+
const primitiveId = json.primitiveId || "";
|
|
722
|
+
const finalResult = json.finalResult;
|
|
723
|
+
const toolCalls = finalResult?.toolCalls || [];
|
|
724
|
+
const childMessages = [];
|
|
725
|
+
for (const toolCall of toolCalls) {
|
|
726
|
+
if (toolCall.type === "tool-call" && toolCall.payload) {
|
|
727
|
+
const toolCallId = toolCall.payload.toolCallId;
|
|
728
|
+
let toolResult;
|
|
729
|
+
for (const message2 of finalResult?.messages || []) {
|
|
730
|
+
for (const part of message2.content || []) {
|
|
731
|
+
if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
|
|
732
|
+
toolResult = part;
|
|
733
|
+
break;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
const isWorkflow = Boolean(toolResult?.result?.result?.steps);
|
|
738
|
+
childMessages.push({
|
|
739
|
+
type: "tool",
|
|
740
|
+
toolCallId: toolCall.payload.toolCallId,
|
|
741
|
+
toolName: toolCall.payload.toolName,
|
|
742
|
+
args: toolCall.payload.args,
|
|
743
|
+
toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
if (finalResult && finalResult.text) {
|
|
748
|
+
childMessages.push({
|
|
749
|
+
type: "text",
|
|
750
|
+
content: finalResult.text
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
const result = {
|
|
754
|
+
childMessages,
|
|
755
|
+
result: finalResult?.text || ""
|
|
756
|
+
};
|
|
757
|
+
const nextMessage = {
|
|
758
|
+
role: "assistant",
|
|
759
|
+
parts: [
|
|
760
|
+
{
|
|
761
|
+
type: "dynamic-tool",
|
|
762
|
+
toolCallId: primitiveId,
|
|
763
|
+
toolName: primitiveId,
|
|
764
|
+
state: "output-available",
|
|
765
|
+
input: json.input,
|
|
766
|
+
output: result
|
|
767
|
+
}
|
|
768
|
+
],
|
|
769
|
+
id: message.id,
|
|
770
|
+
metadata: {
|
|
771
|
+
...message.metadata,
|
|
772
|
+
mode: "network",
|
|
773
|
+
selectionReason,
|
|
774
|
+
agentInput: json.input,
|
|
775
|
+
from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
return nextMessage;
|
|
779
|
+
}
|
|
780
|
+
} catch (error) {
|
|
781
|
+
return message;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
const extendedMessage = message;
|
|
785
|
+
const pendingToolApprovals = extendedMessage.metadata?.pendingToolApprovals;
|
|
786
|
+
if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
|
|
787
|
+
return {
|
|
788
|
+
...message,
|
|
789
|
+
metadata: {
|
|
790
|
+
...message.metadata,
|
|
791
|
+
mode: "stream",
|
|
792
|
+
requireApprovalMetadata: pendingToolApprovals
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
return message;
|
|
797
|
+
});
|
|
798
|
+
};
|
|
799
|
+
const resolveToChildMessages = (messages) => {
|
|
800
|
+
const assistantMessage = messages.find((message) => message.role === "assistant");
|
|
801
|
+
if (!assistantMessage) return [];
|
|
802
|
+
const parts = assistantMessage.parts;
|
|
803
|
+
let childMessages = [];
|
|
804
|
+
for (const part of parts) {
|
|
805
|
+
const toolPart = part;
|
|
806
|
+
if (part.type.startsWith("tool-")) {
|
|
807
|
+
const toolName = part.type.substring("tool-".length);
|
|
808
|
+
const isWorkflow = toolName.startsWith("workflow-");
|
|
809
|
+
childMessages.push({
|
|
810
|
+
type: "tool",
|
|
811
|
+
toolCallId: toolPart.toolCallId,
|
|
812
|
+
toolName,
|
|
813
|
+
args: toolPart.input,
|
|
814
|
+
toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
if (part.type === "text") {
|
|
818
|
+
childMessages.push({
|
|
819
|
+
type: "text",
|
|
820
|
+
content: toolPart.text
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
return childMessages;
|
|
825
|
+
};
|
|
826
|
+
|
|
550
827
|
class AISdkNetworkTransformer {
|
|
551
828
|
transform({ chunk, conversation, metadata }) {
|
|
552
829
|
const newConversation = [...conversation];
|
|
830
|
+
if (chunk.type === "routing-agent-text-delta") {
|
|
831
|
+
return this.handleRoutingAgentConversation(chunk, newConversation);
|
|
832
|
+
}
|
|
553
833
|
if (chunk.type.startsWith("agent-execution-")) {
|
|
554
834
|
return this.handleAgentConversation(chunk, newConversation, metadata);
|
|
555
835
|
}
|
|
@@ -560,22 +840,80 @@ class AISdkNetworkTransformer {
|
|
|
560
840
|
return this.handleToolConversation(chunk, newConversation, metadata);
|
|
561
841
|
}
|
|
562
842
|
if (chunk.type === "network-execution-event-step-finish") {
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
843
|
+
const lastMessage = newConversation[newConversation.length - 1];
|
|
844
|
+
if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
|
|
845
|
+
const agentChunk = chunk.payload;
|
|
846
|
+
const parts = [...lastMessage.parts];
|
|
847
|
+
const textPartIndex = parts.findIndex((part) => part.type === "text");
|
|
848
|
+
if (textPartIndex === -1) {
|
|
849
|
+
parts.push({
|
|
850
|
+
type: "text",
|
|
851
|
+
text: agentChunk.result,
|
|
852
|
+
state: "done"
|
|
853
|
+
});
|
|
854
|
+
return [
|
|
855
|
+
...newConversation.slice(0, -1),
|
|
567
856
|
{
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
state: "done"
|
|
857
|
+
...lastMessage,
|
|
858
|
+
parts
|
|
571
859
|
}
|
|
572
|
-
]
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
860
|
+
];
|
|
861
|
+
}
|
|
862
|
+
const textPart = parts[textPartIndex];
|
|
863
|
+
if (textPart.type === "text") {
|
|
864
|
+
parts[textPartIndex] = {
|
|
865
|
+
...textPart,
|
|
866
|
+
state: "done"
|
|
867
|
+
};
|
|
868
|
+
return [
|
|
869
|
+
...newConversation.slice(0, -1),
|
|
870
|
+
{
|
|
871
|
+
...lastMessage,
|
|
872
|
+
parts
|
|
873
|
+
}
|
|
874
|
+
];
|
|
875
|
+
}
|
|
876
|
+
return newConversation;
|
|
576
877
|
}
|
|
577
878
|
return newConversation;
|
|
578
879
|
}
|
|
880
|
+
handleRoutingAgentConversation = (chunk, newConversation) => {
|
|
881
|
+
const lastMessage = newConversation[newConversation.length - 1];
|
|
882
|
+
if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
|
|
883
|
+
const agentChunk = chunk.payload;
|
|
884
|
+
const parts = [...lastMessage.parts];
|
|
885
|
+
const textPartIndex = parts.findIndex((part) => part.type === "text");
|
|
886
|
+
if (textPartIndex === -1) {
|
|
887
|
+
parts.push({
|
|
888
|
+
type: "text",
|
|
889
|
+
text: agentChunk.text,
|
|
890
|
+
state: "streaming"
|
|
891
|
+
});
|
|
892
|
+
return [
|
|
893
|
+
...newConversation.slice(0, -1),
|
|
894
|
+
{
|
|
895
|
+
...lastMessage,
|
|
896
|
+
parts
|
|
897
|
+
}
|
|
898
|
+
];
|
|
899
|
+
}
|
|
900
|
+
const textPart = parts[textPartIndex];
|
|
901
|
+
if (textPart.type === "text") {
|
|
902
|
+
parts[textPartIndex] = {
|
|
903
|
+
...textPart,
|
|
904
|
+
text: textPart.text + agentChunk.text,
|
|
905
|
+
state: "streaming"
|
|
906
|
+
};
|
|
907
|
+
return [
|
|
908
|
+
...newConversation.slice(0, -1),
|
|
909
|
+
{
|
|
910
|
+
...lastMessage,
|
|
911
|
+
parts
|
|
912
|
+
}
|
|
913
|
+
];
|
|
914
|
+
}
|
|
915
|
+
return newConversation;
|
|
916
|
+
};
|
|
579
917
|
handleAgentConversation = (chunk, newConversation, metadata) => {
|
|
580
918
|
if (chunk.type === "agent-execution-start") {
|
|
581
919
|
const primitiveId = chunk.payload?.args?.primitiveId;
|
|
@@ -858,87 +1196,25 @@ class AISdkNetworkTransformer {
|
|
|
858
1196
|
};
|
|
859
1197
|
}
|
|
860
1198
|
|
|
861
|
-
const
|
|
862
|
-
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
const
|
|
867
|
-
if (
|
|
868
|
-
|
|
869
|
-
const primitiveType = json.primitiveType || "";
|
|
870
|
-
const primitiveId = json.primitiveId || "";
|
|
871
|
-
const finalResult = json.finalResult;
|
|
872
|
-
const toolCalls = finalResult?.toolCalls || [];
|
|
873
|
-
const childMessages = [];
|
|
874
|
-
for (const toolCall of toolCalls) {
|
|
875
|
-
if (toolCall.type === "tool-call" && toolCall.payload) {
|
|
876
|
-
const toolCallId = toolCall.payload.toolCallId;
|
|
877
|
-
let toolResult;
|
|
878
|
-
for (const message2 of finalResult?.messages || []) {
|
|
879
|
-
for (const part of message2.content || []) {
|
|
880
|
-
if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
|
|
881
|
-
toolResult = part;
|
|
882
|
-
break;
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
const isWorkflow = Boolean(toolResult?.result?.result?.steps);
|
|
887
|
-
childMessages.push({
|
|
888
|
-
type: "tool",
|
|
889
|
-
toolCallId: toolCall.payload.toolCallId,
|
|
890
|
-
toolName: toolCall.payload.toolName,
|
|
891
|
-
args: toolCall.payload.args,
|
|
892
|
-
toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
|
|
893
|
-
});
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
if (finalResult && finalResult.text) {
|
|
897
|
-
childMessages.push({
|
|
898
|
-
type: "text",
|
|
899
|
-
content: finalResult.text
|
|
900
|
-
});
|
|
901
|
-
}
|
|
902
|
-
const result = {
|
|
903
|
-
childMessages,
|
|
904
|
-
result: finalResult?.text || ""
|
|
905
|
-
};
|
|
906
|
-
console.log("json", json);
|
|
907
|
-
const nextMessage = {
|
|
908
|
-
role: "assistant",
|
|
909
|
-
parts: [
|
|
910
|
-
{
|
|
911
|
-
type: "dynamic-tool",
|
|
912
|
-
toolCallId: primitiveId,
|
|
913
|
-
toolName: primitiveId,
|
|
914
|
-
state: "output-available",
|
|
915
|
-
input: json.input,
|
|
916
|
-
output: result
|
|
917
|
-
}
|
|
918
|
-
],
|
|
919
|
-
id: message.id,
|
|
920
|
-
metadata: {
|
|
921
|
-
...message.metadata,
|
|
922
|
-
mode: "network",
|
|
923
|
-
selectionReason,
|
|
924
|
-
agentInput: json.input,
|
|
925
|
-
from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
|
|
926
|
-
}
|
|
927
|
-
};
|
|
928
|
-
return nextMessage;
|
|
1199
|
+
const useChat = ({ agentId, resourceId, initializeMessages }) => {
|
|
1200
|
+
const extractRunIdFromMessages = (messages2) => {
|
|
1201
|
+
for (const message of messages2) {
|
|
1202
|
+
const pendingToolApprovals = message.metadata?.pendingToolApprovals;
|
|
1203
|
+
if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
|
|
1204
|
+
const suspensionData = Object.values(pendingToolApprovals)[0];
|
|
1205
|
+
if (suspensionData?.runId) {
|
|
1206
|
+
return suspensionData.runId;
|
|
929
1207
|
}
|
|
930
|
-
} catch (error) {
|
|
931
|
-
return message;
|
|
932
1208
|
}
|
|
933
1209
|
}
|
|
934
|
-
return
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
const
|
|
939
|
-
const
|
|
940
|
-
|
|
941
|
-
);
|
|
1210
|
+
return void 0;
|
|
1211
|
+
};
|
|
1212
|
+
const initialMessages = initializeMessages?.() || [];
|
|
1213
|
+
const initialRunId = extractRunIdFromMessages(initialMessages);
|
|
1214
|
+
const _currentRunId = useRef(initialRunId);
|
|
1215
|
+
const _onChunk = useRef(void 0);
|
|
1216
|
+
const [messages, setMessages] = useState(() => resolveInitialMessages(initialMessages));
|
|
1217
|
+
const [toolCallApprovals, setToolCallApprovals] = useState({});
|
|
942
1218
|
const baseClient = useMastraClient();
|
|
943
1219
|
const [isRunning, setIsRunning] = useState(false);
|
|
944
1220
|
const generate = async ({
|
|
@@ -969,7 +1245,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
969
1245
|
const agent = clientWithAbort.getAgent(agentId);
|
|
970
1246
|
const response = await agent.generate({
|
|
971
1247
|
messages: coreUserMessages,
|
|
972
|
-
runId:
|
|
1248
|
+
runId: v4(),
|
|
973
1249
|
maxSteps,
|
|
974
1250
|
modelSettings: {
|
|
975
1251
|
frequencyPenalty,
|
|
@@ -982,7 +1258,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
982
1258
|
},
|
|
983
1259
|
instructions,
|
|
984
1260
|
runtimeContext,
|
|
985
|
-
...threadId ? { threadId, resourceId: agentId } : {},
|
|
1261
|
+
...threadId ? { threadId, resourceId: resourceId || agentId } : {},
|
|
986
1262
|
providerOptions
|
|
987
1263
|
});
|
|
988
1264
|
setIsRunning(false);
|
|
@@ -1008,7 +1284,8 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1008
1284
|
topP,
|
|
1009
1285
|
instructions,
|
|
1010
1286
|
providerOptions,
|
|
1011
|
-
maxSteps
|
|
1287
|
+
maxSteps,
|
|
1288
|
+
requireToolApproval
|
|
1012
1289
|
} = modelSettings || {};
|
|
1013
1290
|
setIsRunning(true);
|
|
1014
1291
|
const clientWithAbort = new MastraClient({
|
|
@@ -1016,9 +1293,10 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1016
1293
|
abortSignal: signal
|
|
1017
1294
|
});
|
|
1018
1295
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1296
|
+
const runId = v4();
|
|
1019
1297
|
const response = await agent.stream({
|
|
1020
1298
|
messages: coreUserMessages,
|
|
1021
|
-
runId
|
|
1299
|
+
runId,
|
|
1022
1300
|
maxSteps,
|
|
1023
1301
|
modelSettings: {
|
|
1024
1302
|
frequencyPenalty,
|
|
@@ -1031,18 +1309,15 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1031
1309
|
},
|
|
1032
1310
|
instructions,
|
|
1033
1311
|
runtimeContext,
|
|
1034
|
-
...threadId ? { threadId, resourceId: agentId } : {},
|
|
1035
|
-
providerOptions
|
|
1312
|
+
...threadId ? { threadId, resourceId: resourceId || agentId } : {},
|
|
1313
|
+
providerOptions,
|
|
1314
|
+
requireToolApproval
|
|
1036
1315
|
});
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
throw new Error("[Stream] No response body");
|
|
1040
|
-
}
|
|
1316
|
+
_onChunk.current = onChunk;
|
|
1317
|
+
_currentRunId.current = runId;
|
|
1041
1318
|
await response.processDataStream({
|
|
1042
1319
|
onChunk: async (chunk) => {
|
|
1043
|
-
|
|
1044
|
-
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1045
|
-
});
|
|
1320
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1046
1321
|
onChunk?.(chunk);
|
|
1047
1322
|
}
|
|
1048
1323
|
});
|
|
@@ -1063,6 +1338,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1063
1338
|
abortSignal: signal
|
|
1064
1339
|
});
|
|
1065
1340
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1341
|
+
const runId = v4();
|
|
1066
1342
|
const response = await agent.network({
|
|
1067
1343
|
messages: coreUserMessages,
|
|
1068
1344
|
maxSteps,
|
|
@@ -1075,21 +1351,58 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1075
1351
|
topK,
|
|
1076
1352
|
topP
|
|
1077
1353
|
},
|
|
1078
|
-
runId
|
|
1354
|
+
runId,
|
|
1079
1355
|
runtimeContext,
|
|
1080
|
-
...threadId ? { thread: threadId, resourceId: agentId } : {}
|
|
1356
|
+
...threadId ? { thread: threadId, resourceId: resourceId || agentId } : {}
|
|
1081
1357
|
});
|
|
1082
1358
|
const transformer = new AISdkNetworkTransformer();
|
|
1083
1359
|
await response.processDataStream({
|
|
1084
1360
|
onChunk: async (chunk) => {
|
|
1085
|
-
|
|
1086
|
-
setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
|
|
1087
|
-
});
|
|
1361
|
+
setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
|
|
1088
1362
|
onNetworkChunk?.(chunk);
|
|
1089
1363
|
}
|
|
1090
1364
|
});
|
|
1091
1365
|
setIsRunning(false);
|
|
1092
1366
|
};
|
|
1367
|
+
const handleCancelRun = () => {
|
|
1368
|
+
setIsRunning(false);
|
|
1369
|
+
_currentRunId.current = void 0;
|
|
1370
|
+
_onChunk.current = void 0;
|
|
1371
|
+
};
|
|
1372
|
+
const approveToolCall = async (toolCallId) => {
|
|
1373
|
+
const onChunk = _onChunk.current;
|
|
1374
|
+
const currentRunId = _currentRunId.current;
|
|
1375
|
+
if (!currentRunId)
|
|
1376
|
+
return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
|
|
1377
|
+
setIsRunning(true);
|
|
1378
|
+
setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
|
|
1379
|
+
const agent = baseClient.getAgent(agentId);
|
|
1380
|
+
const response = await agent.approveToolCall({ runId: currentRunId, toolCallId });
|
|
1381
|
+
await response.processDataStream({
|
|
1382
|
+
onChunk: async (chunk) => {
|
|
1383
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1384
|
+
onChunk?.(chunk);
|
|
1385
|
+
}
|
|
1386
|
+
});
|
|
1387
|
+
setIsRunning(false);
|
|
1388
|
+
};
|
|
1389
|
+
const declineToolCall = async (toolCallId) => {
|
|
1390
|
+
const onChunk = _onChunk.current;
|
|
1391
|
+
const currentRunId = _currentRunId.current;
|
|
1392
|
+
if (!currentRunId)
|
|
1393
|
+
return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
|
|
1394
|
+
setIsRunning(true);
|
|
1395
|
+
setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
|
|
1396
|
+
const agent = baseClient.getAgent(agentId);
|
|
1397
|
+
const response = await agent.declineToolCall({ runId: currentRunId, toolCallId });
|
|
1398
|
+
await response.processDataStream({
|
|
1399
|
+
onChunk: async (chunk) => {
|
|
1400
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1401
|
+
onChunk?.(chunk);
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
setIsRunning(false);
|
|
1405
|
+
};
|
|
1093
1406
|
const sendMessage = async ({ mode = "stream", ...args }) => {
|
|
1094
1407
|
const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
|
|
1095
1408
|
const messages2 = args.coreUserMessages ? [nextMessage, ...args.coreUserMessages] : [nextMessage];
|
|
@@ -1107,7 +1420,10 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1107
1420
|
sendMessage,
|
|
1108
1421
|
isRunning,
|
|
1109
1422
|
messages,
|
|
1110
|
-
|
|
1423
|
+
approveToolCall,
|
|
1424
|
+
declineToolCall,
|
|
1425
|
+
cancelRun: handleCancelRun,
|
|
1426
|
+
toolCallApprovals
|
|
1111
1427
|
};
|
|
1112
1428
|
};
|
|
1113
1429
|
|
|
@@ -1426,5 +1742,5 @@ const MessageStreaming = ({ className, ...props }) => {
|
|
|
1426
1742
|
return /* @__PURE__ */ jsx("span", { className: className || MessageStreamingClass, ...props });
|
|
1427
1743
|
};
|
|
1428
1744
|
|
|
1429
|
-
export { AgentIcon, CodeBlock, CodeBlockClass, CodeCopyButton, Entity, EntityCaret, EntityContent, EntityContentClass, EntityTrigger, EntityTriggerClass, EntityTriggerVariantClasses, Entry, EntryClass, EntryTitle, EntryTitleClass, Icon, IconButton, IconButtonClass, IconSizes, MastraReactProvider, Message, MessageActions, MessageActionsClass, MessageClass, MessageContent, MessageContentClass, MessageList, MessageListClass, MessageStreaming, MessageStreamingClass, MessageUsage, MessageUsageClass, MessageUsageEntry, MessageUsageEntryClass, MessageUsageValue, MessageUsageValueClass, MessageUsages, MessageUsagesClass, ToolApproval, ToolApprovalActions, ToolApprovalActionsClass, ToolApprovalClass, ToolApprovalContent, ToolApprovalContentClass, ToolApprovalHeader, ToolApprovalHeaderClass, ToolApprovalTitle, ToolApprovalTitleClass, ToolsIcon, Tooltip, TooltipContent, TooltipContentClass, TooltipTrigger, WorkflowIcon, mapWorkflowStreamChunkToWatchResult, toAssistantUIMessage, toUIMessage, useChat, useEntity, useMastraClient };
|
|
1745
|
+
export { AgentIcon, CodeBlock, CodeBlockClass, CodeCopyButton, Entity, EntityCaret, EntityContent, EntityContentClass, EntityTrigger, EntityTriggerClass, EntityTriggerVariantClasses, Entry, EntryClass, EntryTitle, EntryTitleClass, Icon, IconButton, IconButtonClass, IconSizes, MastraReactProvider, Message, MessageActions, MessageActionsClass, MessageClass, MessageContent, MessageContentClass, MessageList, MessageListClass, MessageStreaming, MessageStreamingClass, MessageUsage, MessageUsageClass, MessageUsageEntry, MessageUsageEntryClass, MessageUsageValue, MessageUsageValueClass, MessageUsages, MessageUsagesClass, ToolApproval, ToolApprovalActions, ToolApprovalActionsClass, ToolApprovalClass, ToolApprovalContent, ToolApprovalContentClass, ToolApprovalHeader, ToolApprovalHeaderClass, ToolApprovalTitle, ToolApprovalTitleClass, ToolsIcon, Tooltip, TooltipContent, TooltipContentClass, TooltipTrigger, WorkflowIcon, mapWorkflowStreamChunkToWatchResult, resolveToChildMessages, toAssistantUIMessage, toUIMessage, useChat, useEntity, useMastraClient };
|
|
1430
1746
|
//# sourceMappingURL=index.js.map
|