@myagentroam/node 0.11.44 → 0.11.46

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 (49) hide show
  1. package/dist/connector.js +4 -4
  2. package/dist/database.js +7 -5
  3. package/dist/marctl-guidance.js +2 -2
  4. package/dist/migrations/v023.js +25 -0
  5. package/dist/runner/abstract-runner.js +1 -1
  6. package/dist/runner/claude/managed-run-controller.js +4 -11
  7. package/dist/runner/claude/native-transcript.js +1 -1
  8. package/dist/runner/claude/tool-normalizer.js +16 -11
  9. package/dist/runner/claude-code-runner.js +1 -1
  10. package/dist/runner/codex/conversation-parser.js +29 -38
  11. package/dist/runner/codex/managed-run-controller.js +5 -5
  12. package/dist/runner/codex/native-transcript.js +5 -3
  13. package/dist/runner/codex/tool-normalizer.js +13 -17
  14. package/dist/runner/codex-runner.js +10 -5
  15. package/dist/runner/execution-presentation.js +8 -51
  16. package/dist/runner/mar-agent/agent-network-extension.js +80 -24
  17. package/dist/runner/mar-agent/agent-operation-presentation.js +167 -0
  18. package/dist/runner/mar-agent/conversation-normalizer.js +118 -107
  19. package/dist/runner/mar-agent/history-projection.js +1 -1
  20. package/dist/runner/mar-agent/hosted-conversation-runtime.js +1 -1
  21. package/dist/runner/mar-agent/managed-run-controller.js +2 -2
  22. package/dist/runner/mar-agent-runner.js +5 -5
  23. package/dist/runner/normalization.js +5 -0
  24. package/dist/runner/opencode/managed-run-controller.js +2 -2
  25. package/dist/runner/opencode/tool-normalizer.js +10 -10
  26. package/dist/runner/opencode-runner.js +5 -5
  27. package/dist/runner-profiles.js +1 -1
  28. package/dist/runtime-state.js +7 -7
  29. package/dist/service/agent-network-bindings.js +10 -6
  30. package/dist/service/agent-network-service.js +2 -1
  31. package/dist/service/continuous-run-coordinator.js +1 -1
  32. package/dist/service/external-session-resume-service.js +1 -1
  33. package/dist/service/goal-continuation-coordinator.js +3 -3
  34. package/dist/service/native-session-watch-service.js +6 -3
  35. package/dist/service/planned-restart-handoff.js +24 -5
  36. package/dist/service/restart-session-restorer.js +2 -2
  37. package/dist/service/session-recent-activity.js +1 -1
  38. package/dist/session/native-session-projection-service.js +8 -8
  39. package/dist/session/runtime/conversation-projection.js +10 -3
  40. package/dist/session/session-catalog-service.js +2 -2
  41. package/dist/session/session-command-service.js +1 -0
  42. package/dist/session/session-context-service.js +1 -1
  43. package/dist/session/session-lifecycle-service.js +12 -10
  44. package/dist/session/session-message-service.js +4 -3
  45. package/dist/workspace/git.js +44 -1
  46. package/dist/workspace/workspace-change-service.js +39 -1
  47. package/dist/workspace/workspace-session-service.js +1 -1
  48. package/dist/workspace/workspace-workbench-service.js +8 -0
  49. package/package.json +4 -4
@@ -7,8 +7,9 @@ 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 } from '../execution-presentation.js';
11
- import { publicOutputSnapshot } from '../normalization.js';
10
+ import { publicOutputSnapshot, publicToolOutput } from '../normalization.js';
11
+ import { boundToolOutput } from '@myagentroam/protocol';
12
+ import { agentOperationAction, agentOperationPresentation } from './agent-operation-presentation.js';
12
13
  function boundCodeOutputSnapshots(sources) {
13
14
  for (const channel of ['outputPreview', 'stdout', 'stderr']) {
14
15
  const text = (entry) => channel === 'outputPreview' ? entry.outputPreview : entry.displayOutput[channel];
@@ -147,15 +148,18 @@ export class MarAgentConversationNormalizer {
147
148
  this.#finishCodeModeOutputCall(event.callId, event.parentCallId);
148
149
  return [];
149
150
  }
150
- // Read/web calls and generated artifacts stay visible independently of cell observations.
151
+ // Public Agent calls, read/web calls and artifacts do not depend on model observations.
151
152
  if (event.parentCallId !== undefined &&
152
153
  event.toolName !== 'read' &&
153
154
  event.toolName !== 'web_search' &&
154
155
  event.toolName !== 'web_fetch' &&
156
+ agentOperationAction(event.toolName) === undefined &&
155
157
  !isImageGenerationTool(event.toolName)) {
156
158
  this.#finishCodeModeOutputCall(event.callId, event.parentCallId);
157
159
  return [];
158
160
  }
161
+ if (event.parentCallId !== undefined && agentOperationAction(event.toolName) !== undefined)
162
+ this.#codeModeSourceCallIds.add(event.callId);
159
163
  if (event.type === 'tool.started')
160
164
  return this.#toolStarted(event);
161
165
  this.#finishToolCall(event);
@@ -252,6 +256,7 @@ export class MarAgentConversationNormalizer {
252
256
  input: event.input,
253
257
  itemId: ownItemId,
254
258
  structured: 'input' in event,
259
+ inputTruncated: event.truncated === true,
255
260
  executionId: event.executionId,
256
261
  ...(event.turnId === undefined ? {} : { turnId: event.turnId }),
257
262
  active: true,
@@ -264,7 +269,7 @@ export class MarAgentConversationNormalizer {
264
269
  if (event.toolName === 'apply_patch' && 'input' in event)
265
270
  return [fileChangeItem(ownItemId, 'IN_PROGRESS', [])];
266
271
  return [
267
- genericToolItem(ownItemId, event.toolName, 'IN_PROGRESS', event.input, null, null, event.truncated === true, event.data, subagentTitle, subagentDetails)
272
+ genericToolItem(ownItemId, event.toolName, 'IN_PROGRESS', event.input, null, null, event.truncated === true, event.data, subagentTitle, subagentDetails, undefined, undefined, event.truncated === true)
268
273
  ];
269
274
  }
270
275
  #toolOutput(event) {
@@ -279,14 +284,13 @@ export class MarAgentConversationNormalizer {
279
284
  stderrDroppedBytes: 0
280
285
  };
281
286
  const displayed = [displayOutput.stdout, displayOutput.stderr].filter(Boolean).join('\n');
282
- const bounded = publicOutputSnapshot(displayed, output.truncated ||
283
- displayOutput.stdoutDroppedBytes > 0 ||
284
- displayOutput.stderrDroppedBytes > 0);
287
+ const bounded = publicOutputSnapshot(displayed, event.outputTruncation !== undefined);
285
288
  const snapshot = {
286
289
  outputPreview: bounded.text,
287
290
  truncated: bounded.truncated || inputOutput.length > 10_000,
288
291
  displayOutput,
289
- processId: output.processId
292
+ processId: output.processId,
293
+ ...(event.outputTruncation ? { outputTruncation: event.outputTruncation } : {})
290
294
  };
291
295
  if (parentCallId !== undefined && (toolName === 'exec' || toolName === 'exec_wait'))
292
296
  return this.#codeModeToolOutput(callId, parentCallId, toolName, executionId, turnId, output.processId, snapshot);
@@ -309,7 +313,7 @@ export class MarAgentConversationNormalizer {
309
313
  displayOutput: snapshot.displayOutput,
310
314
  outputHeadTruncated: snapshot.displayOutput.stdoutDroppedBytes > 0 ||
311
315
  snapshot.displayOutput.stderrDroppedBytes > 0
312
- })
316
+ }, undefined, undefined, undefined, event.outputTruncation, state.inputTruncated)
313
317
  ];
314
318
  }
315
319
  const command = this.#commands.get(state.commandOrigin);
@@ -320,6 +324,10 @@ export class MarAgentConversationNormalizer {
320
324
  command.displayOutput = display;
321
325
  command.outputPreview = snapshot.outputPreview;
322
326
  command.truncated = snapshot.truncated;
327
+ if (event.outputTruncation)
328
+ command.outputTruncation = event.outputTruncation;
329
+ else
330
+ delete command.outputTruncation;
323
331
  return [commandItem(command, 'IN_PROGRESS')];
324
332
  }
325
333
  #toolOutputDelta(event) {
@@ -375,26 +383,11 @@ export class MarAgentConversationNormalizer {
375
383
  const command = target.commandOrigin === undefined ? undefined : this.#commands.get(target.commandOrigin);
376
384
  const item = command
377
385
  ? commandItem(command, 'IN_PROGRESS')
378
- : genericToolItem(target.itemId, target.toolName, 'IN_PROGRESS', target.input, null, null);
379
- const original = record(record(item.payload.toolPresentation)?.execution);
386
+ : genericToolItem(target.itemId, target.toolName, 'IN_PROGRESS', target.input, null, null, false, undefined, undefined, undefined, undefined, undefined, target.inputTruncated);
380
387
  const blocks = [
381
388
  ...(output.stdout ? [{ channel: 'STDOUT', text: output.stdout }] : []),
382
389
  ...(output.stderr ? [{ channel: 'STDERR', text: output.stderr }] : [])
383
390
  ];
384
- const text = [output.stdout, output.stderr].filter(Boolean).join('\n');
385
- const boundedText = publicOutputSnapshot(text, output.truncated);
386
- const bounded = boundExecutionPresentation({
387
- kind: parentCallId !== undefined
388
- ? target.toolName === 'code_exec'
389
- ? 'CODE'
390
- : 'CONTROL'
391
- : toolName === 'exec'
392
- ? 'SHELL'
393
- : 'CONTROL',
394
- ...(typeof original?.toolName === 'string' ? { toolName: original.toolName } : {}),
395
- output: blocks,
396
- ...(output.truncated ? { truncation: { output: 'HEAD' } } : {})
397
- });
398
391
  return [
399
392
  {
400
393
  ...item,
@@ -402,9 +395,7 @@ export class MarAgentConversationNormalizer {
402
395
  merge: true,
403
396
  payload: {
404
397
  ...item.payload,
405
- outputPreview: boundedText.text,
406
- output: boundedText,
407
- toolPresentation: bounded.presentation
398
+ output: boundToolOutput(blocks, event.outputTruncation)
408
399
  }
409
400
  }
410
401
  ];
@@ -458,7 +449,13 @@ export class MarAgentConversationNormalizer {
458
449
  .filter(Boolean)
459
450
  .join('')
460
451
  }
461
- })
452
+ }, undefined, undefined, undefined, entries.some((entry) => entry.outputTruncation === 'SOURCE')
453
+ ? 'SOURCE'
454
+ : entries.some((entry) => entry.outputTruncation === 'HEAD' ||
455
+ entry.displayOutput.stdoutDroppedBytes > 0 ||
456
+ entry.displayOutput.stderrDroppedBytes > 0)
457
+ ? 'HEAD'
458
+ : undefined, target.inputTruncated)
462
459
  ];
463
460
  }
464
461
  #trackCodeModeOutputCall(event) {
@@ -626,9 +623,13 @@ export class MarAgentConversationNormalizer {
626
623
  const state = this.#tools.get(event.callId);
627
624
  if (event.toolName === 'exec' && state?.commandOrigin !== undefined) {
628
625
  const command = this.#commands.get(state.commandOrigin);
629
- const result = execResult(event.data, event.summary, event.truncated === true);
626
+ const result = execResult(event.data, event.summary, event.outputTruncation !== undefined);
630
627
  if (command !== undefined && result !== undefined) {
631
628
  applyCommandResult(command, result);
629
+ if (event.outputTruncation)
630
+ command.outputTruncation = event.outputTruncation;
631
+ else
632
+ delete command.outputTruncation;
632
633
  const data = record(event.data);
633
634
  const display = execDisplayOutput(data?.displayOutput);
634
635
  if (display !== undefined)
@@ -672,7 +673,7 @@ export class MarAgentConversationNormalizer {
672
673
  }
673
674
  const item = genericToolItem(state?.itemId ?? itemId('tool', event.callId), event.toolName, 'COMPLETED', state?.input, generatedImages.length === 0
674
675
  ? event.summary
675
- : generatedImages.map((image) => image.name).join(', '), null, event.truncated, event.data, agentId === undefined ? state?.subagentTitle : this.#subagentTitles.get(agentId), details, state?.sleepStartedAt);
676
+ : generatedImages.map((image) => image.name).join(', '), null, event.outputTruncation !== undefined, event.data, agentId === undefined ? state?.subagentTitle : this.#subagentTitles.get(agentId), details, state?.sleepStartedAt, event.outputTruncation, state?.inputTruncated, event.summaryTruncated === true);
676
677
  return [
677
678
  {
678
679
  ...item,
@@ -703,7 +704,7 @@ export class MarAgentConversationNormalizer {
703
704
  return [
704
705
  genericToolItem(state?.itemId ?? itemId('tool', event.callId), event.toolName, event.code === 'MAR_AGENT_CANCELLED' || event.code === 'MAR_AGENT_EXECUTION_CANCELLED'
705
706
  ? 'CANCELLED'
706
- : 'FAILED', state?.input, event.message ?? event.code, event.code, event.truncated === true, state?.presentationData, state?.subagentTitle, state?.subagentDetails, state?.sleepStartedAt)
707
+ : 'FAILED', state?.input, event.message ?? event.code, event.code, event.truncated === true, event.data === undefined ? state?.presentationData : event.data, state?.subagentTitle, state?.subagentDetails, state?.sleepStartedAt, event.outputTruncation, state?.inputTruncated)
707
708
  ];
708
709
  }
709
710
  #codeModeToolResults(event) {
@@ -1026,33 +1027,30 @@ function codeExecutionError(data) {
1026
1027
  message: compactRunnerText(error.message, 1000)
1027
1028
  };
1028
1029
  }
1029
- function genericToolItem(id, toolName, status, input, outputSummary = null, errorCode = null, truncated = false, output, subagentTitle, knownSubagentDetails, sleepStartedAt) {
1030
+ function genericToolItem(id, toolName, status, input, outputSummary = null, errorCode = null, truncated = false, output, subagentTitle, knownSubagentDetails, sleepStartedAt, outputTruncation, inputTruncated = false, summaryTruncated = false) {
1030
1031
  if (toolName === 'code_exec') {
1031
1032
  const code = typeof input === 'string' ? input : record(input)?.code;
1032
1033
  const source = typeof code === 'string' ? code : compactRunnerValue(input, 10_000).text || toolName;
1033
1034
  const resultData = record(output);
1034
- const codeOutput = codeObservationOutput(resultData, outputSummary);
1035
+ const codeOutput = codeObservationOutput(resultData, null);
1035
1036
  const resultError = codeExecutionError(resultData);
1036
1037
  const preview = errorCode === null
1037
1038
  ? (outputSummary ?? '')
1038
1039
  : [errorCode, outputSummary].filter(Boolean).join(': ');
1039
- return commandItem({
1040
+ const item = commandItem({
1040
1041
  itemId: id,
1041
1042
  command: compactRunnerText(source, 10_000),
1042
1043
  cwd: null,
1043
- outputPreview: compactRunnerText(preview, 10_000),
1044
+ outputPreview: '',
1044
1045
  exitCode: null,
1045
- truncated: truncated ||
1046
- resultData?.truncated === true ||
1047
- source.length > 10_000 ||
1048
- preview.length > 10_000
1046
+ truncated: truncated || source.length > 10_000 || preview.length > 10_000
1049
1047
  }, status, 'Code execution', {
1050
1048
  kind: 'CODE',
1051
- ...(source.length > 10_000 || resultData?.outputHeadTruncated === true
1049
+ ...(source.length > 10_000 || inputTruncated || outputTruncation !== undefined
1052
1050
  ? {
1053
1051
  truncation: {
1054
- ...(source.length > 10_000 ? { input: true } : {}),
1055
- ...(resultData?.outputHeadTruncated === true ? { output: 'HEAD' } : {})
1052
+ ...(source.length > 10_000 || inputTruncated ? { input: true } : {}),
1053
+ ...(outputTruncation === undefined ? {} : { output: outputTruncation })
1056
1054
  }
1057
1055
  }
1058
1056
  : {}),
@@ -1068,6 +1066,12 @@ function genericToolItem(id, toolName, status, input, outputSummary = null, erro
1068
1066
  }),
1069
1067
  ...(codeOutput === undefined ? {} : { output: codeOutput })
1070
1068
  }, toolName);
1069
+ if (codeOutput === undefined && errorCode === null && outputSummary !== null) {
1070
+ item.payload.outputSummary = compactRunnerText(outputSummary, 10_000);
1071
+ if (summaryTruncated || outputSummary.length > 10_000)
1072
+ item.payload.outputSummaryTruncated = true;
1073
+ }
1074
+ return item;
1071
1075
  }
1072
1076
  if (toolName === 'code_exec_wait' || toolName === 'exec_wait') {
1073
1077
  const inputRecord = record(input);
@@ -1081,40 +1085,17 @@ function genericToolItem(id, toolName, status, input, outputSummary = null, erro
1081
1085
  ? [{ channel: 'STDERR', text: resultData.stderr }]
1082
1086
  : [])
1083
1087
  ];
1084
- const codeOutput = toolName === 'code_exec_wait' ? codeObservationOutput(resultData, outputSummary) : undefined;
1088
+ const codeOutput = toolName === 'code_exec_wait' ? codeObservationOutput(resultData, null) : undefined;
1085
1089
  const resultError = toolName === 'code_exec_wait' ? codeExecutionError(resultData) : undefined;
1086
1090
  const action = typeof inputRecord?.action === 'string' ? inputRecord.action : 'poll';
1087
1091
  const inputSummary = compactRunnerValue(input, 10_000);
1088
- const result = output === undefined ? null : compactRunnerValue(output, 10_000);
1089
- const resultSummary = [outputSummary, result?.text]
1090
- .filter((value, index, values) => typeof value === 'string' && value.length > 0 && values.indexOf(value) === index)
1091
- .join('\n');
1092
- const details = [
1093
- `Action: ${compactRunnerText(action, 128)}`,
1094
- `Input: ${inputSummary.text || '{}'}`,
1095
- resultSummary.length === 0 ? '' : `Result: ${compactRunnerText(resultSummary, 10_000)}`,
1096
- errorCode === null ? '' : `Error: ${compactRunnerText(errorCode, 80)}`
1097
- ]
1098
- .filter(Boolean)
1099
- .join('\n');
1100
- return commandItem({
1092
+ const item = commandItem({
1101
1093
  itemId: id,
1102
1094
  command: '',
1103
1095
  cwd: null,
1104
- outputPreview: status === 'IN_PROGRESS' && outputSummary !== null
1105
- ? outputSummary
1106
- : legacyBlocks.length > 0
1107
- ? legacyBlocks
1108
- .map((block) => block.text)
1109
- .filter(Boolean)
1110
- .join('\n')
1111
- : details,
1096
+ outputPreview: '',
1112
1097
  exitCode: typeof resultData?.exitCode === 'number' ? resultData.exitCode : null,
1113
- truncated: truncated ||
1114
- resultData?.truncated === true ||
1115
- inputSummary.truncated ||
1116
- result?.truncated === true ||
1117
- resultSummary.length > 10_000
1098
+ truncated: truncated || inputSummary.truncated
1118
1099
  }, status, toolName === 'code_exec_wait' ? 'Code execution wait' : 'Command wait', {
1119
1100
  kind: 'CONTROL',
1120
1101
  toolName,
@@ -1135,21 +1116,21 @@ function genericToolItem(id, toolName, status, input, outputSummary = null, erro
1135
1116
  }),
1136
1117
  ...(display === undefined && legacyBlocks.length > 0 ? { output: legacyBlocks } : {}),
1137
1118
  ...(codeOutput === undefined ? {} : { output: codeOutput }),
1138
- ...((typeof inputRecord?.data === 'string' && inputRecord.data.length > 10_000) ||
1139
- resultData?.outputHeadTruncated === true ||
1140
- (display !== undefined && (display.stdoutDroppedBytes || display.stderrDroppedBytes)) ||
1141
- (display === undefined && legacyBlocks.length > 0 && truncated)
1119
+ ...(inputTruncated ||
1120
+ (typeof inputRecord?.data === 'string' && inputRecord.data.length > 10_000) ||
1121
+ outputTruncation !== undefined ||
1122
+ (display !== undefined && (display.stdoutDroppedBytes || display.stderrDroppedBytes))
1142
1123
  ? {
1143
1124
  truncation: {
1144
- ...(typeof inputRecord?.data === 'string' && inputRecord.data.length > 10_000
1125
+ ...(inputTruncated ||
1126
+ (typeof inputRecord?.data === 'string' && inputRecord.data.length > 10_000)
1145
1127
  ? { input: true }
1146
1128
  : {}),
1147
- ...(resultData?.outputHeadTruncated === true ||
1148
- (display !== undefined &&
1149
- (display.stdoutDroppedBytes || display.stderrDroppedBytes))
1150
- ? { output: 'HEAD' }
1151
- : display === undefined && legacyBlocks.length > 0 && truncated
1152
- ? { output: 'SOURCE' }
1129
+ ...(outputTruncation !== undefined
1130
+ ? { output: outputTruncation }
1131
+ : display !== undefined &&
1132
+ (display.stdoutDroppedBytes || display.stderrDroppedBytes)
1133
+ ? { output: 'HEAD' }
1153
1134
  : {})
1154
1135
  }
1155
1136
  }
@@ -1165,8 +1146,32 @@ function genericToolItem(id, toolName, status, input, outputSummary = null, erro
1165
1146
  }
1166
1147
  })
1167
1148
  });
1149
+ if (display === undefined &&
1150
+ legacyBlocks.length === 0 &&
1151
+ codeOutput === undefined &&
1152
+ errorCode === null &&
1153
+ outputSummary !== null) {
1154
+ item.payload.outputSummary = compactRunnerText(outputSummary, 10_000);
1155
+ if (summaryTruncated || outputSummary.length > 10_000)
1156
+ item.payload.outputSummaryTruncated = true;
1157
+ }
1158
+ return item;
1168
1159
  }
1169
1160
  const subagent = marAgentSubagentProjection(toolName, input, output, subagentTitle, knownSubagentDetails);
1161
+ const agentOperation = agentOperationPresentation(toolName, input, output);
1162
+ if (agentOperation &&
1163
+ record(output)?.agentOperation === undefined &&
1164
+ typeof subagent?.subagentId === 'string') {
1165
+ agentOperation.targets = [
1166
+ {
1167
+ agentId: subagent.subagentId,
1168
+ ...(typeof subagent.subagentSessionId === 'string'
1169
+ ? { sessionId: subagent.subagentSessionId }
1170
+ : {}),
1171
+ ...(typeof subagent.title === 'string' ? { title: subagent.title } : {})
1172
+ }
1173
+ ];
1174
+ }
1170
1175
  const toolCategory = isImageGenerationTool(toolName) ? 'IMAGE_GENERATION' : undefined;
1171
1176
  const presentation = projectToolPresentation(toolName, input, output, sleepStartedAt);
1172
1177
  const inputSummary = compactRunnerValue(input, 10_000);
@@ -1179,13 +1184,20 @@ function genericToolItem(id, toolName, status, input, outputSummary = null, erro
1179
1184
  toolName: compactRunnerText(toolName, 128) || 'unknown',
1180
1185
  title: compactRunnerText(toolName, 500) || 'unknown',
1181
1186
  inputSummary: inputSummary.text || null,
1182
- outputSummary: outputSummary === null ? null : compactRunnerText(outputSummary, 10_000),
1183
- ...(outputSummary === null ? {} : { output: publicOutputSnapshot(outputSummary, truncated) }),
1187
+ outputSummary: typeof output === 'string' || errorCode !== null ? null : outputSummary,
1188
+ ...(typeof output === 'string' ? { output: publicToolOutput(output, outputTruncation) } : {}),
1189
+ ...(typeof output !== 'string' && outputSummary !== null && summaryTruncated
1190
+ ? { outputSummaryTruncated: true }
1191
+ : {}),
1184
1192
  progressLabel: status === 'IN_PROGRESS' ? 'Running' : null,
1185
1193
  errorCode: errorCode === null ? null : compactRunnerText(errorCode, 80),
1186
- truncated: truncated || inputSummary.truncated || (outputSummary?.length ?? 0) > 10_000,
1194
+ ...(errorCode !== null && outputSummary
1195
+ ? { errorMessage: compactRunnerText(outputSummary, 1000) }
1196
+ : {}),
1197
+ ...(inputTruncated || inputSummary.truncated ? { inputTruncated: true } : {}),
1187
1198
  ...(toolCategory === undefined ? {} : { toolCategory }),
1188
1199
  ...(presentation === undefined ? {} : { toolPresentation: presentation }),
1200
+ ...(agentOperation === undefined ? {} : { agentOperation }),
1189
1201
  ...subagent
1190
1202
  },
1191
1203
  merge: true
@@ -1294,7 +1306,14 @@ function commandItem(command, status, title, execution, toolName = 'exec') {
1294
1306
  ]
1295
1307
  })
1296
1308
  };
1297
- const bounded = boundExecutionPresentation({ toolName, ...detail });
1309
+ const { output: detailOutput, truncation, ...executionMetadata } = detail;
1310
+ const blocks = detailOutput ??
1311
+ (!detail.error && command.outputPreview
1312
+ ? [{ channel: 'COMBINED', text: command.outputPreview }]
1313
+ : undefined);
1314
+ const output = blocks === undefined
1315
+ ? undefined
1316
+ : boundToolOutput(blocks, command.outputTruncation ?? truncation?.output);
1298
1317
  return {
1299
1318
  itemId: command.itemId,
1300
1319
  kind: 'command_execution',
@@ -1303,22 +1322,17 @@ function commandItem(command, status, title, execution, toolName = 'exec') {
1303
1322
  ...(title === undefined ? {} : { title }),
1304
1323
  command: command.command,
1305
1324
  cwd: command.cwd,
1306
- outputPreview: command.outputPreview,
1307
- output: {
1308
- text: publicOutputSnapshot(bounded.presentation.execution.output
1309
- ?.map((block) => block.text)
1310
- .filter(Boolean)
1311
- .join('\n') ?? command.outputPreview).text,
1312
- truncated: command.truncated || bounded.truncated
1313
- },
1325
+ ...(output === undefined ? {} : { output }),
1314
1326
  exitCode: command.exitCode,
1315
1327
  durationMs: null,
1316
- truncated: command.truncated ||
1317
- command.inputTruncated === true ||
1318
- bounded.truncated ||
1319
- (display !== undefined &&
1320
- (display.stdoutDroppedBytes > 0 || display.stderrDroppedBytes > 0)),
1321
- toolPresentation: bounded.presentation
1328
+ toolPresentation: {
1329
+ kind: 'EXECUTION',
1330
+ execution: {
1331
+ toolName,
1332
+ ...executionMetadata,
1333
+ ...(truncation?.input ? { truncation: { input: true } } : {})
1334
+ }
1335
+ }
1322
1336
  },
1323
1337
  merge: true
1324
1338
  };
@@ -1421,8 +1435,8 @@ function execResult(value, summary, eventTruncated = false) {
1421
1435
  ...(exitCode === undefined ? {} : { exitCode }),
1422
1436
  ...(data?.cached === true || summaryData?.cached === true ? { cached: true } : {}),
1423
1437
  truncated: eventTruncated ||
1424
- data?.truncated === true ||
1425
- summaryData?.truncated === true ||
1438
+ (execDisplayOutput(data?.displayOutput) === undefined && data?.truncated === true) ||
1439
+ (data === undefined && summaryData?.truncated === true) ||
1426
1440
  structuredSummaryIncomplete
1427
1441
  };
1428
1442
  }
@@ -1458,14 +1472,11 @@ function marAgentSubagentProjection(toolName, input, output, knownTitle, knownDe
1458
1472
  ...(title.length === 0 ? {} : { title }),
1459
1473
  ...subagentPayload(details),
1460
1474
  ...(typeof details.latestMessage?.text === 'string'
1461
- ? {
1462
- outputSummary: boundedToolSummary(details.latestMessage.text),
1463
- output: publicOutputSnapshot(details.latestMessage.text, details.latestMessage.truncated === true)
1464
- }
1475
+ ? { outputSummary: null, output: undefined }
1465
1476
  : typeof outputData?.errorMessage === 'string'
1466
1477
  ? {
1467
- outputSummary: compactRunnerText(outputData.errorMessage, 10_000),
1468
- output: publicOutputSnapshot(outputData.errorMessage)
1478
+ outputSummary: null,
1479
+ output: publicToolOutput(outputData.errorMessage)
1469
1480
  }
1470
1481
  : {}),
1471
1482
  ...(typeof outputData?.errorCode === 'string'
@@ -15,7 +15,7 @@ export function projectMarAgentHistory(session, entries, options = {}) {
15
15
  runId: null,
16
16
  userItemId: null,
17
17
  status: 'INTERRUPTED',
18
- model: session.model,
18
+ model: session.modelId,
19
19
  effort: session.effort,
20
20
  access: session.access,
21
21
  rewind: { before: previous?.id ?? null, after: turnId },
@@ -470,7 +470,7 @@ export class MarAgentHostedConversationRuntime {
470
470
  function historySession(input) {
471
471
  return {
472
472
  id: input.sessionId,
473
- model: input.modelId ?? null,
473
+ modelId: input.modelId ?? null,
474
474
  effort: null,
475
475
  access: 'full-access'
476
476
  };
@@ -118,7 +118,7 @@ export class MarAgentManagedRunController {
118
118
  const execution = context.executionContext;
119
119
  const resolved = resolveMarAgentExecutionInput(execution?.runner === 'mar-agent'
120
120
  ? execution.runnerInput
121
- : undefined, session.model ?? '');
121
+ : undefined, session.modelId ?? '');
122
122
  if (resolved === undefined)
123
123
  throw new Error('RUNNER_COMMAND_UNAVAILABLE');
124
124
  const runId = randomUUID();
@@ -409,7 +409,7 @@ export class MarAgentManagedRunController {
409
409
  if (input.mode !== 'compact')
410
410
  this.#steerTargets.set(input.runId, async (request) => {
411
411
  if (controller.signal.aborted ||
412
- (request.model && request.model !== input.model.id) ||
412
+ (request.modelId && request.modelId !== input.model.id) ||
413
413
  (request.effort &&
414
414
  request.effort !==
415
415
  (reasoningEffort ??
@@ -232,7 +232,7 @@ export class MarAgentRunner extends AbstractRunner {
232
232
  if (configuration.runner !== this.name)
233
233
  return false;
234
234
  const profile = this.profileForValidation();
235
- const model = profile.models.find((candidate) => candidate.id === configuration.model);
235
+ const model = profile.models.find((candidate) => candidate.id === configuration.modelId);
236
236
  return (model !== undefined &&
237
237
  (model.supportedEfforts.length === 0
238
238
  ? configuration.effort === model.defaultEffort
@@ -246,7 +246,7 @@ export class MarAgentRunner extends AbstractRunner {
246
246
  const model = profile.models[0];
247
247
  return {
248
248
  runner: 'mar-agent',
249
- model: model?.id ?? '',
249
+ modelId: model?.id ?? '',
250
250
  effort: model?.defaultEffort ?? '',
251
251
  access: 'auto'
252
252
  };
@@ -357,7 +357,7 @@ export class MarAgentRunner extends AbstractRunner {
357
357
  }),
358
358
  ...(executionConfiguration?.modelId === undefined
359
359
  ? {}
360
- : { model: executionConfiguration.modelId }),
360
+ : { modelId: executionConfiguration.modelId }),
361
361
  ...(executionConfiguration?.reasoningEffort === undefined
362
362
  ? {}
363
363
  : { effort: executionConfiguration.reasoningEffort })
@@ -577,9 +577,9 @@ export class MarAgentRunner extends AbstractRunner {
577
577
  return [resolve(session.cwd), ...(generatedImages === undefined ? [] : [generatedImages])];
578
578
  }
579
579
  async readContextUsage(session) {
580
- if (session.externalSessionId === null || session.model === null)
580
+ if (session.externalSessionId === null || session.modelId === null)
581
581
  return undefined;
582
- const model = this.#models.find((candidate) => candidate.id === session.model);
582
+ const model = this.#models.find((candidate) => candidate.id === session.modelId);
583
583
  if (model === undefined)
584
584
  return undefined;
585
585
  let catalog;
@@ -1,3 +1,4 @@
1
+ import { boundToolOutput } from '@myagentroam/protocol';
1
2
  export function compactRunnerText(value, limit) {
2
3
  return value.length <= limit ? value : `${value.slice(0, Math.max(0, limit - 1))}…`;
3
4
  }
@@ -9,6 +10,10 @@ export function publicOutputSnapshot(value, truncated = false) {
9
10
  bounded = bounded.slice(1);
10
11
  return { text: bounded, truncated: truncated || text.length > 10_000 };
11
12
  }
13
+ export function publicToolOutput(value, truncation, channel = 'TEXT') {
14
+ const text = typeof value === 'string' ? value : compactRunnerValue(value, Number.MAX_SAFE_INTEGER).text;
15
+ return boundToolOutput(text ? [{ channel, text }] : [], truncation);
16
+ }
12
17
  export function compactRunnerValue(value, limit) {
13
18
  if (value === undefined || value === null)
14
19
  return { text: '', truncated: false };
@@ -51,7 +51,7 @@ export class OpenCodeManagedRunController {
51
51
  }
52
52
  compact(session, environment, initiatedByUserId) {
53
53
  if (session.externalSessionId === null ||
54
- session.model === null ||
54
+ session.modelId === null ||
55
55
  session.nativeControl !== 'MAR_MANAGED' ||
56
56
  this.host.hasActiveSessionLease(session.id))
57
57
  throw new Error('RUNNER_COMMAND_UNAVAILABLE');
@@ -78,7 +78,7 @@ export class OpenCodeManagedRunController {
78
78
  });
79
79
  this.host.emit(runId, 'run.started', { command: 'compact' }, 'STARTING');
80
80
  this.host.emitItem(runId, openCodeCompactionItem('opencode-compact', runId, false));
81
- void this.runCompact(runId, session.model);
81
+ void this.runCompact(runId, session.modelId);
82
82
  return {
83
83
  command: 'compact',
84
84
  run: this.host.run(runId),
@@ -1,4 +1,4 @@
1
- import { compactRunnerText, compactRunnerValue, publicOutputSnapshot } from '../normalization.js';
1
+ import { compactRunnerText, compactRunnerValue, publicToolOutput } from '../normalization.js';
2
2
  import { shellExecution } from '../execution-presentation.js';
3
3
  export function normalizeOpenCodeTool(toolName, state) {
4
4
  const status = state?.status === 'completed'
@@ -21,14 +21,14 @@ export function normalizeOpenCodeTool(toolName, state) {
21
21
  ? input.cmd
22
22
  : publicToolName, 10_000),
23
23
  cwd: typeof input?.cwd === 'string' ? compactRunnerText(input.cwd, 4_096) : null,
24
- outputPreview: typeof state?.output === 'string' ? compactRunnerText(state.output, 10_000) : '',
25
24
  exitCode: typeof state?.exitCode === 'number' ? state.exitCode : null,
26
25
  durationMs: null,
27
- truncated: typeof state?.output === 'string' && state.output.length > 10_000,
28
26
  ...(typeof state?.output === 'string'
29
- ? { output: publicOutputSnapshot(state.output) }
27
+ ? { output: publicToolOutput(state.output, undefined, 'COMBINED') }
30
28
  : {}),
31
- toolPresentation: shellExecution(typeof state?.output === 'string' ? state.output : undefined)
29
+ toolPresentation: shellExecution((typeof input?.command === 'string' && input.command.length > 10_000) ||
30
+ (typeof input?.cmd === 'string' && input.cmd.length > 10_000) ||
31
+ (typeof input?.cwd === 'string' && input.cwd.length > 4_096))
32
32
  }
33
33
  };
34
34
  return {
@@ -39,10 +39,10 @@ export function normalizeOpenCodeTool(toolName, state) {
39
39
  title: compactRunnerText(typeof state?.title === 'string' ? state.title : toolName, 500) ||
40
40
  publicToolName,
41
41
  inputSummary: compactRunnerValue(state?.input, 10_000).text || null,
42
- outputSummary: typeof state?.output === 'string' ? compactRunnerText(state.output, 10_000) : null,
42
+ outputSummary: null,
43
43
  progressLabel: null,
44
44
  errorCode: status === 'FAILED' ? 'OPENCODE_TOOL_FAILED' : null,
45
- truncated: false,
45
+ ...(compactRunnerValue(state?.input, 10_000).truncated ? { inputTruncated: true } : {}),
46
46
  ...(normalizedName === 'read'
47
47
  ? {
48
48
  toolPresentation: {
@@ -53,7 +53,7 @@ export function normalizeOpenCodeTool(toolName, state) {
53
53
  }
54
54
  }
55
55
  : {}),
56
- ...(typeof state?.output === 'string' ? { output: publicOutputSnapshot(state.output) } : {}),
56
+ ...(typeof state?.output === 'string' ? { output: publicToolOutput(state.output) } : {}),
57
57
  ...subagent
58
58
  }
59
59
  };
@@ -77,8 +77,8 @@ function openCodeSubagentProjection(toolName, input, output) {
77
77
  ...(nativeResult === undefined
78
78
  ? {}
79
79
  : {
80
- outputSummary: compactRunnerText(nativeResult.result, 10_000) || null,
81
- output: publicOutputSnapshot(nativeResult.result)
80
+ outputSummary: null,
81
+ output: publicToolOutput(nativeResult.result)
82
82
  })
83
83
  };
84
84
  }
@@ -147,7 +147,7 @@ export class OpenCodeRunner extends AbstractRunner {
147
147
  if (configuration.runner !== this.name)
148
148
  return false;
149
149
  const models = this.cachedModels(environment);
150
- const model = models.find((candidate) => candidate.id === configuration.model);
150
+ const model = models.find((candidate) => candidate.id === configuration.modelId);
151
151
  return (model !== undefined &&
152
152
  (model.supportedEfforts.length === 0 ||
153
153
  model.supportedEfforts.includes(configuration.effort)) &&
@@ -157,7 +157,7 @@ export class OpenCodeRunner extends AbstractRunner {
157
157
  const model = this.cachedModels(environment)[0];
158
158
  return {
159
159
  runner: this.name,
160
- model: model?.id ?? '',
160
+ modelId: model?.id ?? '',
161
161
  effort: model?.supportedEfforts[0] ?? '',
162
162
  access: 'default'
163
163
  };
@@ -377,11 +377,11 @@ export class OpenCodeRunner extends AbstractRunner {
377
377
  return value.id;
378
378
  }
379
379
  async executeCompact(session, environment) {
380
- if (session.externalSessionId === null || session.model === null)
380
+ if (session.externalSessionId === null || session.modelId === null)
381
381
  throw new Error('RUNNER_COMMAND_UNAVAILABLE');
382
382
  const client = this.managedClient(environment);
383
383
  try {
384
- return await client.summarize(session.cwd, session.externalSessionId, session.model);
384
+ return await client.summarize(session.cwd, session.externalSessionId, session.modelId);
385
385
  }
386
386
  finally {
387
387
  this.releaseManagedClient(client);
@@ -402,7 +402,7 @@ export class OpenCodeRunner extends AbstractRunner {
402
402
  const tokens = object(latest?.tokens);
403
403
  const cache = object(tokens?.cache);
404
404
  const usedTokens = positiveNumber(tokens?.input) + positiveNumber(cache?.read);
405
- const modelId = provider !== undefined && model !== undefined ? `${provider}/${model}` : session.model;
405
+ const modelId = provider !== undefined && model !== undefined ? `${provider}/${model}` : session.modelId;
406
406
  if (modelId === null || usedTokens <= 0)
407
407
  return undefined;
408
408
  const maxTokens = Date.now() >= this.contextLimitsExpiresAt ? undefined : this.contextLimits.get(modelId);