@mastra/client-js 1.32.1-alpha.2 → 1.33.0-alpha.11

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,144 @@
1
1
  # @mastra/client-js
2
2
 
3
+ ## 1.33.0-alpha.11
4
+
5
+ ### Minor Changes
6
+
7
+ - Added exact thread binding when creating AgentController sessions through the JavaScript client. ([#19902](https://github.com/mastra-ai/mastra/pull/19902))
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`c7d30cd`](https://github.com/mastra-ai/mastra/commit/c7d30cd86009c407df91105591f03cd6e3d2854d), [`ef03fbc`](https://github.com/mastra-ai/mastra/commit/ef03fbcc556bcbc04c9b3d06fab88771ecaa043c), [`a7bbe77`](https://github.com/mastra-ai/mastra/commit/a7bbe773577f60bc4761b534ef7ec6b476332dad), [`a7bbe77`](https://github.com/mastra-ai/mastra/commit/a7bbe773577f60bc4761b534ef7ec6b476332dad), [`4e68363`](https://github.com/mastra-ai/mastra/commit/4e683634f94ebd062d26a3bb6093a8dfc7263d37), [`9251370`](https://github.com/mastra-ai/mastra/commit/9251370ad413af464aa22d7566338bec5613e8de)]:
12
+ - @mastra/core@1.52.0-alpha.11
13
+
14
+ ## 1.33.0-alpha.10
15
+
16
+ ### Minor Changes
17
+
18
+ - Added request-scoped model overrides to agent execution and approvals, and fixed Studio model selection so each tab can use a different model without changing the agent's configured default. ([#19749](https://github.com/mastra-ai/mastra/pull/19749))
19
+
20
+ ```ts
21
+ await agent.stream(messages, { model: 'google/gemini-2.5-flash' });
22
+ ```
23
+
24
+ ### Patch Changes
25
+
26
+ - Updated dependencies [[`41a5392`](https://github.com/mastra-ai/mastra/commit/41a5392d9f6c5e18d6b227f0fc0ddf49c50774e9), [`675fbff`](https://github.com/mastra-ai/mastra/commit/675fbff84d3274391b33e852f76083c38a5514e5), [`da009e1`](https://github.com/mastra-ai/mastra/commit/da009e1aacd89ed94b8d1b2af09c9d4fe7c4db49), [`35c2181`](https://github.com/mastra-ai/mastra/commit/35c2181e6a50e47c90ba36260db7c9723d54696f), [`b4b7ea8`](https://github.com/mastra-ai/mastra/commit/b4b7ea8733f033fc441ea47ed03f6afb17ec2248), [`675fbff`](https://github.com/mastra-ai/mastra/commit/675fbff84d3274391b33e852f76083c38a5514e5), [`c328769`](https://github.com/mastra-ai/mastra/commit/c3287698ff8ef98dba86d415faa566fa3e5f4d56), [`232fcbc`](https://github.com/mastra-ai/mastra/commit/232fcbc14fce625dd672ba043329c0b732c62be2), [`3491666`](https://github.com/mastra-ai/mastra/commit/34916663c4fdd43b48c21f4ab2d5fb6dcccc94f9)]:
27
+ - @mastra/core@1.52.0-alpha.10
28
+
29
+ ## 1.33.0-alpha.9
30
+
31
+ ### Patch Changes
32
+
33
+ - Updated dependencies [[`0a2c22c`](https://github.com/mastra-ai/mastra/commit/0a2c22c902604439ec490319e14c17f331e0c84c), [`3a8024c`](https://github.com/mastra-ai/mastra/commit/3a8024ce615f8aa89479c0d71fe61d10bb0040be)]:
34
+ - @mastra/core@1.52.0-alpha.9
35
+
36
+ ## 1.33.0-alpha.8
37
+
38
+ ### Patch Changes
39
+
40
+ - Updated dependencies [[`3b77e77`](https://github.com/mastra-ai/mastra/commit/3b77e7704936522e4769d29de1b5ea6901f302bd), [`6b1bf3b`](https://github.com/mastra-ai/mastra/commit/6b1bf3b9494bd51aa8f654c68c9355d6046fa2a1), [`72e437c`](https://github.com/mastra-ai/mastra/commit/72e437c515942c80b9def5b026e0bdee61b469d9)]:
41
+ - @mastra/core@1.52.0-alpha.8
42
+
43
+ ## 1.33.0-alpha.7
44
+
45
+ ### Patch Changes
46
+
47
+ - Updated dependencies [[`b7e79c3`](https://github.com/mastra-ai/mastra/commit/b7e79c3c02ac5cd415db34ba0975ceafc1464333), [`b75d749`](https://github.com/mastra-ai/mastra/commit/b75d749621ff5d17e86bcb4ee809d301fb4f7cf3), [`a8799bb`](https://github.com/mastra-ai/mastra/commit/a8799bb8e44f4a60d01e4e2acd3448ff80bf14f8)]:
48
+ - @mastra/core@1.52.0-alpha.7
49
+
50
+ ## 1.33.0-alpha.6
51
+
52
+ ### Patch Changes
53
+
54
+ - Updated dependencies [[`a40adeb`](https://github.com/mastra-ai/mastra/commit/a40adeb222b961a56a58af56a106106525721b74), [`821648b`](https://github.com/mastra-ai/mastra/commit/821648bf2871ef840100c7bacbecf676010bd12a), [`11f6cd9`](https://github.com/mastra-ai/mastra/commit/11f6cd96fe42582403416608beb212cc1a2cc79e)]:
55
+ - @mastra/core@1.52.0-alpha.6
56
+
57
+ ## 1.33.0-alpha.5
58
+
59
+ ### Patch Changes
60
+
61
+ - Replace `any` with `unknown` in generated route types so clients get real type errors instead of silently unchecked values. Route-types generation now deduplicates shared schemas into reusable type aliases, shrinking the generated `route-types.generated.ts` from ~94K to ~22K lines (77% smaller). The memory config response now types `workingMemory` (enabled, scope, template, schema, version) instead of `unknown`. ([#19573](https://github.com/mastra-ai/mastra/pull/19573))
62
+
63
+ If your code read fields from responses that were previously typed `any`, TypeScript now requires you to narrow them before use:
64
+
65
+ ```ts
66
+ // Before: `metadata` was `any`, so this compiled even when unsafe
67
+ const value = response.metadata.someField;
68
+
69
+ // After: `metadata` is `unknown` — narrow it first
70
+ const metadata = response.metadata;
71
+ if (metadata && typeof metadata === 'object' && 'someField' in metadata) {
72
+ const value = metadata.someField;
73
+ }
74
+ // ...or cast if you know the shape: (metadata as MyMetadata).someField
75
+ ```
76
+
77
+ Code that reads `workingMemory` from the memory config response no longer needs casts — `config.workingMemory?.enabled`, `scope`, `template`, `schema`, and `version` are now typed directly.
78
+
79
+ - Updated dependencies [[`ec857fc`](https://github.com/mastra-ai/mastra/commit/ec857fc79c264b53b38e16478c789b7177f2ad59), [`e1f2fae`](https://github.com/mastra-ai/mastra/commit/e1f2faebaf048c3d4c2e2c01d293767c195d5794), [`63aa799`](https://github.com/mastra-ai/mastra/commit/63aa799c6b44eacc7806cda6846b7c5bbee06b37), [`73db8db`](https://github.com/mastra-ai/mastra/commit/73db8db90d69ab6153c7942749f624db0d96952d), [`73db8db`](https://github.com/mastra-ai/mastra/commit/73db8db90d69ab6153c7942749f624db0d96952d), [`76b7181`](https://github.com/mastra-ai/mastra/commit/76b71810366e6d90b9d3973149d1c7ba3659ffb9), [`0c0e8d7`](https://github.com/mastra-ai/mastra/commit/0c0e8d7becd4d1445c656b78d5d845f606c1ff9d), [`9f7c67a`](https://github.com/mastra-ai/mastra/commit/9f7c67abeeb52c41c51a9b5edee60b62afe7cd8d), [`3b65e68`](https://github.com/mastra-ai/mastra/commit/3b65e68d7f1c771c7a70eea42d83fefdd28cad88), [`e3868e2`](https://github.com/mastra-ai/mastra/commit/e3868e22babfffd0133771669ca724501c2dd58e)]:
80
+ - @mastra/core@1.52.0-alpha.5
81
+
82
+ ## 1.33.0-alpha.4
83
+
84
+ ### Patch Changes
85
+
86
+ - Updated dependencies [[`4cfdd64`](https://github.com/mastra-ai/mastra/commit/4cfdd645794feaea0c4ea711e70ecdfbef0c5b8e)]:
87
+ - @mastra/core@1.52.0-alpha.4
88
+
89
+ ## 1.33.0-alpha.3
90
+
91
+ ### Minor Changes
92
+
93
+ - Added a `requestContext` option to agent controller session methods in @mastra/client-js. You can now pass custom request context to `sendMessage`, `steer`, `followUp`, `approveTool`, and `respondToToolSuspension`, matching what `agent.generate()` already supports. The context is merged into the run's request context on the server, so it reaches dynamic instructions and tools. ([#19531](https://github.com/mastra-ai/mastra/pull/19531))
94
+
95
+ ```ts
96
+ const session = client.getAgentController('code').session('user-1');
97
+ await session.sendMessage('hello', { requestContext: { userId: 'user-1', tier: 'pro' } });
98
+ ```
99
+
100
+ - Added reconnect support to `AgentControllerSession.subscribe()` so SSE subscriptions recover after proxy timeouts or transport errors. Fixes #19202. ([#19560](https://github.com/mastra-ai/mastra/pull/19560))
101
+
102
+ ```ts
103
+ await session.subscribe({
104
+ onEvent: event => {
105
+ /* handle event */
106
+ },
107
+ reconnect: true,
108
+ });
109
+ ```
110
+
111
+ ### Patch Changes
112
+
113
+ - Fixed AgentController live events and thread history returning serialized message timestamps instead of Date values. ([#18783](https://github.com/mastra-ai/mastra/pull/18783))
114
+
115
+ - Fixed AgentControllerSession.subscribe() so it resolves only after the stream is established and rejects when it cannot connect (leaving no background retry loop). Reconnect now applies only after an established stream drops, backs off exponentially, and fires a new onReconnect callback on each re-established stream so consumers can re-sync missed events: ([#19580](https://github.com/mastra-ai/mastra/pull/19580))
116
+
117
+ ```ts
118
+ const subscription = await session.subscribe({
119
+ onEvent: event => applyEvent(event),
120
+ onError: error => showDisconnected(error),
121
+ reconnect: { maxRetries: 5, delayMs: 1000, maxDelayMs: 30_000 },
122
+ onReconnect: async () => {
123
+ // Events emitted while disconnected are not replayed — re-sync state.
124
+ applyState(await session.state());
125
+ },
126
+ });
127
+ ```
128
+
129
+ - Added stable metrics and logs capability reporting for observability storage. The system packages response now includes `observabilityStorageCapabilities` with `metrics` and `logs` flags, enabling capability-based detection that is resilient to bundler-generated constructor name changes. ([#19305](https://github.com/mastra-ai/mastra/pull/19305))
130
+
131
+ ```typescript
132
+ const packages = await client.getSystemPackages();
133
+ console.log(packages.observabilityStorageCapabilities?.metrics); // true
134
+ console.log(packages.observabilityStorageCapabilities?.logs); // true
135
+ ```
136
+
137
+ Studio now uses the capability response instead of relying on constructor names, with a fallback for older servers.
138
+
139
+ - Updated dependencies [[`1426af2`](https://github.com/mastra-ai/mastra/commit/1426af24975879c000d13ac75673f630fcc970c1), [`975295d`](https://github.com/mastra-ai/mastra/commit/975295d418552f0d46a59edfef4c3ee555f9930a), [`85e4fb5`](https://github.com/mastra-ai/mastra/commit/85e4fb50087a81c74df3a762f53b56373db0b912), [`ef03c0c`](https://github.com/mastra-ai/mastra/commit/ef03c0cfc62367a458e4cc56462e2148b35681c5), [`4fb4d88`](https://github.com/mastra-ai/mastra/commit/4fb4d881bc107acee13890ad4d78661016c510ed), [`4eba27a`](https://github.com/mastra-ai/mastra/commit/4eba27adcf60f991df0e62f94b3e75b4e67f3b4b), [`c701be3`](https://github.com/mastra-ai/mastra/commit/c701be32d7d9aa94a66da8c6cc38dcac6856f464)]:
140
+ - @mastra/core@1.52.0-alpha.3
141
+
3
142
  ## 1.32.1-alpha.2
4
143
 
5
144
  ### Patch Changes
@@ -2355,9 +2494,7 @@
2355
2494
  await client.storedAgents.unfavorite(agent.id);
2356
2495
 
2357
2496
  // Versioning + publish
2358
- const draft = await client.storedSkills.create({
2359
- /* ... */
2360
- });
2497
+ const draft = await client.storedSkills.create({/* ... */});
2361
2498
  const published = await client.storedSkills.publish(draft.id);
2362
2499
  await client.storedSkills.restore(draft.id, { version: 1 });
2363
2500
  ```
@@ -2529,9 +2666,7 @@
2529
2666
  await client.storedAgents.unfavorite(agent.id);
2530
2667
 
2531
2668
  // Versioning + publish
2532
- const draft = await client.storedSkills.create({
2533
- /* ... */
2534
- });
2669
+ const draft = await client.storedSkills.create({/* ... */});
2535
2670
  const published = await client.storedSkills.publish(draft.id);
2536
2671
  await client.storedSkills.restore(draft.id, { version: 1 });
2537
2672
  ```
@@ -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.32.1-alpha.2"
6
+ version: "1.33.0-alpha.11"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.32.1-alpha.2",
2
+ "version": "1.33.0-alpha.11",
3
3
  "package": "@mastra/client-js",
4
4
  "exports": {
5
5
  "RequestContext": {
@@ -57,9 +57,7 @@ import { Mastra } from '@mastra/core'
57
57
  import { MastraEditor } from '@mastra/editor'
58
58
 
59
59
  export const mastra = new Mastra({
60
- agents: {
61
- /* your existing agents */
62
- },
60
+ agents: {/* your existing agents */},
63
61
  editor: new MastraEditor(),
64
62
  })
65
63
  ```
@@ -84,9 +82,7 @@ import { Mastra } from '@mastra/core'
84
82
  import { MastraEditor } from '@mastra/editor'
85
83
 
86
84
  export const mastra = new Mastra({
87
- agents: {
88
- /* your existing agents */
89
- },
85
+ agents: {/* your existing agents */},
90
86
  editor: new MastraEditor({
91
87
  source: 'code',
92
88
  }),
package/dist/index.cjs CHANGED
@@ -6144,6 +6144,19 @@ var Channels = class extends BaseResource {
6144
6144
  };
6145
6145
 
6146
6146
  // src/resources/agent-controller.ts
6147
+ function hydrateMessage(message) {
6148
+ return {
6149
+ ...message,
6150
+ createdAt: message.createdAt instanceof Date ? message.createdAt : new Date(message.createdAt)
6151
+ };
6152
+ }
6153
+ function hydrateEventMessage(event) {
6154
+ if (event.type !== "message_start" && event.type !== "message_update" && event.type !== "message_end") return event;
6155
+ return {
6156
+ ...event,
6157
+ message: hydrateMessage(event.message)
6158
+ };
6159
+ }
6147
6160
  var AgentControllerSession = class extends BaseResource {
6148
6161
  constructor(options, controllerId, resourceId, scope) {
6149
6162
  super(options);
@@ -6166,59 +6179,175 @@ var AgentControllerSession = class extends BaseResource {
6166
6179
  /**
6167
6180
  * Create or resume this session. Pass `tags` to scope initial thread
6168
6181
  * selection — a thread is a resume candidate only when its metadata matches
6169
- * every tag. Required when sessions share a resourceId (e.g. git worktrees
6170
- * using a `{ projectPath }` tag) so each resumes its own thread instead of the
6171
- * most recent thread across the whole resource.
6182
+ * every tag. Pass `threadId` to bind the session to one exact thread,
6183
+ * creating it with that id when it does not exist.
6172
6184
  */
6173
6185
  create(options) {
6174
6186
  return this.request(`/agent-controller/${encodeURIComponent(this.controllerId)}/sessions`, {
6175
6187
  method: "POST",
6176
- body: { resourceId: this.resourceId, tags: options?.tags, sessionScope: this.scope }
6188
+ body: {
6189
+ resourceId: this.resourceId,
6190
+ tags: options?.tags,
6191
+ threadId: options?.threadId,
6192
+ sessionScope: this.scope
6193
+ }
6177
6194
  });
6178
6195
  }
6179
6196
  /**
6180
6197
  * Subscribe to this session's event stream (SSE). The assistant's reply to a
6181
6198
  * message arrives here as `message_*` events, not on the sendMessage call.
6199
+ *
6200
+ * The returned promise resolves once the stream is actually established and
6201
+ * rejects when it cannot be. A rejected subscribe leaves nothing running —
6202
+ * `reconnect` governs only re-establishment after an established stream
6203
+ * drops, so callers that want connect-time retry can loop around
6204
+ * `subscribe()` themselves and keep cancellation control.
6182
6205
  */
6183
6206
  async subscribe(options) {
6184
- const response = await this.request(this.url(`${this.base()}/stream`), { stream: true });
6185
- if (!response.body) {
6186
- throw new Error("No response body for agent controller session stream");
6187
- }
6188
- const reader = response.body.getReader();
6189
- const decoder = new TextDecoder();
6207
+ const finiteOr = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
6208
+ const retriesOr = (value, fallback) => value === Infinity || typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
6209
+ const reconnectOptions = options.reconnect === true ? { maxRetries: Infinity, delayMs: 1e3, maxDelayMs: 3e4 } : options.reconnect ? {
6210
+ maxRetries: retriesOr(options.reconnect.maxRetries, Infinity),
6211
+ delayMs: finiteOr(options.reconnect.delayMs, 1e3),
6212
+ maxDelayMs: finiteOr(options.reconnect.maxDelayMs, 3e4)
6213
+ } : null;
6214
+ const backoffDelay = (attempt) => reconnectOptions ? Math.min(reconnectOptions.delayMs * 2 ** (attempt - 1), reconnectOptions.maxDelayMs) : 0;
6190
6215
  let cancelled = false;
6191
- let buffer = "";
6192
- const pump = async () => {
6216
+ let currentReader = null;
6217
+ let reconnectTimer;
6218
+ let delayResolve;
6219
+ const settleDelay = () => {
6220
+ if (reconnectTimer) {
6221
+ clearTimeout(reconnectTimer);
6222
+ reconnectTimer = void 0;
6223
+ }
6224
+ const resolve = delayResolve;
6225
+ delayResolve = void 0;
6226
+ resolve?.();
6227
+ };
6228
+ const delay = (ms) => new Promise((resolve) => {
6229
+ delayResolve = resolve;
6230
+ reconnectTimer = setTimeout(settleDelay, ms);
6231
+ });
6232
+ const requestStream = async () => {
6233
+ const response = await this.request(this.url(`${this.base()}/stream`), { stream: true });
6234
+ if (!response.body) {
6235
+ throw new Error("No response body for agent controller session stream");
6236
+ }
6237
+ return response;
6238
+ };
6239
+ const streamEndedError = () => new Error("Agent controller session stream ended unexpectedly");
6240
+ const findFrameSeparator = (text) => {
6241
+ const candidates = [
6242
+ { index: text.indexOf("\r\n\r\n"), length: 4 },
6243
+ { index: text.indexOf("\n\n"), length: 2 },
6244
+ { index: text.indexOf("\r\r"), length: 2 }
6245
+ ].filter((candidate) => candidate.index !== -1);
6246
+ if (candidates.length === 0) return null;
6247
+ return candidates.reduce((earliest, candidate) => candidate.index < earliest.index ? candidate : earliest);
6248
+ };
6249
+ const pump = async (response) => {
6250
+ const reader = response.body.getReader();
6251
+ currentReader = reader;
6252
+ const decoder = new TextDecoder();
6253
+ let buffer = "";
6193
6254
  try {
6194
6255
  while (!cancelled) {
6195
6256
  const { done, value } = await reader.read();
6196
- if (done) break;
6257
+ if (done) return cancelled ? { kind: "cancelled" } : { kind: "done" };
6197
6258
  buffer += decoder.decode(value, { stream: true });
6198
- let sep;
6199
- while ((sep = buffer.indexOf("\n\n")) !== -1) {
6200
- const frame = buffer.slice(0, sep);
6201
- buffer = buffer.slice(sep + 2);
6202
- for (const line of frame.split("\n")) {
6259
+ let separator;
6260
+ while ((separator = findFrameSeparator(buffer)) !== null) {
6261
+ const frame = buffer.slice(0, separator.index);
6262
+ buffer = buffer.slice(separator.index + separator.length);
6263
+ for (const line of frame.split(/\r\n|\n|\r/)) {
6203
6264
  if (!line.startsWith("data:")) continue;
6204
6265
  const data = line.slice(5).trim();
6205
6266
  if (!data) continue;
6267
+ let event;
6206
6268
  try {
6207
- options.onEvent(JSON.parse(data));
6269
+ event = hydrateEventMessage(JSON.parse(data));
6208
6270
  } catch {
6271
+ continue;
6272
+ }
6273
+ try {
6274
+ options.onEvent(event);
6275
+ } catch (cause) {
6276
+ if (!cancelled) safeOnError(cause);
6277
+ return { kind: "consumer_error" };
6209
6278
  }
6210
6279
  }
6211
6280
  }
6212
6281
  }
6282
+ return { kind: "cancelled" };
6283
+ } catch (error) {
6284
+ return cancelled ? { kind: "cancelled" } : { kind: "transport_error", error };
6285
+ } finally {
6286
+ if (currentReader === reader) currentReader = null;
6287
+ void reader.cancel().catch(() => {
6288
+ });
6289
+ }
6290
+ };
6291
+ const safeOnError = (error) => {
6292
+ try {
6293
+ options.onError?.(error);
6294
+ } catch {
6295
+ }
6296
+ };
6297
+ const reportTerminalError = (result) => {
6298
+ safeOnError(result.kind === "transport_error" ? result.error : streamEndedError());
6299
+ };
6300
+ const pumpSafe = async (response) => {
6301
+ try {
6302
+ return await pump(response);
6213
6303
  } catch (error) {
6214
- if (!cancelled) options.onError?.(error);
6304
+ return cancelled ? { kind: "cancelled" } : { kind: "transport_error", error };
6215
6305
  }
6216
6306
  };
6217
- void pump();
6307
+ const firstResponse = await requestStream();
6308
+ const run = async (initial) => {
6309
+ let response = initial;
6310
+ while (!cancelled) {
6311
+ let result = await pumpSafe(response);
6312
+ if (cancelled || result.kind === "cancelled" || result.kind === "consumer_error") return;
6313
+ if (!reconnectOptions) {
6314
+ reportTerminalError(result);
6315
+ return;
6316
+ }
6317
+ let attempts = 0;
6318
+ let reconnectedResponse;
6319
+ while (!reconnectedResponse) {
6320
+ if (attempts >= reconnectOptions.maxRetries) {
6321
+ reportTerminalError(result);
6322
+ return;
6323
+ }
6324
+ attempts++;
6325
+ await delay(backoffDelay(attempts));
6326
+ if (cancelled) return;
6327
+ try {
6328
+ reconnectedResponse = await requestStream();
6329
+ } catch (error) {
6330
+ result = { kind: "transport_error", error };
6331
+ }
6332
+ }
6333
+ if (cancelled) {
6334
+ void reconnectedResponse.body?.cancel().catch(() => {
6335
+ });
6336
+ return;
6337
+ }
6338
+ response = reconnectedResponse;
6339
+ try {
6340
+ options.onReconnect?.();
6341
+ } catch {
6342
+ }
6343
+ }
6344
+ };
6345
+ void run(firstResponse);
6218
6346
  return {
6219
6347
  unsubscribe: () => {
6220
6348
  cancelled = true;
6221
- void reader.cancel().catch(() => {
6349
+ settleDelay();
6350
+ void currentReader?.cancel().catch(() => {
6222
6351
  });
6223
6352
  }
6224
6353
  };
@@ -6227,12 +6356,18 @@ var AgentControllerSession = class extends BaseResource {
6227
6356
  * Send a user message. The reply streams over `subscribe()`.
6228
6357
  * Pass a structured message to attach files (e.g. pasted images) as base64-encoded data:
6229
6358
  * `sendMessage({ content: 'What is in this image?', files })`.
6359
+ * Pass `options.requestContext` to merge custom context into the run's request context.
6230
6360
  */
6231
- async sendMessage(message) {
6361
+ async sendMessage(message, options) {
6232
6362
  const { content, files } = typeof message === "string" ? { content: message, files: void 0 } : message;
6363
+ const requestContext = parseClientRequestContext(options?.requestContext);
6233
6364
  await this.request(this.url(`${this.base()}/messages`), {
6234
6365
  method: "POST",
6235
- body: { message: content, ...files?.length ? { files } : {} }
6366
+ body: {
6367
+ message: content,
6368
+ ...files?.length ? { files } : {},
6369
+ ...requestContext ? { requestContext } : {}
6370
+ }
6236
6371
  });
6237
6372
  }
6238
6373
  /** Abort the in-flight run for this session. */
@@ -6240,10 +6375,11 @@ var AgentControllerSession = class extends BaseResource {
6240
6375
  await this.request(this.url(`${this.base()}/abort`), { method: "POST" });
6241
6376
  }
6242
6377
  /** Approve or decline a pending tool call (`tool_approval_required`). */
6243
- async approveTool(toolCallId, approved) {
6378
+ async approveTool(toolCallId, approved, options) {
6379
+ const requestContext = parseClientRequestContext(options?.requestContext);
6244
6380
  await this.request(this.url(`${this.base()}/tool-approval`), {
6245
6381
  method: "POST",
6246
- body: { toolCallId, approved }
6382
+ body: { toolCallId, approved, ...requestContext ? { requestContext } : {} }
6247
6383
  });
6248
6384
  }
6249
6385
  /**
@@ -6251,15 +6387,20 @@ var AgentControllerSession = class extends BaseResource {
6251
6387
  * depends on the tool: a string (or string[]) for `ask_user`, "Yes"/"No" for
6252
6388
  * `request_access`, and a {@link PlanResume} for `submit_plan`.
6253
6389
  */
6254
- async respondToToolSuspension(toolCallId, resumeData) {
6390
+ async respondToToolSuspension(toolCallId, resumeData, options) {
6391
+ const requestContext = parseClientRequestContext(options?.requestContext);
6255
6392
  await this.request(this.url(`${this.base()}/tool-suspension`), {
6256
6393
  method: "POST",
6257
- body: { toolCallId, resumeData }
6394
+ body: { toolCallId, resumeData, ...requestContext ? { requestContext } : {} }
6258
6395
  });
6259
6396
  }
6260
6397
  /** Inject a message into the in-flight run without starting a new turn. */
6261
- async steer(message) {
6262
- await this.request(this.url(`${this.base()}/steer`), { method: "POST", body: { message } });
6398
+ async steer(message, options) {
6399
+ const requestContext = parseClientRequestContext(options?.requestContext);
6400
+ await this.request(this.url(`${this.base()}/steer`), {
6401
+ method: "POST",
6402
+ body: { message, ...requestContext ? { requestContext } : {} }
6403
+ });
6263
6404
  }
6264
6405
  /** Get the current mode, model, and thread (for initial UI hydration). */
6265
6406
  state() {
@@ -6335,14 +6476,18 @@ var AgentControllerSession = class extends BaseResource {
6335
6476
  const body = await this.request(
6336
6477
  this.url(`${this.base()}/threads/${encodeURIComponent(threadId)}/messages${params}`)
6337
6478
  );
6338
- return body.messages;
6479
+ return body.messages.map(hydrateMessage);
6339
6480
  }
6340
6481
  /**
6341
6482
  * Queue a follow-up message. If the session is idle it sends immediately;
6342
6483
  * if a run is active it queues for after completion.
6343
6484
  */
6344
- async followUp(message) {
6345
- await this.request(this.url(`${this.base()}/follow-up`), { method: "POST", body: { message } });
6485
+ async followUp(message, options) {
6486
+ const requestContext = parseClientRequestContext(options?.requestContext);
6487
+ await this.request(this.url(`${this.base()}/follow-up`), {
6488
+ method: "POST",
6489
+ body: { message, ...requestContext ? { requestContext } : {} }
6490
+ });
6346
6491
  }
6347
6492
  /** Get the observational memory record for this session's thread. */
6348
6493
  async getOMRecord() {
@@ -6452,7 +6597,7 @@ var AgentController = class extends BaseResource {
6452
6597
  }
6453
6598
  };
6454
6599
  function agentControllerMessageText(message) {
6455
- return message.content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("");
6600
+ return message.content.parts.filter((p) => p.type === "text" && typeof p.text === "string").map((p) => p.text).join("");
6456
6601
  }
6457
6602
 
6458
6603
  // src/client.ts