@myagentroam/agent 0.10.18 → 0.10.20
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.
|
@@ -27,10 +27,11 @@ export const codeModeToolDefinition = {
|
|
|
27
27
|
- Single-tool cells are valid. Keep loops and retries bounded, and do not blindly replay operations with side effects.
|
|
28
28
|
- Evaluates source in a fresh restricted ECMAScript runtime with top-level await and Promise.all. It is not Node.js or a browser. JavaScript globals do not survive between cells; bounded JSON state is available through state.
|
|
29
29
|
- Accepts JavaScript source text. When exposed as a freeform tool, send the source directly; when exposed with a JSON input schema, put the source in its code field. Do not add another JSON wrapper, quoted string, or markdown code fence inside the source.
|
|
30
|
+
- Keep embedded commands, patches and source in JSON-escaped double-quoted strings when they contain backticks or literal \${...}; JavaScript template literals would interpolate them before the tool runs. Do not paste Python literals such as None into JavaScript expressions.
|
|
30
31
|
- Use only standard ECMAScript built-ins and the explicitly documented tools, observe, state, catalog and cell namespaces. Do not use Node.js, browser or Web APIs. Module imports, filesystem and network APIs are unavailable. Obtain external capabilities only through available tools. Use tools.exec to start managed processes when permitted; use tools.exec_wait afterward to wait, write stdin or cancel.
|
|
31
32
|
|
|
32
33
|
Tool calls:
|
|
33
|
-
- tools.NAME(input) returns a Promise. Use the existing tool input schema; freeform tools such as apply_patch accept a raw string, not a JSON wrapper.
|
|
34
|
+
- tools.NAME(input) returns a Promise. Use the existing tool input schema; freeform tools such as apply_patch accept a raw string, not a JSON wrapper. For parameterless tools prefer tools.NAME({}); tools.NAME() is accepted only for explicitly closed empty-object schemas.
|
|
34
35
|
- Results use the MAR envelope: { content?: string, data?: unknown, images?: Array<{mimeType:string,dataBase64:string}>, truncated?: boolean }. Redundant JSON content is omitted when it exactly renders data; independent text remains in content. Prefer data for programmatic results: result.data.results[0].text for read source text and result.data.exitCode/result.data.stdout for exec. content, when present, is rendered text, not raw file bytes. Use only fields documented by that tool; do not invent success or ok flags.
|
|
35
36
|
- Tool errors reject with code/message and may be caught. A failed cell preserves already emitted output alongside its status and error; completed tool effects are not rolled back. Inspect it before retrying completed work. Await every call; unawaited calls fail the cell. Use Promise.all for independent calls and sequential await for dependencies. Runtime preserves safe/serial barriers and Host checks.
|
|
36
37
|
- 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.
|
|
@@ -224,10 +224,13 @@ export async function createCodeModeEngine(options) {
|
|
|
224
224
|
return guestError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Code Mode state is too large.');
|
|
225
225
|
};
|
|
226
226
|
const tools = vm.newObject();
|
|
227
|
+
const parameterlessTools = new Set(input.catalog.filter(isParameterlessTool).map((tool) => tool.name));
|
|
227
228
|
let toolCallSequence = 0;
|
|
228
229
|
for (const name of input.tools) {
|
|
229
230
|
method(tools, name, (args = vm.undefined) => {
|
|
230
|
-
const parsed =
|
|
231
|
+
const parsed = vm.typeof(args) === 'undefined' && parameterlessTools.has(name)
|
|
232
|
+
? { value: {} }
|
|
233
|
+
: jsonValue(args, true);
|
|
231
234
|
if (parsed.error)
|
|
232
235
|
return parsed;
|
|
233
236
|
const operationId = ++toolCallSequence;
|
|
@@ -704,19 +707,64 @@ function compilerSourceLocation(error, source) {
|
|
|
704
707
|
const lines = source.split('\n');
|
|
705
708
|
const line = error.lineNumber - 1;
|
|
706
709
|
if (line > lines.length)
|
|
707
|
-
return
|
|
710
|
+
return compilerCaret(source, source, true);
|
|
708
711
|
const column = Number(typeof error.stack === 'string'
|
|
709
712
|
? error.stack.match(/^\s*at code-mode\.js:\d+:(\d+)(?:\n|$)/u)?.[1]
|
|
710
713
|
: undefined);
|
|
711
|
-
if (!Number.isSafeInteger(column) ||
|
|
712
|
-
|
|
714
|
+
if (!Number.isSafeInteger(column) ||
|
|
715
|
+
column < 1 ||
|
|
716
|
+
column > Array.from(lines[line - 1]).length + 1) {
|
|
717
|
+
// Without a valid column, intra-LF-line separators make the original source line ambiguous.
|
|
718
|
+
if (/[\r\u2028\u2029]/u.test(lines[line - 1].replace(/\r$/u, '')))
|
|
719
|
+
return '';
|
|
720
|
+
const preceding = line > 1 ? lines.slice(0, line - 1).join('\n') + '\n' : '';
|
|
721
|
+
return ` (code-mode.js:${preceding.split(/\r\n|[\r\n\u2028\u2029]/u).length})`;
|
|
722
|
+
}
|
|
713
723
|
const prefix = [
|
|
714
724
|
...lines.slice(0, line - 1),
|
|
715
725
|
Array.from(lines[line - 1])
|
|
716
726
|
.slice(0, column - 1)
|
|
717
727
|
.join('')
|
|
718
728
|
].join('\n');
|
|
719
|
-
return
|
|
729
|
+
return compilerCaret(source, prefix);
|
|
730
|
+
}
|
|
731
|
+
function compilerCaret(source, prefix, endOfInput = false) {
|
|
732
|
+
const segments = prefix.split(/\r\n|[\r\n\u2028\u2029]/u);
|
|
733
|
+
const line = segments.length;
|
|
734
|
+
const column = Array.from(segments.at(-1)).length + 1;
|
|
735
|
+
const character = source.slice(prefix.length)[Symbol.iterator]().next().value;
|
|
736
|
+
// Source may contain credentials, commands or private code. Show only a punctuation token.
|
|
737
|
+
const token = endOfInput
|
|
738
|
+
? '<end of input>'
|
|
739
|
+
: character === undefined || /[\r\n\u2028\u2029]/u.test(character)
|
|
740
|
+
? '<end of line>'
|
|
741
|
+
: /^[{}[\]():;,.=+*/?!<>|&%\-]$/u.test(character)
|
|
742
|
+
? character
|
|
743
|
+
: '<character omitted>';
|
|
744
|
+
const preview = '<source omitted>';
|
|
745
|
+
return ` (code-mode.js:${line}${endOfInput ? ', end of input' : ''})\nSyntax location: line ${line}, column ${column}\n${line} | ${preview}${token}\n${' '.repeat(String(line).length)} | ${' '.repeat(preview.length)}^`;
|
|
746
|
+
}
|
|
747
|
+
function isParameterlessTool(tool) {
|
|
748
|
+
const schema = tool.inputSchema;
|
|
749
|
+
return (tool.inputMode === 'json' &&
|
|
750
|
+
schema?.type === 'object' &&
|
|
751
|
+
schema.additionalProperties === false &&
|
|
752
|
+
schema.properties !== null &&
|
|
753
|
+
typeof schema.properties === 'object' &&
|
|
754
|
+
!Array.isArray(schema.properties) &&
|
|
755
|
+
Object.keys(schema.properties).length === 0 &&
|
|
756
|
+
(schema.required === undefined ||
|
|
757
|
+
(Array.isArray(schema.required) && schema.required.length === 0)) &&
|
|
758
|
+
Object.keys(schema).every((key) => [
|
|
759
|
+
'type',
|
|
760
|
+
'properties',
|
|
761
|
+
'additionalProperties',
|
|
762
|
+
'required',
|
|
763
|
+
'title',
|
|
764
|
+
'description',
|
|
765
|
+
'$schema',
|
|
766
|
+
'$comment'
|
|
767
|
+
].includes(key)));
|
|
720
768
|
}
|
|
721
769
|
function diagnostic(code, message) {
|
|
722
770
|
return Object.assign(new Error(message), { code });
|
|
@@ -91,7 +91,7 @@ class FreeformPatchParser {
|
|
|
91
91
|
throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Patch exceeds the file limit.');
|
|
92
92
|
}
|
|
93
93
|
if (!changes.some((change) => change.kind !== 'update' || change.targetPath || change.hunks.some((hunk) => !hunk.anchor)))
|
|
94
|
-
this.#fail('Patch must change or move at least one file.', 1);
|
|
94
|
+
this.#fail('Patch must change or move at least one file. No additions, deletions, or moves were supplied; context-only hunks only validate existing lines. Use read to inspect a file, or supply -old/+new lines to edit it.', 1);
|
|
95
95
|
return changes;
|
|
96
96
|
}
|
|
97
97
|
#marker(index, marker, position) {
|