@myagentroam/agent 0.9.143 → 0.9.145

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.
@@ -9,15 +9,17 @@ export class AsyncQueue {
9
9
  push(value) {
10
10
  if (this.#closed || this.#discarded)
11
11
  return;
12
- const waiter = this.#waiters[this.#waiterOffset++];
12
+ const waiter = this.#waiters[this.#waiterOffset];
13
+ if (!waiter) {
14
+ this.#values.push(value);
15
+ return;
16
+ }
17
+ this.#waiterOffset++;
13
18
  if (this.#waiterOffset > 1024 && this.#waiterOffset * 2 > this.#waiters.length) {
14
19
  this.#waiters.splice(0, this.#waiterOffset);
15
20
  this.#waiterOffset = 0;
16
21
  }
17
- if (waiter)
18
- waiter({ value, done: false });
19
- else
20
- this.#values.push(value);
22
+ waiter({ value, done: false });
21
23
  }
22
24
  close() {
23
25
  if (this.#closed)
@@ -234,7 +234,7 @@ function collectCodeModeCandidates(input, groups, existingTargets, usageRatio) {
234
234
  const eligible = [];
235
235
  let protectedTokens = 0;
236
236
  let retryAfterRollouts = Infinity;
237
- for (const group of [...groups.values()].filter((item) => ['code_mode', 'code_exec', 'code_exec_wait'].includes(item.toolName))) {
237
+ for (const group of [...groups.values()].filter((item) => ['code_exec', 'code_exec_wait'].includes(item.toolName))) {
238
238
  if (!group.call ||
239
239
  !group.result ||
240
240
  group.failed ||
@@ -134,7 +134,7 @@ export function restoreModelContext(payload, providerModelId) {
134
134
  : nativeItem?.type === 'custom_tool_call'
135
135
  ? nativeItem.name
136
136
  : undefined;
137
- const inputLimit = toolName === 'code_mode' || toolName === 'code_exec' || toolName === 'code_exec_wait'
137
+ const inputLimit = toolName === 'code_exec' || toolName === 'code_exec_wait'
138
138
  ? TOOL_EXECUTION_LIMITS.codeMaxInputBytes
139
139
  : toolName === 'apply_patch'
140
140
  ? TOOL_EXECUTION_LIMITS.patchMaxBytes
@@ -562,7 +562,7 @@ export function createSessionOpener(services) {
562
562
  .slice(contextualWorldState.entries.findLast((entry) => entry.kind === 'resources')
563
563
  ?.index ?? 0)
564
564
  .some((message) => message.role === 'tool_call' &&
565
- ['exec', 'code_exec', 'code_mode', 'agent_start'].includes(message.name ?? '')))
565
+ ['exec', 'code_exec', 'agent_start'].includes(message.name ?? '')))
566
566
  });
567
567
  sessionRuntime.contextualWorldState = contextualWorldState;
568
568
  if (!isDeepStrictEqual(previousContextualWorldState, contextualWorldState))
@@ -52,7 +52,7 @@ export type ContextGcReplacement = {
52
52
  readonly evidenceSequences: readonly number[];
53
53
  } | {
54
54
  readonly kind: 'TOOL_CALL_INPUT';
55
- readonly toolName: 'apply_patch' | 'exec' | 'exec_wait' | 'code_mode' | 'code_exec';
55
+ readonly toolName: 'apply_patch' | 'exec' | 'exec_wait' | 'code_exec';
56
56
  readonly callId: string;
57
57
  readonly target: ContextGcTarget;
58
58
  readonly replacementArguments: unknown;
@@ -295,8 +295,7 @@ function replacementMatchesRecords(replacement, records, recordsBySequence, work
295
295
  result !== undefined &&
296
296
  isDeepStrictEqual(replacement.replacementArguments, contextGcApplyPatchInputReplacement(source.payload.arguments, result, replacement.evidenceSequence, applyPatchReplacementFormatVersion(replacement.replacementArguments))));
297
297
  }
298
- if (replacement.kind === 'TOOL_CALL_INPUT' &&
299
- (replacement.toolName === 'code_mode' || replacement.toolName === 'code_exec')) {
298
+ if (replacement.kind === 'TOOL_CALL_INPUT' && replacement.toolName === 'code_exec') {
300
299
  const evidence = successfulToolEvidence(records, recordsBySequence, replacement.evidenceSequence, replacement.toolName);
301
300
  const input = normalizeContextGcCodeModeInput(source.payload.arguments);
302
301
  return (evidence?.callId === replacement.callId &&
@@ -308,7 +307,7 @@ function replacementMatchesRecords(replacement, records, recordsBySequence, work
308
307
  : [])));
309
308
  }
310
309
  if (replacement.kind === 'CODE_MODE_OUTPUT') {
311
- const evidence = ['code_mode', 'code_exec', 'code_exec_wait']
310
+ const evidence = ['code_exec', 'code_exec_wait']
312
311
  .map((name) => successfulToolEvidence(records, recordsBySequence, replacement.evidenceSequence, name))
313
312
  .find((item) => item !== undefined);
314
313
  return (evidence?.callId === replacement.callId &&
@@ -715,7 +714,6 @@ function isContextGcReplacement(value) {
715
714
  (value.toolName === 'apply_patch' ||
716
715
  value.toolName === 'exec' ||
717
716
  value.toolName === 'exec_wait' ||
718
- value.toolName === 'code_mode' ||
719
717
  value.toolName === 'code_exec') &&
720
718
  value.target.toolName === value.toolName &&
721
719
  Array.isArray(value.providerAliasTargets) &&
@@ -20,7 +20,7 @@ export function codeObservationEvidence(records, result, observation) {
20
20
  isRecord(record.payload) &&
21
21
  record.payload.role === 'tool_call' &&
22
22
  record.payload.callId === parentId &&
23
- (record.payload.name === 'code_exec' || record.payload.name === 'code_mode'));
23
+ record.payload.name === 'code_exec');
24
24
  if (!parent)
25
25
  return undefined;
26
26
  const original = records.find((record) => record.recordId === result.recordId) ?? result;
@@ -31,9 +31,7 @@ export function codeObservationEvidence(records, result, observation) {
31
31
  record.type === 'tool.completed' &&
32
32
  isRecord(record.payload) &&
33
33
  record.payload.callId === outerId &&
34
- (record.payload.toolName === 'code_exec' ||
35
- record.payload.toolName === 'code_mode' ||
36
- record.payload.toolName === 'code_exec_wait'));
34
+ (record.payload.toolName === 'code_exec' || record.payload.toolName === 'code_exec_wait'));
37
35
  if (!outer ||
38
36
  codeCellCompletionSequence(records, outer) === undefined ||
39
37
  records.some((record) => record.sequence < result.sequence &&
@@ -324,8 +324,6 @@ function isNonnegativeInteger(value) {
324
324
  export function codeCellCompletionSequence(records, completed) {
325
325
  if (!isRecord(completed.payload))
326
326
  return undefined;
327
- if (completed.payload.toolName === 'code_mode')
328
- return completed.sequence;
329
327
  const data = completed.payload.data;
330
328
  if (!isRecord(data) || typeof data.cellId !== 'string')
331
329
  return undefined;
@@ -13,7 +13,7 @@ export function toolCallers(tool) {
13
13
  export function allowsToolCaller(tool, caller) {
14
14
  // Control tools cannot be widened by a Host override or historical definition.
15
15
  if (caller === 'programmatic' &&
16
- ['code_exec', 'code_exec_wait', 'code_mode', 'tool_search', 'question', 'skill'].includes(tool.name))
16
+ ['code_exec', 'code_exec_wait', 'tool_search', 'question', 'skill'].includes(tool.name))
17
17
  return false;
18
18
  return toolCallers(tool).includes(caller);
19
19
  }
@@ -9,7 +9,9 @@ export class CodeCellExecutionError extends MarAgentError {
9
9
  result;
10
10
  constructor(error, result) {
11
11
  const diagnostic = describeMarAgentError(error, 'MAR_AGENT_CODE_FAILED');
12
- super(diagnostic.code, diagnostic.message.replace(`${diagnostic.code}: `, ''), {
12
+ super(diagnostic.code, diagnostic.message.startsWith(`${diagnostic.code}: `)
13
+ ? diagnostic.message.slice(diagnostic.code.length + 2)
14
+ : diagnostic.message, {
13
15
  cause: error,
14
16
  ...(error instanceof MarAgentError ? { retryable: error.retryable } : {})
15
17
  });
@@ -79,7 +81,7 @@ export class CodeCells {
79
81
  throw new MarAgentError('MAR_AGENT_CODE_CANCELLED', 'Code Exec resources are being released.');
80
82
  if ([...this.#cells.values()].filter((cell) => cell.status === 'running').length >=
81
83
  limits.codeMaxConcurrentCells)
82
- throw new MarAgentError('MAR_AGENT_PROCESS_LIMIT', 'The Code Exec cell limit was reached.');
84
+ throw new MarAgentError('MAR_AGENT_PROCESS_LIMIT', `The Local Host shared running-cell limit (${limits.codeMaxConcurrentCells}) was reached.`);
83
85
  const controller = new AbortController();
84
86
  const cell = {
85
87
  cellId: randomUUID(),
@@ -30,7 +30,7 @@ Tool calls:
30
30
  - skill, tool_search, question, code_exec, code_exec_wait and direct-only tools cannot be called here. Load Skills directly and read their instructions before the next tool call. Use direct tool_search before a later code cell for deferred tools; the current cell's tools do not change.
31
31
 
32
32
  Built-in namespaces:
33
- - observe.result(result): void registers an unmodified complete tools.NAME result or caught tool error as a trusted tool_result, using the original text and all images without repeating program data. Non-original, copied or modified values are rejected. This selects evidence for the next model response, not a log and not a new model call.
33
+ - observe.result(result): void registers an unmodified complete tools.NAME result or caught tool error as a trusted tool_result, using the original text and all images without repeating program data. Non-original, copied or modified values are rejected. This selects evidence for the next model response, not a log and not a new model call. Prefer observe.result for inspecting tool results.
34
34
  - observe.text(value): void registers bounded text/JSON values. observe.image(value): void registers one image value using the existing capability, MIME, byte and count limits. Both accept original tool results for compatibility and use the same complete tool_result observation path; they do not select part of an original result. Extracted single images, copies and computed summaries are value observations, never trusted tool results. Observations are returned in registration order. Only explicitly observed evidence reaches the model; registration does not prove inspection. Sources and types are runtime-assigned. No out or callable observe(value) alias exists.
35
35
  - state.get(key), state.has(key), state.set(key, value), state.delete(key) access bounded session JSON state. Mutations commit atomically only when the cell succeeds; failed or cancelled cells discard them.
36
36
  - catalog.tools() returns a read-only snapshot of the tools callable in this cell, including name, description, inputSchema and inputMode. It does not discover or authorize additional tools.
@@ -218,7 +218,7 @@ export class CodeModeTool {
218
218
  throw new MarAgentError('MAR_AGENT_TOOL_NOT_AVAILABLE', 'Code Mode tool dispatch is unavailable.');
219
219
  context.signal.throwIfAborted();
220
220
  if (this.#active.size >= limits.codeMaxConcurrentCells)
221
- throw new MarAgentError('MAR_AGENT_PROCESS_LIMIT', 'The Code Mode process limit was reached.');
221
+ throw new MarAgentError('MAR_AGENT_PROCESS_LIMIT', `The Local Host shared running-cell limit (${limits.codeMaxConcurrentCells}) was reached.`);
222
222
  const controller = new AbortController();
223
223
  const signal = AbortSignal.any([context.signal, controller.signal]);
224
224
  let release;
@@ -526,7 +526,13 @@ export class CodeModeTool {
526
526
  await write({
527
527
  id,
528
528
  ok: false,
529
- error: { code: diagnostic.code, message: diagnostic.message }
529
+ error: {
530
+ code: diagnostic.code,
531
+ // The guest carries the code separately; the outer error adds its own prefix.
532
+ message: diagnostic.message.startsWith(`${diagnostic.code}: `)
533
+ ? diagnostic.message.slice(diagnostic.code.length + 2)
534
+ : diagnostic.message
535
+ }
530
536
  });
531
537
  }
532
538
  })().catch(fail);
@@ -34,19 +34,27 @@ export async function createCodeModeEngine(options) {
34
34
  wake?.();
35
35
  wake = undefined;
36
36
  };
37
- const fail = (handle) => {
37
+ const fail = (handle, locateSource = false) => {
38
38
  const error = vm.dump(handle);
39
39
  handle.dispose();
40
40
  if (input.signal.aborted)
41
41
  throw input.signal.reason;
42
42
  if (Date.now() >= deadline)
43
43
  throw diagnostic('MAR_AGENT_CODE_TIMEOUT', 'JavaScript execution exceeded its deadline.');
44
- const message = String(error?.message ?? error).slice(0, 4096);
44
+ let message = String(error?.message ?? error).slice(0, 4096);
45
+ const syntaxError = locateSource && error?.name === 'SyntaxError';
46
+ if (syntaxError)
47
+ message = `JavaScript compilation failed before tool execution: ${message}`.slice(0, 4096);
48
+ const location = locateSource ? compilerSourceLocation(error, input.code) : '';
49
+ if (location)
50
+ message = message.slice(0, 4096 - location.length) + location;
45
51
  const code = message.includes('out of memory')
46
52
  ? 'MAR_AGENT_CODE_MEMORY_LIMIT'
47
- : typeof error?.code === 'string'
48
- ? error.code
49
- : 'MAR_AGENT_CODE_FAILED';
53
+ : syntaxError
54
+ ? 'MAR_AGENT_CODE_SYNTAX_ERROR'
55
+ : typeof error?.code === 'string'
56
+ ? error.code
57
+ : 'MAR_AGENT_CODE_FAILED';
50
58
  throw diagnostic(code, message);
51
59
  };
52
60
  const guestError = (code, message) => {
@@ -476,7 +484,7 @@ export async function createCodeModeEngine(options) {
476
484
  try {
477
485
  const evaluated = vm.evalCode(`(async () => {\n${input.code}\n})()`, 'code-mode.js');
478
486
  if (evaluated.error)
479
- fail(evaluated.error);
487
+ fail(evaluated.error, true);
480
488
  main = evaluated.value;
481
489
  for (;;) {
482
490
  input.signal.throwIfAborted();
@@ -625,6 +633,30 @@ function streamText(value, emit) {
625
633
  };
626
634
  write(value, '');
627
635
  }
636
+ function compilerSourceLocation(error, source) {
637
+ if (error?.name !== 'SyntaxError' ||
638
+ error.fileName !== 'code-mode.js' ||
639
+ !Number.isSafeInteger(error.lineNumber) ||
640
+ error.lineNumber <= 1)
641
+ return '';
642
+ // QuickJS counts LF lines and Unicode code-point columns; the wrapper adds one LF line.
643
+ const lines = source.split('\n');
644
+ const line = error.lineNumber - 1;
645
+ if (line > lines.length)
646
+ return ` (code-mode.js:${source.split(/\r\n|[\r\n\u2028\u2029]/u).length}, end of input)`;
647
+ const column = Number(typeof error.stack === 'string'
648
+ ? error.stack.match(/^\s*at code-mode\.js:\d+:(\d+)(?:\n|$)/u)?.[1]
649
+ : undefined);
650
+ if (!Number.isSafeInteger(column) || column < 1)
651
+ return '';
652
+ const prefix = [
653
+ ...lines.slice(0, line - 1),
654
+ Array.from(lines[line - 1])
655
+ .slice(0, column - 1)
656
+ .join('')
657
+ ].join('\n');
658
+ return ` (code-mode.js:${prefix.split(/\r\n|[\r\n\u2028\u2029]/u).length})`;
659
+ }
628
660
  function diagnostic(code, message) {
629
661
  return Object.assign(new Error(message), { code });
630
662
  }
@@ -13,7 +13,7 @@ export declare const TOOL_EXECUTION_LIMITS: Readonly<{
13
13
  execMaxPollYieldMs: 300000;
14
14
  execTerminationGraceMs: 1000;
15
15
  execDefaultMaxOutputBytes: 1000000;
16
- maxProcesses: 8;
16
+ maxProcesses: 64;
17
17
  execMaxCompletedResults: 16;
18
18
  execCompletedRetentionMs: 300000;
19
19
  codeMaxInputBytes: 1048576;
@@ -21,7 +21,7 @@ export declare const TOOL_EXECUTION_LIMITS: Readonly<{
21
21
  codeMaxFrameBytes: 33554432;
22
22
  codeMaxTransportBytes: 67108864;
23
23
  codeMaxCalls: 128;
24
- codeMaxConcurrentCells: 4;
24
+ codeMaxConcurrentCells: 64;
25
25
  codeDefaultYieldMs: 30000;
26
26
  codeDefaultWaitYieldMs: 10000;
27
27
  codeMaxYieldMs: 30000;
@@ -13,7 +13,7 @@ export const TOOL_EXECUTION_LIMITS = Object.freeze({
13
13
  execMaxPollYieldMs: 300_000,
14
14
  execTerminationGraceMs: 1_000,
15
15
  execDefaultMaxOutputBytes: 1_000_000,
16
- maxProcesses: 8,
16
+ maxProcesses: 64,
17
17
  execMaxCompletedResults: 16,
18
18
  execCompletedRetentionMs: 300_000,
19
19
  codeMaxInputBytes: 1_048_576,
@@ -21,7 +21,7 @@ export const TOOL_EXECUTION_LIMITS = Object.freeze({
21
21
  codeMaxFrameBytes: 33_554_432,
22
22
  codeMaxTransportBytes: 67_108_864,
23
23
  codeMaxCalls: 128,
24
- codeMaxConcurrentCells: 4,
24
+ codeMaxConcurrentCells: 64,
25
25
  codeDefaultYieldMs: 30_000,
26
26
  codeDefaultWaitYieldMs: 10_000,
27
27
  codeMaxYieldMs: 30_000,
@@ -161,7 +161,7 @@ export class ExecTool {
161
161
  return result;
162
162
  }
163
163
  if (this.#processes.size + this.#startingProcesses.size >= this.maxProcesses)
164
- throw new MarAgentError('MAR_AGENT_PROCESS_LIMIT', 'The managed process limit was reached.');
164
+ throw new MarAgentError('MAR_AGENT_PROCESS_LIMIT', `The Local Host shared managed-process limit (${this.maxProcesses}) was reached.`);
165
165
  let resolveStarting;
166
166
  const starting = {
167
167
  ...(owner === undefined ? {} : { ownerSessionId: owner.sessionId }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.9.143",
3
+ "version": "0.9.145",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",