@mastra/client-js 1.18.0-alpha.11 → 1.18.0-alpha.13

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,64 @@
1
1
  # @mastra/client-js
2
2
 
3
+ ## 1.18.0-alpha.13
4
+
5
+ ### Minor Changes
6
+
7
+ - Added Agent signals for sending contextual messages into agent thread loops and subscribing to thread activity. ([#16229](https://github.com/mastra-ai/mastra/pull/16229))
8
+
9
+ Call `agent.sendSignal()` to inject context into a running agent loop. When the thread is idle, that same signal becomes the prompt that starts the next loop by default. Use `ifActive.behavior` and `ifIdle.behavior` to deliver, persist, discard, or wake from a signal.
10
+
11
+ Use `agent.subscribeToThread()` to follow the raw stream chunks for a memory thread, observe signal echoes with stable IDs, and abort the active stream for that thread.
12
+
13
+ ```ts
14
+ const subscription = await agent.subscribeToThread({ resourceId, threadId });
15
+
16
+ void (async () => {
17
+ for await (const part of subscription.stream) {
18
+ if (part.type === 'finish') {
19
+ subscription.unsubscribe();
20
+ }
21
+ }
22
+ })();
23
+
24
+ agent.sendSignal({ type: 'user-message', contents: 'Use the latest answer' }, { resourceId, threadId });
25
+ ```
26
+
27
+ - Fix client-js bugs surfaced by the SDK ↔ server contract audit. ([#16439](https://github.com/mastra-ai/mastra/pull/16439))
28
+ - `MastraClient.getAgentBuilderActions()` previously requested `/agent-builder/` (trailing slash) and 404'd. Now hits `/agent-builder`.
29
+ - `AgentBuilder.stream(params, runId)` now requires `runId`. The server route requires it; calls without it failed with a server-side validation error. The SDK now both types `runId` as required and guards at runtime.
30
+ - `MastraClient.createStoredSkill(...)` now requires `description` in its parameter type. The server schema has always required it; the SDK type used to mark it optional, so omitting it produced a runtime 400 instead of a compile error.
31
+
32
+ Migration:
33
+
34
+ ```ts
35
+ // Before
36
+ await agentBuilder.stream({ inputData });
37
+
38
+ // After
39
+ await agentBuilder.stream({ inputData }, runId);
40
+ ```
41
+
42
+ ```ts
43
+ // Before
44
+ await client.createStoredSkill({ name, instructions });
45
+
46
+ // After
47
+ await client.createStoredSkill({ name, description, instructions });
48
+ ```
49
+
50
+ ### Patch Changes
51
+
52
+ - Updated dependencies [[`b59316f`](https://github.com/mastra-ai/mastra/commit/b59316ffa0f7688165b0f9c81ccdf85da461e5b2), [`55f1e2d`](https://github.com/mastra-ai/mastra/commit/55f1e2d65425b95a49ae788053b266f256e38c96), [`d48a705`](https://github.com/mastra-ai/mastra/commit/d48a705ff3dfbdc7a996e07ecd8293b5effd9a2a)]:
53
+ - @mastra/core@1.33.0-alpha.12
54
+
55
+ ## 1.18.0-alpha.12
56
+
57
+ ### Patch Changes
58
+
59
+ - Updated dependencies [[`37c0dc5`](https://github.com/mastra-ai/mastra/commit/37c0dc5697d343db98628bf867bf71ce6deec6d7), [`ef6b584`](https://github.com/mastra-ai/mastra/commit/ef6b5847ac33c0a7e80af3a86e8801e2933dd3ee), [`4dd900d`](https://github.com/mastra-ai/mastra/commit/4dd900d75dfe9be89f8c15188b368a8622aa1e18), [`4ff5bdf`](https://github.com/mastra-ai/mastra/commit/4ff5bdfe170cba6dfb5260c6af0f4ba668430772), [`bbcd93c`](https://github.com/mastra-ai/mastra/commit/bbcd93cf7d8aa1007d6d84bfd033b8015c912087), [`308bd07`](https://github.com/mastra-ai/mastra/commit/308bd074f35cef0c75d82fc1eb19382fe04ecf6f)]:
60
+ - @mastra/core@1.33.0-alpha.11
61
+
3
62
  ## 1.18.0-alpha.11
4
63
 
5
64
  ### Patch 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.18.0-alpha.11"
6
+ version: "1.18.0-alpha.13"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -16,6 +16,7 @@ Read the individual reference documents for detailed explanations and code examp
16
16
 
17
17
  ### Docs
18
18
 
19
+ - [Signals](references/docs-agents-signals.md) - Learn how to send real-time context into a Mastra agent thread.
19
20
  - [Editor overview](references/docs-editor-overview.md) - Let non-technical team members iterate on agents, version every change, and run experiments without redeploying.
20
21
  - [Auth0](references/docs-server-auth-auth0.md) - Documentation for the @mastra/auth-auth0 package, which authenticates Mastra applications using Auth0 authentication.
21
22
  - [Clerk](references/docs-server-auth-clerk.md) - Documentation for the `@mastra/auth-clerk` package, which authenticates Mastra applications using Clerk authentication.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.18.0-alpha.11",
2
+ "version": "1.18.0-alpha.13",
3
3
  "package": "@mastra/client-js",
4
4
  "exports": {
5
5
  "RequestContext": {
@@ -0,0 +1,151 @@
1
+ # Signals
2
+
3
+ > **Experimental:** Agent signals are experimental. The API may change in a future release.
4
+
5
+ Signals are a way to interact with an agent through a thread. Instead of starting every interaction with `agent.stream()`, subscribe to a thread and send signals. Mastra either wakes the agent when the thread is idle or drops the signal into the running agent loop.
6
+
7
+ Signals are a context engineering tool for guiding the agent in real time as the agent loop progresses. Use them to add system-generated content from external event sources, such as incoming email notifications, GitHub pull request comments, background task notifications, and similar events.
8
+
9
+ ## Quickstart
10
+
11
+ Subscribe to the thread before sending signals. The subscription receives the active stream when the signal wakes the agent or enters a running loop.
12
+
13
+ ```typescript
14
+ const subscription = await agent.subscribeToThread({
15
+ resourceId: 'user_123',
16
+ threadId: 'thread_456',
17
+ })
18
+
19
+ agent.sendSignal(
20
+ {
21
+ type: 'user-message',
22
+ contents: 'Compare that with the previous option.',
23
+ },
24
+ {
25
+ resourceId: 'user_123',
26
+ threadId: 'thread_456',
27
+ },
28
+ )
29
+
30
+ for await (const chunk of subscription.stream) {
31
+ console.log(chunk)
32
+ }
33
+ ```
34
+
35
+ When the thread has a running agent stream, the signal becomes new input inside that agent loop. When the thread is idle, Mastra starts a stream with the signal as the first input.
36
+
37
+ ## Control signal behavior
38
+
39
+ By default, Mastra delivers signals to active runs and wakes idle threads. Use `ifActive.behavior` and `ifIdle.behavior` to change that behavior.
40
+
41
+ ```typescript
42
+ const result = agent.sendSignal(
43
+ {
44
+ type: 'user-message',
45
+ contents: 'Store this for later, but do not wake the agent.',
46
+ },
47
+ {
48
+ resourceId: 'user_123',
49
+ threadId: 'thread_456',
50
+ ifIdle: {
51
+ behavior: 'persist',
52
+ },
53
+ },
54
+ )
55
+
56
+ await result.persisted
57
+ ```
58
+
59
+ The behavior options are:
60
+
61
+ - `ifActive.behavior: 'deliver'`: Add the signal to the running agent loop. This is the default.
62
+ - `ifActive.behavior: 'persist'`: Save the signal to memory without adding it to the running loop.
63
+ - `ifActive.behavior: 'discard'`: Ignore the signal while the thread is active.
64
+ - `ifIdle.behavior: 'wake'`: Start a stream with the signal as the first input. This is the default.
65
+ - `ifIdle.behavior: 'persist'`: Save the signal to memory without starting a stream.
66
+ - `ifIdle.behavior: 'discard'`: Ignore the signal while the thread is idle.
67
+
68
+ Pass `ifIdle.streamOptions` when the idle wake-up stream needs options such as model settings, tools, or runtime context. You do not need to repeat `memory.resource` or `memory.thread`; Mastra uses the top-level `resourceId` and `threadId` for the thread.
69
+
70
+ ```typescript
71
+ agent.sendSignal(
72
+ {
73
+ type: 'user-message',
74
+ contents: 'Continue with the next step.',
75
+ },
76
+ {
77
+ resourceId: 'user_123',
78
+ threadId: 'thread_456',
79
+ ifIdle: {
80
+ behavior: 'wake',
81
+ streamOptions: {
82
+ maxSteps: 3,
83
+ },
84
+ },
85
+ },
86
+ )
87
+ ```
88
+
89
+ ## Send external event context
90
+
91
+ Use custom signal types for system-generated context. Non-user signal types are rendered as XML-style user-role context so they can appear inside conversation history without looking like assistant output.
92
+
93
+ ```typescript
94
+ agent.sendSignal(
95
+ {
96
+ type: 'system-reminder',
97
+ contents: 'User X has left a new PR comment asking for a smaller API surface.',
98
+ attributes: {
99
+ type: 'github',
100
+ pr: '123',
101
+ },
102
+ },
103
+ {
104
+ resourceId: 'user_123',
105
+ threadId: 'thread_456',
106
+ },
107
+ )
108
+ ```
109
+
110
+ The model receives the custom signal as context like this:
111
+
112
+ ```xml
113
+ <system-reminder type="github" pr="123">User X has left a new PR comment asking for a smaller API surface.</system-reminder>
114
+ ```
115
+
116
+ Use XML-safe signal type names and attribute names. Signal type names and attribute names can contain letters, numbers, underscores, periods, and hyphens. They must start with a letter or underscore.
117
+
118
+ ## Use the client SDK
119
+
120
+ The JavaScript client exposes the same thread signal APIs. Use `subscribeToThread()` before `sendSignal()` so the client can render the stream that wakes from, or receives, the signal.
121
+
122
+ ```typescript
123
+ const agent = client.getAgent('supportAgent')
124
+
125
+ const subscription = await agent.subscribeToThread({
126
+ resourceId: 'user_123',
127
+ threadId: 'thread_456',
128
+ })
129
+
130
+ await agent.sendSignal({
131
+ signal: {
132
+ type: 'user-message',
133
+ contents: 'Show the shorter version.',
134
+ },
135
+ resourceId: 'user_123',
136
+ threadId: 'thread_456',
137
+ })
138
+
139
+ await subscription.processDataStream({
140
+ onChunk: chunk => {
141
+ console.log(chunk)
142
+ },
143
+ })
144
+ ```
145
+
146
+ ## Related
147
+
148
+ - [`Agent.sendSignal()`](https://mastra.ai/reference/agents/agent)
149
+ - [`Agent.subscribeToThread()`](https://mastra.ai/reference/agents/agent)
150
+ - [`client.getAgent().sendSignal()`](https://mastra.ai/reference/client-js/agents)
151
+ - [`client.getAgent().subscribeToThread()`](https://mastra.ai/reference/client-js/agents)
@@ -151,6 +151,95 @@ for await (const part of uiMessageStream) {
151
151
  }
152
152
  ```
153
153
 
154
+ ### `sendSignal()`
155
+
156
+ Send a signal to an active agent run or memory thread. Use this with `subscribeToThread()` so the client can render the stream that wakes from, or receives, the signal.
157
+
158
+ ```typescript
159
+ const agent = mastraClient.getAgent('support-agent')
160
+
161
+ const result = await agent.sendSignal({
162
+ signal: {
163
+ type: 'user-message',
164
+ contents: 'Also consider the customer note I just added.',
165
+ },
166
+ resourceId: 'user-123',
167
+ threadId: 'thread-abc',
168
+ })
169
+
170
+ console.log(result.runId)
171
+ ```
172
+
173
+ Use `ifActive.behavior` and `ifIdle.behavior` to control whether Mastra delivers, persists, discards, or wakes from a signal:
174
+
175
+ ```typescript
176
+ await agent.sendSignal({
177
+ signal: { type: 'user-message', contents: 'Store this for later.' },
178
+ resourceId: 'user-123',
179
+ threadId: 'thread-abc',
180
+ ifIdle: {
181
+ behavior: 'persist',
182
+ },
183
+ })
184
+ ```
185
+
186
+ Pass `ifIdle.streamOptions` when the idle wake-up stream needs options such as model settings, tools, or runtime context:
187
+
188
+ ```typescript
189
+ await agent.sendSignal({
190
+ signal: { type: 'user-message', contents: 'Start from this signal.' },
191
+ resourceId: 'user-123',
192
+ threadId: 'thread-abc',
193
+ ifIdle: {
194
+ behavior: 'wake',
195
+ streamOptions: {
196
+ maxSteps: 3,
197
+ },
198
+ },
199
+ })
200
+ ```
201
+
202
+ Returns `{ accepted: true, runId: string }`.
203
+
204
+ **signal** (`{ type: 'user-message'; contents: MessageListInput } | { type: string; contents: string }`): \`user-message\` signals are treated as user input. Other signal types are converted to contextual XML before the next model call.
205
+
206
+ **runId** (`string`): Run ID to target directly.
207
+
208
+ **resourceId** (`string`): Resource ID for the memory thread. Use with \`threadId\` for thread-targeted signals.
209
+
210
+ **threadId** (`string`): Thread ID to target. Use with \`resourceId\` for thread-targeted signals.
211
+
212
+ **ifActive.behavior** (`'deliver' | 'persist' | 'discard'`): Controls what happens when the target thread is active. Defaults to \`deliver\`.
213
+
214
+ **ifIdle.behavior** (`'wake' | 'persist' | 'discard'`): Controls what happens when the target thread is idle. Defaults to \`wake\`.
215
+
216
+ **ifIdle.streamOptions** (`Omit<AgentExecutionOptions, 'messages'>`): Options for the stream that starts when \`ifIdle.behavior\` is \`wake\`.
217
+
218
+ ### `subscribeToThread()`
219
+
220
+ Subscribe to raw stream chunks for a memory thread. Use this to render output from a thread that may be started or continued by `sendSignal()`.
221
+
222
+ ```typescript
223
+ const agent = mastraClient.getAgent('support-agent')
224
+
225
+ const subscription = await agent.subscribeToThread({
226
+ resourceId: 'user-123',
227
+ threadId: 'thread-abc',
228
+ })
229
+
230
+ await subscription.processDataStream({
231
+ onChunk: async chunk => {
232
+ console.log(chunk)
233
+ },
234
+ })
235
+ ```
236
+
237
+ `subscribeToThread()` returns the underlying `Response` plus a `processDataStream()` helper. The helper reads the subscription stream until the connection closes or the request is aborted.
238
+
239
+ **resourceId** (`string`): Resource ID for the memory thread.
240
+
241
+ **threadId** (`string`): Thread ID to subscribe to.
242
+
154
243
  ### `streamUntilIdle()`
155
244
 
156
245
  Stream a response and keep the stream open until every [background task](https://mastra.ai/docs/agents/background-tasks) dispatched during the run completes. The server re-enters the agentic loop on each task completion so the LLM can react to results in the same call. Requires background tasks to be [enabled on the Mastra instance](https://mastra.ai/reference/configuration) and a memory thread; otherwise the call falls through to a plain `stream()`.
package/dist/index.cjs CHANGED
@@ -135,11 +135,15 @@ function processClientTools(clientTools) {
135
135
  // src/utils/process-mastra-stream.ts
136
136
  async function sharedProcessMastraStream({
137
137
  stream,
138
- onChunk
138
+ onChunk,
139
+ signal
139
140
  }) {
140
141
  const reader = stream.getReader();
141
142
  const decoder = new TextDecoder();
142
143
  let buffer = "";
144
+ const abort = () => void reader.cancel();
145
+ if (signal?.aborted) abort();
146
+ else signal?.addEventListener("abort", abort, { once: true });
143
147
  try {
144
148
  while (true) {
145
149
  const { done, value } = await reader.read();
@@ -167,25 +171,30 @@ async function sharedProcessMastraStream({
167
171
  }
168
172
  }
169
173
  } finally {
174
+ signal?.removeEventListener("abort", abort);
170
175
  reader.releaseLock();
171
176
  }
172
177
  }
173
178
  async function processMastraNetworkStream({
174
179
  stream,
175
- onChunk
180
+ onChunk,
181
+ signal
176
182
  }) {
177
183
  return sharedProcessMastraStream({
178
184
  stream,
179
- onChunk
185
+ onChunk,
186
+ signal
180
187
  });
181
188
  }
182
189
  async function processMastraStream({
183
190
  stream,
184
- onChunk
191
+ onChunk,
192
+ signal
185
193
  }) {
186
194
  return sharedProcessMastraStream({
187
195
  stream,
188
- onChunk
196
+ onChunk,
197
+ signal
189
198
  });
190
199
  }
191
200
 
@@ -446,6 +455,38 @@ var Agent = class extends BaseResource {
446
455
  body: { instructions, comment }
447
456
  });
448
457
  }
458
+ /**
459
+ * @experimental Agent signals are experimental and may change in a future release.
460
+ */
461
+ sendSignal(params) {
462
+ return this.request(`/agents/${this.agentId}/signals`, {
463
+ method: "POST",
464
+ body: params
465
+ });
466
+ }
467
+ /**
468
+ * @experimental Agent signals are experimental and may change in a future release.
469
+ */
470
+ async subscribeToThread(params) {
471
+ const streamResponse = await this.request(`/agents/${this.agentId}/threads/subscribe`, {
472
+ method: "POST",
473
+ body: params,
474
+ stream: true
475
+ });
476
+ if (!streamResponse.body) {
477
+ throw new Error("No response body");
478
+ }
479
+ streamResponse.processDataStream = async ({
480
+ onChunk
481
+ }) => {
482
+ await processMastraStream({
483
+ stream: streamResponse.body,
484
+ onChunk,
485
+ signal: this.options.abortSignal
486
+ });
487
+ };
488
+ return streamResponse;
489
+ }
449
490
  /**
450
491
  * Clones this agent to a new stored agent in the database
451
492
  * @param params - Clone parameters including optional newId, newName, metadata, authorId, and requestContext
@@ -3423,13 +3464,14 @@ var AgentBuilder = class extends BaseResource {
3423
3464
  * This calls `/agent-builder/:actionId/stream`.
3424
3465
  */
3425
3466
  async stream(params, runId) {
3426
- const searchParams = new URLSearchParams();
3427
- if (runId) {
3428
- searchParams.set("runId", runId);
3467
+ if (!runId) {
3468
+ throw new Error("runId is required to stream an agent builder action");
3429
3469
  }
3470
+ const searchParams = new URLSearchParams();
3471
+ searchParams.set("runId", runId);
3430
3472
  const requestContext = parseClientRequestContext(params.requestContext);
3431
3473
  const { requestContext: _, ...actionParams } = params;
3432
- const url = `/agent-builder/${this.actionId}/stream${searchParams.toString() ? `?${searchParams.toString()}` : ""}`;
3474
+ const url = `/agent-builder/${this.actionId}/stream?${searchParams.toString()}`;
3433
3475
  const response = await this.request(url, {
3434
3476
  method: "POST",
3435
3477
  body: { ...actionParams, requestContext },
@@ -5290,7 +5332,7 @@ var MastraClient = class extends BaseResource {
5290
5332
  * @returns Promise containing map of action IDs to action details
5291
5333
  */
5292
5334
  getAgentBuilderActions() {
5293
- return this.request("/agent-builder/");
5335
+ return this.request("/agent-builder");
5294
5336
  }
5295
5337
  /**
5296
5338
  * Gets an agent builder instance for executing agent-builder workflows