@mastra/react 0.0.0-error-handler-fix-20251020202607 → 0.0.0-esbuild-bundle-worker-20260807182016

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.
Files changed (142) hide show
  1. package/CHANGELOG.md +4402 -3
  2. package/LICENSE.md +15 -0
  3. package/dist/agent/extract-tasks.d.ts +10 -0
  4. package/dist/agent/extract-tasks.d.ts.map +1 -0
  5. package/dist/agent/extractRunIdFromMessages.d.ts +10 -0
  6. package/dist/agent/extractRunIdFromMessages.d.ts.map +1 -0
  7. package/dist/agent/hooks.d.ts +98 -0
  8. package/dist/agent/hooks.d.ts.map +1 -0
  9. package/dist/agent/signal-data.d.ts +5 -0
  10. package/dist/agent/signal-data.d.ts.map +1 -0
  11. package/dist/{src/agent → agent}/types.d.ts +7 -1
  12. package/dist/agent/types.d.ts.map +1 -0
  13. package/dist/index.cjs +3314 -1506
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.ts +12 -2
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +3243 -1444
  18. package/dist/index.js.map +1 -1
  19. package/dist/lib/mastra-db/accumulator.d.ts +48 -0
  20. package/dist/lib/mastra-db/accumulator.d.ts.map +1 -0
  21. package/dist/lib/mastra-db/formatCompletionFeedback.d.ts +19 -0
  22. package/dist/lib/mastra-db/formatCompletionFeedback.d.ts.map +1 -0
  23. package/dist/lib/mastra-db/fromCoreUserMessage.d.ts +14 -0
  24. package/dist/lib/mastra-db/fromCoreUserMessage.d.ts.map +1 -0
  25. package/dist/lib/mastra-db/index.d.ts +6 -0
  26. package/dist/lib/mastra-db/index.d.ts.map +1 -0
  27. package/dist/lib/mastra-db/types.d.ts +171 -0
  28. package/dist/lib/mastra-db/types.d.ts.map +1 -0
  29. package/dist/lib/use-mutation.d.ts +28 -0
  30. package/dist/lib/use-mutation.d.ts.map +1 -0
  31. package/dist/mastra-client-context.d.ts +26 -0
  32. package/dist/mastra-client-context.d.ts.map +1 -0
  33. package/dist/mastra-react-provider.d.ts +5 -0
  34. package/dist/mastra-react-provider.d.ts.map +1 -0
  35. package/dist/react.css +74 -267
  36. package/dist/{src/ui → ui}/Code/Code.d.ts +5 -3
  37. package/dist/ui/Code/Code.d.ts.map +1 -0
  38. package/dist/ui/Code/highlight.d.ts +4 -0
  39. package/dist/ui/Code/highlight.d.ts.map +1 -0
  40. package/dist/ui/Code/index.d.ts +2 -0
  41. package/dist/ui/Code/index.d.ts.map +1 -0
  42. package/dist/{src/ui → ui}/Entity/Entity.d.ts +6 -5
  43. package/dist/ui/Entity/Entity.d.ts.map +1 -0
  44. package/dist/{src/ui → ui}/Entity/Entry.d.ts +4 -3
  45. package/dist/ui/Entity/Entry.d.ts.map +1 -0
  46. package/dist/{src/ui → ui}/Entity/ToolApproval.d.ts +6 -5
  47. package/dist/ui/Entity/ToolApproval.d.ts.map +1 -0
  48. package/dist/{src/ui → ui}/Entity/context.d.ts +4 -3
  49. package/dist/ui/Entity/context.d.ts.map +1 -0
  50. package/dist/ui/Entity/index.d.ts +5 -0
  51. package/dist/ui/Entity/index.d.ts.map +1 -0
  52. package/dist/{src/ui → ui}/Entity/types.d.ts +1 -0
  53. package/dist/ui/Entity/types.d.ts.map +1 -0
  54. package/dist/{src/ui → ui}/Icon/Icon.d.ts +3 -2
  55. package/dist/ui/Icon/Icon.d.ts.map +1 -0
  56. package/dist/ui/Icon/index.d.ts +2 -0
  57. package/dist/ui/Icon/index.d.ts.map +1 -0
  58. package/dist/{src/ui → ui}/IconButton/IconButton.d.ts +3 -2
  59. package/dist/ui/IconButton/IconButton.d.ts.map +1 -0
  60. package/dist/ui/IconButton/index.d.ts +2 -0
  61. package/dist/ui/IconButton/index.d.ts.map +1 -0
  62. package/dist/ui/Icons/AgentIcon.d.ts +3 -0
  63. package/dist/ui/Icons/AgentIcon.d.ts.map +1 -0
  64. package/dist/ui/Icons/ToolsIcon.d.ts +3 -0
  65. package/dist/ui/Icons/ToolsIcon.d.ts.map +1 -0
  66. package/dist/ui/Icons/WorkflowIcon.d.ts +3 -0
  67. package/dist/ui/Icons/WorkflowIcon.d.ts.map +1 -0
  68. package/dist/ui/Icons/index.d.ts +4 -0
  69. package/dist/ui/Icons/index.d.ts.map +1 -0
  70. package/dist/{src/ui → ui}/Message/Message.d.ts +11 -10
  71. package/dist/ui/Message/Message.d.ts.map +1 -0
  72. package/dist/ui/Message/index.d.ts +2 -0
  73. package/dist/ui/Message/index.d.ts.map +1 -0
  74. package/dist/ui/MessageFactory/MessageFactory.d.ts +22 -0
  75. package/dist/ui/MessageFactory/MessageFactory.d.ts.map +1 -0
  76. package/dist/ui/MessageFactory/index.d.ts +3 -0
  77. package/dist/ui/MessageFactory/index.d.ts.map +1 -0
  78. package/dist/ui/MessageFactory/types.d.ts +181 -0
  79. package/dist/ui/MessageFactory/types.d.ts.map +1 -0
  80. package/dist/{src/ui → ui}/Tooltip/Tooltip.d.ts +5 -4
  81. package/dist/ui/Tooltip/Tooltip.d.ts.map +1 -0
  82. package/dist/ui/Tooltip/index.d.ts +2 -0
  83. package/dist/ui/Tooltip/index.d.ts.map +1 -0
  84. package/dist/ui/index.cjs +57 -0
  85. package/dist/ui/index.d.ts +9 -0
  86. package/dist/ui/index.d.ts.map +1 -0
  87. package/dist/ui/index.js +2 -0
  88. package/dist/ui-Bd2cu1B9.js +497 -0
  89. package/dist/ui-Bd2cu1B9.js.map +1 -0
  90. package/dist/ui-DL8WaLmH.cjs +849 -0
  91. package/dist/ui-DL8WaLmH.cjs.map +1 -0
  92. package/dist/voice/index.d.ts +5 -0
  93. package/dist/voice/index.d.ts.map +1 -0
  94. package/dist/voice/play-stream-with-web-audio.d.ts +2 -0
  95. package/dist/voice/play-stream-with-web-audio.d.ts.map +1 -0
  96. package/dist/voice/record-mic-to-file.d.ts +2 -0
  97. package/dist/voice/record-mic-to-file.d.ts.map +1 -0
  98. package/dist/voice/use-speech-recognition.d.ts +20 -0
  99. package/dist/voice/use-speech-recognition.d.ts.map +1 -0
  100. package/dist/workflows/WorkflowStepFactory/WorkflowStepFactory.d.ts +8 -0
  101. package/dist/workflows/WorkflowStepFactory/WorkflowStepFactory.d.ts.map +1 -0
  102. package/dist/workflows/WorkflowStepFactory/index.d.ts +3 -0
  103. package/dist/workflows/WorkflowStepFactory/index.d.ts.map +1 -0
  104. package/dist/workflows/WorkflowStepFactory/types.d.ts +90 -0
  105. package/dist/workflows/WorkflowStepFactory/types.d.ts.map +1 -0
  106. package/dist/workflows/hooks.d.ts +34 -0
  107. package/dist/workflows/hooks.d.ts.map +1 -0
  108. package/dist/workflows/index.d.ts +4 -0
  109. package/dist/workflows/index.d.ts.map +1 -0
  110. package/dist/workflows/types.d.ts +122 -0
  111. package/dist/workflows/types.d.ts.map +1 -0
  112. package/dist/workflows/use-stream-workflow.d.ts +39 -0
  113. package/dist/workflows/use-stream-workflow.d.ts.map +1 -0
  114. package/package.json +52 -30
  115. package/dist/src/agent/hooks.d.ts +0 -46
  116. package/dist/src/index.d.ts +0 -6
  117. package/dist/src/lib/ai-sdk/index.d.ts +0 -3
  118. package/dist/src/lib/ai-sdk/memory/resolveInitialMessages.d.ts +0 -2
  119. package/dist/src/lib/ai-sdk/transformers/AISdkNetworkTransformer.d.ts +0 -10
  120. package/dist/src/lib/ai-sdk/transformers/types.d.ts +0 -10
  121. package/dist/src/lib/ai-sdk/types.d.ts +0 -14
  122. package/dist/src/lib/ai-sdk/utils/toAssistantUIMessage.d.ts +0 -14
  123. package/dist/src/lib/ai-sdk/utils/toAssistantUIMessage.test.d.ts +0 -1
  124. package/dist/src/lib/ai-sdk/utils/toUIMessage.d.ts +0 -17
  125. package/dist/src/mastra-client-context.d.ts +0 -10
  126. package/dist/src/mastra-react-provider.d.ts +0 -4
  127. package/dist/src/ui/Code/highlight.d.ts +0 -3
  128. package/dist/src/ui/Code/index.d.ts +0 -1
  129. package/dist/src/ui/Entity/Entity.stories.d.ts +0 -22
  130. package/dist/src/ui/Entity/index.d.ts +0 -4
  131. package/dist/src/ui/Icon/index.d.ts +0 -1
  132. package/dist/src/ui/IconButton/IconButton.stories.d.ts +0 -12
  133. package/dist/src/ui/IconButton/index.d.ts +0 -1
  134. package/dist/src/ui/Icons/AgentIcon.d.ts +0 -2
  135. package/dist/src/ui/Icons/ToolsIcon.d.ts +0 -2
  136. package/dist/src/ui/Icons/WorkflowIcon.d.ts +0 -2
  137. package/dist/src/ui/Icons/index.d.ts +0 -3
  138. package/dist/src/ui/Message/Message.stories.d.ts +0 -13
  139. package/dist/src/ui/Message/index.d.ts +0 -1
  140. package/dist/src/ui/Tooltip/Tooltip.stories.d.ts +0 -12
  141. package/dist/src/ui/Tooltip/index.d.ts +0 -1
  142. package/dist/src/ui/index.d.ts +0 -7
package/dist/index.cjs CHANGED
@@ -1,1549 +1,3357 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
-
5
- const jsxRuntime = require('react/jsx-runtime');
6
- const react = require('react');
7
- const clientJs = require('@mastra/client-js');
8
- const lucideReact = require('lucide-react');
9
- const tailwindMerge = require('tailwind-merge');
10
- const hastUtilToJsxRuntime = require('hast-util-to-jsx-runtime');
11
- const web = require('shiki/bundle/web');
12
- const reactTooltip = require('@radix-ui/react-tooltip');
13
-
14
- const MastraClientContext = react.createContext({});
15
- const MastraClientProvider = ({ children, baseUrl, headers }) => {
16
- const client = createMastraClient(baseUrl, headers);
17
- return /* @__PURE__ */ jsxRuntime.jsx(MastraClientContext.Provider, { value: client, children });
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_ui = require("./ui-DL8WaLmH.cjs");
3
+ let _mastra_client_js = require("@mastra/client-js");
4
+ let react = require("react");
5
+ let react_jsx_runtime = require("react/jsx-runtime");
6
+ let _lukeed_uuid = require("@lukeed/uuid");
7
+ let _mastra_core_agent_message_list = require("@mastra/core/agent/message-list");
8
+ //#region src/mastra-client-context.tsx
9
+ const MastraClientContext = (0, react.createContext)({});
10
+ const MastraClientProvider = ({ children, baseUrl, headers, apiPrefix, credentials = "include", customFetch }) => {
11
+ const client = createMastraClient(baseUrl, headers, apiPrefix, credentials, customFetch);
12
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MastraClientContext.Provider, {
13
+ value: client,
14
+ children
15
+ });
18
16
  };
19
- const useMastraClient = () => react.useContext(MastraClientContext);
20
- const createMastraClient = (baseUrl, mastraClientHeaders = {}) => {
21
- return new clientJs.MastraClient({
22
- baseUrl: baseUrl || "",
23
- // only add the header if the baseUrl is not provided i.e it's a local dev environment
24
- headers: !baseUrl ? { ...mastraClientHeaders, "x-mastra-dev-playground": "true" } : mastraClientHeaders
25
- });
17
+ const useMastraClient = () => (0, react.useContext)(MastraClientContext);
18
+ const IPV4_LOOPBACK_RE = /^127\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
19
+ const isIPv4Loopback = (hostname) => {
20
+ const m = IPV4_LOOPBACK_RE.exec(hostname);
21
+ if (!m) return false;
22
+ return +m[1] <= 255 && +m[2] <= 255 && +m[3] <= 255;
26
23
  };
27
-
28
- const MastraReactProvider = ({ children, baseUrl, headers }) => {
29
- return /* @__PURE__ */ jsxRuntime.jsx(MastraClientProvider, { baseUrl, headers, children });
24
+ const isLocalUrl = (url) => {
25
+ if (!url) return true;
26
+ try {
27
+ const { hostname } = new URL(url);
28
+ return hostname === "localhost" || hostname.endsWith(".localhost") || isIPv4Loopback(hostname) || hostname === "::1" || hostname === "[::1]";
29
+ } catch {
30
+ return false;
31
+ }
30
32
  };
31
-
32
- const mapWorkflowStreamChunkToWatchResult = (prev, chunk) => {
33
- if (chunk.type === "workflow-start") {
34
- return {
35
- input: prev?.input,
36
- status: "running",
37
- steps: prev?.steps || {}
38
- };
39
- }
40
- if (chunk.type === "workflow-canceled") {
41
- return {
42
- ...prev,
43
- status: "canceled"
44
- };
45
- }
46
- if (chunk.type === "workflow-finish") {
47
- const finalStatus = chunk.payload.workflowStatus;
48
- const prevSteps = prev?.steps ?? {};
49
- const lastStep = Object.values(prevSteps).pop();
50
- return {
51
- ...prev,
52
- status: chunk.payload.workflowStatus,
53
- ...finalStatus === "success" && lastStep?.status === "success" ? { result: lastStep?.output } : finalStatus === "failed" && lastStep?.status === "failed" ? { error: lastStep?.error } : {}
54
- };
55
- }
56
- const { stepCallId, stepName, ...newPayload } = chunk.payload ?? {};
57
- const newSteps = {
58
- ...prev?.steps,
59
- [chunk.payload.id]: {
60
- ...prev?.steps?.[chunk.payload.id],
61
- ...newPayload
62
- }
63
- };
64
- if (chunk.type === "workflow-step-start") {
65
- return {
66
- ...prev,
67
- steps: newSteps
68
- };
69
- }
70
- if (chunk.type === "workflow-step-suspended") {
71
- const suspendedStepIds = Object.entries(newSteps).flatMap(
72
- ([stepId, stepResult]) => {
73
- if (stepResult?.status === "suspended") {
74
- const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
75
- return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
76
- }
77
- return [];
78
- }
79
- );
80
- return {
81
- ...prev,
82
- status: "suspended",
83
- steps: newSteps,
84
- suspendPayload: chunk.payload.suspendPayload,
85
- suspended: suspendedStepIds
86
- };
87
- }
88
- if (chunk.type === "workflow-step-waiting") {
89
- return {
90
- ...prev,
91
- status: "waiting",
92
- steps: newSteps
93
- };
94
- }
95
- if (chunk.type === "workflow-step-result") {
96
- return {
97
- ...prev,
98
- steps: newSteps
99
- };
100
- }
101
- return prev;
33
+ const createMastraClient = (baseUrl, mastraClientHeaders = {}, apiPrefix, credentials = "include", customFetch) => {
34
+ return new _mastra_client_js.MastraClient({
35
+ baseUrl: baseUrl || "",
36
+ headers: isLocalUrl(baseUrl) ? {
37
+ ...mastraClientHeaders,
38
+ "x-mastra-dev-playground": "true"
39
+ } : mastraClientHeaders,
40
+ apiPrefix,
41
+ credentials,
42
+ fetch: customFetch
43
+ });
102
44
  };
103
- const toUIMessage = ({ chunk, conversation, metadata }) => {
104
- const result = [...conversation];
105
- switch (chunk.type) {
106
- case "tripwire": {
107
- const newMessage = {
108
- id: `tripwire-${chunk.runId + Date.now()}`,
109
- role: "assistant",
110
- parts: [
111
- {
112
- type: "text",
113
- text: chunk.payload.tripwireReason
114
- }
115
- ],
116
- metadata: {
117
- ...metadata,
118
- status: "warning"
119
- }
120
- };
121
- return [...result, newMessage];
122
- }
123
- case "start": {
124
- const newMessage = {
125
- id: `start-${chunk.runId + Date.now()}`,
126
- role: "assistant",
127
- parts: [],
128
- metadata
129
- };
130
- return [...result, newMessage];
131
- }
132
- case "text-start":
133
- case "text-delta": {
134
- const lastMessage = result[result.length - 1];
135
- if (!lastMessage || lastMessage.role !== "assistant") return result;
136
- const parts = [...lastMessage.parts];
137
- let textPartIndex = parts.findIndex((part) => part.type === "text");
138
- if (chunk.type === "text-start") {
139
- if (textPartIndex === -1) {
140
- parts.push({
141
- type: "text",
142
- text: "",
143
- state: "streaming",
144
- providerMetadata: chunk.payload.providerMetadata
145
- });
146
- }
147
- } else {
148
- if (textPartIndex === -1) {
149
- parts.push({
150
- type: "text",
151
- text: chunk.payload.text,
152
- state: "streaming",
153
- providerMetadata: chunk.payload.providerMetadata
154
- });
155
- } else {
156
- const textPart = parts[textPartIndex];
157
- if (textPart.type === "text") {
158
- parts[textPartIndex] = {
159
- ...textPart,
160
- text: textPart.text + chunk.payload.text,
161
- state: "streaming"
162
- };
163
- }
164
- }
165
- }
166
- return [
167
- ...result.slice(0, -1),
168
- {
169
- ...lastMessage,
170
- parts
171
- }
172
- ];
173
- }
174
- case "reasoning-delta": {
175
- const lastMessage = result[result.length - 1];
176
- if (!lastMessage || lastMessage.role !== "assistant") {
177
- const newMessage = {
178
- id: `reasoning-${chunk.runId + Date.now()}`,
179
- role: "assistant",
180
- parts: [
181
- {
182
- type: "reasoning",
183
- text: chunk.payload.text,
184
- state: "streaming",
185
- providerMetadata: chunk.payload.providerMetadata
186
- }
187
- ],
188
- metadata
189
- };
190
- return [...result, newMessage];
191
- }
192
- const parts = [...lastMessage.parts];
193
- let reasoningPartIndex = parts.findIndex((part) => part.type === "reasoning");
194
- if (reasoningPartIndex === -1) {
195
- parts.push({
196
- type: "reasoning",
197
- text: chunk.payload.text,
198
- state: "streaming",
199
- providerMetadata: chunk.payload.providerMetadata
200
- });
201
- } else {
202
- const reasoningPart = parts[reasoningPartIndex];
203
- if (reasoningPart.type === "reasoning") {
204
- parts[reasoningPartIndex] = {
205
- ...reasoningPart,
206
- text: reasoningPart.text + chunk.payload.text,
207
- state: "streaming"
208
- };
209
- }
210
- }
211
- return [
212
- ...result.slice(0, -1),
213
- {
214
- ...lastMessage,
215
- parts
216
- }
217
- ];
218
- }
219
- case "tool-call": {
220
- const lastMessage = result[result.length - 1];
221
- if (!lastMessage || lastMessage.role !== "assistant") {
222
- const newMessage = {
223
- id: `tool-call-${chunk.runId + Date.now()}`,
224
- role: "assistant",
225
- parts: [
226
- {
227
- type: "dynamic-tool",
228
- toolName: chunk.payload.toolName,
229
- toolCallId: chunk.payload.toolCallId,
230
- state: "input-available",
231
- input: chunk.payload.args,
232
- callProviderMetadata: chunk.payload.providerMetadata
233
- }
234
- ],
235
- metadata
236
- };
237
- return [...result, newMessage];
238
- }
239
- const parts = [...lastMessage.parts];
240
- parts.push({
241
- type: "dynamic-tool",
242
- toolName: chunk.payload.toolName,
243
- toolCallId: chunk.payload.toolCallId,
244
- state: "input-available",
245
- input: chunk.payload.args,
246
- callProviderMetadata: chunk.payload.providerMetadata
247
- });
248
- return [
249
- ...result.slice(0, -1),
250
- {
251
- ...lastMessage,
252
- parts
253
- }
254
- ];
255
- }
256
- case "tool-result": {
257
- const lastMessage = result[result.length - 1];
258
- if (!lastMessage || lastMessage.role !== "assistant") return result;
259
- const parts = [...lastMessage.parts];
260
- const toolPartIndex = parts.findIndex(
261
- (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
262
- );
263
- if (toolPartIndex !== -1) {
264
- const toolPart = parts[toolPartIndex];
265
- if (toolPart.type === "dynamic-tool") {
266
- if (chunk.payload.isError) {
267
- parts[toolPartIndex] = {
268
- type: "dynamic-tool",
269
- toolName: toolPart.toolName,
270
- toolCallId: toolPart.toolCallId,
271
- state: "output-error",
272
- input: toolPart.input,
273
- errorText: String(chunk.payload.result),
274
- callProviderMetadata: chunk.payload.providerMetadata
275
- };
276
- } else {
277
- const isWorkflow = Boolean(chunk.payload.result?.result?.steps);
278
- parts[toolPartIndex] = {
279
- type: "dynamic-tool",
280
- toolName: toolPart.toolName,
281
- toolCallId: toolPart.toolCallId,
282
- state: "output-available",
283
- input: toolPart.input,
284
- output: isWorkflow ? chunk.payload.result?.result : chunk.payload.result,
285
- callProviderMetadata: chunk.payload.providerMetadata
286
- };
287
- }
288
- }
289
- }
290
- return [
291
- ...result.slice(0, -1),
292
- {
293
- ...lastMessage,
294
- parts
295
- }
296
- ];
297
- }
298
- case "tool-output": {
299
- const lastMessage = result[result.length - 1];
300
- if (!lastMessage || lastMessage.role !== "assistant") return result;
301
- const parts = [...lastMessage.parts];
302
- const toolPartIndex = parts.findIndex(
303
- (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
304
- );
305
- if (toolPartIndex !== -1) {
306
- const toolPart = parts[toolPartIndex];
307
- if (toolPart.type === "dynamic-tool") {
308
- if (chunk.payload.output?.type?.startsWith("workflow-")) {
309
- const existingWorkflowState = toolPart.output || {};
310
- const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(
311
- existingWorkflowState,
312
- chunk.payload.output
313
- );
314
- parts[toolPartIndex] = {
315
- ...toolPart,
316
- output: updatedWorkflowState
317
- };
318
- } else {
319
- const currentOutput = toolPart.output || [];
320
- const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
321
- parts[toolPartIndex] = {
322
- ...toolPart,
323
- output: [...existingOutput, chunk.payload.output]
324
- };
325
- }
326
- }
327
- }
328
- return [
329
- ...result.slice(0, -1),
330
- {
331
- ...lastMessage,
332
- parts
333
- }
334
- ];
335
- }
336
- case "source": {
337
- const lastMessage = result[result.length - 1];
338
- if (!lastMessage || lastMessage.role !== "assistant") return result;
339
- const parts = [...lastMessage.parts];
340
- if (chunk.payload.sourceType === "url") {
341
- parts.push({
342
- type: "source-url",
343
- sourceId: chunk.payload.id,
344
- url: chunk.payload.url || "",
345
- title: chunk.payload.title,
346
- providerMetadata: chunk.payload.providerMetadata
347
- });
348
- } else if (chunk.payload.sourceType === "document") {
349
- parts.push({
350
- type: "source-document",
351
- sourceId: chunk.payload.id,
352
- mediaType: chunk.payload.mimeType || "application/octet-stream",
353
- title: chunk.payload.title,
354
- filename: chunk.payload.filename,
355
- providerMetadata: chunk.payload.providerMetadata
356
- });
357
- }
358
- return [
359
- ...result.slice(0, -1),
360
- {
361
- ...lastMessage,
362
- parts
363
- }
364
- ];
365
- }
366
- case "file": {
367
- const lastMessage = result[result.length - 1];
368
- if (!lastMessage || lastMessage.role !== "assistant") return result;
369
- const parts = [...lastMessage.parts];
370
- let url;
371
- if (typeof chunk.payload.data === "string") {
372
- url = chunk.payload.base64 ? `data:${chunk.payload.mimeType};base64,${chunk.payload.data}` : `data:${chunk.payload.mimeType},${encodeURIComponent(chunk.payload.data)}`;
373
- } else {
374
- const base64 = btoa(String.fromCharCode(...chunk.payload.data));
375
- url = `data:${chunk.payload.mimeType};base64,${base64}`;
376
- }
377
- parts.push({
378
- type: "file",
379
- mediaType: chunk.payload.mimeType,
380
- url,
381
- providerMetadata: chunk.payload.providerMetadata
382
- });
383
- return [
384
- ...result.slice(0, -1),
385
- {
386
- ...lastMessage,
387
- parts
388
- }
389
- ];
390
- }
391
- case "finish": {
392
- const lastMessage = result[result.length - 1];
393
- if (!lastMessage || lastMessage.role !== "assistant") return result;
394
- const parts = lastMessage.parts.map((part) => {
395
- if (part.type === "text" && part.state === "streaming") {
396
- return { ...part, state: "done" };
397
- }
398
- if (part.type === "reasoning" && part.state === "streaming") {
399
- return { ...part, state: "done" };
400
- }
401
- return part;
402
- });
403
- return [
404
- ...result.slice(0, -1),
405
- {
406
- ...lastMessage,
407
- parts
408
- }
409
- ];
410
- }
411
- case "error": {
412
- const newMessage = {
413
- id: `error-${chunk.runId + Date.now()}`,
414
- role: "assistant",
415
- parts: [
416
- {
417
- type: "text",
418
- text: typeof chunk.payload.error === "string" ? chunk.payload.error : JSON.stringify(chunk.payload.error)
419
- }
420
- ],
421
- metadata: {
422
- ...metadata,
423
- status: "error"
424
- }
425
- };
426
- return [...result, newMessage];
427
- }
428
- // For all other chunk types, return conversation unchanged
429
- default:
430
- return result;
431
- }
45
+ //#endregion
46
+ //#region src/mastra-react-provider.tsx
47
+ const MastraReactProvider = ({ children, baseUrl, headers, apiPrefix, credentials, customFetch }) => {
48
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MastraClientProvider, {
49
+ baseUrl,
50
+ headers,
51
+ apiPrefix,
52
+ credentials,
53
+ customFetch,
54
+ children
55
+ });
432
56
  };
433
-
434
- const toAssistantUIMessage = (message) => {
435
- const extendedMessage = message;
436
- const content = message.parts.map((part) => {
437
- if (part.type === "text") {
438
- return {
439
- type: "text",
440
- text: part.text,
441
- metadata: message.metadata
442
- };
443
- }
444
- if (part.type === "reasoning") {
445
- return {
446
- type: "reasoning",
447
- text: part.text,
448
- metadata: message.metadata
449
- };
450
- }
451
- if (part.type === "source-url") {
452
- return {
453
- type: "source",
454
- sourceType: "url",
455
- id: part.sourceId,
456
- url: part.url,
457
- title: part.title,
458
- metadata: message.metadata
459
- };
460
- }
461
- if (part.type === "source-document") {
462
- return {
463
- type: "file",
464
- filename: part.filename,
465
- mimeType: part.mediaType,
466
- data: "",
467
- // Source documents don't have inline data
468
- metadata: message.metadata
469
- };
470
- }
471
- if (part.type === "file") {
472
- return {
473
- type: "file",
474
- mimeType: part.mediaType,
475
- data: part.url,
476
- // Use URL as data source
477
- metadata: message.metadata
478
- };
479
- }
480
- if (part.type === "dynamic-tool") {
481
- const baseToolCall = {
482
- type: "tool-call",
483
- toolCallId: part.toolCallId,
484
- toolName: part.toolName,
485
- argsText: JSON.stringify(part.input),
486
- args: part.input,
487
- metadata: message.metadata
488
- };
489
- if (part.state === "output-error" && "errorText" in part) {
490
- return { ...baseToolCall, result: part.errorText, isError: true };
491
- }
492
- if ("output" in part) {
493
- return { ...baseToolCall, result: part.output };
494
- }
495
- return baseToolCall;
496
- }
497
- if (part.type.startsWith("tool-") && part.state !== "input-available") {
498
- const toolName = "toolName" in part && typeof part.toolName === "string" ? part.toolName : part.type.substring(5);
499
- const baseToolCall = {
500
- type: "tool-call",
501
- toolCallId: "toolCallId" in part && typeof part.toolCallId === "string" ? part.toolCallId : "",
502
- toolName,
503
- argsText: "input" in part ? JSON.stringify(part.input) : "{}",
504
- args: "input" in part ? part.input : {},
505
- metadata: message.metadata
506
- };
507
- if ("output" in part) {
508
- return { ...baseToolCall, result: part.output };
509
- } else if ("error" in part) {
510
- return { ...baseToolCall, result: part.error, isError: true };
511
- }
512
- return baseToolCall;
513
- }
514
- return {
515
- type: "text",
516
- text: "",
517
- metadata: message.metadata
518
- };
519
- });
520
- let status;
521
- if (message.role === "assistant" && content.length > 0) {
522
- const hasStreamingParts = message.parts.some(
523
- (part) => part.type === "text" && "state" in part && part.state === "streaming" || part.type === "reasoning" && "state" in part && part.state === "streaming"
524
- );
525
- const hasToolCalls = message.parts.some((part) => part.type === "dynamic-tool" || part.type.startsWith("tool-"));
526
- const hasInputAvailableTools = message.parts.some(
527
- (part) => part.type === "dynamic-tool" && part.state === "input-available"
528
- );
529
- const hasErrorTools = message.parts.some(
530
- (part) => part.type === "dynamic-tool" && part.state === "output-error" || part.type.startsWith("tool-") && "error" in part
531
- );
532
- if (hasStreamingParts) {
533
- status = { type: "running" };
534
- } else if (hasInputAvailableTools && hasToolCalls) {
535
- status = { type: "requires-action", reason: "tool-calls" };
536
- } else if (hasErrorTools) {
537
- status = { type: "incomplete", reason: "error" };
538
- } else {
539
- status = { type: "complete", reason: "stop" };
540
- }
541
- }
542
- const threadMessage = {
543
- role: message.role,
544
- content,
545
- id: message.id,
546
- createdAt: extendedMessage.createdAt,
547
- status,
548
- attachments: extendedMessage.experimental_attachments
549
- };
550
- return threadMessage;
57
+ //#endregion
58
+ //#region src/agent/signal-data.ts
59
+ const uint8ArrayToBase64 = (bytes) => {
60
+ const chunkSize = 32768;
61
+ let binary = "";
62
+ for (let i = 0; i < bytes.length; i += chunkSize) binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
63
+ return btoa(binary);
551
64
  };
552
-
553
- class AISdkNetworkTransformer {
554
- transform({ chunk, conversation, metadata }) {
555
- const newConversation = [...conversation];
556
- if (chunk.type === "routing-agent-text-delta") {
557
- return this.handleRoutingAgentConversation(chunk, newConversation);
558
- }
559
- if (chunk.type.startsWith("agent-execution-")) {
560
- return this.handleAgentConversation(chunk, newConversation, metadata);
561
- }
562
- if (chunk.type.startsWith("workflow-execution-")) {
563
- return this.handleWorkflowConversation(chunk, newConversation, metadata);
564
- }
565
- if (chunk.type.startsWith("tool-execution-")) {
566
- return this.handleToolConversation(chunk, newConversation, metadata);
567
- }
568
- if (chunk.type === "network-execution-event-step-finish") {
569
- const lastMessage = newConversation[newConversation.length - 1];
570
- if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
571
- const agentChunk = chunk.payload;
572
- const parts = [...lastMessage.parts];
573
- const textPartIndex = parts.findIndex((part) => part.type === "text");
574
- if (textPartIndex === -1) {
575
- parts.push({
576
- type: "text",
577
- text: agentChunk.result,
578
- state: "done"
579
- });
580
- return [
581
- ...newConversation.slice(0, -1),
582
- {
583
- ...lastMessage,
584
- parts
585
- }
586
- ];
587
- }
588
- const textPart = parts[textPartIndex];
589
- if (textPart.type === "text") {
590
- parts[textPartIndex] = {
591
- ...textPart,
592
- state: "done"
593
- };
594
- return [
595
- ...newConversation.slice(0, -1),
596
- {
597
- ...lastMessage,
598
- parts
599
- }
600
- ];
601
- }
602
- return newConversation;
603
- }
604
- return newConversation;
605
- }
606
- handleRoutingAgentConversation = (chunk, newConversation) => {
607
- const lastMessage = newConversation[newConversation.length - 1];
608
- if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
609
- const agentChunk = chunk.payload;
610
- const parts = [...lastMessage.parts];
611
- const textPartIndex = parts.findIndex((part) => part.type === "text");
612
- if (textPartIndex === -1) {
613
- parts.push({
614
- type: "text",
615
- text: agentChunk.text,
616
- state: "streaming"
617
- });
618
- return [
619
- ...newConversation.slice(0, -1),
620
- {
621
- ...lastMessage,
622
- parts
623
- }
624
- ];
625
- }
626
- const textPart = parts[textPartIndex];
627
- if (textPart.type === "text") {
628
- parts[textPartIndex] = {
629
- ...textPart,
630
- text: textPart.text + agentChunk.text,
631
- state: "streaming"
632
- };
633
- return [
634
- ...newConversation.slice(0, -1),
635
- {
636
- ...lastMessage,
637
- parts
638
- }
639
- ];
640
- }
641
- return newConversation;
642
- };
643
- handleAgentConversation = (chunk, newConversation, metadata) => {
644
- if (chunk.type === "agent-execution-start") {
645
- const primitiveId = chunk.payload?.args?.primitiveId;
646
- const runId = chunk.payload.runId;
647
- if (!primitiveId || !runId) return newConversation;
648
- const newMessage = {
649
- id: `agent-execution-start-${runId}-${Date.now()}`,
650
- role: "assistant",
651
- parts: [
652
- {
653
- type: "dynamic-tool",
654
- toolName: primitiveId,
655
- toolCallId: runId,
656
- state: "input-available",
657
- input: chunk.payload.args
658
- }
659
- ],
660
- metadata: {
661
- ...metadata,
662
- selectionReason: chunk.payload?.args?.selectionReason || "",
663
- agentInput: chunk.payload?.args?.task,
664
- mode: "network",
665
- from: "AGENT"
666
- }
667
- };
668
- return [...newConversation, newMessage];
669
- }
670
- if (chunk.type === "agent-execution-end") {
671
- const lastMessage = newConversation[newConversation.length - 1];
672
- if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
673
- const parts = [...lastMessage.parts];
674
- const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
675
- if (toolPartIndex !== -1) {
676
- const toolPart = parts[toolPartIndex];
677
- if (toolPart.type === "dynamic-tool") {
678
- const currentOutput = toolPart.output;
679
- parts[toolPartIndex] = {
680
- type: "dynamic-tool",
681
- toolName: toolPart.toolName,
682
- toolCallId: toolPart.toolCallId,
683
- state: "output-available",
684
- input: toolPart.input,
685
- output: {
686
- ...currentOutput,
687
- result: currentOutput?.result || chunk.payload?.result || ""
688
- }
689
- };
690
- }
691
- }
692
- return [
693
- ...newConversation.slice(0, -1),
694
- {
695
- ...lastMessage,
696
- parts
697
- }
698
- ];
699
- }
700
- if (chunk.type.startsWith("agent-execution-event-")) {
701
- const lastMessage = newConversation[newConversation.length - 1];
702
- if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
703
- const agentChunk = chunk.payload;
704
- const parts = [...lastMessage.parts];
705
- const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
706
- if (toolPartIndex === -1) return newConversation;
707
- const toolPart = parts[toolPartIndex];
708
- if (agentChunk.type === "text-delta") {
709
- const childMessages = toolPart?.output?.childMessages || [];
710
- const lastChildMessage = childMessages[childMessages.length - 1];
711
- const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.payload.text };
712
- const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
713
- parts[toolPartIndex] = {
714
- ...toolPart,
715
- output: {
716
- childMessages: nextMessages
717
- }
718
- };
719
- } else if (agentChunk.type === "tool-call") {
720
- const childMessages = toolPart?.output?.childMessages || [];
721
- parts[toolPartIndex] = {
722
- ...toolPart,
723
- output: {
724
- ...toolPart?.output,
725
- childMessages: [
726
- ...childMessages,
727
- {
728
- type: "tool",
729
- toolCallId: agentChunk.payload.toolCallId,
730
- toolName: agentChunk.payload.toolName,
731
- args: agentChunk.payload.args
732
- }
733
- ]
734
- }
735
- };
736
- } else if (agentChunk.type === "tool-output") {
737
- if (agentChunk.payload?.output?.type?.startsWith("workflow-")) {
738
- const childMessages = toolPart?.output?.childMessages || [];
739
- const lastToolIndex = childMessages.length - 1;
740
- const currentMessage = childMessages[lastToolIndex];
741
- const actualExistingWorkflowState = currentMessage?.toolOutput || {};
742
- const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(
743
- actualExistingWorkflowState,
744
- agentChunk.payload.output
745
- );
746
- if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
747
- parts[toolPartIndex] = {
748
- ...toolPart,
749
- output: {
750
- ...toolPart?.output,
751
- childMessages: [
752
- ...childMessages.slice(0, -1),
753
- {
754
- ...currentMessage,
755
- toolOutput: updatedWorkflowState
756
- }
757
- ]
758
- }
759
- };
760
- }
761
- }
762
- } else if (agentChunk.type === "tool-result") {
763
- const childMessages = toolPart?.output?.childMessages || [];
764
- const lastToolIndex = childMessages.length - 1;
765
- const isWorkflow = Boolean(agentChunk.payload?.result?.result?.steps);
766
- if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
767
- parts[toolPartIndex] = {
768
- ...toolPart,
769
- output: {
770
- ...toolPart?.output,
771
- childMessages: [
772
- ...childMessages.slice(0, -1),
773
- {
774
- ...childMessages[lastToolIndex],
775
- toolOutput: isWorkflow ? agentChunk.payload.result.result : agentChunk.payload.result
776
- }
777
- ]
778
- }
779
- };
780
- }
781
- }
782
- return [
783
- ...newConversation.slice(0, -1),
784
- {
785
- ...lastMessage,
786
- parts
787
- }
788
- ];
789
- }
790
- return newConversation;
791
- };
792
- handleWorkflowConversation = (chunk, newConversation, metadata) => {
793
- if (chunk.type === "workflow-execution-start") {
794
- const primitiveId = chunk.payload?.args?.primitiveId;
795
- const runId = chunk.payload.runId;
796
- if (!primitiveId || !runId) return newConversation;
797
- let agentInput;
798
- try {
799
- agentInput = JSON.parse(chunk?.payload?.args?.prompt);
800
- } catch (e) {
801
- agentInput = chunk?.payload?.args?.prompt;
802
- }
803
- const newMessage = {
804
- id: `workflow-start-${runId}-${Date.now()}`,
805
- role: "assistant",
806
- parts: [
807
- {
808
- type: "dynamic-tool",
809
- toolName: primitiveId,
810
- toolCallId: runId,
811
- state: "input-available",
812
- input: chunk.payload.args
813
- }
814
- ],
815
- metadata: {
816
- ...metadata,
817
- selectionReason: chunk.payload?.args?.selectionReason || "",
818
- from: "WORKFLOW",
819
- mode: "network",
820
- agentInput
821
- }
822
- };
823
- return [...newConversation, newMessage];
824
- }
825
- if (chunk.type.startsWith("workflow-execution-event-")) {
826
- const lastMessage = newConversation[newConversation.length - 1];
827
- if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
828
- const parts = [...lastMessage.parts];
829
- const toolPartIndex = parts.findIndex((part) => part.type === "dynamic-tool");
830
- if (toolPartIndex === -1) return newConversation;
831
- const toolPart = parts[toolPartIndex];
832
- if (toolPart.type !== "dynamic-tool") return newConversation;
833
- const existingWorkflowState = toolPart.output || {};
834
- const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(existingWorkflowState, chunk.payload);
835
- parts[toolPartIndex] = {
836
- ...toolPart,
837
- output: updatedWorkflowState
838
- };
839
- return [
840
- ...newConversation.slice(0, -1),
841
- {
842
- ...lastMessage,
843
- parts
844
- }
845
- ];
846
- }
847
- return newConversation;
848
- };
849
- handleToolConversation = (chunk, newConversation, metadata) => {
850
- if (chunk.type === "tool-execution-start") {
851
- const { args: argsData } = chunk.payload;
852
- const lastMessage = newConversation[newConversation.length - 1];
853
- const nestedArgs = argsData.args || {};
854
- if (!lastMessage || lastMessage.role !== "assistant") {
855
- const newMessage = {
856
- id: `tool-start-${chunk.runId}-${Date.now()}`,
857
- role: "assistant",
858
- parts: [
859
- {
860
- type: "dynamic-tool",
861
- toolName: argsData.toolName || "unknown",
862
- toolCallId: argsData.toolCallId || "unknown",
863
- state: "input-available",
864
- input: nestedArgs
865
- }
866
- ],
867
- metadata: {
868
- ...metadata,
869
- selectionReason: metadata?.mode === "network" ? metadata.selectionReason || argsData.selectionReason : "",
870
- mode: "network",
871
- agentInput: nestedArgs
872
- }
873
- };
874
- return [...newConversation, newMessage];
875
- }
876
- const parts = [...lastMessage.parts];
877
- parts.push({
878
- type: "dynamic-tool",
879
- toolName: argsData.toolName || "unknown",
880
- toolCallId: argsData.toolCallId || "unknown",
881
- state: "input-available",
882
- input: nestedArgs
883
- });
884
- return [
885
- ...newConversation.slice(0, -1),
886
- {
887
- ...lastMessage,
888
- parts
889
- }
890
- ];
891
- }
892
- if (chunk.type === "tool-execution-end") {
893
- const lastMessage = newConversation[newConversation.length - 1];
894
- if (!lastMessage || lastMessage.role !== "assistant") return newConversation;
895
- const parts = [...lastMessage.parts];
896
- const toolPartIndex = parts.findIndex(
897
- (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
898
- );
899
- if (toolPartIndex !== -1) {
900
- const toolPart = parts[toolPartIndex];
901
- if (toolPart.type === "dynamic-tool") {
902
- const currentOutput = toolPart.output;
903
- parts[toolPartIndex] = {
904
- type: "dynamic-tool",
905
- toolName: toolPart.toolName,
906
- toolCallId: toolPart.toolCallId,
907
- state: "output-available",
908
- input: toolPart.input,
909
- output: currentOutput?.result || chunk.payload?.result || ""
910
- };
911
- }
912
- }
913
- return [
914
- ...newConversation.slice(0, -1),
915
- {
916
- ...lastMessage,
917
- parts
918
- }
919
- ];
920
- }
921
- return newConversation;
922
- };
65
+ function convertSignalDataToBase64String(content) {
66
+ if (typeof content === "string") return content;
67
+ const bytes = content instanceof ArrayBuffer ? new Uint8Array(content) : content;
68
+ return uint8ArrayToBase64(bytes);
923
69
  }
924
-
925
- const resolveInitialMessages = (messages) => {
926
- return messages.map((message) => {
927
- const networkPart = message.parts.find((part) => part.type === "text" && part.text.includes('"isNetwork":true'));
928
- if (networkPart && networkPart.type === "text") {
929
- try {
930
- const json = JSON.parse(networkPart.text);
931
- if (json.isNetwork === true) {
932
- const selectionReason = json.selectionReason || "";
933
- const primitiveType = json.primitiveType || "";
934
- const primitiveId = json.primitiveId || "";
935
- const finalResult = json.finalResult;
936
- const toolCalls = finalResult?.toolCalls || [];
937
- const childMessages = [];
938
- for (const toolCall of toolCalls) {
939
- if (toolCall.type === "tool-call" && toolCall.payload) {
940
- const toolCallId = toolCall.payload.toolCallId;
941
- let toolResult;
942
- for (const message2 of finalResult?.messages || []) {
943
- for (const part of message2.content || []) {
944
- if (typeof part === "object" && part.type === "tool-result" && part.toolCallId === toolCallId) {
945
- toolResult = part;
946
- break;
947
- }
948
- }
949
- }
950
- const isWorkflow = Boolean(toolResult?.result?.result?.steps);
951
- childMessages.push({
952
- type: "tool",
953
- toolCallId: toolCall.payload.toolCallId,
954
- toolName: toolCall.payload.toolName,
955
- args: toolCall.payload.args,
956
- toolOutput: isWorkflow ? toolResult?.result?.result : toolResult?.result
957
- });
958
- }
959
- }
960
- if (finalResult && finalResult.text) {
961
- childMessages.push({
962
- type: "text",
963
- content: finalResult.text
964
- });
965
- }
966
- const result = {
967
- childMessages,
968
- result: finalResult?.text || ""
969
- };
970
- console.log("json", json);
971
- const nextMessage = {
972
- role: "assistant",
973
- parts: [
974
- {
975
- type: "dynamic-tool",
976
- toolCallId: primitiveId,
977
- toolName: primitiveId,
978
- state: "output-available",
979
- input: json.input,
980
- output: result
981
- }
982
- ],
983
- id: message.id,
984
- metadata: {
985
- ...message.metadata,
986
- mode: "network",
987
- selectionReason,
988
- agentInput: json.input,
989
- from: primitiveType === "agent" ? "AGENT" : "WORKFLOW"
990
- }
991
- };
992
- return nextMessage;
993
- }
994
- } catch (error) {
995
- return message;
996
- }
997
- }
998
- return message;
999
- });
70
+ /** Canonical DB `file` part `data` for optimistic UI and memory-shaped storage. */
71
+ function encodeFilePartDataForStorage(data, mimeType) {
72
+ if (typeof data === "string") return data;
73
+ if (data instanceof URL) return data.toString();
74
+ const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
75
+ const base64 = uint8ArrayToBase64(bytes);
76
+ if (base64.startsWith("data:")) return base64;
77
+ return `data:${mimeType};base64,${base64}`;
78
+ }
79
+ //#endregion
80
+ //#region src/lib/mastra-db/formatCompletionFeedback.ts
81
+ const formatBaseCompletionFeedback = (result, maxIterationReached, formatScorerHeading, incompleteMessage) => {
82
+ const lines = [];
83
+ lines.push("#### Completion Check Results");
84
+ lines.push("");
85
+ lines.push(`Overall: ${result.complete ? "✅ COMPLETE" : "❌ NOT COMPLETE"}`);
86
+ lines.push(`Duration: ${result.totalDuration}ms`);
87
+ if (result.timedOut) lines.push("⚠️ Scoring timed out");
88
+ lines.push("");
89
+ for (const scorer of result.scorers) {
90
+ lines.push(formatScorerHeading(scorer));
91
+ lines.push(`Score: ${scorer.score} ${scorer.passed ? "✅" : "❌"}`);
92
+ if (scorer.reason) lines.push(`Reason: ${scorer.reason}`);
93
+ lines.push("");
94
+ }
95
+ if (result.complete) lines.push("✅ The task is complete.");
96
+ else if (maxIterationReached) lines.push("⚠️ Max iterations reached.");
97
+ else lines.push(incompleteMessage);
98
+ return lines.join("\n");
1000
99
  };
1001
-
1002
- const useChat = ({ agentId, initializeMessages }) => {
1003
- const [messages, setMessages] = react.useState(
1004
- () => resolveInitialMessages(initializeMessages?.() || [])
1005
- );
1006
- const baseClient = useMastraClient();
1007
- const [isRunning, setIsRunning] = react.useState(false);
1008
- const generate = async ({
1009
- coreUserMessages,
1010
- runtimeContext,
1011
- threadId,
1012
- modelSettings,
1013
- signal,
1014
- onFinish
1015
- }) => {
1016
- const {
1017
- frequencyPenalty,
1018
- presencePenalty,
1019
- maxRetries,
1020
- maxTokens,
1021
- temperature,
1022
- topK,
1023
- topP,
1024
- instructions,
1025
- providerOptions,
1026
- maxSteps
1027
- } = modelSettings || {};
1028
- setIsRunning(true);
1029
- const clientWithAbort = new clientJs.MastraClient({
1030
- ...baseClient.options,
1031
- abortSignal: signal
1032
- });
1033
- const agent = clientWithAbort.getAgent(agentId);
1034
- const response = await agent.generate({
1035
- messages: coreUserMessages,
1036
- runId: agentId,
1037
- maxSteps,
1038
- modelSettings: {
1039
- frequencyPenalty,
1040
- presencePenalty,
1041
- maxRetries,
1042
- maxOutputTokens: maxTokens,
1043
- temperature,
1044
- topK,
1045
- topP
1046
- },
1047
- instructions,
1048
- runtimeContext,
1049
- ...threadId ? { threadId, resourceId: agentId } : {},
1050
- providerOptions
1051
- });
1052
- setIsRunning(false);
1053
- if (response && "uiMessages" in response.response && response.response.uiMessages) {
1054
- onFinish?.(response.response.uiMessages);
1055
- const mastraUIMessages = (response.response.uiMessages || []).map((message) => ({
1056
- ...message,
1057
- metadata: {
1058
- mode: "generate"
1059
- }
1060
- }));
1061
- setMessages((prev) => [...prev, ...mastraUIMessages]);
1062
- }
1063
- };
1064
- const stream = async ({ coreUserMessages, runtimeContext, threadId, onChunk, modelSettings, signal }) => {
1065
- const {
1066
- frequencyPenalty,
1067
- presencePenalty,
1068
- maxRetries,
1069
- maxTokens,
1070
- temperature,
1071
- topK,
1072
- topP,
1073
- instructions,
1074
- providerOptions,
1075
- maxSteps
1076
- } = modelSettings || {};
1077
- setIsRunning(true);
1078
- const clientWithAbort = new clientJs.MastraClient({
1079
- ...baseClient.options,
1080
- abortSignal: signal
1081
- });
1082
- const agent = clientWithAbort.getAgent(agentId);
1083
- const response = await agent.stream({
1084
- messages: coreUserMessages,
1085
- runId: agentId,
1086
- maxSteps,
1087
- modelSettings: {
1088
- frequencyPenalty,
1089
- presencePenalty,
1090
- maxRetries,
1091
- maxOutputTokens: maxTokens,
1092
- temperature,
1093
- topK,
1094
- topP
1095
- },
1096
- instructions,
1097
- runtimeContext,
1098
- ...threadId ? { threadId, resourceId: agentId } : {},
1099
- providerOptions
1100
- });
1101
- if (!response.body) {
1102
- setIsRunning(false);
1103
- throw new Error("[Stream] No response body");
1104
- }
1105
- await response.processDataStream({
1106
- onChunk: async (chunk) => {
1107
- setMessages((prev) => toUIMessage({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1108
- onChunk?.(chunk);
1109
- }
1110
- });
1111
- setIsRunning(false);
1112
- };
1113
- const network = async ({
1114
- coreUserMessages,
1115
- runtimeContext,
1116
- threadId,
1117
- onNetworkChunk,
1118
- modelSettings,
1119
- signal
1120
- }) => {
1121
- const { frequencyPenalty, presencePenalty, maxRetries, maxTokens, temperature, topK, topP, maxSteps } = modelSettings || {};
1122
- setIsRunning(true);
1123
- const clientWithAbort = new clientJs.MastraClient({
1124
- ...baseClient.options,
1125
- abortSignal: signal
1126
- });
1127
- const agent = clientWithAbort.getAgent(agentId);
1128
- const response = await agent.network({
1129
- messages: coreUserMessages,
1130
- maxSteps,
1131
- modelSettings: {
1132
- frequencyPenalty,
1133
- presencePenalty,
1134
- maxRetries,
1135
- maxOutputTokens: maxTokens,
1136
- temperature,
1137
- topK,
1138
- topP
1139
- },
1140
- runId: agentId,
1141
- runtimeContext,
1142
- ...threadId ? { thread: threadId, resourceId: agentId } : {}
1143
- });
1144
- const transformer = new AISdkNetworkTransformer();
1145
- await response.processDataStream({
1146
- onChunk: async (chunk) => {
1147
- setMessages((prev) => transformer.transform({ chunk, conversation: prev, metadata: { mode: "network" } }));
1148
- onNetworkChunk?.(chunk);
1149
- }
1150
- });
1151
- setIsRunning(false);
1152
- };
1153
- const sendMessage = async ({ mode = "stream", ...args }) => {
1154
- const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
1155
- const messages2 = args.coreUserMessages ? [nextMessage, ...args.coreUserMessages] : [nextMessage];
1156
- setMessages((s) => [...s, { role: "user", parts: [{ type: "text", text: args.message }] }]);
1157
- if (mode === "generate") {
1158
- await generate({ ...args, coreUserMessages: messages2 });
1159
- } else if (mode === "stream") {
1160
- await stream({ ...args, coreUserMessages: messages2 });
1161
- } else if (mode === "network") {
1162
- await network({ ...args, coreUserMessages: messages2 });
1163
- }
1164
- };
1165
- return {
1166
- setMessages,
1167
- sendMessage,
1168
- isRunning,
1169
- messages,
1170
- cancelRun: () => setIsRunning(false)
1171
- };
100
+ const formatCompletionFeedback = (result, maxIterationReached) => {
101
+ return formatBaseCompletionFeedback(result, maxIterationReached, (scorer) => `###### ${scorer.scorerName} (${scorer.scorerId})`, "🔄 Will continue working on the task.");
1172
102
  };
1173
-
1174
- const EntityContext = react.createContext({
1175
- expanded: false,
1176
- setExpanded: () => {
1177
- },
1178
- variant: "initial",
1179
- disabled: false
103
+ const formatStreamCompletionFeedback = (result, maxIterationReached) => {
104
+ return formatBaseCompletionFeedback(result, maxIterationReached, (scorer) => `**${scorer.scorerName}** (${scorer.scorerId})`, "🔄 The task is not yet complete. Please continue working based on the feedback above.");
105
+ };
106
+ //#endregion
107
+ //#region src/lib/mastra-db/types.ts
108
+ /**
109
+ * Canonical metadata block stored under `MastraDBMessage.content.metadata`.
110
+ *
111
+ * Every UX hint the React accumulator needs to surface lives here. Mode-specific
112
+ * fields are all optional so a single record can carry the union without forcing
113
+ * narrowing on the consumer side.
114
+ */
115
+ /**
116
+ * Metadata key carrying a client-generated correlation id. The optimistic
117
+ * pending user bubble and the outgoing `sendMessage` request both stamp this
118
+ * id; the server echoes it back on the `data-user-message` data part so the
119
+ * accumulator can reconcile the pending bubble deterministically (decoupled
120
+ * from the server-assigned signal id). This is transient client state and is
121
+ * stripped once the echo is reconciled and on reload.
122
+ */
123
+ const CLIENT_MESSAGE_ID_KEY = "clientMessageId";
124
+ //#endregion
125
+ //#region src/lib/mastra-db/accumulator.ts
126
+ const cloneMetadata = (metadata) => metadata ? { ...metadata } : {};
127
+ const withParts = (message, parts) => ({
128
+ ...message,
129
+ content: {
130
+ ...message.content,
131
+ parts
132
+ }
1180
133
  });
1181
- const EntityProvider = EntityContext.Provider;
1182
- const useEntity = () => react.useContext(EntityContext);
1183
-
1184
- const IconSizes = {
1185
- sm: "mastra:[&>svg]:size-3",
1186
- md: "mastra:[&>svg]:size-4",
1187
- lg: "mastra:[&>svg]:size-5"
134
+ const withMetadata = (message, metadata) => ({
135
+ ...message,
136
+ content: {
137
+ ...message.content,
138
+ metadata
139
+ }
140
+ });
141
+ const clearPendingStatus = (message) => {
142
+ const { status: _status, [CLIENT_MESSAGE_ID_KEY]: _clientMessageId, ...rest } = message.content.metadata ?? {};
143
+ return withMetadata(message, rest);
1188
144
  };
1189
- const Icon = ({ children, className, size = "md", ...props }) => {
1190
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className || IconSizes[size], ...props, children });
145
+ const clearPendingStatusKeepClientId = (message) => {
146
+ const { status: _status, ...rest } = message.content.metadata ?? {};
147
+ return withMetadata(message, rest);
1191
148
  };
1192
-
1193
- const Entity = ({
1194
- className,
1195
- variant = "initial",
1196
- initialExpanded = false,
1197
- disabled = false,
1198
- ...props
1199
- }) => {
1200
- const [expanded, setExpanded] = react.useState(initialExpanded);
1201
- return /* @__PURE__ */ jsxRuntime.jsx(EntityProvider, { value: { expanded, setExpanded, variant, disabled }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className, ...props }) });
149
+ const replaceLast = (conversation, message) => [...conversation.slice(0, -1), message];
150
+ const replaceAt = (conversation, index, message) => [
151
+ ...conversation.slice(0, index),
152
+ message,
153
+ ...conversation.slice(index + 1)
154
+ ];
155
+ const newAssistantMessage = (id, parts, metadata) => ({
156
+ id,
157
+ role: "assistant",
158
+ createdAt: /* @__PURE__ */ new Date(),
159
+ content: {
160
+ format: 2,
161
+ parts,
162
+ metadata: cloneMetadata(metadata)
163
+ }
164
+ });
165
+ const appendAssistantMessage = (conversation, id, parts, metadata) => [...conversation, newAssistantMessage(id, parts, metadata)];
166
+ const isToolPart = (part) => part.type === "tool-invocation";
167
+ const partTextId = (part) => part.type === "text" ? part.textId : void 0;
168
+ const partState = (part) => part.state;
169
+ /**
170
+ * Set any streaming text/reasoning parts on the trailing assistant message to
171
+ * `state: 'done'`. Mirrors the previous `finishStreamingAssistantMessage` from
172
+ * the AI-SDK accumulator.
173
+ */
174
+ const finishStreamingAssistantMessage = (conversation) => {
175
+ const lastMessage = conversation[conversation.length - 1];
176
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
177
+ if (lastMessage.content.parts.length === 0) return conversation.slice(0, -1);
178
+ const nextParts = lastMessage.content.parts.map((part) => {
179
+ if ((part.type === "text" || part.type === "reasoning") && partState(part) === "streaming") return {
180
+ ...part,
181
+ state: "done"
182
+ };
183
+ return part;
184
+ });
185
+ return replaceLast(conversation, withParts(lastMessage, nextParts));
1202
186
  };
1203
- const EntityTriggerClass = tailwindMerge.twMerge(
1204
- "mastra:aria-disabled:cursor-not-allowed mastra:aria-disabled:bg-surface5 mastra:aria-disabled:text-text3",
1205
- "mastra:aria-expanded:rounded-b-none mastra:aria-expanded:border-b-0",
1206
- "mastra:bg-surface3 mastra:text-text6 mastra:hover:bg-surface4 mastra:active:bg-surface5",
1207
- "mastra:rounded-lg mastra:py-2 mastra:px-4 mastra:border mastra:border-border1",
1208
- "mastra:cursor-pointer mastra:inline-flex mastra:items-center mastra:gap-1 mastra:font-mono"
1209
- );
1210
- const EntityTriggerVariantClasses = {
1211
- agent: "mastra:[&_svg.mastra-icon]:text-accent1",
1212
- workflow: "mastra:[&_svg.mastra-icon]:text-accent3",
1213
- tool: "mastra:[&_svg.mastra-icon]:text-accent6",
1214
- memory: "mastra:[&_svg.mastra-icon]:text-accent2",
1215
- initial: "mastra:[&_svg.mastra-icon]:text-text3"
187
+ /**
188
+ * Locate the assistant message + tool part owning `toolCallId`. Prefers the
189
+ * most recent assistant message and walks back up to 10 messages, matching the
190
+ * historical accumulator's lookup behavior.
191
+ */
192
+ const locateToolPart = (messages, toolCallId, allowMetadataOnlyMatch) => {
193
+ const findIndex = (parts) => parts.findIndex((part) => isToolPart(part) && part.toolInvocation.toolCallId === toolCallId);
194
+ const lastMessage = messages[messages.length - 1];
195
+ if (lastMessage && lastMessage.role === "assistant") {
196
+ const idx = findIndex(lastMessage.content.parts);
197
+ if (idx !== -1) return {
198
+ messageIndex: messages.length - 1,
199
+ toolPartIndex: idx
200
+ };
201
+ }
202
+ let count = 0;
203
+ const maxMessagesBack = 10;
204
+ for (let i = messages.length - 1; i >= 0; i--) {
205
+ if (count > maxMessagesBack) break;
206
+ const message = messages[i];
207
+ if (message.role !== "assistant") continue;
208
+ const idx = findIndex(message.content.parts);
209
+ if (idx !== -1) return {
210
+ messageIndex: i,
211
+ toolPartIndex: idx
212
+ };
213
+ count++;
214
+ }
215
+ if (!allowMetadataOnlyMatch) return null;
216
+ for (let i = messages.length - 1; i >= 0; i--) if (messages[i].role === "assistant") return {
217
+ messageIndex: i,
218
+ toolPartIndex: -1
219
+ };
220
+ return null;
1216
221
  };
1217
- const EntityTrigger = ({ className, children, ...props }) => {
1218
- const { expanded, setExpanded, variant, disabled } = useEntity();
1219
- const handleClick = (e) => {
1220
- if (disabled) return;
1221
- setExpanded(!expanded);
1222
- props?.onClick?.(e);
1223
- };
1224
- return /* @__PURE__ */ jsxRuntime.jsx(
1225
- "button",
1226
- {
1227
- className: className || tailwindMerge.twMerge(EntityTriggerClass, !disabled && EntityTriggerVariantClasses[variant]),
1228
- ...props,
1229
- onClick: handleClick,
1230
- "aria-expanded": expanded,
1231
- "aria-disabled": disabled,
1232
- children
1233
- }
1234
- );
222
+ /**
223
+ * Merge per-toolCallId background-task bookkeeping onto message metadata.
224
+ */
225
+ const mergeBgTaskMetadata = (existing, mode, args, otherMetadata) => {
226
+ const base = cloneMetadata(existing);
227
+ const existingBgTasks = base.backgroundTasks ?? {};
228
+ const nextBgTasks = { ...existingBgTasks };
229
+ if (args.perTaskEntry) {
230
+ const { toolCallId, startedAt, completedAt, taskId, suspendedAt } = args.perTaskEntry;
231
+ nextBgTasks[toolCallId] = {
232
+ ...existingBgTasks[toolCallId] ?? { taskId },
233
+ taskId,
234
+ ...startedAt !== void 0 ? { startedAt } : {},
235
+ ...completedAt !== void 0 ? { completedAt } : {},
236
+ ...suspendedAt !== void 0 ? { suspendedAt } : {}
237
+ };
238
+ }
239
+ const merged = {
240
+ ...base,
241
+ ...otherMetadata ?? {},
242
+ mode,
243
+ backgroundTasks: nextBgTasks
244
+ };
245
+ if (args.resetRunningCount) merged.runningBackgroundTasksCount = void 0;
246
+ return merged;
1235
247
  };
1236
- const EntityContentClass = tailwindMerge.twMerge(
1237
- "mastra:space-y-4",
1238
- "mastra:rounded-lg mastra:rounded-tl-none mastra:p-4 mastra:border mastra:border-border1 mastra:-mt-[0.5px]",
1239
- "mastra:bg-surface3 mastra:text-text6"
1240
- );
1241
- const EntityContent = ({ className, ...props }) => {
1242
- const { expanded } = useEntity();
1243
- if (!expanded) return null;
1244
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className || EntityContentClass, ...props });
248
+ /**
249
+ * Workflow chunk accumulation. Mirrors
250
+ * `mapWorkflowStreamChunkToWatchResult` from the previous accumulator.
251
+ */
252
+ const mapWorkflowStreamChunkToWatchResult = (prev, chunk) => {
253
+ if (chunk.type === "workflow-start") return {
254
+ input: prev?.input,
255
+ status: "running",
256
+ steps: prev?.steps || {}
257
+ };
258
+ if (chunk.type === "workflow-canceled") return {
259
+ ...prev,
260
+ status: "canceled"
261
+ };
262
+ if (chunk.type === "workflow-finish") {
263
+ const finalStatus = chunk.payload.workflowStatus;
264
+ const prevSteps = prev?.steps ?? {};
265
+ const lastStep = Object.values(prevSteps).pop();
266
+ return {
267
+ ...prev,
268
+ status: chunk.payload.workflowStatus,
269
+ ...finalStatus === "success" && lastStep?.status === "success" ? { result: lastStep?.output } : finalStatus === "failed" && lastStep?.status === "failed" ? { error: lastStep?.error } : finalStatus === "tripwire" && chunk.payload.tripwire ? { tripwire: chunk.payload.tripwire } : {}
270
+ };
271
+ }
272
+ const { stepCallId: _stepCallId, stepName: _stepName, ...newPayload } = chunk.payload ?? {};
273
+ const newSteps = {
274
+ ...prev?.steps,
275
+ [chunk.payload.id]: {
276
+ ...prev?.steps?.[chunk.payload.id],
277
+ ...newPayload
278
+ }
279
+ };
280
+ if (chunk.type === "workflow-step-start") return {
281
+ ...prev,
282
+ steps: newSteps
283
+ };
284
+ if (chunk.type === "workflow-step-suspended") {
285
+ const suspendedStepIds = Object.entries(newSteps).flatMap(([stepId, stepResult]) => {
286
+ if (stepResult?.status === "suspended") {
287
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
288
+ return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
289
+ }
290
+ return [];
291
+ });
292
+ return {
293
+ ...prev,
294
+ status: "suspended",
295
+ steps: newSteps,
296
+ suspendPayload: chunk.payload.suspendPayload,
297
+ suspended: suspendedStepIds
298
+ };
299
+ }
300
+ if (chunk.type === "workflow-step-waiting") return {
301
+ ...prev,
302
+ status: "waiting",
303
+ steps: newSteps
304
+ };
305
+ if (chunk.type === "workflow-step-progress") return {
306
+ ...prev,
307
+ steps: {
308
+ ...prev?.steps,
309
+ [chunk.payload.id]: {
310
+ ...prev?.steps?.[chunk.payload.id],
311
+ foreachProgress: {
312
+ completedCount: chunk.payload.completedCount,
313
+ totalCount: chunk.payload.totalCount,
314
+ currentIndex: chunk.payload.currentIndex,
315
+ iterationStatus: chunk.payload.iterationStatus,
316
+ iterationOutput: chunk.payload.iterationOutput
317
+ }
318
+ }
319
+ }
320
+ };
321
+ if (chunk.type === "workflow-step-result") return {
322
+ ...prev,
323
+ steps: newSteps
324
+ };
325
+ return prev;
1245
326
  };
1246
- const EntityCaret = ({ className, ...props }) => {
1247
- const { expanded } = useEntity();
1248
- return /* @__PURE__ */ jsxRuntime.jsx(Icon, { children: /* @__PURE__ */ jsxRuntime.jsx(
1249
- lucideReact.ChevronDownIcon,
1250
- {
1251
- className: tailwindMerge.twMerge(
1252
- `mastra:text-text3 mastra:transition-transform mastra:duration-200 mastra:ease-in-out`,
1253
- expanded ? "mastra:rotate-0" : "mastra:-rotate-90",
1254
- className
1255
- ),
1256
- ...props
1257
- }
1258
- ) });
327
+ const signalContentsToUserMessages = (contents, metadata) => {
328
+ const makeUserMessage = (parts) => ({
329
+ id: `signal-${Date.now()}`,
330
+ role: "user",
331
+ createdAt: /* @__PURE__ */ new Date(),
332
+ content: {
333
+ format: 2,
334
+ parts,
335
+ metadata: cloneMetadata(metadata)
336
+ }
337
+ });
338
+ const toMessagePart = (part) => {
339
+ if (!part || typeof part !== "object") return [];
340
+ const typedPart = part;
341
+ if (typedPart.type === "text" && typeof typedPart.text === "string") return [{
342
+ type: "text",
343
+ text: typedPart.text
344
+ }];
345
+ if (typedPart.type === "image") {
346
+ const image = typedPart.image;
347
+ const mimeType = typeof typedPart.mediaType === "string" ? typedPart.mediaType : typeof typedPart.mimeType === "string" ? typedPart.mimeType : "image/*";
348
+ if (typeof image === "string" || image instanceof URL || image instanceof ArrayBuffer || image instanceof Uint8Array) return [{
349
+ type: "file",
350
+ mimeType,
351
+ data: encodeFilePartDataForStorage(image, mimeType)
352
+ }];
353
+ return [{
354
+ type: "file",
355
+ mimeType,
356
+ data: ""
357
+ }];
358
+ }
359
+ if (typedPart.type === "file") {
360
+ const data = typedPart.data;
361
+ const mimeType = typeof typedPart.mediaType === "string" ? typedPart.mediaType : typeof typedPart.mimeType === "string" ? typedPart.mimeType : "application/octet-stream";
362
+ if (typeof data === "string" || data instanceof URL || data instanceof ArrayBuffer || data instanceof Uint8Array) return [{
363
+ type: "file",
364
+ mimeType,
365
+ data: encodeFilePartDataForStorage(data, mimeType),
366
+ ...typeof typedPart.filename === "string" ? { filename: typedPart.filename } : {}
367
+ }];
368
+ return [{
369
+ type: "file",
370
+ mimeType,
371
+ data: typeof typedPart.url === "string" ? typedPart.url : "",
372
+ ...typeof typedPart.filename === "string" ? { filename: typedPart.filename } : {}
373
+ }];
374
+ }
375
+ return [];
376
+ };
377
+ if (typeof contents === "string") return [makeUserMessage([{
378
+ type: "text",
379
+ text: contents
380
+ }])];
381
+ if (Array.isArray(contents)) {
382
+ const parts = contents.flatMap(toMessagePart);
383
+ return parts.length ? [makeUserMessage(parts)] : contents.flatMap((content) => signalContentsToUserMessages(content, metadata));
384
+ }
385
+ if (!contents || typeof contents !== "object") return [];
386
+ const message = contents;
387
+ if (message.role && message.role !== "user") return [];
388
+ const content = message.content;
389
+ if (typeof content === "string") return [makeUserMessage([{
390
+ type: "text",
391
+ text: content
392
+ }])];
393
+ if (!Array.isArray(content)) return [];
394
+ const parts = content.flatMap(toMessagePart);
395
+ return parts.length ? [makeUserMessage(parts)] : [];
1259
396
  };
1260
-
1261
- const ToolApprovalClass = tailwindMerge.twMerge(
1262
- "mastra:rounded-lg mastra:border mastra:border-border1 mastra:max-w-1/2 mastra:mt-2",
1263
- "mastra:bg-surface3 mastra:text-text6"
1264
- );
1265
- const ToolApproval = ({ className, ...props }) => {
1266
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className || ToolApprovalClass, ...props });
397
+ const reconcilePendingUserEcho = (message, echoedContents, metadata, options) => {
398
+ const echoedParts = signalContentsToUserMessages(echoedContents, metadata)[0]?.content.parts;
399
+ let reconciled = typeof options.signalId === "string" ? {
400
+ ...message,
401
+ id: options.signalId
402
+ } : message;
403
+ if (echoedParts?.length) reconciled = {
404
+ ...reconciled,
405
+ content: {
406
+ ...reconciled.content,
407
+ parts: echoedParts
408
+ }
409
+ };
410
+ return options.keepClientMessageId ? clearPendingStatusKeepClientId(reconciled) : clearPendingStatus(reconciled);
1267
411
  };
1268
- const ToolApprovalTitleClass = tailwindMerge.twMerge("mastra:text-text6 mastra:inline-flex mastra:items-center mastra:gap-1");
1269
- const ToolApprovalTitle = ({ className, ...props }) => {
1270
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className || ToolApprovalTitleClass, ...props });
412
+ const makeToolInvocationPart = (invocation) => ({
413
+ type: "tool-invocation",
414
+ toolInvocation: invocation
415
+ });
416
+ /**
417
+ * Narrow the chunk to the template-literal passthrough variants from
418
+ * `NetworkChunkType`. Encoded as a type guard so the surrounding `switch`
419
+ * statement can stay exhaustive over the remaining string-literal cases.
420
+ */
421
+ const isTemplateLiteralPassthrough = (chunk) => chunk.type.startsWith("agent-execution-event-") || chunk.type.startsWith("workflow-execution-event-");
422
+ /**
423
+ * Narrow the chunk to the `data-${string}` family. Used so the trailing
424
+ * exhaustiveness check can prove the switch covers every remaining variant.
425
+ */
426
+ const isDataChunk$2 = (chunk) => chunk.type.startsWith("data-");
427
+ /**
428
+ * Reduce a single stream chunk into the running `MastraDBMessage[]`
429
+ * conversation. The accumulator owns the entire chunk→DB mapping for the
430
+ * React SDK; consumers downstream (e.g. `toAISdkV5Messages` in the playground)
431
+ * translate the result into AI SDK / assistant-ui shapes as needed.
432
+ */
433
+ const accumulateChunk = ({ chunk, conversation, metadata }) => {
434
+ const result = [...conversation];
435
+ if (isTemplateLiteralPassthrough(chunk)) return result;
436
+ if (isDataChunk$2(chunk)) {
437
+ if (chunk.type === "data-user-message" && "data" in chunk && (chunk.data?.type === "user-message" || chunk.data?.type === "user")) {
438
+ const signalId = chunk.data.id;
439
+ const echoedClientMessageId = chunk.data?.metadata?.[CLIENT_MESSAGE_ID_KEY];
440
+ if (typeof echoedClientMessageId === "string" && result.some((message) => message.content.metadata?.status === "pending" && message.content.metadata["clientMessageId"] === echoedClientMessageId)) return finishStreamingAssistantMessage(result.map((message) => message.content.metadata?.status === "pending" && message.content.metadata["clientMessageId"] === echoedClientMessageId ? reconcilePendingUserEcho(message, chunk.data.contents, metadata, {
441
+ signalId: typeof signalId === "string" ? signalId : void 0,
442
+ keepClientMessageId: true
443
+ }) : message));
444
+ if (typeof signalId === "string" && result.some((message) => message.id === signalId)) return finishStreamingAssistantMessage(result.map((message) => message.id === signalId && message.content.metadata?.status === "pending" ? reconcilePendingUserEcho(message, chunk.data.contents, metadata, { keepClientMessageId: false }) : message));
445
+ const userMessages = signalContentsToUserMessages(chunk.data.contents, metadata);
446
+ if (!userMessages.length) return result;
447
+ const conversationWithFinishedAssistant = finishStreamingAssistantMessage(result);
448
+ const messageIdPrefix = typeof signalId === "string" ? signalId : `signal-${chunk.runId}-${Date.now()}`;
449
+ return [...conversationWithFinishedAssistant, ...userMessages.map((message, index) => ({
450
+ ...message,
451
+ id: index === 0 ? messageIdPrefix : `${messageIdPrefix}-${index}`
452
+ }))];
453
+ }
454
+ const dataPart = {
455
+ type: chunk.type,
456
+ data: "data" in chunk ? chunk.data : void 0,
457
+ ..."id" in chunk && typeof chunk.id === "string" ? { id: chunk.id } : {}
458
+ };
459
+ const lastMessage = result[result.length - 1];
460
+ if (!lastMessage || lastMessage.role !== "assistant") return appendAssistantMessage(result, `data-${chunk.runId}-${Date.now()}`, [dataPart], metadata);
461
+ return replaceLast(result, withParts(lastMessage, [...lastMessage.content.parts, dataPart]));
462
+ }
463
+ switch (chunk.type) {
464
+ case "tripwire": {
465
+ const newMessage = newAssistantMessage(`tripwire-${chunk.runId + Date.now()}`, [{
466
+ type: "text",
467
+ text: chunk.payload.reason
468
+ }], {
469
+ ...metadata,
470
+ status: "tripwire",
471
+ tripwire: {
472
+ reason: chunk.payload.reason,
473
+ retry: chunk.payload.retry,
474
+ metadata: chunk.payload.metadata,
475
+ processorId: chunk.payload.processorId
476
+ }
477
+ });
478
+ return [...result, newMessage];
479
+ }
480
+ case "start": {
481
+ const messageId = typeof chunk.payload.messageId === "string" ? chunk.payload.messageId : void 0;
482
+ if (messageId && result.some((message) => message.id === messageId)) return result;
483
+ return [...result, newAssistantMessage(messageId ?? `start-${chunk.runId + Date.now()}`, [], metadata)];
484
+ }
485
+ case "text-start": {
486
+ const lastMessage = result[result.length - 1];
487
+ const textId = chunk.payload.id || `text-${Date.now()}`;
488
+ const tailPart = lastMessage?.content.parts[lastMessage.content.parts.length - 1];
489
+ if (chunk.payload.id && lastMessage?.role === "assistant" && tailPart?.type === "text" && partTextId(tailPart) === textId) return result;
490
+ const newTextPart = {
491
+ type: "text",
492
+ text: "",
493
+ state: "streaming",
494
+ textId,
495
+ providerMetadata: chunk.payload.providerMetadata
496
+ };
497
+ if (!lastMessage || lastMessage.role !== "assistant") return appendAssistantMessage(result, `start-${chunk.runId}-${Date.now()}`, [newTextPart], metadata);
498
+ if (lastMessage.content.metadata?.completionResult) return appendAssistantMessage(result, `start-${chunk.runId}-${Date.now()}`, [newTextPart], metadata);
499
+ return replaceLast(result, withParts(lastMessage, [...lastMessage.content.parts, newTextPart]));
500
+ }
501
+ case "background-task-progress": {
502
+ const lastMessage = result[result.length - 1];
503
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
504
+ return replaceLast(result, withMetadata(lastMessage, {
505
+ mode: metadata.mode,
506
+ ...lastMessage.content.metadata,
507
+ runningBackgroundTasksCount: chunk.payload.runningCount
508
+ }));
509
+ }
510
+ case "text-delta": {
511
+ const lastMessage = result[result.length - 1];
512
+ const textId = chunk.payload.id;
513
+ if (!lastMessage || lastMessage.role !== "assistant") {
514
+ const newTextPart = {
515
+ type: "text",
516
+ text: chunk.payload.text,
517
+ state: "streaming",
518
+ textId,
519
+ providerMetadata: chunk.payload.providerMetadata
520
+ };
521
+ return appendAssistantMessage(result, `text-${chunk.runId}-${Date.now()}`, [newTextPart], metadata);
522
+ }
523
+ const parts = [...lastMessage.content.parts];
524
+ let textPartIndex = textId ? parts.findLastIndex((part) => part.type === "text" && partTextId(part) === textId) : -1;
525
+ if (textPartIndex === -1) textPartIndex = parts.findLastIndex((part) => part.type === "text" && partState(part) === "streaming");
526
+ if (textPartIndex !== -1 && parts.some((part, index) => index > textPartIndex && part.type !== "text")) textPartIndex = -1;
527
+ if (textPartIndex === -1) {
528
+ const newTextPart = {
529
+ type: "text",
530
+ text: chunk.payload.text,
531
+ state: "streaming",
532
+ textId,
533
+ providerMetadata: chunk.payload.providerMetadata
534
+ };
535
+ parts.push(newTextPart);
536
+ } else {
537
+ const textPart = parts[textPartIndex];
538
+ parts[textPartIndex] = {
539
+ ...textPart,
540
+ text: textPart.text + chunk.payload.text,
541
+ state: "streaming"
542
+ };
543
+ }
544
+ return replaceLast(result, withParts(lastMessage, parts));
545
+ }
546
+ case "text-end": return result;
547
+ case "reasoning-start": {
548
+ const lastMessage = result[result.length - 1];
549
+ const newReasoningPart = {
550
+ type: "reasoning",
551
+ reasoning: "",
552
+ state: "streaming",
553
+ providerMetadata: chunk.payload.providerMetadata
554
+ };
555
+ if (!lastMessage || lastMessage.role !== "assistant") return appendAssistantMessage(result, `reasoning-${chunk.runId + Date.now()}`, [newReasoningPart], metadata);
556
+ return replaceLast(result, withParts(lastMessage, [...lastMessage.content.parts, newReasoningPart]));
557
+ }
558
+ case "reasoning-delta": {
559
+ const lastMessage = result[result.length - 1];
560
+ if (!lastMessage || lastMessage.role !== "assistant") {
561
+ const newReasoningPart = {
562
+ type: "reasoning",
563
+ reasoning: chunk.payload.text,
564
+ state: "streaming",
565
+ providerMetadata: chunk.payload.providerMetadata
566
+ };
567
+ return appendAssistantMessage(result, `reasoning-${chunk.runId + Date.now()}`, [newReasoningPart], metadata);
568
+ }
569
+ const parts = [...lastMessage.content.parts];
570
+ const lastIndex = parts.length - 1;
571
+ const lastPart = parts[lastIndex];
572
+ if (lastPart?.type === "reasoning") {
573
+ const reasoningPart = lastPart;
574
+ parts[lastIndex] = {
575
+ ...reasoningPart,
576
+ reasoning: reasoningPart.reasoning + chunk.payload.text,
577
+ state: "streaming"
578
+ };
579
+ } else {
580
+ const newReasoningPart = {
581
+ type: "reasoning",
582
+ reasoning: chunk.payload.text,
583
+ state: "streaming",
584
+ providerMetadata: chunk.payload.providerMetadata
585
+ };
586
+ parts.push(newReasoningPart);
587
+ }
588
+ return replaceLast(result, withParts(lastMessage, parts));
589
+ }
590
+ case "reasoning-end": {
591
+ const lastMessage = result[result.length - 1];
592
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
593
+ const parts = [...lastMessage.content.parts];
594
+ const reasoningIndex = parts.findLastIndex((part) => part.type === "reasoning" && partState(part) === "streaming");
595
+ if (reasoningIndex === -1) return result;
596
+ const reasoningPart = parts[reasoningIndex];
597
+ const existingMeta = reasoningPart.providerMetadata;
598
+ const endMeta = chunk.payload.providerMetadata;
599
+ parts[reasoningIndex] = {
600
+ ...reasoningPart,
601
+ state: "done",
602
+ ...existingMeta || endMeta ? { providerMetadata: {
603
+ ...existingMeta ?? {},
604
+ ...endMeta ?? {}
605
+ } } : {}
606
+ };
607
+ return replaceLast(result, withParts(lastMessage, parts));
608
+ }
609
+ case "reasoning-signature": {
610
+ const lastMessage = result[result.length - 1];
611
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
612
+ const parts = [...lastMessage.content.parts];
613
+ const reasoningIndex = parts.findLastIndex((part) => part.type === "reasoning");
614
+ if (reasoningIndex === -1) return result;
615
+ const reasoningPart = parts[reasoningIndex];
616
+ const existingMeta = reasoningPart.providerMetadata;
617
+ const sigMeta = chunk.payload.providerMetadata;
618
+ parts[reasoningIndex] = {
619
+ ...reasoningPart,
620
+ ...existingMeta || sigMeta ? { providerMetadata: {
621
+ ...existingMeta ?? {},
622
+ ...sigMeta ?? {}
623
+ } } : {}
624
+ };
625
+ return replaceLast(result, withParts(lastMessage, parts));
626
+ }
627
+ case "redacted-reasoning": {
628
+ const lastMessage = result[result.length - 1];
629
+ const redactedData = chunk.payload.data;
630
+ const redactedPart = {
631
+ type: "reasoning",
632
+ reasoning: typeof redactedData === "string" ? redactedData : "",
633
+ state: "done",
634
+ redacted: true,
635
+ providerMetadata: chunk.payload.providerMetadata
636
+ };
637
+ if (!lastMessage || lastMessage.role !== "assistant") return appendAssistantMessage(result, `redacted-reasoning-${chunk.runId + Date.now()}`, [redactedPart], metadata);
638
+ return replaceLast(result, withParts(lastMessage, [...lastMessage.content.parts, redactedPart]));
639
+ }
640
+ case "tool-call": {
641
+ const invocation = {
642
+ state: "call",
643
+ toolCallId: chunk.payload.toolCallId,
644
+ toolName: chunk.payload.toolName,
645
+ args: chunk.payload.args
646
+ };
647
+ const newPart = {
648
+ ...makeToolInvocationPart(invocation),
649
+ providerMetadata: chunk.payload.providerMetadata
650
+ };
651
+ const existing = locateToolPart(result, chunk.payload.toolCallId, false);
652
+ if (existing && existing.toolPartIndex >= 0) {
653
+ const { messageIndex, toolPartIndex } = existing;
654
+ const targetMessage = result[messageIndex];
655
+ if (targetMessage && targetMessage.role === "assistant") {
656
+ const parts = [...targetMessage.content.parts];
657
+ const prev = parts[toolPartIndex];
658
+ if (isToolPart(prev)) {
659
+ const { argsText: _argsText, ...rest } = prev;
660
+ parts[toolPartIndex] = {
661
+ ...rest,
662
+ toolInvocation: {
663
+ ...prev.toolInvocation,
664
+ state: "call",
665
+ toolName: chunk.payload.toolName,
666
+ toolCallId: chunk.payload.toolCallId,
667
+ args: chunk.payload.args
668
+ },
669
+ providerMetadata: chunk.payload.providerMetadata ?? prev.providerMetadata
670
+ };
671
+ return replaceAt(result, messageIndex, withParts(targetMessage, parts));
672
+ }
673
+ }
674
+ }
675
+ const lastMessage = result[result.length - 1];
676
+ if (!lastMessage || lastMessage.role !== "assistant") return appendAssistantMessage(result, `tool-call-${chunk.runId + Date.now()}`, [newPart], metadata);
677
+ return replaceLast(result, withParts(lastMessage, [...lastMessage.content.parts, newPart]));
678
+ }
679
+ case "tool-call-input-streaming-start": {
680
+ const lastMessage = result[result.length - 1];
681
+ const invocation = {
682
+ state: "partial-call",
683
+ toolCallId: chunk.payload.toolCallId,
684
+ toolName: chunk.payload.toolName,
685
+ args: {}
686
+ };
687
+ const newPart = {
688
+ ...makeToolInvocationPart(invocation),
689
+ argsText: ""
690
+ };
691
+ if (!lastMessage || lastMessage.role !== "assistant") return appendAssistantMessage(result, `tool-call-streaming-${chunk.runId + Date.now()}`, [newPart], metadata);
692
+ return replaceLast(result, withParts(lastMessage, [...lastMessage.content.parts, newPart]));
693
+ }
694
+ case "tool-call-delta": {
695
+ const location = locateToolPart(result, chunk.payload.toolCallId, false);
696
+ if (!location || location.toolPartIndex < 0) return result;
697
+ const { messageIndex, toolPartIndex } = location;
698
+ const targetMessage = result[messageIndex];
699
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
700
+ const parts = [...targetMessage.content.parts];
701
+ const toolPart = parts[toolPartIndex];
702
+ if (!isToolPart(toolPart)) return result;
703
+ const nextArgsText = (toolPart.argsText ?? "") + (chunk.payload.argsTextDelta ?? "");
704
+ parts[toolPartIndex] = {
705
+ ...toolPart,
706
+ argsText: nextArgsText,
707
+ toolInvocation: {
708
+ ...toolPart.toolInvocation,
709
+ state: "partial-call"
710
+ }
711
+ };
712
+ return replaceAt(result, messageIndex, withParts(targetMessage, parts));
713
+ }
714
+ case "tool-call-input-streaming-end": {
715
+ const location = locateToolPart(result, chunk.payload.toolCallId, false);
716
+ if (!location || location.toolPartIndex < 0) return result;
717
+ const { messageIndex, toolPartIndex } = location;
718
+ const targetMessage = result[messageIndex];
719
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
720
+ const parts = [...targetMessage.content.parts];
721
+ const toolPart = parts[toolPartIndex];
722
+ if (!isToolPart(toolPart)) return result;
723
+ let parsedArgs = {};
724
+ const argsText = toolPart.argsText;
725
+ if (typeof argsText === "string" && argsText.length > 0) try {
726
+ const maybe = JSON.parse(argsText);
727
+ if (maybe && typeof maybe === "object" && !Array.isArray(maybe)) parsedArgs = maybe;
728
+ } catch {
729
+ parsedArgs = {};
730
+ }
731
+ parts[toolPartIndex] = {
732
+ ...toolPart,
733
+ toolInvocation: {
734
+ ...toolPart.toolInvocation,
735
+ state: "call",
736
+ args: parsedArgs
737
+ }
738
+ };
739
+ return replaceAt(result, messageIndex, withParts(targetMessage, parts));
740
+ }
741
+ case "tool-output-denied": {
742
+ const location = locateToolPart(result, chunk.payload.toolCallId, false);
743
+ if (!location || location.toolPartIndex < 0) return result;
744
+ const { messageIndex, toolPartIndex } = location;
745
+ const targetMessage = result[messageIndex];
746
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
747
+ const parts = [...targetMessage.content.parts];
748
+ const toolPart = parts[toolPartIndex];
749
+ if (!isToolPart(toolPart)) return result;
750
+ parts[toolPartIndex] = {
751
+ ...toolPart,
752
+ toolInvocation: {
753
+ ...toolPart.toolInvocation,
754
+ state: "output-denied",
755
+ toolName: chunk.payload.toolName,
756
+ args: chunk.payload.args ?? toolPart.toolInvocation.args,
757
+ approval: chunk.payload.approval
758
+ }
759
+ };
760
+ return replaceAt(result, messageIndex, withParts(targetMessage, parts));
761
+ }
762
+ case "tool-error":
763
+ case "tool-result":
764
+ case "background-task-completed":
765
+ case "background-task-failed": {
766
+ const isBgTaskEvent = chunk.type === "background-task-completed" || chunk.type === "background-task-failed";
767
+ const location = locateToolPart(result, chunk.payload.toolCallId, isBgTaskEvent);
768
+ if (!location) return result;
769
+ const { messageIndex, toolPartIndex } = location;
770
+ const targetMessage = result[messageIndex];
771
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
772
+ const parts = [...targetMessage.content.parts];
773
+ const toolPart = toolPartIndex >= 0 ? parts[toolPartIndex] : void 0;
774
+ let payloadResult;
775
+ let payloadError;
776
+ let payloadIsError = false;
777
+ let payloadProviderMetadata;
778
+ let payloadCompletedAt;
779
+ let payloadTaskId;
780
+ switch (chunk.type) {
781
+ case "tool-result":
782
+ payloadResult = chunk.payload.result;
783
+ payloadIsError = Boolean(chunk.payload.isError);
784
+ payloadProviderMetadata = chunk.payload.providerMetadata;
785
+ break;
786
+ case "tool-error":
787
+ payloadError = chunk.payload.error;
788
+ payloadProviderMetadata = chunk.payload.providerMetadata;
789
+ break;
790
+ case "background-task-completed":
791
+ payloadResult = chunk.payload.result;
792
+ payloadCompletedAt = chunk.payload.completedAt;
793
+ payloadTaskId = chunk.payload.taskId;
794
+ break;
795
+ case "background-task-failed":
796
+ payloadError = chunk.payload.error;
797
+ payloadCompletedAt = chunk.payload.completedAt;
798
+ payloadTaskId = chunk.payload.taskId;
799
+ break;
800
+ }
801
+ if (toolPart && isToolPart(toolPart)) {
802
+ const { toolName, toolCallId, args } = toolPart.toolInvocation;
803
+ const providerMeta = payloadProviderMetadata ?? toolPart.providerMetadata;
804
+ if (chunk.type === "tool-error" || chunk.type === "background-task-failed" || payloadIsError) {
805
+ const error = chunk.type === "tool-error" || chunk.type === "background-task-failed" ? payloadError : payloadResult;
806
+ const errorText = typeof error === "string" ? error : error instanceof Error ? error.message : error?.message ?? String(error);
807
+ parts[toolPartIndex] = {
808
+ ...toolPart,
809
+ providerMetadata: providerMeta,
810
+ toolInvocation: {
811
+ state: "output-error",
812
+ toolCallId,
813
+ toolName,
814
+ args,
815
+ errorText
816
+ }
817
+ };
818
+ } else {
819
+ const resultObj = payloadResult;
820
+ const existingResult = toolPart.toolInvocation.state === "partial-call" || toolPart.toolInvocation.state === "result" ? toolPart.toolInvocation.result : void 0;
821
+ const existingLooksLikeWorkflow = Boolean(existingResult && typeof existingResult === "object" && "steps" in existingResult);
822
+ const isWorkflow = Boolean(resultObj?.result?.steps) || toolName?.startsWith("workflow-") || existingLooksLikeWorkflow;
823
+ const isAgent = chunk.from === "AGENT";
824
+ let output;
825
+ if (isWorkflow) {
826
+ const accumulated = existingLooksLikeWorkflow && existingResult && typeof existingResult === "object" ? existingResult : void 0;
827
+ const payloadWorkflow = resultObj?.result && typeof resultObj.result === "object" ? resultObj.result : void 0;
828
+ if (accumulated || payloadWorkflow) output = {
829
+ ...accumulated ?? {},
830
+ ...payloadWorkflow ?? {},
831
+ steps: payloadWorkflow?.steps ?? accumulated?.steps ?? [],
832
+ status: payloadWorkflow?.status ?? accumulated?.status ?? "success",
833
+ output: payloadResult
834
+ };
835
+ else output = payloadResult;
836
+ } else if (isAgent) {
837
+ const existingOutput = toolPart.toolInvocation.state === "result" ? toolPart.toolInvocation.result : void 0;
838
+ const existingChild = existingOutput?.childMessages;
839
+ output = existingOutput ? {
840
+ ...payloadResult,
841
+ childMessages: existingChild?.length ? existingChild : resultObj?.childMessages
842
+ } : payloadResult;
843
+ } else output = payloadResult;
844
+ parts[toolPartIndex] = {
845
+ ...toolPart,
846
+ providerMetadata: providerMeta,
847
+ toolInvocation: {
848
+ state: "result",
849
+ toolCallId,
850
+ toolName,
851
+ args,
852
+ result: output
853
+ }
854
+ };
855
+ }
856
+ }
857
+ const nextMetadata = mergeBgTaskMetadata(targetMessage.content.metadata, metadata.mode, {
858
+ resetRunningCount: isBgTaskEvent,
859
+ perTaskEntry: isBgTaskEvent && payloadTaskId ? {
860
+ toolCallId: chunk.payload.toolCallId,
861
+ completedAt: payloadCompletedAt,
862
+ taskId: payloadTaskId
863
+ } : void 0
864
+ });
865
+ const nextMessage = {
866
+ ...targetMessage,
867
+ content: {
868
+ ...targetMessage.content,
869
+ parts,
870
+ metadata: nextMetadata
871
+ }
872
+ };
873
+ return replaceAt(result, messageIndex, nextMessage);
874
+ }
875
+ case "background-task-running": {
876
+ const location = locateToolPart(result, chunk.payload.toolCallId, true);
877
+ if (!location) return result;
878
+ const { messageIndex } = location;
879
+ const targetMessage = result[messageIndex];
880
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
881
+ const nextMetadata = mergeBgTaskMetadata(targetMessage.content.metadata, metadata.mode, { perTaskEntry: {
882
+ toolCallId: chunk.payload.toolCallId,
883
+ startedAt: chunk.payload.startedAt,
884
+ taskId: chunk.payload.taskId
885
+ } });
886
+ return replaceAt(result, messageIndex, withMetadata(targetMessage, nextMetadata));
887
+ }
888
+ case "tool-output":
889
+ case "background-task-output": {
890
+ const isBgTaskOutput = chunk.type === "background-task-output";
891
+ const location = locateToolPart(result, chunk.payload.toolCallId, isBgTaskOutput);
892
+ if (!location || location.toolPartIndex < 0) return result;
893
+ const { messageIndex, toolPartIndex } = location;
894
+ const targetMessage = result[messageIndex];
895
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
896
+ const parts = [...targetMessage.content.parts];
897
+ const toolPart = parts[toolPartIndex];
898
+ if (!isToolPart(toolPart)) return result;
899
+ const { toolName, toolCallId, args } = toolPart.toolInvocation;
900
+ const payloadOutput = chunk.type === "background-task-output" ? chunk.payload.payload.payload.output : chunk.payload.output;
901
+ if (payloadOutput?.type?.startsWith("workflow-")) {
902
+ const existingWorkflowState = toolPart.toolInvocation.result || {};
903
+ const updated = mapWorkflowStreamChunkToWatchResult(existingWorkflowState, payloadOutput);
904
+ parts[toolPartIndex] = {
905
+ ...toolPart,
906
+ toolInvocation: {
907
+ state: "partial-call",
908
+ toolCallId,
909
+ toolName,
910
+ args,
911
+ result: updated
912
+ }
913
+ };
914
+ } else if (payloadOutput?.from === "AGENT" || payloadOutput?.from === "USER" && payloadOutput?.payload?.output?.type?.startsWith("workflow-")) return accumulateAgentChunk(payloadOutput, result, metadata, toolCallId, toolName);
915
+ else {
916
+ const currentResult = toolPart.toolInvocation.result;
917
+ const existing = Array.isArray(currentResult) ? currentResult : [];
918
+ parts[toolPartIndex] = {
919
+ ...toolPart,
920
+ toolInvocation: {
921
+ state: "partial-call",
922
+ toolCallId,
923
+ toolName,
924
+ args,
925
+ result: [...existing, payloadOutput]
926
+ }
927
+ };
928
+ }
929
+ return replaceAt(result, messageIndex, withParts(targetMessage, parts));
930
+ }
931
+ case "is-task-complete": {
932
+ if (chunk.payload.suppressFeedback) return result;
933
+ const feedback = formatStreamCompletionFeedback({
934
+ complete: chunk.payload.passed,
935
+ scorers: chunk.payload.results,
936
+ totalDuration: chunk.payload.duration,
937
+ timedOut: chunk.payload.timedOut,
938
+ completionReason: chunk.payload.reason
939
+ }, chunk.payload.maxIterationReached);
940
+ const newMessage = newAssistantMessage(`is-task-complete-${chunk.runId + Date.now()}`, [{
941
+ type: "text",
942
+ text: feedback
943
+ }], {
944
+ ...metadata,
945
+ completionResult: { passed: chunk.payload.passed }
946
+ });
947
+ return [...result, newMessage];
948
+ }
949
+ case "source": {
950
+ const lastMessage = result[result.length - 1];
951
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
952
+ const parts = [...lastMessage.content.parts];
953
+ if (chunk.payload.sourceType === "url") {
954
+ const sourceUrlPart = {
955
+ type: "source-url",
956
+ sourceId: chunk.payload.id,
957
+ url: chunk.payload.url || "",
958
+ title: chunk.payload.title,
959
+ providerMetadata: chunk.payload.providerMetadata
960
+ };
961
+ parts.push(sourceUrlPart);
962
+ } else if (chunk.payload.sourceType === "document") parts.push({
963
+ type: "source-document",
964
+ sourceId: chunk.payload.id,
965
+ mediaType: chunk.payload.mimeType || "application/octet-stream",
966
+ title: chunk.payload.title,
967
+ filename: chunk.payload.filename,
968
+ providerMetadata: chunk.payload.providerMetadata
969
+ });
970
+ return replaceLast(result, withParts(lastMessage, parts));
971
+ }
972
+ case "file": {
973
+ const lastMessage = result[result.length - 1];
974
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
975
+ const parts = [...lastMessage.content.parts];
976
+ let data;
977
+ if (typeof chunk.payload.data === "string") data = chunk.payload.base64 ? `data:${chunk.payload.mimeType};base64,${chunk.payload.data}` : `data:${chunk.payload.mimeType},${encodeURIComponent(chunk.payload.data)}`;
978
+ else {
979
+ const base64 = uint8ArrayToBase64(chunk.payload.data);
980
+ data = `data:${chunk.payload.mimeType};base64,${base64}`;
981
+ }
982
+ parts.push({
983
+ type: "file",
984
+ mimeType: chunk.payload.mimeType,
985
+ data,
986
+ providerMetadata: chunk.payload.providerMetadata
987
+ });
988
+ return replaceLast(result, withParts(lastMessage, parts));
989
+ }
990
+ case "tool-call-approval": {
991
+ const lastMessage = result[result.length - 1];
992
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
993
+ const existingMeta = lastMessage.content.metadata ?? {};
994
+ const lastRequireApproval = existingMeta.mode === "stream" ? existingMeta.requireApprovalMetadata ?? {} : {};
995
+ return replaceLast(result, {
996
+ ...lastMessage,
997
+ content: {
998
+ ...lastMessage.content,
999
+ metadata: {
1000
+ ...existingMeta,
1001
+ mode: "stream",
1002
+ requireApprovalMetadata: {
1003
+ ...lastRequireApproval,
1004
+ [chunk.payload.toolName]: {
1005
+ toolCallId: chunk.payload.toolCallId,
1006
+ toolName: chunk.payload.toolName,
1007
+ args: chunk.payload.args
1008
+ }
1009
+ }
1010
+ }
1011
+ }
1012
+ });
1013
+ }
1014
+ case "tool-call-suspended":
1015
+ case "background-task-suspended": {
1016
+ const isBgTaskEvent = chunk.type === "background-task-suspended";
1017
+ let suspToolCallId;
1018
+ let suspToolName;
1019
+ let suspArgs;
1020
+ let suspPayload;
1021
+ let suspSuspendedAt;
1022
+ let suspTaskId;
1023
+ if (chunk.type === "background-task-suspended") {
1024
+ suspToolCallId = chunk.payload.toolCallId;
1025
+ suspToolName = chunk.payload.toolName;
1026
+ suspArgs = chunk.payload.args;
1027
+ suspPayload = chunk.payload.suspendPayload;
1028
+ suspSuspendedAt = chunk.payload.suspendedAt;
1029
+ suspTaskId = chunk.payload.taskId;
1030
+ } else {
1031
+ suspToolCallId = chunk.payload.toolCallId;
1032
+ suspToolName = chunk.payload.toolName;
1033
+ suspArgs = chunk.payload.args;
1034
+ suspPayload = chunk.payload.suspendPayload;
1035
+ }
1036
+ const location = isBgTaskEvent ? locateToolPart(result, suspToolCallId, true) : { messageIndex: result.length - 1 };
1037
+ if (!location) return result;
1038
+ const { messageIndex } = location;
1039
+ const targetMessage = result[messageIndex];
1040
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
1041
+ const existingMeta = targetMessage.content.metadata ?? {};
1042
+ const lastSuspendedTools = existingMeta.mode === "stream" ? existingMeta.suspendedTools ?? {} : {};
1043
+ const nextMetadata = mergeBgTaskMetadata(existingMeta, "stream", {
1044
+ resetRunningCount: isBgTaskEvent,
1045
+ perTaskEntry: isBgTaskEvent && suspTaskId ? {
1046
+ toolCallId: suspToolCallId,
1047
+ suspendedAt: suspSuspendedAt,
1048
+ taskId: suspTaskId
1049
+ } : void 0
1050
+ }, { suspendedTools: {
1051
+ ...lastSuspendedTools,
1052
+ [suspToolName]: {
1053
+ toolCallId: suspToolCallId,
1054
+ toolName: suspToolName,
1055
+ args: suspArgs,
1056
+ suspendPayload: suspPayload,
1057
+ runId: chunk.runId
1058
+ }
1059
+ } });
1060
+ return replaceAt(result, messageIndex, withMetadata(targetMessage, nextMetadata));
1061
+ }
1062
+ case "finish":
1063
+ case "abort": return finishStreamingAssistantMessage(result);
1064
+ case "error": {
1065
+ const newMessage = newAssistantMessage(`error-${chunk.runId + Date.now()}`, [{
1066
+ type: "text",
1067
+ text: typeof chunk.payload.error === "string" ? chunk.payload.error : JSON.stringify(chunk.payload.error)
1068
+ }], {
1069
+ ...metadata,
1070
+ status: "error"
1071
+ });
1072
+ return [...result, newMessage];
1073
+ }
1074
+ case "step-start": {
1075
+ const stepMessageId = typeof chunk.payload?.messageId === "string" ? chunk.payload.messageId : void 0;
1076
+ if (!stepMessageId) return result;
1077
+ const lastMessage = result[result.length - 1];
1078
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
1079
+ if (result.some((message) => message.id === stepMessageId)) return result;
1080
+ if (!lastMessage.content.parts.some((part) => !String(part.type).startsWith("data-"))) return replaceLast(result, {
1081
+ ...lastMessage,
1082
+ id: stepMessageId
1083
+ });
1084
+ return appendAssistantMessage(finishStreamingAssistantMessage(result), stepMessageId, [], metadata);
1085
+ }
1086
+ case "step-finish":
1087
+ case "step-output":
1088
+ case "raw":
1089
+ case "watch":
1090
+ case "response-metadata": return result;
1091
+ case "goal": return result;
1092
+ case "object":
1093
+ case "object-result": return result;
1094
+ case "background-task-started":
1095
+ case "background-task-cancelled":
1096
+ case "background-task-resumed": return result;
1097
+ case "workflow-start":
1098
+ case "workflow-finish":
1099
+ case "workflow-canceled":
1100
+ case "workflow-paused":
1101
+ case "workflow-step-start":
1102
+ case "workflow-step-finish":
1103
+ case "workflow-step-suspended":
1104
+ case "workflow-step-waiting":
1105
+ case "workflow-step-output":
1106
+ case "workflow-step-progress":
1107
+ case "workflow-step-result": return result;
1108
+ case "agent-execution-start":
1109
+ case "agent-execution-approval":
1110
+ case "agent-execution-suspended":
1111
+ case "agent-execution-end":
1112
+ case "agent-execution-abort":
1113
+ case "tool-execution-start":
1114
+ case "tool-execution-end":
1115
+ case "tool-execution-approval":
1116
+ case "tool-execution-suspended":
1117
+ case "tool-execution-abort":
1118
+ case "routing-agent-start":
1119
+ case "routing-agent-text-delta":
1120
+ case "routing-agent-text-start":
1121
+ case "routing-agent-end":
1122
+ case "routing-agent-abort":
1123
+ case "workflow-execution-start":
1124
+ case "workflow-execution-end":
1125
+ case "workflow-execution-suspended":
1126
+ case "workflow-execution-abort":
1127
+ case "network-execution-event-step-finish":
1128
+ case "network-execution-event-finish":
1129
+ case "network-validation-start":
1130
+ case "network-validation-end":
1131
+ case "network-object":
1132
+ case "network-object-result":
1133
+ case "tool-output-denied": return result;
1134
+ default: return assertExhaustive(chunk, result);
1135
+ }
1271
1136
  };
1272
- const ToolApprovalHeaderClass = tailwindMerge.twMerge(
1273
- "mastra:flex mastra:justify-between mastra:items-center mastra:gap-2",
1274
- "mastra:border-b mastra:border-border1 mastra:px-4 mastra:py-2"
1275
- );
1276
- const ToolApprovalHeader = ({ className, ...props }) => {
1277
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className || ToolApprovalHeaderClass, ...props });
1137
+ /**
1138
+ * Compile-time exhaustiveness helper. At runtime, returns the conversation
1139
+ * unchanged so unexpected chunk variants never throw inside the React stream
1140
+ * pump; TypeScript will fail to compile if `ChunkType` ever grows a new branch
1141
+ * that isn't enumerated above.
1142
+ */
1143
+ const assertExhaustive = (_chunk, fallback) => fallback;
1144
+ const accumulateAgentChunk = (chunk, conversation, _metadata, parentToolCallId, parentToolName) => {
1145
+ const lastMessage = conversation[conversation.length - 1];
1146
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
1147
+ const parts = [...lastMessage.content.parts];
1148
+ const findToolPartIndex = () => parts.findIndex((part) => isToolPart(part) && (parentToolCallId && part.toolInvocation.toolCallId === parentToolCallId || parentToolName && part.toolInvocation.toolName === parentToolName));
1149
+ if (chunk.type === "text-delta") {
1150
+ const agentChunk = chunk.payload;
1151
+ const toolPartIndex = findToolPartIndex();
1152
+ if (toolPartIndex === -1) return conversation;
1153
+ const toolPart = parts[toolPartIndex];
1154
+ const existingResult = toolPart.toolInvocation.result || {};
1155
+ const childMessages = existingResult.childMessages || [];
1156
+ const lastChildMessage = childMessages[childMessages.length - 1];
1157
+ const textMessage = {
1158
+ type: "text",
1159
+ content: (lastChildMessage?.content || "") + agentChunk.text
1160
+ };
1161
+ const nextChildren = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
1162
+ parts[toolPartIndex] = {
1163
+ ...toolPart,
1164
+ toolInvocation: {
1165
+ ...toolPart.toolInvocation,
1166
+ result: {
1167
+ ...existingResult,
1168
+ childMessages: nextChildren
1169
+ }
1170
+ }
1171
+ };
1172
+ } else if (chunk.type === "tool-call") {
1173
+ const agentChunk = chunk.payload;
1174
+ const toolPartIndex = findToolPartIndex();
1175
+ if (toolPartIndex === -1) return conversation;
1176
+ const toolPart = parts[toolPartIndex];
1177
+ const existingResult = toolPart.toolInvocation.result || {};
1178
+ const childMessages = existingResult.childMessages || [];
1179
+ parts[toolPartIndex] = {
1180
+ ...toolPart,
1181
+ toolInvocation: {
1182
+ ...toolPart.toolInvocation,
1183
+ result: {
1184
+ ...existingResult,
1185
+ childMessages: [...childMessages, {
1186
+ type: "tool",
1187
+ toolCallId: agentChunk.toolCallId,
1188
+ toolName: agentChunk.toolName,
1189
+ args: agentChunk.args
1190
+ }]
1191
+ }
1192
+ }
1193
+ };
1194
+ } else if (chunk.type === "tool-output") {
1195
+ const agentChunk = chunk.payload;
1196
+ const toolPartIndex = findToolPartIndex();
1197
+ if (toolPartIndex === -1) return conversation;
1198
+ const toolPart = parts[toolPartIndex];
1199
+ if (agentChunk?.output?.type?.startsWith("workflow-")) {
1200
+ const existingResult = toolPart.toolInvocation.result || {};
1201
+ const childMessages = existingResult.childMessages || [];
1202
+ const lastIndex = childMessages.length - 1;
1203
+ const currentMessage = childMessages[lastIndex];
1204
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
1205
+ const updated = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
1206
+ if (lastIndex >= 0 && childMessages[lastIndex]?.type === "tool") parts[toolPartIndex] = {
1207
+ ...toolPart,
1208
+ toolInvocation: {
1209
+ ...toolPart.toolInvocation,
1210
+ result: {
1211
+ ...existingResult,
1212
+ childMessages: [...childMessages.slice(0, -1), {
1213
+ ...currentMessage,
1214
+ toolOutput: {
1215
+ ...updated,
1216
+ runId: agentChunk.output.runId
1217
+ }
1218
+ }]
1219
+ }
1220
+ }
1221
+ };
1222
+ }
1223
+ } else if (chunk.type === "tool-result") {
1224
+ const agentChunk = chunk.payload;
1225
+ const toolPartIndex = findToolPartIndex();
1226
+ if (toolPartIndex === -1) return conversation;
1227
+ const toolPart = parts[toolPartIndex];
1228
+ const existingResult = toolPart.toolInvocation.result || {};
1229
+ const childMessages = existingResult.childMessages || [];
1230
+ const lastIndex = childMessages.length - 1;
1231
+ const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
1232
+ if (lastIndex >= 0 && childMessages[lastIndex]?.type === "tool") parts[toolPartIndex] = {
1233
+ ...toolPart,
1234
+ toolInvocation: {
1235
+ ...toolPart.toolInvocation,
1236
+ result: {
1237
+ ...existingResult,
1238
+ childMessages: [...childMessages.slice(0, -1), {
1239
+ ...childMessages[lastIndex],
1240
+ toolOutput: isWorkflow ? {
1241
+ ...agentChunk.result?.result,
1242
+ runId: agentChunk.result?.runId
1243
+ } : agentChunk.result
1244
+ }]
1245
+ }
1246
+ }
1247
+ };
1248
+ }
1249
+ return replaceLast(conversation, withParts(lastMessage, parts));
1278
1250
  };
1279
- const ToolApprovalContentClass = tailwindMerge.twMerge("mastra:text-text6 mastra:p-4");
1280
- const ToolApprovalContent = ({ className, ...props }) => {
1281
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className || ToolApprovalContentClass, ...props });
1251
+ const networkMode = (metadata) => ({
1252
+ ...metadata,
1253
+ mode: "network"
1254
+ });
1255
+ const findPartIndex = (parts, predicate) => parts.findIndex(predicate);
1256
+ const isDynamicToolPart = (part) => part.type === "dynamic-tool";
1257
+ const lastAssistant = (conversation) => {
1258
+ const last = conversation[conversation.length - 1];
1259
+ return last && last.role === "assistant" ? last : void 0;
1282
1260
  };
1283
- const ToolApprovalActionsClass = tailwindMerge.twMerge("mastra:flex mastra:gap-2 mastra:items-center");
1284
- const ToolApprovalActions = ({ className, ...props }) => {
1285
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className || ToolApprovalActionsClass, ...props });
1261
+ /**
1262
+ * Try to parse the buffered routing-agent text as a JSON object. Returns the
1263
+ * parsed object on success, or `null` while the buffer is still incomplete or
1264
+ * not JSON at all.
1265
+ */
1266
+ const tryParseRoutingDecision = (buffered) => {
1267
+ const trimmed = buffered.trim();
1268
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
1269
+ try {
1270
+ const parsed = JSON.parse(trimmed);
1271
+ if (parsed && typeof parsed === "object") return parsed;
1272
+ return null;
1273
+ } catch {
1274
+ return null;
1275
+ }
1286
1276
  };
1287
-
1288
- const EntryClass = "mastra:space-y-2";
1289
- const Entry = ({ className, ...props }) => {
1290
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className || EntryClass, ...props });
1277
+ /**
1278
+ * Routing-agent text deltas describe the network's routing decision (often a
1279
+ * JSON object such as `{ "isNetwork": true, "agentId": "...", ... }`). The raw
1280
+ * payload is never useful in the rendered thread, so we buffer it in
1281
+ * message-level metadata, promote it to `routingDecision` when it parses as
1282
+ * JSON, and fall back to `routingDecisionText` for non-JSON routing models.
1283
+ * No visible text part is produced.
1284
+ */
1285
+ const handleRoutingAgentDelta = (chunk, conversation, metadata) => {
1286
+ const delta = chunk.payload?.text ?? "";
1287
+ if (!delta) return conversation;
1288
+ const lastMessage = lastAssistant(conversation);
1289
+ const mergeRoutingMetadata = (existing) => {
1290
+ const buffered = (existing.routingDecisionBuffer ?? "") + delta;
1291
+ const next = {
1292
+ ...cloneMetadata(existing),
1293
+ mode: "network"
1294
+ };
1295
+ const parsed = tryParseRoutingDecision(buffered);
1296
+ if (parsed) {
1297
+ next.routingDecision = parsed;
1298
+ delete next.routingDecisionBuffer;
1299
+ delete next.routingDecisionText;
1300
+ } else {
1301
+ next.routingDecisionBuffer = buffered;
1302
+ next.routingDecisionText = buffered;
1303
+ }
1304
+ return next;
1305
+ };
1306
+ if (!lastMessage) {
1307
+ const seed = mergeRoutingMetadata({});
1308
+ return appendAssistantMessage(conversation, `routing-agent-${chunk.payload?.runId ?? "unknown"}-${Date.now()}`, [], {
1309
+ ...networkMode(metadata),
1310
+ ...seed
1311
+ });
1312
+ }
1313
+ return replaceLast(conversation, withMetadata(lastMessage, mergeRoutingMetadata(lastMessage.content.metadata ?? {})));
1291
1314
  };
1292
- const EntryTitleClass = "mastra:font-mono mastra:text-sm mastra:text-text3";
1293
- const EntryTitle = ({ className, as: Root = "h3", ...props }) => {
1294
- return /* @__PURE__ */ jsxRuntime.jsx(Root, { className: className || EntryTitleClass, ...props });
1315
+ const handleAgentNetworkChunk = (chunk, conversation, metadata) => {
1316
+ if (chunk.type === "agent-execution-start") {
1317
+ const primitiveId = chunk.payload?.args?.primitiveId;
1318
+ const runId = chunk.payload.runId;
1319
+ if (!primitiveId || !runId) return conversation;
1320
+ const toolPart = {
1321
+ type: "dynamic-tool",
1322
+ toolName: primitiveId,
1323
+ toolCallId: runId,
1324
+ state: "input-available",
1325
+ input: chunk.payload.args
1326
+ };
1327
+ return appendAssistantMessage(conversation, `agent-execution-start-${runId}-${Date.now()}`, [toolPart], {
1328
+ ...networkMode(metadata),
1329
+ selectionReason: chunk.payload?.args?.selectionReason || "",
1330
+ agentInput: chunk.payload?.args?.task,
1331
+ from: "AGENT"
1332
+ });
1333
+ }
1334
+ if (chunk.type === "agent-execution-end") {
1335
+ const lastMessage = lastAssistant(conversation);
1336
+ if (!lastMessage) return conversation;
1337
+ const parts = [...lastMessage.content.parts];
1338
+ const toolPartIndex = findPartIndex(parts, (part) => isDynamicToolPart(part));
1339
+ if (toolPartIndex !== -1) {
1340
+ const toolPart = parts[toolPartIndex];
1341
+ const currentOutput = toolPart.output;
1342
+ parts[toolPartIndex] = {
1343
+ type: "dynamic-tool",
1344
+ toolName: toolPart.toolName,
1345
+ toolCallId: toolPart.toolCallId,
1346
+ state: "output-available",
1347
+ input: toolPart.input,
1348
+ output: {
1349
+ ...currentOutput,
1350
+ result: currentOutput?.result || chunk.payload?.result || ""
1351
+ }
1352
+ };
1353
+ }
1354
+ return replaceLast(conversation, withParts(lastMessage, parts));
1355
+ }
1356
+ if (chunk.type.startsWith("agent-execution-event-")) {
1357
+ const lastMessage = lastAssistant(conversation);
1358
+ if (!lastMessage) return conversation;
1359
+ const agentChunk = chunk.payload;
1360
+ const parts = [...lastMessage.content.parts];
1361
+ const toolPartIndex = findPartIndex(parts, (part) => isDynamicToolPart(part));
1362
+ if (toolPartIndex === -1) return conversation;
1363
+ const toolPart = parts[toolPartIndex];
1364
+ if (agentChunk.type === "text-delta") {
1365
+ const childMessages = toolPart?.output?.childMessages || [];
1366
+ const lastChildMessage = childMessages[childMessages.length - 1];
1367
+ const textMessage = {
1368
+ type: "text",
1369
+ content: (lastChildMessage?.content || "") + agentChunk.payload.text
1370
+ };
1371
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
1372
+ parts[toolPartIndex] = {
1373
+ ...toolPart,
1374
+ output: { childMessages: nextMessages }
1375
+ };
1376
+ } else if (agentChunk.type === "tool-call") {
1377
+ const childMessages = toolPart?.output?.childMessages || [];
1378
+ parts[toolPartIndex] = {
1379
+ ...toolPart,
1380
+ output: {
1381
+ ...toolPart?.output,
1382
+ childMessages: [...childMessages, {
1383
+ type: "tool",
1384
+ toolCallId: agentChunk.payload.toolCallId,
1385
+ toolName: agentChunk.payload.toolName,
1386
+ args: agentChunk.payload.args
1387
+ }]
1388
+ }
1389
+ };
1390
+ } else if (agentChunk.type === "tool-output") {
1391
+ if (agentChunk.payload?.output?.type?.startsWith("workflow-")) {
1392
+ const childMessages = toolPart?.output?.childMessages || [];
1393
+ const lastToolIndex = childMessages.length - 1;
1394
+ const currentMessage = childMessages[lastToolIndex];
1395
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
1396
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.payload.output);
1397
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") parts[toolPartIndex] = {
1398
+ ...toolPart,
1399
+ output: {
1400
+ ...toolPart?.output,
1401
+ childMessages: [...childMessages.slice(0, -1), {
1402
+ ...currentMessage,
1403
+ toolOutput: updatedWorkflowState
1404
+ }]
1405
+ }
1406
+ };
1407
+ }
1408
+ } else if (agentChunk.type === "tool-result") {
1409
+ const childMessages = toolPart?.output?.childMessages || [];
1410
+ const lastToolIndex = childMessages.length - 1;
1411
+ const isWorkflow = Boolean(agentChunk.payload?.result?.result?.steps);
1412
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") parts[toolPartIndex] = {
1413
+ ...toolPart,
1414
+ output: {
1415
+ ...toolPart?.output,
1416
+ childMessages: [...childMessages.slice(0, -1), {
1417
+ ...childMessages[lastToolIndex],
1418
+ toolOutput: isWorkflow ? agentChunk.payload.result.result : agentChunk.payload.result
1419
+ }]
1420
+ }
1421
+ };
1422
+ }
1423
+ return replaceLast(conversation, withParts(lastMessage, parts));
1424
+ }
1425
+ return conversation;
1295
1426
  };
1296
-
1297
- async function highlight(code, lang) {
1298
- const out = await web.codeToHast(code, {
1299
- lang,
1300
- theme: "dracula-soft"
1301
- });
1302
- return hastUtilToJsxRuntime.toJsxRuntime(out, {
1303
- Fragment: react.Fragment,
1304
- jsx: jsxRuntime.jsx,
1305
- jsxs: jsxRuntime.jsxs
1306
- });
1307
- }
1308
-
1309
- const Tooltip = ({ children }) => {
1310
- return /* @__PURE__ */ jsxRuntime.jsx(reactTooltip.TooltipProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(reactTooltip.Root, { children }) });
1427
+ const handleWorkflowNetworkChunk = (chunk, conversation, metadata) => {
1428
+ if (chunk.type === "workflow-execution-start") {
1429
+ const primitiveId = chunk.payload?.args?.primitiveId;
1430
+ const runId = chunk.payload.runId;
1431
+ if (!primitiveId || !runId) return conversation;
1432
+ let agentInput;
1433
+ try {
1434
+ agentInput = JSON.parse(chunk.payload?.args?.prompt);
1435
+ } catch {
1436
+ agentInput = chunk.payload?.args?.prompt;
1437
+ }
1438
+ const toolPart = {
1439
+ type: "dynamic-tool",
1440
+ toolName: primitiveId,
1441
+ toolCallId: runId,
1442
+ state: "input-available",
1443
+ input: chunk.payload.args
1444
+ };
1445
+ return appendAssistantMessage(conversation, `workflow-start-${runId}-${Date.now()}`, [toolPart], {
1446
+ ...networkMode(metadata),
1447
+ selectionReason: chunk.payload?.args?.selectionReason || "",
1448
+ from: "WORKFLOW",
1449
+ agentInput
1450
+ });
1451
+ }
1452
+ if (chunk.type === "workflow-execution-suspended") {
1453
+ const lastMessage = lastAssistant(conversation);
1454
+ if (!lastMessage) return conversation;
1455
+ const existing = lastMessage.content.metadata?.suspendedTools ?? {};
1456
+ return replaceLast(conversation, withMetadata(lastMessage, {
1457
+ ...cloneMetadata(lastMessage.content.metadata),
1458
+ mode: "network",
1459
+ suspendedTools: {
1460
+ ...existing,
1461
+ [chunk.payload.toolName]: {
1462
+ toolCallId: chunk.payload.toolCallId,
1463
+ toolName: chunk.payload.toolName,
1464
+ args: chunk.payload.args,
1465
+ suspendPayload: chunk.payload.suspendPayload,
1466
+ runId: chunk.payload.runId
1467
+ }
1468
+ }
1469
+ }));
1470
+ }
1471
+ if (chunk.type.startsWith("workflow-execution-event-")) {
1472
+ const lastMessage = lastAssistant(conversation);
1473
+ if (!lastMessage) return conversation;
1474
+ const parts = [...lastMessage.content.parts];
1475
+ const toolPartIndex = findPartIndex(parts, (part) => isDynamicToolPart(part));
1476
+ if (toolPartIndex === -1) return conversation;
1477
+ const toolPart = parts[toolPartIndex];
1478
+ const existingWorkflowState = toolPart.output || {};
1479
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(existingWorkflowState, chunk.payload);
1480
+ parts[toolPartIndex] = {
1481
+ ...toolPart,
1482
+ output: updatedWorkflowState
1483
+ };
1484
+ return replaceLast(conversation, withParts(lastMessage, parts));
1485
+ }
1486
+ return conversation;
1311
1487
  };
1312
- const TooltipContentClass = "mastra:bg-surface4 mastra:text-text6 mastra mastra:rounded-lg mastra:py-1 mastra:px-2 mastra:text-xs mastra:border mastra:border-border1 mastra-tooltip-enter";
1313
- const TooltipContent = ({ children, className, ...props }) => {
1314
- return /* @__PURE__ */ jsxRuntime.jsx(reactTooltip.TooltipPortal, { children: /* @__PURE__ */ jsxRuntime.jsx(reactTooltip.TooltipContent, { className: className || TooltipContentClass, ...props, children }) });
1488
+ const handleToolNetworkChunk = (chunk, conversation, metadata) => {
1489
+ if (chunk.type === "tool-execution-start") {
1490
+ const argsData = chunk.payload.args;
1491
+ const nestedArgs = argsData.args || {};
1492
+ const lastMessage = lastAssistant(conversation);
1493
+ const toolPart = {
1494
+ type: "dynamic-tool",
1495
+ toolName: argsData.toolName || "unknown",
1496
+ toolCallId: argsData.toolCallId || "unknown",
1497
+ state: "input-available",
1498
+ input: nestedArgs
1499
+ };
1500
+ if (!lastMessage) return appendAssistantMessage(conversation, `tool-start-${chunk.payload.runId}-${Date.now()}`, [toolPart], {
1501
+ ...networkMode(metadata),
1502
+ selectionReason: metadata.mode === "network" ? metadata.selectionReason || argsData.selectionReason : "",
1503
+ agentInput: nestedArgs
1504
+ });
1505
+ const parts = [...lastMessage.content.parts, toolPart];
1506
+ return replaceLast(conversation, withParts(lastMessage, parts));
1507
+ }
1508
+ if (chunk.type === "tool-execution-approval") {
1509
+ const lastMessage = lastAssistant(conversation);
1510
+ if (!lastMessage) return conversation;
1511
+ const existing = lastMessage.content.metadata?.requireApprovalMetadata ?? {};
1512
+ return replaceLast(conversation, withMetadata(lastMessage, {
1513
+ ...cloneMetadata(lastMessage.content.metadata),
1514
+ mode: "network",
1515
+ requireApprovalMetadata: {
1516
+ ...existing,
1517
+ [chunk.payload.toolName]: {
1518
+ toolCallId: chunk.payload.toolCallId,
1519
+ toolName: chunk.payload.toolName,
1520
+ args: chunk.payload.args,
1521
+ runId: chunk.payload.runId
1522
+ }
1523
+ }
1524
+ }));
1525
+ }
1526
+ if (chunk.type === "tool-execution-suspended") {
1527
+ const lastMessage = lastAssistant(conversation);
1528
+ if (!lastMessage) return conversation;
1529
+ const existing = lastMessage.content.metadata?.suspendedTools ?? {};
1530
+ return replaceLast(conversation, withMetadata(lastMessage, {
1531
+ ...cloneMetadata(lastMessage.content.metadata),
1532
+ mode: "network",
1533
+ suspendedTools: {
1534
+ ...existing,
1535
+ [chunk.payload.toolName]: {
1536
+ toolCallId: chunk.payload.toolCallId,
1537
+ toolName: chunk.payload.toolName,
1538
+ args: chunk.payload.args,
1539
+ suspendPayload: chunk.payload.suspendPayload,
1540
+ runId: chunk.payload.runId
1541
+ }
1542
+ }
1543
+ }));
1544
+ }
1545
+ if (chunk.type === "tool-execution-end") {
1546
+ const lastMessage = lastAssistant(conversation);
1547
+ if (!lastMessage) return conversation;
1548
+ const parts = [...lastMessage.content.parts];
1549
+ const toolPartIndex = findPartIndex(parts, (part) => isDynamicToolPart(part) && part.toolCallId === chunk.payload.toolCallId);
1550
+ if (toolPartIndex !== -1) {
1551
+ const toolPart = parts[toolPartIndex];
1552
+ const currentOutput = toolPart.output;
1553
+ parts[toolPartIndex] = {
1554
+ type: "dynamic-tool",
1555
+ toolName: toolPart.toolName,
1556
+ toolCallId: toolPart.toolCallId,
1557
+ state: "output-available",
1558
+ input: toolPart.input,
1559
+ output: currentOutput?.result || chunk.payload?.result || ""
1560
+ };
1561
+ }
1562
+ return replaceLast(conversation, withParts(lastMessage, parts));
1563
+ }
1564
+ return conversation;
1315
1565
  };
1316
- const TooltipTrigger = (props) => {
1317
- return /* @__PURE__ */ jsxRuntime.jsx(reactTooltip.TooltipTrigger, { ...props, asChild: true });
1566
+ /**
1567
+ * Reduce a single network-mode chunk into the running `MastraDBMessage[]`
1568
+ * conversation. Ports the historical `AISdkNetworkTransformer` so the playground
1569
+ * keeps rendering network badges (routing text, agent/workflow/tool execution,
1570
+ * suspensions, approvals, completion feedback) until the next major.
1571
+ */
1572
+ const accumulateNetworkChunk = ({ chunk, conversation, metadata }) => {
1573
+ const newConversation = [...conversation];
1574
+ if (chunk.type === "routing-agent-text-delta") return handleRoutingAgentDelta(chunk, newConversation, metadata);
1575
+ if (chunk.type.startsWith("agent-execution-")) return handleAgentNetworkChunk(chunk, newConversation, metadata);
1576
+ if (chunk.type.startsWith("workflow-execution-")) return handleWorkflowNetworkChunk(chunk, newConversation, metadata);
1577
+ if (chunk.type.startsWith("tool-execution-")) return handleToolNetworkChunk(chunk, newConversation, metadata);
1578
+ if (chunk.type === "network-validation-end") {
1579
+ if (chunk.payload.suppressFeedback) return newConversation;
1580
+ const textPart = {
1581
+ type: "text",
1582
+ text: formatCompletionFeedback({
1583
+ complete: chunk.payload.passed,
1584
+ scorers: chunk.payload.results,
1585
+ totalDuration: chunk.payload.duration,
1586
+ timedOut: chunk.payload.timedOut,
1587
+ completionReason: chunk.payload.reason
1588
+ }, chunk.payload.maxIterationReached)
1589
+ };
1590
+ return appendAssistantMessage(newConversation, `network-validation-end-${chunk.payload.runId}-${Date.now()}`, [textPart], {
1591
+ ...networkMode(metadata),
1592
+ completionResult: { passed: chunk.payload.passed }
1593
+ });
1594
+ }
1595
+ if (chunk.type === "network-execution-event-step-finish") {
1596
+ const lastMessage = lastAssistant(newConversation);
1597
+ if (!lastMessage) return newConversation;
1598
+ const agentChunk = chunk.payload;
1599
+ const parts = [...lastMessage.content.parts];
1600
+ const textPartIndex = findPartIndex(parts, (part) => part.type === "text");
1601
+ if (textPartIndex === -1) {
1602
+ parts.push({
1603
+ type: "text",
1604
+ text: agentChunk.result,
1605
+ state: "done"
1606
+ });
1607
+ return replaceLast(newConversation, withParts(lastMessage, parts));
1608
+ }
1609
+ const textPart = parts[textPartIndex];
1610
+ if (textPart.type === "text") {
1611
+ parts[textPartIndex] = {
1612
+ ...textPart,
1613
+ state: "done"
1614
+ };
1615
+ return replaceLast(newConversation, withParts(lastMessage, parts));
1616
+ }
1617
+ return newConversation;
1618
+ }
1619
+ return newConversation;
1318
1620
  };
1319
-
1320
- const IconButtonClass = "mastra:text-text3 mastra:hover:text-text6 mastra:active:text-text6 mastra:hover:bg-surface4 mastra:active:bg-surface5 mastra:rounded-md mastra:cursor-pointer";
1321
- const IconButton = ({ children, tooltip, size = "md", className, ...props }) => {
1322
- return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
1323
- /* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx(
1324
- "button",
1325
- {
1326
- ...props,
1327
- className: className || tailwindMerge.twMerge(IconButtonClass, size === "md" && "mastra:p-0.5", size === "lg" && "mastra:p-1"),
1328
- children: /* @__PURE__ */ jsxRuntime.jsx(Icon, { size, children })
1329
- }
1330
- ) }),
1331
- /* @__PURE__ */ jsxRuntime.jsx(TooltipContent, { children: tooltip })
1332
- ] });
1621
+ //#endregion
1622
+ //#region src/lib/mastra-db/fromCoreUserMessage.ts
1623
+ /**
1624
+ * Convert a CoreUserMessage into a canonical `MastraDBMessage` (`format: 2`).
1625
+ *
1626
+ * Image and file inputs are emitted as the canonical V4 `file` part shape
1627
+ * (`{ type: 'file', mimeType, data }`) — the exact shape memory resolves on
1628
+ * reload (see `AIV4Adapter`), so optimistic-send and reload render identically.
1629
+ *
1630
+ * Handles all CoreUserMessage content types:
1631
+ * - String content → single text part
1632
+ * - Array content with text/image/file parts → corresponding `MastraMessagePart`s
1633
+ */
1634
+ const coreUserMessageToParts = (coreUserMessage) => typeof coreUserMessage.content === "string" ? [{
1635
+ type: "text",
1636
+ text: coreUserMessage.content
1637
+ }] : coreUserMessage.content.map((part) => {
1638
+ switch (part.type) {
1639
+ case "text": return {
1640
+ type: "text",
1641
+ text: part.text
1642
+ };
1643
+ case "image": {
1644
+ const mimeType = part.mimeType ?? "image/*";
1645
+ return {
1646
+ type: "file",
1647
+ mimeType,
1648
+ data: encodeFilePartDataForStorage(part.image, mimeType)
1649
+ };
1650
+ }
1651
+ case "file": return {
1652
+ type: "file",
1653
+ mimeType: part.mimeType,
1654
+ data: encodeFilePartDataForStorage(part.data, part.mimeType),
1655
+ ...part.filename !== void 0 ? { filename: part.filename } : {}
1656
+ };
1657
+ default: throw new Error(`Unhandled content part type: ${part.type}`);
1658
+ }
1659
+ });
1660
+ const newUserMessage = (parts) => ({
1661
+ id: `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
1662
+ role: "user",
1663
+ createdAt: /* @__PURE__ */ new Date(),
1664
+ content: {
1665
+ format: 2,
1666
+ parts
1667
+ }
1668
+ });
1669
+ const fromCoreUserMessageToMastraDBMessage = (coreUserMessage) => newUserMessage(coreUserMessageToParts(coreUserMessage));
1670
+ /**
1671
+ * Merge multiple `CoreUserMessage`s into a single canonical `MastraDBMessage`.
1672
+ *
1673
+ * A user turn that carries attachments arrives as several `CoreUserMessage`s
1674
+ * (one for the text, one per attachment). Memory/reload persists and resolves
1675
+ * that whole turn as a single multi-part user message, so the optimistic
1676
+ * streaming display must do the same — flatten every message's parts into one
1677
+ * `parts` array — to render identically (one bubble, not one per message).
1678
+ */
1679
+ const fromCoreUserMessagesToMastraDBMessage = (coreUserMessages) => newUserMessage(coreUserMessages.flatMap(coreUserMessageToParts));
1680
+ //#endregion
1681
+ //#region src/agent/extract-tasks.ts
1682
+ const TASK_TOOL_NAMES = /* @__PURE__ */ new Set([
1683
+ "task_write",
1684
+ "task_update",
1685
+ "task_complete",
1686
+ "task_check"
1687
+ ]);
1688
+ const TASK_SIGNAL_ID = "tasks";
1689
+ const TASK_TAG_NAMES = /* @__PURE__ */ new Set(["current-task-list", "task-list-update"]);
1690
+ const TASK_STATUSES = /* @__PURE__ */ new Set([
1691
+ "pending",
1692
+ "in_progress",
1693
+ "completed"
1694
+ ]);
1695
+ const isDataChunk$1 = (chunk) => typeof chunk.type === "string" && chunk.type.startsWith("data-");
1696
+ const isRecord$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1697
+ const isTaskStatus = (value) => typeof value === "string" && TASK_STATUSES.has(value);
1698
+ const isTaskItemArray = (value) => Array.isArray(value) && value.every((item) => isRecord$1(item) && typeof item.id === "string" && typeof item.content === "string" && isTaskStatus(item.status) && typeof item.activeForm === "string");
1699
+ const isTaskSignal = (value) => {
1700
+ if (!isRecord$1(value)) return false;
1701
+ return value.id === TASK_SIGNAL_ID || typeof value.tagName === "string" && TASK_TAG_NAMES.has(value.tagName);
1333
1702
  };
1334
-
1335
- const CodeBlockClass = "mastra:rounded-lg mastra:[&>pre]:p-4 mastra:overflow-hidden mastra:[&>pre]:!bg-surface4 mastra:[&>pre>code]:leading-5 mastra:relative";
1336
- const CodeBlock = ({ code, language, className, cta }) => {
1337
- const [nodes, setNodes] = react.useState(null);
1338
- react.useLayoutEffect(() => {
1339
- void highlight(code, language).then(setNodes);
1340
- }, [language]);
1341
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: className || CodeBlockClass, children: [
1342
- nodes ?? null,
1343
- cta
1344
- ] });
1703
+ const extractTasksFromSignalData = (data) => {
1704
+ if (!isTaskSignal(data) || !isRecord$1(data)) return void 0;
1705
+ const metadata = data.metadata;
1706
+ if (!isRecord$1(metadata)) return void 0;
1707
+ const value = metadata.value;
1708
+ if (!isRecord$1(value)) return void 0;
1709
+ return isTaskItemArray(value.tasks) ? value.tasks : void 0;
1345
1710
  };
1346
- const CodeCopyButton = ({ code }) => {
1347
- const [isCopied, setIsCopied] = react.useState(false);
1348
- const handleCopy = () => {
1349
- navigator.clipboard.writeText(code);
1350
- setIsCopied(true);
1351
- setTimeout(() => setIsCopied(false), 2e3);
1352
- };
1353
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mastra:absolute mastra:top-2 mastra:right-2", children: /* @__PURE__ */ jsxRuntime.jsx(IconButton, { tooltip: "Copy", onClick: handleCopy, children: isCopied ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CopyIcon, {}) }) });
1711
+ const parseTasksFromResult = (raw) => {
1712
+ if (isRecord$1(raw) && isTaskItemArray(raw.tasks)) return raw.tasks;
1713
+ if (typeof raw !== "string") return void 0;
1714
+ try {
1715
+ const parsed = JSON.parse(raw);
1716
+ return isRecord$1(parsed) && isTaskItemArray(parsed.tasks) ? parsed.tasks : void 0;
1717
+ } catch {
1718
+ return;
1719
+ }
1354
1720
  };
1355
-
1356
- const AgentIcon = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsxs(
1357
- "svg",
1358
- {
1359
- width: "17",
1360
- height: "16",
1361
- viewBox: "0 0 17 16",
1362
- fill: "none",
1363
- xmlns: "http://www.w3.org/2000/svg",
1364
- ...props,
1365
- className: tailwindMerge.twMerge("mastra-icon", className),
1366
- children: [
1367
- /* @__PURE__ */ jsxRuntime.jsx(
1368
- "path",
1369
- {
1370
- fillRule: "evenodd",
1371
- clipRule: "evenodd",
1372
- d: "M8.5 15C10.3565 15 12.137 14.2625 13.4497 12.9497C14.7625 11.637 15.5 9.85652 15.5 8C15.5 6.14348 14.7625 4.36301 13.4497 3.05025C12.137 1.7375 10.3565 1 8.5 1C6.64348 1 4.86301 1.7375 3.55025 3.05025C2.2375 4.36301 1.5 6.14348 1.5 8C1.5 9.85652 2.2375 11.637 3.55025 12.9497C4.86301 14.2625 6.64348 15 8.5 15ZM5.621 10.879L4.611 11.889C3.84179 11.1198 3.31794 10.1398 3.1057 9.07291C2.89346 8.00601 3.00236 6.90013 3.41864 5.89512C3.83491 4.89012 4.53986 4.03112 5.44434 3.42676C6.34881 2.8224 7.41219 2.49983 8.5 2.49983C9.58781 2.49983 10.6512 2.8224 11.5557 3.42676C12.4601 4.03112 13.1651 4.89012 13.5814 5.89512C13.9976 6.90013 14.1065 8.00601 13.8943 9.07291C13.6821 10.1398 13.1582 11.1198 12.389 11.889L11.379 10.879C11.1004 10.6003 10.7696 10.3792 10.4055 10.2284C10.0414 10.0776 9.6511 9.99995 9.257 10H7.743C7.3489 9.99995 6.95865 10.0776 6.59455 10.2284C6.23045 10.3792 5.89963 10.6003 5.621 10.879Z",
1373
- fill: "currentColor"
1374
- }
1375
- ),
1376
- /* @__PURE__ */ jsxRuntime.jsx(
1377
- "path",
1378
- {
1379
- d: "M8.5 4C7.96957 4 7.46086 4.21071 7.08579 4.58579C6.71071 4.96086 6.5 5.46957 6.5 6V6.5C6.5 7.03043 6.71071 7.53914 7.08579 7.91421C7.46086 8.28929 7.96957 8.5 8.5 8.5C9.03043 8.5 9.53914 8.28929 9.91421 7.91421C10.2893 7.53914 10.5 7.03043 10.5 6.5V6C10.5 5.46957 10.2893 4.96086 9.91421 4.58579C9.53914 4.21071 9.03043 4 8.5 4Z",
1380
- fill: "currentColor"
1381
- }
1382
- )
1383
- ]
1384
- }
1385
- );
1386
-
1387
- const ToolsIcon = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
1388
- "svg",
1389
- {
1390
- width: "17",
1391
- height: "16",
1392
- viewBox: "0 0 17 16",
1393
- fill: "none",
1394
- xmlns: "http://www.w3.org/2000/svg",
1395
- ...props,
1396
- className: tailwindMerge.twMerge("mastra-icon", className),
1397
- children: /* @__PURE__ */ jsxRuntime.jsx(
1398
- "path",
1399
- {
1400
- fillRule: "evenodd",
1401
- clipRule: "evenodd",
1402
- d: "M7.5605 1.42351C8.0791 0.904904 8.92215 0.906157 9.4395 1.42351L10.6922 2.67617C11.2108 3.19477 11.2095 4.03782 10.6922 4.55517L9.4395 5.80783C8.9209 6.32643 8.07785 6.32518 7.5605 5.80783L6.30784 4.55517C5.78923 4.03656 5.79049 3.19352 6.30784 2.67617L7.5605 1.42351ZM3.17618 5.80783C3.69478 5.28923 4.53782 5.29048 5.05517 5.80783L6.30784 7.0605C6.82644 7.5791 6.82519 8.42214 6.30784 8.93949L5.05517 10.1922C4.53657 10.7108 3.69353 10.7095 3.17618 10.1922L1.92351 8.93949C1.40491 8.42089 1.40616 7.57785 1.92351 7.0605L3.17618 5.80783ZM11.9448 5.80783C12.4634 5.28923 13.3065 5.29048 13.8238 5.80783L15.0765 7.0605C15.5951 7.5791 15.5938 8.42214 15.0765 8.93949L13.8238 10.1922C13.3052 10.7108 12.4622 10.7095 11.9448 10.1922L10.6922 8.93949C10.1736 8.42089 10.1748 7.57785 10.6922 7.0605L11.9448 5.80783ZM7.5605 10.1922C8.0791 9.67355 8.92215 9.67481 9.4395 10.1922L10.6922 11.4448C11.2108 11.9634 11.2095 12.8065 10.6922 13.3238L9.4395 14.5765C8.9209 15.0951 8.07785 15.0938 7.5605 14.5765L6.30784 13.3238C5.78923 12.8052 5.79049 11.9622 6.30784 11.4448L7.5605 10.1922Z",
1403
- fill: "currentColor"
1404
- }
1405
- )
1406
- }
1407
- );
1408
-
1409
- const WorkflowIcon = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
1410
- "svg",
1411
- {
1412
- width: "17",
1413
- height: "16",
1414
- viewBox: "0 0 17 16",
1415
- fill: "none",
1416
- xmlns: "http://www.w3.org/2000/svg",
1417
- ...props,
1418
- className: tailwindMerge.twMerge("mastra-icon", className),
1419
- children: /* @__PURE__ */ jsxRuntime.jsx(
1420
- "path",
1421
- {
1422
- fillRule: "evenodd",
1423
- clipRule: "evenodd",
1424
- d: "M6.24388 2.4018C6.24388 2.0394 6.53767 1.74561 6.90008 1.74561H10.0991C10.4614 1.74561 10.7553 2.0394 10.7553 2.4018V4.57546C10.7553 4.93787 10.4614 5.23166 10.0991 5.23166H9.31982V7.35469L10.0033 9.22664C9.90442 9.20146 9.80035 9.1761 9.6915 9.14986L9.62652 9.13422C9.30473 9.05687 8.92256 8.96501 8.61993 8.84491C8.5819 8.82981 8.54147 8.81292 8.49957 8.79391C8.45767 8.81292 8.41724 8.82981 8.3792 8.84491C8.07657 8.96501 7.6944 9.05687 7.37261 9.13422L7.30763 9.14986C7.19879 9.1761 7.09471 9.20146 6.99577 9.22664L7.67932 7.35469V5.23166H6.90008C6.53767 5.23166 6.24388 4.93787 6.24388 4.57546V2.4018ZM6.99577 9.22664C6.99577 9.22664 6.99578 9.22664 6.99577 9.22664L6.43283 10.7683H6.81806C7.18047 10.7683 7.47426 11.0622 7.47426 11.4245V13.5982C7.47426 13.9606 7.18047 14.2544 6.81806 14.2544H3.61909C3.25668 14.2544 2.96289 13.9606 2.96289 13.5982V11.4245C2.96289 11.0622 3.25668 10.7683 3.61909 10.7683H4.26617C4.2921 10.4663 4.32783 10.1494 4.37744 9.85171C4.43762 9.49063 4.52982 9.08135 4.68998 8.76102C4.93975 8.2615 5.44743 8.01751 5.7771 7.88788C6.14684 7.74249 6.57537 7.63889 6.92317 7.55505C7.24707 7.47696 7.49576 7.41679 7.67932 7.35469L6.99577 9.22664ZM6.43283 10.7683L6.99577 9.22664C6.75846 9.28705 6.55067 9.34646 6.37745 9.41458C6.22784 9.47341 6.1623 9.51712 6.14023 9.53254C6.09752 9.63631 6.04409 9.83055 5.99562 10.1214C5.96201 10.3231 5.93498 10.5439 5.91341 10.7683H6.43283ZM10.0033 9.22664L9.31982 7.35469C9.50338 7.41679 9.75206 7.47696 10.076 7.55505C10.4238 7.63889 10.8523 7.74249 11.2221 7.88788C11.5517 8.01751 12.0594 8.2615 12.3091 8.76102C12.4693 9.08135 12.5615 9.49063 12.6217 9.85171C12.6713 10.1494 12.707 10.4663 12.733 10.7683H13.38C13.7424 10.7683 14.0362 11.0622 14.0362 11.4245V13.5982C14.0362 13.9606 13.7424 14.2544 13.38 14.2544H10.1811C9.81867 14.2544 9.52488 13.9606 9.52488 13.5982V11.4245C9.52488 11.0622 9.81867 10.7683 10.1811 10.7683H10.5663L10.0033 9.22664ZM10.0033 9.22664L10.5663 10.7683H11.0857C11.0642 10.5439 11.0372 10.3231 11.0035 10.1214C10.9551 9.83055 10.9016 9.63631 10.8589 9.53254C10.8369 9.51712 10.7713 9.47341 10.6217 9.41458C10.4485 9.34646 10.2407 9.28705 10.0033 9.22664Z",
1425
- fill: "currentColor"
1426
- }
1427
- )
1428
- }
1429
- );
1430
-
1431
- const MessageClass = "mastra:flex mastra:flex-col mastra:w-full mastra:py-4 mastra:gap-2 mastra:group";
1432
- const Message = ({ position, className, children, ...props }) => {
1433
- return /* @__PURE__ */ jsxRuntime.jsx(
1434
- "div",
1435
- {
1436
- className: className || tailwindMerge.twMerge(
1437
- MessageClass,
1438
- position === "left" ? "" : "mastra:items-end mastra:[&_.mastra-message-content]:bg-surface4 mastra:[&_.mastra-message-content]:px-4"
1439
- ),
1440
- ...props,
1441
- children
1442
- }
1443
- );
1721
+ const extractTasksFromSignalChunk = (chunk) => {
1722
+ if (!isDataChunk$1(chunk)) return void 0;
1723
+ return extractTasksFromSignalData(chunk.data);
1444
1724
  };
1445
- const MessageContentClass = "mastra:max-w-4/5 mastra:py-2 mastra:text-text6 mastra:rounded-lg mastra-message-content mastra:text-md";
1446
- const MessageContent = ({ children, className, isStreaming, ...props }) => {
1447
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: className || MessageContentClass, ...props, children: [
1448
- children,
1449
- isStreaming && /* @__PURE__ */ jsxRuntime.jsx(MessageStreaming, {})
1450
- ] });
1725
+ const extractTasksFromToolResultChunk = (chunk) => {
1726
+ if (chunk.type !== "tool-result") return void 0;
1727
+ const payload = chunk.payload;
1728
+ if (!isRecord$1(payload) || typeof payload.toolName !== "string" || !TASK_TOOL_NAMES.has(payload.toolName)) return;
1729
+ return parseTasksFromResult(payload.result);
1451
1730
  };
1452
- const MessageActionsClass = "mastra:gap-2 mastra:flex mastra:opacity-0 mastra:group-hover:opacity-100 mastra:group-focus-within:opacity-100 mastra:items-center";
1453
- const MessageActions = ({ children, className, ...props }) => {
1454
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className || MessageActionsClass, ...props, children });
1731
+ const extractTasksFromToolInvocationPart = (part) => {
1732
+ if (!isRecord$1(part) || part.type !== "tool-invocation" || !isRecord$1(part.toolInvocation)) return void 0;
1733
+ const toolInvocation = part.toolInvocation;
1734
+ if (typeof toolInvocation.toolName !== "string" || !TASK_TOOL_NAMES.has(toolInvocation.toolName)) return void 0;
1735
+ return parseTasksFromResult(toolInvocation.result);
1455
1736
  };
1456
- const MessageUsagesClass = "mastra:flex mastra:gap-2 mastra:items-center";
1457
- const MessageUsages = ({ children, className, ...props }) => {
1458
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className || MessageUsagesClass, ...props, children });
1737
+ const extractTasksFromDataPart = (part) => {
1738
+ if (!isRecord$1(part) || typeof part.type !== "string" || !part.type.startsWith("data-")) return void 0;
1739
+ return extractTasksFromSignalData(part.data);
1459
1740
  };
1460
- const MessageUsageClass = "mastra:flex mastra:gap-2 mastra:items-center mastra:font-mono mastra:text-xs mastra:bg-surface3 mastra:rounded-lg mastra:px-2 mastra:py-1";
1461
- const MessageUsage = ({ children, className, ...props }) => {
1462
- return /* @__PURE__ */ jsxRuntime.jsx("dl", { className: className || MessageUsageClass, ...props, children });
1741
+ const extractTasksFromSignalMessage = (message) => {
1742
+ if (message.role !== "signal") return void 0;
1743
+ const metadata = message.content?.metadata;
1744
+ if (!isRecord$1(metadata)) return void 0;
1745
+ return extractTasksFromSignalData(metadata.signal);
1463
1746
  };
1464
- const MessageUsageEntryClass = "mastra:text-text3 mastra:text-xs mastra:flex mastra:gap-1 mastra:items-center";
1465
- const MessageUsageEntry = ({ children, className, ...props }) => {
1466
- return /* @__PURE__ */ jsxRuntime.jsx("dt", { className: className || MessageUsageEntryClass, ...props, children });
1747
+ const extractLatestTasksFromMessages = (messages) => {
1748
+ let latest;
1749
+ for (const message of messages) {
1750
+ for (const part of message.content?.parts ?? []) {
1751
+ const toolTasks = extractTasksFromToolInvocationPart(part);
1752
+ if (toolTasks !== void 0) latest = toolTasks;
1753
+ }
1754
+ const signalTasks = extractTasksFromSignalMessage(message);
1755
+ if (signalTasks !== void 0) latest = signalTasks;
1756
+ for (const part of message.content?.parts ?? []) {
1757
+ const dataTasks = extractTasksFromDataPart(part);
1758
+ if (dataTasks !== void 0) latest = dataTasks;
1759
+ }
1760
+ }
1761
+ return latest ?? [];
1467
1762
  };
1468
- const MessageUsageValueClass = "mastra:text-text6 mastra:text-xs";
1469
- const MessageUsageValue = ({ children, className, ...props }) => {
1470
- return /* @__PURE__ */ jsxRuntime.jsx("dd", { className: className || MessageUsageValueClass, ...props, children });
1763
+ //#endregion
1764
+ //#region src/agent/extractRunIdFromMessages.ts
1765
+ const isRecord = (value) => value !== null && typeof value === "object";
1766
+ const runIdMetadataKeys = [
1767
+ "pendingToolApprovals",
1768
+ "requireApprovalMetadata",
1769
+ "suspendedTools"
1770
+ ];
1771
+ const isRunIdMetadataSource = (value) => isRecord(value) && Object.values(value).every((entry) => isRecord(entry));
1772
+ const getRunIdMetadataSources = (metadata) => {
1773
+ if (!isRecord(metadata)) return [];
1774
+ const sources = [];
1775
+ for (const key of runIdMetadataKeys) {
1776
+ const source = metadata[key];
1777
+ if (isRunIdMetadataSource(source)) sources.push(source);
1778
+ }
1779
+ return sources;
1471
1780
  };
1472
- const MessageListClass = "mastra:overflow-y-auto mastra:h-full mastra-list";
1473
- const MessageList = ({ children, className, ...props }) => {
1474
- const listRef = react.useRef(null);
1475
- react.useEffect(() => {
1476
- const scrollToBottom = () => {
1477
- if (!listRef.current) return;
1478
- listRef.current.scrollTo({ top: listRef.current.scrollHeight, behavior: "smooth" });
1479
- };
1480
- requestAnimationFrame(scrollToBottom);
1481
- });
1482
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: className || MessageListClass, ...props, ref: listRef, children });
1781
+ /**
1782
+ * Scan initial DB-shape messages for any pending approvals, suspended tools, or
1783
+ * `requireApprovalMetadata` entries and return the first non-empty `runId`.
1784
+ *
1785
+ * Metadata is read off `message.content.metadata`, the canonical location for
1786
+ * MastraDBMessage UX hints.
1787
+ */
1788
+ const extractRunIdFromMessages = (messages) => {
1789
+ for (const message of messages) for (const source of getRunIdMetadataSources(message.content?.metadata)) for (const entry of Object.values(source)) if (isRecord(entry) && typeof entry.runId === "string" && entry.runId.length > 0) return entry.runId;
1483
1790
  };
1484
- const MessageStreamingClass = "mastra:inline-block mastra:w-[2px] mastra:h-[1em] mastra:bg-text5 mastra:ml-0.5 mastra:align-text-bottom mastra:animate-pulse";
1485
- const MessageStreaming = ({ className, ...props }) => {
1486
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: className || MessageStreamingClass, ...props });
1791
+ //#endregion
1792
+ //#region src/agent/hooks.ts
1793
+ const extractPendingToolApprovalIdsFromMessages = (messages) => {
1794
+ const pendingToolApprovalIds = /* @__PURE__ */ new Set();
1795
+ for (const message of messages) {
1796
+ const metadata = message.content?.metadata;
1797
+ if (!metadata) continue;
1798
+ const metadataSources = [
1799
+ metadata.pendingToolApprovals,
1800
+ metadata.requireApprovalMetadata,
1801
+ metadata.suspendedTools
1802
+ ];
1803
+ for (const source of metadataSources) {
1804
+ if (!source || typeof source !== "object") continue;
1805
+ for (const suspensionData of Object.values(source)) {
1806
+ const toolCallId = suspensionData?.toolCallId;
1807
+ if (typeof toolCallId === "string" && toolCallId.length > 0) pendingToolApprovalIds.add(toolCallId);
1808
+ }
1809
+ }
1810
+ }
1811
+ return pendingToolApprovalIds;
1487
1812
  };
1488
-
1489
- exports.AgentIcon = AgentIcon;
1490
- exports.CodeBlock = CodeBlock;
1491
- exports.CodeBlockClass = CodeBlockClass;
1492
- exports.CodeCopyButton = CodeCopyButton;
1493
- exports.Entity = Entity;
1494
- exports.EntityCaret = EntityCaret;
1495
- exports.EntityContent = EntityContent;
1496
- exports.EntityContentClass = EntityContentClass;
1497
- exports.EntityTrigger = EntityTrigger;
1498
- exports.EntityTriggerClass = EntityTriggerClass;
1499
- exports.EntityTriggerVariantClasses = EntityTriggerVariantClasses;
1500
- exports.Entry = Entry;
1501
- exports.EntryClass = EntryClass;
1502
- exports.EntryTitle = EntryTitle;
1503
- exports.EntryTitleClass = EntryTitleClass;
1504
- exports.Icon = Icon;
1505
- exports.IconButton = IconButton;
1506
- exports.IconButtonClass = IconButtonClass;
1507
- exports.IconSizes = IconSizes;
1813
+ const toolCallHasOutput = (parts, toolCallId) => parts.some((part) => {
1814
+ if (part.type !== "tool-invocation") return false;
1815
+ const invocation = part.toolInvocation;
1816
+ if (invocation.toolCallId !== toolCallId) return false;
1817
+ return invocation.state === "result" || invocation.result != null;
1818
+ });
1819
+ /**
1820
+ * Normalize persisted initial messages back into the stream-friendly shape the
1821
+ * UI renders from. Mirrors `main`'s `resolveInitialMessages`:
1822
+ *
1823
+ * - Converts persisted `pendingToolApprovals` (DB shape) into
1824
+ * `requireApprovalMetadata` (stream shape) so reloaded threads still render
1825
+ * approve/decline buttons, filtering out approvals whose tool already
1826
+ * produced output, and marks the message `mode: 'stream'`.
1827
+ * - Drops assistant completion messages flagged `suppressFeedback`, which are
1828
+ * persisted by the supervisor agent but must stay hidden on reload.
1829
+ */
1830
+ const resolveInitialMessages = (messages) => messages.filter((message) => {
1831
+ const metadata = message.content?.metadata;
1832
+ if (metadata?.completionResult?.suppressFeedback || metadata?.isTaskCompleteResult?.suppressFeedback) return false;
1833
+ return true;
1834
+ }).map((message) => {
1835
+ const metadata = message.content?.metadata;
1836
+ const normalizedMessage = metadata && (metadata.status === "pending" || "clientMessageId" in metadata) ? (() => {
1837
+ const { [CLIENT_MESSAGE_ID_KEY]: _omitClientMessageId, ...rest } = metadata;
1838
+ const { status: _omitStatus, ...restWithoutStatus } = rest;
1839
+ return {
1840
+ ...message,
1841
+ content: {
1842
+ ...message.content,
1843
+ metadata: metadata.status === "pending" ? restWithoutStatus : rest
1844
+ }
1845
+ };
1846
+ })() : message;
1847
+ const normalizedMetadata = normalizedMessage.content?.metadata;
1848
+ const pendingToolApprovals = normalizedMetadata?.pendingToolApprovals;
1849
+ if (!pendingToolApprovals || typeof pendingToolApprovals !== "object") return normalizedMessage;
1850
+ const stillPending = Object.fromEntries(Object.entries(pendingToolApprovals).filter(([, approval]) => approval && typeof approval === "object" && typeof approval.toolCallId === "string" && !toolCallHasOutput(normalizedMessage.content.parts, approval.toolCallId)));
1851
+ const { pendingToolApprovals: _omit, ...restMetadata } = normalizedMetadata;
1852
+ const hasStillPending = Object.keys(stillPending).length > 0;
1853
+ return {
1854
+ ...normalizedMessage,
1855
+ content: {
1856
+ ...normalizedMessage.content,
1857
+ metadata: {
1858
+ ...restMetadata,
1859
+ mode: "stream",
1860
+ ...hasStillPending ? {
1861
+ pendingToolApprovals: stillPending,
1862
+ requireApprovalMetadata: stillPending
1863
+ } : {}
1864
+ }
1865
+ }
1866
+ };
1867
+ });
1868
+ const isObject = (value) => typeof value === "object" && value !== null;
1869
+ const getErrorName = (error) => isObject(error) && typeof error.name === "string" ? error.name : void 0;
1870
+ const isAbortError = (error) => getErrorName(error) === "AbortError";
1871
+ const isThreadSignalUnsupportedError = (error) => {
1872
+ if (!isObject(error)) return false;
1873
+ const status = error.status;
1874
+ if (status === 404 || status === 405 || status === 501) return true;
1875
+ return status === 400 && typeof error.message === "string" && error.message.includes("No active agent run found for signal target");
1876
+ };
1877
+ const isDataChunk = (chunk) => typeof chunk.type === "string" && chunk.type.startsWith("data-");
1878
+ /**
1879
+ * Convert AI-SDK v5 UIMessages returned by the server (generate mode) into
1880
+ * `MastraDBMessage[]`, stamping the supplied metadata onto each message's
1881
+ * `content.metadata`. Private helper — `useChat` never exposes the AI-SDK
1882
+ * shape to consumers.
1883
+ */
1884
+ const dbFromServerUiMessages = (uiMessages, metadata) => uiMessages.map((uiMsg) => {
1885
+ const dbMsg = _mastra_core_agent_message_list.AIV5Adapter.fromUIMessage(uiMsg);
1886
+ return {
1887
+ ...dbMsg,
1888
+ content: {
1889
+ ...dbMsg.content,
1890
+ metadata: {
1891
+ ...dbMsg.content.metadata ?? {},
1892
+ ...metadata
1893
+ }
1894
+ }
1895
+ };
1896
+ });
1897
+ const useChat = ({ agentId, resourceId, threadId, initialMessages, requestContext: propsRequestContext, clientTools: hookClientTools, onSignalSent, onSignalEcho, onThreadSignalsUnsupported, enableThreadSignals = false }) => {
1898
+ const threadSignalsDisabled = enableThreadSignals === false;
1899
+ const _currentRunId = (0, react.useRef)(void 0);
1900
+ const _onChunk = (0, react.useRef)(void 0);
1901
+ const _networkRunId = (0, react.useRef)(void 0);
1902
+ const _onNetworkChunk = (0, react.useRef)(void 0);
1903
+ const _activeContinuation = (0, react.useRef)({ requestContext: propsRequestContext });
1904
+ const _streamAbortRef = (0, react.useRef)(null);
1905
+ const _threadSubscriptionAbortRef = (0, react.useRef)(null);
1906
+ const _threadSubscriptionRef = (0, react.useRef)(null);
1907
+ const _threadSubscriptionKeyRef = (0, react.useRef)(void 0);
1908
+ const _threadSubscriptionPromiseRef = (0, react.useRef)(null);
1909
+ const _threadSignalsUnsupportedRef = (0, react.useRef)(false);
1910
+ const [messages, setMessages] = (0, react.useState)([]);
1911
+ const [tasks, setTasks] = (0, react.useState)([]);
1912
+ const [toolCallApprovals, setToolCallApprovals] = (0, react.useState)({});
1913
+ const [networkToolCallApprovals, setNetworkToolCallApprovals] = (0, react.useState)({});
1914
+ const pendingToolApprovalIdsRef = (0, react.useRef)(/* @__PURE__ */ new Set());
1915
+ const [isAwaitingToolApproval, setIsAwaitingToolApproval] = (0, react.useState)(false);
1916
+ const baseClient = useMastraClient();
1917
+ const [isRunning, setIsRunning] = (0, react.useState)(false);
1918
+ (0, react.useEffect)(() => {
1919
+ const formattedMessages = resolveInitialMessages(initialMessages ?? []);
1920
+ setMessages(formattedMessages);
1921
+ setTasks(extractLatestTasksFromMessages(formattedMessages));
1922
+ pendingToolApprovalIdsRef.current = extractPendingToolApprovalIdsFromMessages(formattedMessages);
1923
+ setIsAwaitingToolApproval(pendingToolApprovalIdsRef.current.size > 0);
1924
+ _currentRunId.current = extractRunIdFromMessages(formattedMessages);
1925
+ }, [initialMessages]);
1926
+ (0, react.useEffect)(() => {
1927
+ _activeContinuation.current = {
1928
+ ..._activeContinuation.current,
1929
+ requestContext: propsRequestContext
1930
+ };
1931
+ }, [propsRequestContext]);
1932
+ const normalizeSignalFileData = (data) => {
1933
+ if (data instanceof URL) return data.toString();
1934
+ return convertSignalDataToBase64String(data);
1935
+ };
1936
+ const getSignalContents = (coreUserMessages) => {
1937
+ const parts = coreUserMessages.reduce((allParts, message) => {
1938
+ if (typeof message.content === "string") {
1939
+ allParts.push({
1940
+ type: "text",
1941
+ text: message.content
1942
+ });
1943
+ return allParts;
1944
+ }
1945
+ for (const part of message.content) if (part.type === "text") allParts.push({
1946
+ type: "text",
1947
+ text: part.text
1948
+ });
1949
+ else if (part.type === "file") allParts.push({
1950
+ type: "file",
1951
+ data: normalizeSignalFileData(part.data),
1952
+ mediaType: part.mimeType,
1953
+ ...part.filename ? { filename: part.filename } : {}
1954
+ });
1955
+ else if (part.type === "image") allParts.push({
1956
+ type: "file",
1957
+ data: normalizeSignalFileData(part.image),
1958
+ mediaType: part.mimeType ?? "image/png"
1959
+ });
1960
+ return allParts;
1961
+ }, []);
1962
+ return parts.length === 1 && parts[0]?.type === "text" ? parts[0].text : parts;
1963
+ };
1964
+ const markThreadSignalsUnsupported = (0, react.useCallback)(() => {
1965
+ _threadSignalsUnsupportedRef.current = true;
1966
+ onThreadSignalsUnsupported?.();
1967
+ }, [onThreadSignalsUnsupported]);
1968
+ const getSignalPreview = (coreUserMessages) => {
1969
+ return coreUserMessages.flatMap((message) => {
1970
+ if (typeof message.content === "string") return [message.content];
1971
+ return message.content.map((part) => {
1972
+ if (part.type === "text") return part.text;
1973
+ if (part.type === "image") return "Image";
1974
+ return part.filename ? `File: ${part.filename}` : "File";
1975
+ });
1976
+ }).join(" ").replace(/\s+/g, " ").trim() || "Attachment";
1977
+ };
1978
+ const closeThreadSubscription = (0, react.useCallback)(() => {
1979
+ const subscription = _threadSubscriptionRef.current;
1980
+ if (subscription?.unsubscribe) subscription.unsubscribe();
1981
+ else _threadSubscriptionAbortRef.current?.abort();
1982
+ _threadSubscriptionRef.current = null;
1983
+ _threadSubscriptionAbortRef.current = null;
1984
+ _threadSubscriptionKeyRef.current = void 0;
1985
+ _threadSubscriptionPromiseRef.current = null;
1986
+ }, []);
1987
+ const processStreamChunk = (0, react.useCallback)(async (chunk, onChunk) => {
1988
+ setMessages((prev) => accumulateChunk({
1989
+ chunk,
1990
+ conversation: prev,
1991
+ metadata: { mode: "stream" }
1992
+ }));
1993
+ const signalTasks = extractTasksFromSignalChunk(chunk);
1994
+ if (signalTasks !== void 0) setTasks(signalTasks);
1995
+ const toolTasks = extractTasksFromToolResultChunk(chunk);
1996
+ if (toolTasks !== void 0) setTasks(toolTasks);
1997
+ if (chunk.type === "data-user-message" && isDataChunk(chunk) && (chunk.data?.type === "user-message" || chunk.data?.type === "user") && typeof chunk.data?.id === "string") onSignalEcho?.(chunk.data.id);
1998
+ if (chunk.type === "start") {
1999
+ setIsRunning(true);
2000
+ if ("runId" in chunk && typeof chunk.runId === "string") _currentRunId.current = chunk.runId;
2001
+ }
2002
+ if (chunk.type === "tool-call-approval" || chunk.type === "tool-call-suspended") {
2003
+ const toolCallId = chunk.payload?.toolCallId;
2004
+ if (typeof toolCallId === "string") {
2005
+ pendingToolApprovalIdsRef.current.add(toolCallId);
2006
+ setIsAwaitingToolApproval(true);
2007
+ }
2008
+ setIsRunning(false);
2009
+ }
2010
+ if (chunk.type === "finish" || chunk.type === "abort" || chunk.type === "error") {
2011
+ pendingToolApprovalIdsRef.current.clear();
2012
+ setIsAwaitingToolApproval(false);
2013
+ setIsRunning(false);
2014
+ }
2015
+ (onChunk ?? _onChunk.current)?.(chunk);
2016
+ }, [onSignalEcho]);
2017
+ const ensureThreadSubscription = (0, react.useCallback)(async ({ threadId, resourceId }) => {
2018
+ const subscriptionKey = `${agentId}:${resourceId ?? ""}:${threadId}`;
2019
+ if (_threadSubscriptionKeyRef.current === subscriptionKey && _threadSubscriptionPromiseRef.current) {
2020
+ await _threadSubscriptionPromiseRef.current;
2021
+ return;
2022
+ }
2023
+ closeThreadSubscription();
2024
+ const subscriptionAbort = new AbortController();
2025
+ _threadSubscriptionAbortRef.current = subscriptionAbort;
2026
+ _threadSubscriptionKeyRef.current = subscriptionKey;
2027
+ const releaseSubscriptionRefs = () => {
2028
+ if (_threadSubscriptionAbortRef.current !== subscriptionAbort) return;
2029
+ _threadSubscriptionRef.current = null;
2030
+ _threadSubscriptionAbortRef.current = null;
2031
+ _threadSubscriptionKeyRef.current = void 0;
2032
+ _threadSubscriptionPromiseRef.current = null;
2033
+ };
2034
+ const subscriptionAgent = new _mastra_client_js.MastraClient({
2035
+ ...baseClient.options,
2036
+ abortSignal: subscriptionAbort.signal
2037
+ }).getAgent(agentId);
2038
+ _threadSubscriptionPromiseRef.current = subscriptionAgent.subscribeToThread({
2039
+ resourceId,
2040
+ threadId
2041
+ }).then((response) => {
2042
+ const subscription = response;
2043
+ if (_threadSubscriptionAbortRef.current !== subscriptionAbort) {
2044
+ subscription.unsubscribe();
2045
+ return;
2046
+ }
2047
+ _threadSubscriptionRef.current = subscription;
2048
+ subscription.processDataStream({ onChunk: (chunk) => processStreamChunk(chunk) }).catch((error) => {
2049
+ if (!isAbortError(error)) {
2050
+ console.error("[useChat] Thread subscription failed", error);
2051
+ setIsRunning(false);
2052
+ }
2053
+ }).finally(() => {
2054
+ if (_threadSubscriptionRef.current === subscription) _threadSubscriptionRef.current = null;
2055
+ releaseSubscriptionRefs();
2056
+ });
2057
+ }).catch((error) => {
2058
+ releaseSubscriptionRefs();
2059
+ if (isThreadSignalUnsupportedError(error)) {
2060
+ markThreadSignalsUnsupported();
2061
+ return;
2062
+ }
2063
+ if (!isAbortError(error)) {
2064
+ console.error("[useChat] Thread subscription failed", error);
2065
+ setIsRunning(false);
2066
+ }
2067
+ throw error;
2068
+ });
2069
+ await _threadSubscriptionPromiseRef.current;
2070
+ }, [
2071
+ agentId,
2072
+ baseClient,
2073
+ closeThreadSubscription,
2074
+ markThreadSignalsUnsupported,
2075
+ processStreamChunk
2076
+ ]);
2077
+ (0, react.useEffect)(() => {
2078
+ _threadSignalsUnsupportedRef.current = false;
2079
+ return closeThreadSubscription;
2080
+ }, [
2081
+ agentId,
2082
+ resourceId,
2083
+ threadId,
2084
+ closeThreadSubscription
2085
+ ]);
2086
+ (0, react.useEffect)(() => {
2087
+ if (!threadId || threadSignalsDisabled) {
2088
+ closeThreadSubscription();
2089
+ return;
2090
+ }
2091
+ ensureThreadSubscription({
2092
+ threadId,
2093
+ resourceId: resourceId || agentId
2094
+ }).catch((error) => {
2095
+ if (!isAbortError(error)) console.error("[useChat] Thread subscription failed", error);
2096
+ });
2097
+ }, [
2098
+ agentId,
2099
+ closeThreadSubscription,
2100
+ ensureThreadSubscription,
2101
+ resourceId,
2102
+ threadId,
2103
+ threadSignalsDisabled
2104
+ ]);
2105
+ const generate = async ({ coreUserMessages, model, requestContext, threadId, modelSettings, signal, onFinish, tracingOptions, clientTools }) => {
2106
+ const { frequencyPenalty, presencePenalty, maxRetries, maxTokens, temperature, topK, topP, instructions, providerOptions, maxSteps, requireToolApproval } = modelSettings || {};
2107
+ const resolvedRequestContext = requestContext ?? propsRequestContext;
2108
+ const resolvedClientTools = clientTools ?? hookClientTools;
2109
+ _activeContinuation.current = {
2110
+ model,
2111
+ requestContext: resolvedRequestContext
2112
+ };
2113
+ setIsRunning(true);
2114
+ const agent = new _mastra_client_js.MastraClient({
2115
+ ...baseClient.options,
2116
+ abortSignal: signal
2117
+ }).getAgent(agentId);
2118
+ const runId = (0, _lukeed_uuid.v4)();
2119
+ _currentRunId.current = runId;
2120
+ const response = await agent.generate(coreUserMessages, {
2121
+ model,
2122
+ runId,
2123
+ maxSteps,
2124
+ modelSettings: {
2125
+ frequencyPenalty,
2126
+ presencePenalty,
2127
+ maxRetries,
2128
+ maxOutputTokens: maxTokens,
2129
+ temperature,
2130
+ topK,
2131
+ topP
2132
+ },
2133
+ instructions,
2134
+ requestContext: resolvedRequestContext,
2135
+ ...threadId ? { memory: {
2136
+ thread: threadId,
2137
+ resource: resourceId || agentId
2138
+ } } : {},
2139
+ providerOptions,
2140
+ tracingOptions,
2141
+ requireToolApproval,
2142
+ clientTools: resolvedClientTools
2143
+ });
2144
+ if (response.finishReason === "suspended" && response.suspendPayload) {
2145
+ const { toolCallId, toolName, args } = response.suspendPayload;
2146
+ if (response.response?.uiMessages) {
2147
+ const dbMessages = dbFromServerUiMessages(response.response.uiMessages, {
2148
+ mode: "generate",
2149
+ requireApprovalMetadata: { [toolName]: {
2150
+ toolCallId,
2151
+ toolName,
2152
+ args
2153
+ } }
2154
+ });
2155
+ setMessages((prev) => [...prev, ...dbMessages]);
2156
+ }
2157
+ setIsRunning(false);
2158
+ return;
2159
+ }
2160
+ setIsRunning(false);
2161
+ if (response && "uiMessages" in response.response && response.response.uiMessages) {
2162
+ const dbMessages = dbFromServerUiMessages(response.response.uiMessages, { mode: "generate" });
2163
+ onFinish?.(dbMessages);
2164
+ setMessages((prev) => [...prev, ...dbMessages]);
2165
+ }
2166
+ };
2167
+ const stream = async ({ coreUserMessages, model, requestContext, threadId, onChunk, modelSettings, signal, tracingOptions, clientTools, signalId, clientMessageId }) => {
2168
+ const { frequencyPenalty, presencePenalty, maxRetries, maxTokens, temperature, topK, topP, instructions, providerOptions, maxSteps, requireToolApproval } = modelSettings || {};
2169
+ const resolvedRequestContext = requestContext ?? propsRequestContext;
2170
+ const resolvedClientTools = clientTools ?? hookClientTools;
2171
+ const signalContinuationOptions = {
2172
+ model,
2173
+ maxSteps,
2174
+ modelSettings: {
2175
+ frequencyPenalty,
2176
+ presencePenalty,
2177
+ maxRetries,
2178
+ maxOutputTokens: maxTokens,
2179
+ temperature,
2180
+ topK,
2181
+ topP
2182
+ },
2183
+ instructions,
2184
+ providerOptions,
2185
+ requireToolApproval,
2186
+ tracingOptions
2187
+ };
2188
+ _activeContinuation.current = {
2189
+ model,
2190
+ requestContext: resolvedRequestContext
2191
+ };
2192
+ setIsRunning(true);
2193
+ _streamAbortRef.current?.abort();
2194
+ const internalAbort = new AbortController();
2195
+ _streamAbortRef.current = internalAbort;
2196
+ if (signal) if (signal.aborted) internalAbort.abort();
2197
+ else signal.addEventListener("abort", () => internalAbort.abort(), { once: true });
2198
+ const agent = new _mastra_client_js.MastraClient({
2199
+ ...baseClient.options,
2200
+ abortSignal: internalAbort.signal
2201
+ }).getAgent(agentId);
2202
+ const streamWithLegacyRoute = async () => {
2203
+ const runId = (0, _lukeed_uuid.v4)();
2204
+ const response = await agent.stream(coreUserMessages, {
2205
+ model,
2206
+ runId,
2207
+ maxSteps,
2208
+ untilIdle: true,
2209
+ modelSettings: {
2210
+ frequencyPenalty,
2211
+ presencePenalty,
2212
+ maxRetries,
2213
+ maxOutputTokens: maxTokens,
2214
+ temperature,
2215
+ topK,
2216
+ topP
2217
+ },
2218
+ instructions,
2219
+ requestContext: resolvedRequestContext,
2220
+ ...threadId ? { memory: {
2221
+ thread: threadId,
2222
+ resource: resourceId || agentId
2223
+ } } : {},
2224
+ providerOptions,
2225
+ requireToolApproval,
2226
+ tracingOptions,
2227
+ clientTools: resolvedClientTools
2228
+ });
2229
+ _onChunk.current = onChunk;
2230
+ _currentRunId.current = runId;
2231
+ await response.processDataStream({ onChunk: (chunk) => processStreamChunk(chunk, onChunk) });
2232
+ if (_streamAbortRef.current === internalAbort) _streamAbortRef.current = null;
2233
+ setIsRunning(false);
2234
+ };
2235
+ if (!threadId || _threadSignalsUnsupportedRef.current || threadSignalsDisabled) {
2236
+ await streamWithLegacyRoute();
2237
+ return;
2238
+ }
2239
+ _onChunk.current = onChunk;
2240
+ await ensureThreadSubscription({
2241
+ threadId,
2242
+ resourceId: resourceId || agentId
2243
+ });
2244
+ if (_threadSignalsUnsupportedRef.current) {
2245
+ await streamWithLegacyRoute();
2246
+ return;
2247
+ }
2248
+ const resolvedSignalId = signalId ?? (0, _lukeed_uuid.v4)();
2249
+ const messageContents = getSignalContents(coreUserMessages);
2250
+ const requestContextRecord = resolvedRequestContext;
2251
+ const streamOptions = {
2252
+ model,
2253
+ maxSteps,
2254
+ modelSettings: {
2255
+ frequencyPenalty,
2256
+ presencePenalty,
2257
+ maxRetries,
2258
+ maxOutputTokens: maxTokens,
2259
+ temperature,
2260
+ topK,
2261
+ topP
2262
+ },
2263
+ instructions,
2264
+ requestContext: requestContextRecord,
2265
+ providerOptions,
2266
+ requireToolApproval,
2267
+ tracingOptions
2268
+ };
2269
+ try {
2270
+ const result = await agent.sendMessage({
2271
+ message: clientMessageId ? {
2272
+ contents: messageContents,
2273
+ metadata: { [CLIENT_MESSAGE_ID_KEY]: clientMessageId }
2274
+ } : messageContents,
2275
+ resourceId: resourceId || agentId,
2276
+ threadId,
2277
+ ifIdle: { streamOptions: {
2278
+ ...signalContinuationOptions,
2279
+ requestContext: requestContextRecord,
2280
+ clientTools: resolvedClientTools
2281
+ } }
2282
+ });
2283
+ const echoedSignalId = result.signal && typeof result.signal === "object" && "id" in result.signal && typeof result.signal.id === "string" ? result.signal.id : resolvedSignalId;
2284
+ onSignalSent?.(echoedSignalId, getSignalPreview(coreUserMessages));
2285
+ if (pendingToolApprovalIdsRef.current.size > 0) setIsRunning(false);
2286
+ } catch (error) {
2287
+ if (isThreadSignalUnsupportedError(error)) {
2288
+ onSignalSent?.(resolvedSignalId, getSignalPreview(coreUserMessages));
2289
+ try {
2290
+ await agent.sendSignal({
2291
+ signal: {
2292
+ id: resolvedSignalId,
2293
+ type: "user-message",
2294
+ contents: messageContents
2295
+ },
2296
+ resourceId: resourceId || agentId,
2297
+ threadId,
2298
+ ifIdle: { streamOptions }
2299
+ });
2300
+ return;
2301
+ } catch (signalError) {
2302
+ onSignalEcho?.(resolvedSignalId);
2303
+ if (isThreadSignalUnsupportedError(signalError)) {
2304
+ markThreadSignalsUnsupported();
2305
+ setMessages((prev) => [...prev, fromCoreUserMessagesToMastraDBMessage(coreUserMessages)]);
2306
+ await streamWithLegacyRoute();
2307
+ return;
2308
+ }
2309
+ throw signalError;
2310
+ }
2311
+ }
2312
+ throw error;
2313
+ }
2314
+ if (_streamAbortRef.current === internalAbort) _streamAbortRef.current = null;
2315
+ };
2316
+ const network = async ({ coreUserMessages, model, requestContext, threadId, onNetworkChunk, modelSettings, signal, tracingOptions }) => {
2317
+ const { frequencyPenalty, presencePenalty, maxRetries, maxTokens, temperature, topK, topP, maxSteps } = modelSettings || {};
2318
+ const resolvedRequestContext = requestContext ?? propsRequestContext;
2319
+ _activeContinuation.current = {
2320
+ model,
2321
+ requestContext: resolvedRequestContext
2322
+ };
2323
+ setIsRunning(true);
2324
+ const agent = new _mastra_client_js.MastraClient({
2325
+ ...baseClient.options,
2326
+ abortSignal: signal
2327
+ }).getAgent(agentId);
2328
+ const runId = (0, _lukeed_uuid.v4)();
2329
+ const response = await agent.network(coreUserMessages, {
2330
+ model,
2331
+ maxSteps,
2332
+ modelSettings: {
2333
+ frequencyPenalty,
2334
+ presencePenalty,
2335
+ maxRetries,
2336
+ maxOutputTokens: maxTokens,
2337
+ temperature,
2338
+ topK,
2339
+ topP
2340
+ },
2341
+ runId,
2342
+ requestContext: resolvedRequestContext,
2343
+ ...threadId ? { memory: {
2344
+ thread: threadId,
2345
+ resource: resourceId || agentId
2346
+ } } : {},
2347
+ tracingOptions
2348
+ });
2349
+ _onNetworkChunk.current = onNetworkChunk;
2350
+ _networkRunId.current = runId;
2351
+ await response.processDataStream({ onChunk: async (chunk) => {
2352
+ setMessages((prev) => accumulateNetworkChunk({
2353
+ chunk,
2354
+ conversation: prev,
2355
+ metadata: { mode: "network" }
2356
+ }));
2357
+ onNetworkChunk?.(chunk);
2358
+ } });
2359
+ setMessages((prev) => finishStreamingAssistantMessage(prev));
2360
+ setIsRunning(false);
2361
+ };
2362
+ const handleCancelRun = () => {
2363
+ _streamAbortRef.current?.abort();
2364
+ _streamAbortRef.current = null;
2365
+ const threadSubscription = _threadSubscriptionRef.current;
2366
+ Promise.resolve(threadSubscription?.abort?.()).catch((error) => {
2367
+ console.error("[useChat] Failed to abort thread subscription", error);
2368
+ });
2369
+ closeThreadSubscription();
2370
+ setMessages((prev) => finishStreamingAssistantMessage(prev));
2371
+ pendingToolApprovalIdsRef.current.clear();
2372
+ setIsAwaitingToolApproval(false);
2373
+ setIsRunning(false);
2374
+ _currentRunId.current = void 0;
2375
+ _onChunk.current = void 0;
2376
+ _networkRunId.current = void 0;
2377
+ _onNetworkChunk.current = void 0;
2378
+ _activeContinuation.current = {};
2379
+ };
2380
+ const approveToolCall = async (toolCallId, resumeData) => {
2381
+ const onChunk = _onChunk.current;
2382
+ const currentRunId = _currentRunId.current;
2383
+ const continuation = _activeContinuation.current;
2384
+ if (!currentRunId) return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
2385
+ setIsRunning(true);
2386
+ setToolCallApprovals((prev) => ({
2387
+ ...prev,
2388
+ [toolCallId]: { status: "approved" }
2389
+ }));
2390
+ const agent = baseClient.getAgent(agentId);
2391
+ if (_threadSubscriptionKeyRef.current && threadId) {
2392
+ try {
2393
+ await agent.sendToolApproval({
2394
+ resourceId: resourceId || agentId,
2395
+ threadId,
2396
+ toolCallId,
2397
+ approved: true,
2398
+ ...continuation.model !== void 0 ? { streamOptions: { model: continuation.model } } : {},
2399
+ ...resumeData !== void 0 ? { resumeData } : {},
2400
+ requestContext: continuation.requestContext
2401
+ });
2402
+ pendingToolApprovalIdsRef.current.delete(toolCallId);
2403
+ setIsAwaitingToolApproval(pendingToolApprovalIdsRef.current.size > 0);
2404
+ setIsRunning(false);
2405
+ } catch (error) {
2406
+ setToolCallApprovals((prev) => {
2407
+ const next = { ...prev };
2408
+ delete next[toolCallId];
2409
+ return next;
2410
+ });
2411
+ setIsRunning(false);
2412
+ throw error;
2413
+ }
2414
+ return;
2415
+ }
2416
+ await (await agent.approveToolCall({
2417
+ runId: currentRunId,
2418
+ toolCallId,
2419
+ ...continuation
2420
+ })).processDataStream({ onChunk: async (chunk) => {
2421
+ await processStreamChunk(chunk, onChunk);
2422
+ } });
2423
+ setIsRunning(false);
2424
+ };
2425
+ const declineToolCall = async (toolCallId) => {
2426
+ const onChunk = _onChunk.current;
2427
+ const currentRunId = _currentRunId.current;
2428
+ const continuation = _activeContinuation.current;
2429
+ if (!currentRunId) return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
2430
+ setIsRunning(true);
2431
+ setToolCallApprovals((prev) => ({
2432
+ ...prev,
2433
+ [toolCallId]: { status: "declined" }
2434
+ }));
2435
+ const agent = baseClient.getAgent(agentId);
2436
+ if (_threadSubscriptionKeyRef.current && threadId) {
2437
+ try {
2438
+ await agent.sendToolApproval({
2439
+ resourceId: resourceId || agentId,
2440
+ threadId,
2441
+ toolCallId,
2442
+ approved: false,
2443
+ ...continuation.model !== void 0 ? { streamOptions: { model: continuation.model } } : {},
2444
+ requestContext: continuation.requestContext
2445
+ });
2446
+ pendingToolApprovalIdsRef.current.delete(toolCallId);
2447
+ setIsAwaitingToolApproval(pendingToolApprovalIdsRef.current.size > 0);
2448
+ setIsRunning(false);
2449
+ } catch (error) {
2450
+ setToolCallApprovals((prev) => {
2451
+ const next = { ...prev };
2452
+ delete next[toolCallId];
2453
+ return next;
2454
+ });
2455
+ setIsRunning(false);
2456
+ throw error;
2457
+ }
2458
+ return;
2459
+ }
2460
+ await (await agent.declineToolCall({
2461
+ runId: currentRunId,
2462
+ toolCallId,
2463
+ ...continuation
2464
+ })).processDataStream({ onChunk: async (chunk) => {
2465
+ await processStreamChunk(chunk, onChunk);
2466
+ } });
2467
+ setIsRunning(false);
2468
+ };
2469
+ const approveToolCallGenerate = async (toolCallId) => {
2470
+ const currentRunId = _currentRunId.current;
2471
+ const continuation = _activeContinuation.current;
2472
+ if (!currentRunId) return console.info("[approveToolCallGenerate] approveToolCallGenerate can only be called after a generate has started");
2473
+ setIsRunning(true);
2474
+ setToolCallApprovals((prev) => ({
2475
+ ...prev,
2476
+ [toolCallId]: { status: "approved" }
2477
+ }));
2478
+ const response = await baseClient.getAgent(agentId).approveToolCallGenerate({
2479
+ runId: currentRunId,
2480
+ toolCallId,
2481
+ ...continuation
2482
+ });
2483
+ if (response && "uiMessages" in response.response && response.response.uiMessages) {
2484
+ const dbMessages = dbFromServerUiMessages(response.response.uiMessages, { mode: "generate" });
2485
+ setMessages((prev) => [...prev, ...dbMessages]);
2486
+ }
2487
+ setIsRunning(false);
2488
+ };
2489
+ const declineToolCallGenerate = async (toolCallId) => {
2490
+ const currentRunId = _currentRunId.current;
2491
+ const continuation = _activeContinuation.current;
2492
+ if (!currentRunId) return console.info("[declineToolCallGenerate] declineToolCallGenerate can only be called after a generate has started");
2493
+ setIsRunning(true);
2494
+ setToolCallApprovals((prev) => ({
2495
+ ...prev,
2496
+ [toolCallId]: { status: "declined" }
2497
+ }));
2498
+ const response = await baseClient.getAgent(agentId).declineToolCallGenerate({
2499
+ runId: currentRunId,
2500
+ toolCallId,
2501
+ ...continuation
2502
+ });
2503
+ if (response && "uiMessages" in response.response && response.response.uiMessages) {
2504
+ const dbMessages = dbFromServerUiMessages(response.response.uiMessages, { mode: "generate" });
2505
+ setMessages((prev) => [...prev, ...dbMessages]);
2506
+ }
2507
+ setIsRunning(false);
2508
+ };
2509
+ const approveNetworkToolCall = async (toolName, runId) => {
2510
+ const onNetworkChunk = _onNetworkChunk.current;
2511
+ const networkRunId = runId || _networkRunId.current;
2512
+ const continuation = _activeContinuation.current;
2513
+ if (!networkRunId) return console.info("[approveNetworkToolCall] approveNetworkToolCall can only be called after a network stream has started");
2514
+ setIsRunning(true);
2515
+ setNetworkToolCallApprovals((prev) => ({
2516
+ ...prev,
2517
+ [runId ? `${runId}-${toolName}` : toolName]: { status: "approved" }
2518
+ }));
2519
+ await (await baseClient.getAgent(agentId).approveNetworkToolCall({
2520
+ runId: networkRunId,
2521
+ ...continuation
2522
+ })).processDataStream({ onChunk: async (chunk) => {
2523
+ setMessages((prev) => accumulateNetworkChunk({
2524
+ chunk,
2525
+ conversation: prev,
2526
+ metadata: { mode: "network" }
2527
+ }));
2528
+ onNetworkChunk?.(chunk);
2529
+ } });
2530
+ setMessages((prev) => finishStreamingAssistantMessage(prev));
2531
+ setIsRunning(false);
2532
+ };
2533
+ const declineNetworkToolCall = async (toolName, runId) => {
2534
+ const onNetworkChunk = _onNetworkChunk.current;
2535
+ const networkRunId = runId || _networkRunId.current;
2536
+ const continuation = _activeContinuation.current;
2537
+ if (!networkRunId) return console.info("[declineNetworkToolCall] declineNetworkToolCall can only be called after a network stream has started");
2538
+ setIsRunning(true);
2539
+ setNetworkToolCallApprovals((prev) => ({
2540
+ ...prev,
2541
+ [runId ? `${runId}-${toolName}` : toolName]: { status: "declined" }
2542
+ }));
2543
+ await (await baseClient.getAgent(agentId).declineNetworkToolCall({
2544
+ runId: networkRunId,
2545
+ ...continuation
2546
+ })).processDataStream({ onChunk: async (chunk) => {
2547
+ setMessages((prev) => accumulateNetworkChunk({
2548
+ chunk,
2549
+ conversation: prev,
2550
+ metadata: { mode: "network" }
2551
+ }));
2552
+ onNetworkChunk?.(chunk);
2553
+ } });
2554
+ setMessages((prev) => finishStreamingAssistantMessage(prev));
2555
+ setIsRunning(false);
2556
+ };
2557
+ const sendMessage = async ({ mode = "stream", ...args }) => {
2558
+ const coreUserMessages = [{
2559
+ role: "user",
2560
+ content: [{
2561
+ type: "text",
2562
+ text: args.message
2563
+ }]
2564
+ }];
2565
+ if (args.coreUserMessages) coreUserMessages.push(...args.coreUserMessages);
2566
+ const dbUserMessage = fromCoreUserMessagesToMastraDBMessage(coreUserMessages);
2567
+ const clientSetId = mode === "stream" && args.threadId && !_threadSignalsUnsupportedRef.current && !threadSignalsDisabled ? `client-set-${(0, _lukeed_uuid.v4)()}` : void 0;
2568
+ const signalId = clientSetId;
2569
+ const clientMessageId = clientSetId;
2570
+ if (signalId) {
2571
+ const metadata = {
2572
+ ...dbUserMessage.content.metadata,
2573
+ mode: "stream",
2574
+ status: "pending",
2575
+ [CLIENT_MESSAGE_ID_KEY]: clientMessageId
2576
+ };
2577
+ const pendingMessage = {
2578
+ ...dbUserMessage,
2579
+ id: clientSetId,
2580
+ content: {
2581
+ ...dbUserMessage.content,
2582
+ metadata
2583
+ }
2584
+ };
2585
+ setMessages((s) => [...s, pendingMessage]);
2586
+ } else setMessages((s) => [...s, dbUserMessage]);
2587
+ try {
2588
+ if (mode === "generate") await generate({
2589
+ ...args,
2590
+ coreUserMessages
2591
+ });
2592
+ else if (mode === "stream") await stream({
2593
+ ...args,
2594
+ coreUserMessages,
2595
+ signalId,
2596
+ clientMessageId
2597
+ });
2598
+ else if (mode === "network") await network({
2599
+ ...args,
2600
+ coreUserMessages
2601
+ });
2602
+ } catch (error) {
2603
+ setIsRunning(false);
2604
+ throw error;
2605
+ }
2606
+ };
2607
+ return {
2608
+ setMessages,
2609
+ sendMessage,
2610
+ isRunning,
2611
+ isAwaitingToolApproval,
2612
+ messages,
2613
+ tasks,
2614
+ approveToolCall,
2615
+ declineToolCall,
2616
+ approveToolCallGenerate,
2617
+ declineToolCallGenerate,
2618
+ cancelRun: handleCancelRun,
2619
+ toolCallApprovals,
2620
+ approveNetworkToolCall,
2621
+ declineNetworkToolCall,
2622
+ networkToolCallApprovals
2623
+ };
2624
+ };
2625
+ //#endregion
2626
+ //#region src/lib/use-mutation.ts
2627
+ /**
2628
+ * Internal helper hook that provides mutation-like functionality without react-query.
2629
+ * Tracks pending, success, and error states for async operations.
2630
+ */
2631
+ function useMutation(mutationFn) {
2632
+ const [isPending, setIsPending] = (0, react.useState)(false);
2633
+ const [isSuccess, setIsSuccess] = (0, react.useState)(false);
2634
+ const [isError, setIsError] = (0, react.useState)(false);
2635
+ const [error, setError] = (0, react.useState)(null);
2636
+ const [data, setData] = (0, react.useState)(void 0);
2637
+ const mutationFnRef = (0, react.useRef)(mutationFn);
2638
+ mutationFnRef.current = mutationFn;
2639
+ const reset = (0, react.useCallback)(() => {
2640
+ setIsPending(false);
2641
+ setIsSuccess(false);
2642
+ setIsError(false);
2643
+ setError(null);
2644
+ setData(void 0);
2645
+ }, []);
2646
+ const mutateAsync = (0, react.useCallback)(async (variables) => {
2647
+ setIsPending(true);
2648
+ setIsSuccess(false);
2649
+ setIsError(false);
2650
+ setError(null);
2651
+ try {
2652
+ const result = await mutationFnRef.current(variables);
2653
+ setData(result);
2654
+ setIsSuccess(true);
2655
+ return result;
2656
+ } catch (err) {
2657
+ setError(err);
2658
+ setIsError(true);
2659
+ throw err;
2660
+ } finally {
2661
+ setIsPending(false);
2662
+ }
2663
+ }, []);
2664
+ return {
2665
+ mutate: (0, react.useCallback)((variables) => {
2666
+ mutateAsync(variables).catch(() => {});
2667
+ }, [mutateAsync]),
2668
+ mutateAsync,
2669
+ isPending,
2670
+ isSuccess,
2671
+ isError,
2672
+ error,
2673
+ data,
2674
+ reset
2675
+ };
2676
+ }
2677
+ //#endregion
2678
+ //#region src/workflows/use-stream-workflow.ts
2679
+ /**
2680
+ * Hook for streaming workflow execution with support for observing, resuming, and time-travel.
2681
+ *
2682
+ * @example
2683
+ * ```tsx
2684
+ * const {
2685
+ * streamWorkflow,
2686
+ * streamResult,
2687
+ * isStreaming,
2688
+ * observeWorkflowStream,
2689
+ * closeStreamsAndReset,
2690
+ * resumeWorkflowStream,
2691
+ * timeTravelWorkflowStream,
2692
+ * } = useStreamWorkflow({
2693
+ * debugMode: true,
2694
+ * tracingOptions: { enabled: true },
2695
+ * onError: (error, defaultMessage) => console.error(defaultMessage, error),
2696
+ * });
2697
+ *
2698
+ * // Start streaming a workflow
2699
+ * await streamWorkflow.mutateAsync({
2700
+ * workflowId: 'my-workflow',
2701
+ * runId: 'run-123',
2702
+ * inputData: { key: 'value' },
2703
+ * requestContext: {},
2704
+ * });
2705
+ * ```
2706
+ */
2707
+ function useStreamWorkflow({ debugMode, tracingOptions, onError }) {
2708
+ const client = useMastraClient();
2709
+ const [streamResult, setStreamResult] = (0, react.useState)({});
2710
+ const [isStreaming, setIsStreaming] = (0, react.useState)(false);
2711
+ const readerRef = (0, react.useRef)(null);
2712
+ const observerRef = (0, react.useRef)(null);
2713
+ const resumeStreamRef = (0, react.useRef)(null);
2714
+ const timeTravelStreamRef = (0, react.useRef)(null);
2715
+ const isMountedRef = (0, react.useRef)(true);
2716
+ (0, react.useEffect)(() => {
2717
+ isMountedRef.current = true;
2718
+ return () => {
2719
+ isMountedRef.current = false;
2720
+ if (readerRef.current) {
2721
+ try {
2722
+ readerRef.current.releaseLock();
2723
+ } catch {}
2724
+ readerRef.current = null;
2725
+ }
2726
+ if (observerRef.current) {
2727
+ try {
2728
+ observerRef.current.releaseLock();
2729
+ } catch {}
2730
+ observerRef.current = null;
2731
+ }
2732
+ if (resumeStreamRef.current) {
2733
+ try {
2734
+ resumeStreamRef.current.releaseLock();
2735
+ } catch {}
2736
+ resumeStreamRef.current = null;
2737
+ }
2738
+ if (timeTravelStreamRef.current) {
2739
+ try {
2740
+ timeTravelStreamRef.current.releaseLock();
2741
+ } catch {}
2742
+ timeTravelStreamRef.current = null;
2743
+ }
2744
+ };
2745
+ }, []);
2746
+ const handleStreamError = (0, react.useCallback)((err, defaultMessage, setStreamingState) => {
2747
+ if (err instanceof TypeError) return;
2748
+ const error = err instanceof Error ? err : new Error(defaultMessage);
2749
+ onError?.(error, defaultMessage);
2750
+ setStreamingState?.(false);
2751
+ }, [onError]);
2752
+ const handleWorkflowFinish = (0, react.useCallback)((value) => {
2753
+ if (value.type === "workflow-finish") {
2754
+ const streamStatus = value.payload?.workflowStatus;
2755
+ const metadata = value.payload?.metadata;
2756
+ setStreamResult((prev) => ({
2757
+ ...prev,
2758
+ status: streamStatus
2759
+ }));
2760
+ if (streamStatus === "failed") throw new Error(metadata?.errorMessage || "Workflow execution failed");
2761
+ }
2762
+ }, []);
2763
+ const streamWorkflow = useMutation(async ({ workflowId, runId, inputData, initialState, requestContext: playgroundRequestContext, perStep }) => {
2764
+ if (readerRef.current) readerRef.current.releaseLock();
2765
+ if (!isMountedRef.current) return;
2766
+ setIsStreaming(true);
2767
+ setStreamResult({ input: inputData });
2768
+ const stream = await (await client.getWorkflow(workflowId).createRun({ runId })).stream({
2769
+ inputData,
2770
+ initialState,
2771
+ requestContext: playgroundRequestContext,
2772
+ closeOnSuspend: true,
2773
+ tracingOptions,
2774
+ perStep: perStep ?? debugMode
2775
+ });
2776
+ if (!stream) return handleStreamError(/* @__PURE__ */ new Error("No stream returned"), "No stream returned", setIsStreaming);
2777
+ const reader = stream.getReader();
2778
+ readerRef.current = reader;
2779
+ try {
2780
+ while (true) {
2781
+ if (!isMountedRef.current) break;
2782
+ const { done, value } = await reader.read();
2783
+ if (done) break;
2784
+ if (isMountedRef.current) {
2785
+ setStreamResult((prev) => {
2786
+ return mapWorkflowStreamChunkToWatchResult(prev, value);
2787
+ });
2788
+ if (value.type === "workflow-step-start") setIsStreaming(true);
2789
+ if (value.type === "workflow-step-suspended") setIsStreaming(false);
2790
+ if (value.type === "workflow-finish") handleWorkflowFinish(value);
2791
+ }
2792
+ }
2793
+ } catch (err) {
2794
+ handleStreamError(err, "Error streaming workflow");
2795
+ } finally {
2796
+ if (isMountedRef.current) setIsStreaming(false);
2797
+ if (readerRef.current) {
2798
+ readerRef.current.releaseLock();
2799
+ readerRef.current = null;
2800
+ }
2801
+ }
2802
+ });
2803
+ const observeWorkflowStream = useMutation(async ({ workflowId, runId, storeRunResult }) => {
2804
+ if (observerRef.current) observerRef.current.releaseLock();
2805
+ if (!isMountedRef.current) return;
2806
+ setIsStreaming(true);
2807
+ setStreamResult(storeRunResult || {});
2808
+ if (storeRunResult?.status === "suspended") {
2809
+ setIsStreaming(false);
2810
+ return;
2811
+ }
2812
+ const stream = await (await client.getWorkflow(workflowId).createRun({ runId })).observeStream();
2813
+ if (!stream) return handleStreamError(/* @__PURE__ */ new Error("No stream returned"), "No stream returned", setIsStreaming);
2814
+ const reader = stream.getReader();
2815
+ observerRef.current = reader;
2816
+ try {
2817
+ while (true) {
2818
+ if (!isMountedRef.current) break;
2819
+ const { done, value } = await reader.read();
2820
+ if (done) break;
2821
+ if (isMountedRef.current) {
2822
+ setStreamResult((prev) => {
2823
+ return mapWorkflowStreamChunkToWatchResult(prev, value);
2824
+ });
2825
+ if (value.type === "workflow-step-start") setIsStreaming(true);
2826
+ if (value.type === "workflow-step-suspended") setIsStreaming(false);
2827
+ if (value.type === "workflow-finish") handleWorkflowFinish(value);
2828
+ }
2829
+ }
2830
+ } catch (err) {
2831
+ handleStreamError(err, "Error observing workflow");
2832
+ } finally {
2833
+ if (isMountedRef.current) setIsStreaming(false);
2834
+ if (observerRef.current) {
2835
+ observerRef.current.releaseLock();
2836
+ observerRef.current = null;
2837
+ }
2838
+ }
2839
+ });
2840
+ const resumeWorkflowStream = useMutation(async ({ workflowId, runId, step, resumeData, requestContext: playgroundRequestContext, perStep }) => {
2841
+ if (resumeStreamRef.current) resumeStreamRef.current.releaseLock();
2842
+ if (!isMountedRef.current) return;
2843
+ setIsStreaming(true);
2844
+ const stream = await (await client.getWorkflow(workflowId).createRun({ runId })).resumeStream({
2845
+ step,
2846
+ resumeData,
2847
+ requestContext: playgroundRequestContext,
2848
+ tracingOptions,
2849
+ perStep: perStep ?? debugMode
2850
+ });
2851
+ if (!stream) return handleStreamError(/* @__PURE__ */ new Error("No stream returned"), "No stream returned", setIsStreaming);
2852
+ const reader = stream.getReader();
2853
+ resumeStreamRef.current = reader;
2854
+ try {
2855
+ while (true) {
2856
+ if (!isMountedRef.current) break;
2857
+ const { done, value } = await reader.read();
2858
+ if (done) break;
2859
+ if (isMountedRef.current) {
2860
+ setStreamResult((prev) => {
2861
+ return mapWorkflowStreamChunkToWatchResult(prev, value);
2862
+ });
2863
+ if (value.type === "workflow-step-start") setIsStreaming(true);
2864
+ if (value.type === "workflow-step-suspended") setIsStreaming(false);
2865
+ if (value.type === "workflow-finish") handleWorkflowFinish(value);
2866
+ }
2867
+ }
2868
+ } catch (err) {
2869
+ handleStreamError(err, "Error resuming workflow stream");
2870
+ } finally {
2871
+ if (isMountedRef.current) setIsStreaming(false);
2872
+ if (resumeStreamRef.current) {
2873
+ resumeStreamRef.current.releaseLock();
2874
+ resumeStreamRef.current = null;
2875
+ }
2876
+ }
2877
+ });
2878
+ const timeTravelWorkflowStream = useMutation(async ({ workflowId, requestContext: playgroundRequestContext, runId, perStep, ...params }) => {
2879
+ if (timeTravelStreamRef.current) timeTravelStreamRef.current.releaseLock();
2880
+ if (!isMountedRef.current) return;
2881
+ setIsStreaming(true);
2882
+ const stream = await (await client.getWorkflow(workflowId).createRun({ runId })).timeTravelStream({
2883
+ ...params,
2884
+ perStep: perStep ?? debugMode,
2885
+ requestContext: playgroundRequestContext,
2886
+ tracingOptions
2887
+ });
2888
+ if (!stream) return handleStreamError(/* @__PURE__ */ new Error("No stream returned"), "No stream returned", setIsStreaming);
2889
+ const reader = stream.getReader();
2890
+ timeTravelStreamRef.current = reader;
2891
+ try {
2892
+ while (true) {
2893
+ if (!isMountedRef.current) break;
2894
+ const { done, value } = await reader.read();
2895
+ if (done) break;
2896
+ if (isMountedRef.current) {
2897
+ setStreamResult((prev) => {
2898
+ return mapWorkflowStreamChunkToWatchResult(prev, value);
2899
+ });
2900
+ if (value.type === "workflow-step-start") setIsStreaming(true);
2901
+ if (value.type === "workflow-step-suspended") setIsStreaming(false);
2902
+ if (value.type === "workflow-finish") handleWorkflowFinish(value);
2903
+ }
2904
+ }
2905
+ } catch (err) {
2906
+ handleStreamError(err, "Error time traveling workflow stream");
2907
+ } finally {
2908
+ if (isMountedRef.current) setIsStreaming(false);
2909
+ if (timeTravelStreamRef.current) {
2910
+ timeTravelStreamRef.current.releaseLock();
2911
+ timeTravelStreamRef.current = null;
2912
+ }
2913
+ }
2914
+ });
2915
+ return {
2916
+ streamWorkflow,
2917
+ streamResult,
2918
+ isStreaming,
2919
+ observeWorkflowStream,
2920
+ closeStreamsAndReset: (0, react.useCallback)(() => {
2921
+ setIsStreaming(false);
2922
+ setStreamResult({});
2923
+ if (readerRef.current) {
2924
+ try {
2925
+ readerRef.current.releaseLock();
2926
+ } catch {}
2927
+ readerRef.current = null;
2928
+ }
2929
+ if (observerRef.current) {
2930
+ try {
2931
+ observerRef.current.releaseLock();
2932
+ } catch {}
2933
+ observerRef.current = null;
2934
+ }
2935
+ if (resumeStreamRef.current) {
2936
+ try {
2937
+ resumeStreamRef.current.releaseLock();
2938
+ } catch {}
2939
+ resumeStreamRef.current = null;
2940
+ }
2941
+ if (timeTravelStreamRef.current) {
2942
+ try {
2943
+ timeTravelStreamRef.current.releaseLock();
2944
+ } catch {}
2945
+ timeTravelStreamRef.current = null;
2946
+ }
2947
+ }, []),
2948
+ resumeWorkflowStream,
2949
+ timeTravelWorkflowStream
2950
+ };
2951
+ }
2952
+ //#endregion
2953
+ //#region src/workflows/hooks.ts
2954
+ /**
2955
+ * Hook for creating workflow runs.
2956
+ * Returns a mutation for creating a new workflow run.
2957
+ *
2958
+ * @example
2959
+ * ```tsx
2960
+ * const createWorkflowRun = useCreateWorkflowRun();
2961
+ *
2962
+ * // Create a run
2963
+ * const { runId } = await createWorkflowRun.mutateAsync({
2964
+ * workflowId: 'my-workflow'
2965
+ * });
2966
+ * ```
2967
+ */
2968
+ function useCreateWorkflowRun() {
2969
+ const client = useMastraClient();
2970
+ return useMutation(async ({ workflowId, prevRunId }) => {
2971
+ try {
2972
+ const { runId: newRunId } = await client.getWorkflow(workflowId).createRun({ runId: prevRunId });
2973
+ return { runId: newRunId };
2974
+ } catch (error) {
2975
+ console.error("Error creating workflow run:", error);
2976
+ throw error;
2977
+ }
2978
+ });
2979
+ }
2980
+ /**
2981
+ * Hook for canceling workflow runs.
2982
+ * Returns a mutation for canceling a running workflow.
2983
+ *
2984
+ * @example
2985
+ * ```tsx
2986
+ * const cancelWorkflowRun = useCancelWorkflowRun();
2987
+ *
2988
+ * // Cancel a run
2989
+ * await cancelWorkflowRun.mutateAsync({
2990
+ * workflowId: 'my-workflow',
2991
+ * runId: 'run-123'
2992
+ * });
2993
+ * ```
2994
+ */
2995
+ function useCancelWorkflowRun() {
2996
+ const client = useMastraClient();
2997
+ return useMutation(async ({ workflowId, runId }) => {
2998
+ try {
2999
+ return (await client.getWorkflow(workflowId).createRun({ runId })).cancelRun();
3000
+ } catch (error) {
3001
+ console.error("Error canceling workflow run:", error);
3002
+ throw error;
3003
+ }
3004
+ });
3005
+ }
3006
+ //#endregion
3007
+ //#region src/workflows/WorkflowStepFactory/WorkflowStepFactory.tsx
3008
+ const renderUnknown = (step, UnknownStep) => UnknownStep?.(step) ?? null;
3009
+ const WorkflowStepFactoryComponent = ({ step, Step, MapStep, AgentStep, ToolStep, ForEachStep, ParallelStep, Conditional, LoopStep, SleepStep, SleepUntilStep, NestedWorkflowStep, UnknownStep }) => {
3010
+ switch (step.kind) {
3011
+ case "step": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: Step?.(step) ?? renderUnknown(step, UnknownStep) });
3012
+ case "map-step": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: MapStep?.(step) ?? renderUnknown(step, UnknownStep) });
3013
+ case "agent-step": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: AgentStep?.(step) ?? renderUnknown(step, UnknownStep) });
3014
+ case "tool-step": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: ToolStep?.(step) ?? renderUnknown(step, UnknownStep) });
3015
+ case "foreach-step": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: ForEachStep?.(step) ?? renderUnknown(step, UnknownStep) });
3016
+ case "parallel-step": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: ParallelStep?.(step) ?? renderUnknown(step, UnknownStep) });
3017
+ case "conditional": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: Conditional?.(step) ?? renderUnknown(step, UnknownStep) });
3018
+ case "loop-step": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: LoopStep?.(step) ?? renderUnknown(step, UnknownStep) });
3019
+ case "sleep-step": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: SleepStep?.(step) ?? renderUnknown(step, UnknownStep) });
3020
+ case "sleep-until-step": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: SleepUntilStep?.(step) ?? renderUnknown(step, UnknownStep) });
3021
+ case "nested-workflow-step": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: NestedWorkflowStep?.(step) ?? renderUnknown(step, UnknownStep) });
3022
+ default: return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: renderUnknown(step, UnknownStep) });
3023
+ }
3024
+ };
3025
+ const WorkflowStepFactory = (0, react.memo)(WorkflowStepFactoryComponent);
3026
+ //#endregion
3027
+ //#region src/voice/record-mic-to-file.ts
3028
+ async function recordMicrophoneToFile(onFinish) {
3029
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
3030
+ const mediaRecorder = new MediaRecorder(stream);
3031
+ let chunks = [];
3032
+ mediaRecorder.ondataavailable = (e) => {
3033
+ chunks.push(e.data);
3034
+ };
3035
+ mediaRecorder.onstop = () => {
3036
+ const blob = new Blob(chunks, { type: "audio/webm" });
3037
+ const file = new File([blob], `recording-${Date.now()}.webm`, {
3038
+ type: "audio/webm",
3039
+ lastModified: Date.now()
3040
+ });
3041
+ stream.getTracks().forEach((track) => track.stop());
3042
+ onFinish(file);
3043
+ };
3044
+ return mediaRecorder;
3045
+ }
3046
+ //#endregion
3047
+ //#region src/voice/play-stream-with-web-audio.ts
3048
+ async function playStreamWithWebAudio(stream, onEnded) {
3049
+ const audioContext = new window.AudioContext();
3050
+ const reader = stream.getReader();
3051
+ const chunks = [];
3052
+ try {
3053
+ while (true) {
3054
+ const { done, value } = await reader.read();
3055
+ if (done) break;
3056
+ chunks.push(value);
3057
+ }
3058
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
3059
+ const combinedBuffer = new Uint8Array(totalLength);
3060
+ let offset = 0;
3061
+ for (const chunk of chunks) {
3062
+ combinedBuffer.set(chunk, offset);
3063
+ offset += chunk.length;
3064
+ }
3065
+ const audioBuffer = await audioContext.decodeAudioData(combinedBuffer.buffer);
3066
+ const source = audioContext.createBufferSource();
3067
+ source.buffer = audioBuffer;
3068
+ source.onended = onEnded ?? null;
3069
+ source.connect(audioContext.destination);
3070
+ source.start();
3071
+ return () => {
3072
+ source.onended = null;
3073
+ source.stop();
3074
+ audioContext.close();
3075
+ };
3076
+ } catch (error) {
3077
+ await reader.cancel().catch(() => void 0);
3078
+ await audioContext.close().catch(() => void 0);
3079
+ throw error;
3080
+ } finally {
3081
+ reader.releaseLock();
3082
+ }
3083
+ }
3084
+ //#endregion
3085
+ //#region src/voice/use-speech-recognition.ts
3086
+ const useSpeechRecognition = ({ language = "en-US", agentId, requestContext }) => {
3087
+ const client = useMastraClient();
3088
+ const [agent, setAgent] = (0, react.useState)(null);
3089
+ (0, react.useEffect)(() => {
3090
+ let cancelled = false;
3091
+ if (!agentId) {
3092
+ setAgent(null);
3093
+ return () => {
3094
+ cancelled = true;
3095
+ };
3096
+ }
3097
+ const agent = client.getAgent(agentId);
3098
+ const check = async () => {
3099
+ try {
3100
+ const speakers = await agent.voice.getSpeakers(requestContext);
3101
+ if (!cancelled) setAgent(speakers.length > 0 ? agent : null);
3102
+ } catch {
3103
+ if (!cancelled) setAgent(null);
3104
+ }
3105
+ };
3106
+ check();
3107
+ return () => {
3108
+ cancelled = true;
3109
+ };
3110
+ }, [
3111
+ agentId,
3112
+ client,
3113
+ requestContext
3114
+ ]);
3115
+ const browserSpeechRecognition = useBrowserSpeechRecognition({ language });
3116
+ const mastraSpeechRecognition = useMastraSpeechToText({
3117
+ agent,
3118
+ language
3119
+ });
3120
+ if (!agent) return browserSpeechRecognition;
3121
+ return mastraSpeechRecognition;
3122
+ };
3123
+ const useBrowserSpeechRecognition = ({ language = "en-US" }) => {
3124
+ const speechRecognitionRef = (0, react.useRef)(null);
3125
+ const [state, setState] = (0, react.useState)({
3126
+ isListening: false,
3127
+ transcript: "",
3128
+ error: null
3129
+ });
3130
+ const start = () => {
3131
+ if (!speechRecognitionRef.current) return;
3132
+ speechRecognitionRef.current.start();
3133
+ };
3134
+ const stop = () => {
3135
+ if (!speechRecognitionRef.current) return;
3136
+ speechRecognitionRef.current.stop();
3137
+ };
3138
+ (0, react.useEffect)(() => {
3139
+ if (!("webkitSpeechRecognition" in window) && !("SpeechRecognition" in window)) {
3140
+ setState((prev) => ({
3141
+ ...prev,
3142
+ error: "Speech Recognition not supported in this browser"
3143
+ }));
3144
+ return;
3145
+ }
3146
+ const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
3147
+ speechRecognitionRef.current = recognition;
3148
+ recognition.continuous = true;
3149
+ recognition.lang = language;
3150
+ recognition.onstart = () => {
3151
+ setState((prev) => ({
3152
+ ...prev,
3153
+ isListening: true,
3154
+ error: null
3155
+ }));
3156
+ };
3157
+ recognition.onresult = (event) => {
3158
+ let finalTranscript = "";
3159
+ for (let i = event.resultIndex; i < event.results.length; i++) {
3160
+ const transcript = event.results[i][0].transcript;
3161
+ if (event.results[i].isFinal) finalTranscript += transcript + " ";
3162
+ }
3163
+ setState((prev) => ({
3164
+ ...prev,
3165
+ transcript: finalTranscript
3166
+ }));
3167
+ };
3168
+ recognition.onerror = (event) => {
3169
+ setState((prev) => ({
3170
+ ...prev,
3171
+ error: `Error: ${event.error}`
3172
+ }));
3173
+ };
3174
+ recognition.onend = () => setState((prev) => ({
3175
+ ...prev,
3176
+ isListening: false
3177
+ }));
3178
+ return () => {
3179
+ try {
3180
+ recognition.stop();
3181
+ } catch {}
3182
+ recognition.onstart = null;
3183
+ recognition.onresult = null;
3184
+ recognition.onerror = null;
3185
+ recognition.onend = null;
3186
+ speechRecognitionRef.current = null;
3187
+ };
3188
+ }, [language]);
3189
+ return {
3190
+ ...state,
3191
+ start,
3192
+ stop
3193
+ };
3194
+ };
3195
+ const useMastraSpeechToText = ({ agent, language }) => {
3196
+ const [state, setState] = (0, react.useState)({
3197
+ isListening: false,
3198
+ transcript: "",
3199
+ error: null
3200
+ });
3201
+ const recorderRef = (0, react.useRef)(null);
3202
+ const sessionRef = (0, react.useRef)(0);
3203
+ const startInFlightRef = (0, react.useRef)(false);
3204
+ (0, react.useEffect)(() => {
3205
+ return () => {
3206
+ sessionRef.current += 1;
3207
+ startInFlightRef.current = false;
3208
+ recorderRef.current?.stop();
3209
+ recorderRef.current = null;
3210
+ };
3211
+ }, [agent]);
3212
+ const handleFinish = (session) => (file) => {
3213
+ if (!agent || session !== sessionRef.current) return;
3214
+ recorderRef.current = null;
3215
+ setState((prev) => ({
3216
+ ...prev,
3217
+ isListening: false
3218
+ }));
3219
+ agent.voice.listen(file, { language }).then((res) => {
3220
+ if (session !== sessionRef.current) return;
3221
+ setState((prev) => ({
3222
+ ...prev,
3223
+ transcript: res.text,
3224
+ error: null
3225
+ }));
3226
+ }).catch((error) => {
3227
+ if (session !== sessionRef.current) return;
3228
+ const message = error instanceof Error ? error.message : "Failed to transcribe speech";
3229
+ setState((prev) => ({
3230
+ ...prev,
3231
+ error: message
3232
+ }));
3233
+ });
3234
+ };
3235
+ const start = () => {
3236
+ if (!agent || startInFlightRef.current || recorderRef.current) return;
3237
+ startInFlightRef.current = true;
3238
+ sessionRef.current += 1;
3239
+ const session = sessionRef.current;
3240
+ recordMicrophoneToFile(handleFinish(session)).then((recorder) => {
3241
+ startInFlightRef.current = false;
3242
+ if (session !== sessionRef.current) {
3243
+ try {
3244
+ recorder.stop();
3245
+ } catch {}
3246
+ return;
3247
+ }
3248
+ recorderRef.current = recorder;
3249
+ setState((prev) => ({
3250
+ ...prev,
3251
+ isListening: true,
3252
+ error: null
3253
+ }));
3254
+ recorder.start();
3255
+ }).catch((error) => {
3256
+ startInFlightRef.current = false;
3257
+ if (session !== sessionRef.current) return;
3258
+ const message = error instanceof Error ? error.message : "Failed to start speech recording";
3259
+ setState((prev) => ({
3260
+ ...prev,
3261
+ isListening: false,
3262
+ error: message
3263
+ }));
3264
+ });
3265
+ };
3266
+ const stop = () => {
3267
+ if (recorderRef.current) {
3268
+ recorderRef.current.stop();
3269
+ recorderRef.current = null;
3270
+ } else if (startInFlightRef.current) sessionRef.current += 1;
3271
+ startInFlightRef.current = false;
3272
+ setState((prev) => ({
3273
+ ...prev,
3274
+ isListening: false
3275
+ }));
3276
+ };
3277
+ return {
3278
+ ...state,
3279
+ start,
3280
+ stop
3281
+ };
3282
+ };
3283
+ //#endregion
3284
+ exports.AgentIcon = require_ui.AgentIcon;
3285
+ exports.CLIENT_MESSAGE_ID_KEY = CLIENT_MESSAGE_ID_KEY;
3286
+ exports.CodeBlock = require_ui.CodeBlock;
3287
+ exports.CodeBlockClass = require_ui.CodeBlockClass;
3288
+ exports.CodeCopyButton = require_ui.CodeCopyButton;
3289
+ exports.Entity = require_ui.Entity;
3290
+ exports.EntityCaret = require_ui.EntityCaret;
3291
+ exports.EntityContent = require_ui.EntityContent;
3292
+ exports.EntityContentClass = require_ui.EntityContentClass;
3293
+ exports.EntityTrigger = require_ui.EntityTrigger;
3294
+ exports.EntityTriggerClass = require_ui.EntityTriggerClass;
3295
+ exports.EntityTriggerVariantClasses = require_ui.EntityTriggerVariantClasses;
3296
+ exports.Entry = require_ui.Entry;
3297
+ exports.EntryClass = require_ui.EntryClass;
3298
+ exports.EntryTitle = require_ui.EntryTitle;
3299
+ exports.EntryTitleClass = require_ui.EntryTitleClass;
3300
+ exports.Icon = require_ui.Icon;
3301
+ exports.IconButton = require_ui.IconButton;
3302
+ exports.IconButtonClass = require_ui.IconButtonClass;
3303
+ exports.IconSizes = require_ui.IconSizes;
1508
3304
  exports.MastraReactProvider = MastraReactProvider;
1509
- exports.Message = Message;
1510
- exports.MessageActions = MessageActions;
1511
- exports.MessageActionsClass = MessageActionsClass;
1512
- exports.MessageClass = MessageClass;
1513
- exports.MessageContent = MessageContent;
1514
- exports.MessageContentClass = MessageContentClass;
1515
- exports.MessageList = MessageList;
1516
- exports.MessageListClass = MessageListClass;
1517
- exports.MessageStreaming = MessageStreaming;
1518
- exports.MessageStreamingClass = MessageStreamingClass;
1519
- exports.MessageUsage = MessageUsage;
1520
- exports.MessageUsageClass = MessageUsageClass;
1521
- exports.MessageUsageEntry = MessageUsageEntry;
1522
- exports.MessageUsageEntryClass = MessageUsageEntryClass;
1523
- exports.MessageUsageValue = MessageUsageValue;
1524
- exports.MessageUsageValueClass = MessageUsageValueClass;
1525
- exports.MessageUsages = MessageUsages;
1526
- exports.MessageUsagesClass = MessageUsagesClass;
1527
- exports.ToolApproval = ToolApproval;
1528
- exports.ToolApprovalActions = ToolApprovalActions;
1529
- exports.ToolApprovalActionsClass = ToolApprovalActionsClass;
1530
- exports.ToolApprovalClass = ToolApprovalClass;
1531
- exports.ToolApprovalContent = ToolApprovalContent;
1532
- exports.ToolApprovalContentClass = ToolApprovalContentClass;
1533
- exports.ToolApprovalHeader = ToolApprovalHeader;
1534
- exports.ToolApprovalHeaderClass = ToolApprovalHeaderClass;
1535
- exports.ToolApprovalTitle = ToolApprovalTitle;
1536
- exports.ToolApprovalTitleClass = ToolApprovalTitleClass;
1537
- exports.ToolsIcon = ToolsIcon;
1538
- exports.Tooltip = Tooltip;
1539
- exports.TooltipContent = TooltipContent;
1540
- exports.TooltipContentClass = TooltipContentClass;
1541
- exports.TooltipTrigger = TooltipTrigger;
1542
- exports.WorkflowIcon = WorkflowIcon;
3305
+ exports.Message = require_ui.Message;
3306
+ exports.MessageActions = require_ui.MessageActions;
3307
+ exports.MessageActionsClass = require_ui.MessageActionsClass;
3308
+ exports.MessageClass = require_ui.MessageClass;
3309
+ exports.MessageContent = require_ui.MessageContent;
3310
+ exports.MessageContentClass = require_ui.MessageContentClass;
3311
+ exports.MessageFactory = require_ui.MessageFactory;
3312
+ exports.MessageList = require_ui.MessageList;
3313
+ exports.MessageListClass = require_ui.MessageListClass;
3314
+ exports.MessageStreaming = require_ui.MessageStreaming;
3315
+ exports.MessageStreamingClass = require_ui.MessageStreamingClass;
3316
+ exports.MessageUsage = require_ui.MessageUsage;
3317
+ exports.MessageUsageClass = require_ui.MessageUsageClass;
3318
+ exports.MessageUsageEntry = require_ui.MessageUsageEntry;
3319
+ exports.MessageUsageEntryClass = require_ui.MessageUsageEntryClass;
3320
+ exports.MessageUsageValue = require_ui.MessageUsageValue;
3321
+ exports.MessageUsageValueClass = require_ui.MessageUsageValueClass;
3322
+ exports.MessageUsages = require_ui.MessageUsages;
3323
+ exports.MessageUsagesClass = require_ui.MessageUsagesClass;
3324
+ exports.ToolApproval = require_ui.ToolApproval;
3325
+ exports.ToolApprovalActions = require_ui.ToolApprovalActions;
3326
+ exports.ToolApprovalActionsClass = require_ui.ToolApprovalActionsClass;
3327
+ exports.ToolApprovalClass = require_ui.ToolApprovalClass;
3328
+ exports.ToolApprovalContent = require_ui.ToolApprovalContent;
3329
+ exports.ToolApprovalContentClass = require_ui.ToolApprovalContentClass;
3330
+ exports.ToolApprovalHeader = require_ui.ToolApprovalHeader;
3331
+ exports.ToolApprovalHeaderClass = require_ui.ToolApprovalHeaderClass;
3332
+ exports.ToolApprovalTitle = require_ui.ToolApprovalTitle;
3333
+ exports.ToolApprovalTitleClass = require_ui.ToolApprovalTitleClass;
3334
+ exports.ToolsIcon = require_ui.ToolsIcon;
3335
+ exports.Tooltip = require_ui.Tooltip;
3336
+ exports.TooltipContent = require_ui.TooltipContent;
3337
+ exports.TooltipContentClass = require_ui.TooltipContentClass;
3338
+ exports.TooltipTrigger = require_ui.TooltipTrigger;
3339
+ exports.WorkflowIcon = require_ui.WorkflowIcon;
3340
+ exports.WorkflowStepFactory = WorkflowStepFactory;
3341
+ exports.accumulateChunk = accumulateChunk;
3342
+ exports.accumulateNetworkChunk = accumulateNetworkChunk;
3343
+ exports.finishStreamingAssistantMessage = finishStreamingAssistantMessage;
3344
+ exports.fromCoreUserMessageToMastraDBMessage = fromCoreUserMessageToMastraDBMessage;
3345
+ exports.fromCoreUserMessagesToMastraDBMessage = fromCoreUserMessagesToMastraDBMessage;
1543
3346
  exports.mapWorkflowStreamChunkToWatchResult = mapWorkflowStreamChunkToWatchResult;
1544
- exports.toAssistantUIMessage = toAssistantUIMessage;
1545
- exports.toUIMessage = toUIMessage;
3347
+ exports.playStreamWithWebAudio = playStreamWithWebAudio;
3348
+ exports.recordMicrophoneToFile = recordMicrophoneToFile;
3349
+ exports.useCancelWorkflowRun = useCancelWorkflowRun;
1546
3350
  exports.useChat = useChat;
1547
- exports.useEntity = useEntity;
3351
+ exports.useCreateWorkflowRun = useCreateWorkflowRun;
3352
+ exports.useEntity = require_ui.useEntity;
1548
3353
  exports.useMastraClient = useMastraClient;
1549
- //# sourceMappingURL=index.cjs.map
3354
+ exports.useSpeechRecognition = useSpeechRecognition;
3355
+ exports.useStreamWorkflow = useStreamWorkflow;
3356
+
3357
+ //# sourceMappingURL=index.cjs.map