@myagentroam/node 0.11.38 → 0.11.40

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.
Files changed (65) hide show
  1. package/dist/computer-use/contracts.js +8 -0
  2. package/dist/{runner/mar-agent/computer-use-indicator.js → computer-use/indicator.js} +61 -38
  3. package/dist/computer-use/probe.js +95 -0
  4. package/dist/computer-use/provider.js +159 -0
  5. package/dist/computer-use/session.js +334 -0
  6. package/dist/computer-use/worker-source.js +135 -0
  7. package/dist/computer-use/worker.js +321 -0
  8. package/dist/connector.js +181 -22
  9. package/dist/database.js +35 -11
  10. package/dist/main.js +12 -1
  11. package/dist/marctl-guidance.js +18 -27
  12. package/dist/mcp/naming.js +6 -1
  13. package/dist/migrations/v022.js +58 -0
  14. package/dist/runner/abstract-runner.js +14 -0
  15. package/dist/runner/claude/tool-normalizer.js +6 -1
  16. package/dist/runner/codex/conversation-parser.js +23 -4
  17. package/dist/runner/codex/managed-run-controller.js +4 -2
  18. package/dist/runner/codex/tool-normalizer.js +9 -0
  19. package/dist/runner/execution-presentation.js +56 -0
  20. package/dist/runner/mar-agent/agent-network-extension.js +168 -0
  21. package/dist/runner/mar-agent/agent-network-wait-output.js +72 -0
  22. package/dist/runner/mar-agent/computer-use-skill.js +11 -2
  23. package/dist/runner/mar-agent/computer-use.js +104 -728
  24. package/dist/runner/mar-agent/conversation-normalizer.js +241 -121
  25. package/dist/runner/mar-agent/managed-run-controller.js +13 -5
  26. package/dist/runner/mar-agent/marctl-skill.js +3 -3
  27. package/dist/runner/mar-agent/runtime-model-factory.js +1 -0
  28. package/dist/runner/mar-agent/session-runtime.js +34 -1
  29. package/dist/runner/mar-agent-runner.js +36 -0
  30. package/dist/runner/opencode/tool-normalizer.js +6 -1
  31. package/dist/runtime-state.js +57 -0
  32. package/dist/service/agent-network-bindings.js +483 -0
  33. package/dist/service/agent-network-goal.js +19 -0
  34. package/dist/service/agent-network-invoke.js +179 -0
  35. package/dist/service/agent-network-observations.js +377 -0
  36. package/dist/service/agent-network-service.js +315 -0
  37. package/dist/service/agent-network-wait.js +130 -0
  38. package/dist/service/composer-message-input.js +9 -2
  39. package/dist/service/computer-use-enablement-service.js +13 -7
  40. package/dist/service/continuous-run-coordinator.js +24 -1
  41. package/dist/service/conversation-hosting-enablement-service.js +2 -2
  42. package/dist/service/goal-continuation-coordinator.js +12 -2
  43. package/dist/service/marctl-caller.js +80 -0
  44. package/dist/service/marctl-execution-credential-control.js +65 -0
  45. package/dist/service/model-usage-service.js +9 -0
  46. package/dist/service/node-config-mutations.js +27 -0
  47. package/dist/service/node-control-message-service.js +10 -0
  48. package/dist/service/node-request-service.js +52 -7
  49. package/dist/service/node-upgrade-coordinator.js +79 -8
  50. package/dist/service/node-upgrade-credential-control.js +57 -0
  51. package/dist/service/node-upgrade-reporter.js +108 -0
  52. package/dist/service/run-event-service.js +8 -0
  53. package/dist/service/run-workbench-service.js +11 -0
  54. package/dist/service/supervised-node-child.js +153 -0
  55. package/dist/service/supervisor-upgrade-handoff.js +104 -0
  56. package/dist/session/native-session-projection-service.js +69 -6
  57. package/dist/session/operation-admission.js +7 -0
  58. package/dist/session/runtime/conversation-projection.js +25 -3
  59. package/dist/session/session-catalog-service.js +156 -32
  60. package/dist/session/session-lifecycle-service.js +68 -42
  61. package/dist/session/session-message-service.js +16 -6
  62. package/dist/supervisor.js +209 -20
  63. package/dist/terminal.js +41 -21
  64. package/package.json +6 -5
  65. /package/dist/{runner/mar-agent/computer-use-probe.js → computer-use/probe-source.js} +0 -0
@@ -7,6 +7,7 @@ export function normalizeMarAgentUsage(usage) {
7
7
  import { boundedConversationItemId, compactRunnerText, compactRunnerValue } from '../normalization.js';
8
8
  import { runnerErrorProjection } from '../runner-error.js';
9
9
  import { toolPresentationSchema } from '@myagentroam/protocol';
10
+ import { boundExecutionPresentation, publicOutputSnapshot } from '../execution-presentation.js';
10
11
  export class MarAgentConversationNormalizer {
11
12
  input(entry) {
12
13
  return {
@@ -25,12 +26,10 @@ export class MarAgentConversationNormalizer {
25
26
  }
26
27
  #tools = new Map();
27
28
  #commands = new Map();
28
- #processOrigins = new Map();
29
29
  #subagentTitles = new Map();
30
30
  #subagentDetails = new Map();
31
31
  #codeModeObservationIds = new Set();
32
32
  #codeModeSourceCallIds = new Set();
33
- #toolOutputSnapshots = new Map();
34
33
  #codeModeOutputCalls = new Map();
35
34
  #codeModeOutputSnapshots = new Map();
36
35
  #runningCodeModeCells = new Map();
@@ -69,7 +68,8 @@ export class MarAgentConversationNormalizer {
69
68
  const payload = {
70
69
  text: event.type === 'message.completed' ? event.text : '',
71
70
  format: 'markdown',
72
- model: typeof modelName === 'string' ? modelName : null
71
+ model: typeof modelName === 'string' ? modelName : null,
72
+ phase: event.phase
73
73
  };
74
74
  return [
75
75
  {
@@ -168,7 +168,6 @@ export class MarAgentConversationNormalizer {
168
168
  #toolStarted(event) {
169
169
  const ownItemId = itemId('tool', event.callId);
170
170
  this.#clearRetainedCodeModeCellsForOtherExecutions(event.executionId);
171
- this.#toolOutputSnapshots.delete(event.callId);
172
171
  this.#codeModeOutputCalls.delete(event.callId);
173
172
  this.#clearCodeModeOutputSnapshots(event.callId);
174
173
  if (event.toolName === 'exec' || event.toolName === 'exec_wait') {
@@ -182,13 +181,17 @@ export class MarAgentConversationNormalizer {
182
181
  if (action === 'start' && typeof input.command === 'string') {
183
182
  const command = {
184
183
  itemId: ownItemId,
185
- turnKey: event.turnId ?? event.executionId,
186
184
  command: compactRunnerText(input.command, 10_000),
187
185
  cwd: typeof input.cwd === 'string' ? compactRunnerText(input.cwd, 4_096) : null,
188
186
  status: 'IN_PROGRESS',
189
187
  outputPreview: '',
190
188
  exitCode: null,
191
- truncated: false
189
+ truncated: event.truncated === true ||
190
+ input.command.length > 10_000 ||
191
+ (typeof input.cwd === 'string' && input.cwd.length > 4096),
192
+ inputTruncated: event.truncated === true ||
193
+ input.command.length > 10_000 ||
194
+ (typeof input.cwd === 'string' && input.cwd.length > 4096)
192
195
  };
193
196
  this.#commands.set(event.callId, command);
194
197
  this.#tools.set(event.callId, {
@@ -203,49 +206,6 @@ export class MarAgentConversationNormalizer {
203
206
  });
204
207
  return [commandItem(command, 'IN_PROGRESS')];
205
208
  }
206
- if ((action === 'poll' || action === 'write' || action === 'cancel') &&
207
- typeof input.processId === 'string') {
208
- const origin = this.#processOrigins.get(input.processId);
209
- if (origin !== undefined) {
210
- const previous = this.#commands.get(origin);
211
- const sameTurn = previous?.turnKey === (event.turnId ?? event.executionId);
212
- if (previous !== undefined && !sameTurn) {
213
- const command = {
214
- itemId: ownItemId,
215
- turnKey: event.turnId ?? event.executionId,
216
- command: previous.command,
217
- cwd: previous.cwd,
218
- status: 'IN_PROGRESS',
219
- outputPreview: '',
220
- exitCode: null,
221
- truncated: false
222
- };
223
- this.#commands.set(event.callId, command);
224
- this.#tools.set(event.callId, {
225
- toolName: event.toolName,
226
- input: event.input,
227
- itemId: ownItemId,
228
- structured: true,
229
- executionId: event.executionId,
230
- ...(event.turnId === undefined ? {} : { turnId: event.turnId }),
231
- active: true,
232
- commandOrigin: event.callId
233
- });
234
- return [];
235
- }
236
- this.#tools.set(event.callId, {
237
- toolName: event.toolName,
238
- input: event.input,
239
- itemId: ownItemId,
240
- structured: true,
241
- executionId: event.executionId,
242
- ...(event.turnId === undefined ? {} : { turnId: event.turnId }),
243
- active: true,
244
- commandOrigin: origin
245
- });
246
- return [];
247
- }
248
- }
249
209
  }
250
210
  const agentId = isMarAgentControlTool(event.toolName)
251
211
  ? marAgentAgentId(event.input)
@@ -275,9 +235,20 @@ export class MarAgentConversationNormalizer {
275
235
  #toolOutput(event) {
276
236
  const { callId, toolName, executionId, turnId, parentCallId, output } = event;
277
237
  const inputOutput = [output.stdout, output.stderr].filter(Boolean).join('\n');
238
+ const displayOutput = execDisplayOutput(output.displayOutput) ?? {
239
+ stdout: output.stdout,
240
+ stderr: output.stderr,
241
+ stdoutDroppedBytes: 0,
242
+ stderrDroppedBytes: 0
243
+ };
244
+ const displayed = [displayOutput.stdout, displayOutput.stderr].filter(Boolean).join('\n');
245
+ const bounded = publicOutputSnapshot(displayed, output.truncated ||
246
+ displayOutput.stdoutDroppedBytes > 0 ||
247
+ displayOutput.stderrDroppedBytes > 0);
278
248
  const snapshot = {
279
- outputPreview: compactRunnerText(inputOutput, 10_000),
280
- truncated: output.truncated || inputOutput.length > 10_000
249
+ outputPreview: bounded.text,
250
+ truncated: bounded.truncated || inputOutput.length > 10_000,
251
+ displayOutput
281
252
  };
282
253
  if (parentCallId !== undefined)
283
254
  return this.#codeModeToolOutput(callId, parentCallId, toolName, executionId, turnId, output.processId, snapshot);
@@ -286,22 +257,27 @@ export class MarAgentConversationNormalizer {
286
257
  !state.active ||
287
258
  state.toolName !== toolName ||
288
259
  state.executionId !== executionId ||
289
- (state.turnId !== undefined && turnId !== undefined && state.turnId !== turnId) ||
290
- state.commandOrigin === undefined)
260
+ (state.turnId !== undefined && turnId !== undefined && state.turnId !== turnId))
291
261
  return [];
292
262
  const input = record(state.input);
293
263
  if (typeof input?.processId === 'string' && input.processId !== output.processId)
294
264
  return [];
265
+ if (state.commandOrigin === undefined) {
266
+ if (toolName !== 'exec_wait')
267
+ return [];
268
+ return [
269
+ genericToolItem(state.itemId, toolName, 'IN_PROGRESS', state.input, snapshot.outputPreview, null, snapshot.truncated, { processId: output.processId, displayOutput: snapshot.displayOutput })
270
+ ];
271
+ }
295
272
  const command = this.#commands.get(state.commandOrigin);
296
273
  if (command === undefined || command.status !== 'IN_PROGRESS')
297
274
  return [];
298
- this.#toolOutputSnapshots.set(callId, {
299
- commandOrigin: state.commandOrigin,
300
- ...snapshot
301
- });
302
- return [
303
- commandItem(commandWithOutputSnapshots(command, [...this.#toolOutputSnapshots.values()].filter((entry) => entry.commandOrigin === state.commandOrigin)), 'IN_PROGRESS')
304
- ];
275
+ const display = snapshot.displayOutput;
276
+ if (display !== undefined)
277
+ command.displayOutput = display;
278
+ command.outputPreview = snapshot.outputPreview;
279
+ command.truncated = snapshot.truncated;
280
+ return [commandItem(command, 'IN_PROGRESS')];
305
281
  }
306
282
  #codeModeToolOutput(callId, parentCallId, toolName, executionId, turnId, processId, snapshot) {
307
283
  const parent = this.#tools.get(parentCallId);
@@ -333,9 +309,9 @@ export class MarAgentConversationNormalizer {
333
309
  .map((entry) => entry.outputPreview)
334
310
  .filter(Boolean)
335
311
  .join('\n');
336
- const truncated = [...snapshots.values()].some((entry) => entry.truncated) || combined.length > 10_000;
312
+ const bounded = publicOutputSnapshot(combined, [...snapshots.values()].some((entry) => entry.truncated));
337
313
  return [
338
- genericToolItem(target.itemId, target.toolName, 'IN_PROGRESS', target.input, compactRunnerText(combined, 10_000), null, truncated)
314
+ genericToolItem(target.itemId, target.toolName, 'IN_PROGRESS', target.input, bounded.text, null, bounded.truncated)
339
315
  ];
340
316
  }
341
317
  #trackCodeModeOutputCall(event) {
@@ -403,7 +379,6 @@ export class MarAgentConversationNormalizer {
403
379
  const state = this.#tools.get(event.callId);
404
380
  if (state !== undefined)
405
381
  state.active = false;
406
- this.#toolOutputSnapshots.delete(event.callId);
407
382
  const data = record(event.data);
408
383
  const cellId = typeof data?.cellId === 'string' ? data.cellId : undefined;
409
384
  const status = data?.status;
@@ -462,7 +437,6 @@ export class MarAgentConversationNormalizer {
462
437
  for (const [callId, state] of this.#tools)
463
438
  if (state.executionId !== executionId) {
464
439
  state.active = false;
465
- this.#toolOutputSnapshots.delete(callId);
466
440
  }
467
441
  for (const [callId, state] of this.#codeModeOutputCalls)
468
442
  if (state.executionId !== executionId)
@@ -493,21 +467,19 @@ export class MarAgentConversationNormalizer {
493
467
  }
494
468
  #toolCompleted(event) {
495
469
  const state = this.#tools.get(event.callId);
496
- if ((event.toolName === 'exec' || event.toolName === 'exec_wait') &&
497
- state?.commandOrigin !== undefined) {
470
+ if (event.toolName === 'exec' && state?.commandOrigin !== undefined) {
498
471
  const command = this.#commands.get(state.commandOrigin);
499
472
  const result = execResult(event.data, event.summary, event.truncated === true);
500
473
  if (command !== undefined && result !== undefined) {
501
- if (result.processId !== undefined)
502
- this.#processOrigins.set(result.processId, state.commandOrigin);
503
474
  applyCommandResult(command, result);
504
- const status = result.status === 'running'
505
- ? 'IN_PROGRESS'
506
- : result.status === 'completed' && result.exitCode === 0
507
- ? 'COMPLETED'
508
- : 'FAILED';
509
- command.status = status;
510
- return [commandItem(command, status)];
475
+ const data = record(event.data);
476
+ const display = execDisplayOutput(data?.displayOutput);
477
+ if (display !== undefined)
478
+ command.displayOutput = display;
479
+ else
480
+ delete command.displayOutput;
481
+ command.status = 'COMPLETED';
482
+ return [commandItem(command, 'COMPLETED')];
511
483
  }
512
484
  }
513
485
  if (event.toolName === 'apply_patch' &&
@@ -553,16 +525,17 @@ export class MarAgentConversationNormalizer {
553
525
  }
554
526
  #toolFailed(event) {
555
527
  const state = this.#tools.get(event.callId);
556
- if ((event.toolName === 'exec' || event.toolName === 'exec_wait') &&
557
- state?.commandOrigin !== undefined) {
528
+ if (event.toolName === 'exec' && state?.commandOrigin !== undefined) {
558
529
  const command = this.#commands.get(state.commandOrigin);
559
- const input = record(state.input);
560
- if (command !== undefined &&
561
- command.status === 'IN_PROGRESS' &&
562
- (state.itemId !== command.itemId ||
563
- input?.action === 'start' ||
564
- (input?.action == null && typeof input?.command === 'string'))) {
530
+ if (command !== undefined) {
531
+ const error = {
532
+ code: compactRunnerText(event.code, 80) || 'UNKNOWN',
533
+ message: compactRunnerText(event.message ?? event.code, 1000)
534
+ };
565
535
  command.status = 'FAILED';
536
+ command.error = error;
537
+ delete command.displayOutput;
538
+ command.outputPreview = '';
566
539
  return [commandItem(command, 'FAILED')];
567
540
  }
568
541
  }
@@ -848,24 +821,89 @@ function normalizeContextCompaction(event, anchorItemId) {
848
821
  function validCompactAnchor(value) {
849
822
  return value !== undefined && value.length > 0 && value.length <= 128 ? value : undefined;
850
823
  }
824
+ function codeObservationOutput(data, summary) {
825
+ if (Array.isArray(data?.observations)) {
826
+ return data.observations
827
+ .flatMap((entry) => {
828
+ const observation = record(entry);
829
+ if (observation?.type === 'value' && typeof observation.value === 'string')
830
+ return [observation.value];
831
+ const result = record(observation?.result);
832
+ const source = record(observation?.source);
833
+ if (observation?.type === 'tool_result' &&
834
+ (source?.toolName === 'exec' || source?.toolName === 'exec_wait')) {
835
+ const resultData = record(result?.data);
836
+ const display = record(resultData?.displayOutput) ?? resultData;
837
+ if (typeof display?.stdout === 'string' || typeof display?.stderr === 'string')
838
+ return [display?.stdout, display?.stderr].filter((value) => typeof value === 'string' && value.length > 0);
839
+ }
840
+ return observation?.type === 'tool_result' && typeof result?.content === 'string'
841
+ ? [result.content]
842
+ : [];
843
+ })
844
+ .join('\n');
845
+ }
846
+ return summary ?? undefined;
847
+ }
848
+ function codeExecutionError(data) {
849
+ const error = record(data?.error);
850
+ if (typeof error?.code !== 'string' || !error.code || typeof error.message !== 'string')
851
+ return undefined;
852
+ return {
853
+ code: compactRunnerText(error.code, 80),
854
+ message: compactRunnerText(error.message, 1000)
855
+ };
856
+ }
851
857
  function genericToolItem(id, toolName, status, input, outputSummary = null, errorCode = null, truncated = false, output, subagentTitle, knownSubagentDetails, sleepStartedAt) {
852
858
  if (toolName === 'code_exec') {
853
859
  const code = typeof input === 'string' ? input : record(input)?.code;
854
860
  const source = typeof code === 'string' ? code : compactRunnerValue(input, 10_000).text || toolName;
855
- const output = errorCode === null
861
+ const resultData = record(output);
862
+ const codeOutput = codeObservationOutput(resultData, outputSummary);
863
+ const resultError = codeExecutionError(resultData);
864
+ const preview = errorCode === null
856
865
  ? (outputSummary ?? '')
857
866
  : [errorCode, outputSummary].filter(Boolean).join(': ');
858
867
  return commandItem({
859
868
  itemId: id,
860
869
  command: compactRunnerText(source, 10_000),
861
870
  cwd: null,
862
- outputPreview: compactRunnerText(output, 10_000),
871
+ outputPreview: compactRunnerText(preview, 10_000),
863
872
  exitCode: null,
864
- truncated: truncated || source.length > 10_000 || output.length > 10_000
865
- }, status, 'Code execution');
873
+ truncated: truncated ||
874
+ resultData?.truncated === true ||
875
+ source.length > 10_000 ||
876
+ preview.length > 10_000
877
+ }, status, 'Code execution', {
878
+ kind: 'CODE',
879
+ ...(source.length > 10_000 ? { truncation: { input: true } } : {}),
880
+ ...(errorCode === null
881
+ ? resultError === undefined
882
+ ? {}
883
+ : { error: resultError }
884
+ : {
885
+ error: {
886
+ code: compactRunnerText(errorCode, 80),
887
+ message: compactRunnerText(outputSummary ?? '', 1000)
888
+ }
889
+ }),
890
+ ...(codeOutput === undefined ? {} : { output: [{ channel: 'TEXT', text: codeOutput }] })
891
+ });
866
892
  }
867
- if (toolName === 'code_exec_wait') {
893
+ if (toolName === 'code_exec_wait' || toolName === 'exec_wait') {
868
894
  const inputRecord = record(input);
895
+ const resultData = record(output);
896
+ const display = execDisplayOutput(resultData?.displayOutput);
897
+ const legacyBlocks = [
898
+ ...(typeof resultData?.stdout === 'string'
899
+ ? [{ channel: 'STDOUT', text: resultData.stdout }]
900
+ : []),
901
+ ...(typeof resultData?.stderr === 'string'
902
+ ? [{ channel: 'STDERR', text: resultData.stderr }]
903
+ : [])
904
+ ];
905
+ const codeOutput = toolName === 'code_exec_wait' ? codeObservationOutput(resultData, outputSummary) : undefined;
906
+ const resultError = toolName === 'code_exec_wait' ? codeExecutionError(resultData) : undefined;
869
907
  const action = typeof inputRecord?.action === 'string' ? inputRecord.action : 'poll';
870
908
  const inputSummary = compactRunnerValue(input, 10_000);
871
909
  const result = output === undefined ? null : compactRunnerValue(output, 10_000);
@@ -882,15 +920,64 @@ function genericToolItem(id, toolName, status, input, outputSummary = null, erro
882
920
  .join('\n');
883
921
  return commandItem({
884
922
  itemId: id,
885
- command: toolName,
923
+ command: `${toolName} (${compactRunnerText(action, 128)})`,
886
924
  cwd: null,
887
- outputPreview: details,
888
- exitCode: null,
925
+ outputPreview: status === 'IN_PROGRESS' && outputSummary !== null
926
+ ? outputSummary
927
+ : legacyBlocks.length > 0
928
+ ? legacyBlocks
929
+ .map((block) => block.text)
930
+ .filter(Boolean)
931
+ .join('\n')
932
+ : details,
933
+ exitCode: typeof resultData?.exitCode === 'number' ? resultData.exitCode : null,
889
934
  truncated: truncated ||
935
+ resultData?.truncated === true ||
890
936
  inputSummary.truncated ||
891
937
  result?.truncated === true ||
892
938
  resultSummary.length > 10_000
893
- }, status, 'Code execution wait');
939
+ }, status, toolName === 'code_exec_wait' ? 'Code execution wait' : 'Command wait', {
940
+ kind: 'CONTROL',
941
+ ...(display === undefined
942
+ ? {}
943
+ : {
944
+ output: [
945
+ { channel: 'STDOUT', text: display.stdout },
946
+ { channel: 'STDERR', text: display.stderr }
947
+ ]
948
+ }),
949
+ ...(display === undefined && legacyBlocks.length > 0 ? { output: legacyBlocks } : {}),
950
+ ...(codeOutput === undefined
951
+ ? {}
952
+ : { output: [{ channel: 'TEXT', text: codeOutput }] }),
953
+ ...((typeof inputRecord?.data === 'string' && inputRecord.data.length > 10_000) ||
954
+ (display !== undefined && (display.stdoutDroppedBytes || display.stderrDroppedBytes)) ||
955
+ (display === undefined && legacyBlocks.length > 0 && truncated)
956
+ ? {
957
+ truncation: {
958
+ ...(typeof inputRecord?.data === 'string' && inputRecord.data.length > 10_000
959
+ ? { input: true }
960
+ : {}),
961
+ ...(display !== undefined &&
962
+ (display.stdoutDroppedBytes || display.stderrDroppedBytes)
963
+ ? { output: 'HEAD' }
964
+ : display === undefined && legacyBlocks.length > 0 && truncated
965
+ ? { output: 'SOURCE' }
966
+ : {})
967
+ }
968
+ }
969
+ : {}),
970
+ ...(errorCode === null
971
+ ? resultError === undefined
972
+ ? {}
973
+ : { error: resultError }
974
+ : {
975
+ error: {
976
+ code: compactRunnerText(errorCode, 80),
977
+ message: compactRunnerText(outputSummary ?? '', 1000)
978
+ }
979
+ })
980
+ });
894
981
  }
895
982
  const subagent = marAgentSubagentProjection(toolName, input, output, subagentTitle, knownSubagentDetails);
896
983
  const toolCategory = isImageGenerationTool(toolName) ? 'IMAGE_GENERATION' : undefined;
@@ -959,7 +1046,50 @@ function projectToolPresentation(toolName, input, output, startedAt) {
959
1046
  const parsed = toolPresentationSchema.safeParse(candidate);
960
1047
  return parsed.success ? parsed.data : { kind };
961
1048
  }
962
- function commandItem(command, status, title) {
1049
+ function execDisplayOutput(value) {
1050
+ const data = record(value);
1051
+ if (typeof data?.stdout !== 'string' ||
1052
+ typeof data.stderr !== 'string' ||
1053
+ typeof data.stdoutDroppedBytes !== 'number' ||
1054
+ !Number.isSafeInteger(data.stdoutDroppedBytes) ||
1055
+ data.stdoutDroppedBytes < 0 ||
1056
+ typeof data.stderrDroppedBytes !== 'number' ||
1057
+ !Number.isSafeInteger(data.stderrDroppedBytes) ||
1058
+ data.stderrDroppedBytes < 0)
1059
+ return undefined;
1060
+ return {
1061
+ stdout: data.stdout,
1062
+ stderr: data.stderr,
1063
+ stdoutDroppedBytes: data.stdoutDroppedBytes,
1064
+ stderrDroppedBytes: data.stderrDroppedBytes
1065
+ };
1066
+ }
1067
+ function commandItem(command, status, title, execution) {
1068
+ const display = command.displayOutput;
1069
+ const detail = execution ?? {
1070
+ kind: 'SHELL',
1071
+ ...(command.error === undefined ? {} : { error: command.error }),
1072
+ ...(!command.inputTruncated &&
1073
+ !(display && (display.stdoutDroppedBytes > 0 || display.stderrDroppedBytes > 0))
1074
+ ? {}
1075
+ : {
1076
+ truncation: {
1077
+ ...(command.inputTruncated ? { input: true } : {}),
1078
+ ...(display && (display.stdoutDroppedBytes > 0 || display.stderrDroppedBytes > 0)
1079
+ ? { output: 'HEAD' }
1080
+ : {})
1081
+ }
1082
+ }),
1083
+ ...(display === undefined
1084
+ ? {}
1085
+ : {
1086
+ output: [
1087
+ { channel: 'STDOUT', text: display.stdout },
1088
+ { channel: 'STDERR', text: display.stderr }
1089
+ ]
1090
+ })
1091
+ };
1092
+ const bounded = boundExecutionPresentation(detail);
963
1093
  return {
964
1094
  itemId: command.itemId,
965
1095
  kind: 'command_execution',
@@ -972,37 +1102,21 @@ function commandItem(command, status, title) {
972
1102
  outputRef: null,
973
1103
  exitCode: command.exitCode,
974
1104
  durationMs: null,
975
- truncated: command.truncated
1105
+ truncated: command.truncated ||
1106
+ command.inputTruncated === true ||
1107
+ bounded.truncated ||
1108
+ (display !== undefined &&
1109
+ (display.stdoutDroppedBytes > 0 || display.stderrDroppedBytes > 0)),
1110
+ toolPresentation: bounded.presentation
976
1111
  },
977
1112
  merge: true
978
1113
  };
979
1114
  }
980
- function commandWithOutputSnapshots(command, snapshots) {
981
- const outputPreview = [
982
- command.outputPreview,
983
- ...snapshots.map((snapshot) => snapshot.outputPreview)
984
- ]
985
- .filter(Boolean)
986
- .join('\n');
987
- return {
988
- ...command,
989
- outputPreview: compactRunnerText(outputPreview, 10_000),
990
- truncated: command.truncated ||
991
- snapshots.some((snapshot) => snapshot.truncated) ||
992
- outputPreview.length > 10_000
993
- };
994
- }
995
1115
  function applyCommandResult(command, result) {
996
1116
  const output = [result.stdout, result.stderr].filter(Boolean).join('\n');
997
- if (output.length > 0) {
998
- const combined = result.cached
999
- ? output
1000
- : [command.outputPreview, output].filter(Boolean).join('\n');
1001
- command.truncated ||= combined.length > 10_000;
1002
- command.outputPreview = compactRunnerText(combined, 10_000);
1003
- }
1004
- command.exitCode = result.exitCode ?? command.exitCode;
1005
- command.truncated ||= result.truncated;
1117
+ command.outputPreview = compactRunnerText(output, 10_000);
1118
+ command.truncated = result.truncated || output.length > 10_000;
1119
+ command.exitCode = result.exitCode ?? null;
1006
1120
  }
1007
1121
  function fileChangeItem(id, status, changes) {
1008
1122
  return { itemId: id, kind: 'file_change', status, payload: { changes }, merge: true };
@@ -1120,11 +1234,17 @@ function marAgentSubagentProjection(toolName, input, output, knownTitle, knownDe
1120
1234
  ? outputData.description
1121
1235
  : operation === 'START' && typeof inputData?.description === 'string'
1122
1236
  ? inputData.description
1123
- : ''), 500);
1237
+ : operation === 'START' && typeof inputData?.title === 'string'
1238
+ ? inputData.title
1239
+ : ''), 500);
1124
1240
  return {
1125
1241
  subagentOperation: operation,
1126
1242
  ...(operation === 'STATUS' ? { subagentWait: inputData?.waitMs !== 0 } : {}),
1127
1243
  subagentId: marAgentAgentId(input) ?? marAgentAgentId(controlOutput) ?? null,
1244
+ ...(typeof outputData?.productSessionId === 'string' &&
1245
+ outputData.productSessionId === marAgentAgentId(controlOutput)
1246
+ ? { subagentSessionId: outputData.productSessionId }
1247
+ : {}),
1128
1248
  ...(title.length === 0 ? {} : { title }),
1129
1249
  ...subagentPayload(details),
1130
1250
  ...(typeof details.latestMessage?.text === 'string'
@@ -1165,9 +1285,9 @@ function marAgentSubagentOperation(toolName) {
1165
1285
  return 'START';
1166
1286
  if (toolName === 'agent_wait')
1167
1287
  return 'STATUS';
1168
- if (toolName === 'agent_message')
1288
+ if (toolName === 'agent_send' || toolName === 'agent_message')
1169
1289
  return 'MESSAGE';
1170
- if (toolName === 'agent_cancel')
1290
+ if (toolName === 'agent_stop' || toolName === 'agent_cancel')
1171
1291
  return 'CANCEL';
1172
1292
  return undefined;
1173
1293
  }
@@ -1,6 +1,6 @@
1
1
  import { marAgentEnvelopeInput, resolveMarAgentExecutionInput } from './execution-input.js';
2
2
  export { resolveRunModels } from './execution-input.js';
3
- import { NODE_MCP } from '../../mcp/naming.js';
3
+ import { NODE_MCP, NODE_COMPUTER_WAIT_TOOL_NAME } from '../../mcp/naming.js';
4
4
  import { computerUseHostSkill } from './computer-use-skill.js';
5
5
  import { marctlExecutionEnvironment, marctlHostSkill } from './marctl-skill.js';
6
6
  import { createHash, randomUUID } from 'node:crypto';
@@ -51,6 +51,11 @@ export class MarAgentManagedRunController {
51
51
  }
52
52
  }),
53
53
  customTitle: (sessionId) => this.host.customTitle?.(sessionId) ?? undefined,
54
+ ...(options.attachNetworkContext === undefined
55
+ ? {}
56
+ : {
57
+ attachNetworkContext: options.attachNetworkContext
58
+ }),
54
59
  modelUsage: (runId, usage) => this.host.emit(runId, 'run.usage', normalizeMarAgentUsage(usage)),
55
60
  publishModelResource: options.publishModelResource,
56
61
  question: (runId, request, signal) => this.requestQuestion(runId, request, signal),
@@ -291,6 +296,7 @@ export class MarAgentManagedRunController {
291
296
  sessionId: runtime.session.id,
292
297
  mode: input.mode,
293
298
  enabled: input.computerUseEnabled === true,
299
+ signal: controller.signal,
294
300
  modelSupportsImages: input.model.inputCapabilities.includes('IMAGE')
295
301
  });
296
302
  use.assertUsable();
@@ -344,7 +350,9 @@ export class MarAgentManagedRunController {
344
350
  const computer = nodeTools.map((definition) => ({
345
351
  definition,
346
352
  serverId: NODE_MCP.computer.name,
347
- rawName: NODE_MCP.computer.tools.exec,
353
+ rawName: definition.name === NODE_COMPUTER_WAIT_TOOL_NAME
354
+ ? NODE_MCP.computer.tools.wait
355
+ : NODE_MCP.computer.tools.exec,
348
356
  sourceIdentity: `node:${input.runId}:computer`,
349
357
  definitionRevision: createHash('sha256')
350
358
  .update(JSON.stringify(definition))
@@ -540,6 +548,9 @@ export class MarAgentManagedRunController {
540
548
  finally {
541
549
  titleController.abort();
542
550
  const cleanup = [
551
+ async () => {
552
+ await computerUseBinding?.close();
553
+ },
543
554
  async () => {
544
555
  await titleTask;
545
556
  },
@@ -549,9 +560,6 @@ export class MarAgentManagedRunController {
549
560
  async () => {
550
561
  await closeImageCredentialProviders(executionModels);
551
562
  },
552
- async () => {
553
- await computerUseBinding?.close();
554
- },
555
563
  async () => {
556
564
  runtime?.host.unbindExecutionMcp(executionMcpBinding);
557
565
  },
@@ -1,4 +1,4 @@
1
- import { hasMarctlContext, marctlDescription, marctlInstructions } from '../../marctl-guidance.js';
1
+ import { hasMarctlContext, marctlManagementDescription, marctlManagementInstructions } from '../../marctl-guidance.js';
2
2
  export function marctlExecutionEnvironment(environment = {}) {
3
3
  return Object.fromEntries(Object.entries(environment).filter(([key]) => key.startsWith('MAR_CTL_')));
4
4
  }
@@ -7,8 +7,8 @@ export function marctlHostSkill(environment = {}) {
7
7
  return undefined;
8
8
  return {
9
9
  name: 'marctl',
10
- description: marctlDescription,
10
+ description: marctlManagementDescription,
11
11
  requiredTools: ['exec'],
12
- load: async () => marctlInstructions
12
+ load: async () => marctlManagementInstructions
13
13
  };
14
14
  }
@@ -63,6 +63,7 @@ export class MarAgentRuntimeModelFactory {
63
63
  reasoningEfforts: configuration.reasoningEfforts,
64
64
  defaultReasoningEffort: resolveMarAgentDefaultReasoningEffort(configuration.defaultReasoningEffort, configuration.reasoningEfforts),
65
65
  conversationModel: configuration.conversationModel ?? true,
66
+ subagentModel: configuration.subagentModel ?? false,
66
67
  titleGeneration: configuration.titleGeneration,
67
68
  codeMode: configuration.codeMode,
68
69
  ...(configuration.serviceTier === undefined