@mastra/react 1.0.0-beta.24 → 1.0.2

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 (156) hide show
  1. package/CHANGELOG.md +2819 -2
  2. package/LICENSE.md +15 -0
  3. package/dist/agent/extractRunIdFromMessages.d.ts +10 -0
  4. package/dist/agent/extractRunIdFromMessages.d.ts.map +1 -0
  5. package/dist/agent/hooks.d.ts +91 -0
  6. package/dist/agent/hooks.d.ts.map +1 -0
  7. package/dist/agent/signal-data.d.ts +2 -0
  8. package/dist/agent/signal-data.d.ts.map +1 -0
  9. package/dist/{src/agent → agent}/types.d.ts +6 -1
  10. package/dist/agent/types.d.ts.map +1 -0
  11. package/dist/index.cjs +3743 -63
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.ts +11 -2
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +3676 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/lib/mastra-db/accumulator.d.ts +48 -0
  18. package/dist/lib/mastra-db/accumulator.d.ts.map +1 -0
  19. package/dist/lib/mastra-db/formatCompletionFeedback.d.ts +19 -0
  20. package/dist/lib/mastra-db/formatCompletionFeedback.d.ts.map +1 -0
  21. package/dist/lib/mastra-db/fromCoreUserMessage.d.ts +14 -0
  22. package/dist/lib/mastra-db/fromCoreUserMessage.d.ts.map +1 -0
  23. package/dist/lib/mastra-db/index.d.ts +6 -0
  24. package/dist/lib/mastra-db/index.d.ts.map +1 -0
  25. package/dist/lib/mastra-db/types.d.ts +171 -0
  26. package/dist/lib/mastra-db/types.d.ts.map +1 -0
  27. package/dist/lib/use-mutation.d.ts +28 -0
  28. package/dist/lib/use-mutation.d.ts.map +1 -0
  29. package/dist/mastra-client-context.d.ts +26 -0
  30. package/dist/mastra-client-context.d.ts.map +1 -0
  31. package/dist/mastra-react-provider.d.ts +5 -0
  32. package/dist/mastra-react-provider.d.ts.map +1 -0
  33. package/dist/react.css +184 -322
  34. package/dist/{src/ui → ui}/Code/Code.d.ts +2 -1
  35. package/dist/ui/Code/Code.d.ts.map +1 -0
  36. package/dist/ui/Code/highlight.d.ts +4 -0
  37. package/dist/ui/Code/highlight.d.ts.map +1 -0
  38. package/dist/ui/Code/index.d.ts +2 -0
  39. package/dist/ui/Code/index.d.ts.map +1 -0
  40. package/dist/{src/ui → ui}/Entity/Entity.d.ts +2 -1
  41. package/dist/ui/Entity/Entity.d.ts.map +1 -0
  42. package/dist/{src/ui → ui}/Entity/Entry.d.ts +2 -1
  43. package/dist/ui/Entity/Entry.d.ts.map +1 -0
  44. package/dist/{src/ui → ui}/Entity/ToolApproval.d.ts +1 -0
  45. package/dist/ui/Entity/ToolApproval.d.ts.map +1 -0
  46. package/dist/{src/ui → ui}/Entity/context.d.ts +4 -3
  47. package/dist/ui/Entity/context.d.ts.map +1 -0
  48. package/dist/ui/Entity/index.d.ts +5 -0
  49. package/dist/ui/Entity/index.d.ts.map +1 -0
  50. package/dist/{src/ui → ui}/Entity/types.d.ts +1 -0
  51. package/dist/ui/Entity/types.d.ts.map +1 -0
  52. package/dist/{src/ui → ui}/Icon/Icon.d.ts +2 -1
  53. package/dist/ui/Icon/Icon.d.ts.map +1 -0
  54. package/dist/ui/Icon/index.d.ts +2 -0
  55. package/dist/ui/Icon/index.d.ts.map +1 -0
  56. package/dist/{src/ui → ui}/IconButton/IconButton.d.ts +2 -1
  57. package/dist/ui/IconButton/IconButton.d.ts.map +1 -0
  58. package/dist/ui/IconButton/index.d.ts +2 -0
  59. package/dist/ui/IconButton/index.d.ts.map +1 -0
  60. package/dist/{src/ui → ui}/Icons/AgentIcon.d.ts +2 -1
  61. package/dist/ui/Icons/AgentIcon.d.ts.map +1 -0
  62. package/dist/{src/ui → ui}/Icons/ToolsIcon.d.ts +2 -1
  63. package/dist/ui/Icons/ToolsIcon.d.ts.map +1 -0
  64. package/dist/{src/ui → ui}/Icons/WorkflowIcon.d.ts +2 -1
  65. package/dist/ui/Icons/WorkflowIcon.d.ts.map +1 -0
  66. package/dist/ui/Icons/index.d.ts +4 -0
  67. package/dist/ui/Icons/index.d.ts.map +1 -0
  68. package/dist/{src/ui → ui}/Message/Message.d.ts +2 -1
  69. package/dist/ui/Message/Message.d.ts.map +1 -0
  70. package/dist/ui/Message/index.d.ts +2 -0
  71. package/dist/ui/Message/index.d.ts.map +1 -0
  72. package/dist/ui/MessageFactory/MessageFactory.d.ts +22 -0
  73. package/dist/ui/MessageFactory/MessageFactory.d.ts.map +1 -0
  74. package/dist/ui/MessageFactory/index.d.ts +3 -0
  75. package/dist/ui/MessageFactory/index.d.ts.map +1 -0
  76. package/dist/ui/MessageFactory/types.d.ts +181 -0
  77. package/dist/ui/MessageFactory/types.d.ts.map +1 -0
  78. package/dist/{src/ui → ui}/Tooltip/Tooltip.d.ts +2 -1
  79. package/dist/ui/Tooltip/Tooltip.d.ts.map +1 -0
  80. package/dist/ui/Tooltip/index.d.ts +2 -0
  81. package/dist/ui/Tooltip/index.d.ts.map +1 -0
  82. package/dist/ui/index.d.ts +9 -0
  83. package/dist/ui/index.d.ts.map +1 -0
  84. package/dist/voice/index.d.ts +5 -0
  85. package/dist/voice/index.d.ts.map +1 -0
  86. package/dist/voice/play-stream-with-web-audio.d.ts +2 -0
  87. package/dist/voice/play-stream-with-web-audio.d.ts.map +1 -0
  88. package/dist/voice/record-mic-to-file.d.ts +2 -0
  89. package/dist/voice/record-mic-to-file.d.ts.map +1 -0
  90. package/dist/voice/use-speech-recognition.d.ts +20 -0
  91. package/dist/voice/use-speech-recognition.d.ts.map +1 -0
  92. package/dist/workflows/WorkflowStepFactory/WorkflowStepFactory.d.ts +8 -0
  93. package/dist/workflows/WorkflowStepFactory/WorkflowStepFactory.d.ts.map +1 -0
  94. package/dist/workflows/WorkflowStepFactory/index.d.ts +3 -0
  95. package/dist/workflows/WorkflowStepFactory/index.d.ts.map +1 -0
  96. package/dist/workflows/WorkflowStepFactory/types.d.ts +72 -0
  97. package/dist/workflows/WorkflowStepFactory/types.d.ts.map +1 -0
  98. package/dist/workflows/hooks.d.ts +34 -0
  99. package/dist/workflows/hooks.d.ts.map +1 -0
  100. package/dist/workflows/index.d.ts +4 -0
  101. package/dist/workflows/index.d.ts.map +1 -0
  102. package/dist/workflows/types.d.ts +122 -0
  103. package/dist/workflows/types.d.ts.map +1 -0
  104. package/dist/workflows/use-stream-workflow.d.ts +39 -0
  105. package/dist/workflows/use-stream-workflow.d.ts.map +1 -0
  106. package/package.json +35 -31
  107. package/dist/chunk-55VPMN3N-BuLK6rn1.js +0 -249
  108. package/dist/chunk-55VPMN3N-BuLK6rn1.js.map +0 -1
  109. package/dist/chunk-55VPMN3N-Dhj5NfGj.cjs +0 -251
  110. package/dist/chunk-55VPMN3N-Dhj5NfGj.cjs.map +0 -1
  111. package/dist/index-BEw00-Pp.cjs +0 -20642
  112. package/dist/index-BEw00-Pp.cjs.map +0 -1
  113. package/dist/index-BaK_Y6TP.cjs +0 -185
  114. package/dist/index-BaK_Y6TP.cjs.map +0 -1
  115. package/dist/index-C1OzXW5i.js +0 -180
  116. package/dist/index-C1OzXW5i.js.map +0 -1
  117. package/dist/index-CIU9zuI1.js +0 -20559
  118. package/dist/index-CIU9zuI1.js.map +0 -1
  119. package/dist/src/agent/hooks.d.ts +0 -63
  120. package/dist/src/index.d.ts +0 -6
  121. package/dist/src/lib/ai-sdk/index.d.ts +0 -4
  122. package/dist/src/lib/ai-sdk/memory/resolveInitialMessages.d.ts +0 -12
  123. package/dist/src/lib/ai-sdk/memory/resolveInitialMessages.test.d.ts +0 -1
  124. package/dist/src/lib/ai-sdk/transformers/AISdkNetworkTransformer.d.ts +0 -10
  125. package/dist/src/lib/ai-sdk/transformers/AISdkNetworkTransformer.test.d.ts +0 -1
  126. package/dist/src/lib/ai-sdk/transformers/types.d.ts +0 -10
  127. package/dist/src/lib/ai-sdk/types.d.ts +0 -90
  128. package/dist/src/lib/ai-sdk/utils/fromCoreUserMessageToUIMessage.d.ts +0 -10
  129. package/dist/src/lib/ai-sdk/utils/fromCoreUserMessageToUIMessage.test.d.ts +0 -1
  130. package/dist/src/lib/ai-sdk/utils/toAssistantUIMessage.d.ts +0 -14
  131. package/dist/src/lib/ai-sdk/utils/toAssistantUIMessage.test.d.ts +0 -1
  132. package/dist/src/lib/ai-sdk/utils/toUIMessage.d.ts +0 -17
  133. package/dist/src/lib/ai-sdk/utils/toUIMessage.test.d.ts +0 -1
  134. package/dist/src/mastra-client-context.d.ts +0 -10
  135. package/dist/src/mastra-react-provider.d.ts +0 -4
  136. package/dist/src/ui/Code/highlight.d.ts +0 -3
  137. package/dist/src/ui/Code/index.d.ts +0 -1
  138. package/dist/src/ui/Entity/Entity.stories.d.ts +0 -22
  139. package/dist/src/ui/Entity/index.d.ts +0 -4
  140. package/dist/src/ui/Icon/index.d.ts +0 -1
  141. package/dist/src/ui/IconButton/IconButton.stories.d.ts +0 -12
  142. package/dist/src/ui/IconButton/index.d.ts +0 -1
  143. package/dist/src/ui/Icons/index.d.ts +0 -3
  144. package/dist/src/ui/Message/Message.stories.d.ts +0 -13
  145. package/dist/src/ui/Message/index.d.ts +0 -1
  146. package/dist/src/ui/Tooltip/Tooltip.stories.d.ts +0 -12
  147. package/dist/src/ui/Tooltip/index.d.ts +0 -1
  148. package/dist/src/ui/index.d.ts +0 -7
  149. package/dist/token-6GSAFR2W-SPYPLMBM-Bmb7aObX.js +0 -60
  150. package/dist/token-6GSAFR2W-SPYPLMBM-Bmb7aObX.js.map +0 -1
  151. package/dist/token-6GSAFR2W-SPYPLMBM-DPP_j841.cjs +0 -64
  152. package/dist/token-6GSAFR2W-SPYPLMBM-DPP_j841.cjs.map +0 -1
  153. package/dist/token-util-NEHG7TUY-JRJTGTAB-0WkcL_9T.cjs +0 -11
  154. package/dist/token-util-NEHG7TUY-JRJTGTAB-0WkcL_9T.cjs.map +0 -1
  155. package/dist/token-util-NEHG7TUY-JRJTGTAB-BLZ0BA54.js +0 -7
  156. package/dist/token-util-NEHG7TUY-JRJTGTAB-BLZ0BA54.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,2 +1,3677 @@
1
- export { K as AgentIcon, D as CodeBlock, C as CodeBlockClass, F as CodeCopyButton, E as Entity, k as EntityCaret, j as EntityContent, i as EntityContentClass, h as EntityTrigger, f as EntityTriggerClass, g as EntityTriggerVariantClasses, z as Entry, y as EntryClass, B as EntryTitle, A as EntryTitleClass, G as Icon, J as IconButton, H as IconButtonClass, I as IconSizes, M as MastraReactProvider, S as Message, Y as MessageActions, X as MessageActionsClass, R as MessageClass, V as MessageContent, U as MessageContentClass, a7 as MessageList, a6 as MessageListClass, a9 as MessageStreaming, a8 as MessageStreamingClass, a1 as MessageUsage, a0 as MessageUsageClass, a3 as MessageUsageEntry, a2 as MessageUsageEntryClass, a5 as MessageUsageValue, a4 as MessageUsageValueClass, $ as MessageUsages, Z as MessageUsagesClass, l as ToolApproval, x as ToolApprovalActions, w as ToolApprovalActionsClass, T as ToolApprovalClass, v as ToolApprovalContent, s as ToolApprovalContentClass, q as ToolApprovalHeader, p as ToolApprovalHeaderClass, o as ToolApprovalTitle, n as ToolApprovalTitleClass, L as ToolsIcon, N as Tooltip, P as TooltipContent, O as TooltipContentClass, Q as TooltipTrigger, W as WorkflowIcon, m as mapWorkflowStreamChunkToWatchResult, c as resolveToChildMessages, d as toAssistantUIMessage, t as toUIMessage, b as useChat, e as useEntity, u as useMastraClient } from './index-CIU9zuI1.js';
1
+ import { MastraClient } from '@mastra/client-js';
2
+ import { createContext, memo, useContext, useRef, useState, useEffect, useCallback, useLayoutEffect, Fragment as Fragment$1 } from 'react';
3
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
4
+ import { v4 } from '@lukeed/uuid';
5
+ import { AIV5Adapter } from '@mastra/core/agent/message-list';
6
+ import { ChevronDownIcon, CheckIcon, CopyIcon } from 'lucide-react';
7
+ import { twMerge } from 'tailwind-merge';
8
+ import { TooltipProvider, Root, TooltipPortal, TooltipContent as TooltipContent$1, TooltipTrigger as TooltipTrigger$1 } from '@radix-ui/react-tooltip';
9
+ import { toJsxRuntime } from 'hast-util-to-jsx-runtime';
10
+ import { codeToHast } from 'shiki/bundle/web';
11
+
12
+ // src/mastra-client-context.tsx
13
+ var MastraClientContext = createContext({});
14
+ var MastraClientProvider = ({
15
+ children,
16
+ baseUrl,
17
+ headers,
18
+ apiPrefix,
19
+ credentials = "include",
20
+ customFetch
21
+ }) => {
22
+ const client = createMastraClient(baseUrl, headers, apiPrefix, credentials, customFetch);
23
+ return /* @__PURE__ */ jsx(MastraClientContext.Provider, { value: client, children });
24
+ };
25
+ var useMastraClient = () => useContext(MastraClientContext);
26
+ var IPV4_LOOPBACK_RE = /^127\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
27
+ var isIPv4Loopback = (hostname) => {
28
+ const m = IPV4_LOOPBACK_RE.exec(hostname);
29
+ if (!m) return false;
30
+ return +m[1] <= 255 && +m[2] <= 255 && +m[3] <= 255;
31
+ };
32
+ var isLocalUrl = (url) => {
33
+ if (!url) return true;
34
+ try {
35
+ const { hostname } = new URL(url);
36
+ return hostname === "localhost" || hostname.endsWith(".localhost") || isIPv4Loopback(hostname) || hostname === "::1" || hostname === "[::1]";
37
+ } catch {
38
+ return false;
39
+ }
40
+ };
41
+ var createMastraClient = (baseUrl, mastraClientHeaders = {}, apiPrefix, credentials = "include", customFetch) => {
42
+ return new MastraClient({
43
+ baseUrl: baseUrl || "",
44
+ headers: isLocalUrl(baseUrl) ? { ...mastraClientHeaders, "x-mastra-dev-playground": "true" } : mastraClientHeaders,
45
+ apiPrefix,
46
+ credentials,
47
+ fetch: customFetch
48
+ });
49
+ };
50
+ var MastraReactProvider = ({
51
+ children,
52
+ baseUrl,
53
+ headers,
54
+ apiPrefix,
55
+ credentials,
56
+ customFetch
57
+ }) => {
58
+ return /* @__PURE__ */ jsx(
59
+ MastraClientProvider,
60
+ {
61
+ baseUrl,
62
+ headers,
63
+ apiPrefix,
64
+ credentials,
65
+ customFetch,
66
+ children
67
+ }
68
+ );
69
+ };
70
+
71
+ // src/lib/mastra-db/formatCompletionFeedback.ts
72
+ var formatBaseCompletionFeedback = (result, maxIterationReached, formatScorerHeading, incompleteMessage) => {
73
+ const lines = [];
74
+ lines.push("#### Completion Check Results");
75
+ lines.push("");
76
+ lines.push(`Overall: ${result.complete ? "\u2705 COMPLETE" : "\u274C NOT COMPLETE"}`);
77
+ lines.push(`Duration: ${result.totalDuration}ms`);
78
+ if (result.timedOut) {
79
+ lines.push("\u26A0\uFE0F Scoring timed out");
80
+ }
81
+ lines.push("");
82
+ for (const scorer of result.scorers) {
83
+ lines.push(formatScorerHeading(scorer));
84
+ lines.push(`Score: ${scorer.score} ${scorer.passed ? "\u2705" : "\u274C"}`);
85
+ if (scorer.reason) {
86
+ lines.push(`Reason: ${scorer.reason}`);
87
+ }
88
+ lines.push("");
89
+ }
90
+ if (result.complete) {
91
+ lines.push("\u2705 The task is complete.");
92
+ } else if (maxIterationReached) {
93
+ lines.push("\u26A0\uFE0F Max iterations reached.");
94
+ } else {
95
+ lines.push(incompleteMessage);
96
+ }
97
+ return lines.join("\n");
98
+ };
99
+ var formatCompletionFeedback = (result, maxIterationReached) => {
100
+ return formatBaseCompletionFeedback(
101
+ result,
102
+ maxIterationReached,
103
+ (scorer) => `###### ${scorer.scorerName} (${scorer.scorerId})`,
104
+ "\u{1F504} Will continue working on the task."
105
+ );
106
+ };
107
+ var formatStreamCompletionFeedback = (result, maxIterationReached) => {
108
+ return formatBaseCompletionFeedback(
109
+ result,
110
+ maxIterationReached,
111
+ (scorer) => `**${scorer.scorerName}** (${scorer.scorerId})`,
112
+ "\u{1F504} The task is not yet complete. Please continue working based on the feedback above."
113
+ );
114
+ };
115
+
116
+ // src/lib/mastra-db/types.ts
117
+ var CLIENT_MESSAGE_ID_KEY = "clientMessageId";
118
+
119
+ // src/lib/mastra-db/accumulator.ts
120
+ var cloneMetadata = (metadata) => metadata ? { ...metadata } : {};
121
+ var withParts = (message, parts) => ({
122
+ ...message,
123
+ content: {
124
+ ...message.content,
125
+ parts
126
+ }
127
+ });
128
+ var withMetadata = (message, metadata) => ({
129
+ ...message,
130
+ content: {
131
+ ...message.content,
132
+ metadata
133
+ }
134
+ });
135
+ var clearPendingStatus = (message) => {
136
+ const { status: _status, [CLIENT_MESSAGE_ID_KEY]: _clientMessageId, ...rest } = message.content.metadata ?? {};
137
+ return withMetadata(message, rest);
138
+ };
139
+ var clearPendingStatusKeepClientId = (message) => {
140
+ const { status: _status, ...rest } = message.content.metadata ?? {};
141
+ return withMetadata(message, rest);
142
+ };
143
+ var replaceLast = (conversation, message) => [
144
+ ...conversation.slice(0, -1),
145
+ message
146
+ ];
147
+ var replaceAt = (conversation, index, message) => [
148
+ ...conversation.slice(0, index),
149
+ message,
150
+ ...conversation.slice(index + 1)
151
+ ];
152
+ var newAssistantMessage = (id, parts, metadata) => ({
153
+ id,
154
+ role: "assistant",
155
+ createdAt: /* @__PURE__ */ new Date(),
156
+ content: {
157
+ format: 2,
158
+ parts,
159
+ metadata: cloneMetadata(metadata)
160
+ }
161
+ });
162
+ var appendAssistantMessage = (conversation, id, parts, metadata) => [...conversation, newAssistantMessage(id, parts, metadata)];
163
+ var isToolPart = (part) => part.type === "tool-invocation";
164
+ var partTextId = (part) => part.type === "text" ? part.textId : void 0;
165
+ var partState = (part) => part.state;
166
+ var finishStreamingAssistantMessage = (conversation) => {
167
+ const lastMessage = conversation[conversation.length - 1];
168
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
169
+ if (lastMessage.content.parts.length === 0) return conversation.slice(0, -1);
170
+ const nextParts = lastMessage.content.parts.map((part) => {
171
+ if ((part.type === "text" || part.type === "reasoning") && partState(part) === "streaming") {
172
+ return {
173
+ ...part,
174
+ state: "done"
175
+ };
176
+ }
177
+ return part;
178
+ });
179
+ return replaceLast(conversation, withParts(lastMessage, nextParts));
180
+ };
181
+ var locateToolPart = (messages, toolCallId, allowMetadataOnlyMatch) => {
182
+ const findIndex = (parts) => parts.findIndex((part) => isToolPart(part) && part.toolInvocation.toolCallId === toolCallId);
183
+ const lastMessage = messages[messages.length - 1];
184
+ if (lastMessage && lastMessage.role === "assistant") {
185
+ const idx = findIndex(lastMessage.content.parts);
186
+ if (idx !== -1) return { messageIndex: messages.length - 1, toolPartIndex: idx };
187
+ }
188
+ let count = 0;
189
+ const maxMessagesBack = 10;
190
+ for (let i = messages.length - 1; i >= 0; i--) {
191
+ if (count > maxMessagesBack) break;
192
+ const message = messages[i];
193
+ if (message.role !== "assistant") continue;
194
+ const idx = findIndex(message.content.parts);
195
+ if (idx !== -1) return { messageIndex: i, toolPartIndex: idx };
196
+ count++;
197
+ }
198
+ if (!allowMetadataOnlyMatch) return null;
199
+ for (let i = messages.length - 1; i >= 0; i--) {
200
+ if (messages[i].role === "assistant") return { messageIndex: i, toolPartIndex: -1 };
201
+ }
202
+ return null;
203
+ };
204
+ var mergeBgTaskMetadata = (existing, mode, args, otherMetadata) => {
205
+ const base = cloneMetadata(existing);
206
+ const existingBgTasks = base.backgroundTasks ?? {};
207
+ const nextBgTasks = { ...existingBgTasks };
208
+ if (args.perTaskEntry) {
209
+ const { toolCallId, startedAt, completedAt, taskId, suspendedAt } = args.perTaskEntry;
210
+ const prev = existingBgTasks[toolCallId] ?? { taskId };
211
+ nextBgTasks[toolCallId] = {
212
+ ...prev,
213
+ taskId,
214
+ ...startedAt !== void 0 ? { startedAt } : {},
215
+ ...completedAt !== void 0 ? { completedAt } : {},
216
+ ...suspendedAt !== void 0 ? { suspendedAt } : {}
217
+ };
218
+ }
219
+ const merged = {
220
+ ...base,
221
+ ...otherMetadata ?? {},
222
+ mode,
223
+ backgroundTasks: nextBgTasks
224
+ };
225
+ if (args.resetRunningCount) merged.runningBackgroundTasksCount = void 0;
226
+ return merged;
227
+ };
228
+ var mapWorkflowStreamChunkToWatchResult = (prev, chunk) => {
229
+ if (chunk.type === "workflow-start") {
230
+ return {
231
+ input: prev?.input,
232
+ status: "running",
233
+ steps: prev?.steps || {}
234
+ };
235
+ }
236
+ if (chunk.type === "workflow-canceled") {
237
+ return { ...prev, status: "canceled" };
238
+ }
239
+ if (chunk.type === "workflow-finish") {
240
+ const finalStatus = chunk.payload.workflowStatus;
241
+ const prevSteps = prev?.steps ?? {};
242
+ const lastStep = Object.values(prevSteps).pop();
243
+ return {
244
+ ...prev,
245
+ status: chunk.payload.workflowStatus,
246
+ ...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 } : {}
247
+ };
248
+ }
249
+ const { stepCallId: _stepCallId, stepName: _stepName, ...newPayload } = chunk.payload ?? {};
250
+ const newSteps = {
251
+ ...prev?.steps,
252
+ [chunk.payload.id]: {
253
+ ...prev?.steps?.[chunk.payload.id],
254
+ ...newPayload
255
+ }
256
+ };
257
+ if (chunk.type === "workflow-step-start") return { ...prev, steps: newSteps };
258
+ if (chunk.type === "workflow-step-suspended") {
259
+ const suspendedStepIds = Object.entries(newSteps).flatMap(
260
+ ([stepId, stepResult]) => {
261
+ if (stepResult?.status === "suspended") {
262
+ const nestedPath = stepResult?.suspendPayload?.__workflow_meta?.path;
263
+ return nestedPath ? [[stepId, ...nestedPath]] : [[stepId]];
264
+ }
265
+ return [];
266
+ }
267
+ );
268
+ return {
269
+ ...prev,
270
+ status: "suspended",
271
+ steps: newSteps,
272
+ suspendPayload: chunk.payload.suspendPayload,
273
+ suspended: suspendedStepIds
274
+ };
275
+ }
276
+ if (chunk.type === "workflow-step-waiting") return { ...prev, status: "waiting", steps: newSteps };
277
+ if (chunk.type === "workflow-step-progress") {
278
+ return {
279
+ ...prev,
280
+ steps: {
281
+ ...prev?.steps,
282
+ [chunk.payload.id]: {
283
+ ...prev?.steps?.[chunk.payload.id],
284
+ foreachProgress: {
285
+ completedCount: chunk.payload.completedCount,
286
+ totalCount: chunk.payload.totalCount,
287
+ currentIndex: chunk.payload.currentIndex,
288
+ iterationStatus: chunk.payload.iterationStatus,
289
+ iterationOutput: chunk.payload.iterationOutput
290
+ }
291
+ }
292
+ }
293
+ };
294
+ }
295
+ if (chunk.type === "workflow-step-result") return { ...prev, steps: newSteps };
296
+ return prev;
297
+ };
298
+ var signalContentsToUserMessages = (contents, metadata) => {
299
+ const makeUserMessage = (parts2) => ({
300
+ id: `signal-${Date.now()}`,
301
+ role: "user",
302
+ createdAt: /* @__PURE__ */ new Date(),
303
+ content: {
304
+ format: 2,
305
+ parts: parts2,
306
+ metadata: cloneMetadata(metadata)
307
+ }
308
+ });
309
+ const toMessagePart = (part) => {
310
+ if (!part || typeof part !== "object") return [];
311
+ const typedPart = part;
312
+ if (typedPart.type === "text" && typeof typedPart.text === "string") {
313
+ return [{ type: "text", text: typedPart.text }];
314
+ }
315
+ if (typedPart.type === "image") {
316
+ const image = typedPart.image;
317
+ return [
318
+ {
319
+ type: "file",
320
+ mediaType: typeof typedPart.mediaType === "string" ? typedPart.mediaType : typeof typedPart.mimeType === "string" ? typedPart.mimeType : "image/*",
321
+ url: typeof image === "string" ? image : image instanceof URL ? image.toString() : ""
322
+ }
323
+ ];
324
+ }
325
+ if (typedPart.type === "file") {
326
+ const data = typedPart.data;
327
+ return [
328
+ {
329
+ type: "file",
330
+ mediaType: typeof typedPart.mediaType === "string" ? typedPart.mediaType : typeof typedPart.mimeType === "string" ? typedPart.mimeType : "application/octet-stream",
331
+ url: typeof data === "string" ? data : data instanceof URL ? data.toString() : "",
332
+ ...typeof typedPart.filename === "string" ? { filename: typedPart.filename } : {}
333
+ }
334
+ ];
335
+ }
336
+ return [];
337
+ };
338
+ if (typeof contents === "string") {
339
+ return [makeUserMessage([{ type: "text", text: contents }])];
340
+ }
341
+ if (Array.isArray(contents)) {
342
+ const parts2 = contents.flatMap(toMessagePart);
343
+ return parts2.length ? [makeUserMessage(parts2)] : contents.flatMap((content2) => signalContentsToUserMessages(content2, metadata));
344
+ }
345
+ if (!contents || typeof contents !== "object") return [];
346
+ const message = contents;
347
+ if (message.role && message.role !== "user") return [];
348
+ const content = message.content;
349
+ if (typeof content === "string") {
350
+ return [makeUserMessage([{ type: "text", text: content }])];
351
+ }
352
+ if (!Array.isArray(content)) return [];
353
+ const parts = content.flatMap(toMessagePart);
354
+ return parts.length ? [makeUserMessage(parts)] : [];
355
+ };
356
+ var makeToolInvocationPart = (invocation) => ({
357
+ type: "tool-invocation",
358
+ toolInvocation: invocation
359
+ });
360
+ var isTemplateLiteralPassthrough = (chunk) => chunk.type.startsWith("agent-execution-event-") || chunk.type.startsWith("workflow-execution-event-");
361
+ var isDataChunk = (chunk) => chunk.type.startsWith("data-");
362
+ var accumulateChunk = ({ chunk, conversation, metadata }) => {
363
+ const result = [...conversation];
364
+ if (isTemplateLiteralPassthrough(chunk)) {
365
+ return result;
366
+ }
367
+ if (isDataChunk(chunk)) {
368
+ if (chunk.type === "data-user-message" && "data" in chunk && (chunk.data?.type === "user-message" || chunk.data?.type === "user")) {
369
+ const signalId = chunk.data.id;
370
+ const echoedClientMessageId = chunk.data?.metadata?.[CLIENT_MESSAGE_ID_KEY];
371
+ if (typeof echoedClientMessageId === "string" && result.some(
372
+ (message) => message.content.metadata?.status === "pending" && message.content.metadata[CLIENT_MESSAGE_ID_KEY] === echoedClientMessageId
373
+ )) {
374
+ return finishStreamingAssistantMessage(
375
+ result.map(
376
+ (message) => message.content.metadata?.status === "pending" && message.content.metadata[CLIENT_MESSAGE_ID_KEY] === echoedClientMessageId ? clearPendingStatusKeepClientId(typeof signalId === "string" ? { ...message, id: signalId } : message) : message
377
+ )
378
+ );
379
+ }
380
+ if (typeof signalId === "string" && result.some((message) => message.id === signalId)) {
381
+ return finishStreamingAssistantMessage(
382
+ result.map(
383
+ (message) => message.id === signalId && message.content.metadata?.status === "pending" ? clearPendingStatus(message) : message
384
+ )
385
+ );
386
+ }
387
+ const userMessages = signalContentsToUserMessages(chunk.data.contents, metadata);
388
+ if (!userMessages.length) return result;
389
+ const conversationWithFinishedAssistant = finishStreamingAssistantMessage(result);
390
+ const messageIdPrefix = typeof signalId === "string" ? signalId : `signal-${chunk.runId}-${Date.now()}`;
391
+ return [
392
+ ...conversationWithFinishedAssistant,
393
+ ...userMessages.map((message, index) => ({
394
+ ...message,
395
+ id: index === 0 ? messageIdPrefix : `${messageIdPrefix}-${index}`
396
+ }))
397
+ ];
398
+ }
399
+ const dataPart = {
400
+ type: chunk.type,
401
+ data: "data" in chunk ? chunk.data : void 0,
402
+ ..."id" in chunk && typeof chunk.id === "string" ? { id: chunk.id } : {}
403
+ };
404
+ const lastMessage = result[result.length - 1];
405
+ if (!lastMessage || lastMessage.role !== "assistant") {
406
+ return appendAssistantMessage(result, `data-${chunk.runId}-${Date.now()}`, [dataPart], metadata);
407
+ }
408
+ return replaceLast(result, withParts(lastMessage, [...lastMessage.content.parts, dataPart]));
409
+ }
410
+ switch (chunk.type) {
411
+ case "tripwire": {
412
+ const newMessage = newAssistantMessage(
413
+ `tripwire-${chunk.runId + Date.now()}`,
414
+ [{ type: "text", text: chunk.payload.reason }],
415
+ {
416
+ ...metadata,
417
+ status: "tripwire",
418
+ tripwire: {
419
+ reason: chunk.payload.reason,
420
+ retry: chunk.payload.retry,
421
+ metadata: chunk.payload.metadata,
422
+ processorId: chunk.payload.processorId
423
+ }
424
+ }
425
+ );
426
+ return [...result, newMessage];
427
+ }
428
+ case "start": {
429
+ const messageId = typeof chunk.payload.messageId === "string" ? chunk.payload.messageId : void 0;
430
+ if (messageId && result.some((message) => message.id === messageId)) return result;
431
+ return [...result, newAssistantMessage(messageId ?? `start-${chunk.runId + Date.now()}`, [], metadata)];
432
+ }
433
+ case "text-start": {
434
+ const lastMessage = result[result.length - 1];
435
+ const textId = chunk.payload.id || `text-${Date.now()}`;
436
+ if (chunk.payload.id && lastMessage?.role === "assistant" && lastMessage.content.parts.some((part) => part.type === "text" && partTextId(part) === textId)) {
437
+ return result;
438
+ }
439
+ const newTextPart = {
440
+ type: "text",
441
+ text: "",
442
+ state: "streaming",
443
+ textId,
444
+ providerMetadata: chunk.payload.providerMetadata
445
+ };
446
+ if (!lastMessage || lastMessage.role !== "assistant") {
447
+ return appendAssistantMessage(
448
+ result,
449
+ `start-${chunk.runId}-${Date.now()}`,
450
+ [newTextPart],
451
+ metadata
452
+ );
453
+ }
454
+ if (lastMessage.content.metadata?.completionResult) {
455
+ return appendAssistantMessage(
456
+ result,
457
+ `start-${chunk.runId}-${Date.now()}`,
458
+ [newTextPart],
459
+ metadata
460
+ );
461
+ }
462
+ return replaceLast(
463
+ result,
464
+ withParts(lastMessage, [...lastMessage.content.parts, newTextPart])
465
+ );
466
+ }
467
+ case "background-task-progress": {
468
+ const lastMessage = result[result.length - 1];
469
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
470
+ return replaceLast(
471
+ result,
472
+ withMetadata(lastMessage, {
473
+ mode: metadata.mode,
474
+ ...lastMessage.content.metadata,
475
+ runningBackgroundTasksCount: chunk.payload.runningCount
476
+ })
477
+ );
478
+ }
479
+ case "text-delta": {
480
+ const lastMessage = result[result.length - 1];
481
+ const textId = chunk.payload.id;
482
+ if (!lastMessage || lastMessage.role !== "assistant") {
483
+ const newTextPart = {
484
+ type: "text",
485
+ text: chunk.payload.text,
486
+ state: "streaming",
487
+ textId,
488
+ providerMetadata: chunk.payload.providerMetadata
489
+ };
490
+ return appendAssistantMessage(
491
+ result,
492
+ `text-${chunk.runId}-${Date.now()}`,
493
+ [newTextPart],
494
+ metadata
495
+ );
496
+ }
497
+ const parts = [...lastMessage.content.parts];
498
+ let textPartIndex = textId ? parts.findLastIndex((part) => part.type === "text" && partTextId(part) === textId) : -1;
499
+ if (textPartIndex === -1) {
500
+ textPartIndex = parts.findLastIndex((part) => part.type === "text" && partState(part) === "streaming");
501
+ }
502
+ if (textPartIndex === -1) {
503
+ const newTextPart = {
504
+ type: "text",
505
+ text: chunk.payload.text,
506
+ state: "streaming",
507
+ textId,
508
+ providerMetadata: chunk.payload.providerMetadata
509
+ };
510
+ parts.push(newTextPart);
511
+ } else {
512
+ const textPart = parts[textPartIndex];
513
+ parts[textPartIndex] = {
514
+ ...textPart,
515
+ text: textPart.text + chunk.payload.text,
516
+ state: "streaming"
517
+ };
518
+ }
519
+ return replaceLast(result, withParts(lastMessage, parts));
520
+ }
521
+ case "text-end": {
522
+ return result;
523
+ }
524
+ case "reasoning-start": {
525
+ const lastMessage = result[result.length - 1];
526
+ const newReasoningPart = {
527
+ type: "reasoning",
528
+ reasoning: "",
529
+ state: "streaming",
530
+ providerMetadata: chunk.payload.providerMetadata
531
+ };
532
+ if (!lastMessage || lastMessage.role !== "assistant") {
533
+ return appendAssistantMessage(
534
+ result,
535
+ `reasoning-${chunk.runId + Date.now()}`,
536
+ [newReasoningPart],
537
+ metadata
538
+ );
539
+ }
540
+ return replaceLast(
541
+ result,
542
+ withParts(lastMessage, [...lastMessage.content.parts, newReasoningPart])
543
+ );
544
+ }
545
+ case "reasoning-delta": {
546
+ const lastMessage = result[result.length - 1];
547
+ if (!lastMessage || lastMessage.role !== "assistant") {
548
+ const newReasoningPart = {
549
+ type: "reasoning",
550
+ reasoning: chunk.payload.text,
551
+ state: "streaming",
552
+ providerMetadata: chunk.payload.providerMetadata
553
+ };
554
+ return appendAssistantMessage(
555
+ result,
556
+ `reasoning-${chunk.runId + Date.now()}`,
557
+ [newReasoningPart],
558
+ metadata
559
+ );
560
+ }
561
+ const parts = [...lastMessage.content.parts];
562
+ const lastIndex = parts.length - 1;
563
+ const lastPart = parts[lastIndex];
564
+ if (lastPart?.type === "reasoning") {
565
+ const reasoningPart = lastPart;
566
+ parts[lastIndex] = {
567
+ ...reasoningPart,
568
+ reasoning: reasoningPart.reasoning + chunk.payload.text,
569
+ state: "streaming"
570
+ };
571
+ } else {
572
+ const newReasoningPart = {
573
+ type: "reasoning",
574
+ reasoning: chunk.payload.text,
575
+ state: "streaming",
576
+ providerMetadata: chunk.payload.providerMetadata
577
+ };
578
+ parts.push(newReasoningPart);
579
+ }
580
+ return replaceLast(result, withParts(lastMessage, parts));
581
+ }
582
+ case "reasoning-end": {
583
+ const lastMessage = result[result.length - 1];
584
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
585
+ const parts = [...lastMessage.content.parts];
586
+ const reasoningIndex = parts.findLastIndex((part) => part.type === "reasoning" && partState(part) === "streaming");
587
+ if (reasoningIndex === -1) return result;
588
+ const reasoningPart = parts[reasoningIndex];
589
+ const existingMeta = reasoningPart.providerMetadata;
590
+ const endMeta = chunk.payload.providerMetadata;
591
+ parts[reasoningIndex] = {
592
+ ...reasoningPart,
593
+ state: "done",
594
+ ...existingMeta || endMeta ? { providerMetadata: { ...existingMeta ?? {}, ...endMeta ?? {} } } : {}
595
+ };
596
+ return replaceLast(result, withParts(lastMessage, parts));
597
+ }
598
+ case "reasoning-signature": {
599
+ const lastMessage = result[result.length - 1];
600
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
601
+ const parts = [...lastMessage.content.parts];
602
+ const reasoningIndex = parts.findLastIndex((part) => part.type === "reasoning");
603
+ if (reasoningIndex === -1) return result;
604
+ const reasoningPart = parts[reasoningIndex];
605
+ const existingMeta = reasoningPart.providerMetadata;
606
+ const sigMeta = chunk.payload.providerMetadata;
607
+ parts[reasoningIndex] = {
608
+ ...reasoningPart,
609
+ ...existingMeta || sigMeta ? { providerMetadata: { ...existingMeta ?? {}, ...sigMeta ?? {} } } : {}
610
+ };
611
+ return replaceLast(result, withParts(lastMessage, parts));
612
+ }
613
+ case "redacted-reasoning": {
614
+ const lastMessage = result[result.length - 1];
615
+ const redactedData = chunk.payload.data;
616
+ const redactedPart = {
617
+ type: "reasoning",
618
+ reasoning: typeof redactedData === "string" ? redactedData : "",
619
+ state: "done",
620
+ redacted: true,
621
+ providerMetadata: chunk.payload.providerMetadata
622
+ };
623
+ if (!lastMessage || lastMessage.role !== "assistant") {
624
+ return appendAssistantMessage(
625
+ result,
626
+ `redacted-reasoning-${chunk.runId + Date.now()}`,
627
+ [redactedPart],
628
+ metadata
629
+ );
630
+ }
631
+ return replaceLast(
632
+ result,
633
+ withParts(lastMessage, [...lastMessage.content.parts, redactedPart])
634
+ );
635
+ }
636
+ case "tool-call": {
637
+ const invocation = {
638
+ state: "call",
639
+ toolCallId: chunk.payload.toolCallId,
640
+ toolName: chunk.payload.toolName,
641
+ args: chunk.payload.args
642
+ };
643
+ const newPart = {
644
+ ...makeToolInvocationPart(invocation),
645
+ providerMetadata: chunk.payload.providerMetadata
646
+ };
647
+ const existing = locateToolPart(result, chunk.payload.toolCallId, false);
648
+ if (existing && existing.toolPartIndex >= 0) {
649
+ const { messageIndex, toolPartIndex } = existing;
650
+ const targetMessage = result[messageIndex];
651
+ if (targetMessage && targetMessage.role === "assistant") {
652
+ const parts = [...targetMessage.content.parts];
653
+ const prev = parts[toolPartIndex];
654
+ if (isToolPart(prev)) {
655
+ const { argsText: _argsText, ...rest } = prev;
656
+ parts[toolPartIndex] = {
657
+ ...rest,
658
+ toolInvocation: {
659
+ ...prev.toolInvocation,
660
+ state: "call",
661
+ toolName: chunk.payload.toolName,
662
+ toolCallId: chunk.payload.toolCallId,
663
+ args: chunk.payload.args
664
+ },
665
+ providerMetadata: chunk.payload.providerMetadata ?? prev.providerMetadata
666
+ };
667
+ return replaceAt(result, messageIndex, withParts(targetMessage, parts));
668
+ }
669
+ }
670
+ }
671
+ const lastMessage = result[result.length - 1];
672
+ if (!lastMessage || lastMessage.role !== "assistant") {
673
+ return appendAssistantMessage(result, `tool-call-${chunk.runId + Date.now()}`, [newPart], metadata);
674
+ }
675
+ return replaceLast(result, withParts(lastMessage, [...lastMessage.content.parts, newPart]));
676
+ }
677
+ case "tool-call-input-streaming-start": {
678
+ const lastMessage = result[result.length - 1];
679
+ const invocation = {
680
+ state: "partial-call",
681
+ toolCallId: chunk.payload.toolCallId,
682
+ toolName: chunk.payload.toolName,
683
+ args: {}
684
+ };
685
+ const newPart = {
686
+ ...makeToolInvocationPart(invocation),
687
+ argsText: ""
688
+ };
689
+ if (!lastMessage || lastMessage.role !== "assistant") {
690
+ return appendAssistantMessage(
691
+ result,
692
+ `tool-call-streaming-${chunk.runId + Date.now()}`,
693
+ [newPart],
694
+ metadata
695
+ );
696
+ }
697
+ return replaceLast(result, withParts(lastMessage, [...lastMessage.content.parts, newPart]));
698
+ }
699
+ case "tool-call-delta": {
700
+ const location = locateToolPart(result, chunk.payload.toolCallId, false);
701
+ if (!location || location.toolPartIndex < 0) return result;
702
+ const { messageIndex, toolPartIndex } = location;
703
+ const targetMessage = result[messageIndex];
704
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
705
+ const parts = [...targetMessage.content.parts];
706
+ const toolPart = parts[toolPartIndex];
707
+ if (!isToolPart(toolPart)) return result;
708
+ const nextArgsText = (toolPart.argsText ?? "") + (chunk.payload.argsTextDelta ?? "");
709
+ parts[toolPartIndex] = {
710
+ ...toolPart,
711
+ argsText: nextArgsText,
712
+ toolInvocation: {
713
+ ...toolPart.toolInvocation,
714
+ state: "partial-call"
715
+ }
716
+ };
717
+ return replaceAt(result, messageIndex, withParts(targetMessage, parts));
718
+ }
719
+ case "tool-call-input-streaming-end": {
720
+ const location = locateToolPart(result, chunk.payload.toolCallId, false);
721
+ if (!location || location.toolPartIndex < 0) return result;
722
+ const { messageIndex, toolPartIndex } = location;
723
+ const targetMessage = result[messageIndex];
724
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
725
+ const parts = [...targetMessage.content.parts];
726
+ const toolPart = parts[toolPartIndex];
727
+ if (!isToolPart(toolPart)) return result;
728
+ let parsedArgs = {};
729
+ const argsText = toolPart.argsText;
730
+ if (typeof argsText === "string" && argsText.length > 0) {
731
+ try {
732
+ const maybe = JSON.parse(argsText);
733
+ if (maybe && typeof maybe === "object" && !Array.isArray(maybe)) {
734
+ parsedArgs = maybe;
735
+ }
736
+ } catch {
737
+ parsedArgs = {};
738
+ }
739
+ }
740
+ parts[toolPartIndex] = {
741
+ ...toolPart,
742
+ toolInvocation: {
743
+ ...toolPart.toolInvocation,
744
+ state: "call",
745
+ args: parsedArgs
746
+ }
747
+ };
748
+ return replaceAt(result, messageIndex, withParts(targetMessage, parts));
749
+ }
750
+ case "tool-error":
751
+ case "tool-result":
752
+ case "background-task-completed":
753
+ case "background-task-failed": {
754
+ const isBgTaskEvent = chunk.type === "background-task-completed" || chunk.type === "background-task-failed";
755
+ const location = locateToolPart(result, chunk.payload.toolCallId, isBgTaskEvent);
756
+ if (!location) return result;
757
+ const { messageIndex, toolPartIndex } = location;
758
+ const targetMessage = result[messageIndex];
759
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
760
+ const parts = [...targetMessage.content.parts];
761
+ const toolPart = toolPartIndex >= 0 ? parts[toolPartIndex] : void 0;
762
+ let payloadResult;
763
+ let payloadError;
764
+ let payloadIsError = false;
765
+ let payloadProviderMetadata;
766
+ let payloadCompletedAt;
767
+ let payloadTaskId;
768
+ switch (chunk.type) {
769
+ case "tool-result":
770
+ payloadResult = chunk.payload.result;
771
+ payloadIsError = Boolean(chunk.payload.isError);
772
+ payloadProviderMetadata = chunk.payload.providerMetadata;
773
+ break;
774
+ case "tool-error":
775
+ payloadError = chunk.payload.error;
776
+ payloadProviderMetadata = chunk.payload.providerMetadata;
777
+ break;
778
+ case "background-task-completed":
779
+ payloadResult = chunk.payload.result;
780
+ payloadCompletedAt = chunk.payload.completedAt;
781
+ payloadTaskId = chunk.payload.taskId;
782
+ break;
783
+ case "background-task-failed":
784
+ payloadError = chunk.payload.error;
785
+ payloadCompletedAt = chunk.payload.completedAt;
786
+ payloadTaskId = chunk.payload.taskId;
787
+ break;
788
+ }
789
+ if (toolPart && isToolPart(toolPart)) {
790
+ const { toolName, toolCallId, args } = toolPart.toolInvocation;
791
+ const providerMeta = payloadProviderMetadata ?? toolPart.providerMetadata;
792
+ const isError = chunk.type === "tool-error" || chunk.type === "background-task-failed" || payloadIsError;
793
+ if (isError) {
794
+ const error = chunk.type === "tool-error" || chunk.type === "background-task-failed" ? payloadError : payloadResult;
795
+ const errorText = typeof error === "string" ? error : error instanceof Error ? error.message : error?.message ?? String(error);
796
+ parts[toolPartIndex] = {
797
+ ...toolPart,
798
+ providerMetadata: providerMeta,
799
+ toolInvocation: {
800
+ state: "output-error",
801
+ toolCallId,
802
+ toolName,
803
+ args,
804
+ errorText
805
+ }
806
+ };
807
+ } else {
808
+ const resultObj = payloadResult;
809
+ const existingResult = toolPart.toolInvocation.state === "partial-call" || toolPart.toolInvocation.state === "result" ? toolPart.toolInvocation.result : void 0;
810
+ const existingLooksLikeWorkflow = Boolean(
811
+ existingResult && typeof existingResult === "object" && "steps" in existingResult
812
+ );
813
+ const isWorkflow = Boolean(resultObj?.result?.steps) || toolName?.startsWith("workflow-") || existingLooksLikeWorkflow;
814
+ const isAgent = chunk.from === "AGENT";
815
+ let output;
816
+ if (isWorkflow) {
817
+ const accumulated = existingLooksLikeWorkflow && existingResult && typeof existingResult === "object" ? existingResult : void 0;
818
+ const payloadWorkflow = resultObj?.result && typeof resultObj.result === "object" ? resultObj.result : void 0;
819
+ if (accumulated || payloadWorkflow) {
820
+ output = {
821
+ ...accumulated ?? {},
822
+ ...payloadWorkflow ?? {},
823
+ // Preserve `steps` from accumulated state when the terminal
824
+ // payload doesn't carry them.
825
+ steps: payloadWorkflow?.steps ?? accumulated?.steps ?? [],
826
+ status: payloadWorkflow?.status ?? accumulated?.status ?? "success",
827
+ // Surface the terminal scalar output without losing history.
828
+ output: payloadResult
829
+ };
830
+ } else {
831
+ output = payloadResult;
832
+ }
833
+ } else if (isAgent) {
834
+ const existingOutput = toolPart.toolInvocation.state === "result" ? toolPart.toolInvocation.result : void 0;
835
+ const existingChild = existingOutput?.childMessages;
836
+ output = existingOutput ? {
837
+ ...payloadResult,
838
+ childMessages: existingChild?.length ? existingChild : resultObj?.childMessages
839
+ } : payloadResult;
840
+ } else {
841
+ output = payloadResult;
842
+ }
843
+ parts[toolPartIndex] = {
844
+ ...toolPart,
845
+ providerMetadata: providerMeta,
846
+ toolInvocation: {
847
+ state: "result",
848
+ toolCallId,
849
+ toolName,
850
+ args,
851
+ result: output
852
+ }
853
+ };
854
+ }
855
+ }
856
+ const nextMetadata = mergeBgTaskMetadata(
857
+ targetMessage.content.metadata,
858
+ metadata.mode,
859
+ {
860
+ resetRunningCount: isBgTaskEvent,
861
+ perTaskEntry: isBgTaskEvent && payloadTaskId ? {
862
+ toolCallId: chunk.payload.toolCallId,
863
+ completedAt: payloadCompletedAt,
864
+ taskId: payloadTaskId
865
+ } : void 0
866
+ }
867
+ );
868
+ const nextMessage = {
869
+ ...targetMessage,
870
+ content: {
871
+ ...targetMessage.content,
872
+ parts,
873
+ metadata: nextMetadata
874
+ }
875
+ };
876
+ return replaceAt(result, messageIndex, nextMessage);
877
+ }
878
+ case "background-task-running": {
879
+ const location = locateToolPart(result, chunk.payload.toolCallId, true);
880
+ if (!location) return result;
881
+ const { messageIndex } = location;
882
+ const targetMessage = result[messageIndex];
883
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
884
+ const nextMetadata = mergeBgTaskMetadata(
885
+ targetMessage.content.metadata,
886
+ metadata.mode,
887
+ {
888
+ perTaskEntry: {
889
+ toolCallId: chunk.payload.toolCallId,
890
+ startedAt: chunk.payload.startedAt,
891
+ taskId: chunk.payload.taskId
892
+ }
893
+ }
894
+ );
895
+ return replaceAt(result, messageIndex, withMetadata(targetMessage, nextMetadata));
896
+ }
897
+ case "tool-output":
898
+ case "background-task-output": {
899
+ const isBgTaskOutput = chunk.type === "background-task-output";
900
+ const location = locateToolPart(result, chunk.payload.toolCallId, isBgTaskOutput);
901
+ if (!location || location.toolPartIndex < 0) return result;
902
+ const { messageIndex, toolPartIndex } = location;
903
+ const targetMessage = result[messageIndex];
904
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
905
+ const parts = [...targetMessage.content.parts];
906
+ const toolPart = parts[toolPartIndex];
907
+ if (!isToolPart(toolPart)) return result;
908
+ const { toolName, toolCallId, args } = toolPart.toolInvocation;
909
+ const payloadOutput = chunk.type === "background-task-output" ? chunk.payload.payload.payload.output : chunk.payload.output;
910
+ if (payloadOutput?.type?.startsWith("workflow-")) {
911
+ const existingWorkflowState = toolPart.toolInvocation.result || {};
912
+ const updated = mapWorkflowStreamChunkToWatchResult(existingWorkflowState, payloadOutput);
913
+ parts[toolPartIndex] = {
914
+ ...toolPart,
915
+ toolInvocation: {
916
+ state: "partial-call",
917
+ toolCallId,
918
+ toolName,
919
+ args,
920
+ result: updated
921
+ }
922
+ };
923
+ } else if (payloadOutput?.from === "AGENT" || payloadOutput?.from === "USER" && payloadOutput?.payload?.output?.type?.startsWith("workflow-")) {
924
+ return accumulateAgentChunk(payloadOutput, result, metadata, toolCallId, toolName);
925
+ } else {
926
+ const currentResult = toolPart.toolInvocation.result;
927
+ const existing = Array.isArray(currentResult) ? currentResult : [];
928
+ parts[toolPartIndex] = {
929
+ ...toolPart,
930
+ toolInvocation: {
931
+ state: "partial-call",
932
+ toolCallId,
933
+ toolName,
934
+ args,
935
+ result: [...existing, payloadOutput]
936
+ }
937
+ };
938
+ }
939
+ return replaceAt(result, messageIndex, withParts(targetMessage, parts));
940
+ }
941
+ case "is-task-complete": {
942
+ if (chunk.payload.suppressFeedback) return result;
943
+ const feedback = formatStreamCompletionFeedback(
944
+ {
945
+ complete: chunk.payload.passed,
946
+ scorers: chunk.payload.results,
947
+ totalDuration: chunk.payload.duration,
948
+ timedOut: chunk.payload.timedOut},
949
+ chunk.payload.maxIterationReached
950
+ );
951
+ const newMessage = newAssistantMessage(
952
+ `is-task-complete-${chunk.runId + Date.now()}`,
953
+ [{ type: "text", text: feedback }],
954
+ {
955
+ ...metadata,
956
+ completionResult: { passed: chunk.payload.passed }
957
+ }
958
+ );
959
+ return [...result, newMessage];
960
+ }
961
+ case "source": {
962
+ const lastMessage = result[result.length - 1];
963
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
964
+ const parts = [...lastMessage.content.parts];
965
+ if (chunk.payload.sourceType === "url") {
966
+ const sourceUrlPart = {
967
+ type: "source-url",
968
+ sourceId: chunk.payload.id,
969
+ url: chunk.payload.url || "",
970
+ title: chunk.payload.title,
971
+ providerMetadata: chunk.payload.providerMetadata
972
+ };
973
+ parts.push(sourceUrlPart);
974
+ } else if (chunk.payload.sourceType === "document") {
975
+ parts.push({
976
+ type: "source-document",
977
+ sourceId: chunk.payload.id,
978
+ mediaType: chunk.payload.mimeType || "application/octet-stream",
979
+ title: chunk.payload.title,
980
+ filename: chunk.payload.filename,
981
+ providerMetadata: chunk.payload.providerMetadata
982
+ });
983
+ }
984
+ return replaceLast(result, withParts(lastMessage, parts));
985
+ }
986
+ case "file": {
987
+ const lastMessage = result[result.length - 1];
988
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
989
+ const parts = [...lastMessage.content.parts];
990
+ let url;
991
+ if (typeof chunk.payload.data === "string") {
992
+ url = chunk.payload.base64 ? `data:${chunk.payload.mimeType};base64,${chunk.payload.data}` : `data:${chunk.payload.mimeType},${encodeURIComponent(chunk.payload.data)}`;
993
+ } else {
994
+ const base64 = btoa(String.fromCharCode(...chunk.payload.data));
995
+ url = `data:${chunk.payload.mimeType};base64,${base64}`;
996
+ }
997
+ parts.push({
998
+ type: "file",
999
+ mediaType: chunk.payload.mimeType,
1000
+ url,
1001
+ providerMetadata: chunk.payload.providerMetadata
1002
+ });
1003
+ return replaceLast(result, withParts(lastMessage, parts));
1004
+ }
1005
+ case "tool-call-approval": {
1006
+ const lastMessage = result[result.length - 1];
1007
+ if (!lastMessage || lastMessage.role !== "assistant") return result;
1008
+ const existingMeta = lastMessage.content.metadata ?? {};
1009
+ const lastRequireApproval = existingMeta.mode === "stream" ? existingMeta.requireApprovalMetadata ?? {} : {};
1010
+ return replaceLast(result, {
1011
+ ...lastMessage,
1012
+ content: {
1013
+ ...lastMessage.content,
1014
+ metadata: {
1015
+ ...existingMeta,
1016
+ mode: "stream",
1017
+ requireApprovalMetadata: {
1018
+ ...lastRequireApproval,
1019
+ [chunk.payload.toolName]: {
1020
+ toolCallId: chunk.payload.toolCallId,
1021
+ toolName: chunk.payload.toolName,
1022
+ args: chunk.payload.args
1023
+ }
1024
+ }
1025
+ }
1026
+ }
1027
+ });
1028
+ }
1029
+ case "tool-call-suspended":
1030
+ case "background-task-suspended": {
1031
+ const isBgTaskEvent = chunk.type === "background-task-suspended";
1032
+ let suspToolCallId;
1033
+ let suspToolName;
1034
+ let suspArgs;
1035
+ let suspPayload;
1036
+ let suspSuspendedAt;
1037
+ let suspTaskId;
1038
+ if (chunk.type === "background-task-suspended") {
1039
+ suspToolCallId = chunk.payload.toolCallId;
1040
+ suspToolName = chunk.payload.toolName;
1041
+ suspArgs = chunk.payload.args;
1042
+ suspPayload = chunk.payload.suspendPayload;
1043
+ suspSuspendedAt = chunk.payload.suspendedAt;
1044
+ suspTaskId = chunk.payload.taskId;
1045
+ } else {
1046
+ suspToolCallId = chunk.payload.toolCallId;
1047
+ suspToolName = chunk.payload.toolName;
1048
+ suspArgs = chunk.payload.args;
1049
+ suspPayload = chunk.payload.suspendPayload;
1050
+ }
1051
+ const location = isBgTaskEvent ? locateToolPart(result, suspToolCallId, true) : { messageIndex: result.length - 1 };
1052
+ if (!location) return result;
1053
+ const { messageIndex } = location;
1054
+ const targetMessage = result[messageIndex];
1055
+ if (!targetMessage || targetMessage.role !== "assistant") return result;
1056
+ const existingMeta = targetMessage.content.metadata ?? {};
1057
+ const lastSuspendedTools = existingMeta.mode === "stream" ? existingMeta.suspendedTools ?? {} : {};
1058
+ const nextMetadata = mergeBgTaskMetadata(
1059
+ existingMeta,
1060
+ "stream",
1061
+ {
1062
+ resetRunningCount: isBgTaskEvent,
1063
+ perTaskEntry: isBgTaskEvent && suspTaskId ? {
1064
+ toolCallId: suspToolCallId,
1065
+ suspendedAt: suspSuspendedAt,
1066
+ taskId: suspTaskId
1067
+ } : void 0
1068
+ },
1069
+ {
1070
+ suspendedTools: {
1071
+ ...lastSuspendedTools,
1072
+ [suspToolName]: {
1073
+ toolCallId: suspToolCallId,
1074
+ toolName: suspToolName,
1075
+ args: suspArgs,
1076
+ suspendPayload: suspPayload,
1077
+ runId: chunk.runId
1078
+ }
1079
+ }
1080
+ }
1081
+ );
1082
+ return replaceAt(result, messageIndex, withMetadata(targetMessage, nextMetadata));
1083
+ }
1084
+ case "finish":
1085
+ case "abort": {
1086
+ return finishStreamingAssistantMessage(result);
1087
+ }
1088
+ case "error": {
1089
+ const newMessage = newAssistantMessage(
1090
+ `error-${chunk.runId + Date.now()}`,
1091
+ [
1092
+ {
1093
+ type: "text",
1094
+ text: typeof chunk.payload.error === "string" ? chunk.payload.error : JSON.stringify(chunk.payload.error)
1095
+ }
1096
+ ],
1097
+ {
1098
+ ...metadata,
1099
+ status: "error"
1100
+ }
1101
+ );
1102
+ return [...result, newMessage];
1103
+ }
1104
+ // ----- Lifecycle / step / framing chunks (not surfaced on DB messages) -----
1105
+ case "step-start":
1106
+ case "step-finish":
1107
+ case "step-output":
1108
+ case "raw":
1109
+ case "watch":
1110
+ case "response-metadata":
1111
+ return result;
1112
+ // ----- Goal evaluation signal (feedback is already injected into the
1113
+ // message history by the core goal step; the chunk is a consumer-only
1114
+ // signal and is not surfaced as its own DB message). -----
1115
+ case "goal":
1116
+ return result;
1117
+ // ----- Object chunks (object/object-result are not stored on DB messages) -----
1118
+ case "object":
1119
+ case "object-result":
1120
+ return result;
1121
+ // ----- Background-task lifecycle markers not folded into messages -----
1122
+ case "background-task-started":
1123
+ case "background-task-cancelled":
1124
+ case "background-task-resumed":
1125
+ return result;
1126
+ // ----- Workflow lifecycle passthroughs (handled by mapWorkflowStreamChunkToWatchResult inside tool-output) -----
1127
+ case "workflow-start":
1128
+ case "workflow-finish":
1129
+ case "workflow-canceled":
1130
+ case "workflow-paused":
1131
+ case "workflow-step-start":
1132
+ case "workflow-step-finish":
1133
+ case "workflow-step-suspended":
1134
+ case "workflow-step-waiting":
1135
+ case "workflow-step-output":
1136
+ case "workflow-step-progress":
1137
+ case "workflow-step-result":
1138
+ return result;
1139
+ // ----- Nested-execution / routing / network passthroughs -----
1140
+ case "agent-execution-start":
1141
+ case "agent-execution-approval":
1142
+ case "agent-execution-suspended":
1143
+ case "agent-execution-end":
1144
+ case "agent-execution-abort":
1145
+ case "tool-execution-start":
1146
+ case "tool-execution-end":
1147
+ case "tool-execution-approval":
1148
+ case "tool-execution-suspended":
1149
+ case "tool-execution-abort":
1150
+ case "routing-agent-start":
1151
+ case "routing-agent-text-delta":
1152
+ case "routing-agent-text-start":
1153
+ case "routing-agent-end":
1154
+ case "routing-agent-abort":
1155
+ case "workflow-execution-start":
1156
+ case "workflow-execution-end":
1157
+ case "workflow-execution-suspended":
1158
+ case "workflow-execution-abort":
1159
+ case "network-execution-event-step-finish":
1160
+ case "network-execution-event-finish":
1161
+ case "network-validation-start":
1162
+ case "network-validation-end":
1163
+ case "network-object":
1164
+ case "network-object-result":
1165
+ return result;
1166
+ default:
1167
+ return assertExhaustive(chunk, result);
1168
+ }
1169
+ };
1170
+ var assertExhaustive = (_chunk, fallback) => fallback;
1171
+ var accumulateAgentChunk = (chunk, conversation, _metadata, parentToolCallId, parentToolName) => {
1172
+ const lastMessage = conversation[conversation.length - 1];
1173
+ if (!lastMessage || lastMessage.role !== "assistant") return conversation;
1174
+ const parts = [...lastMessage.content.parts];
1175
+ const findToolPartIndex = () => parts.findIndex(
1176
+ (part) => isToolPart(part) && (parentToolCallId && part.toolInvocation.toolCallId === parentToolCallId || parentToolName && part.toolInvocation.toolName === parentToolName)
1177
+ );
1178
+ if (chunk.type === "text-delta") {
1179
+ const agentChunk = chunk.payload;
1180
+ const toolPartIndex = findToolPartIndex();
1181
+ if (toolPartIndex === -1) return conversation;
1182
+ const toolPart = parts[toolPartIndex];
1183
+ const existingResult = toolPart.toolInvocation.result || {};
1184
+ const childMessages = existingResult.childMessages || [];
1185
+ const lastChildMessage = childMessages[childMessages.length - 1];
1186
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.text };
1187
+ const nextChildren = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
1188
+ parts[toolPartIndex] = {
1189
+ ...toolPart,
1190
+ toolInvocation: {
1191
+ ...toolPart.toolInvocation,
1192
+ result: { ...existingResult, childMessages: nextChildren }
1193
+ }
1194
+ };
1195
+ } else if (chunk.type === "tool-call") {
1196
+ const agentChunk = chunk.payload;
1197
+ const toolPartIndex = findToolPartIndex();
1198
+ if (toolPartIndex === -1) return conversation;
1199
+ const toolPart = parts[toolPartIndex];
1200
+ const existingResult = toolPart.toolInvocation.result || {};
1201
+ const childMessages = existingResult.childMessages || [];
1202
+ parts[toolPartIndex] = {
1203
+ ...toolPart,
1204
+ toolInvocation: {
1205
+ ...toolPart.toolInvocation,
1206
+ result: {
1207
+ ...existingResult,
1208
+ childMessages: [
1209
+ ...childMessages,
1210
+ {
1211
+ type: "tool",
1212
+ toolCallId: agentChunk.toolCallId,
1213
+ toolName: agentChunk.toolName,
1214
+ args: agentChunk.args
1215
+ }
1216
+ ]
1217
+ }
1218
+ }
1219
+ };
1220
+ } else if (chunk.type === "tool-output") {
1221
+ const agentChunk = chunk.payload;
1222
+ const toolPartIndex = findToolPartIndex();
1223
+ if (toolPartIndex === -1) return conversation;
1224
+ const toolPart = parts[toolPartIndex];
1225
+ if (agentChunk?.output?.type?.startsWith("workflow-")) {
1226
+ const existingResult = toolPart.toolInvocation.result || {};
1227
+ const childMessages = existingResult.childMessages || [];
1228
+ const lastIndex = childMessages.length - 1;
1229
+ const currentMessage = childMessages[lastIndex];
1230
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
1231
+ const updated = mapWorkflowStreamChunkToWatchResult(actualExistingWorkflowState, agentChunk.output);
1232
+ if (lastIndex >= 0 && childMessages[lastIndex]?.type === "tool") {
1233
+ parts[toolPartIndex] = {
1234
+ ...toolPart,
1235
+ toolInvocation: {
1236
+ ...toolPart.toolInvocation,
1237
+ result: {
1238
+ ...existingResult,
1239
+ childMessages: [
1240
+ ...childMessages.slice(0, -1),
1241
+ {
1242
+ ...currentMessage,
1243
+ toolOutput: { ...updated, runId: agentChunk.output.runId }
1244
+ }
1245
+ ]
1246
+ }
1247
+ }
1248
+ };
1249
+ }
1250
+ }
1251
+ } else if (chunk.type === "tool-result") {
1252
+ const agentChunk = chunk.payload;
1253
+ const toolPartIndex = findToolPartIndex();
1254
+ if (toolPartIndex === -1) return conversation;
1255
+ const toolPart = parts[toolPartIndex];
1256
+ const existingResult = toolPart.toolInvocation.result || {};
1257
+ const childMessages = existingResult.childMessages || [];
1258
+ const lastIndex = childMessages.length - 1;
1259
+ const isWorkflow = agentChunk?.toolName?.startsWith("workflow-");
1260
+ if (lastIndex >= 0 && childMessages[lastIndex]?.type === "tool") {
1261
+ parts[toolPartIndex] = {
1262
+ ...toolPart,
1263
+ toolInvocation: {
1264
+ ...toolPart.toolInvocation,
1265
+ result: {
1266
+ ...existingResult,
1267
+ childMessages: [
1268
+ ...childMessages.slice(0, -1),
1269
+ {
1270
+ ...childMessages[lastIndex],
1271
+ toolOutput: isWorkflow ? { ...agentChunk.result?.result, runId: agentChunk.result?.runId } : agentChunk.result
1272
+ }
1273
+ ]
1274
+ }
1275
+ }
1276
+ };
1277
+ }
1278
+ }
1279
+ return replaceLast(conversation, withParts(lastMessage, parts));
1280
+ };
1281
+ var networkMode = (metadata) => ({ ...metadata, mode: "network" });
1282
+ var findPartIndex = (parts, predicate) => parts.findIndex(predicate);
1283
+ var isDynamicToolPart = (part) => part.type === "dynamic-tool";
1284
+ var lastAssistant = (conversation) => {
1285
+ const last = conversation[conversation.length - 1];
1286
+ return last && last.role === "assistant" ? last : void 0;
1287
+ };
1288
+ var tryParseRoutingDecision = (buffered) => {
1289
+ const trimmed = buffered.trim();
1290
+ if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
1291
+ try {
1292
+ const parsed = JSON.parse(trimmed);
1293
+ if (parsed && typeof parsed === "object") {
1294
+ return parsed;
1295
+ }
1296
+ return null;
1297
+ } catch {
1298
+ return null;
1299
+ }
1300
+ };
1301
+ var handleRoutingAgentDelta = (chunk, conversation, metadata) => {
1302
+ const delta = chunk.payload?.text ?? "";
1303
+ if (!delta) return conversation;
1304
+ const lastMessage = lastAssistant(conversation);
1305
+ const mergeRoutingMetadata = (existing) => {
1306
+ const buffered = (existing.routingDecisionBuffer ?? "") + delta;
1307
+ const next = { ...cloneMetadata(existing), mode: "network" };
1308
+ const parsed = tryParseRoutingDecision(buffered);
1309
+ if (parsed) {
1310
+ next.routingDecision = parsed;
1311
+ delete next.routingDecisionBuffer;
1312
+ delete next.routingDecisionText;
1313
+ } else {
1314
+ next.routingDecisionBuffer = buffered;
1315
+ next.routingDecisionText = buffered;
1316
+ }
1317
+ return next;
1318
+ };
1319
+ if (!lastMessage) {
1320
+ const seed = mergeRoutingMetadata({});
1321
+ return appendAssistantMessage(
1322
+ conversation,
1323
+ `routing-agent-${chunk.payload?.runId ?? "unknown"}-${Date.now()}`,
1324
+ [],
1325
+ { ...networkMode(metadata), ...seed }
1326
+ );
1327
+ }
1328
+ return replaceLast(conversation, withMetadata(lastMessage, mergeRoutingMetadata(lastMessage.content.metadata ?? {})));
1329
+ };
1330
+ var handleAgentNetworkChunk = (chunk, conversation, metadata) => {
1331
+ if (chunk.type === "agent-execution-start") {
1332
+ const primitiveId = chunk.payload?.args?.primitiveId;
1333
+ const runId = chunk.payload.runId;
1334
+ if (!primitiveId || !runId) return conversation;
1335
+ const toolPart = {
1336
+ type: "dynamic-tool",
1337
+ toolName: primitiveId,
1338
+ toolCallId: runId,
1339
+ state: "input-available",
1340
+ input: chunk.payload.args
1341
+ };
1342
+ return appendAssistantMessage(conversation, `agent-execution-start-${runId}-${Date.now()}`, [toolPart], {
1343
+ ...networkMode(metadata),
1344
+ selectionReason: chunk.payload?.args?.selectionReason || "",
1345
+ agentInput: chunk.payload?.args?.task,
1346
+ from: "AGENT"
1347
+ });
1348
+ }
1349
+ if (chunk.type === "agent-execution-end") {
1350
+ const lastMessage = lastAssistant(conversation);
1351
+ if (!lastMessage) return conversation;
1352
+ const parts = [...lastMessage.content.parts];
1353
+ const toolPartIndex = findPartIndex(parts, (part) => isDynamicToolPart(part));
1354
+ if (toolPartIndex !== -1) {
1355
+ const toolPart = parts[toolPartIndex];
1356
+ const currentOutput = toolPart.output;
1357
+ parts[toolPartIndex] = {
1358
+ type: "dynamic-tool",
1359
+ toolName: toolPart.toolName,
1360
+ toolCallId: toolPart.toolCallId,
1361
+ state: "output-available",
1362
+ input: toolPart.input,
1363
+ output: { ...currentOutput, result: currentOutput?.result || chunk.payload?.result || "" }
1364
+ };
1365
+ }
1366
+ return replaceLast(conversation, withParts(lastMessage, parts));
1367
+ }
1368
+ if (chunk.type.startsWith("agent-execution-event-")) {
1369
+ const lastMessage = lastAssistant(conversation);
1370
+ if (!lastMessage) return conversation;
1371
+ const agentChunk = chunk.payload;
1372
+ const parts = [...lastMessage.content.parts];
1373
+ const toolPartIndex = findPartIndex(parts, (part) => isDynamicToolPart(part));
1374
+ if (toolPartIndex === -1) return conversation;
1375
+ const toolPart = parts[toolPartIndex];
1376
+ if (agentChunk.type === "text-delta") {
1377
+ const childMessages = toolPart?.output?.childMessages || [];
1378
+ const lastChildMessage = childMessages[childMessages.length - 1];
1379
+ const textMessage = { type: "text", content: (lastChildMessage?.content || "") + agentChunk.payload.text };
1380
+ const nextMessages = lastChildMessage?.type === "text" ? [...childMessages.slice(0, -1), textMessage] : [...childMessages, textMessage];
1381
+ parts[toolPartIndex] = {
1382
+ ...toolPart,
1383
+ output: { childMessages: nextMessages }
1384
+ };
1385
+ } else if (agentChunk.type === "tool-call") {
1386
+ const childMessages = toolPart?.output?.childMessages || [];
1387
+ parts[toolPartIndex] = {
1388
+ ...toolPart,
1389
+ output: {
1390
+ ...toolPart?.output,
1391
+ childMessages: [
1392
+ ...childMessages,
1393
+ {
1394
+ type: "tool",
1395
+ toolCallId: agentChunk.payload.toolCallId,
1396
+ toolName: agentChunk.payload.toolName,
1397
+ args: agentChunk.payload.args
1398
+ }
1399
+ ]
1400
+ }
1401
+ };
1402
+ } else if (agentChunk.type === "tool-output") {
1403
+ if (agentChunk.payload?.output?.type?.startsWith("workflow-")) {
1404
+ const childMessages = toolPart?.output?.childMessages || [];
1405
+ const lastToolIndex = childMessages.length - 1;
1406
+ const currentMessage = childMessages[lastToolIndex];
1407
+ const actualExistingWorkflowState = currentMessage?.toolOutput || {};
1408
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(
1409
+ actualExistingWorkflowState,
1410
+ agentChunk.payload.output
1411
+ );
1412
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
1413
+ parts[toolPartIndex] = {
1414
+ ...toolPart,
1415
+ output: {
1416
+ ...toolPart?.output,
1417
+ childMessages: [...childMessages.slice(0, -1), { ...currentMessage, toolOutput: updatedWorkflowState }]
1418
+ }
1419
+ };
1420
+ }
1421
+ }
1422
+ } else if (agentChunk.type === "tool-result") {
1423
+ const childMessages = toolPart?.output?.childMessages || [];
1424
+ const lastToolIndex = childMessages.length - 1;
1425
+ const isWorkflow = Boolean(agentChunk.payload?.result?.result?.steps);
1426
+ if (lastToolIndex >= 0 && childMessages[lastToolIndex]?.type === "tool") {
1427
+ parts[toolPartIndex] = {
1428
+ ...toolPart,
1429
+ output: {
1430
+ ...toolPart?.output,
1431
+ childMessages: [
1432
+ ...childMessages.slice(0, -1),
1433
+ {
1434
+ ...childMessages[lastToolIndex],
1435
+ toolOutput: isWorkflow ? agentChunk.payload.result.result : agentChunk.payload.result
1436
+ }
1437
+ ]
1438
+ }
1439
+ };
1440
+ }
1441
+ }
1442
+ return replaceLast(conversation, withParts(lastMessage, parts));
1443
+ }
1444
+ return conversation;
1445
+ };
1446
+ var handleWorkflowNetworkChunk = (chunk, conversation, metadata) => {
1447
+ if (chunk.type === "workflow-execution-start") {
1448
+ const primitiveId = chunk.payload?.args?.primitiveId;
1449
+ const runId = chunk.payload.runId;
1450
+ if (!primitiveId || !runId) return conversation;
1451
+ let agentInput;
1452
+ try {
1453
+ agentInput = JSON.parse(chunk.payload?.args?.prompt);
1454
+ } catch {
1455
+ agentInput = chunk.payload?.args?.prompt;
1456
+ }
1457
+ const toolPart = {
1458
+ type: "dynamic-tool",
1459
+ toolName: primitiveId,
1460
+ toolCallId: runId,
1461
+ state: "input-available",
1462
+ input: chunk.payload.args
1463
+ };
1464
+ return appendAssistantMessage(conversation, `workflow-start-${runId}-${Date.now()}`, [toolPart], {
1465
+ ...networkMode(metadata),
1466
+ selectionReason: chunk.payload?.args?.selectionReason || "",
1467
+ from: "WORKFLOW",
1468
+ agentInput
1469
+ });
1470
+ }
1471
+ if (chunk.type === "workflow-execution-suspended") {
1472
+ const lastMessage = lastAssistant(conversation);
1473
+ if (!lastMessage) return conversation;
1474
+ const existing = lastMessage.content.metadata?.suspendedTools ?? {};
1475
+ return replaceLast(
1476
+ conversation,
1477
+ withMetadata(lastMessage, {
1478
+ ...cloneMetadata(lastMessage.content.metadata),
1479
+ mode: "network",
1480
+ suspendedTools: {
1481
+ ...existing,
1482
+ [chunk.payload.toolName]: {
1483
+ toolCallId: chunk.payload.toolCallId,
1484
+ toolName: chunk.payload.toolName,
1485
+ args: chunk.payload.args,
1486
+ suspendPayload: chunk.payload.suspendPayload,
1487
+ runId: chunk.payload.runId
1488
+ }
1489
+ }
1490
+ })
1491
+ );
1492
+ }
1493
+ if (chunk.type.startsWith("workflow-execution-event-")) {
1494
+ const lastMessage = lastAssistant(conversation);
1495
+ if (!lastMessage) return conversation;
1496
+ const parts = [...lastMessage.content.parts];
1497
+ const toolPartIndex = findPartIndex(parts, (part) => isDynamicToolPart(part));
1498
+ if (toolPartIndex === -1) return conversation;
1499
+ const toolPart = parts[toolPartIndex];
1500
+ const existingWorkflowState = toolPart.output || {};
1501
+ const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(existingWorkflowState, chunk.payload);
1502
+ parts[toolPartIndex] = { ...toolPart, output: updatedWorkflowState };
1503
+ return replaceLast(conversation, withParts(lastMessage, parts));
1504
+ }
1505
+ return conversation;
1506
+ };
1507
+ var handleToolNetworkChunk = (chunk, conversation, metadata) => {
1508
+ if (chunk.type === "tool-execution-start") {
1509
+ const argsData = chunk.payload.args;
1510
+ const nestedArgs = argsData.args || {};
1511
+ const lastMessage = lastAssistant(conversation);
1512
+ const toolPart = {
1513
+ type: "dynamic-tool",
1514
+ toolName: argsData.toolName || "unknown",
1515
+ toolCallId: argsData.toolCallId || "unknown",
1516
+ state: "input-available",
1517
+ input: nestedArgs
1518
+ };
1519
+ if (!lastMessage) {
1520
+ return appendAssistantMessage(
1521
+ conversation,
1522
+ `tool-start-${chunk.payload.runId}-${Date.now()}`,
1523
+ [toolPart],
1524
+ {
1525
+ ...networkMode(metadata),
1526
+ selectionReason: metadata.mode === "network" ? metadata.selectionReason || argsData.selectionReason : "",
1527
+ agentInput: nestedArgs
1528
+ }
1529
+ );
1530
+ }
1531
+ const parts = [...lastMessage.content.parts, toolPart];
1532
+ return replaceLast(conversation, withParts(lastMessage, parts));
1533
+ }
1534
+ if (chunk.type === "tool-execution-approval") {
1535
+ const lastMessage = lastAssistant(conversation);
1536
+ if (!lastMessage) return conversation;
1537
+ const existing = lastMessage.content.metadata?.requireApprovalMetadata ?? {};
1538
+ return replaceLast(
1539
+ conversation,
1540
+ withMetadata(lastMessage, {
1541
+ ...cloneMetadata(lastMessage.content.metadata),
1542
+ mode: "network",
1543
+ requireApprovalMetadata: {
1544
+ ...existing,
1545
+ [chunk.payload.toolName]: {
1546
+ toolCallId: chunk.payload.toolCallId,
1547
+ toolName: chunk.payload.toolName,
1548
+ args: chunk.payload.args,
1549
+ runId: chunk.payload.runId
1550
+ }
1551
+ }
1552
+ })
1553
+ );
1554
+ }
1555
+ if (chunk.type === "tool-execution-suspended") {
1556
+ const lastMessage = lastAssistant(conversation);
1557
+ if (!lastMessage) return conversation;
1558
+ const existing = lastMessage.content.metadata?.suspendedTools ?? {};
1559
+ return replaceLast(
1560
+ conversation,
1561
+ withMetadata(lastMessage, {
1562
+ ...cloneMetadata(lastMessage.content.metadata),
1563
+ mode: "network",
1564
+ suspendedTools: {
1565
+ ...existing,
1566
+ [chunk.payload.toolName]: {
1567
+ toolCallId: chunk.payload.toolCallId,
1568
+ toolName: chunk.payload.toolName,
1569
+ args: chunk.payload.args,
1570
+ suspendPayload: chunk.payload.suspendPayload,
1571
+ runId: chunk.payload.runId
1572
+ }
1573
+ }
1574
+ })
1575
+ );
1576
+ }
1577
+ if (chunk.type === "tool-execution-end") {
1578
+ const lastMessage = lastAssistant(conversation);
1579
+ if (!lastMessage) return conversation;
1580
+ const parts = [...lastMessage.content.parts];
1581
+ const toolPartIndex = findPartIndex(
1582
+ parts,
1583
+ (part) => isDynamicToolPart(part) && part.toolCallId === chunk.payload.toolCallId
1584
+ );
1585
+ if (toolPartIndex !== -1) {
1586
+ const toolPart = parts[toolPartIndex];
1587
+ const currentOutput = toolPart.output;
1588
+ parts[toolPartIndex] = {
1589
+ type: "dynamic-tool",
1590
+ toolName: toolPart.toolName,
1591
+ toolCallId: toolPart.toolCallId,
1592
+ state: "output-available",
1593
+ input: toolPart.input,
1594
+ output: currentOutput?.result || chunk.payload?.result || ""
1595
+ };
1596
+ }
1597
+ return replaceLast(conversation, withParts(lastMessage, parts));
1598
+ }
1599
+ return conversation;
1600
+ };
1601
+ var accumulateNetworkChunk = ({
1602
+ chunk,
1603
+ conversation,
1604
+ metadata
1605
+ }) => {
1606
+ const newConversation = [...conversation];
1607
+ if (chunk.type === "routing-agent-text-delta") {
1608
+ return handleRoutingAgentDelta(chunk, newConversation, metadata);
1609
+ }
1610
+ if (chunk.type.startsWith("agent-execution-")) {
1611
+ return handleAgentNetworkChunk(chunk, newConversation, metadata);
1612
+ }
1613
+ if (chunk.type.startsWith("workflow-execution-")) {
1614
+ return handleWorkflowNetworkChunk(chunk, newConversation, metadata);
1615
+ }
1616
+ if (chunk.type.startsWith("tool-execution-")) {
1617
+ return handleToolNetworkChunk(chunk, newConversation, metadata);
1618
+ }
1619
+ if (chunk.type === "network-validation-end") {
1620
+ if (chunk.payload.suppressFeedback) return newConversation;
1621
+ const feedback = formatCompletionFeedback(
1622
+ {
1623
+ complete: chunk.payload.passed,
1624
+ scorers: chunk.payload.results,
1625
+ totalDuration: chunk.payload.duration,
1626
+ timedOut: chunk.payload.timedOut},
1627
+ chunk.payload.maxIterationReached
1628
+ );
1629
+ const textPart = { type: "text", text: feedback };
1630
+ return appendAssistantMessage(
1631
+ newConversation,
1632
+ `network-validation-end-${chunk.payload.runId}-${Date.now()}`,
1633
+ [textPart],
1634
+ {
1635
+ ...networkMode(metadata),
1636
+ completionResult: { passed: chunk.payload.passed }
1637
+ }
1638
+ );
1639
+ }
1640
+ if (chunk.type === "network-execution-event-step-finish") {
1641
+ const lastMessage = lastAssistant(newConversation);
1642
+ if (!lastMessage) return newConversation;
1643
+ const agentChunk = chunk.payload;
1644
+ const parts = [...lastMessage.content.parts];
1645
+ const textPartIndex = findPartIndex(parts, (part) => part.type === "text");
1646
+ if (textPartIndex === -1) {
1647
+ parts.push({ type: "text", text: agentChunk.result, state: "done" });
1648
+ return replaceLast(newConversation, withParts(lastMessage, parts));
1649
+ }
1650
+ const textPart = parts[textPartIndex];
1651
+ if (textPart.type === "text") {
1652
+ parts[textPartIndex] = {
1653
+ ...textPart,
1654
+ state: "done"
1655
+ };
1656
+ return replaceLast(newConversation, withParts(lastMessage, parts));
1657
+ }
1658
+ return newConversation;
1659
+ }
1660
+ return newConversation;
1661
+ };
1662
+
1663
+ // src/lib/mastra-db/fromCoreUserMessage.ts
1664
+ var coreUserMessageToParts = (coreUserMessage) => typeof coreUserMessage.content === "string" ? [{ type: "text", text: coreUserMessage.content }] : coreUserMessage.content.map((part) => {
1665
+ switch (part.type) {
1666
+ case "text": {
1667
+ return { type: "text", text: part.text };
1668
+ }
1669
+ case "image": {
1670
+ const data = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
1671
+ return {
1672
+ type: "file",
1673
+ mimeType: part.mimeType ?? "image/*",
1674
+ data
1675
+ };
1676
+ }
1677
+ case "file": {
1678
+ const data = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
1679
+ return {
1680
+ type: "file",
1681
+ mimeType: part.mimeType,
1682
+ data,
1683
+ ...part.filename !== void 0 ? { filename: part.filename } : {}
1684
+ };
1685
+ }
1686
+ default: {
1687
+ const exhaustiveCheck = part;
1688
+ throw new Error(`Unhandled content part type: ${exhaustiveCheck.type}`);
1689
+ }
1690
+ }
1691
+ });
1692
+ var newUserMessage = (parts) => ({
1693
+ id: `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
1694
+ role: "user",
1695
+ createdAt: /* @__PURE__ */ new Date(),
1696
+ content: {
1697
+ format: 2,
1698
+ parts
1699
+ }
1700
+ });
1701
+ var fromCoreUserMessageToMastraDBMessage = (coreUserMessage) => newUserMessage(coreUserMessageToParts(coreUserMessage));
1702
+ var fromCoreUserMessagesToMastraDBMessage = (coreUserMessages) => newUserMessage(coreUserMessages.flatMap(coreUserMessageToParts));
1703
+
1704
+ // src/agent/extractRunIdFromMessages.ts
1705
+ var isRecord = (value) => value !== null && typeof value === "object";
1706
+ var runIdMetadataKeys = ["pendingToolApprovals", "requireApprovalMetadata", "suspendedTools"];
1707
+ var isRunIdMetadataSource = (value) => isRecord(value) && Object.values(value).every((entry) => isRecord(entry));
1708
+ var getRunIdMetadataSources = (metadata) => {
1709
+ if (!isRecord(metadata)) return [];
1710
+ const sources = [];
1711
+ for (const key of runIdMetadataKeys) {
1712
+ const source = metadata[key];
1713
+ if (isRunIdMetadataSource(source)) {
1714
+ sources.push(source);
1715
+ }
1716
+ }
1717
+ return sources;
1718
+ };
1719
+ var extractRunIdFromMessages = (messages) => {
1720
+ for (const message of messages) {
1721
+ for (const source of getRunIdMetadataSources(message.content?.metadata)) {
1722
+ for (const entry of Object.values(source)) {
1723
+ if (isRecord(entry) && typeof entry.runId === "string" && entry.runId.length > 0) {
1724
+ return entry.runId;
1725
+ }
1726
+ }
1727
+ }
1728
+ }
1729
+ return void 0;
1730
+ };
1731
+
1732
+ // src/agent/signal-data.ts
1733
+ function convertSignalDataToBase64String(content) {
1734
+ if (typeof content === "string") {
1735
+ return content;
1736
+ }
1737
+ const bytes = content instanceof ArrayBuffer ? new Uint8Array(content) : content;
1738
+ let binary = "";
1739
+ for (const byte of bytes) {
1740
+ binary += String.fromCharCode(byte);
1741
+ }
1742
+ return btoa(binary);
1743
+ }
1744
+
1745
+ // src/agent/hooks.ts
1746
+ var extractPendingToolApprovalIdsFromMessages = (messages) => {
1747
+ const pendingToolApprovalIds = /* @__PURE__ */ new Set();
1748
+ for (const message of messages) {
1749
+ const metadata = message.content?.metadata;
1750
+ if (!metadata) continue;
1751
+ const metadataSources = [
1752
+ metadata.pendingToolApprovals,
1753
+ metadata.requireApprovalMetadata,
1754
+ metadata.suspendedTools
1755
+ ];
1756
+ for (const source of metadataSources) {
1757
+ if (!source || typeof source !== "object") continue;
1758
+ for (const suspensionData of Object.values(source)) {
1759
+ const toolCallId = suspensionData?.toolCallId;
1760
+ if (typeof toolCallId === "string" && toolCallId.length > 0) {
1761
+ pendingToolApprovalIds.add(toolCallId);
1762
+ }
1763
+ }
1764
+ }
1765
+ }
1766
+ return pendingToolApprovalIds;
1767
+ };
1768
+ var toolCallHasOutput = (parts, toolCallId) => parts.some((part) => {
1769
+ if (part.type !== "tool-invocation") return false;
1770
+ const invocation = part.toolInvocation;
1771
+ if (invocation.toolCallId !== toolCallId) return false;
1772
+ return invocation.state === "result" || invocation.result != null;
1773
+ });
1774
+ var resolveInitialMessages = (messages) => messages.filter((message) => {
1775
+ const metadata = message.content?.metadata;
1776
+ if (metadata?.completionResult?.suppressFeedback || metadata?.isTaskCompleteResult?.suppressFeedback) {
1777
+ return false;
1778
+ }
1779
+ return true;
1780
+ }).map((message) => {
1781
+ const metadata = message.content?.metadata;
1782
+ const normalizedMessage = metadata && (metadata.status === "pending" || CLIENT_MESSAGE_ID_KEY in metadata) ? (() => {
1783
+ const { [CLIENT_MESSAGE_ID_KEY]: _omitClientMessageId, ...rest } = metadata;
1784
+ const { status: _omitStatus, ...restWithoutStatus } = rest;
1785
+ return {
1786
+ ...message,
1787
+ content: {
1788
+ ...message.content,
1789
+ metadata: metadata.status === "pending" ? restWithoutStatus : rest
1790
+ }
1791
+ };
1792
+ })() : message;
1793
+ const normalizedMetadata = normalizedMessage.content?.metadata;
1794
+ const pendingToolApprovals = normalizedMetadata?.pendingToolApprovals;
1795
+ if (!pendingToolApprovals || typeof pendingToolApprovals !== "object") {
1796
+ return normalizedMessage;
1797
+ }
1798
+ const stillPending = Object.fromEntries(
1799
+ Object.entries(pendingToolApprovals).filter(
1800
+ ([, approval]) => approval && typeof approval === "object" && typeof approval.toolCallId === "string" && !toolCallHasOutput(normalizedMessage.content.parts, approval.toolCallId)
1801
+ )
1802
+ );
1803
+ const { pendingToolApprovals: _omit, ...restMetadata } = normalizedMetadata;
1804
+ const hasStillPending = Object.keys(stillPending).length > 0;
1805
+ return {
1806
+ ...normalizedMessage,
1807
+ content: {
1808
+ ...normalizedMessage.content,
1809
+ metadata: {
1810
+ ...restMetadata,
1811
+ mode: "stream",
1812
+ ...hasStillPending ? { pendingToolApprovals: stillPending, requireApprovalMetadata: stillPending } : {}
1813
+ }
1814
+ }
1815
+ };
1816
+ });
1817
+ var isObject = (value) => typeof value === "object" && value !== null;
1818
+ var getErrorName = (error) => isObject(error) && typeof error.name === "string" ? error.name : void 0;
1819
+ var isAbortError = (error) => getErrorName(error) === "AbortError";
1820
+ var isThreadSignalUnsupportedError = (error) => {
1821
+ if (!isObject(error)) return false;
1822
+ const status = error.status;
1823
+ if (status === 404 || status === 405 || status === 501) {
1824
+ return true;
1825
+ }
1826
+ return status === 400 && typeof error.message === "string" && error.message.includes("No active agent run found for signal target");
1827
+ };
1828
+ var isDataChunk2 = (chunk) => typeof chunk.type === "string" && chunk.type.startsWith("data-");
1829
+ var dbFromServerUiMessages = (uiMessages, metadata) => uiMessages.map((uiMsg) => {
1830
+ const dbMsg = AIV5Adapter.fromUIMessage(uiMsg);
1831
+ return {
1832
+ ...dbMsg,
1833
+ content: {
1834
+ ...dbMsg.content,
1835
+ metadata: {
1836
+ ...dbMsg.content.metadata ?? {},
1837
+ ...metadata
1838
+ }
1839
+ }
1840
+ };
1841
+ });
1842
+ var useChat = ({
1843
+ agentId,
1844
+ resourceId,
1845
+ threadId,
1846
+ initialMessages,
1847
+ requestContext: propsRequestContext,
1848
+ clientTools: hookClientTools,
1849
+ onSignalSent,
1850
+ onSignalEcho,
1851
+ onThreadSignalsUnsupported,
1852
+ enableThreadSignals = false
1853
+ }) => {
1854
+ const threadSignalsDisabled = enableThreadSignals === false;
1855
+ const _currentRunId = useRef(void 0);
1856
+ const _onChunk = useRef(void 0);
1857
+ const _networkRunId = useRef(void 0);
1858
+ const _onNetworkChunk = useRef(void 0);
1859
+ const _requestContext = useRef(propsRequestContext);
1860
+ const _streamAbortRef = useRef(null);
1861
+ const _threadSubscriptionAbortRef = useRef(null);
1862
+ const _threadSubscriptionRef = useRef(
1863
+ null
1864
+ );
1865
+ const _threadSubscriptionKeyRef = useRef(void 0);
1866
+ const _threadSubscriptionPromiseRef = useRef(null);
1867
+ const _threadSignalsUnsupportedRef = useRef(false);
1868
+ const [messages, setMessages] = useState([]);
1869
+ const [toolCallApprovals, setToolCallApprovals] = useState({});
1870
+ const [networkToolCallApprovals, setNetworkToolCallApprovals] = useState({});
1871
+ const pendingToolApprovalIdsRef = useRef(/* @__PURE__ */ new Set());
1872
+ const [isAwaitingToolApproval, setIsAwaitingToolApproval] = useState(false);
1873
+ const baseClient = useMastraClient();
1874
+ const [isRunning, setIsRunning] = useState(false);
1875
+ useEffect(() => {
1876
+ const formattedMessages = resolveInitialMessages(initialMessages ?? []);
1877
+ setMessages(formattedMessages);
1878
+ pendingToolApprovalIdsRef.current = extractPendingToolApprovalIdsFromMessages(formattedMessages);
1879
+ setIsAwaitingToolApproval(pendingToolApprovalIdsRef.current.size > 0);
1880
+ _currentRunId.current = extractRunIdFromMessages(formattedMessages);
1881
+ }, [initialMessages]);
1882
+ useEffect(() => {
1883
+ _requestContext.current = propsRequestContext;
1884
+ }, [propsRequestContext]);
1885
+ const normalizeSignalFileData = (data) => {
1886
+ if (data instanceof URL) return data.toString();
1887
+ return convertSignalDataToBase64String(data);
1888
+ };
1889
+ const getSignalContents = (coreUserMessages) => {
1890
+ const parts = coreUserMessages.reduce((allParts, message) => {
1891
+ if (typeof message.content === "string") {
1892
+ allParts.push({ type: "text", text: message.content });
1893
+ return allParts;
1894
+ }
1895
+ for (const part of message.content) {
1896
+ if (part.type === "text") {
1897
+ allParts.push({ type: "text", text: part.text });
1898
+ } else if (part.type === "file") {
1899
+ allParts.push({
1900
+ type: "file",
1901
+ data: normalizeSignalFileData(part.data),
1902
+ mediaType: part.mimeType,
1903
+ ...part.filename ? { filename: part.filename } : {}
1904
+ });
1905
+ } else if (part.type === "image") {
1906
+ allParts.push({
1907
+ type: "file",
1908
+ data: normalizeSignalFileData(part.image),
1909
+ mediaType: part.mimeType ?? "image/png"
1910
+ });
1911
+ }
1912
+ }
1913
+ return allParts;
1914
+ }, []);
1915
+ return parts.length === 1 && parts[0]?.type === "text" ? parts[0].text : parts;
1916
+ };
1917
+ const markThreadSignalsUnsupported = useCallback(() => {
1918
+ _threadSignalsUnsupportedRef.current = true;
1919
+ onThreadSignalsUnsupported?.();
1920
+ }, [onThreadSignalsUnsupported]);
1921
+ const getSignalPreview = (coreUserMessages) => {
1922
+ const preview = coreUserMessages.flatMap((message) => {
1923
+ if (typeof message.content === "string") {
1924
+ return [message.content];
1925
+ }
1926
+ return message.content.map((part) => {
1927
+ if (part.type === "text") return part.text;
1928
+ if (part.type === "image") return "Image";
1929
+ return part.filename ? `File: ${part.filename}` : "File";
1930
+ });
1931
+ }).join(" ").replace(/\s+/g, " ").trim();
1932
+ return preview || "Attachment";
1933
+ };
1934
+ const closeThreadSubscription = useCallback(() => {
1935
+ const subscription = _threadSubscriptionRef.current;
1936
+ if (subscription?.unsubscribe) {
1937
+ subscription.unsubscribe();
1938
+ } else {
1939
+ _threadSubscriptionAbortRef.current?.abort();
1940
+ }
1941
+ _threadSubscriptionRef.current = null;
1942
+ _threadSubscriptionAbortRef.current = null;
1943
+ _threadSubscriptionKeyRef.current = void 0;
1944
+ _threadSubscriptionPromiseRef.current = null;
1945
+ }, []);
1946
+ const processStreamChunk = useCallback(
1947
+ async (chunk, onChunk) => {
1948
+ setMessages((prev) => accumulateChunk({ chunk, conversation: prev, metadata: { mode: "stream" } }));
1949
+ if (chunk.type === "data-user-message" && isDataChunk2(chunk) && (chunk.data?.type === "user-message" || chunk.data?.type === "user") && typeof chunk.data?.id === "string") {
1950
+ onSignalEcho?.(chunk.data.id);
1951
+ }
1952
+ if (chunk.type === "start") {
1953
+ setIsRunning(true);
1954
+ if ("runId" in chunk && typeof chunk.runId === "string") {
1955
+ _currentRunId.current = chunk.runId;
1956
+ }
1957
+ }
1958
+ if (chunk.type === "tool-call-approval" || chunk.type === "tool-call-suspended") {
1959
+ const toolCallId = chunk.payload?.toolCallId;
1960
+ if (typeof toolCallId === "string") {
1961
+ pendingToolApprovalIdsRef.current.add(toolCallId);
1962
+ setIsAwaitingToolApproval(true);
1963
+ }
1964
+ setIsRunning(false);
1965
+ }
1966
+ if (chunk.type === "finish" || chunk.type === "abort" || chunk.type === "error") {
1967
+ pendingToolApprovalIdsRef.current.clear();
1968
+ setIsAwaitingToolApproval(false);
1969
+ setIsRunning(false);
1970
+ }
1971
+ void (onChunk ?? _onChunk.current)?.(chunk);
1972
+ },
1973
+ [onSignalEcho]
1974
+ );
1975
+ const ensureThreadSubscription = useCallback(
1976
+ async ({ threadId: threadId2, resourceId: resourceId2 }) => {
1977
+ const subscriptionKey = `${agentId}:${resourceId2 ?? ""}:${threadId2}`;
1978
+ if (_threadSubscriptionKeyRef.current === subscriptionKey && _threadSubscriptionPromiseRef.current) {
1979
+ await _threadSubscriptionPromiseRef.current;
1980
+ return;
1981
+ }
1982
+ closeThreadSubscription();
1983
+ const subscriptionAbort = new AbortController();
1984
+ _threadSubscriptionAbortRef.current = subscriptionAbort;
1985
+ _threadSubscriptionKeyRef.current = subscriptionKey;
1986
+ const clientWithAbort = new MastraClient({
1987
+ ...baseClient.options,
1988
+ abortSignal: subscriptionAbort.signal
1989
+ });
1990
+ const subscriptionAgent = clientWithAbort.getAgent(agentId);
1991
+ _threadSubscriptionPromiseRef.current = subscriptionAgent.subscribeToThread({ resourceId: resourceId2, threadId: threadId2 }).then((response) => {
1992
+ const subscription = response;
1993
+ if (_threadSubscriptionAbortRef.current !== subscriptionAbort) {
1994
+ subscription.unsubscribe();
1995
+ return;
1996
+ }
1997
+ _threadSubscriptionRef.current = subscription;
1998
+ void subscription.processDataStream({
1999
+ onChunk: (chunk) => processStreamChunk(chunk)
2000
+ }).catch((error) => {
2001
+ if (!isAbortError(error)) {
2002
+ console.error("[useChat] Thread subscription failed", error);
2003
+ setIsRunning(false);
2004
+ }
2005
+ }).finally(() => {
2006
+ if (_threadSubscriptionRef.current === subscription) {
2007
+ _threadSubscriptionRef.current = null;
2008
+ }
2009
+ if (_threadSubscriptionAbortRef.current === subscriptionAbort) {
2010
+ _threadSubscriptionAbortRef.current = null;
2011
+ _threadSubscriptionKeyRef.current = void 0;
2012
+ _threadSubscriptionPromiseRef.current = null;
2013
+ }
2014
+ });
2015
+ }).catch((error) => {
2016
+ if (isThreadSignalUnsupportedError(error)) {
2017
+ markThreadSignalsUnsupported();
2018
+ if (_threadSubscriptionAbortRef.current === subscriptionAbort) {
2019
+ _threadSubscriptionRef.current = null;
2020
+ _threadSubscriptionAbortRef.current = null;
2021
+ _threadSubscriptionKeyRef.current = void 0;
2022
+ _threadSubscriptionPromiseRef.current = null;
2023
+ }
2024
+ return;
2025
+ }
2026
+ if (!isAbortError(error)) {
2027
+ console.error("[useChat] Thread subscription failed", error);
2028
+ setIsRunning(false);
2029
+ }
2030
+ throw error;
2031
+ });
2032
+ await _threadSubscriptionPromiseRef.current;
2033
+ },
2034
+ [agentId, baseClient, closeThreadSubscription, markThreadSignalsUnsupported, processStreamChunk]
2035
+ );
2036
+ useEffect(() => {
2037
+ _threadSignalsUnsupportedRef.current = false;
2038
+ return closeThreadSubscription;
2039
+ }, [agentId, resourceId, threadId, closeThreadSubscription]);
2040
+ useEffect(() => {
2041
+ if (!threadId || threadSignalsDisabled) {
2042
+ closeThreadSubscription();
2043
+ return;
2044
+ }
2045
+ void ensureThreadSubscription({ threadId, resourceId: resourceId || agentId }).catch((error) => {
2046
+ if (!isAbortError(error)) {
2047
+ console.error("[useChat] Thread subscription failed", error);
2048
+ }
2049
+ });
2050
+ }, [agentId, closeThreadSubscription, ensureThreadSubscription, resourceId, threadId, threadSignalsDisabled]);
2051
+ const generate = async ({
2052
+ coreUserMessages,
2053
+ requestContext,
2054
+ threadId: threadId2,
2055
+ modelSettings,
2056
+ signal,
2057
+ onFinish,
2058
+ tracingOptions,
2059
+ clientTools
2060
+ }) => {
2061
+ const {
2062
+ frequencyPenalty,
2063
+ presencePenalty,
2064
+ maxRetries,
2065
+ maxTokens,
2066
+ temperature,
2067
+ topK,
2068
+ topP,
2069
+ instructions,
2070
+ providerOptions,
2071
+ maxSteps,
2072
+ requireToolApproval
2073
+ } = modelSettings || {};
2074
+ const resolvedRequestContext = requestContext ?? propsRequestContext;
2075
+ const resolvedClientTools = clientTools ?? hookClientTools;
2076
+ _requestContext.current = resolvedRequestContext;
2077
+ setIsRunning(true);
2078
+ const clientWithAbort = new MastraClient({
2079
+ ...baseClient.options,
2080
+ abortSignal: signal
2081
+ });
2082
+ const agent = clientWithAbort.getAgent(agentId);
2083
+ const runId = v4();
2084
+ _currentRunId.current = runId;
2085
+ const response = await agent.generate(coreUserMessages, {
2086
+ runId,
2087
+ maxSteps,
2088
+ modelSettings: {
2089
+ frequencyPenalty,
2090
+ presencePenalty,
2091
+ maxRetries,
2092
+ maxOutputTokens: maxTokens,
2093
+ temperature,
2094
+ topK,
2095
+ topP
2096
+ },
2097
+ instructions,
2098
+ requestContext: resolvedRequestContext,
2099
+ ...threadId2 ? { memory: { thread: threadId2, resource: resourceId || agentId } } : {},
2100
+ providerOptions,
2101
+ tracingOptions,
2102
+ requireToolApproval,
2103
+ clientTools: resolvedClientTools
2104
+ });
2105
+ if (response.finishReason === "suspended" && response.suspendPayload) {
2106
+ const { toolCallId, toolName, args } = response.suspendPayload;
2107
+ if (response.response?.uiMessages) {
2108
+ const dbMessages = dbFromServerUiMessages(response.response.uiMessages, {
2109
+ mode: "generate",
2110
+ requireApprovalMetadata: {
2111
+ [toolName]: { toolCallId, toolName, args }
2112
+ }
2113
+ });
2114
+ setMessages((prev) => [...prev, ...dbMessages]);
2115
+ }
2116
+ setIsRunning(false);
2117
+ return;
2118
+ }
2119
+ setIsRunning(false);
2120
+ if (response && "uiMessages" in response.response && response.response.uiMessages) {
2121
+ const dbMessages = dbFromServerUiMessages(response.response.uiMessages, { mode: "generate" });
2122
+ void onFinish?.(dbMessages);
2123
+ setMessages((prev) => [...prev, ...dbMessages]);
2124
+ }
2125
+ };
2126
+ const stream = async ({
2127
+ coreUserMessages,
2128
+ requestContext,
2129
+ threadId: threadId2,
2130
+ onChunk,
2131
+ modelSettings,
2132
+ signal,
2133
+ tracingOptions,
2134
+ clientTools,
2135
+ signalId,
2136
+ clientMessageId
2137
+ }) => {
2138
+ const {
2139
+ frequencyPenalty,
2140
+ presencePenalty,
2141
+ maxRetries,
2142
+ maxTokens,
2143
+ temperature,
2144
+ topK,
2145
+ topP,
2146
+ instructions,
2147
+ providerOptions,
2148
+ maxSteps,
2149
+ requireToolApproval
2150
+ } = modelSettings || {};
2151
+ const resolvedRequestContext = requestContext ?? propsRequestContext;
2152
+ const resolvedClientTools = clientTools ?? hookClientTools;
2153
+ const signalContinuationOptions = {
2154
+ maxSteps,
2155
+ modelSettings: {
2156
+ frequencyPenalty,
2157
+ presencePenalty,
2158
+ maxRetries,
2159
+ maxOutputTokens: maxTokens,
2160
+ temperature,
2161
+ topK,
2162
+ topP
2163
+ },
2164
+ instructions,
2165
+ providerOptions,
2166
+ requireToolApproval,
2167
+ tracingOptions
2168
+ };
2169
+ _requestContext.current = resolvedRequestContext;
2170
+ setIsRunning(true);
2171
+ _streamAbortRef.current?.abort();
2172
+ const internalAbort = new AbortController();
2173
+ _streamAbortRef.current = internalAbort;
2174
+ if (signal) {
2175
+ if (signal.aborted) internalAbort.abort();
2176
+ else signal.addEventListener("abort", () => internalAbort.abort(), { once: true });
2177
+ }
2178
+ const clientWithAbort = new MastraClient({
2179
+ ...baseClient.options,
2180
+ abortSignal: internalAbort.signal
2181
+ });
2182
+ const agent = clientWithAbort.getAgent(agentId);
2183
+ const streamWithLegacyRoute = async () => {
2184
+ const runId = v4();
2185
+ const response = await agent.stream(coreUserMessages, {
2186
+ runId,
2187
+ maxSteps,
2188
+ untilIdle: true,
2189
+ modelSettings: {
2190
+ frequencyPenalty,
2191
+ presencePenalty,
2192
+ maxRetries,
2193
+ maxOutputTokens: maxTokens,
2194
+ temperature,
2195
+ topK,
2196
+ topP
2197
+ },
2198
+ instructions,
2199
+ requestContext: resolvedRequestContext,
2200
+ ...threadId2 ? { memory: { thread: threadId2, resource: resourceId || agentId } } : {},
2201
+ providerOptions,
2202
+ requireToolApproval,
2203
+ tracingOptions,
2204
+ clientTools: resolvedClientTools
2205
+ });
2206
+ _onChunk.current = onChunk;
2207
+ _currentRunId.current = runId;
2208
+ await response.processDataStream({
2209
+ onChunk: (chunk) => processStreamChunk(chunk, onChunk)
2210
+ });
2211
+ if (_streamAbortRef.current === internalAbort) {
2212
+ _streamAbortRef.current = null;
2213
+ }
2214
+ setIsRunning(false);
2215
+ };
2216
+ if (!threadId2 || _threadSignalsUnsupportedRef.current || threadSignalsDisabled) {
2217
+ await streamWithLegacyRoute();
2218
+ return;
2219
+ }
2220
+ _onChunk.current = onChunk;
2221
+ await ensureThreadSubscription({ threadId: threadId2, resourceId: resourceId || agentId });
2222
+ if (_threadSignalsUnsupportedRef.current) {
2223
+ await streamWithLegacyRoute();
2224
+ return;
2225
+ }
2226
+ const resolvedSignalId = signalId ?? v4();
2227
+ const messageContents = getSignalContents(coreUserMessages);
2228
+ const streamOptions = {
2229
+ maxSteps,
2230
+ modelSettings: {
2231
+ frequencyPenalty,
2232
+ presencePenalty,
2233
+ maxRetries,
2234
+ maxOutputTokens: maxTokens,
2235
+ temperature,
2236
+ topK,
2237
+ topP
2238
+ },
2239
+ instructions,
2240
+ requestContext: resolvedRequestContext,
2241
+ providerOptions,
2242
+ requireToolApproval,
2243
+ tracingOptions
2244
+ };
2245
+ try {
2246
+ const result = await agent.sendMessage({
2247
+ message: clientMessageId ? { contents: messageContents, metadata: { [CLIENT_MESSAGE_ID_KEY]: clientMessageId } } : messageContents,
2248
+ resourceId: resourceId || agentId,
2249
+ threadId: threadId2,
2250
+ ifIdle: {
2251
+ streamOptions: {
2252
+ ...signalContinuationOptions,
2253
+ requestContext: resolvedRequestContext,
2254
+ clientTools: resolvedClientTools
2255
+ }
2256
+ }
2257
+ });
2258
+ const echoedSignalId = result.signal && typeof result.signal === "object" && "id" in result.signal && typeof result.signal.id === "string" ? result.signal.id : resolvedSignalId;
2259
+ onSignalSent?.(echoedSignalId, getSignalPreview(coreUserMessages));
2260
+ if (pendingToolApprovalIdsRef.current.size > 0) {
2261
+ setIsRunning(false);
2262
+ }
2263
+ } catch (error) {
2264
+ if (isThreadSignalUnsupportedError(error)) {
2265
+ onSignalSent?.(resolvedSignalId, getSignalPreview(coreUserMessages));
2266
+ try {
2267
+ await agent.sendSignal({
2268
+ signal: {
2269
+ id: resolvedSignalId,
2270
+ type: "user-message",
2271
+ contents: messageContents
2272
+ },
2273
+ resourceId: resourceId || agentId,
2274
+ threadId: threadId2,
2275
+ ifIdle: { streamOptions }
2276
+ });
2277
+ return;
2278
+ } catch (signalError) {
2279
+ onSignalEcho?.(resolvedSignalId);
2280
+ if (isThreadSignalUnsupportedError(signalError)) {
2281
+ markThreadSignalsUnsupported();
2282
+ setMessages((prev) => [...prev, fromCoreUserMessagesToMastraDBMessage(coreUserMessages)]);
2283
+ await streamWithLegacyRoute();
2284
+ return;
2285
+ }
2286
+ throw signalError;
2287
+ }
2288
+ }
2289
+ throw error;
2290
+ }
2291
+ if (_streamAbortRef.current === internalAbort) {
2292
+ _streamAbortRef.current = null;
2293
+ }
2294
+ };
2295
+ const network = async ({
2296
+ coreUserMessages,
2297
+ requestContext,
2298
+ threadId: threadId2,
2299
+ onNetworkChunk,
2300
+ modelSettings,
2301
+ signal,
2302
+ tracingOptions
2303
+ }) => {
2304
+ const { frequencyPenalty, presencePenalty, maxRetries, maxTokens, temperature, topK, topP, maxSteps } = modelSettings || {};
2305
+ const resolvedRequestContext = requestContext ?? propsRequestContext;
2306
+ _requestContext.current = resolvedRequestContext;
2307
+ setIsRunning(true);
2308
+ const clientWithAbort = new MastraClient({
2309
+ ...baseClient.options,
2310
+ abortSignal: signal
2311
+ });
2312
+ const agent = clientWithAbort.getAgent(agentId);
2313
+ const runId = v4();
2314
+ const response = await agent.network(coreUserMessages, {
2315
+ maxSteps,
2316
+ modelSettings: {
2317
+ frequencyPenalty,
2318
+ presencePenalty,
2319
+ maxRetries,
2320
+ maxOutputTokens: maxTokens,
2321
+ temperature,
2322
+ topK,
2323
+ topP
2324
+ },
2325
+ runId,
2326
+ requestContext: resolvedRequestContext,
2327
+ ...threadId2 ? { memory: { thread: threadId2, resource: resourceId || agentId } } : {},
2328
+ tracingOptions
2329
+ });
2330
+ _onNetworkChunk.current = onNetworkChunk;
2331
+ _networkRunId.current = runId;
2332
+ await response.processDataStream({
2333
+ onChunk: async (chunk) => {
2334
+ setMessages((prev) => accumulateNetworkChunk({ chunk, conversation: prev, metadata: { mode: "network" } }));
2335
+ void onNetworkChunk?.(chunk);
2336
+ }
2337
+ });
2338
+ setMessages((prev) => finishStreamingAssistantMessage(prev));
2339
+ setIsRunning(false);
2340
+ };
2341
+ const handleCancelRun = () => {
2342
+ _streamAbortRef.current?.abort();
2343
+ _streamAbortRef.current = null;
2344
+ const threadSubscription = _threadSubscriptionRef.current;
2345
+ void Promise.resolve(threadSubscription?.abort?.()).catch((error) => {
2346
+ console.error("[useChat] Failed to abort thread subscription", error);
2347
+ });
2348
+ closeThreadSubscription();
2349
+ setMessages((prev) => finishStreamingAssistantMessage(prev));
2350
+ pendingToolApprovalIdsRef.current.clear();
2351
+ setIsAwaitingToolApproval(false);
2352
+ setIsRunning(false);
2353
+ _currentRunId.current = void 0;
2354
+ _onChunk.current = void 0;
2355
+ _networkRunId.current = void 0;
2356
+ _onNetworkChunk.current = void 0;
2357
+ _requestContext.current = void 0;
2358
+ };
2359
+ const approveToolCall = async (toolCallId) => {
2360
+ const onChunk = _onChunk.current;
2361
+ const currentRunId = _currentRunId.current;
2362
+ if (!currentRunId)
2363
+ return console.info("[approveToolCall] approveToolCall can only be called after a stream has started");
2364
+ setIsRunning(true);
2365
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
2366
+ const agent = baseClient.getAgent(agentId);
2367
+ if (_threadSubscriptionKeyRef.current && threadId) {
2368
+ try {
2369
+ await agent.sendToolApproval({
2370
+ resourceId: resourceId || agentId,
2371
+ threadId,
2372
+ toolCallId,
2373
+ approved: true,
2374
+ requestContext: _requestContext.current
2375
+ });
2376
+ pendingToolApprovalIdsRef.current.delete(toolCallId);
2377
+ setIsAwaitingToolApproval(pendingToolApprovalIdsRef.current.size > 0);
2378
+ setIsRunning(false);
2379
+ } catch (error) {
2380
+ setToolCallApprovals((prev) => {
2381
+ const next = { ...prev };
2382
+ delete next[toolCallId];
2383
+ return next;
2384
+ });
2385
+ setIsRunning(false);
2386
+ throw error;
2387
+ }
2388
+ return;
2389
+ }
2390
+ const response = await agent.approveToolCall({
2391
+ runId: currentRunId,
2392
+ toolCallId,
2393
+ requestContext: _requestContext.current
2394
+ });
2395
+ await response.processDataStream({
2396
+ onChunk: async (chunk) => {
2397
+ await processStreamChunk(chunk, onChunk);
2398
+ }
2399
+ });
2400
+ setIsRunning(false);
2401
+ };
2402
+ const declineToolCall = async (toolCallId) => {
2403
+ const onChunk = _onChunk.current;
2404
+ const currentRunId = _currentRunId.current;
2405
+ if (!currentRunId)
2406
+ return console.info("[declineToolCall] declineToolCall can only be called after a stream has started");
2407
+ setIsRunning(true);
2408
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
2409
+ const agent = baseClient.getAgent(agentId);
2410
+ if (_threadSubscriptionKeyRef.current && threadId) {
2411
+ try {
2412
+ await agent.sendToolApproval({
2413
+ resourceId: resourceId || agentId,
2414
+ threadId,
2415
+ toolCallId,
2416
+ approved: false,
2417
+ requestContext: _requestContext.current
2418
+ });
2419
+ pendingToolApprovalIdsRef.current.delete(toolCallId);
2420
+ setIsAwaitingToolApproval(pendingToolApprovalIdsRef.current.size > 0);
2421
+ setIsRunning(false);
2422
+ } catch (error) {
2423
+ setToolCallApprovals((prev) => {
2424
+ const next = { ...prev };
2425
+ delete next[toolCallId];
2426
+ return next;
2427
+ });
2428
+ setIsRunning(false);
2429
+ throw error;
2430
+ }
2431
+ return;
2432
+ }
2433
+ const response = await agent.declineToolCall({
2434
+ runId: currentRunId,
2435
+ toolCallId,
2436
+ requestContext: _requestContext.current
2437
+ });
2438
+ await response.processDataStream({
2439
+ onChunk: async (chunk) => {
2440
+ await processStreamChunk(chunk, onChunk);
2441
+ }
2442
+ });
2443
+ setIsRunning(false);
2444
+ };
2445
+ const approveToolCallGenerate = async (toolCallId) => {
2446
+ const currentRunId = _currentRunId.current;
2447
+ if (!currentRunId)
2448
+ return console.info(
2449
+ "[approveToolCallGenerate] approveToolCallGenerate can only be called after a generate has started"
2450
+ );
2451
+ setIsRunning(true);
2452
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "approved" } }));
2453
+ const agent = baseClient.getAgent(agentId);
2454
+ const response = await agent.approveToolCallGenerate({
2455
+ runId: currentRunId,
2456
+ toolCallId,
2457
+ requestContext: _requestContext.current
2458
+ });
2459
+ if (response && "uiMessages" in response.response && response.response.uiMessages) {
2460
+ const dbMessages = dbFromServerUiMessages(response.response.uiMessages, { mode: "generate" });
2461
+ setMessages((prev) => [...prev, ...dbMessages]);
2462
+ }
2463
+ setIsRunning(false);
2464
+ };
2465
+ const declineToolCallGenerate = async (toolCallId) => {
2466
+ const currentRunId = _currentRunId.current;
2467
+ if (!currentRunId)
2468
+ return console.info(
2469
+ "[declineToolCallGenerate] declineToolCallGenerate can only be called after a generate has started"
2470
+ );
2471
+ setIsRunning(true);
2472
+ setToolCallApprovals((prev) => ({ ...prev, [toolCallId]: { status: "declined" } }));
2473
+ const agent = baseClient.getAgent(agentId);
2474
+ const response = await agent.declineToolCallGenerate({
2475
+ runId: currentRunId,
2476
+ toolCallId,
2477
+ requestContext: _requestContext.current
2478
+ });
2479
+ if (response && "uiMessages" in response.response && response.response.uiMessages) {
2480
+ const dbMessages = dbFromServerUiMessages(response.response.uiMessages, { mode: "generate" });
2481
+ setMessages((prev) => [...prev, ...dbMessages]);
2482
+ }
2483
+ setIsRunning(false);
2484
+ };
2485
+ const approveNetworkToolCall = async (toolName, runId) => {
2486
+ const onNetworkChunk = _onNetworkChunk.current;
2487
+ const networkRunId = runId || _networkRunId.current;
2488
+ if (!networkRunId)
2489
+ return console.info(
2490
+ "[approveNetworkToolCall] approveNetworkToolCall can only be called after a network stream has started"
2491
+ );
2492
+ setIsRunning(true);
2493
+ setNetworkToolCallApprovals((prev) => ({
2494
+ ...prev,
2495
+ [runId ? `${runId}-${toolName}` : toolName]: { status: "approved" }
2496
+ }));
2497
+ const agent = baseClient.getAgent(agentId);
2498
+ const response = await agent.approveNetworkToolCall({
2499
+ runId: networkRunId,
2500
+ requestContext: _requestContext.current
2501
+ });
2502
+ await response.processDataStream({
2503
+ onChunk: async (chunk) => {
2504
+ setMessages((prev) => accumulateNetworkChunk({ chunk, conversation: prev, metadata: { mode: "network" } }));
2505
+ void onNetworkChunk?.(chunk);
2506
+ }
2507
+ });
2508
+ setMessages((prev) => finishStreamingAssistantMessage(prev));
2509
+ setIsRunning(false);
2510
+ };
2511
+ const declineNetworkToolCall = async (toolName, runId) => {
2512
+ const onNetworkChunk = _onNetworkChunk.current;
2513
+ const networkRunId = runId || _networkRunId.current;
2514
+ if (!networkRunId)
2515
+ return console.info(
2516
+ "[declineNetworkToolCall] declineNetworkToolCall can only be called after a network stream has started"
2517
+ );
2518
+ setIsRunning(true);
2519
+ setNetworkToolCallApprovals((prev) => ({
2520
+ ...prev,
2521
+ [runId ? `${runId}-${toolName}` : toolName]: { status: "declined" }
2522
+ }));
2523
+ const agent = baseClient.getAgent(agentId);
2524
+ const response = await agent.declineNetworkToolCall({
2525
+ runId: networkRunId,
2526
+ requestContext: _requestContext.current
2527
+ });
2528
+ await response.processDataStream({
2529
+ onChunk: async (chunk) => {
2530
+ setMessages((prev) => accumulateNetworkChunk({ chunk, conversation: prev, metadata: { mode: "network" } }));
2531
+ void onNetworkChunk?.(chunk);
2532
+ }
2533
+ });
2534
+ setMessages((prev) => finishStreamingAssistantMessage(prev));
2535
+ setIsRunning(false);
2536
+ };
2537
+ const sendMessage = async ({ mode = "stream", ...args }) => {
2538
+ const nextMessage = { role: "user", content: [{ type: "text", text: args.message }] };
2539
+ const coreUserMessages = [nextMessage];
2540
+ if (args.coreUserMessages) {
2541
+ coreUserMessages.push(...args.coreUserMessages);
2542
+ }
2543
+ const dbUserMessage = fromCoreUserMessagesToMastraDBMessage(coreUserMessages);
2544
+ const clientSetId = mode === "stream" && args.threadId && !_threadSignalsUnsupportedRef.current && !threadSignalsDisabled ? `client-set-${v4()}` : void 0;
2545
+ const signalId = clientSetId;
2546
+ const clientMessageId = clientSetId;
2547
+ if (signalId) {
2548
+ const metadata = {
2549
+ ...dbUserMessage.content.metadata,
2550
+ mode: "stream",
2551
+ status: "pending",
2552
+ [CLIENT_MESSAGE_ID_KEY]: clientMessageId
2553
+ };
2554
+ const pendingMessage = { ...dbUserMessage, id: clientSetId, content: { ...dbUserMessage.content, metadata } };
2555
+ setMessages((s) => [...s, pendingMessage]);
2556
+ } else {
2557
+ setMessages((s) => [...s, dbUserMessage]);
2558
+ }
2559
+ if (mode === "generate") {
2560
+ await generate({ ...args, coreUserMessages });
2561
+ } else if (mode === "stream") {
2562
+ await stream({ ...args, coreUserMessages, signalId, clientMessageId });
2563
+ } else if (mode === "network") {
2564
+ await network({ ...args, coreUserMessages });
2565
+ }
2566
+ };
2567
+ return {
2568
+ setMessages,
2569
+ sendMessage,
2570
+ isRunning,
2571
+ isAwaitingToolApproval,
2572
+ messages,
2573
+ approveToolCall,
2574
+ declineToolCall,
2575
+ approveToolCallGenerate,
2576
+ declineToolCallGenerate,
2577
+ cancelRun: handleCancelRun,
2578
+ toolCallApprovals,
2579
+ approveNetworkToolCall,
2580
+ declineNetworkToolCall,
2581
+ networkToolCallApprovals
2582
+ };
2583
+ };
2584
+ var IconSizes = {
2585
+ sm: "mastra:[&>svg]:size-3",
2586
+ md: "mastra:[&>svg]:size-4",
2587
+ lg: "mastra:[&>svg]:size-5"
2588
+ };
2589
+ var Icon = ({ children, className, size = "md", ...props }) => {
2590
+ return /* @__PURE__ */ jsx("div", { className: className || IconSizes[size], ...props, children });
2591
+ };
2592
+ var EntityContext = createContext({
2593
+ expanded: false,
2594
+ setExpanded: () => {
2595
+ },
2596
+ variant: "initial",
2597
+ disabled: false
2598
+ });
2599
+ var EntityProvider = EntityContext.Provider;
2600
+ var useEntity = () => useContext(EntityContext);
2601
+ var Entity = ({
2602
+ className,
2603
+ variant = "initial",
2604
+ initialExpanded = false,
2605
+ disabled = false,
2606
+ ...props
2607
+ }) => {
2608
+ const [expanded, setExpanded] = useState(initialExpanded);
2609
+ return /* @__PURE__ */ jsx(EntityProvider, { value: { expanded, setExpanded, variant, disabled }, children: /* @__PURE__ */ jsx("div", { className, ...props }) });
2610
+ };
2611
+ var EntityTriggerClass = twMerge(
2612
+ "mastra:aria-disabled:cursor-not-allowed mastra:aria-disabled:bg-surface5 mastra:aria-disabled:text-text3",
2613
+ "mastra:aria-expanded:rounded-b-none mastra:aria-expanded:border-b-0",
2614
+ "mastra:bg-surface3 mastra:text-text6 mastra:hover:bg-surface4 mastra:active:bg-surface5",
2615
+ "mastra:rounded-lg mastra:py-2 mastra:px-4 mastra:border mastra:border-border1",
2616
+ "mastra:cursor-pointer mastra:inline-flex mastra:items-center mastra:gap-1 mastra:font-mono"
2617
+ );
2618
+ var EntityTriggerVariantClasses = {
2619
+ agent: "mastra:[&_svg.mastra-icon]:text-accent1",
2620
+ workflow: "mastra:[&_svg.mastra-icon]:text-accent3",
2621
+ tool: "mastra:[&_svg.mastra-icon]:text-accent6",
2622
+ memory: "mastra:[&_svg.mastra-icon]:text-accent2",
2623
+ initial: "mastra:[&_svg.mastra-icon]:text-text3"
2624
+ };
2625
+ var EntityTrigger = ({ className, children, ...props }) => {
2626
+ const { expanded, setExpanded, variant, disabled } = useEntity();
2627
+ const handleClick = (e) => {
2628
+ if (disabled) return;
2629
+ setExpanded(!expanded);
2630
+ props?.onClick?.(e);
2631
+ };
2632
+ return /* @__PURE__ */ jsx(
2633
+ "button",
2634
+ {
2635
+ className: className || twMerge(EntityTriggerClass, !disabled && EntityTriggerVariantClasses[variant]),
2636
+ ...props,
2637
+ onClick: handleClick,
2638
+ "aria-expanded": expanded,
2639
+ "aria-disabled": disabled,
2640
+ children
2641
+ }
2642
+ );
2643
+ };
2644
+ var EntityContentClass = twMerge(
2645
+ "mastra:space-y-4",
2646
+ "mastra:rounded-lg mastra:rounded-tl-none mastra:p-4 mastra:border mastra:border-border1 mastra:-mt-[0.5px]",
2647
+ "mastra:bg-surface3 mastra:text-text6"
2648
+ );
2649
+ var EntityContent = ({ className, ...props }) => {
2650
+ const { expanded } = useEntity();
2651
+ if (!expanded) return null;
2652
+ return /* @__PURE__ */ jsx("div", { className: className || EntityContentClass, ...props });
2653
+ };
2654
+ var EntityCaret = ({ className, ...props }) => {
2655
+ const { expanded } = useEntity();
2656
+ return /* @__PURE__ */ jsx(Icon, { children: /* @__PURE__ */ jsx(
2657
+ ChevronDownIcon,
2658
+ {
2659
+ className: twMerge(
2660
+ `mastra:text-text3 mastra:transition-transform mastra:duration-200 mastra:ease-in-out`,
2661
+ expanded ? "mastra:rotate-0" : "mastra:-rotate-90",
2662
+ className
2663
+ ),
2664
+ ...props
2665
+ }
2666
+ ) });
2667
+ };
2668
+ var ToolApprovalClass = twMerge(
2669
+ "mastra:rounded-lg mastra:border mastra:border-border1 mastra:max-w-1/2 mastra:mt-2",
2670
+ "mastra:bg-surface3 mastra:text-text6"
2671
+ );
2672
+ var ToolApproval = ({ className, ...props }) => {
2673
+ return /* @__PURE__ */ jsx("div", { className: className || ToolApprovalClass, ...props });
2674
+ };
2675
+ var ToolApprovalTitleClass = twMerge("mastra:text-text6 mastra:inline-flex mastra:items-center mastra:gap-1");
2676
+ var ToolApprovalTitle = ({ className, ...props }) => {
2677
+ return /* @__PURE__ */ jsx("div", { className: className || ToolApprovalTitleClass, ...props });
2678
+ };
2679
+ var ToolApprovalHeaderClass = twMerge(
2680
+ "mastra:flex mastra:justify-between mastra:items-center mastra:gap-2",
2681
+ "mastra:border-b mastra:border-border1 mastra:px-4 mastra:py-2"
2682
+ );
2683
+ var ToolApprovalHeader = ({ className, ...props }) => {
2684
+ return /* @__PURE__ */ jsx("div", { className: className || ToolApprovalHeaderClass, ...props });
2685
+ };
2686
+ var ToolApprovalContentClass = twMerge("mastra:text-text6 mastra:p-4");
2687
+ var ToolApprovalContent = ({ className, ...props }) => {
2688
+ return /* @__PURE__ */ jsx("div", { className: className || ToolApprovalContentClass, ...props });
2689
+ };
2690
+ var ToolApprovalActionsClass = twMerge("mastra:flex mastra:gap-2 mastra:items-center");
2691
+ var ToolApprovalActions = ({ className, ...props }) => {
2692
+ return /* @__PURE__ */ jsx("div", { className: className || ToolApprovalActionsClass, ...props });
2693
+ };
2694
+ var EntryClass = "mastra:space-y-2";
2695
+ var Entry = ({ className, ...props }) => {
2696
+ return /* @__PURE__ */ jsx("div", { className: className || EntryClass, ...props });
2697
+ };
2698
+ var EntryTitleClass = "mastra:font-mono mastra:text-sm mastra:text-text3";
2699
+ var EntryTitle = ({ className, as: Root = "h3", ...props }) => {
2700
+ return /* @__PURE__ */ jsx(Root, { className: className || EntryTitleClass, ...props });
2701
+ };
2702
+ var Tooltip = ({ children }) => {
2703
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(Root, { children }) });
2704
+ };
2705
+ var 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";
2706
+ var TooltipContent = ({ children, className, ...props }) => {
2707
+ return /* @__PURE__ */ jsx(TooltipPortal, { children: /* @__PURE__ */ jsx(TooltipContent$1, { className: className || TooltipContentClass, ...props, children }) });
2708
+ };
2709
+ var TooltipTrigger = (props) => {
2710
+ return /* @__PURE__ */ jsx(TooltipTrigger$1, { ...props, asChild: true });
2711
+ };
2712
+ var 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";
2713
+ var IconButton = ({ children, tooltip, size = "md", className, ...props }) => {
2714
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
2715
+ /* @__PURE__ */ jsx(TooltipTrigger, { children: /* @__PURE__ */ jsx(
2716
+ "button",
2717
+ {
2718
+ ...props,
2719
+ className: className || twMerge(IconButtonClass, size === "md" && "mastra:p-0.5", size === "lg" && "mastra:p-1"),
2720
+ children: /* @__PURE__ */ jsx(Icon, { size, children })
2721
+ }
2722
+ ) }),
2723
+ /* @__PURE__ */ jsx(TooltipContent, { children: tooltip })
2724
+ ] });
2725
+ };
2726
+ async function highlight(code, lang) {
2727
+ const out = await codeToHast(code, {
2728
+ lang,
2729
+ theme: "dracula-soft"
2730
+ });
2731
+ return toJsxRuntime(out, {
2732
+ Fragment: Fragment$1,
2733
+ jsx: jsx,
2734
+ jsxs: jsxs
2735
+ });
2736
+ }
2737
+ var CodeBlockClass = "mastra:rounded-lg mastra:[&>pre]:p-4 mastra:overflow-hidden mastra:[&>pre]:!bg-surface4 mastra:[&>pre>code]:leading-5 mastra:relative";
2738
+ var CodeBlock = ({ code, language, className, cta }) => {
2739
+ const [nodes, setNodes] = useState(null);
2740
+ useLayoutEffect(() => {
2741
+ void highlight(code, language).then(setNodes);
2742
+ }, [language]);
2743
+ return /* @__PURE__ */ jsxs("div", { className: className || CodeBlockClass, children: [
2744
+ nodes ?? null,
2745
+ cta
2746
+ ] });
2747
+ };
2748
+ var CodeCopyButton = ({ code }) => {
2749
+ const [isCopied, setIsCopied] = useState(false);
2750
+ const handleCopy = () => {
2751
+ void navigator.clipboard.writeText(code);
2752
+ setIsCopied(true);
2753
+ setTimeout(() => setIsCopied(false), 2e3);
2754
+ };
2755
+ return /* @__PURE__ */ jsx("div", { className: "mastra:absolute mastra:top-2 mastra:right-2", children: /* @__PURE__ */ jsx(IconButton, { tooltip: "Copy", onClick: handleCopy, children: isCopied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {}) }) });
2756
+ };
2757
+ var AgentIcon = ({ className, ...props }) => /* @__PURE__ */ jsxs(
2758
+ "svg",
2759
+ {
2760
+ width: "17",
2761
+ height: "16",
2762
+ viewBox: "0 0 17 16",
2763
+ fill: "none",
2764
+ xmlns: "http://www.w3.org/2000/svg",
2765
+ ...props,
2766
+ className: twMerge("mastra-icon", className),
2767
+ children: [
2768
+ /* @__PURE__ */ jsx(
2769
+ "path",
2770
+ {
2771
+ fillRule: "evenodd",
2772
+ clipRule: "evenodd",
2773
+ 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",
2774
+ fill: "currentColor"
2775
+ }
2776
+ ),
2777
+ /* @__PURE__ */ jsx(
2778
+ "path",
2779
+ {
2780
+ 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",
2781
+ fill: "currentColor"
2782
+ }
2783
+ )
2784
+ ]
2785
+ }
2786
+ );
2787
+ var ToolsIcon = ({ className, ...props }) => /* @__PURE__ */ jsx(
2788
+ "svg",
2789
+ {
2790
+ width: "17",
2791
+ height: "16",
2792
+ viewBox: "0 0 17 16",
2793
+ fill: "none",
2794
+ xmlns: "http://www.w3.org/2000/svg",
2795
+ ...props,
2796
+ className: twMerge("mastra-icon", className),
2797
+ children: /* @__PURE__ */ jsx(
2798
+ "path",
2799
+ {
2800
+ fillRule: "evenodd",
2801
+ clipRule: "evenodd",
2802
+ 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",
2803
+ fill: "currentColor"
2804
+ }
2805
+ )
2806
+ }
2807
+ );
2808
+ var WorkflowIcon = ({ className, ...props }) => /* @__PURE__ */ jsx(
2809
+ "svg",
2810
+ {
2811
+ width: "17",
2812
+ height: "16",
2813
+ viewBox: "0 0 17 16",
2814
+ fill: "none",
2815
+ xmlns: "http://www.w3.org/2000/svg",
2816
+ ...props,
2817
+ className: twMerge("mastra-icon", className),
2818
+ children: /* @__PURE__ */ jsx(
2819
+ "path",
2820
+ {
2821
+ fillRule: "evenodd",
2822
+ clipRule: "evenodd",
2823
+ 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",
2824
+ fill: "currentColor"
2825
+ }
2826
+ )
2827
+ }
2828
+ );
2829
+ var MessageClass = "mastra:flex mastra:flex-col mastra:w-full mastra:py-4 mastra:gap-2 mastra:group";
2830
+ var Message = ({ position, className, children, ...props }) => {
2831
+ return /* @__PURE__ */ jsx(
2832
+ "div",
2833
+ {
2834
+ className: className || twMerge(
2835
+ MessageClass,
2836
+ position === "left" ? "" : "mastra:items-end mastra:[&_.mastra-message-content]:bg-surface4 mastra:[&_.mastra-message-content]:px-4"
2837
+ ),
2838
+ ...props,
2839
+ children
2840
+ }
2841
+ );
2842
+ };
2843
+ var MessageContentClass = "mastra:max-w-4/5 mastra:py-2 mastra:text-text6 mastra:rounded-lg mastra-message-content mastra:text-md";
2844
+ var MessageContent = ({ children, className, isStreaming, ...props }) => {
2845
+ return /* @__PURE__ */ jsxs("div", { className: className || MessageContentClass, ...props, children: [
2846
+ children,
2847
+ isStreaming && /* @__PURE__ */ jsx(MessageStreaming, {})
2848
+ ] });
2849
+ };
2850
+ var MessageActionsClass = "mastra:gap-2 mastra:flex mastra:opacity-0 mastra:group-hover:opacity-100 mastra:group-focus-within:opacity-100 mastra:items-center";
2851
+ var MessageActions = ({ children, className, ...props }) => {
2852
+ return /* @__PURE__ */ jsx("div", { className: className || MessageActionsClass, ...props, children });
2853
+ };
2854
+ var MessageUsagesClass = "mastra:flex mastra:gap-2 mastra:items-center";
2855
+ var MessageUsages = ({ children, className, ...props }) => {
2856
+ return /* @__PURE__ */ jsx("div", { className: className || MessageUsagesClass, ...props, children });
2857
+ };
2858
+ var 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";
2859
+ var MessageUsage = ({ children, className, ...props }) => {
2860
+ return /* @__PURE__ */ jsx("dl", { className: className || MessageUsageClass, ...props, children });
2861
+ };
2862
+ var MessageUsageEntryClass = "mastra:text-text3 mastra:text-xs mastra:flex mastra:gap-1 mastra:items-center";
2863
+ var MessageUsageEntry = ({ children, className, ...props }) => {
2864
+ return /* @__PURE__ */ jsx("dt", { className: className || MessageUsageEntryClass, ...props, children });
2865
+ };
2866
+ var MessageUsageValueClass = "mastra:text-text6 mastra:text-xs";
2867
+ var MessageUsageValue = ({ children, className, ...props }) => {
2868
+ return /* @__PURE__ */ jsx("dd", { className: className || MessageUsageValueClass, ...props, children });
2869
+ };
2870
+ var MessageListClass = "mastra:overflow-y-auto mastra:h-full mastra-list";
2871
+ var MessageList = ({ children, className, ...props }) => {
2872
+ const listRef = useRef(null);
2873
+ useEffect(() => {
2874
+ const scrollToBottom = () => {
2875
+ if (!listRef.current) return;
2876
+ listRef.current.scrollTo({ top: listRef.current.scrollHeight, behavior: "smooth" });
2877
+ };
2878
+ requestAnimationFrame(scrollToBottom);
2879
+ });
2880
+ return /* @__PURE__ */ jsx("div", { className: className || MessageListClass, ...props, ref: listRef, children });
2881
+ };
2882
+ var MessageStreamingClass = "mastra:inline-block mastra:w-[2px] mastra:h-[1em] mastra:bg-text5 mastra:ml-0.5 mastra:align-text-bottom mastra:animate-pulse";
2883
+ var MessageStreaming = ({ className, ...props }) => {
2884
+ return /* @__PURE__ */ jsx("span", { className: className || MessageStreamingClass, ...props });
2885
+ };
2886
+ var isDynamicToolPart2 = (part) => (
2887
+ // `tool-invocation` is the v4 typed discriminant and must NOT be treated as a
2888
+ // v5 `tool-${string}` streaming part, even though it shares the `tool-` prefix.
2889
+ part.type === "dynamic-tool" || part.type.startsWith("tool-") && part.type !== "tool-invocation"
2890
+ );
2891
+ var isDataPart = (part) => part.type.startsWith("data-");
2892
+ var sourceToSourceUrl = (part) => ({
2893
+ type: "source-url",
2894
+ sourceId: part.source.id,
2895
+ url: part.source.url,
2896
+ title: part.source.title,
2897
+ providerMetadata: part.providerMetadata
2898
+ });
2899
+ var getPartKey = (part, index) => {
2900
+ if (isDynamicToolPart2(part)) {
2901
+ return part.toolCallId ?? `${part.type}-${index}`;
2902
+ }
2903
+ switch (part.type) {
2904
+ case "text":
2905
+ return part.textId ?? `text-${index}`;
2906
+ case "reasoning":
2907
+ return part.reasoningId ?? `reasoning-${index}`;
2908
+ case "tool-invocation":
2909
+ return part.toolInvocation.toolCallId ?? `tool-invocation-${index}`;
2910
+ case "source-url":
2911
+ return part.sourceId || `source-url-${index}`;
2912
+ case "source":
2913
+ return part.source.id ?? `source-${index}`;
2914
+ }
2915
+ const id = part.id;
2916
+ return id ?? `${part.type}-${index}`;
2917
+ };
2918
+ var renderPart = (part, renderers, fallback) => {
2919
+ if (isDynamicToolPart2(part)) {
2920
+ return renderers.DynamicTool?.(part) ?? fallback?.(part) ?? null;
2921
+ }
2922
+ if (isDataPart(part)) {
2923
+ return renderers.Data?.(part) ?? fallback?.(part) ?? null;
2924
+ }
2925
+ switch (part.type) {
2926
+ case "text":
2927
+ return renderers.Text?.(part) ?? fallback?.(part) ?? null;
2928
+ case "reasoning":
2929
+ return renderers.Reasoning?.(part) ?? fallback?.(part) ?? null;
2930
+ case "file":
2931
+ return renderers.File?.(part) ?? fallback?.(part) ?? null;
2932
+ case "step-start":
2933
+ return renderers.StepStart?.(part) ?? fallback?.(part) ?? null;
2934
+ case "tool-invocation":
2935
+ return renderers.ToolInvocation?.(part) ?? fallback?.(part) ?? null;
2936
+ case "source":
2937
+ return renderers.SourceUrl?.(sourceToSourceUrl(part)) ?? fallback?.(part) ?? null;
2938
+ case "source-url":
2939
+ return renderers.SourceUrl?.(part) ?? fallback?.(part) ?? null;
2940
+ case "source-document":
2941
+ return renderers.SourceDocument?.(part) ?? fallback?.(part) ?? null;
2942
+ default: {
2943
+ return fallback?.(part) ?? null;
2944
+ }
2945
+ }
2946
+ };
2947
+ var PartRenderer = memo(({ part, renderers, fallback }) => /* @__PURE__ */ jsx(Fragment, { children: renderPart(part, renderers, fallback) }));
2948
+ PartRenderer.displayName = "PartRenderer";
2949
+ var joinText = (parts) => parts.filter((part) => part.type === "text").map((part) => part.text).join("");
2950
+ var resolveTaskVerdict = (metadata) => {
2951
+ const verdict = metadata?.completionResult ?? metadata?.isTaskCompleteResult;
2952
+ if (!verdict) return void 0;
2953
+ return { passed: !!verdict.passed, suppressFeedback: verdict.suppressFeedback };
2954
+ };
2955
+ var roleRendererFor = (role, roles) => {
2956
+ switch (role) {
2957
+ case "user":
2958
+ return roles?.User;
2959
+ case "assistant":
2960
+ return roles?.Assistant;
2961
+ case "system":
2962
+ return roles?.System;
2963
+ case "signal":
2964
+ return roles?.Signal;
2965
+ default:
2966
+ return void 0;
2967
+ }
2968
+ };
2969
+ var MessageFactoryComponent = ({ message, roles, status, fallback, ...renderers }) => {
2970
+ const parts = message.content.parts ?? [];
2971
+ const metadata = message.content.metadata;
2972
+ let content;
2973
+ if (metadata?.status === "tripwire" && status?.Tripwire) {
2974
+ content = status.Tripwire({ text: joinText(parts), tripwire: metadata.tripwire, message });
2975
+ } else if (metadata?.status === "warning" && status?.Warning) {
2976
+ content = status.Warning({ text: joinText(parts), message });
2977
+ } else if (metadata?.status === "error" && status?.Error) {
2978
+ content = status.Error({ text: joinText(parts), message });
2979
+ } else {
2980
+ content = /* @__PURE__ */ jsx(Fragment, { children: parts.map((part, index) => /* @__PURE__ */ jsx(PartRenderer, { part, renderers, fallback }, getPartKey(part, index))) });
2981
+ if (metadata?.status === "pending" && status?.Pending) {
2982
+ content = status.Pending({ children: content, text: joinText(parts), message });
2983
+ }
2984
+ const verdict = resolveTaskVerdict(metadata);
2985
+ if (verdict && status?.Task) {
2986
+ content = /* @__PURE__ */ jsxs(Fragment, { children: [
2987
+ content,
2988
+ status.Task({ ...verdict, text: joinText(parts), message })
2989
+ ] });
2990
+ }
2991
+ }
2992
+ const RoleWrapper = roleRendererFor(message.role, roles);
2993
+ if (RoleWrapper) {
2994
+ return /* @__PURE__ */ jsx(Fragment, { children: RoleWrapper({ message, children: content }) });
2995
+ }
2996
+ return /* @__PURE__ */ jsx(Fragment, { children: content });
2997
+ };
2998
+ var MessageFactory = memo(MessageFactoryComponent);
2999
+ MessageFactory.displayName = "MessageFactory";
3000
+ function useMutation(mutationFn) {
3001
+ const [isPending, setIsPending] = useState(false);
3002
+ const [isSuccess, setIsSuccess] = useState(false);
3003
+ const [isError, setIsError] = useState(false);
3004
+ const [error, setError] = useState(null);
3005
+ const [data, setData] = useState(void 0);
3006
+ const mutationFnRef = useRef(mutationFn);
3007
+ mutationFnRef.current = mutationFn;
3008
+ const reset = useCallback(() => {
3009
+ setIsPending(false);
3010
+ setIsSuccess(false);
3011
+ setIsError(false);
3012
+ setError(null);
3013
+ setData(void 0);
3014
+ }, []);
3015
+ const mutateAsync = useCallback(async (variables) => {
3016
+ setIsPending(true);
3017
+ setIsSuccess(false);
3018
+ setIsError(false);
3019
+ setError(null);
3020
+ try {
3021
+ const result = await mutationFnRef.current(variables);
3022
+ setData(result);
3023
+ setIsSuccess(true);
3024
+ return result;
3025
+ } catch (err) {
3026
+ const typedError = err;
3027
+ setError(typedError);
3028
+ setIsError(true);
3029
+ throw err;
3030
+ } finally {
3031
+ setIsPending(false);
3032
+ }
3033
+ }, []);
3034
+ const mutate = useCallback(
3035
+ (variables) => {
3036
+ mutateAsync(variables).catch(() => {
3037
+ });
3038
+ },
3039
+ [mutateAsync]
3040
+ );
3041
+ return {
3042
+ mutate,
3043
+ mutateAsync,
3044
+ isPending,
3045
+ isSuccess,
3046
+ isError,
3047
+ error,
3048
+ data,
3049
+ reset
3050
+ };
3051
+ }
3052
+ function useStreamWorkflow({ debugMode, tracingOptions, onError }) {
3053
+ const client = useMastraClient();
3054
+ const [streamResult, setStreamResult] = useState({});
3055
+ const [isStreaming, setIsStreaming] = useState(false);
3056
+ const readerRef = useRef(null);
3057
+ const observerRef = useRef(null);
3058
+ const resumeStreamRef = useRef(null);
3059
+ const timeTravelStreamRef = useRef(null);
3060
+ const isMountedRef = useRef(true);
3061
+ useEffect(() => {
3062
+ isMountedRef.current = true;
3063
+ return () => {
3064
+ isMountedRef.current = false;
3065
+ if (readerRef.current) {
3066
+ try {
3067
+ readerRef.current.releaseLock();
3068
+ } catch {
3069
+ }
3070
+ readerRef.current = null;
3071
+ }
3072
+ if (observerRef.current) {
3073
+ try {
3074
+ observerRef.current.releaseLock();
3075
+ } catch {
3076
+ }
3077
+ observerRef.current = null;
3078
+ }
3079
+ if (resumeStreamRef.current) {
3080
+ try {
3081
+ resumeStreamRef.current.releaseLock();
3082
+ } catch {
3083
+ }
3084
+ resumeStreamRef.current = null;
3085
+ }
3086
+ if (timeTravelStreamRef.current) {
3087
+ try {
3088
+ timeTravelStreamRef.current.releaseLock();
3089
+ } catch {
3090
+ }
3091
+ timeTravelStreamRef.current = null;
3092
+ }
3093
+ };
3094
+ }, []);
3095
+ const handleStreamError = useCallback(
3096
+ (err, defaultMessage, setStreamingState) => {
3097
+ if (err instanceof TypeError) {
3098
+ return;
3099
+ }
3100
+ const error = err instanceof Error ? err : new Error(defaultMessage);
3101
+ onError?.(error, defaultMessage);
3102
+ setStreamingState?.(false);
3103
+ },
3104
+ [onError]
3105
+ );
3106
+ const handleWorkflowFinish = useCallback((value) => {
3107
+ if (value.type === "workflow-finish") {
3108
+ const streamStatus = value.payload?.workflowStatus;
3109
+ const metadata = value.payload?.metadata;
3110
+ setStreamResult((prev) => ({
3111
+ ...prev,
3112
+ status: streamStatus
3113
+ }));
3114
+ if (streamStatus === "failed") {
3115
+ throw new Error(metadata?.errorMessage || "Workflow execution failed");
3116
+ }
3117
+ }
3118
+ }, []);
3119
+ const streamWorkflow = useMutation(
3120
+ async ({ workflowId, runId, inputData, initialState, requestContext: playgroundRequestContext, perStep }) => {
3121
+ if (readerRef.current) {
3122
+ readerRef.current.releaseLock();
3123
+ }
3124
+ if (!isMountedRef.current) return;
3125
+ setIsStreaming(true);
3126
+ setStreamResult({ input: inputData });
3127
+ const workflow = client.getWorkflow(workflowId);
3128
+ const run = await workflow.createRun({ runId });
3129
+ const stream = await run.stream({
3130
+ inputData,
3131
+ initialState,
3132
+ requestContext: playgroundRequestContext,
3133
+ closeOnSuspend: true,
3134
+ tracingOptions,
3135
+ perStep: perStep ?? debugMode
3136
+ });
3137
+ if (!stream) {
3138
+ return handleStreamError(new Error("No stream returned"), "No stream returned", setIsStreaming);
3139
+ }
3140
+ const reader = stream.getReader();
3141
+ readerRef.current = reader;
3142
+ try {
3143
+ while (true) {
3144
+ if (!isMountedRef.current) break;
3145
+ const { done, value } = await reader.read();
3146
+ if (done) break;
3147
+ if (isMountedRef.current) {
3148
+ setStreamResult((prev) => {
3149
+ const newResult = mapWorkflowStreamChunkToWatchResult(prev, value);
3150
+ return newResult;
3151
+ });
3152
+ if (value.type === "workflow-step-start") {
3153
+ setIsStreaming(true);
3154
+ }
3155
+ if (value.type === "workflow-step-suspended") {
3156
+ setIsStreaming(false);
3157
+ }
3158
+ if (value.type === "workflow-finish") {
3159
+ handleWorkflowFinish(value);
3160
+ }
3161
+ }
3162
+ }
3163
+ } catch (err) {
3164
+ handleStreamError(err, "Error streaming workflow");
3165
+ } finally {
3166
+ if (isMountedRef.current) {
3167
+ setIsStreaming(false);
3168
+ }
3169
+ if (readerRef.current) {
3170
+ readerRef.current.releaseLock();
3171
+ readerRef.current = null;
3172
+ }
3173
+ }
3174
+ }
3175
+ );
3176
+ const observeWorkflowStream = useMutation(
3177
+ async ({ workflowId, runId, storeRunResult }) => {
3178
+ if (observerRef.current) {
3179
+ observerRef.current.releaseLock();
3180
+ }
3181
+ if (!isMountedRef.current) return;
3182
+ setIsStreaming(true);
3183
+ setStreamResult(storeRunResult || {});
3184
+ if (storeRunResult?.status === "suspended") {
3185
+ setIsStreaming(false);
3186
+ return;
3187
+ }
3188
+ const workflow = client.getWorkflow(workflowId);
3189
+ const run = await workflow.createRun({ runId });
3190
+ const stream = await run.observeStream();
3191
+ if (!stream) {
3192
+ return handleStreamError(new Error("No stream returned"), "No stream returned", setIsStreaming);
3193
+ }
3194
+ const reader = stream.getReader();
3195
+ observerRef.current = reader;
3196
+ try {
3197
+ while (true) {
3198
+ if (!isMountedRef.current) break;
3199
+ const { done, value } = await reader.read();
3200
+ if (done) break;
3201
+ if (isMountedRef.current) {
3202
+ setStreamResult((prev) => {
3203
+ const newResult = mapWorkflowStreamChunkToWatchResult(prev, value);
3204
+ return newResult;
3205
+ });
3206
+ if (value.type === "workflow-step-start") {
3207
+ setIsStreaming(true);
3208
+ }
3209
+ if (value.type === "workflow-step-suspended") {
3210
+ setIsStreaming(false);
3211
+ }
3212
+ if (value.type === "workflow-finish") {
3213
+ handleWorkflowFinish(value);
3214
+ }
3215
+ }
3216
+ }
3217
+ } catch (err) {
3218
+ handleStreamError(err, "Error observing workflow");
3219
+ } finally {
3220
+ if (isMountedRef.current) {
3221
+ setIsStreaming(false);
3222
+ }
3223
+ if (observerRef.current) {
3224
+ observerRef.current.releaseLock();
3225
+ observerRef.current = null;
3226
+ }
3227
+ }
3228
+ }
3229
+ );
3230
+ const resumeWorkflowStream = useMutation(
3231
+ async ({ workflowId, runId, step, resumeData, requestContext: playgroundRequestContext, perStep }) => {
3232
+ if (resumeStreamRef.current) {
3233
+ resumeStreamRef.current.releaseLock();
3234
+ }
3235
+ if (!isMountedRef.current) return;
3236
+ setIsStreaming(true);
3237
+ const workflow = client.getWorkflow(workflowId);
3238
+ const run = await workflow.createRun({ runId });
3239
+ const stream = await run.resumeStream({
3240
+ step,
3241
+ resumeData,
3242
+ requestContext: playgroundRequestContext,
3243
+ tracingOptions,
3244
+ perStep: perStep ?? debugMode
3245
+ });
3246
+ if (!stream) {
3247
+ return handleStreamError(new Error("No stream returned"), "No stream returned", setIsStreaming);
3248
+ }
3249
+ const reader = stream.getReader();
3250
+ resumeStreamRef.current = reader;
3251
+ try {
3252
+ while (true) {
3253
+ if (!isMountedRef.current) break;
3254
+ const { done, value } = await reader.read();
3255
+ if (done) break;
3256
+ if (isMountedRef.current) {
3257
+ setStreamResult((prev) => {
3258
+ const newResult = mapWorkflowStreamChunkToWatchResult(prev, value);
3259
+ return newResult;
3260
+ });
3261
+ if (value.type === "workflow-step-start") {
3262
+ setIsStreaming(true);
3263
+ }
3264
+ if (value.type === "workflow-step-suspended") {
3265
+ setIsStreaming(false);
3266
+ }
3267
+ if (value.type === "workflow-finish") {
3268
+ handleWorkflowFinish(value);
3269
+ }
3270
+ }
3271
+ }
3272
+ } catch (err) {
3273
+ handleStreamError(err, "Error resuming workflow stream");
3274
+ } finally {
3275
+ if (isMountedRef.current) {
3276
+ setIsStreaming(false);
3277
+ }
3278
+ if (resumeStreamRef.current) {
3279
+ resumeStreamRef.current.releaseLock();
3280
+ resumeStreamRef.current = null;
3281
+ }
3282
+ }
3283
+ }
3284
+ );
3285
+ const timeTravelWorkflowStream = useMutation(
3286
+ async ({ workflowId, requestContext: playgroundRequestContext, runId, perStep, ...params }) => {
3287
+ if (timeTravelStreamRef.current) {
3288
+ timeTravelStreamRef.current.releaseLock();
3289
+ }
3290
+ if (!isMountedRef.current) return;
3291
+ setIsStreaming(true);
3292
+ const workflow = client.getWorkflow(workflowId);
3293
+ const run = await workflow.createRun({ runId });
3294
+ const stream = await run.timeTravelStream({
3295
+ ...params,
3296
+ perStep: perStep ?? debugMode,
3297
+ requestContext: playgroundRequestContext,
3298
+ tracingOptions
3299
+ });
3300
+ if (!stream) {
3301
+ return handleStreamError(new Error("No stream returned"), "No stream returned", setIsStreaming);
3302
+ }
3303
+ const reader = stream.getReader();
3304
+ timeTravelStreamRef.current = reader;
3305
+ try {
3306
+ while (true) {
3307
+ if (!isMountedRef.current) break;
3308
+ const { done, value } = await reader.read();
3309
+ if (done) break;
3310
+ if (isMountedRef.current) {
3311
+ setStreamResult((prev) => {
3312
+ const newResult = mapWorkflowStreamChunkToWatchResult(prev, value);
3313
+ return newResult;
3314
+ });
3315
+ if (value.type === "workflow-step-start") {
3316
+ setIsStreaming(true);
3317
+ }
3318
+ if (value.type === "workflow-step-suspended") {
3319
+ setIsStreaming(false);
3320
+ }
3321
+ if (value.type === "workflow-finish") {
3322
+ handleWorkflowFinish(value);
3323
+ }
3324
+ }
3325
+ }
3326
+ } catch (err) {
3327
+ handleStreamError(err, "Error time traveling workflow stream");
3328
+ } finally {
3329
+ if (isMountedRef.current) {
3330
+ setIsStreaming(false);
3331
+ }
3332
+ if (timeTravelStreamRef.current) {
3333
+ timeTravelStreamRef.current.releaseLock();
3334
+ timeTravelStreamRef.current = null;
3335
+ }
3336
+ }
3337
+ }
3338
+ );
3339
+ const closeStreamsAndReset = useCallback(() => {
3340
+ setIsStreaming(false);
3341
+ setStreamResult({});
3342
+ if (readerRef.current) {
3343
+ try {
3344
+ readerRef.current.releaseLock();
3345
+ } catch {
3346
+ }
3347
+ readerRef.current = null;
3348
+ }
3349
+ if (observerRef.current) {
3350
+ try {
3351
+ observerRef.current.releaseLock();
3352
+ } catch {
3353
+ }
3354
+ observerRef.current = null;
3355
+ }
3356
+ if (resumeStreamRef.current) {
3357
+ try {
3358
+ resumeStreamRef.current.releaseLock();
3359
+ } catch {
3360
+ }
3361
+ resumeStreamRef.current = null;
3362
+ }
3363
+ if (timeTravelStreamRef.current) {
3364
+ try {
3365
+ timeTravelStreamRef.current.releaseLock();
3366
+ } catch {
3367
+ }
3368
+ timeTravelStreamRef.current = null;
3369
+ }
3370
+ }, []);
3371
+ return {
3372
+ streamWorkflow,
3373
+ streamResult,
3374
+ isStreaming,
3375
+ observeWorkflowStream,
3376
+ closeStreamsAndReset,
3377
+ resumeWorkflowStream,
3378
+ timeTravelWorkflowStream
3379
+ };
3380
+ }
3381
+
3382
+ // src/workflows/hooks.ts
3383
+ function useCreateWorkflowRun() {
3384
+ const client = useMastraClient();
3385
+ return useMutation(async ({ workflowId, prevRunId }) => {
3386
+ try {
3387
+ const workflow = client.getWorkflow(workflowId);
3388
+ const { runId: newRunId } = await workflow.createRun({ runId: prevRunId });
3389
+ return { runId: newRunId };
3390
+ } catch (error) {
3391
+ console.error("Error creating workflow run:", error);
3392
+ throw error;
3393
+ }
3394
+ });
3395
+ }
3396
+ function useCancelWorkflowRun() {
3397
+ const client = useMastraClient();
3398
+ return useMutation(async ({ workflowId, runId }) => {
3399
+ try {
3400
+ const workflow = client.getWorkflow(workflowId);
3401
+ const run = await workflow.createRun({ runId });
3402
+ return run.cancelRun();
3403
+ } catch (error) {
3404
+ console.error("Error canceling workflow run:", error);
3405
+ throw error;
3406
+ }
3407
+ });
3408
+ }
3409
+ var renderUnknown = (step, UnknownStep) => UnknownStep?.(step) ?? null;
3410
+ var WorkflowStepFactoryComponent = ({
3411
+ step,
3412
+ Step,
3413
+ MapStep,
3414
+ ForEachStep,
3415
+ ParallelStep,
3416
+ Conditional,
3417
+ LoopStep,
3418
+ SleepStep,
3419
+ SleepUntilStep,
3420
+ NestedWorkflowStep,
3421
+ UnknownStep
3422
+ }) => {
3423
+ switch (step.kind) {
3424
+ case "step":
3425
+ return /* @__PURE__ */ jsx(Fragment, { children: Step?.(step) ?? renderUnknown(step, UnknownStep) });
3426
+ case "map-step":
3427
+ return /* @__PURE__ */ jsx(Fragment, { children: MapStep?.(step) ?? renderUnknown(step, UnknownStep) });
3428
+ case "foreach-step":
3429
+ return /* @__PURE__ */ jsx(Fragment, { children: ForEachStep?.(step) ?? renderUnknown(step, UnknownStep) });
3430
+ case "parallel-step":
3431
+ return /* @__PURE__ */ jsx(Fragment, { children: ParallelStep?.(step) ?? renderUnknown(step, UnknownStep) });
3432
+ case "conditional":
3433
+ return /* @__PURE__ */ jsx(Fragment, { children: Conditional?.(step) ?? renderUnknown(step, UnknownStep) });
3434
+ case "loop-step":
3435
+ return /* @__PURE__ */ jsx(Fragment, { children: LoopStep?.(step) ?? renderUnknown(step, UnknownStep) });
3436
+ case "sleep-step":
3437
+ return /* @__PURE__ */ jsx(Fragment, { children: SleepStep?.(step) ?? renderUnknown(step, UnknownStep) });
3438
+ case "sleep-until-step":
3439
+ return /* @__PURE__ */ jsx(Fragment, { children: SleepUntilStep?.(step) ?? renderUnknown(step, UnknownStep) });
3440
+ case "nested-workflow-step":
3441
+ return /* @__PURE__ */ jsx(Fragment, { children: NestedWorkflowStep?.(step) ?? renderUnknown(step, UnknownStep) });
3442
+ default:
3443
+ return /* @__PURE__ */ jsx(Fragment, { children: renderUnknown(step, UnknownStep) });
3444
+ }
3445
+ };
3446
+ var WorkflowStepFactory = memo(WorkflowStepFactoryComponent);
3447
+
3448
+ // src/voice/record-mic-to-file.ts
3449
+ async function recordMicrophoneToFile(onFinish) {
3450
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
3451
+ const mediaRecorder = new MediaRecorder(stream);
3452
+ let chunks = [];
3453
+ mediaRecorder.ondataavailable = (e) => {
3454
+ chunks.push(e.data);
3455
+ };
3456
+ mediaRecorder.onstop = () => {
3457
+ const blob = new Blob(chunks, { type: "audio/webm" });
3458
+ const file = new File([blob], `recording-${Date.now()}.webm`, {
3459
+ type: "audio/webm",
3460
+ lastModified: Date.now()
3461
+ });
3462
+ stream.getTracks().forEach((track) => track.stop());
3463
+ onFinish(file);
3464
+ };
3465
+ return mediaRecorder;
3466
+ }
3467
+
3468
+ // src/voice/play-stream-with-web-audio.ts
3469
+ async function playStreamWithWebAudio(stream, onEnded) {
3470
+ const audioContext = new window.AudioContext();
3471
+ const reader = stream.getReader();
3472
+ const chunks = [];
3473
+ try {
3474
+ while (true) {
3475
+ const { done, value } = await reader.read();
3476
+ if (done) break;
3477
+ chunks.push(value);
3478
+ }
3479
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
3480
+ const combinedBuffer = new Uint8Array(totalLength);
3481
+ let offset = 0;
3482
+ for (const chunk of chunks) {
3483
+ combinedBuffer.set(chunk, offset);
3484
+ offset += chunk.length;
3485
+ }
3486
+ const audioBuffer = await audioContext.decodeAudioData(combinedBuffer.buffer);
3487
+ const source = audioContext.createBufferSource();
3488
+ source.buffer = audioBuffer;
3489
+ source.onended = onEnded ?? null;
3490
+ source.connect(audioContext.destination);
3491
+ source.start();
3492
+ return () => {
3493
+ source.onended = null;
3494
+ source.stop();
3495
+ void audioContext.close();
3496
+ };
3497
+ } catch (error) {
3498
+ await reader.cancel().catch(() => void 0);
3499
+ await audioContext.close().catch(() => void 0);
3500
+ throw error;
3501
+ } finally {
3502
+ reader.releaseLock();
3503
+ }
3504
+ }
3505
+ var useSpeechRecognition = ({
3506
+ language = "en-US",
3507
+ agentId,
3508
+ requestContext
3509
+ }) => {
3510
+ const client = useMastraClient();
3511
+ const [agent, setAgent] = useState(null);
3512
+ useEffect(() => {
3513
+ let cancelled = false;
3514
+ if (!agentId) {
3515
+ setAgent(null);
3516
+ return () => {
3517
+ cancelled = true;
3518
+ };
3519
+ }
3520
+ const agent2 = client.getAgent(agentId);
3521
+ const check = async () => {
3522
+ try {
3523
+ const speakers = await agent2.voice.getSpeakers(requestContext);
3524
+ if (!cancelled) {
3525
+ setAgent(speakers.length > 0 ? agent2 : null);
3526
+ }
3527
+ } catch {
3528
+ if (!cancelled) {
3529
+ setAgent(null);
3530
+ }
3531
+ }
3532
+ };
3533
+ void check();
3534
+ return () => {
3535
+ cancelled = true;
3536
+ };
3537
+ }, [agentId, client, requestContext]);
3538
+ const browserSpeechRecognition = useBrowserSpeechRecognition({ language });
3539
+ const mastraSpeechRecognition = useMastraSpeechToText({ agent, language });
3540
+ if (!agent) {
3541
+ return browserSpeechRecognition;
3542
+ }
3543
+ return mastraSpeechRecognition;
3544
+ };
3545
+ var useBrowserSpeechRecognition = ({ language = "en-US" }) => {
3546
+ const speechRecognitionRef = useRef(null);
3547
+ const [state, setState] = useState({
3548
+ isListening: false,
3549
+ transcript: "",
3550
+ error: null
3551
+ });
3552
+ const start = () => {
3553
+ if (!speechRecognitionRef.current) return;
3554
+ speechRecognitionRef.current.start();
3555
+ };
3556
+ const stop = () => {
3557
+ if (!speechRecognitionRef.current) return;
3558
+ speechRecognitionRef.current.stop();
3559
+ };
3560
+ useEffect(() => {
3561
+ if (!("webkitSpeechRecognition" in window) && !("SpeechRecognition" in window)) {
3562
+ setState((prev) => ({ ...prev, error: "Speech Recognition not supported in this browser" }));
3563
+ return;
3564
+ }
3565
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
3566
+ const recognition = new SpeechRecognition();
3567
+ speechRecognitionRef.current = recognition;
3568
+ recognition.continuous = true;
3569
+ recognition.lang = language;
3570
+ recognition.onstart = () => {
3571
+ setState((prev) => ({ ...prev, isListening: true, error: null }));
3572
+ };
3573
+ recognition.onresult = (event) => {
3574
+ let finalTranscript = "";
3575
+ for (let i = event.resultIndex; i < event.results.length; i++) {
3576
+ const transcript = event.results[i][0].transcript;
3577
+ if (event.results[i].isFinal) {
3578
+ finalTranscript += transcript + " ";
3579
+ }
3580
+ }
3581
+ setState((prev) => ({ ...prev, transcript: finalTranscript }));
3582
+ };
3583
+ recognition.onerror = (event) => {
3584
+ setState((prev) => ({ ...prev, error: `Error: ${event.error}` }));
3585
+ };
3586
+ recognition.onend = () => setState((prev) => ({ ...prev, isListening: false }));
3587
+ return () => {
3588
+ try {
3589
+ recognition.stop();
3590
+ } catch {
3591
+ }
3592
+ recognition.onstart = null;
3593
+ recognition.onresult = null;
3594
+ recognition.onerror = null;
3595
+ recognition.onend = null;
3596
+ speechRecognitionRef.current = null;
3597
+ };
3598
+ }, [language]);
3599
+ return {
3600
+ ...state,
3601
+ start,
3602
+ stop
3603
+ };
3604
+ };
3605
+ var useMastraSpeechToText = ({
3606
+ agent,
3607
+ language
3608
+ }) => {
3609
+ const [state, setState] = useState({
3610
+ isListening: false,
3611
+ transcript: "",
3612
+ error: null
3613
+ });
3614
+ const recorderRef = useRef(null);
3615
+ const sessionRef = useRef(0);
3616
+ const startInFlightRef = useRef(false);
3617
+ useEffect(() => {
3618
+ return () => {
3619
+ sessionRef.current += 1;
3620
+ startInFlightRef.current = false;
3621
+ recorderRef.current?.stop();
3622
+ recorderRef.current = null;
3623
+ };
3624
+ }, [agent]);
3625
+ const handleFinish = (session) => (file) => {
3626
+ if (!agent || session !== sessionRef.current) return;
3627
+ recorderRef.current = null;
3628
+ setState((prev) => ({ ...prev, isListening: false }));
3629
+ void agent.voice.listen(file, { language }).then((res) => {
3630
+ if (session !== sessionRef.current) return;
3631
+ setState((prev) => ({ ...prev, transcript: res.text, error: null }));
3632
+ }).catch((error) => {
3633
+ if (session !== sessionRef.current) return;
3634
+ const message = error instanceof Error ? error.message : "Failed to transcribe speech";
3635
+ setState((prev) => ({ ...prev, error: message }));
3636
+ });
3637
+ };
3638
+ const start = () => {
3639
+ if (!agent || startInFlightRef.current || recorderRef.current) return;
3640
+ startInFlightRef.current = true;
3641
+ const session = sessionRef.current;
3642
+ void recordMicrophoneToFile(handleFinish(session)).then((recorder) => {
3643
+ startInFlightRef.current = false;
3644
+ if (session !== sessionRef.current) {
3645
+ try {
3646
+ recorder.stop();
3647
+ } catch {
3648
+ }
3649
+ return;
3650
+ }
3651
+ recorderRef.current = recorder;
3652
+ setState((prev) => ({ ...prev, isListening: true, error: null }));
3653
+ recorder.start();
3654
+ }).catch((error) => {
3655
+ startInFlightRef.current = false;
3656
+ if (session !== sessionRef.current) return;
3657
+ const message = error instanceof Error ? error.message : "Failed to start speech recording";
3658
+ setState((prev) => ({ ...prev, isListening: false, error: message }));
3659
+ });
3660
+ };
3661
+ const stop = () => {
3662
+ sessionRef.current += 1;
3663
+ startInFlightRef.current = false;
3664
+ recorderRef.current?.stop();
3665
+ recorderRef.current = null;
3666
+ setState((prev) => ({ ...prev, isListening: false }));
3667
+ };
3668
+ return {
3669
+ ...state,
3670
+ start,
3671
+ stop
3672
+ };
3673
+ };
3674
+
3675
+ export { AgentIcon, CLIENT_MESSAGE_ID_KEY, CodeBlock, CodeBlockClass, CodeCopyButton, Entity, EntityCaret, EntityContent, EntityContentClass, EntityTrigger, EntityTriggerClass, EntityTriggerVariantClasses, Entry, EntryClass, EntryTitle, EntryTitleClass, Icon, IconButton, IconButtonClass, IconSizes, MastraReactProvider, Message, MessageActions, MessageActionsClass, MessageClass, MessageContent, MessageContentClass, MessageFactory, MessageList, MessageListClass, MessageStreaming, MessageStreamingClass, MessageUsage, MessageUsageClass, MessageUsageEntry, MessageUsageEntryClass, MessageUsageValue, MessageUsageValueClass, MessageUsages, MessageUsagesClass, ToolApproval, ToolApprovalActions, ToolApprovalActionsClass, ToolApprovalClass, ToolApprovalContent, ToolApprovalContentClass, ToolApprovalHeader, ToolApprovalHeaderClass, ToolApprovalTitle, ToolApprovalTitleClass, ToolsIcon, Tooltip, TooltipContent, TooltipContentClass, TooltipTrigger, WorkflowIcon, WorkflowStepFactory, accumulateChunk, accumulateNetworkChunk, finishStreamingAssistantMessage, fromCoreUserMessageToMastraDBMessage, fromCoreUserMessagesToMastraDBMessage, mapWorkflowStreamChunkToWatchResult, playStreamWithWebAudio, recordMicrophoneToFile, useCancelWorkflowRun, useChat, useCreateWorkflowRun, useEntity, useMastraClient, useSpeechRecognition, useStreamWorkflow };
2
3676
  //# sourceMappingURL=index.js.map
3677
+ //# sourceMappingURL=index.js.map