@mastra/react 0.5.3-alpha.3 → 0.6.0-alpha.4

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/dist/index.d.ts CHANGED
@@ -7,4 +7,5 @@ export * from './lib/mastra-db/index.js';
7
7
  export type { MastraDBMessage, MastraMessageContentV2, MastraMessagePart, MastraToolApproval, MastraToolInvocation, MastraToolInvocationPart, MessageSource, MemoryInfo, } from '@mastra/core/agent/message-list';
8
8
  export * from './ui/index.js';
9
9
  export * from './workflows/index.js';
10
+ export * from './voice/index.js';
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,cAAc,iBAAiB,CAAC;AAChC,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,aAAa,EACb,UAAU,GACX,MAAM,iCAAiC,CAAC;AACzC,cAAc,MAAM,CAAC;AACrB,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,YAAY,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,cAAc,iBAAiB,CAAC;AAChC,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,aAAa,EACb,UAAU,GACX,MAAM,iCAAiC,CAAC;AACzC,cAAc,MAAM,CAAC;AACrB,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -113,6 +113,9 @@ var formatStreamCompletionFeedback = (result, maxIterationReached) => {
113
113
  );
114
114
  };
115
115
 
116
+ // src/lib/mastra-db/types.ts
117
+ var CLIENT_MESSAGE_ID_KEY = "clientMessageId";
118
+
116
119
  // src/lib/mastra-db/accumulator.ts
117
120
  var cloneMetadata = (metadata) => metadata ? { ...metadata } : {};
118
121
  var withParts = (message, parts) => ({
@@ -129,6 +132,14 @@ var withMetadata = (message, metadata) => ({
129
132
  metadata
130
133
  }
131
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
+ };
132
143
  var replaceLast = (conversation, message) => [
133
144
  ...conversation.slice(0, -1),
134
145
  message
@@ -155,6 +166,7 @@ var partState = (part) => part.state;
155
166
  var finishStreamingAssistantMessage = (conversation) => {
156
167
  const lastMessage = conversation[conversation.length - 1];
157
168
  if (!lastMessage || lastMessage.role !== "assistant") return conversation;
169
+ if (lastMessage.content.parts.length === 0) return conversation.slice(0, -1);
158
170
  const nextParts = lastMessage.content.parts.map((part) => {
159
171
  if ((part.type === "text" || part.type === "reasoning") && partState(part) === "streaming") {
160
172
  return {
@@ -355,8 +367,22 @@ var accumulateChunk = ({ chunk, conversation, metadata }) => {
355
367
  if (isDataChunk(chunk)) {
356
368
  if (chunk.type === "data-user-message" && "data" in chunk && (chunk.data?.type === "user-message" || chunk.data?.type === "user")) {
357
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
+ }
358
380
  if (typeof signalId === "string" && result.some((message) => message.id === signalId)) {
359
- return result;
381
+ return finishStreamingAssistantMessage(
382
+ result.map(
383
+ (message) => message.id === signalId && message.content.metadata?.status === "pending" ? clearPendingStatus(message) : message
384
+ )
385
+ );
360
386
  }
361
387
  const userMessages = signalContentsToUserMessages(chunk.data.contents, metadata);
362
388
  if (!userMessages.length) return result;
@@ -1630,46 +1656,45 @@ var accumulateNetworkChunk = ({
1630
1656
  };
1631
1657
 
1632
1658
  // src/lib/mastra-db/fromCoreUserMessage.ts
1633
- var fromCoreUserMessageToMastraDBMessage = (coreUserMessage) => {
1634
- const id = `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
1635
- const parts = typeof coreUserMessage.content === "string" ? [{ type: "text", text: coreUserMessage.content }] : coreUserMessage.content.map((part) => {
1636
- switch (part.type) {
1637
- case "text": {
1638
- return { type: "text", text: part.text };
1639
- }
1640
- case "image": {
1641
- const url = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
1642
- return {
1643
- type: "file",
1644
- mediaType: part.mimeType ?? "image/*",
1645
- url
1646
- };
1647
- }
1648
- case "file": {
1649
- const url = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
1650
- return {
1651
- type: "file",
1652
- mediaType: part.mimeType,
1653
- url,
1654
- ...part.filename !== void 0 ? { filename: part.filename } : {}
1655
- };
1656
- }
1657
- default: {
1658
- const exhaustiveCheck = part;
1659
- throw new Error(`Unhandled content part type: ${exhaustiveCheck.type}`);
1660
- }
1659
+ var coreUserMessageToParts = (coreUserMessage) => typeof coreUserMessage.content === "string" ? [{ type: "text", text: coreUserMessage.content }] : coreUserMessage.content.map((part) => {
1660
+ switch (part.type) {
1661
+ case "text": {
1662
+ return { type: "text", text: part.text };
1661
1663
  }
1662
- });
1663
- return {
1664
- id,
1665
- role: "user",
1666
- createdAt: /* @__PURE__ */ new Date(),
1667
- content: {
1668
- format: 2,
1669
- parts
1664
+ case "image": {
1665
+ const data = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
1666
+ return {
1667
+ type: "file",
1668
+ mimeType: part.mimeType ?? "image/*",
1669
+ data
1670
+ };
1670
1671
  }
1671
- };
1672
- };
1672
+ case "file": {
1673
+ const data = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
1674
+ return {
1675
+ type: "file",
1676
+ mimeType: part.mimeType,
1677
+ data,
1678
+ ...part.filename !== void 0 ? { filename: part.filename } : {}
1679
+ };
1680
+ }
1681
+ default: {
1682
+ const exhaustiveCheck = part;
1683
+ throw new Error(`Unhandled content part type: ${exhaustiveCheck.type}`);
1684
+ }
1685
+ }
1686
+ });
1687
+ var newUserMessage = (parts) => ({
1688
+ id: `user-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
1689
+ role: "user",
1690
+ createdAt: /* @__PURE__ */ new Date(),
1691
+ content: {
1692
+ format: 2,
1693
+ parts
1694
+ }
1695
+ });
1696
+ var fromCoreUserMessageToMastraDBMessage = (coreUserMessage) => newUserMessage(coreUserMessageToParts(coreUserMessage));
1697
+ var fromCoreUserMessagesToMastraDBMessage = (coreUserMessages) => newUserMessage(coreUserMessages.flatMap(coreUserMessageToParts));
1673
1698
 
1674
1699
  // src/agent/extractRunIdFromMessages.ts
1675
1700
  var isRecord = (value) => value !== null && typeof value === "object";
@@ -1749,21 +1774,33 @@ var resolveInitialMessages = (messages) => messages.filter((message) => {
1749
1774
  return true;
1750
1775
  }).map((message) => {
1751
1776
  const metadata = message.content?.metadata;
1752
- const pendingToolApprovals = metadata?.pendingToolApprovals;
1777
+ const normalizedMessage = metadata && (metadata.status === "pending" || CLIENT_MESSAGE_ID_KEY in metadata) ? (() => {
1778
+ const { [CLIENT_MESSAGE_ID_KEY]: _omitClientMessageId, ...rest } = metadata;
1779
+ const { status: _omitStatus, ...restWithoutStatus } = rest;
1780
+ return {
1781
+ ...message,
1782
+ content: {
1783
+ ...message.content,
1784
+ metadata: metadata.status === "pending" ? restWithoutStatus : rest
1785
+ }
1786
+ };
1787
+ })() : message;
1788
+ const normalizedMetadata = normalizedMessage.content?.metadata;
1789
+ const pendingToolApprovals = normalizedMetadata?.pendingToolApprovals;
1753
1790
  if (!pendingToolApprovals || typeof pendingToolApprovals !== "object") {
1754
- return message;
1791
+ return normalizedMessage;
1755
1792
  }
1756
1793
  const stillPending = Object.fromEntries(
1757
1794
  Object.entries(pendingToolApprovals).filter(
1758
- ([, approval]) => approval && typeof approval === "object" && typeof approval.toolCallId === "string" && !toolCallHasOutput(message.content.parts, approval.toolCallId)
1795
+ ([, approval]) => approval && typeof approval === "object" && typeof approval.toolCallId === "string" && !toolCallHasOutput(normalizedMessage.content.parts, approval.toolCallId)
1759
1796
  )
1760
1797
  );
1761
- const { pendingToolApprovals: _omit, ...restMetadata } = metadata;
1798
+ const { pendingToolApprovals: _omit, ...restMetadata } = normalizedMetadata;
1762
1799
  const hasStillPending = Object.keys(stillPending).length > 0;
1763
1800
  return {
1764
- ...message,
1801
+ ...normalizedMessage,
1765
1802
  content: {
1766
- ...message.content,
1803
+ ...normalizedMessage.content,
1767
1804
  metadata: {
1768
1805
  ...restMetadata,
1769
1806
  mode: "stream",
@@ -2090,7 +2127,8 @@ var useChat = ({
2090
2127
  signal,
2091
2128
  tracingOptions,
2092
2129
  clientTools,
2093
- signalId
2130
+ signalId,
2131
+ clientMessageId
2094
2132
  }) => {
2095
2133
  const {
2096
2134
  frequencyPenalty,
@@ -2201,7 +2239,7 @@ var useChat = ({
2201
2239
  };
2202
2240
  try {
2203
2241
  const result = await agent.sendMessage({
2204
- message: messageContents,
2242
+ message: clientMessageId ? { contents: messageContents, metadata: { [CLIENT_MESSAGE_ID_KEY]: clientMessageId } } : messageContents,
2205
2243
  resourceId: resourceId || agentId,
2206
2244
  threadId: threadId2,
2207
2245
  ifIdle: {
@@ -2236,7 +2274,7 @@ var useChat = ({
2236
2274
  onSignalEcho?.(resolvedSignalId);
2237
2275
  if (isThreadSignalUnsupportedError(signalError)) {
2238
2276
  markThreadSignalsUnsupported();
2239
- setMessages((prev) => [...prev, ...coreUserMessages.map(fromCoreUserMessageToMastraDBMessage)]);
2277
+ setMessages((prev) => [...prev, fromCoreUserMessagesToMastraDBMessage(coreUserMessages)]);
2240
2278
  await streamWithLegacyRoute();
2241
2279
  return;
2242
2280
  }
@@ -2497,15 +2535,26 @@ var useChat = ({
2497
2535
  if (args.coreUserMessages) {
2498
2536
  coreUserMessages.push(...args.coreUserMessages);
2499
2537
  }
2500
- const dbUserMessages = coreUserMessages.map(fromCoreUserMessageToMastraDBMessage);
2501
- const signalId = mode === "stream" && args.threadId && !_threadSignalsUnsupportedRef.current && !threadSignalsDisabled ? dbUserMessages[0]?.id : void 0;
2502
- if (!signalId) {
2503
- setMessages((s) => [...s, ...dbUserMessages]);
2538
+ const dbUserMessage = fromCoreUserMessagesToMastraDBMessage(coreUserMessages);
2539
+ const clientSetId = mode === "stream" && args.threadId && !_threadSignalsUnsupportedRef.current && !threadSignalsDisabled ? `client-set-${v4()}` : void 0;
2540
+ const signalId = clientSetId;
2541
+ const clientMessageId = clientSetId;
2542
+ if (signalId) {
2543
+ const metadata = {
2544
+ ...dbUserMessage.content.metadata,
2545
+ mode: "stream",
2546
+ status: "pending",
2547
+ [CLIENT_MESSAGE_ID_KEY]: clientMessageId
2548
+ };
2549
+ const pendingMessage = { ...dbUserMessage, id: clientSetId, content: { ...dbUserMessage.content, metadata } };
2550
+ setMessages((s) => [...s, pendingMessage]);
2551
+ } else {
2552
+ setMessages((s) => [...s, dbUserMessage]);
2504
2553
  }
2505
2554
  if (mode === "generate") {
2506
2555
  await generate({ ...args, coreUserMessages });
2507
2556
  } else if (mode === "stream") {
2508
- await stream({ ...args, coreUserMessages, signalId });
2557
+ await stream({ ...args, coreUserMessages, signalId, clientMessageId });
2509
2558
  } else if (mode === "network") {
2510
2559
  await network({ ...args, coreUserMessages });
2511
2560
  }
@@ -2924,6 +2973,9 @@ var MessageFactoryComponent = ({ message, roles, status, fallback, ...renderers
2924
2973
  content = status.Error({ text: joinText(parts), message });
2925
2974
  } else {
2926
2975
  content = /* @__PURE__ */ jsx(Fragment, { children: parts.map((part, index) => /* @__PURE__ */ jsx(PartRenderer, { part, renderers, fallback }, getPartKey(part, index))) });
2976
+ if (metadata?.status === "pending" && status?.Pending) {
2977
+ content = status.Pending({ children: content, text: joinText(parts), message });
2978
+ }
2927
2979
  const verdict = resolveTaskVerdict(metadata);
2928
2980
  if (verdict && status?.Task) {
2929
2981
  content = /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -3350,6 +3402,233 @@ function useCancelWorkflowRun() {
3350
3402
  });
3351
3403
  }
3352
3404
 
3353
- export { AgentIcon, CodeBlock, CodeBlockClass, CodeCopyButton, Entity, EntityCaret, EntityContent, EntityContentClass, EntityTrigger, EntityTriggerClass, EntityTriggerVariantClasses, Entry, EntryClass, EntryTitle, EntryTitleClass, Icon, IconButton, IconButtonClass, IconSizes, MastraReactProvider, Message, MessageActions, MessageActionsClass, MessageClass, MessageContent, MessageContentClass, 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, accumulateChunk, accumulateNetworkChunk, finishStreamingAssistantMessage, fromCoreUserMessageToMastraDBMessage, mapWorkflowStreamChunkToWatchResult, useCancelWorkflowRun, useChat, useCreateWorkflowRun, useEntity, useMastraClient, useStreamWorkflow };
3405
+ // src/voice/record-mic-to-file.ts
3406
+ async function recordMicrophoneToFile(onFinish) {
3407
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
3408
+ const mediaRecorder = new MediaRecorder(stream);
3409
+ let chunks = [];
3410
+ mediaRecorder.ondataavailable = (e) => {
3411
+ chunks.push(e.data);
3412
+ };
3413
+ mediaRecorder.onstop = () => {
3414
+ const blob = new Blob(chunks, { type: "audio/webm" });
3415
+ const file = new File([blob], `recording-${Date.now()}.webm`, {
3416
+ type: "audio/webm",
3417
+ lastModified: Date.now()
3418
+ });
3419
+ stream.getTracks().forEach((track) => track.stop());
3420
+ onFinish(file);
3421
+ };
3422
+ return mediaRecorder;
3423
+ }
3424
+
3425
+ // src/voice/play-stream-with-web-audio.ts
3426
+ async function playStreamWithWebAudio(stream, onEnded) {
3427
+ const audioContext = new window.AudioContext();
3428
+ const reader = stream.getReader();
3429
+ const chunks = [];
3430
+ try {
3431
+ while (true) {
3432
+ const { done, value } = await reader.read();
3433
+ if (done) break;
3434
+ chunks.push(value);
3435
+ }
3436
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
3437
+ const combinedBuffer = new Uint8Array(totalLength);
3438
+ let offset = 0;
3439
+ for (const chunk of chunks) {
3440
+ combinedBuffer.set(chunk, offset);
3441
+ offset += chunk.length;
3442
+ }
3443
+ const audioBuffer = await audioContext.decodeAudioData(combinedBuffer.buffer);
3444
+ const source = audioContext.createBufferSource();
3445
+ source.buffer = audioBuffer;
3446
+ source.onended = onEnded ?? null;
3447
+ source.connect(audioContext.destination);
3448
+ source.start();
3449
+ return () => {
3450
+ source.onended = null;
3451
+ source.stop();
3452
+ void audioContext.close();
3453
+ };
3454
+ } catch (error) {
3455
+ await reader.cancel().catch(() => void 0);
3456
+ await audioContext.close().catch(() => void 0);
3457
+ throw error;
3458
+ } finally {
3459
+ reader.releaseLock();
3460
+ }
3461
+ }
3462
+ var useSpeechRecognition = ({
3463
+ language = "en-US",
3464
+ agentId,
3465
+ requestContext
3466
+ }) => {
3467
+ const client = useMastraClient();
3468
+ const [agent, setAgent] = useState(null);
3469
+ useEffect(() => {
3470
+ let cancelled = false;
3471
+ if (!agentId) {
3472
+ setAgent(null);
3473
+ return () => {
3474
+ cancelled = true;
3475
+ };
3476
+ }
3477
+ const agent2 = client.getAgent(agentId);
3478
+ const check = async () => {
3479
+ try {
3480
+ const speakers = await agent2.voice.getSpeakers(requestContext);
3481
+ if (!cancelled) {
3482
+ setAgent(speakers.length > 0 ? agent2 : null);
3483
+ }
3484
+ } catch {
3485
+ if (!cancelled) {
3486
+ setAgent(null);
3487
+ }
3488
+ }
3489
+ };
3490
+ void check();
3491
+ return () => {
3492
+ cancelled = true;
3493
+ };
3494
+ }, [agentId, client, requestContext]);
3495
+ const browserSpeechRecognition = useBrowserSpeechRecognition({ language });
3496
+ const mastraSpeechRecognition = useMastraSpeechToText({ agent, language });
3497
+ if (!agent) {
3498
+ return browserSpeechRecognition;
3499
+ }
3500
+ return mastraSpeechRecognition;
3501
+ };
3502
+ var useBrowserSpeechRecognition = ({ language = "en-US" }) => {
3503
+ const speechRecognitionRef = useRef(null);
3504
+ const [state, setState] = useState({
3505
+ isListening: false,
3506
+ transcript: "",
3507
+ error: null
3508
+ });
3509
+ const start = () => {
3510
+ if (!speechRecognitionRef.current) return;
3511
+ speechRecognitionRef.current.start();
3512
+ };
3513
+ const stop = () => {
3514
+ if (!speechRecognitionRef.current) return;
3515
+ speechRecognitionRef.current.stop();
3516
+ };
3517
+ useEffect(() => {
3518
+ if (!("webkitSpeechRecognition" in window) && !("SpeechRecognition" in window)) {
3519
+ setState((prev) => ({ ...prev, error: "Speech Recognition not supported in this browser" }));
3520
+ return;
3521
+ }
3522
+ const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
3523
+ const recognition = new SpeechRecognition();
3524
+ speechRecognitionRef.current = recognition;
3525
+ recognition.continuous = true;
3526
+ recognition.lang = language;
3527
+ recognition.onstart = () => {
3528
+ setState((prev) => ({ ...prev, isListening: true, error: null }));
3529
+ };
3530
+ recognition.onresult = (event) => {
3531
+ let finalTranscript = "";
3532
+ for (let i = event.resultIndex; i < event.results.length; i++) {
3533
+ const transcript = event.results[i][0].transcript;
3534
+ if (event.results[i].isFinal) {
3535
+ finalTranscript += transcript + " ";
3536
+ }
3537
+ }
3538
+ setState((prev) => ({ ...prev, transcript: finalTranscript }));
3539
+ };
3540
+ recognition.onerror = (event) => {
3541
+ setState((prev) => ({ ...prev, error: `Error: ${event.error}` }));
3542
+ };
3543
+ recognition.onend = () => setState((prev) => ({ ...prev, isListening: false }));
3544
+ return () => {
3545
+ try {
3546
+ recognition.stop();
3547
+ } catch {
3548
+ }
3549
+ recognition.onstart = null;
3550
+ recognition.onresult = null;
3551
+ recognition.onerror = null;
3552
+ recognition.onend = null;
3553
+ speechRecognitionRef.current = null;
3554
+ };
3555
+ }, [language]);
3556
+ return {
3557
+ ...state,
3558
+ start,
3559
+ stop
3560
+ };
3561
+ };
3562
+ var useMastraSpeechToText = ({
3563
+ agent,
3564
+ language
3565
+ }) => {
3566
+ const [state, setState] = useState({
3567
+ isListening: false,
3568
+ transcript: "",
3569
+ error: null
3570
+ });
3571
+ const recorderRef = useRef(null);
3572
+ const sessionRef = useRef(0);
3573
+ const startInFlightRef = useRef(false);
3574
+ useEffect(() => {
3575
+ return () => {
3576
+ sessionRef.current += 1;
3577
+ startInFlightRef.current = false;
3578
+ recorderRef.current?.stop();
3579
+ recorderRef.current = null;
3580
+ };
3581
+ }, [agent]);
3582
+ const handleFinish = (session) => (file) => {
3583
+ if (!agent || session !== sessionRef.current) return;
3584
+ recorderRef.current = null;
3585
+ setState((prev) => ({ ...prev, isListening: false }));
3586
+ void agent.voice.listen(file, { language }).then((res) => {
3587
+ if (session !== sessionRef.current) return;
3588
+ setState((prev) => ({ ...prev, transcript: res.text, error: null }));
3589
+ }).catch((error) => {
3590
+ if (session !== sessionRef.current) return;
3591
+ const message = error instanceof Error ? error.message : "Failed to transcribe speech";
3592
+ setState((prev) => ({ ...prev, error: message }));
3593
+ });
3594
+ };
3595
+ const start = () => {
3596
+ if (!agent || startInFlightRef.current || recorderRef.current) return;
3597
+ startInFlightRef.current = true;
3598
+ const session = sessionRef.current;
3599
+ void recordMicrophoneToFile(handleFinish(session)).then((recorder) => {
3600
+ startInFlightRef.current = false;
3601
+ if (session !== sessionRef.current) {
3602
+ try {
3603
+ recorder.stop();
3604
+ } catch {
3605
+ }
3606
+ return;
3607
+ }
3608
+ recorderRef.current = recorder;
3609
+ setState((prev) => ({ ...prev, isListening: true, error: null }));
3610
+ recorder.start();
3611
+ }).catch((error) => {
3612
+ startInFlightRef.current = false;
3613
+ if (session !== sessionRef.current) return;
3614
+ const message = error instanceof Error ? error.message : "Failed to start speech recording";
3615
+ setState((prev) => ({ ...prev, isListening: false, error: message }));
3616
+ });
3617
+ };
3618
+ const stop = () => {
3619
+ sessionRef.current += 1;
3620
+ startInFlightRef.current = false;
3621
+ recorderRef.current?.stop();
3622
+ recorderRef.current = null;
3623
+ setState((prev) => ({ ...prev, isListening: false }));
3624
+ };
3625
+ return {
3626
+ ...state,
3627
+ start,
3628
+ stop
3629
+ };
3630
+ };
3631
+
3632
+ 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, accumulateChunk, accumulateNetworkChunk, finishStreamingAssistantMessage, fromCoreUserMessageToMastraDBMessage, fromCoreUserMessagesToMastraDBMessage, mapWorkflowStreamChunkToWatchResult, playStreamWithWebAudio, recordMicrophoneToFile, useCancelWorkflowRun, useChat, useCreateWorkflowRun, useEntity, useMastraClient, useSpeechRecognition, useStreamWorkflow };
3354
3633
  //# sourceMappingURL=index.js.map
3355
3634
  //# sourceMappingURL=index.js.map