@mastra/react 1.2.5 → 1.2.6-alpha.1

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,23 @@
1
1
  # @mastra/react
2
2
 
3
+ ## 1.2.6-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies:
8
+ - @mastra/core@1.51.1-alpha.1
9
+ - @mastra/client-js@1.32.1-alpha.1
10
+
11
+ ## 1.2.6-alpha.0
12
+
13
+ ### Patch Changes
14
+
15
+ - Fixed binary file attachments missing during live streaming in `useChat` when `enableThreadSignals` is enabled. Attachments sent as `Uint8Array` or `ArrayBuffer` now render in the optimistic pending bubble and stay visible after the signal echo, without requiring a page refresh. ([#19439](https://github.com/mastra-ai/mastra/pull/19439))
16
+
17
+ - Updated dependencies [[`8a0d145`](https://github.com/mastra-ai/mastra/commit/8a0d145aadbdf7278665aceaaec364b35dd9bd94), [`bd2f1d2`](https://github.com/mastra-ai/mastra/commit/bd2f1d274d05e60e2366f005ea0d94d5cea0d5ff), [`21a0eb8`](https://github.com/mastra-ai/mastra/commit/21a0eb86746ba0b703acea360d4f84c6a5a493f2), [`de86fd7`](https://github.com/mastra-ai/mastra/commit/de86fd7119f0438381d1a642e3d258143c0b9c29), [`2745031`](https://github.com/mastra-ai/mastra/commit/2745031d1d4a4978f037092da371428c32e2842a), [`db650ce`](https://github.com/mastra-ai/mastra/commit/db650ce490348914e85b93651d83acdf8f2a4c31), [`6354eeb`](https://github.com/mastra-ai/mastra/commit/6354eeb32efa9f5f68f51dda394e90e2ee76f1fb)]:
18
+ - @mastra/core@1.51.1-alpha.0
19
+ - @mastra/client-js@1.32.1-alpha.0
20
+
3
21
  ## 1.2.5
4
22
 
5
23
  ### Patch Changes
@@ -1,2 +1,5 @@
1
+ export declare const uint8ArrayToBase64: (bytes: Uint8Array) => string;
1
2
  export declare function convertSignalDataToBase64String(content: string | ArrayBuffer | Uint8Array): string;
3
+ /** Canonical DB `file` part `data` for optimistic UI and memory-shaped storage. */
4
+ export declare function encodeFilePartDataForStorage(data: string | URL | ArrayBuffer | Uint8Array, mimeType: string): string;
2
5
  //# sourceMappingURL=signal-data.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"signal-data.d.ts","sourceRoot":"","sources":["../../src/agent/signal-data.ts"],"names":[],"mappings":"AAAA,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,CAYlG"}
1
+ {"version":3,"file":"signal-data.d.ts","sourceRoot":"","sources":["../../src/agent/signal-data.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,GAAI,OAAO,UAAU,KAAG,MAOtD,CAAC;AAEF,wBAAgB,+BAA+B,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,MAAM,CAOlG;AAED,mFAAmF;AACnF,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,WAAW,GAAG,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgBpH"}
package/dist/index.cjs CHANGED
@@ -70,6 +70,37 @@ var MastraReactProvider = ({
70
70
  );
71
71
  };
72
72
 
73
+ // src/agent/signal-data.ts
74
+ var uint8ArrayToBase64 = (bytes) => {
75
+ const chunkSize = 32768;
76
+ let binary = "";
77
+ for (let i = 0; i < bytes.length; i += chunkSize) {
78
+ binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
79
+ }
80
+ return btoa(binary);
81
+ };
82
+ function convertSignalDataToBase64String(content) {
83
+ if (typeof content === "string") {
84
+ return content;
85
+ }
86
+ const bytes = content instanceof ArrayBuffer ? new Uint8Array(content) : content;
87
+ return uint8ArrayToBase64(bytes);
88
+ }
89
+ function encodeFilePartDataForStorage(data, mimeType) {
90
+ if (typeof data === "string") {
91
+ return data;
92
+ }
93
+ if (data instanceof URL) {
94
+ return data.toString();
95
+ }
96
+ const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
97
+ const base64 = uint8ArrayToBase64(bytes);
98
+ if (base64.startsWith("data:")) {
99
+ return base64;
100
+ }
101
+ return `data:${mimeType};base64,${base64}`;
102
+ }
103
+
73
104
  // src/lib/mastra-db/formatCompletionFeedback.ts
74
105
  var formatBaseCompletionFeedback = (result, maxIterationReached, formatScorerHeading, incompleteMessage) => {
75
106
  const lines = [];
@@ -120,14 +151,6 @@ var CLIENT_MESSAGE_ID_KEY = "clientMessageId";
120
151
 
121
152
  // src/lib/mastra-db/accumulator.ts
122
153
  var cloneMetadata = (metadata) => metadata ? { ...metadata } : {};
123
- var uint8ArrayToBase64 = (bytes) => {
124
- const chunkSize = 32768;
125
- let binary = "";
126
- for (let i = 0; i < bytes.length; i += chunkSize) {
127
- binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
128
- }
129
- return btoa(binary);
130
- };
131
154
  var withParts = (message, parts) => ({
132
155
  ...message,
133
156
  content: {
@@ -324,22 +347,37 @@ var signalContentsToUserMessages = (contents, metadata) => {
324
347
  }
325
348
  if (typedPart.type === "image") {
326
349
  const image = typedPart.image;
327
- return [
328
- {
329
- type: "file",
330
- mimeType: typeof typedPart.mediaType === "string" ? typedPart.mediaType : typeof typedPart.mimeType === "string" ? typedPart.mimeType : "image/*",
331
- data: typeof image === "string" ? image : image instanceof URL ? image.toString() : ""
332
- }
333
- ];
350
+ const mimeType = typeof typedPart.mediaType === "string" ? typedPart.mediaType : typeof typedPart.mimeType === "string" ? typedPart.mimeType : "image/*";
351
+ if (typeof image === "string" || image instanceof URL || image instanceof ArrayBuffer || image instanceof Uint8Array) {
352
+ return [
353
+ {
354
+ type: "file",
355
+ mimeType,
356
+ data: encodeFilePartDataForStorage(image, mimeType)
357
+ }
358
+ ];
359
+ }
360
+ return [{ type: "file", mimeType, data: "" }];
334
361
  }
335
362
  if (typedPart.type === "file") {
336
363
  const data = typedPart.data;
337
- const dataValue = typeof data === "string" ? data : data instanceof URL ? data.toString() : typeof typedPart.url === "string" ? typedPart.url : "";
364
+ const mimeType = typeof typedPart.mediaType === "string" ? typedPart.mediaType : typeof typedPart.mimeType === "string" ? typedPart.mimeType : "application/octet-stream";
365
+ if (typeof data === "string" || data instanceof URL || data instanceof ArrayBuffer || data instanceof Uint8Array) {
366
+ return [
367
+ {
368
+ type: "file",
369
+ mimeType,
370
+ data: encodeFilePartDataForStorage(data, mimeType),
371
+ ...typeof typedPart.filename === "string" ? { filename: typedPart.filename } : {}
372
+ }
373
+ ];
374
+ }
375
+ const urlFallback = typeof typedPart.url === "string" ? typedPart.url : "";
338
376
  return [
339
377
  {
340
378
  type: "file",
341
- mimeType: typeof typedPart.mediaType === "string" ? typedPart.mediaType : typeof typedPart.mimeType === "string" ? typedPart.mimeType : "application/octet-stream",
342
- data: dataValue,
379
+ mimeType,
380
+ data: urlFallback,
343
381
  ...typeof typedPart.filename === "string" ? { filename: typedPart.filename } : {}
344
382
  }
345
383
  ];
@@ -364,6 +402,15 @@ var signalContentsToUserMessages = (contents, metadata) => {
364
402
  const parts = content.flatMap(toMessagePart);
365
403
  return parts.length ? [makeUserMessage(parts)] : [];
366
404
  };
405
+ var reconcilePendingUserEcho = (message, echoedContents, metadata, options) => {
406
+ const echoedMessages = signalContentsToUserMessages(echoedContents, metadata);
407
+ const echoedParts = echoedMessages[0]?.content.parts;
408
+ let reconciled = typeof options.signalId === "string" ? { ...message, id: options.signalId } : message;
409
+ if (echoedParts?.length) {
410
+ reconciled = { ...reconciled, content: { ...reconciled.content, parts: echoedParts } };
411
+ }
412
+ return options.keepClientMessageId ? clearPendingStatusKeepClientId(reconciled) : clearPendingStatus(reconciled);
413
+ };
367
414
  var makeToolInvocationPart = (invocation) => ({
368
415
  type: "tool-invocation",
369
416
  toolInvocation: invocation
@@ -384,14 +431,19 @@ var accumulateChunk = ({ chunk, conversation, metadata }) => {
384
431
  )) {
385
432
  return finishStreamingAssistantMessage(
386
433
  result.map(
387
- (message) => message.content.metadata?.status === "pending" && message.content.metadata[CLIENT_MESSAGE_ID_KEY] === echoedClientMessageId ? clearPendingStatusKeepClientId(typeof signalId === "string" ? { ...message, id: signalId } : message) : message
434
+ (message) => message.content.metadata?.status === "pending" && message.content.metadata[CLIENT_MESSAGE_ID_KEY] === echoedClientMessageId ? reconcilePendingUserEcho(message, chunk.data.contents, metadata, {
435
+ signalId: typeof signalId === "string" ? signalId : void 0,
436
+ keepClientMessageId: true
437
+ }) : message
388
438
  )
389
439
  );
390
440
  }
391
441
  if (typeof signalId === "string" && result.some((message) => message.id === signalId)) {
392
442
  return finishStreamingAssistantMessage(
393
443
  result.map(
394
- (message) => message.id === signalId && message.content.metadata?.status === "pending" ? clearPendingStatus(message) : message
444
+ (message) => message.id === signalId && message.content.metadata?.status === "pending" ? reconcilePendingUserEcho(message, chunk.data.contents, metadata, {
445
+ keepClientMessageId: false
446
+ }) : message
395
447
  )
396
448
  );
397
449
  }
@@ -1678,19 +1730,18 @@ var coreUserMessageToParts = (coreUserMessage) => typeof coreUserMessage.content
1678
1730
  return { type: "text", text: part.text };
1679
1731
  }
1680
1732
  case "image": {
1681
- const data = typeof part.image === "string" ? part.image : part.image instanceof URL ? part.image.toString() : "";
1733
+ const mimeType = part.mimeType ?? "image/*";
1682
1734
  return {
1683
1735
  type: "file",
1684
- mimeType: part.mimeType ?? "image/*",
1685
- data
1736
+ mimeType,
1737
+ data: encodeFilePartDataForStorage(part.image, mimeType)
1686
1738
  };
1687
1739
  }
1688
1740
  case "file": {
1689
- const data = typeof part.data === "string" ? part.data : part.data instanceof URL ? part.data.toString() : "";
1690
1741
  return {
1691
1742
  type: "file",
1692
1743
  mimeType: part.mimeType,
1693
- data,
1744
+ data: encodeFilePartDataForStorage(part.data, part.mimeType),
1694
1745
  ...part.filename !== void 0 ? { filename: part.filename } : {}
1695
1746
  };
1696
1747
  }
@@ -1818,19 +1869,6 @@ var extractRunIdFromMessages = (messages) => {
1818
1869
  return void 0;
1819
1870
  };
1820
1871
 
1821
- // src/agent/signal-data.ts
1822
- function convertSignalDataToBase64String(content) {
1823
- if (typeof content === "string") {
1824
- return content;
1825
- }
1826
- const bytes = content instanceof ArrayBuffer ? new Uint8Array(content) : content;
1827
- let binary = "";
1828
- for (const byte of bytes) {
1829
- binary += String.fromCharCode(byte);
1830
- }
1831
- return btoa(binary);
1832
- }
1833
-
1834
1872
  // src/agent/hooks.ts
1835
1873
  var extractPendingToolApprovalIdsFromMessages = (messages) => {
1836
1874
  const pendingToolApprovalIds = /* @__PURE__ */ new Set();