@mastra/react 0.1.0-beta.4 → 0.1.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # @mastra/react-hooks
2
2
 
3
+ ## 0.1.0-beta.6
4
+
5
+ ### Patch Changes
6
+
7
+ - Adjust the types to accept tracingOptions ([#10742](https://github.com/mastra-ai/mastra/pull/10742))
8
+
9
+ - Updated dependencies [[`6edf340`](https://github.com/mastra-ai/mastra/commit/6edf3402f6a46ee8def2f42a2287785251fbffd6), [`ad7e8f1`](https://github.com/mastra-ai/mastra/commit/ad7e8f16ac843cbd16687ad47b66ba96bcffe111), [`e1b7118`](https://github.com/mastra-ai/mastra/commit/e1b7118f42ca0a97247afc75e57dcd5fdf987752), [`441c7b6`](https://github.com/mastra-ai/mastra/commit/441c7b6665915cfa7fd625fded8c0f518530bf10), [`e849603`](https://github.com/mastra-ai/mastra/commit/e849603a596269069f58a438b98449ea2770493d)]:
10
+ - @mastra/client-js@1.0.0-beta.6
11
+
12
+ ## 0.1.0-beta.5
13
+
14
+ ### Patch Changes
15
+
16
+ - Configurable resourceId in react useChat ([#10461](https://github.com/mastra-ai/mastra/pull/10461))
17
+
18
+ - fix(agent): persist messages before tool suspension ([#10369](https://github.com/mastra-ai/mastra/pull/10369))
19
+
20
+ Fixes issues where thread and messages were not saved before suspension when tools require approval or call suspend() during execution. This caused conversation history to be lost if users refreshed during tool approval or suspension.
21
+
22
+ **Backend changes (@mastra/core):**
23
+ - Add assistant messages to messageList immediately after LLM execution
24
+ - Flush messages synchronously before suspension to persist state
25
+ - Create thread if it doesn't exist before flushing
26
+ - Add metadata helpers to persist and remove tool approval state
27
+ - Pass saveQueueManager and memory context through workflow for immediate persistence
28
+
29
+ **Frontend changes (@mastra/react):**
30
+ - Extract runId from pending approvals to enable resumption after refresh
31
+ - Convert `pendingToolApprovals` (DB format) to `requireApprovalMetadata` (runtime format)
32
+ - Handle both `dynamic-tool` and `tool-{NAME}` part types for approval state
33
+ - Change runId from hardcoded `agentId` to unique `uuid()`
34
+
35
+ **UI changes (@mastra/playground-ui):**
36
+ - Handle tool calls awaiting approval in message initialization
37
+ - Convert approval metadata format when loading initial messages
38
+
39
+ Fixes #9745, #9906
40
+
41
+ - Updated dependencies [[`898a972`](https://github.com/mastra-ai/mastra/commit/898a9727d286c2510d6b702dfd367e6aaf5c6b0f)]:
42
+ - @mastra/client-js@1.0.0-beta.5
43
+
3
44
  ## 0.1.0-beta.4
4
45
 
5
46
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -5,6 +5,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
5
5
  const jsxRuntime = require('react/jsx-runtime');
6
6
  const react = require('react');
7
7
  const clientJs = require('@mastra/client-js');
8
+ const uuid = require('@lukeed/uuid');
8
9
  const lucideReact = require('lucide-react');
9
10
  const tailwindMerge = require('tailwind-merge');
10
11
  const hastUtilToJsxRuntime = require('hast-util-to-jsx-runtime');
@@ -259,17 +260,19 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
259
260
  if (!lastMessage || lastMessage.role !== "assistant") return result;
260
261
  const parts = [...lastMessage.parts];
261
262
  const toolPartIndex = parts.findIndex(
262
- (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
263
+ (part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
263
264
  );
264
265
  if (toolPartIndex !== -1) {
265
266
  const toolPart = parts[toolPartIndex];
266
- if (toolPart.type === "dynamic-tool") {
267
+ if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
268
+ const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
269
+ const toolCallId = toolPart.toolCallId;
267
270
  if (chunk.type === "tool-result" && chunk.payload.isError || chunk.type === "tool-error") {
268
271
  const error = chunk.type === "tool-error" ? chunk.payload.error : chunk.payload.result;
269
272
  parts[toolPartIndex] = {
270
273
  type: "dynamic-tool",
271
- toolName: toolPart.toolName,
272
- toolCallId: toolPart.toolCallId,
274
+ toolName,
275
+ toolCallId,
273
276
  state: "output-error",
274
277
  input: toolPart.input,
275
278
  errorText: String(error),
@@ -288,8 +291,8 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
288
291
  }
289
292
  parts[toolPartIndex] = {
290
293
  type: "dynamic-tool",
291
- toolName: toolPart.toolName,
292
- toolCallId: toolPart.toolCallId,
294
+ toolName,
295
+ toolCallId,
293
296
  state: "output-available",
294
297
  input: toolPart.input,
295
298
  output,
@@ -311,11 +314,14 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
311
314
  if (!lastMessage || lastMessage.role !== "assistant") return result;
312
315
  const parts = [...lastMessage.parts];
313
316
  const toolPartIndex = parts.findIndex(
314
- (part) => part.type === "dynamic-tool" && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
317
+ (part) => (part.type === "dynamic-tool" || typeof part.type === "string" && part.type.startsWith("tool-")) && "toolCallId" in part && part.toolCallId === chunk.payload.toolCallId
315
318
  );
316
319
  if (toolPartIndex !== -1) {
317
320
  const toolPart = parts[toolPartIndex];
318
- if (toolPart.type === "dynamic-tool") {
321
+ if (toolPart.type === "dynamic-tool" || typeof toolPart.type === "string" && toolPart.type.startsWith("tool-")) {
322
+ const toolName = "toolName" in toolPart && typeof toolPart.toolName === "string" ? toolPart.toolName : typeof toolPart.type === "string" && toolPart.type.startsWith("tool-") ? toolPart.type.substring(5) : "";
323
+ const toolCallId = toolPart.toolCallId;
324
+ const input = toolPart.input;
319
325
  if (chunk.payload.output?.type?.startsWith("workflow-")) {
320
326
  const existingWorkflowState = toolPart.output || {};
321
327
  const updatedWorkflowState = mapWorkflowStreamChunkToWatchResult(
@@ -323,7 +329,11 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
323
329
  chunk.payload.output
324
330
  );
325
331
  parts[toolPartIndex] = {
326
- ...toolPart,
332
+ type: "dynamic-tool",
333
+ toolName,
334
+ toolCallId,
335
+ state: "input-streaming",
336
+ input,
327
337
  output: updatedWorkflowState
328
338
  };
329
339
  } else if (chunk.payload.output?.from === "AGENT" || chunk.payload.output?.from === "USER" && chunk.payload.output?.payload?.output?.type?.startsWith("workflow-")) {
@@ -332,7 +342,11 @@ const toUIMessage = ({ chunk, conversation, metadata }) => {
332
342
  const currentOutput = toolPart.output || [];
333
343
  const existingOutput = Array.isArray(currentOutput) ? currentOutput : [];
334
344
  parts[toolPartIndex] = {
335
- ...toolPart,
345
+ type: "dynamic-tool",
346
+ toolName,
347
+ toolCallId,
348
+ state: "input-streaming",
349
+ input,
336
350
  output: [...existingOutput, chunk.payload.output]
337
351
  };
338
352
  }
@@ -655,6 +669,20 @@ const toAssistantUIMessage = (message) => {
655
669
  }
656
670
  return baseToolCall;
657
671
  }
672
+ const requireApprovalMetadata = extendedMessage.metadata?.requireApprovalMetadata;
673
+ const partToolCallId = "toolCallId" in part && typeof part.toolCallId === "string" ? part.toolCallId : void 0;
674
+ const suspensionData = partToolCallId ? requireApprovalMetadata?.[partToolCallId] : void 0;
675
+ if (suspensionData) {
676
+ const toolName = "toolName" in part && typeof part.toolName === "string" ? part.toolName : part.type.startsWith("tool-") ? part.type.substring(5) : "";
677
+ return {
678
+ type: "tool-call",
679
+ toolCallId: partToolCallId,
680
+ toolName,
681
+ argsText: "input" in part ? JSON.stringify(part.input) : "{}",
682
+ args: "input" in part ? part.input : {},
683
+ metadata: extendedMessage.metadata
684
+ };
685
+ }
658
686
  return {
659
687
  type: "text",
660
688
  text: "",
@@ -741,7 +769,6 @@ const resolveInitialMessages = (messages) => {
741
769
  childMessages,
742
770
  result: finalResult?.text || ""
743
771
  };
744
- console.log("json", json);
745
772
  const nextMessage = {
746
773
  role: "assistant",
747
774
  parts: [
@@ -769,6 +796,18 @@ const resolveInitialMessages = (messages) => {
769
796
  return message;
770
797
  }
771
798
  }
799
+ const extendedMessage = message;
800
+ const pendingToolApprovals = extendedMessage.metadata?.pendingToolApprovals;
801
+ if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
802
+ return {
803
+ ...message,
804
+ metadata: {
805
+ ...message.metadata,
806
+ mode: "stream",
807
+ requireApprovalMetadata: pendingToolApprovals
808
+ }
809
+ };
810
+ }
772
811
  return message;
773
812
  });
774
813
  };
@@ -1217,12 +1256,24 @@ const fromCoreUserMessageToUIMessage = (coreUserMessage) => {
1217
1256
  };
1218
1257
  };
1219
1258
 
1220
- const useChat = ({ agentId, initializeMessages }) => {
1221
- const _currentRunId = react.useRef(void 0);
1259
+ const useChat = ({ agentId, resourceId, initializeMessages }) => {
1260
+ const extractRunIdFromMessages = (messages2) => {
1261
+ for (const message of messages2) {
1262
+ const pendingToolApprovals = message.metadata?.pendingToolApprovals;
1263
+ if (pendingToolApprovals && typeof pendingToolApprovals === "object") {
1264
+ const suspensionData = Object.values(pendingToolApprovals)[0];
1265
+ if (suspensionData?.runId) {
1266
+ return suspensionData.runId;
1267
+ }
1268
+ }
1269
+ }
1270
+ return void 0;
1271
+ };
1272
+ const initialMessages = initializeMessages?.() || [];
1273
+ const initialRunId = extractRunIdFromMessages(initialMessages);
1274
+ const _currentRunId = react.useRef(initialRunId);
1222
1275
  const _onChunk = react.useRef(void 0);
1223
- const [messages, setMessages] = react.useState(
1224
- () => resolveInitialMessages(initializeMessages?.() || [])
1225
- );
1276
+ const [messages, setMessages] = react.useState(() => resolveInitialMessages(initialMessages));
1226
1277
  const [toolCallApprovals, setToolCallApprovals] = react.useState({});
1227
1278
  const baseClient = useMastraClient();
1228
1279
  const [isRunning, setIsRunning] = react.useState(false);
@@ -1232,7 +1283,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1232
1283
  threadId,
1233
1284
  modelSettings,
1234
1285
  signal,
1235
- onFinish
1286
+ onFinish,
1287
+ tracingOptions
1236
1288
  }) => {
1237
1289
  const {
1238
1290
  frequencyPenalty,
@@ -1254,7 +1306,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1254
1306
  const agent = clientWithAbort.getAgent(agentId);
1255
1307
  const response = await agent.generate({
1256
1308
  messages: coreUserMessages,
1257
- runId: agentId,
1309
+ runId: uuid.v4(),
1258
1310
  maxSteps,
1259
1311
  modelSettings: {
1260
1312
  frequencyPenalty,
@@ -1267,8 +1319,9 @@ const useChat = ({ agentId, initializeMessages }) => {
1267
1319
  },
1268
1320
  instructions,
1269
1321
  requestContext,
1270
- ...threadId ? { threadId, resourceId: agentId } : {},
1271
- providerOptions
1322
+ ...threadId ? { threadId, resourceId: resourceId || agentId } : {},
1323
+ providerOptions,
1324
+ tracingOptions
1272
1325
  });
1273
1326
  setIsRunning(false);
1274
1327
  if (response && "uiMessages" in response.response && response.response.uiMessages) {
@@ -1282,7 +1335,15 @@ const useChat = ({ agentId, initializeMessages }) => {
1282
1335
  setMessages((prev) => [...prev, ...mastraUIMessages]);
1283
1336
  }
1284
1337
  };
1285
- const stream = async ({ coreUserMessages, requestContext, threadId, onChunk, modelSettings, signal }) => {
1338
+ const stream = async ({
1339
+ coreUserMessages,
1340
+ requestContext,
1341
+ threadId,
1342
+ onChunk,
1343
+ modelSettings,
1344
+ signal,
1345
+ tracingOptions
1346
+ }) => {
1286
1347
  const {
1287
1348
  frequencyPenalty,
1288
1349
  presencePenalty,
@@ -1302,7 +1363,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1302
1363
  abortSignal: signal
1303
1364
  });
1304
1365
  const agent = clientWithAbort.getAgent(agentId);
1305
- const runId = agentId;
1366
+ const runId = uuid.v4();
1306
1367
  const response = await agent.stream({
1307
1368
  messages: coreUserMessages,
1308
1369
  runId,
@@ -1318,9 +1379,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1318
1379
  },
1319
1380
  instructions,
1320
1381
  requestContext,
1321
- ...threadId ? { threadId, resourceId: agentId } : {},
1382
+ ...threadId ? { threadId, resourceId: resourceId || agentId } : {},
1322
1383
  providerOptions,
1323
- requireToolApproval
1384
+ requireToolApproval,
1385
+ tracingOptions
1324
1386
  });
1325
1387
  _onChunk.current = onChunk;
1326
1388
  _currentRunId.current = runId;
@@ -1338,7 +1400,8 @@ const useChat = ({ agentId, initializeMessages }) => {
1338
1400
  threadId,
1339
1401
  onNetworkChunk,
1340
1402
  modelSettings,
1341
- signal
1403
+ signal,
1404
+ tracingOptions
1342
1405
  }) => {
1343
1406
  const { frequencyPenalty, presencePenalty, maxRetries, maxTokens, temperature, topK, topP, maxSteps } = modelSettings || {};
1344
1407
  setIsRunning(true);
@@ -1347,6 +1410,7 @@ const useChat = ({ agentId, initializeMessages }) => {
1347
1410
  abortSignal: signal
1348
1411
  });
1349
1412
  const agent = clientWithAbort.getAgent(agentId);
1413
+ const runId = uuid.v4();
1350
1414
  const response = await agent.network({
1351
1415
  messages: coreUserMessages,
1352
1416
  maxSteps,
@@ -1359,9 +1423,10 @@ const useChat = ({ agentId, initializeMessages }) => {
1359
1423
  topK,
1360
1424
  topP
1361
1425
  },
1362
- runId: agentId,
1426
+ runId,
1363
1427
  requestContext,
1364
- ...threadId ? { thread: threadId, resourceId: agentId } : {}
1428
+ ...threadId ? { thread: threadId, resourceId: resourceId || agentId } : {},
1429
+ tracingOptions
1365
1430
  });
1366
1431
  const transformer = new AISdkNetworkTransformer();
1367
1432
  await response.processDataStream({