@mastra/react 0.0.0-ai-sdk-workflow-route-20251010135341

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.
@@ -0,0 +1,1100 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { createContext, useContext, useState } from 'react';
3
+ import { MastraClient } from '@mastra/client-js';
4
+ import { flushSync } from 'react-dom';
5
+
6
+ const MastraClientContext = createContext({});
7
+ const MastraClientProvider = ({ children, baseUrl, headers }) => {
8
+ const client = createMastraClient(baseUrl, headers);
9
+ return /* @__PURE__ */ jsx(MastraClientContext.Provider, { value: client, children });
10
+ };
11
+ const useMastraClient = () => useContext(MastraClientContext);
12
+ const createMastraClient = (baseUrl, mastraClientHeaders = {}) => {
13
+ return new MastraClient({
14
+ baseUrl: baseUrl || "",
15
+ // only add the header if the baseUrl is not provided i.e it's a local dev environment
16
+ headers: !baseUrl ? { ...mastraClientHeaders, "x-mastra-dev-playground": "true" } : mastraClientHeaders
17
+ });
18
+ };
19
+
20
+ const MastraReactProvider = ({ children, baseUrl, headers }) => {
21
+ return /* @__PURE__ */ jsx(MastraClientProvider, { baseUrl, headers, children });
22
+ };
23
+
24
+ const mapWorkflowStreamChunkToWatchResult = (prev, chunk) => {
25
+ if (chunk.type === "workflow-start") {
26
+ return {
27
+ input: prev?.input,
28
+ status: "running",
29
+ steps: prev?.steps || {}
30
+ };
31
+ }
32
+ if (chunk.type === "workflow-canceled") {
33
+ return {
34
+ ...prev,
35
+ status: "canceled"
36
+ };
37
+ }
38
+ if (chunk.type === "workflow-finish") {
39
+ const finalStatus = chunk.payload.workflowStatus;
40
+ const prevSteps = prev?.steps ?? {};
41
+ const lastStep = Object.values(prevSteps).pop();
42
+ return {
43
+ ...prev,
44
+ status: chunk.payload.workflowStatus,
45
+ ...finalStatus === "success" && lastStep?.status === "success" ? { result: lastStep?.output } : finalStatus === "failed" && lastStep?.status === "failed" ? { error: lastStep?.error } : {}
46
+ };
47
+ }
48
+ const { stepCallId, stepName, ...newPayload } = chunk.payload ?? {};
49
+ const newSteps = {
50
+ ...prev?.steps,
51
+ [chunk.payload.id]: {
52
+ ...prev?.steps?.[chunk.payload.id],
53
+ ...newPayload
54
+ }
55
+ };
56
+ if (chunk.type === "workflow-step-start") {
57
+ return {
58
+ ...prev,
59
+ steps: newSteps
60
+ };
61
+ }
62
+ if (chunk.type === "workflow-step-suspended") {
63
+ const suspendedStepIds = Object.entries(newSteps).flatMap(
64
+ ([stepId, stepResult]) => {
65
+ if (stepResult?.status === "suspended") {
66
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
67
+ return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
68
+ }
69
+ return [];
70
+ }
71
+ );
72
+ return {
73
+ ...prev,
74
+ status: "suspended",
75
+ steps: newSteps,
76
+ suspendPayload: chunk.payload.suspendPayload,
77
+ suspended: suspendedStepIds
78
+ };
79
+ }
80
+ if (chunk.type === "workflow-step-waiting") {
81
+ return {
82
+ ...prev,
83
+ status: "waiting",
84
+ steps: newSteps
85
+ };
86
+ }
87
+ if (chunk.type === "workflow-step-result") {
88
+ return {
89
+ ...prev,
90
+ steps: newSteps
91
+ };
92
+ }
93
+ return prev;
94
+ };
95
+ const toUIMessage = ({ chunk, conversation, metadata }) => {
96
+ const result = [...conversation];
97
+ switch (chunk.type) {
98
+ case "tripwire": {
99
+ const newMessage = {
100
+ id: `tripwire-${chunk.runId + Date.now()}`,
101
+ role: "assistant",
102
+ parts: [
103
+ {
104
+ type: "text",
105
+ text: chunk.payload.tripwireReason
106
+ }
107
+ ],
108
+ metadata: {
109
+ ...metadata,
110
+ status: "warning"
111
+ }
112
+ };
113
+ return [...result, newMessage];
114
+ }
115
+ case "start": {
116
+ const newMessage = {
117
+ id: `start-${chunk.runId + Date.now()}`,
118
+ role: "assistant",
119
+ parts: [],
120
+ metadata
121
+ };
122
+ return [...result, newMessage];
123
+ }
124
+ case "text-start":
125
+ case "text-delta": {
126
+ const lastMessage = result[result.length - 1];
127
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
128
+ const parts = [...lastMessage.parts];
129
+ let textPartIndex = parts.findIndex((part) => part.type === "text");
130
+ if (chunk.type === "text-start") {
131
+ if (textPartIndex === -1) {
132
+ parts.push({
133
+ type: "text",
134
+ text: "",
135
+ state: "streaming",
136
+ providerMetadata: chunk.payload.providerMetadata
137
+ });
138
+ }
139
+ } else {
140
+ if (textPartIndex === -1) {
141
+ parts.push({
142
+ type: "text",
143
+ text: chunk.payload.text,
144
+ state: "streaming",
145
+ providerMetadata: chunk.payload.providerMetadata
146
+ });
147
+ } else {
148
+ const textPart = parts[textPartIndex];
149
+ if (textPart.type === "text") {
150
+ parts[textPartIndex] = {
151
+ ...textPart,
152
+ text: textPart.text + chunk.payload.text,
153
+ state: "streaming"
154
+ };
155
+ }
156
+ }
157
+ }
158
+ return [
159
+ ...result.slice(0, -1),
160
+ {
161
+ ...lastMessage,
162
+ parts
163
+ }
164
+ ];
165
+ }
166
+ case "reasoning-delta": {
167
+ const lastMessage = result[result.length - 1];
168
+ if (!lastMessage || lastMessage.role !== "assistant") {
169
+ const newMessage = {
170
+ id: `reasoning-${chunk.runId + Date.now()}`,
171
+ role: "assistant",
172
+ parts: [
173
+ {
174
+ type: "reasoning",
175
+ text: chunk.payload.text,
176
+ state: "streaming",
177
+ providerMetadata: chunk.payload.providerMetadata
178
+ }
179
+ ],
180
+ metadata
181
+ };
182
+ return [...result, newMessage];
183
+ }
184
+ const parts = [...lastMessage.parts];
185
+ let reasoningPartIndex = parts.findIndex((part) => part.type === "reasoning");
186
+ if (reasoningPartIndex === -1) {
187
+ parts.push({
188
+ type: "reasoning",
189
+ text: chunk.payload.text,
190
+ state: "streaming",
191
+ providerMetadata: chunk.payload.providerMetadata
192
+ });
193
+ } else {
194
+ const reasoningPart = parts[reasoningPartIndex];
195
+ if (reasoningPart.type === "reasoning") {
196
+ parts[reasoningPartIndex] = {
197
+ ...reasoningPart,
198
+ text: reasoningPart.text + chunk.payload.text,
199
+ state: "streaming"
200
+ };
201
+ }
202
+ }
203
+ return [
204
+ ...result.slice(0, -1),
205
+ {
206
+ ...lastMessage,
207
+ parts
208
+ }
209
+ ];
210
+ }
211
+ case "tool-call": {
212
+ const lastMessage = result[result.length - 1];
213
+ if (!lastMessage || lastMessage.role !== "assistant") {
214
+ const newMessage = {
215
+ id: `tool-call-${chunk.runId + Date.now()}`,
216
+ role: "assistant",
217
+ parts: [
218
+ {
219
+ type: "dynamic-tool",
220
+ toolName: chunk.payload.toolName,
221
+ toolCallId: chunk.payload.toolCallId,
222
+ state: "input-available",
223
+ input: chunk.payload.args,
224
+ callProviderMetadata: chunk.payload.providerMetadata
225
+ }
226
+ ],
227
+ metadata
228
+ };
229
+ return [...result, newMessage];
230
+ }
231
+ const parts = [...lastMessage.parts];
232
+ parts.push({
233
+ type: "dynamic-tool",
234
+ toolName: chunk.payload.toolName,
235
+ toolCallId: chunk.payload.toolCallId,
236
+ state: "input-available",
237
+ input: chunk.payload.args,
238
+ callProviderMetadata: chunk.payload.providerMetadata
239
+ });
240
+ return [
241
+ ...result.slice(0, -1),
242
+ {
243
+ ...lastMessage,
244
+ parts
245
+ }
246
+ ];
247
+ }
248
+ case "tool-result": {
249
+ const lastMessage = result[result.length - 1];
250
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
251
+ const parts = [...lastMessage.parts];
252
+ const toolPartIndex = parts.findIndex(
253
+ (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
254
+ );
255
+ if (toolPartIndex !== -1) {
256
+ const toolPart = parts[toolPartIndex];
257
+ if (toolPart.type === "dynamic-tool") {
258
+ if (chunk.payload.isError) {
259
+ parts[toolPartIndex] = {
260
+ type: "dynamic-tool",
261
+ toolName: toolPart.toolName,
262
+ toolCallId: toolPart.toolCallId,
263
+ state: "output-error",
264
+ input: toolPart.input,
265
+ errorText: String(chunk.payload.result),
266
+ callProviderMetadata: chunk.payload.providerMetadata
267
+ };
268
+ } else {
269
+ const isWorkflow = Boolean(chunk.payload.result?.result?.steps);
270
+ parts[toolPartIndex] = {
271
+ type: "dynamic-tool",
272
+ toolName: toolPart.toolName,
273
+ toolCallId: toolPart.toolCallId,
274
+ state: "output-available",
275
+ input: toolPart.input,
276
+ output: isWorkflow ? chunk.payload.result?.result : chunk.payload.result,
277
+ callProviderMetadata: chunk.payload.providerMetadata
278
+ };
279
+ }
280
+ }
281
+ }
282
+ return [
283
+ ...result.slice(0, -1),
284
+ {
285
+ ...lastMessage,
286
+ parts
287
+ }
288
+ ];
289
+ }
290
+ case "tool-output": {
291
+ const lastMessage = result[result.length - 1];
292
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
293
+ const parts = [...lastMessage.parts];
294
+ const toolPartIndex = parts.findIndex(
295
+ (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
296
+ );
297
+ if (toolPartIndex !== -1) {
298
+ const toolPart = parts[toolPartIndex];
299
+ if (toolPart.type === "dynamic-tool") {
300
+ if (chunk.payload.output?.type?.startsWith("workflow-")) {
301
+ const existingWorkflowState = toolPart.output || {};
302
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(
303
+ existingWorkflowState,
304
+ chunk.payload.output
305
+ );
306
+ parts[toolPartIndex] = {
307
+ ...toolPart,
308
+ output: updatedWorkflowState
309
+ };
310
+ } else {
311
+ const currentOutput = toolPart.output || [];
312
+ const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
313
+ parts[toolPartIndex] = {
314
+ ...toolPart,
315
+ output: [...existingOutput, chunk.payload.output]
316
+ };
317
+ }
318
+ }
319
+ }
320
+ return [
321
+ ...result.slice(0, -1),
322
+ {
323
+ ...lastMessage,
324
+ parts
325
+ }
326
+ ];
327
+ }
328
+ case "source": {
329
+ const lastMessage = result[result.length - 1];
330
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
331
+ const parts = [...lastMessage.parts];
332
+ if (chunk.payload.sourceType === "url") {
333
+ parts.push({
334
+ type: "source-url",
335
+ sourceId: chunk.payload.id,
336
+ url: chunk.payload.url || "",
337
+ title: chunk.payload.title,
338
+ providerMetadata: chunk.payload.providerMetadata
339
+ });
340
+ } else if (chunk.payload.sourceType === "document") {
341
+ parts.push({
342
+ type: "source-document",
343
+ sourceId: chunk.payload.id,
344
+ mediaType: chunk.payload.mimeType || "application/octet-stream",
345
+ title: chunk.payload.title,
346
+ filename: chunk.payload.filename,
347
+ providerMetadata: chunk.payload.providerMetadata
348
+ });
349
+ }
350
+ return [
351
+ ...result.slice(0, -1),
352
+ {
353
+ ...lastMessage,
354
+ parts
355
+ }
356
+ ];
357
+ }
358
+ case "file": {
359
+ const lastMessage = result[result.length - 1];
360
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
361
+ const parts = [...lastMessage.parts];
362
+ let url;
363
+ if (typeof chunk.payload.data === "string") {
364
+ url = chunk.payload.base64 ? `data:${chunk.payload.mimeType};base64,${chunk.payload.data}` : `data:${chunk.payload.mimeType},${encodeURIComponent(chunk.payload.data)}`;
365
+ } else {
366
+ const base64 = btoa(String.fromCharCode(...chunk.payload.data));
367
+ url = `data:${chunk.payload.mimeType};base64,${base64}`;
368
+ }
369
+ parts.push({
370
+ type: "file",
371
+ mediaType: chunk.payload.mimeType,
372
+ url,
373
+ providerMetadata: chunk.payload.providerMetadata
374
+ });
375
+ return [
376
+ ...result.slice(0, -1),
377
+ {
378
+ ...lastMessage,
379
+ parts
380
+ }
381
+ ];
382
+ }
383
+ case "finish": {
384
+ const lastMessage = result[result.length - 1];
385
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
386
+ const parts = lastMessage.parts.map((part) => {
387
+ if (part.type === "text" && part.state === "streaming") {
388
+ return { ...part, state: "done" };
389
+ }
390
+ if (part.type === "reasoning" && part.state === "streaming") {
391
+ return { ...part, state: "done" };
392
+ }
393
+ return part;
394
+ });
395
+ return [
396
+ ...result.slice(0, -1),
397
+ {
398
+ ...lastMessage,
399
+ parts
400
+ }
401
+ ];
402
+ }
403
+ case "error": {
404
+ const newMessage = {
405
+ id: `error-${chunk.runId + Date.now()}`,
406
+ role: "assistant",
407
+ parts: [
408
+ {
409
+ type: "text",
410
+ text: chunk.payload.error
411
+ }
412
+ ],
413
+ metadata: {
414
+ ...metadata,
415
+ status: "error"
416
+ }
417
+ };
418
+ return [...result, newMessage];
419
+ }
420
+ // For all other chunk types, return conversation unchanged
421
+ default:
422
+ return result;
423
+ }
424
+ };
425
+
426
+ const toAssistantUIMessage = (message) => {
427
+ const extendedMessage = message;
428
+ const content = message.parts.map((part) => {
429
+ if (part.type === "text") {
430
+ return {
431
+ type: "text",
432
+ text: part.text,
433
+ metadata: message.metadata
434
+ };
435
+ }
436
+ if (part.type === "reasoning") {
437
+ return {
438
+ type: "reasoning",
439
+ text: part.text,
440
+ metadata: message.metadata
441
+ };
442
+ }
443
+ if (part.type === "source-url") {
444
+ return {
445
+ type: "source",
446
+ sourceType: "url",
447
+ id: part.sourceId,
448
+ url: part.url,
449
+ title: part.title,
450
+ metadata: message.metadata
451
+ };
452
+ }
453
+ if (part.type === "source-document") {
454
+ return {
455
+ type: "file",
456
+ filename: part.filename,
457
+ mimeType: part.mediaType,
458
+ data: "",
459
+ // Source documents don't have inline data
460
+ metadata: message.metadata
461
+ };
462
+ }
463
+ if (part.type === "file") {
464
+ return {
465
+ type: "file",
466
+ mimeType: part.mediaType,
467
+ data: part.url,
468
+ // Use URL as data source
469
+ metadata: message.metadata
470
+ };
471
+ }
472
+ if (part.type === "dynamic-tool") {
473
+ const baseToolCall = {
474
+ type: "tool-call",
475
+ toolCallId: part.toolCallId,
476
+ toolName: part.toolName,
477
+ argsText: JSON.stringify(part.input),
478
+ args: part.input,
479
+ metadata: message.metadata
480
+ };
481
+ if (part.state === "output-error" && "errorText" in part) {
482
+ return { ...baseToolCall, result: part.errorText, isError: true };
483
+ }
484
+ if ("output" in part) {
485
+ return { ...baseToolCall, result: part.output };
486
+ }
487
+ return baseToolCall;
488
+ }
489
+ if (part.type.startsWith("tool-") && part.state !== "input-available") {
490
+ const toolName = "toolName" in part && typeof part.toolName === "string" ? part.toolName : part.type.substring(5);
491
+ const baseToolCall = {
492
+ type: "tool-call",
493
+ toolCallId: "toolCallId" in part && typeof part.toolCallId === "string" ? part.toolCallId : "",
494
+ toolName,
495
+ argsText: "input" in part ? JSON.stringify(part.input) : "{}",
496
+ args: "input" in part ? part.input : {},
497
+ metadata: message.metadata
498
+ };
499
+ if ("output" in part) {
500
+ return { ...baseToolCall, result: part.output };
501
+ } else if ("error" in part) {
502
+ return { ...baseToolCall, result: part.error, isError: true };
503
+ }
504
+ return baseToolCall;
505
+ }
506
+ return {
507
+ type: "text",
508
+ text: "",
509
+ metadata: message.metadata
510
+ };
511
+ });
512
+ let status;
513
+ if (message.role === "assistant" && content.length > 0) {
514
+ const hasStreamingParts = message.parts.some(
515
+ (part) => part.type === "text" && "state" in part && part.state === "streaming" || part.type === "reasoning" && "state" in part && part.state === "streaming"
516
+ );
517
+ const hasToolCalls = message.parts.some((part) => part.type === "dynamic-tool" || part.type.startsWith("tool-"));
518
+ const hasInputAvailableTools = message.parts.some(
519
+ (part) => part.type === "dynamic-tool" && part.state === "input-available"
520
+ );
521
+ const hasErrorTools = message.parts.some(
522
+ (part) => part.type === "dynamic-tool" && part.state === "output-error" || part.type.startsWith("tool-") && "error" in part
523
+ );
524
+ if (hasStreamingParts) {
525
+ status = { type: "running" };
526
+ } else if (hasInputAvailableTools && hasToolCalls) {
527
+ status = { type: "requires-action", reason: "tool-calls" };
528
+ } else if (hasErrorTools) {
529
+ status = { type: "incomplete", reason: "error" };
530
+ } else {
531
+ status = { type: "complete", reason: "stop" };
532
+ }
533
+ }
534
+ const threadMessage = {
535
+ role: message.role,
536
+ content,
537
+ id: message.id,
538
+ createdAt: extendedMessage.createdAt,
539
+ status,
540
+ attachments: extendedMessage.experimental_attachments
541
+ };
542
+ return threadMessage;
543
+ };
544
+
545
+ class AISdkNetworkTransformer {
546
+ transform({ chunk, conversation, metadata }) {
547
+ const newConversation = [...conversation];
548
+ if (chunk.type.startsWith("agent-execution-")) {
549
+ return this.handleAgentConversation(chunk, newConversation, metadata);
550
+ }
551
+ if (chunk.type.startsWith("workflow-execution-")) {
552
+ return this.handleWorkflowConversation(chunk, newConversation, metadata);
553
+ }
554
+ if (chunk.type.startsWith("tool-execution-")) {
555
+ return this.handleToolConversation(chunk, newConversation, metadata);
556
+ }
557
+ if (chunk.type === "network-execution-event-step-finish") {
558
+ const newMessage = {
559
+ id: `network-execution-event-step-finish-${chunk.runId}-${Date.now()}`,
560
+ role: "assistant",
561
+ parts: [
562
+ {
563
+ type: "text",
564
+ text: chunk.payload?.result || "",
565
+ state: "done"
566
+ }
567
+ ],
568
+ metadata
569
+ };
570
+ return [...newConversation, newMessage];
571
+ }
572
+ return newConversation;
573
+ }
574
+ handleAgentConversation = (chunk, newConversation, metadata) => {
575
+ if (chunk.type === "agent-execution-start") {
576
+ const primitiveId = chunk.payload?.args?.primitiveId;
577
+ const runId = chunk.payload.runId;
578
+ if (!primitiveId || !runId) return newConversation;
579
+ const newMessage = {
580
+ id: `agent-execution-start-${runId}-${Date.now()}`,
581
+ role: "assistant",
582
+ parts: [
583
+ {
584
+ type: "dynamic-tool",
585
+ toolName: primitiveId,
586
+ toolCallId: runId,
587
+ state: "input-available",
588
+ input: chunk.payload.args
589
+ }
590
+ ],
591
+ metadata: {
592
+ ...metadata,
593
+ selectionReason: chunk.payload?.args?.selectionReason || "",
594
+ agentInput: chunk.payload?.args?.task,
595
+ mode: "network",
596
+ from: "AGENT"
597
+ }
598
+ };
599
+ return [...newConversation, newMessage];
600
+ }
601
+ if (chunk.type === "agent-execution-end") {
602
+ const lastMessage = newConversation[newConversation.length - 1];
603
+ if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
604
+ const parts = [...lastMessage.parts];
605
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
606
+ if (toolPartIndex !== -1) {
607
+ const toolPart = parts[toolPartIndex];
608
+ if (toolPart.type === "dynamic-tool") {
609
+ const currentOutput = toolPart.output;
610
+ parts[toolPartIndex] = {
611
+ type: "dynamic-tool",
612
+ toolName: toolPart.toolName,
613
+ toolCallId: toolPart.toolCallId,
614
+ state: "output-available",
615
+ input: toolPart.input,
616
+ output: {
617
+ ...currentOutput,
618
+ result: currentOutput?.result || chunk.payload?.result || ""
619
+ }
620
+ };
621
+ }
622
+ }
623
+ return [
624
+ ...newConversation.slice(0, -1),
625
+ {
626
+ ...lastMessage,
627
+ parts
628
+ }
629
+ ];
630
+ }
631
+ if (chunk.type.startsWith("agent-execution-event-")) {
632
+ const lastMessage = newConversation[newConversation.length - 1];
633
+ if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
634
+ const agentChunk = chunk.payload;
635
+ const parts = [...lastMessage.parts];
636
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
637
+ if (toolPartIndex === -1) return newConversation;
638
+ const toolPart = parts[toolPartIndex];
639
+ if (agentChunk.type === "text-delta") {
640
+ const childMessages = toolPart?.output?.childMessages || [];
641
+ const lastChildMessage = childMessages[childMessages.length - 1];
642
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.payload.text };
643
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
644
+ parts[toolPartIndex] = {
645
+ ...toolPart,
646
+ output: {
647
+ childMessages: nextMessages
648
+ }
649
+ };
650
+ } else if (agentChunk.type === "tool-call") {
651
+ const childMessages = toolPart?.output?.childMessages || [];
652
+ parts[toolPartIndex] = {
653
+ ...toolPart,
654
+ output: {
655
+ ...toolPart?.output,
656
+ childMessages: [
657
+ ...childMessages,
658
+ {
659
+ type: "tool",
660
+ toolCallId: agentChunk.payload.toolCallId,
661
+ toolName: agentChunk.payload.toolName,
662
+ args: agentChunk.payload.args
663
+ }
664
+ ]
665
+ }
666
+ };
667
+ } else if (agentChunk.type === "tool-output") {
668
+ if (agentChunk.payload?.output?.type?.startsWith("workflow-")) {
669
+ const childMessages = toolPart?.output?.childMessages || [];
670
+ const lastToolIndex = childMessages.length - 1;
671
+ const currentMessage = childMessages[lastToolIndex];
672
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
673
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(
674
+ actualExistingWorkflowState,
675
+ agentChunk.payload.output
676
+ );
677
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
678
+ parts[toolPartIndex] = {
679
+ ...toolPart,
680
+ output: {
681
+ ...toolPart?.output,
682
+ childMessages: [
683
+ ...childMessages.slice(0, -1),
684
+ {
685
+ ...currentMessage,
686
+ toolOutput: updatedWorkflowState
687
+ }
688
+ ]
689
+ }
690
+ };
691
+ }
692
+ }
693
+ } else if (agentChunk.type === "tool-result") {
694
+ const childMessages = toolPart?.output?.childMessages || [];
695
+ const lastToolIndex = childMessages.length - 1;
696
+ const isWorkflow = Boolean(agentChunk.payload?.result?.result?.steps);
697
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
698
+ parts[toolPartIndex] = {
699
+ ...toolPart,
700
+ output: {
701
+ ...toolPart?.output,
702
+ childMessages: [
703
+ ...childMessages.slice(0, -1),
704
+ {
705
+ ...childMessages[lastToolIndex],
706
+ toolOutput: isWorkflow ? agentChunk.payload.result.result : agentChunk.payload.result
707
+ }
708
+ ]
709
+ }
710
+ };
711
+ }
712
+ }
713
+ return [
714
+ ...newConversation.slice(0, -1),
715
+ {
716
+ ...lastMessage,
717
+ parts
718
+ }
719
+ ];
720
+ }
721
+ return newConversation;
722
+ };
723
+ handleWorkflowConversation = (chunk, newConversation, metadata) => {
724
+ if (chunk.type === "workflow-execution-start") {
725
+ const primitiveId = chunk.payload?.args?.primitiveId;
726
+ const runId = chunk.payload.runId;
727
+ if (!primitiveId || !runId) return newConversation;
728
+ let agentInput;
729
+ try {
730
+ agentInput = JSON.parse(chunk?.payload?.args?.prompt);
731
+ } catch (e) {
732
+ agentInput = chunk?.payload?.args?.prompt;
733
+ }
734
+ const newMessage = {
735
+ id: `workflow-start-${runId}-${Date.now()}`,
736
+ role: "assistant",
737
+ parts: [
738
+ {
739
+ type: "dynamic-tool",
740
+ toolName: primitiveId,
741
+ toolCallId: runId,
742
+ state: "input-available",
743
+ input: chunk.payload.args
744
+ }
745
+ ],
746
+ metadata: {
747
+ ...metadata,
748
+ selectionReason: chunk.payload?.args?.selectionReason || "",
749
+ from: "WORKFLOW",
750
+ mode: "network",
751
+ agentInput
752
+ }
753
+ };
754
+ return [...newConversation, newMessage];
755
+ }
756
+ if (chunk.type.startsWith("workflow-execution-event-")) {
757
+ const lastMessage = newConversation[newConversation.length - 1];
758
+ if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
759
+ const parts = [...lastMessage.parts];
760
+ const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
761
+ if (toolPartIndex === -1) return newConversation;
762
+ const toolPart = parts[toolPartIndex];
763
+ if (toolPart.type !== "dynamic-tool") return newConversation;
764
+ const existingWorkflowState = toolPart.output || {};
765
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(existingWorkflowState, chunk.payload);
766
+ parts[toolPartIndex] = {
767
+ ...toolPart,
768
+ output: updatedWorkflowState
769
+ };
770
+ return [
771
+ ...newConversation.slice(0, -1),
772
+ {
773
+ ...lastMessage,
774
+ parts
775
+ }
776
+ ];
777
+ }
778
+ return newConversation;
779
+ };
780
+ handleToolConversation = (chunk, newConversation, metadata) => {
781
+ if (chunk.type === "tool-execution-start") {
782
+ const { args: argsData } = chunk.payload;
783
+ const lastMessage = newConversation[newConversation.length - 1];
784
+ const nestedArgs = argsData.args || {};
785
+ if (!lastMessage || lastMessage.role !== "assistant") {
786
+ const newMessage = {
787
+ id: `tool-start-${chunk.runId}-${Date.now()}`,
788
+ role: "assistant",
789
+ parts: [
790
+ {
791
+ type: "dynamic-tool",
792
+ toolName: argsData.toolName || "unknown",
793
+ toolCallId: argsData.toolCallId || "unknown",
794
+ state: "input-available",
795
+ input: nestedArgs
796
+ }
797
+ ],
798
+ metadata: {
799
+ ...metadata,
800
+ selectionReason: metadata?.mode === "network" ? metadata.selectionReason || argsData.selectionReason : "",
801
+ mode: "network",
802
+ agentInput: nestedArgs
803
+ }
804
+ };
805
+ return [...newConversation, newMessage];
806
+ }
807
+ const parts = [...lastMessage.parts];
808
+ parts.push({
809
+ type: "dynamic-tool",
810
+ toolName: argsData.toolName || "unknown",
811
+ toolCallId: argsData.toolCallId || "unknown",
812
+ state: "input-available",
813
+ input: nestedArgs
814
+ });
815
+ return [
816
+ ...newConversation.slice(0, -1),
817
+ {
818
+ ...lastMessage,
819
+ parts
820
+ }
821
+ ];
822
+ }
823
+ if (chunk.type === "tool-execution-end") {
824
+ const lastMessage = newConversation[newConversation.length - 1];
825
+ if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
826
+ const parts = [...lastMessage.parts];
827
+ const toolPartIndex = parts.findIndex(
828
+ (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
829
+ );
830
+ if (toolPartIndex !== -1) {
831
+ const toolPart = parts[toolPartIndex];
832
+ if (toolPart.type === "dynamic-tool") {
833
+ const currentOutput = toolPart.output;
834
+ parts[toolPartIndex] = {
835
+ type: "dynamic-tool",
836
+ toolName: toolPart.toolName,
837
+ toolCallId: toolPart.toolCallId,
838
+ state: "output-available",
839
+ input: toolPart.input,
840
+ output: currentOutput?.result || chunk.payload?.result || ""
841
+ };
842
+ }
843
+ }
844
+ return [
845
+ ...newConversation.slice(0, -1),
846
+ {
847
+ ...lastMessage,
848
+ parts
849
+ }
850
+ ];
851
+ }
852
+ return newConversation;
853
+ };
854
+ }
855
+
856
+ const resolveInitialMessages = (messages) => {
857
+ return messages.map((message) => {
858
+ const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
859
+ if (networkPart && networkPart.type === "text") {
860
+ try {
861
+ const json = JSON.parse(networkPart.text);
862
+ if (json.isNetwork === true) {
863
+ const selectionReason = json.selectionReason || "";
864
+ const primitiveType = json.primitiveType || "";
865
+ const primitiveId = json.primitiveId || "";
866
+ const finalResult = json.finalResult;
867
+ const toolCalls = finalResult?.toolCalls || [];
868
+ const childMessages = [];
869
+ for (const toolCall of toolCalls) {
870
+ if (toolCall.type === "tool-call" && toolCall.payload) {
871
+ const toolCallId = toolCall.payload.toolCallId;
872
+ let toolResult;
873
+ for (const message2 of finalResult?.messages || []) {
874
+ for (const part of message2.content || []) {
875
+ if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
876
+ toolResult = part;
877
+ break;
878
+ }
879
+ }
880
+ }
881
+ const isWorkflow = Boolean(toolResult?.result?.result?.steps);
882
+ childMessages.push({
883
+ type: "tool",
884
+ toolCallId: toolCall.payload.toolCallId,
885
+ toolName: toolCall.payload.toolName,
886
+ args: toolCall.payload.args,
887
+ toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
888
+ });
889
+ }
890
+ }
891
+ if (finalResult && finalResult.text) {
892
+ childMessages.push({
893
+ type: "text",
894
+ content: finalResult.text
895
+ });
896
+ }
897
+ const result = {
898
+ childMessages,
899
+ result: finalResult?.text || ""
900
+ };
901
+ console.log("json", json);
902
+ const nextMessage = {
903
+ role: "assistant",
904
+ parts: [
905
+ {
906
+ type: "dynamic-tool",
907
+ toolCallId: primitiveId,
908
+ toolName: primitiveId,
909
+ state: "output-available",
910
+ input: json.input,
911
+ output: result
912
+ }
913
+ ],
914
+ id: message.id,
915
+ metadata: {
916
+ ...message.metadata,
917
+ mode: "network",
918
+ selectionReason,
919
+ agentInput: json.input,
920
+ from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
921
+ }
922
+ };
923
+ return nextMessage;
924
+ }
925
+ } catch (error) {
926
+ return message;
927
+ }
928
+ }
929
+ return message;
930
+ });
931
+ };
932
+
933
+ const useChat = ({ agentId, initializeMessages }) => {
934
+ const [messages, setMessages] = useState(
935
+ () => resolveInitialMessages(initializeMessages?.() || [])
936
+ );
937
+ const baseClient = useMastraClient();
938
+ const [isRunning, setIsRunning] = useState(false);
939
+ const generate = async ({
940
+ coreUserMessages,
941
+ runtimeContext,
942
+ threadId,
943
+ modelSettings,
944
+ signal,
945
+ onFinish
946
+ }) => {
947
+ const {
948
+ frequencyPenalty,
949
+ presencePenalty,
950
+ maxRetries,
951
+ maxTokens,
952
+ temperature,
953
+ topK,
954
+ topP,
955
+ instructions,
956
+ providerOptions,
957
+ maxSteps
958
+ } = modelSettings || {};
959
+ setIsRunning(true);
960
+ const clientWithAbort = new MastraClient({
961
+ ...baseClient.options,
962
+ abortSignal: signal
963
+ });
964
+ const agent = clientWithAbort.getAgent(agentId);
965
+ const response = await agent.generate({
966
+ messages: coreUserMessages,
967
+ runId: agentId,
968
+ maxSteps,
969
+ modelSettings: {
970
+ frequencyPenalty,
971
+ presencePenalty,
972
+ maxRetries,
973
+ maxOutputTokens: maxTokens,
974
+ temperature,
975
+ topK,
976
+ topP
977
+ },
978
+ instructions,
979
+ runtimeContext,
980
+ ...threadId ? { threadId, resourceId: agentId } : {},
981
+ providerOptions
982
+ });
983
+ setIsRunning(false);
984
+ if (response && "uiMessages" in response.response && response.response.uiMessages) {
985
+ onFinish?.(response.response.uiMessages);
986
+ const mastraUIMessages = (response.response.uiMessages || []).map((message) => ({
987
+ ...message,
988
+ metadata: {
989
+ mode: "generate"
990
+ }
991
+ }));
992
+ setMessages((prev) => [...prev, ...mastraUIMessages]);
993
+ }
994
+ };
995
+ const stream = async ({ coreUserMessages, runtimeContext, threadId, onChunk, modelSettings, signal }) => {
996
+ const {
997
+ frequencyPenalty,
998
+ presencePenalty,
999
+ maxRetries,
1000
+ maxTokens,
1001
+ temperature,
1002
+ topK,
1003
+ topP,
1004
+ instructions,
1005
+ providerOptions,
1006
+ maxSteps
1007
+ } = modelSettings || {};
1008
+ setIsRunning(true);
1009
+ const clientWithAbort = new MastraClient({
1010
+ ...baseClient.options,
1011
+ abortSignal: signal
1012
+ });
1013
+ const agent = clientWithAbort.getAgent(agentId);
1014
+ const response = await agent.stream({
1015
+ messages: coreUserMessages,
1016
+ runId: agentId,
1017
+ maxSteps,
1018
+ modelSettings: {
1019
+ frequencyPenalty,
1020
+ presencePenalty,
1021
+ maxRetries,
1022
+ maxOutputTokens: maxTokens,
1023
+ temperature,
1024
+ topK,
1025
+ topP
1026
+ },
1027
+ instructions,
1028
+ runtimeContext,
1029
+ ...threadId ? { threadId, resourceId: agentId } : {},
1030
+ providerOptions
1031
+ });
1032
+ if (!response.body) {
1033
+ setIsRunning(false);
1034
+ throw new Error("[Stream] No response body");
1035
+ }
1036
+ await response.processDataStream({
1037
+ onChunk: async (chunk) => {
1038
+ flushSync(() => {
1039
+ setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1040
+ });
1041
+ onChunk?.(chunk);
1042
+ }
1043
+ });
1044
+ setIsRunning(false);
1045
+ };
1046
+ const network = async ({
1047
+ coreUserMessages,
1048
+ runtimeContext,
1049
+ threadId,
1050
+ onNetworkChunk,
1051
+ modelSettings,
1052
+ signal
1053
+ }) => {
1054
+ const { frequencyPenalty, presencePenalty, maxRetries, maxTokens, temperature, topK, topP, maxSteps } = modelSettings || {};
1055
+ setIsRunning(true);
1056
+ const clientWithAbort = new MastraClient({
1057
+ ...baseClient.options,
1058
+ abortSignal: signal
1059
+ });
1060
+ const agent = clientWithAbort.getAgent(agentId);
1061
+ const response = await agent.network({
1062
+ messages: coreUserMessages,
1063
+ maxSteps,
1064
+ modelSettings: {
1065
+ frequencyPenalty,
1066
+ presencePenalty,
1067
+ maxRetries,
1068
+ maxOutputTokens: maxTokens,
1069
+ temperature,
1070
+ topK,
1071
+ topP
1072
+ },
1073
+ runId: agentId,
1074
+ runtimeContext,
1075
+ ...threadId ? { thread: threadId, resourceId: agentId } : {}
1076
+ });
1077
+ const transformer = new AISdkNetworkTransformer();
1078
+ await response.processDataStream({
1079
+ onChunk: async (chunk) => {
1080
+ flushSync(() => {
1081
+ setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1082
+ });
1083
+ onNetworkChunk?.(chunk);
1084
+ }
1085
+ });
1086
+ setIsRunning(false);
1087
+ };
1088
+ return {
1089
+ network,
1090
+ stream,
1091
+ generate,
1092
+ isRunning,
1093
+ messages,
1094
+ setMessages,
1095
+ cancelRun: () => setIsRunning(false)
1096
+ };
1097
+ };
1098
+
1099
+ export { MastraReactProvider, mapWorkflowStreamChunkToWatchResult, toAssistantUIMessage, toUIMessage, useChat, useMastraClient };
1100
+ //# sourceMappingURL=index.es.js.map