@mastra/client-js 1.24.0 → 1.25.1-alpha.0

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/client-js
2
2
 
3
+ ## 1.25.1-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Security remediation for the 2026-06-17 "easy-day-js" supply-chain incident. Patch bump to publish clean versions and move the `latest` dist-tag forward, superseding the compromised versions that declared the malicious `easy-day-js` dependency. ([#18056](https://github.com/mastra-ai/mastra/pull/18056))
8
+
9
+ - Updated dependencies [[`77a2351`](https://github.com/mastra-ai/mastra/commit/77a2351ee79296e360bce822cb3391f7cfd6489d)]:
10
+ - @mastra/core@1.43.1-alpha.0
11
+ - @mastra/schema-compat@1.2.14-alpha.0
12
+
13
+ ## 1.25.0
14
+
15
+ ### Minor Changes
16
+
17
+ - Added server and client APIs for source-backed stored agent workflows. ([#17583](https://github.com/mastra-ai/mastra/pull/17583))
18
+
19
+ The stored agent API can now report editor source capabilities, export owned agent override JSON, and open provider-backed change requests from the server. The client SDK exposes matching methods so Studio and other clients can use the same stored-agent workflow without calling a source provider directly.
20
+
21
+ ```ts
22
+ const storedAgent = client.getStoredAgent('weather-agent');
23
+ const exported = await storedAgent.export({ instructions: '...' });
24
+ await storedAgent.openChangeRequest({
25
+ instructions: '...',
26
+ changeMessage: 'Tune weather instructions',
27
+ });
28
+ ```
29
+
30
+ ### Patch Changes
31
+
32
+ - Fixed client tool model output so multimodal content uses the AI SDK media format. ([#17825](https://github.com/mastra-ai/mastra/pull/17825))
33
+
34
+ - Republished clean patch versions after compromised npm releases were published outside of the trusted release workflow. ([#18049](https://github.com/mastra-ai/mastra/pull/18049))
35
+
36
+ These packages must be released as clean versions higher than the compromised versions currently present on npm so semver ranges resolve to trusted tarballs.
37
+
38
+ - Fixed client tools ignoring `toModelOutput`. Client tools defined with a `toModelOutput` function now send their transformed output to the model, the same way server tools do. Previously the mapping was silently skipped for client tools, so multimodal tool results (for example screenshots returned as images) reached the model as stringified JSON instead of native image content. The raw tool result is still preserved for storage and application logic; only what the model sees changes. Fixes https://github.com/mastra-ai/mastra/issues/17792 ([#17825](https://github.com/mastra-ai/mastra/pull/17825))
39
+
40
+ - Updated dependencies [[`de66bb0`](https://github.com/mastra-ai/mastra/commit/de66bb040570444c702ce4d8e1e228a5de2949cb), [`67bf8e2`](https://github.com/mastra-ai/mastra/commit/67bf8e206dfe583954d96015cf0d09f7ac50e45f), [`8216d05`](https://github.com/mastra-ai/mastra/commit/8216d0528d866eb9a07f5d4c87ea3bb1e1139b45), [`d18b23c`](https://github.com/mastra-ai/mastra/commit/d18b23c5e29dfc381e73e3c51fcf6c779afd1823), [`5eb94eb`](https://github.com/mastra-ai/mastra/commit/5eb94ebcf66d4e28c9e26d5821ac93379bab20a0), [`1fa3e12`](https://github.com/mastra-ai/mastra/commit/1fa3e123582b63cfe49de4ee52dc6a065e8d956a), [`f9ee2ac`](https://github.com/mastra-ai/mastra/commit/f9ee2ac661af584e61bc063ac208c9035cd752ef), [`c853d53`](https://github.com/mastra-ai/mastra/commit/c853d535d2df84ab89db1adb4c28900c54c9a2d2), [`d8df1f8`](https://github.com/mastra-ai/mastra/commit/d8df1f8e947e1966c9d4e54713df56d0d0d65226), [`9192ddb`](https://github.com/mastra-ai/mastra/commit/9192ddbced8949113b30de444cbe763f075b59f5), [`ae96523`](https://github.com/mastra-ai/mastra/commit/ae965231f562d9766b0c90c49a69fc68acaa031c), [`17d5a92`](https://github.com/mastra-ai/mastra/commit/17d5a9211aa293b4d4418de3de70dc0394d58101), [`5573693`](https://github.com/mastra-ai/mastra/commit/5573693b589822250e20dfe6cf66e9ff3bc96da8), [`ec4da8a`](https://github.com/mastra-ai/mastra/commit/ec4da8a09e0d2ab452c6ee2c786042ea826b77e5), [`adc44e1`](https://github.com/mastra-ai/mastra/commit/adc44e13c7e570b91e86b20ea7556e61d819db31), [`ed346c0`](https://github.com/mastra-ai/mastra/commit/ed346c0bee2d8496690a4e538bfba1e46894660f), [`9b1adf7`](https://github.com/mastra-ai/mastra/commit/9b1adf7f39943c869182106bc4016e793b3304ac), [`c9ce1b2`](https://github.com/mastra-ai/mastra/commit/c9ce1b28d10871110648f9d7b6d76e880b9fa999), [`3ef01fd`](https://github.com/mastra-ai/mastra/commit/3ef01fd130b53d5bd4f828beb174e516a2eb1158), [`245a9a3`](https://github.com/mastra-ai/mastra/commit/245a9a315705fce17ddd980f78a92504b6615c4a), [`dc0b611`](https://github.com/mastra-ai/mastra/commit/dc0b6119b769bd00ee2c5df9259fb376fe63077a), [`38b5de8`](https://github.com/mastra-ai/mastra/commit/38b5de8e5d1d41a69522addf53d96f4b3a1d5bf0), [`dc0b611`](https://github.com/mastra-ai/mastra/commit/dc0b6119b769bd00ee2c5df9259fb376fe63077a), [`dd6a66e`](https://github.com/mastra-ai/mastra/commit/dd6a66ea0b32e0dea8059aec6b35d151e2c87dc4), [`d785c59`](https://github.com/mastra-ai/mastra/commit/d785c593b67fcb4cdc4fab9fdbde5f3b7665efc0), [`1fa3e12`](https://github.com/mastra-ai/mastra/commit/1fa3e123582b63cfe49de4ee52dc6a065e8d956a), [`8b984f4`](https://github.com/mastra-ai/mastra/commit/8b984f4361c202270ceb69257185c4756c9a7c56), [`bf08402`](https://github.com/mastra-ai/mastra/commit/bf084022374fa5d06ca70ed67a86dd64e379071b), [`81fe587`](https://github.com/mastra-ai/mastra/commit/81fe587275035715c1720ddf3fee0505cf053036), [`1fa3e12`](https://github.com/mastra-ai/mastra/commit/1fa3e123582b63cfe49de4ee52dc6a065e8d956a), [`403c438`](https://github.com/mastra-ai/mastra/commit/403c438e417278989ce247233d2c465b8d902cdd), [`f8ba195`](https://github.com/mastra-ai/mastra/commit/f8ba1954e27ee2b20586cc6cd9cf13c002c232f2)]:
41
+ - @mastra/core@1.43.0
42
+ - @mastra/schema-compat@1.2.12
43
+
3
44
  ## 1.24.0
4
45
 
5
46
  ### Minor Changes
@@ -3,7 +3,7 @@ name: mastra-client-js
3
3
  description: Documentation for @mastra/client-js. Use when working with @mastra/client-js APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/client-js"
6
- version: "1.24.0"
6
+ version: "1.25.1-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.24.0",
2
+ "version": "1.25.1-alpha.0",
3
3
  "package": "@mastra/client-js",
4
4
  "exports": {
5
5
  "RequestContext": {
@@ -522,6 +522,26 @@ response.processDataStream({
522
522
  })
523
523
  ```
524
524
 
525
+ ### Shape client tool output for the model
526
+
527
+ Client tools support `toModelOutput` to control what the model receives, including multimodal content such as images. Because client tools execute locally, the mapping also runs on the client after `execute` completes. The transformed output is sent back to the server alongside the raw result, so the raw result stays available for storage and application logic.
528
+
529
+ ```typescript
530
+ const screenshotTool = createTool({
531
+ id: 'takeScreenshot',
532
+ description: 'Takes a screenshot of the current page',
533
+ inputSchema: z.object({}),
534
+ execute: async () => {
535
+ const base64 = await captureScreenshot()
536
+ return { ok: true, data: base64 }
537
+ },
538
+ toModelOutput: output => ({
539
+ type: 'content',
540
+ value: [{ type: 'media', data: output.data, mediaType: 'image/jpeg' }],
541
+ }),
542
+ })
543
+ ```
544
+
525
545
  ### Tracing client tools
526
546
 
527
547
  When `@mastra/observability` is installed and configured on the server, a client-side tool records a `CLIENT_TOOL_CALL` span as a child of the current `AGENT_RUN` span. The server creates that span when the model emits the client tool call, injects a W3C trace carrier into the outgoing tool-call chunk, and ends the span once the tool arguments are available. Without server-side observability configured, client tool tracing is a no-op.
package/dist/index.cjs CHANGED
@@ -302,6 +302,40 @@ function requestContextQueryString(requestContext, delimiter = "?") {
302
302
  const queryString = searchParams.toString();
303
303
  return queryString ? `${delimiter}${queryString}` : "";
304
304
  }
305
+
306
+ // src/utils/client-tool-model-output.ts
307
+ function normalizeModelOutput(output) {
308
+ if (output == null || typeof output !== "object") return output;
309
+ const obj = output;
310
+ if (obj.type !== "content" || !Array.isArray(obj.value)) return output;
311
+ return {
312
+ ...obj,
313
+ value: obj.value.map((item) => {
314
+ if (item == null || typeof item !== "object") return item;
315
+ const part = item;
316
+ if (part.type === "image-url" && typeof part.url === "string") {
317
+ const semicolonIndex = part.url.indexOf(";");
318
+ const commaIndex = part.url.indexOf(",");
319
+ const mediaTypeEnd = semicolonIndex === -1 ? commaIndex : commaIndex === -1 ? semicolonIndex : Math.min(semicolonIndex, commaIndex);
320
+ const mediaType = typeof part.mediaType === "string" && part.mediaType ? part.mediaType : part.url.startsWith("data:") ? part.url.slice(5, mediaTypeEnd === -1 ? void 0 : mediaTypeEnd) || "image/jpeg" : "image/jpeg";
321
+ return { type: "media", data: part.url, mediaType };
322
+ }
323
+ if (part.type === "image-data" && typeof part.data === "string") {
324
+ return { type: "media", data: part.data, mediaType: part.mediaType ?? "image/jpeg" };
325
+ }
326
+ if (part.type === "file-data" && typeof part.data === "string") {
327
+ return { type: "media", data: part.data, mediaType: part.mediaType ?? "application/octet-stream" };
328
+ }
329
+ return part;
330
+ })
331
+ };
332
+ }
333
+ async function getClientToolModelOutput(clientTool, result) {
334
+ const toModelOutput = clientTool.toModelOutput;
335
+ if (typeof toModelOutput !== "function" || result == null) return void 0;
336
+ const modelOutput = await toModelOutput(result);
337
+ return modelOutput == null ? void 0 : normalizeModelOutput(modelOutput);
338
+ }
305
339
  function isZodType(value) {
306
340
  return typeof value === "object" && value !== null && "_def" in value && "parse" in value && typeof value.parse === "function" && "safeParse" in value && typeof value.safeParse === "function";
307
341
  }
@@ -596,11 +630,15 @@ async function executeToolCallAndRespond({
596
630
  }
597
631
  }
598
632
  });
633
+ const modelOutput = await getClientToolModelOutput(clientTool, result);
599
634
  const toolResultContent = {
600
635
  type: "tool-result",
601
636
  toolCallId: toolCall.payload.toolCallId,
602
637
  toolName: toolCall.payload.toolName,
603
- result
638
+ result,
639
+ // Carry the client-side toModelOutput result so the server uses it
640
+ // when building the model prompt, while result keeps the raw value.
641
+ ...modelOutput != null ? { providerOptions: { mastra: { modelOutput } } } : {}
604
642
  };
605
643
  if (observability) {
606
644
  toolResultContent.__mastraObservability = observability;
@@ -948,6 +986,7 @@ var Agent = class extends BaseResource {
948
986
  const clientTool = activeClientTools[toolCall.toolName];
949
987
  if (!clientTool || typeof clientTool.execute !== "function") continue;
950
988
  let result;
989
+ let modelOutput;
951
990
  let observability;
952
991
  try {
953
992
  const execution = await executeClientToolWithObservability({
@@ -971,8 +1010,14 @@ var Agent = class extends BaseResource {
971
1010
  });
972
1011
  result = execution.result;
973
1012
  observability = execution.observability;
1013
+ try {
1014
+ modelOutput = await getClientToolModelOutput(clientTool, result);
1015
+ } catch {
1016
+ modelOutput = void 0;
1017
+ }
974
1018
  } catch (error) {
975
1019
  result = { error: String(error) };
1020
+ modelOutput = void 0;
976
1021
  }
977
1022
  const toolResultContent = {
978
1023
  type: "tool-result",
@@ -998,6 +1043,9 @@ var Agent = class extends BaseResource {
998
1043
  toolCallId: toolCall.toolCallId,
999
1044
  toolName: toolCall.toolName,
1000
1045
  output: { type: "json", value: result },
1046
+ // Carry the client-side toModelOutput result so the server uses it
1047
+ // when building the model prompt, while output keeps the raw result.
1048
+ ...modelOutput != null ? { providerOptions: { mastra: { modelOutput } } } : {},
1001
1049
  ...observability ? { __mastraObservability: observability } : {}
1002
1050
  };
1003
1051
  toolResultMessages.push({
@@ -1979,6 +2027,7 @@ var Agent = class extends BaseResource {
1979
2027
  shouldExecuteClientTool = true;
1980
2028
  const runId = streamRunId ?? toolCall2.toolCallId;
1981
2029
  let result;
2030
+ let modelOutput;
1982
2031
  let observability;
1983
2032
  let synthetic;
1984
2033
  try {
@@ -2001,6 +2050,7 @@ var Agent = class extends BaseResource {
2001
2050
  }
2002
2051
  }
2003
2052
  }));
2053
+ modelOutput = await getClientToolModelOutput(clientTool, result);
2004
2054
  synthetic = {
2005
2055
  type: "tool-result",
2006
2056
  runId,
@@ -2059,6 +2109,14 @@ var Agent = class extends BaseResource {
2059
2109
  result,
2060
2110
  ...observability ? { __mastraObservability: observability } : {}
2061
2111
  };
2112
+ if (modelOutput != null) {
2113
+ const partWithMetadata = toolInvocationPart;
2114
+ const existingMastra = partWithMetadata.providerMetadata?.mastra != null && typeof partWithMetadata.providerMetadata.mastra === "object" ? partWithMetadata.providerMetadata.mastra : {};
2115
+ partWithMetadata.providerMetadata = {
2116
+ ...partWithMetadata.providerMetadata,
2117
+ mastra: { ...existingMastra, modelOutput }
2118
+ };
2119
+ }
2062
2120
  }
2063
2121
  const toolInvocation = lastMessage?.toolInvocations?.find(
2064
2122
  (toolInvocation2) => toolInvocation2.toolCallId === toolCall2.toolCallId
@@ -4814,6 +4872,15 @@ var StoredAgent = class extends BaseResource {
4814
4872
  body: params
4815
4873
  });
4816
4874
  }
4875
+ /**
4876
+ * Opens a source-provider change request for deterministic agent JSON without mutating storage.
4877
+ */
4878
+ openChangeRequest(params) {
4879
+ return this.request(`/stored/agents/${encodeURIComponent(this.storedAgentId)}/change-request`, {
4880
+ method: "POST",
4881
+ body: params
4882
+ });
4883
+ }
4817
4884
  /**
4818
4885
  * Deletes the stored agent
4819
4886
  * @param requestContext - Optional request context to pass as query parameter