@mastra/react 0.0.0-model-router-unknown-provider-20251017212006 → 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 +181 -2
- package/dist/index.cjs +448 -132
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +449 -134
- 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.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 +14 -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,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,6 +722,123 @@ 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];
|
|
@@ -923,92 +1211,75 @@ class AISdkNetworkTransformer {
|
|
|
923
1211
|
};
|
|
924
1212
|
}
|
|
925
1213
|
|
|
926
|
-
const
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
if (finalResult && finalResult.text) {
|
|
962
|
-
childMessages.push({
|
|
963
|
-
type: "text",
|
|
964
|
-
content: finalResult.text
|
|
965
|
-
});
|
|
966
|
-
}
|
|
967
|
-
const result = {
|
|
968
|
-
childMessages,
|
|
969
|
-
result: finalResult?.text || ""
|
|
970
|
-
};
|
|
971
|
-
console.log("json", json);
|
|
972
|
-
const nextMessage = {
|
|
973
|
-
role: "assistant",
|
|
974
|
-
parts: [
|
|
975
|
-
{
|
|
976
|
-
type: "dynamic-tool",
|
|
977
|
-
toolCallId: primitiveId,
|
|
978
|
-
toolName: primitiveId,
|
|
979
|
-
state: "output-available",
|
|
980
|
-
input: json.input,
|
|
981
|
-
output: result
|
|
982
|
-
}
|
|
983
|
-
],
|
|
984
|
-
id: message.id,
|
|
985
|
-
metadata: {
|
|
986
|
-
...message.metadata,
|
|
987
|
-
mode: "network",
|
|
988
|
-
selectionReason,
|
|
989
|
-
agentInput: json.input,
|
|
990
|
-
from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
|
|
991
|
-
}
|
|
992
|
-
};
|
|
993
|
-
return nextMessage;
|
|
994
|
-
}
|
|
995
|
-
} catch (error) {
|
|
996
|
-
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}`);
|
|
997
1249
|
}
|
|
998
1250
|
}
|
|
999
|
-
return message;
|
|
1000
1251
|
});
|
|
1252
|
+
return {
|
|
1253
|
+
id,
|
|
1254
|
+
role: "user",
|
|
1255
|
+
parts
|
|
1256
|
+
};
|
|
1001
1257
|
};
|
|
1002
1258
|
|
|
1003
|
-
const useChat = ({ agentId, initializeMessages }) => {
|
|
1004
|
-
const
|
|
1005
|
-
(
|
|
1006
|
-
|
|
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({});
|
|
1007
1278
|
const baseClient = useMastraClient();
|
|
1008
1279
|
const [isRunning, setIsRunning] = react.useState(false);
|
|
1009
1280
|
const generate = async ({
|
|
1010
1281
|
coreUserMessages,
|
|
1011
|
-
|
|
1282
|
+
requestContext,
|
|
1012
1283
|
threadId,
|
|
1013
1284
|
modelSettings,
|
|
1014
1285
|
signal,
|
|
@@ -1034,7 +1305,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1034
1305
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1035
1306
|
const response = await agent.generate({
|
|
1036
1307
|
messages: coreUserMessages,
|
|
1037
|
-
runId:
|
|
1308
|
+
runId: uuid.v4(),
|
|
1038
1309
|
maxSteps,
|
|
1039
1310
|
modelSettings: {
|
|
1040
1311
|
frequencyPenalty,
|
|
@@ -1046,8 +1317,8 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1046
1317
|
topP
|
|
1047
1318
|
},
|
|
1048
1319
|
instructions,
|
|
1049
|
-
|
|
1050
|
-
...threadId ? { threadId, resourceId: agentId } : {},
|
|
1320
|
+
requestContext,
|
|
1321
|
+
...threadId ? { threadId, resourceId: resourceId || agentId } : {},
|
|
1051
1322
|
providerOptions
|
|
1052
1323
|
});
|
|
1053
1324
|
setIsRunning(false);
|
|
@@ -1062,7 +1333,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1062
1333
|
setMessages((prev) => [...prev, ...mastraUIMessages]);
|
|
1063
1334
|
}
|
|
1064
1335
|
};
|
|
1065
|
-
const stream = async ({ coreUserMessages,
|
|
1336
|
+
const stream = async ({ coreUserMessages, requestContext, threadId, onChunk, modelSettings, signal }) => {
|
|
1066
1337
|
const {
|
|
1067
1338
|
frequencyPenalty,
|
|
1068
1339
|
presencePenalty,
|
|
@@ -1073,7 +1344,8 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1073
1344
|
topP,
|
|
1074
1345
|
instructions,
|
|
1075
1346
|
providerOptions,
|
|
1076
|
-
maxSteps
|
|
1347
|
+
maxSteps,
|
|
1348
|
+
requireToolApproval
|
|
1077
1349
|
} = modelSettings || {};
|
|
1078
1350
|
setIsRunning(true);
|
|
1079
1351
|
const clientWithAbort = new clientJs.MastraClient({
|
|
@@ -1081,9 +1353,10 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1081
1353
|
abortSignal: signal
|
|
1082
1354
|
});
|
|
1083
1355
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1356
|
+
const runId = uuid.v4();
|
|
1084
1357
|
const response = await agent.stream({
|
|
1085
1358
|
messages: coreUserMessages,
|
|
1086
|
-
runId
|
|
1359
|
+
runId,
|
|
1087
1360
|
maxSteps,
|
|
1088
1361
|
modelSettings: {
|
|
1089
1362
|
frequencyPenalty,
|
|
@@ -1095,19 +1368,16 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1095
1368
|
topP
|
|
1096
1369
|
},
|
|
1097
1370
|
instructions,
|
|
1098
|
-
|
|
1099
|
-
...threadId ? { threadId, resourceId: agentId } : {},
|
|
1100
|
-
providerOptions
|
|
1371
|
+
requestContext,
|
|
1372
|
+
...threadId ? { threadId, resourceId: resourceId || agentId } : {},
|
|
1373
|
+
providerOptions,
|
|
1374
|
+
requireToolApproval
|
|
1101
1375
|
});
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
throw new Error("[Stream] No response body");
|
|
1105
|
-
}
|
|
1376
|
+
_onChunk.current = onChunk;
|
|
1377
|
+
_currentRunId.current = runId;
|
|
1106
1378
|
await response.processDataStream({
|
|
1107
1379
|
onChunk: async (chunk) => {
|
|
1108
|
-
|
|
1109
|
-
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1110
|
-
});
|
|
1380
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1111
1381
|
onChunk?.(chunk);
|
|
1112
1382
|
}
|
|
1113
1383
|
});
|
|
@@ -1115,7 +1385,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1115
1385
|
};
|
|
1116
1386
|
const network = async ({
|
|
1117
1387
|
coreUserMessages,
|
|
1118
|
-
|
|
1388
|
+
requestContext,
|
|
1119
1389
|
threadId,
|
|
1120
1390
|
onNetworkChunk,
|
|
1121
1391
|
modelSettings,
|
|
@@ -1128,6 +1398,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1128
1398
|
abortSignal: signal
|
|
1129
1399
|
});
|
|
1130
1400
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1401
|
+
const runId = uuid.v4();
|
|
1131
1402
|
const response = await agent.network({
|
|
1132
1403
|
messages: coreUserMessages,
|
|
1133
1404
|
maxSteps,
|
|
@@ -1140,31 +1411,72 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1140
1411
|
topK,
|
|
1141
1412
|
topP
|
|
1142
1413
|
},
|
|
1143
|
-
runId
|
|
1144
|
-
|
|
1145
|
-
...threadId ? { thread: threadId, resourceId: agentId } : {}
|
|
1414
|
+
runId,
|
|
1415
|
+
requestContext,
|
|
1416
|
+
...threadId ? { thread: threadId, resourceId: resourceId || agentId } : {}
|
|
1146
1417
|
});
|
|
1147
1418
|
const transformer = new AISdkNetworkTransformer();
|
|
1148
1419
|
await response.processDataStream({
|
|
1149
1420
|
onChunk: async (chunk) => {
|
|
1150
|
-
|
|
1151
|
-
setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
|
|
1152
|
-
});
|
|
1421
|
+
setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
|
|
1153
1422
|
onNetworkChunk?.(chunk);
|
|
1154
1423
|
}
|
|
1155
1424
|
});
|
|
1156
1425
|
setIsRunning(false);
|
|
1157
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
|
+
};
|
|
1158
1466
|
const sendMessage = async ({ mode = "stream", ...args }) => {
|
|
1159
1467
|
const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
|
|
1160
|
-
const
|
|
1161
|
-
|
|
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]);
|
|
1162
1474
|
if (mode === "generate") {
|
|
1163
|
-
await generate({ ...args, coreUserMessages
|
|
1475
|
+
await generate({ ...args, coreUserMessages });
|
|
1164
1476
|
} else if (mode === "stream") {
|
|
1165
|
-
await stream({ ...args, coreUserMessages
|
|
1477
|
+
await stream({ ...args, coreUserMessages });
|
|
1166
1478
|
} else if (mode === "network") {
|
|
1167
|
-
await network({ ...args, coreUserMessages
|
|
1479
|
+
await network({ ...args, coreUserMessages });
|
|
1168
1480
|
}
|
|
1169
1481
|
};
|
|
1170
1482
|
return {
|
|
@@ -1172,7 +1484,10 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1172
1484
|
sendMessage,
|
|
1173
1485
|
isRunning,
|
|
1174
1486
|
messages,
|
|
1175
|
-
|
|
1487
|
+
approveToolCall,
|
|
1488
|
+
declineToolCall,
|
|
1489
|
+
cancelRun: handleCancelRun,
|
|
1490
|
+
toolCallApprovals
|
|
1176
1491
|
};
|
|
1177
1492
|
};
|
|
1178
1493
|
|
|
@@ -1546,6 +1861,7 @@ exports.TooltipContentClass = TooltipContentClass;
|
|
|
1546
1861
|
exports.TooltipTrigger = TooltipTrigger;
|
|
1547
1862
|
exports.WorkflowIcon = WorkflowIcon;
|
|
1548
1863
|
exports.mapWorkflowStreamChunkToWatchResult = mapWorkflowStreamChunkToWatchResult;
|
|
1864
|
+
exports.resolveToChildMessages = resolveToChildMessages;
|
|
1549
1865
|
exports.toAssistantUIMessage = toAssistantUIMessage;
|
|
1550
1866
|
exports.toUIMessage = toUIMessage;
|
|
1551
1867
|
exports.useChat = useChat;
|