@mastra/react 0.5.3-alpha.2 → 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/CHANGELOG.md +39 -0
- package/dist/agent/hooks.d.ts +5 -0
- package/dist/agent/hooks.d.ts.map +1 -1
- package/dist/index.cjs +337 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +333 -54
- package/dist/index.js.map +1 -1
- package/dist/lib/mastra-db/accumulator.d.ts.map +1 -1
- package/dist/lib/mastra-db/fromCoreUserMessage.d.ts +8 -5
- package/dist/lib/mastra-db/fromCoreUserMessage.d.ts.map +1 -1
- package/dist/lib/mastra-db/index.d.ts +2 -1
- package/dist/lib/mastra-db/index.d.ts.map +1 -1
- package/dist/lib/mastra-db/types.d.ts +17 -2
- package/dist/lib/mastra-db/types.d.ts.map +1 -1
- package/dist/ui/MessageFactory/MessageFactory.d.ts.map +1 -1
- package/dist/ui/MessageFactory/index.d.ts +1 -1
- package/dist/ui/MessageFactory/index.d.ts.map +1 -1
- package/dist/ui/MessageFactory/types.d.ts +26 -9
- package/dist/ui/MessageFactory/types.d.ts.map +1 -1
- package/dist/voice/index.d.ts +5 -0
- package/dist/voice/index.d.ts.map +1 -0
- package/dist/voice/play-stream-with-web-audio.d.ts +2 -0
- package/dist/voice/play-stream-with-web-audio.d.ts.map +1 -0
- package/dist/voice/record-mic-to-file.d.ts +2 -0
- package/dist/voice/record-mic-to-file.d.ts.map +1 -0
- package/dist/voice/use-speech-recognition.d.ts +20 -0
- package/dist/voice/use-speech-recognition.d.ts.map +1 -0
- package/package.json +4 -4
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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
|
|
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
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
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
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
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
|
|
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
|
|
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(
|
|
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 } =
|
|
1798
|
+
const { pendingToolApprovals: _omit, ...restMetadata } = normalizedMetadata;
|
|
1762
1799
|
const hasStillPending = Object.keys(stillPending).length > 0;
|
|
1763
1800
|
return {
|
|
1764
|
-
...
|
|
1801
|
+
...normalizedMessage,
|
|
1765
1802
|
content: {
|
|
1766
|
-
...
|
|
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,
|
|
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
|
|
2501
|
-
const
|
|
2502
|
-
|
|
2503
|
-
|
|
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
|
-
|
|
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
|