@myagentroam/node 0.9.149 → 0.9.151

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.
@@ -152,8 +152,6 @@ export class MarAgentHostedConversationRuntime {
152
152
  await input.onEvent?.(projected);
153
153
  }
154
154
  const result = await execution.result();
155
- if (result.status === 'cancelled')
156
- titleController.abort();
157
155
  const generatedTitle = await titleTask;
158
156
  if (generatedTitle && !titleController.signal.aborted)
159
157
  await agent
@@ -203,25 +201,31 @@ export class MarAgentHostedConversationRuntime {
203
201
  cancel: () => {
204
202
  if (settled || this.#active.get(input.sessionId)?.handle !== handle)
205
203
  return false;
206
- titleController.abort();
207
204
  execution.cancel();
208
205
  return true;
209
206
  }
210
207
  };
211
- this.#active.set(input.sessionId, { handle, completion });
208
+ this.#active.set(input.sessionId, {
209
+ handle,
210
+ completion,
211
+ cancelTitle: () => titleController.abort()
212
+ });
212
213
  return handle;
213
214
  }
214
215
  async releaseSession(input) {
215
216
  const active = this.#active.get(input.sessionId);
216
217
  if (active === undefined)
217
218
  return;
219
+ active.cancelTitle();
218
220
  active.handle.cancel();
219
221
  await active.completion.catch(() => undefined);
220
222
  }
221
223
  async dispose() {
222
224
  const active = [...this.#active.values()];
223
- for (const execution of active)
225
+ for (const execution of active) {
226
+ execution.cancelTitle();
224
227
  execution.handle.cancel();
228
+ }
225
229
  await Promise.allSettled(active.map((execution) => execution.completion));
226
230
  }
227
231
  async #readGeneratedTitle(homeDirectory, sessionId) {
@@ -52,11 +52,15 @@ export class MarAgentManagedRunController {
52
52
  return this.#disposePromise;
53
53
  this.#disposed = true;
54
54
  this.#disposePromise = (async () => {
55
- for (const execution of this.#executions.values())
55
+ for (const execution of this.#executions.values()) {
56
+ execution.cancelTitle();
56
57
  execution.cancel();
58
+ }
57
59
  await Promise.allSettled([...new Set(this.#runtimeAcquisitions.values())]);
58
- for (const execution of this.#executions.values())
60
+ for (const execution of this.#executions.values()) {
61
+ execution.cancelTitle();
59
62
  execution.cancel();
63
+ }
60
64
  await Promise.all([...new Set(this.#sessionRuntimes.values())].map((runtime) => this.#releaseRuntime(runtime)));
61
65
  await this.#mcpClients.close();
62
66
  await this.#computerUse?.dispose();
@@ -74,8 +78,11 @@ export class MarAgentManagedRunController {
74
78
  await this.#computerUse?.releaseSession(sessionId);
75
79
  return;
76
80
  }
77
- if (runtime.activeRunId !== undefined)
78
- this.#executions.get(runtime.activeRunId)?.cancel();
81
+ if (runtime.activeRunId !== undefined) {
82
+ const execution = this.#executions.get(runtime.activeRunId);
83
+ execution?.cancelTitle();
84
+ execution?.cancel();
85
+ }
79
86
  await this.#releaseRuntime(runtime);
80
87
  await Promise.all([
81
88
  this.#computerUse?.releaseSession(sessionId),
@@ -212,7 +219,7 @@ export class MarAgentManagedRunController {
212
219
  if (!execution)
213
220
  return false;
214
221
  execution.cancel();
215
- this.host.emit(runId, 'run.cancelling', { intent }, 'RUNNING');
222
+ this.host.emit(runId, 'run.cancelling', { intent });
216
223
  return true;
217
224
  }
218
225
  respondUserInput(runId, requestId, answers) {
@@ -229,6 +236,20 @@ export class MarAgentManagedRunController {
229
236
  return true;
230
237
  }
231
238
  async run(input) {
239
+ const controller = new AbortController();
240
+ const titleController = new AbortController();
241
+ let cancelExecution;
242
+ // Own cancellation before any asynchronous preparation, not only after SDK admission.
243
+ this.#executions.set(input.runId, {
244
+ cancel: () => {
245
+ if (controller.signal.aborted)
246
+ return;
247
+ controller.abort();
248
+ titleController.abort();
249
+ cancelExecution?.();
250
+ },
251
+ cancelTitle: () => titleController.abort()
252
+ });
232
253
  this.host.active.add(input.runId);
233
254
  this.host.adopt({
234
255
  runId: input.runId,
@@ -246,9 +267,10 @@ export class MarAgentManagedRunController {
246
267
  let executionMcpBinding;
247
268
  let computerUseBinding;
248
269
  let executionModels = [];
249
- const titleController = new AbortController();
250
270
  let titleTask;
271
+ let cancelledDuringPreparation = false;
251
272
  try {
273
+ controller.signal.throwIfAborted();
252
274
  const sessionKey = input.externalSessionId ?? input.sessionId;
253
275
  // Reserve both identities while opening so a concurrent release can await the same runtime.
254
276
  const acquisitionKeys = [...new Set([sessionKey, input.sessionId])];
@@ -266,6 +288,7 @@ export class MarAgentManagedRunController {
266
288
  if (this.#runtimeAcquisitions.get(key) === acquisition)
267
289
  this.#runtimeAcquisitions.delete(key);
268
290
  }
291
+ controller.signal.throwIfAborted();
269
292
  if (this.#disposed ||
270
293
  this.#sessionReleases.has(sessionKey) ||
271
294
  this.#sessionReleases.has(input.sessionId) ||
@@ -277,6 +300,7 @@ export class MarAgentManagedRunController {
277
300
  throw new Error('MAR_AGENT_SESSION_RUNTIME_ACTIVE');
278
301
  runtime.activeRunId = input.runId;
279
302
  await runtime.mcpLease.pool.refreshForExecution();
303
+ controller.signal.throwIfAborted();
280
304
  const executionMcpServers = input.mcpServers
281
305
  .filter(isExecutionScopedMcp)
282
306
  .map((server) => ({ ...server, lifecycle: 'EXECUTION' }));
@@ -287,6 +311,7 @@ export class MarAgentManagedRunController {
287
311
  enabled: input.computerUseEnabled === true,
288
312
  modelSupportsImages: input.model.inputCapabilities.includes('IMAGE')
289
313
  });
314
+ controller.signal.throwIfAborted();
290
315
  if (this.#disposed ||
291
316
  this.#sessionReleases.has(sessionKey) ||
292
317
  this.#sessionReleases.has(input.sessionId) ||
@@ -302,6 +327,7 @@ export class MarAgentManagedRunController {
302
327
  authorizationScope: runtime.session.id
303
328
  });
304
329
  }
330
+ controller.signal.throwIfAborted();
305
331
  const userTools = executionMcpLease?.pool.definitions() ?? [];
306
332
  const nodeTools = computerUseBinding?.tools ?? [];
307
333
  if (userTools.some((tool) => tool.name.startsWith('mcp__computer__')))
@@ -371,6 +397,7 @@ export class MarAgentManagedRunController {
371
397
  const metadata = input.mode === 'compact' || !runtime.automaticTitleEnabled
372
398
  ? undefined
373
399
  : await runtime.agent.getSession(session.id).catch(() => undefined);
400
+ controller.signal.throwIfAborted();
374
401
  const handle = input.mode === 'plan'
375
402
  ? session.plan({
376
403
  ...runInput
@@ -378,12 +405,7 @@ export class MarAgentManagedRunController {
378
405
  : input.mode === 'compact'
379
406
  ? session.compact(runInput)
380
407
  : session.run(runInput);
381
- this.#executions.set(input.runId, {
382
- cancel: () => {
383
- titleController.abort();
384
- handle.cancel();
385
- }
386
- });
408
+ cancelExecution = () => handle.cancel();
387
409
  this.host.emit(input.runId, 'run.running', {}, 'RUNNING');
388
410
  for await (const event of handle) {
389
411
  if (event.type === 'execution.started' && metadata?.automaticTitlePending && !titleTask) {
@@ -398,8 +420,6 @@ export class MarAgentManagedRunController {
398
420
  this.project(input.runId, event);
399
421
  }
400
422
  const result = await handle.result();
401
- if (result.status === 'cancelled')
402
- titleController.abort();
403
423
  const title = await titleTask;
404
424
  if (title && !titleController.signal.aborted)
405
425
  await runtime.agent
@@ -427,20 +447,26 @@ export class MarAgentManagedRunController {
427
447
  }, status);
428
448
  }
429
449
  catch (error) {
430
- if (runtime !== undefined)
431
- this.#prepareRuntimeForTerminal(input.runId, runtime);
432
- const projected = runnerErrorProjection(error, 'MAR_AGENT_RUN_FAILED');
433
- this.host.emitItem(input.runId, {
434
- itemId: boundedConversationItemId('mar-agent-error', input.runId),
435
- kind: 'error',
436
- status: 'FAILED',
437
- payload: {
438
- ...projected,
439
- recoverable: true,
440
- retryAfterMs: null
441
- }
442
- });
443
- this.host.emit(input.runId, 'run.failed', projected, 'FAILED');
450
+ if (controller.signal.aborted && cancelExecution === undefined) {
451
+ // Keep the Run owned until preparation and its resources actually settle.
452
+ cancelledDuringPreparation = true;
453
+ }
454
+ else {
455
+ if (runtime !== undefined)
456
+ this.#prepareRuntimeForTerminal(input.runId, runtime);
457
+ const projected = runnerErrorProjection(error, 'MAR_AGENT_RUN_FAILED');
458
+ this.host.emitItem(input.runId, {
459
+ itemId: boundedConversationItemId('mar-agent-error', input.runId),
460
+ kind: 'error',
461
+ status: 'FAILED',
462
+ payload: {
463
+ ...projected,
464
+ recoverable: true,
465
+ retryAfterMs: null
466
+ }
467
+ });
468
+ this.host.emit(input.runId, 'run.failed', projected, 'FAILED');
469
+ }
444
470
  }
445
471
  finally {
446
472
  titleController.abort();
@@ -449,14 +475,16 @@ export class MarAgentManagedRunController {
449
475
  delete runtime.automaticTitleTask;
450
476
  this.clearInteractions(input.runId);
451
477
  this.#normalizers.delete(input.runId);
452
- this.host.active.delete(input.runId);
453
- this.#executions.delete(input.runId);
454
478
  await closeImageCredentialProviders(executionModels);
455
479
  await computerUseBinding?.close().catch(() => undefined);
456
480
  runtime?.host.unbindExecutionMcp(executionMcpBinding);
457
481
  await executionMcpLease?.release().catch(() => undefined);
458
482
  if (runtime !== undefined)
459
483
  await this.#finishRuntimeExecution(input.runId, runtime).catch(() => undefined);
484
+ this.host.active.delete(input.runId);
485
+ this.#executions.delete(input.runId);
486
+ if (cancelledDuringPreparation)
487
+ this.host.emit(input.runId, 'run.cancelled', { status: 'CANCELLED' }, 'CANCELLED');
460
488
  }
461
489
  }
462
490
  #prepareRuntimeForTerminal(runId, runtime) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/node",
3
- "version": "0.9.149",
3
+ "version": "0.9.151",
4
4
  "description": "MyAgentRoam Node runtime CLI.",
5
5
  "license": "Apache-2.0 AND GPL-2.0-or-later",
6
6
  "type": "module",
@@ -34,10 +34,10 @@
34
34
  "npm": "11.12.1",
35
35
  "ws": "^8.21.3",
36
36
  "zod": "4.4.3",
37
+ "@myagentroam/marctl": "0.9.120",
38
+ "@myagentroam/protocol": "0.9.151",
37
39
  "@myagentroam/code-navigation": "0.9.129",
38
- "@myagentroam/agent": "0.9.149",
39
- "@myagentroam/protocol": "0.9.149",
40
- "@myagentroam/marctl": "0.9.120"
40
+ "@myagentroam/agent": "0.9.151"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/ws": "^8.18.1"