@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.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,15 +411,37 @@ 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;
|
|
391
440
|
const parts = lastMessage.parts.map((part) => {
|
|
392
|
-
if (part
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
return { ...part, state: "done" };
|
|
441
|
+
if (typeof part === "object" && part !== null && "type" in part && "state" in part && part.state === "streaming") {
|
|
442
|
+
if (part.type === "text" || part.type === "reasoning") {
|
|
443
|
+
return { ...part, state: "done" };
|
|
444
|
+
}
|
|
397
445
|
}
|
|
398
446
|
return part;
|
|
399
447
|
});
|
|
@@ -427,6 +475,105 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
|
|
|
427
475
|
return result;
|
|
428
476
|
}
|
|
429
477
|
};
|
|
478
|
+
const toUIMessageFromAgent = (chunk, conversation, metadata) => {
|
|
479
|
+
const lastMessage = conversation[conversation.length - 1];
|
|
480
|
+
if (!lastMessage || lastMessage.role !== "assistant") return conversation;
|
|
481
|
+
const parts = [...lastMessage.parts];
|
|
482
|
+
if (chunk.type === "text-delta") {
|
|
483
|
+
const agentChunk = chunk.payload;
|
|
484
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
485
|
+
if (toolPartIndex === -1) return conversation;
|
|
486
|
+
const toolPart = parts[toolPartIndex];
|
|
487
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
488
|
+
const lastChildMessage = childMessages[childMessages.length - 1];
|
|
489
|
+
const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
|
|
490
|
+
const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
|
|
491
|
+
parts[toolPartIndex] = {
|
|
492
|
+
...toolPart,
|
|
493
|
+
output: {
|
|
494
|
+
childMessages: nextMessages
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
} else if (chunk.type === "tool-call") {
|
|
498
|
+
const agentChunk = chunk.payload;
|
|
499
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
500
|
+
if (toolPartIndex === -1) return conversation;
|
|
501
|
+
const toolPart = parts[toolPartIndex];
|
|
502
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
503
|
+
parts[toolPartIndex] = {
|
|
504
|
+
...toolPart,
|
|
505
|
+
output: {
|
|
506
|
+
...toolPart?.output,
|
|
507
|
+
childMessages: [
|
|
508
|
+
...childMessages,
|
|
509
|
+
{
|
|
510
|
+
type: "tool",
|
|
511
|
+
toolCallId: agentChunk.toolCallId,
|
|
512
|
+
toolName: agentChunk.toolName,
|
|
513
|
+
args: agentChunk.args
|
|
514
|
+
}
|
|
515
|
+
]
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
} else if (chunk.type === "tool-output") {
|
|
519
|
+
const agentChunk = chunk.payload;
|
|
520
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
521
|
+
if (toolPartIndex === -1) return conversation;
|
|
522
|
+
const toolPart = parts[toolPartIndex];
|
|
523
|
+
if (agentChunk?.output?.type?.startsWith("workflow-")) {
|
|
524
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
525
|
+
const lastToolIndex = childMessages.length - 1;
|
|
526
|
+
const currentMessage = childMessages[lastToolIndex];
|
|
527
|
+
const actualExistingWorkflowState = currentMessage?.toolOutput || {};
|
|
528
|
+
const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
|
|
529
|
+
if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
|
|
530
|
+
parts[toolPartIndex] = {
|
|
531
|
+
...toolPart,
|
|
532
|
+
output: {
|
|
533
|
+
...toolPart?.output,
|
|
534
|
+
childMessages: [
|
|
535
|
+
...childMessages.slice(0, -1),
|
|
536
|
+
{
|
|
537
|
+
...currentMessage,
|
|
538
|
+
toolOutput: { ...updatedWorkflowState, runId: agentChunk.output.runId }
|
|
539
|
+
}
|
|
540
|
+
]
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
} else if (chunk.type === "tool-result") {
|
|
546
|
+
const agentChunk = chunk.payload;
|
|
547
|
+
const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
|
|
548
|
+
if (toolPartIndex === -1) return conversation;
|
|
549
|
+
const toolPart = parts[toolPartIndex];
|
|
550
|
+
const childMessages = toolPart?.output?.childMessages || [];
|
|
551
|
+
const lastToolIndex = childMessages.length - 1;
|
|
552
|
+
const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
|
|
553
|
+
if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
|
|
554
|
+
parts[toolPartIndex] = {
|
|
555
|
+
...toolPart,
|
|
556
|
+
output: {
|
|
557
|
+
...toolPart?.output,
|
|
558
|
+
childMessages: [
|
|
559
|
+
...childMessages.slice(0, -1),
|
|
560
|
+
{
|
|
561
|
+
...childMessages[lastToolIndex],
|
|
562
|
+
toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
|
|
563
|
+
}
|
|
564
|
+
]
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return [
|
|
570
|
+
...conversation.slice(0, -1),
|
|
571
|
+
{
|
|
572
|
+
...lastMessage,
|
|
573
|
+
parts
|
|
574
|
+
}
|
|
575
|
+
];
|
|
576
|
+
};
|
|
430
577
|
|
|
431
578
|
const toAssistantUIMessage = (message) => {
|
|
432
579
|
const extendedMessage = message;
|
|
@@ -466,13 +613,23 @@ const toAssistantUIMessage = (message) => {
|
|
|
466
613
|
};
|
|
467
614
|
}
|
|
468
615
|
if (part.type === "file") {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
616
|
+
const type = part.mediaType.includes("image/") ? "image" : "file";
|
|
617
|
+
if (type === "file") {
|
|
618
|
+
return {
|
|
619
|
+
type,
|
|
620
|
+
mimeType: part.mediaType,
|
|
621
|
+
data: part.url,
|
|
622
|
+
// Use URL as data source
|
|
623
|
+
metadata: message.metadata
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
if (type === "image") {
|
|
627
|
+
return {
|
|
628
|
+
type,
|
|
629
|
+
image: part.url,
|
|
630
|
+
metadata: message.metadata
|
|
631
|
+
};
|
|
632
|
+
}
|
|
476
633
|
}
|
|
477
634
|
if (part.type === "dynamic-tool") {
|
|
478
635
|
const baseToolCall = {
|
|
@@ -508,6 +665,20 @@ const toAssistantUIMessage = (message) => {
|
|
|
508
665
|
}
|
|
509
666
|
return baseToolCall;
|
|
510
667
|
}
|
|
668
|
+
const requireApprovalMetadata = extendedMessage.metadata?.requireApprovalMetadata;
|
|
669
|
+
const partToolCallId = "toolCallId" in part && typeof part.toolCallId === "string" ? part.toolCallId : void 0;
|
|
670
|
+
const suspensionData = partToolCallId ? requireApprovalMetadata?.[partToolCallId] : void 0;
|
|
671
|
+
if (suspensionData) {
|
|
672
|
+
const toolName = "toolName" in part && typeof part.toolName === "string" ? part.toolName : part.type.startsWith("tool-") ? part.type.substring(5) : "";
|
|
673
|
+
return {
|
|
674
|
+
type: "tool-call",
|
|
675
|
+
toolCallId: partToolCallId,
|
|
676
|
+
toolName,
|
|
677
|
+
argsText: "input" in part ? JSON.stringify(part.input) : "{}",
|
|
678
|
+
args: "input" in part ? part.input : {},
|
|
679
|
+
metadata: extendedMessage.metadata
|
|
680
|
+
};
|
|
681
|
+
}
|
|
511
682
|
return {
|
|
512
683
|
type: "text",
|
|
513
684
|
text: "",
|
|
@@ -547,6 +718,123 @@ const toAssistantUIMessage = (message) => {
|
|
|
547
718
|
return threadMessage;
|
|
548
719
|
};
|
|
549
720
|
|
|
721
|
+
const resolveInitialMessages = (messages) => {
|
|
722
|
+
return messages.map((message) => {
|
|
723
|
+
const networkPart = message.parts.find(
|
|
724
|
+
(part) => typeof part === "object" && part !== null && "type" in part && part.type === "text" && "text" in part && typeof part.text === "string" && part.text.includes('"isNetwork":true')
|
|
725
|
+
);
|
|
726
|
+
if (networkPart && networkPart.type === "text") {
|
|
727
|
+
try {
|
|
728
|
+
const json = JSON.parse(networkPart.text);
|
|
729
|
+
if (json.isNetwork === true) {
|
|
730
|
+
const selectionReason = json.selectionReason || "";
|
|
731
|
+
const primitiveType = json.primitiveType || "";
|
|
732
|
+
const primitiveId = json.primitiveId || "";
|
|
733
|
+
const finalResult = json.finalResult;
|
|
734
|
+
const toolCalls = finalResult?.toolCalls || [];
|
|
735
|
+
const childMessages = [];
|
|
736
|
+
for (const toolCall of toolCalls) {
|
|
737
|
+
if (toolCall.type === "tool-call" && toolCall.payload) {
|
|
738
|
+
const toolCallId = toolCall.payload.toolCallId;
|
|
739
|
+
let toolResult;
|
|
740
|
+
for (const message2 of finalResult?.messages || []) {
|
|
741
|
+
for (const part of message2.content || []) {
|
|
742
|
+
if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
|
|
743
|
+
toolResult = part;
|
|
744
|
+
break;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
const isWorkflow = Boolean(toolResult?.result?.result?.steps);
|
|
749
|
+
childMessages.push({
|
|
750
|
+
type: "tool",
|
|
751
|
+
toolCallId: toolCall.payload.toolCallId,
|
|
752
|
+
toolName: toolCall.payload.toolName,
|
|
753
|
+
args: toolCall.payload.args,
|
|
754
|
+
toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
if (finalResult && finalResult.text) {
|
|
759
|
+
childMessages.push({
|
|
760
|
+
type: "text",
|
|
761
|
+
content: finalResult.text
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
const result = {
|
|
765
|
+
childMessages,
|
|
766
|
+
result: finalResult?.text || ""
|
|
767
|
+
};
|
|
768
|
+
const nextMessage = {
|
|
769
|
+
role: "assistant",
|
|
770
|
+
parts: [
|
|
771
|
+
{
|
|
772
|
+
type: "dynamic-tool",
|
|
773
|
+
toolCallId: primitiveId,
|
|
774
|
+
toolName: primitiveId,
|
|
775
|
+
state: "output-available",
|
|
776
|
+
input: json.input,
|
|
777
|
+
output: result
|
|
778
|
+
}
|
|
779
|
+
],
|
|
780
|
+
id: message.id,
|
|
781
|
+
metadata: {
|
|
782
|
+
...message.metadata,
|
|
783
|
+
mode: "network",
|
|
784
|
+
selectionReason,
|
|
785
|
+
agentInput: json.input,
|
|
786
|
+
from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
|
|
787
|
+
}
|
|
788
|
+
};
|
|
789
|
+
return nextMessage;
|
|
790
|
+
}
|
|
791
|
+
} catch (error) {
|
|
792
|
+
return message;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
const extendedMessage = message;
|
|
796
|
+
const pendingToolApprovals = extendedMessage.metadata?.pendingToolApprovals;
|
|
797
|
+
if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
|
|
798
|
+
return {
|
|
799
|
+
...message,
|
|
800
|
+
metadata: {
|
|
801
|
+
...message.metadata,
|
|
802
|
+
mode: "stream",
|
|
803
|
+
requireApprovalMetadata: pendingToolApprovals
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
return message;
|
|
808
|
+
});
|
|
809
|
+
};
|
|
810
|
+
const resolveToChildMessages = (messages) => {
|
|
811
|
+
const assistantMessage = messages.find((message) => message.role === "assistant");
|
|
812
|
+
if (!assistantMessage) return [];
|
|
813
|
+
const parts = assistantMessage.parts;
|
|
814
|
+
let childMessages = [];
|
|
815
|
+
for (const part of parts) {
|
|
816
|
+
const toolPart = part;
|
|
817
|
+
if (part.type.startsWith("tool-")) {
|
|
818
|
+
const toolName = part.type.substring("tool-".length);
|
|
819
|
+
const isWorkflow = toolName.startsWith("workflow-");
|
|
820
|
+
childMessages.push({
|
|
821
|
+
type: "tool",
|
|
822
|
+
toolCallId: toolPart.toolCallId,
|
|
823
|
+
toolName,
|
|
824
|
+
args: toolPart.input,
|
|
825
|
+
toolOutput: isWorkflow ? { ...toolPart.output?.result, runId: toolPart.output?.runId } : toolPart.output
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
if (part.type === "text") {
|
|
829
|
+
childMessages.push({
|
|
830
|
+
type: "text",
|
|
831
|
+
content: toolPart.text
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
return childMessages;
|
|
836
|
+
};
|
|
837
|
+
|
|
550
838
|
class AISdkNetworkTransformer {
|
|
551
839
|
transform({ chunk, conversation, metadata }) {
|
|
552
840
|
const newConversation = [...conversation];
|
|
@@ -919,92 +1207,75 @@ class AISdkNetworkTransformer {
|
|
|
919
1207
|
};
|
|
920
1208
|
}
|
|
921
1209
|
|
|
922
|
-
const
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
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
|
-
if (finalResult && finalResult.text) {
|
|
958
|
-
childMessages.push({
|
|
959
|
-
type: "text",
|
|
960
|
-
content: finalResult.text
|
|
961
|
-
});
|
|
962
|
-
}
|
|
963
|
-
const result = {
|
|
964
|
-
childMessages,
|
|
965
|
-
result: finalResult?.text || ""
|
|
966
|
-
};
|
|
967
|
-
console.log("json", json);
|
|
968
|
-
const nextMessage = {
|
|
969
|
-
role: "assistant",
|
|
970
|
-
parts: [
|
|
971
|
-
{
|
|
972
|
-
type: "dynamic-tool",
|
|
973
|
-
toolCallId: primitiveId,
|
|
974
|
-
toolName: primitiveId,
|
|
975
|
-
state: "output-available",
|
|
976
|
-
input: json.input,
|
|
977
|
-
output: result
|
|
978
|
-
}
|
|
979
|
-
],
|
|
980
|
-
id: message.id,
|
|
981
|
-
metadata: {
|
|
982
|
-
...message.metadata,
|
|
983
|
-
mode: "network",
|
|
984
|
-
selectionReason,
|
|
985
|
-
agentInput: json.input,
|
|
986
|
-
from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
|
|
987
|
-
}
|
|
988
|
-
};
|
|
989
|
-
return nextMessage;
|
|
990
|
-
}
|
|
991
|
-
} catch (error) {
|
|
992
|
-
return message;
|
|
1210
|
+
const fromCoreUserMessageToUIMessage = (coreUserMessage) => {
|
|
1211
|
+
const id = `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
1212
|
+
const parts = typeof coreUserMessage.content === "string" ? [
|
|
1213
|
+
{
|
|
1214
|
+
type: "text",
|
|
1215
|
+
text: coreUserMessage.content
|
|
1216
|
+
}
|
|
1217
|
+
] : coreUserMessage.content.map((part) => {
|
|
1218
|
+
switch (part.type) {
|
|
1219
|
+
case "text": {
|
|
1220
|
+
return {
|
|
1221
|
+
type: "text",
|
|
1222
|
+
text: part.text
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
case "image": {
|
|
1226
|
+
const url = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
|
|
1227
|
+
return {
|
|
1228
|
+
type: "file",
|
|
1229
|
+
mediaType: part.mimeType ?? "image/*",
|
|
1230
|
+
url
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
case "file": {
|
|
1234
|
+
const url = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
|
|
1235
|
+
return {
|
|
1236
|
+
type: "file",
|
|
1237
|
+
mediaType: part.mimeType,
|
|
1238
|
+
url,
|
|
1239
|
+
...part.filename !== void 0 ? { filename: part.filename } : {}
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
default: {
|
|
1243
|
+
const exhaustiveCheck = part;
|
|
1244
|
+
throw new Error(`Unhandled content part type: ${exhaustiveCheck.type}`);
|
|
993
1245
|
}
|
|
994
1246
|
}
|
|
995
|
-
return message;
|
|
996
1247
|
});
|
|
1248
|
+
return {
|
|
1249
|
+
id,
|
|
1250
|
+
role: "user",
|
|
1251
|
+
parts
|
|
1252
|
+
};
|
|
997
1253
|
};
|
|
998
1254
|
|
|
999
|
-
const useChat = ({ agentId, initializeMessages }) => {
|
|
1000
|
-
const
|
|
1001
|
-
(
|
|
1002
|
-
|
|
1255
|
+
const useChat = ({ agentId, resourceId, initializeMessages }) => {
|
|
1256
|
+
const extractRunIdFromMessages = (messages2) => {
|
|
1257
|
+
for (const message of messages2) {
|
|
1258
|
+
const pendingToolApprovals = message.metadata?.pendingToolApprovals;
|
|
1259
|
+
if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
|
|
1260
|
+
const suspensionData = Object.values(pendingToolApprovals)[0];
|
|
1261
|
+
if (suspensionData?.runId) {
|
|
1262
|
+
return suspensionData.runId;
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
return void 0;
|
|
1267
|
+
};
|
|
1268
|
+
const initialMessages = initializeMessages?.() || [];
|
|
1269
|
+
const initialRunId = extractRunIdFromMessages(initialMessages);
|
|
1270
|
+
const _currentRunId = useRef(initialRunId);
|
|
1271
|
+
const _onChunk = useRef(void 0);
|
|
1272
|
+
const [messages, setMessages] = useState(() => resolveInitialMessages(initialMessages));
|
|
1273
|
+
const [toolCallApprovals, setToolCallApprovals] = useState({});
|
|
1003
1274
|
const baseClient = useMastraClient();
|
|
1004
1275
|
const [isRunning, setIsRunning] = useState(false);
|
|
1005
1276
|
const generate = async ({
|
|
1006
1277
|
coreUserMessages,
|
|
1007
|
-
|
|
1278
|
+
requestContext,
|
|
1008
1279
|
threadId,
|
|
1009
1280
|
modelSettings,
|
|
1010
1281
|
signal,
|
|
@@ -1030,7 +1301,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1030
1301
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1031
1302
|
const response = await agent.generate({
|
|
1032
1303
|
messages: coreUserMessages,
|
|
1033
|
-
runId:
|
|
1304
|
+
runId: v4(),
|
|
1034
1305
|
maxSteps,
|
|
1035
1306
|
modelSettings: {
|
|
1036
1307
|
frequencyPenalty,
|
|
@@ -1042,8 +1313,8 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1042
1313
|
topP
|
|
1043
1314
|
},
|
|
1044
1315
|
instructions,
|
|
1045
|
-
|
|
1046
|
-
...threadId ? { threadId, resourceId: agentId } : {},
|
|
1316
|
+
requestContext,
|
|
1317
|
+
...threadId ? { threadId, resourceId: resourceId || agentId } : {},
|
|
1047
1318
|
providerOptions
|
|
1048
1319
|
});
|
|
1049
1320
|
setIsRunning(false);
|
|
@@ -1058,7 +1329,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1058
1329
|
setMessages((prev) => [...prev, ...mastraUIMessages]);
|
|
1059
1330
|
}
|
|
1060
1331
|
};
|
|
1061
|
-
const stream = async ({ coreUserMessages,
|
|
1332
|
+
const stream = async ({ coreUserMessages, requestContext, threadId, onChunk, modelSettings, signal }) => {
|
|
1062
1333
|
const {
|
|
1063
1334
|
frequencyPenalty,
|
|
1064
1335
|
presencePenalty,
|
|
@@ -1069,7 +1340,8 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1069
1340
|
topP,
|
|
1070
1341
|
instructions,
|
|
1071
1342
|
providerOptions,
|
|
1072
|
-
maxSteps
|
|
1343
|
+
maxSteps,
|
|
1344
|
+
requireToolApproval
|
|
1073
1345
|
} = modelSettings || {};
|
|
1074
1346
|
setIsRunning(true);
|
|
1075
1347
|
const clientWithAbort = new MastraClient({
|
|
@@ -1077,9 +1349,10 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1077
1349
|
abortSignal: signal
|
|
1078
1350
|
});
|
|
1079
1351
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1352
|
+
const runId = v4();
|
|
1080
1353
|
const response = await agent.stream({
|
|
1081
1354
|
messages: coreUserMessages,
|
|
1082
|
-
runId
|
|
1355
|
+
runId,
|
|
1083
1356
|
maxSteps,
|
|
1084
1357
|
modelSettings: {
|
|
1085
1358
|
frequencyPenalty,
|
|
@@ -1091,19 +1364,16 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1091
1364
|
topP
|
|
1092
1365
|
},
|
|
1093
1366
|
instructions,
|
|
1094
|
-
|
|
1095
|
-
...threadId ? { threadId, resourceId: agentId } : {},
|
|
1096
|
-
providerOptions
|
|
1367
|
+
requestContext,
|
|
1368
|
+
...threadId ? { threadId, resourceId: resourceId || agentId } : {},
|
|
1369
|
+
providerOptions,
|
|
1370
|
+
requireToolApproval
|
|
1097
1371
|
});
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
throw new Error("[Stream] No response body");
|
|
1101
|
-
}
|
|
1372
|
+
_onChunk.current = onChunk;
|
|
1373
|
+
_currentRunId.current = runId;
|
|
1102
1374
|
await response.processDataStream({
|
|
1103
1375
|
onChunk: async (chunk) => {
|
|
1104
|
-
|
|
1105
|
-
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1106
|
-
});
|
|
1376
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1107
1377
|
onChunk?.(chunk);
|
|
1108
1378
|
}
|
|
1109
1379
|
});
|
|
@@ -1111,7 +1381,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1111
1381
|
};
|
|
1112
1382
|
const network = async ({
|
|
1113
1383
|
coreUserMessages,
|
|
1114
|
-
|
|
1384
|
+
requestContext,
|
|
1115
1385
|
threadId,
|
|
1116
1386
|
onNetworkChunk,
|
|
1117
1387
|
modelSettings,
|
|
@@ -1124,6 +1394,7 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1124
1394
|
abortSignal: signal
|
|
1125
1395
|
});
|
|
1126
1396
|
const agent = clientWithAbort.getAgent(agentId);
|
|
1397
|
+
const runId = v4();
|
|
1127
1398
|
const response = await agent.network({
|
|
1128
1399
|
messages: coreUserMessages,
|
|
1129
1400
|
maxSteps,
|
|
@@ -1136,31 +1407,72 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1136
1407
|
topK,
|
|
1137
1408
|
topP
|
|
1138
1409
|
},
|
|
1139
|
-
runId
|
|
1140
|
-
|
|
1141
|
-
...threadId ? { thread: threadId, resourceId: agentId } : {}
|
|
1410
|
+
runId,
|
|
1411
|
+
requestContext,
|
|
1412
|
+
...threadId ? { thread: threadId, resourceId: resourceId || agentId } : {}
|
|
1142
1413
|
});
|
|
1143
1414
|
const transformer = new AISdkNetworkTransformer();
|
|
1144
1415
|
await response.processDataStream({
|
|
1145
1416
|
onChunk: async (chunk) => {
|
|
1146
|
-
|
|
1147
|
-
setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
|
|
1148
|
-
});
|
|
1417
|
+
setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
|
|
1149
1418
|
onNetworkChunk?.(chunk);
|
|
1150
1419
|
}
|
|
1151
1420
|
});
|
|
1152
1421
|
setIsRunning(false);
|
|
1153
1422
|
};
|
|
1423
|
+
const handleCancelRun = () => {
|
|
1424
|
+
setIsRunning(false);
|
|
1425
|
+
_currentRunId.current = void 0;
|
|
1426
|
+
_onChunk.current = void 0;
|
|
1427
|
+
};
|
|
1428
|
+
const approveToolCall = async (toolCallId) => {
|
|
1429
|
+
const onChunk = _onChunk.current;
|
|
1430
|
+
const currentRunId = _currentRunId.current;
|
|
1431
|
+
if (!currentRunId)
|
|
1432
|
+
return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
|
|
1433
|
+
setIsRunning(true);
|
|
1434
|
+
setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
|
|
1435
|
+
const agent = baseClient.getAgent(agentId);
|
|
1436
|
+
const response = await agent.approveToolCall({ runId: currentRunId, toolCallId });
|
|
1437
|
+
await response.processDataStream({
|
|
1438
|
+
onChunk: async (chunk) => {
|
|
1439
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1440
|
+
onChunk?.(chunk);
|
|
1441
|
+
}
|
|
1442
|
+
});
|
|
1443
|
+
setIsRunning(false);
|
|
1444
|
+
};
|
|
1445
|
+
const declineToolCall = async (toolCallId) => {
|
|
1446
|
+
const onChunk = _onChunk.current;
|
|
1447
|
+
const currentRunId = _currentRunId.current;
|
|
1448
|
+
if (!currentRunId)
|
|
1449
|
+
return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
|
|
1450
|
+
setIsRunning(true);
|
|
1451
|
+
setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
|
|
1452
|
+
const agent = baseClient.getAgent(agentId);
|
|
1453
|
+
const response = await agent.declineToolCall({ runId: currentRunId, toolCallId });
|
|
1454
|
+
await response.processDataStream({
|
|
1455
|
+
onChunk: async (chunk) => {
|
|
1456
|
+
setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
|
|
1457
|
+
onChunk?.(chunk);
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
setIsRunning(false);
|
|
1461
|
+
};
|
|
1154
1462
|
const sendMessage = async ({ mode = "stream", ...args }) => {
|
|
1155
1463
|
const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1464
|
+
const coreUserMessages = [nextMessage];
|
|
1465
|
+
if (args.coreUserMessages) {
|
|
1466
|
+
coreUserMessages.push(...args.coreUserMessages);
|
|
1467
|
+
}
|
|
1468
|
+
const uiMessages = coreUserMessages.map(fromCoreUserMessageToUIMessage);
|
|
1469
|
+
setMessages((s) => [...s, ...uiMessages]);
|
|
1158
1470
|
if (mode === "generate") {
|
|
1159
|
-
await generate({ ...args, coreUserMessages
|
|
1471
|
+
await generate({ ...args, coreUserMessages });
|
|
1160
1472
|
} else if (mode === "stream") {
|
|
1161
|
-
await stream({ ...args, coreUserMessages
|
|
1473
|
+
await stream({ ...args, coreUserMessages });
|
|
1162
1474
|
} else if (mode === "network") {
|
|
1163
|
-
await network({ ...args, coreUserMessages
|
|
1475
|
+
await network({ ...args, coreUserMessages });
|
|
1164
1476
|
}
|
|
1165
1477
|
};
|
|
1166
1478
|
return {
|
|
@@ -1168,7 +1480,10 @@ const useChat = ({ agentId, initializeMessages }) => {
|
|
|
1168
1480
|
sendMessage,
|
|
1169
1481
|
isRunning,
|
|
1170
1482
|
messages,
|
|
1171
|
-
|
|
1483
|
+
approveToolCall,
|
|
1484
|
+
declineToolCall,
|
|
1485
|
+
cancelRun: handleCancelRun,
|
|
1486
|
+
toolCallApprovals
|
|
1172
1487
|
};
|
|
1173
1488
|
};
|
|
1174
1489
|
|
|
@@ -1487,5 +1802,5 @@ const MessageStreaming = ({ className, ...props }) => {
|
|
|
1487
1802
|
return /* @__PURE__ */ jsx("span", { className: className || MessageStreamingClass, ...props });
|
|
1488
1803
|
};
|
|
1489
1804
|
|
|
1490
|
-
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 };
|
|
1805
|
+
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 };
|
|
1491
1806
|
//# sourceMappingURL=index.js.map
|