@mastra/client-js 1.56.0-alpha.5 → 1.56.0-alpha.7

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.
@@ -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.56.0-alpha.5"
6
+ version: "1.56.0-alpha.7"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.56.0-alpha.5",
2
+ "version": "1.56.0-alpha.7",
3
3
  "package": "@mastra/client-js",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -321,6 +321,26 @@ await subscription.processDataStream({
321
321
 
322
322
  Pass `withInitialHistory: true` (or `{ perPage }`) to receive the stored messages as a first `thread-history` chunk instead of fetching history separately. Finished runs aren't replayed after it, so completed answers don't stream again on reconnect.
323
323
 
324
+ In the React SDK, `useChat()` exposes the `hasMore` flag from that first page as `initialHistoryPagination`, so you can decide whether to offer loading older messages without another history request:
325
+
326
+ ```typescript
327
+ import { useChat } from '@mastra/react'
328
+
329
+ const { messages, initialHistoryPagination } = useChat({
330
+ agentId: 'support-agent',
331
+ resourceId: 'user-123',
332
+ threadId: 'thread-abc',
333
+ enableThreadSignals: true,
334
+ withInitialHistory: { perPage: 20 },
335
+ })
336
+
337
+ // { hasMore: true }: older messages exist
338
+ // { hasMore: false }: the page reaches the start of the thread
339
+ // undefined: history is disabled, still loading, or the subscription ended
340
+ ```
341
+
342
+ `initialHistoryPagination` only describes the initial subscription page for the current agent, resource, thread, and `withInitialHistory` value. It isn't changed by live output or `setMessages()`. After you load older pages yourself, use the `hasMore` value from those responses.
343
+
324
344
  `subscribeToThread()` returns the underlying `Response` plus a `processDataStream()` helper. The helper reads the subscription stream until the connection closes or the request is aborted. Pass `reconnect: true` to resubscribe when the transport closes or a reconnect request fails, such as after a proxy idle timeout. If a reconnect request fails with a 4xx status (for example `401` or `403`) or `501`, `processDataStream()` stops reconnecting and rejects with the original `MastraClientError`. `408` and `429` are still retried.
325
345
 
326
346
  **resourceId** (`string`): Resource ID for the memory thread.
package/dist/index.cjs CHANGED
@@ -23,8 +23,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  //#endregion
24
24
  let _lukeed_uuid = require("@lukeed/uuid");
25
25
  let _mastra_core_error = require("@mastra/core/error");
26
- let _mastra_schema_compat_schema = require("@mastra/schema-compat/schema");
27
26
  let _mastra_core_request_context = require("@mastra/core/request-context");
27
+ let _mastra_schema_compat_schema = require("@mastra/schema-compat/schema");
28
28
  let _mastra_schema_compat_zod_to_json = require("@mastra/schema-compat/zod-to-json");
29
29
  let _mastra_core_a2a_client = require("@mastra/core/a2a/client");
30
30
  let _mastra_core_a2a_v1 = require("@mastra/core/a2a/v1");
@@ -2644,6 +2644,7 @@ var Agent = class extends BaseResource {
2644
2644
  try {
2645
2645
  let messages = [];
2646
2646
  let streamRunId = processedParams.runId;
2647
+ let finishedHistory;
2647
2648
  const [streamForController, streamForProcessing] = response.body.tee();
2648
2649
  const decoder = new TextDecoder();
2649
2650
  let pendingText = "";
@@ -2651,6 +2652,13 @@ var Agent = class extends BaseResource {
2651
2652
  pendingText += text;
2652
2653
  const lines = pendingText.split("\n\n");
2653
2654
  pendingText = isFinal ? "" : lines.pop() ?? "";
2655
+ for (const line of lines) {
2656
+ if (!line.startsWith("data: ") || !line.includes("\"type\":\"finish\"")) continue;
2657
+ try {
2658
+ const all = JSON.parse(line.slice(6))?.payload?.messages?.all;
2659
+ if (Array.isArray(all)) finishedHistory = all;
2660
+ } catch {}
2661
+ }
2654
2662
  const readableLines = lines.filter((line) => line.trim() !== "[DONE]" && line.trim() !== "data: [DONE]").join("\n\n");
2655
2663
  if (readableLines) safeEnqueue(new TextEncoder().encode(`${readableLines}\n\n`));
2656
2664
  };
@@ -2804,12 +2812,12 @@ var Agent = class extends BaseResource {
2804
2812
  role: "tool",
2805
2813
  content: toolResultContents
2806
2814
  };
2807
- const updatedMessages = threadId ? [toolResultMessage] : [
2815
+ const updatedMessages = threadId ? [toolResultMessage] : (route === "resume-stream" || route === "approve-tool-call" || route === "decline-tool-call") && finishedHistory ? [...finishedHistory, toolResultMessage] : [
2808
2816
  ...Array.isArray(processedParams.messages) ? processedParams.messages : [],
2809
2817
  ...messages,
2810
2818
  toolResultMessage
2811
2819
  ];
2812
- const recursionRoute = route === "resume-stream" ? "stream" : route === "resume-stream-until-idle" ? "stream-until-idle" : route;
2820
+ const recursionRoute = route === "resume-stream" || route === "approve-tool-call" || route === "decline-tool-call" ? "stream" : route === "resume-stream-until-idle" ? "stream-until-idle" : route;
2813
2821
  if (isAborted()) return;
2814
2822
  try {
2815
2823
  await this.processStreamResponse({
@@ -3010,7 +3018,8 @@ var Agent = class extends BaseResource {
3010
3018
  const { requestContext, ...rest } = params;
3011
3019
  const processedParams = {
3012
3020
  ...rest,
3013
- requestContext: parseClientRequestContext(requestContext)
3021
+ requestContext: parseClientRequestContext(requestContext),
3022
+ clientTools: processClientTools(params.clientToolsResolver?.() ?? params.clientTools)
3014
3023
  };
3015
3024
  const { readable, controller: readableController, signal } = this.createCancellableStream(params.abortSignal);
3016
3025
  const response = await this.processStreamResponse(processedParams, readableController, "approve-tool-call", signal);
@@ -3041,7 +3050,8 @@ var Agent = class extends BaseResource {
3041
3050
  const { requestContext, ...rest } = params;
3042
3051
  const processedParams = {
3043
3052
  ...rest,
3044
- requestContext: parseClientRequestContext(requestContext)
3053
+ requestContext: parseClientRequestContext(requestContext),
3054
+ clientTools: processClientTools(params.clientToolsResolver?.() ?? params.clientTools)
3045
3055
  };
3046
3056
  const { readable, controller: readableController, signal } = this.createCancellableStream(params.abortSignal);
3047
3057
  const response = await this.processStreamResponse(processedParams, readableController, "decline-tool-call", signal);
@@ -3198,28 +3208,70 @@ var Agent = class extends BaseResource {
3198
3208
  * Used when `requireToolApproval` is enabled with generate() to allow the agent to proceed.
3199
3209
  */
3200
3210
  async approveToolCallGenerate(params) {
3201
- const { requestContext, ...rest } = params;
3202
- return this.request(`/agents/${this.agentId}/approve-tool-call-generate`, {
3211
+ const { requestContext, clientTools, clientToolsResolver, memory, ...rest } = params;
3212
+ const response = await this.request(`/agents/${this.agentId}/approve-tool-call-generate`, {
3203
3213
  method: "POST",
3204
3214
  body: {
3205
3215
  ...rest,
3206
- requestContext: parseClientRequestContext(requestContext)
3216
+ requestContext: parseClientRequestContext(requestContext),
3217
+ clientTools: processClientTools(clientToolsResolver?.() ?? clientTools)
3207
3218
  }
3208
3219
  });
3220
+ return this.continueResumedGenerate(response, {
3221
+ requestContext,
3222
+ clientTools,
3223
+ clientToolsResolver,
3224
+ memory
3225
+ });
3209
3226
  }
3210
3227
  /**
3211
3228
  * Declines a pending tool call and returns the complete response (non-streaming).
3212
3229
  * Used when `requireToolApproval` is enabled with generate() to prevent tool execution.
3213
3230
  */
3214
3231
  async declineToolCallGenerate(params) {
3215
- const { requestContext, ...rest } = params;
3216
- return this.request(`/agents/${this.agentId}/decline-tool-call-generate`, {
3232
+ const { requestContext, clientTools, clientToolsResolver, memory, ...rest } = params;
3233
+ const response = await this.request(`/agents/${this.agentId}/decline-tool-call-generate`, {
3217
3234
  method: "POST",
3218
3235
  body: {
3219
3236
  ...rest,
3220
- requestContext: parseClientRequestContext(requestContext)
3237
+ requestContext: parseClientRequestContext(requestContext),
3238
+ clientTools: processClientTools(clientToolsResolver?.() ?? clientTools)
3221
3239
  }
3222
3240
  });
3241
+ return this.continueResumedGenerate(response, {
3242
+ requestContext,
3243
+ clientTools,
3244
+ clientToolsResolver,
3245
+ memory
3246
+ });
3247
+ }
3248
+ /**
3249
+ * Runs executable client tools the model called after an approval decision and continues on
3250
+ * /generate, like generate() does. With memory the continuation sends only the new messages to the
3251
+ * thread. Without memory it re-sends the conversation up to the last user turn, because the resume
3252
+ * routes keep the earlier history server-side and drop it once the run finishes.
3253
+ */
3254
+ async continueResumedGenerate(response, { requestContext, clientTools, clientToolsResolver, memory }) {
3255
+ if (response.finishReason !== "tool-calls") return response;
3256
+ const context = requestContext === void 0 || requestContext instanceof _mastra_core_request_context.RequestContext ? requestContext : new _mastra_core_request_context.RequestContext(Object.entries(requestContext));
3257
+ const threadId = typeof memory?.thread === "string" ? memory.thread : memory?.thread?.id;
3258
+ const history = response.messages ?? [];
3259
+ const priorTurns = history.slice(0, history.findLastIndex((message) => message.role === "user") + 1);
3260
+ return executeToolCallAndRespond({
3261
+ response,
3262
+ params: {
3263
+ messages: threadId ? [] : priorTurns,
3264
+ clientTools: clientToolsResolver?.() ?? clientTools,
3265
+ clientToolsResolver,
3266
+ requestContext: context,
3267
+ memory
3268
+ },
3269
+ agentId: this.agentId,
3270
+ resourceId: memory?.resource,
3271
+ threadId,
3272
+ requestContext: context,
3273
+ respondFn: (messages, options) => this.generate(messages, options)
3274
+ });
3223
3275
  }
3224
3276
  /**
3225
3277
  * Processes the stream response and handles tool calls