@myagentroam/agent 0.9.135 → 0.9.137
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.
- package/dist/cli/main.js +1 -1
- package/dist/host/local-agent-host.d.ts +9 -7
- package/dist/host/local-agent-host.js +77 -5
- package/dist/host/local-process-executor.d.ts +2 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -0
- package/dist/model/catalog-file.d.ts +2 -0
- package/dist/model/configuration.d.ts +5 -0
- package/dist/model/configuration.js +8 -0
- package/dist/model/contracts.d.ts +7 -0
- package/dist/model/openai-responses.d.ts +1 -1
- package/dist/model/openai-responses.js +85 -20
- package/dist/prompts/index.d.ts +2 -1
- package/dist/prompts/index.js +2 -2
- package/dist/prompts/workflow.d.ts +1 -1
- package/dist/prompts/workflow.js +9 -2
- package/dist/runtime/context-gc-runtime.d.ts +1 -0
- package/dist/runtime/context-gc-runtime.js +3 -0
- package/dist/runtime/context-gc-tokens.d.ts +1 -0
- package/dist/runtime/context-gc-tokens.js +1 -1
- package/dist/runtime/context-gc.d.ts +1 -0
- package/dist/runtime/context-gc.js +85 -8
- package/dist/runtime/context-projection.js +19 -2
- package/dist/sandbox/linux/bubblewrap-sandbox-executor.js +29 -2
- package/dist/sdk/agent.js +249 -26
- package/dist/sdk/mcp-catalog.d.ts +13 -0
- package/dist/sdk/mcp-catalog.js +219 -0
- package/dist/sdk/types.d.ts +53 -1
- package/dist/session/context-gc-checkpoint.d.ts +7 -1
- package/dist/session/context-gc-checkpoint.js +28 -2
- package/dist/session/context-gc-replacements.d.ts +7 -0
- package/dist/session/context-gc-replacements.js +26 -0
- package/dist/session/jsonl-store.d.ts +6 -0
- package/dist/session/jsonl-store.js +92 -54
- package/dist/subagent/scheduler.d.ts +3 -3
- package/dist/subagent/session-controller.d.ts +1 -1
- package/dist/tools/agent-cancel.js +1 -0
- package/dist/tools/agent-message.js +1 -0
- package/dist/tools/agent-start.js +1 -0
- package/dist/tools/agent-wait.js +1 -0
- package/dist/tools/apply-patch.js +2 -1
- package/dist/tools/callers.d.ts +6 -0
- package/dist/tools/callers.js +23 -0
- package/dist/tools/code-mode/engine.d.ts +43 -0
- package/dist/tools/code-mode/engine.js +1 -0
- package/dist/tools/code-mode/quickjs-engine.d.ts +2 -0
- package/dist/tools/code-mode/quickjs-engine.js +454 -0
- package/dist/tools/code-mode/state.d.ts +20 -0
- package/dist/tools/code-mode/state.js +82 -0
- package/dist/tools/code-mode/worker.d.ts +1 -0
- package/dist/tools/code-mode/worker.js +65 -0
- package/dist/tools/code-mode.d.ts +8 -4
- package/dist/tools/code-mode.js +154 -120
- package/dist/tools/exec.js +1 -0
- package/dist/tools/execution-limits.d.ts +8 -0
- package/dist/tools/execution-limits.js +8 -0
- package/dist/tools/local-registry.d.ts +2 -0
- package/dist/tools/local-registry.js +1 -1
- package/dist/tools/question.js +1 -0
- package/dist/tools/read.js +1 -0
- package/dist/tools/registry.js +3 -0
- package/dist/tools/runtime-context.d.ts +2 -0
- package/dist/tools/runtime.js +3 -1
- package/dist/tools/skill.js +1 -0
- package/dist/tools/todo-read.js +1 -0
- package/dist/tools/todo-write.js +1 -0
- package/dist/tools/tool-search.d.ts +43 -0
- package/dist/tools/tool-search.js +284 -0
- package/dist/tools/view-image.js +1 -0
- package/dist/tools/web-fetch.js +1 -0
- package/dist/tools/web-search.js +1 -0
- package/package.json +3 -1
package/dist/tools/code-mode.js
CHANGED
|
@@ -1,13 +1,58 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { readFile } from 'node:fs/promises';
|
|
5
|
+
import { dirname, sep } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
2
7
|
import { StringDecoder } from 'node:string_decoder';
|
|
3
8
|
import { MarAgentError, describeMarAgentError } from '../error.js';
|
|
4
9
|
import { directLocalProcessExecutor, signalProcessTree } from '../host/local-process-executor.js';
|
|
5
10
|
import { TOOL_EXECUTION_LIMITS as limits } from './execution-limits.js';
|
|
6
11
|
import { createToolCallScheduler } from './scheduler.js';
|
|
7
12
|
import { detectImageMime } from './view-image.js';
|
|
13
|
+
import { allowsDirectTool, allowsToolCaller } from './callers.js';
|
|
14
|
+
import { parseCodeModeStateMutations } from './code-mode/state.js';
|
|
8
15
|
export const codeModeToolDefinition = {
|
|
9
16
|
name: 'code_mode',
|
|
10
|
-
description:
|
|
17
|
+
description: `Run JavaScript to orchestrate or compose tool calls.
|
|
18
|
+
- Code Mode Only: call the programmatic tools listed below through tools.NAME inside this tool, including single-tool operations. They are omitted from the top-level tool list. Direct-only tools remain separate model tools and cannot be called here.
|
|
19
|
+
- Use bounded combinations, parallel independent calls, and filtering of large intermediate results to reduce model round trips.
|
|
20
|
+
- 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.
|
|
21
|
+
- Accepts raw JavaScript source text, not JSON, quoted strings, or markdown code fences. Responses uses the source directly; Anthropic uses the code field of its tool input object. In either case, do not quote or fence the source again.
|
|
22
|
+
- Use only standard ECMAScript built-ins and the explicitly documented tools, out, 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 for managed background processes when permitted.
|
|
23
|
+
|
|
24
|
+
Tool calls:
|
|
25
|
+
- 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.
|
|
26
|
+
- Results use the MAR envelope: { content: string, data?: unknown, images?: Array<{mimeType:string,dataBase64:string}>, truncated?: boolean }. content is rendered text, not raw file bytes. Use result.data.results[0].text for read source text and result.data.exitCode/result.data.stdout for exec. Use only fields documented by that tool; do not invent success or ok flags.
|
|
27
|
+
- Tool errors reject with code/message and may be caught. 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.
|
|
28
|
+
- tool_search, question, code_mode and direct-only tools cannot be called here. Use direct tool_search before a later code cell for deferred tools; the current cell's tools do not change.
|
|
29
|
+
|
|
30
|
+
Built-in namespaces:
|
|
31
|
+
- out.text(value): void emits text. Strings and scalar values are stringified; JSON-compatible objects/arrays are serialized as compact JSON. Cyclic or unsupported object values fail. Only explicitly emitted output reaches the model.
|
|
32
|
+
- out.image(value: {mimeType:string,dataBase64:string}): void emits one returned image; for example out.image(result.images[0]) when that image exists and the model supports images. It does not accept a path, URL, or result.content.
|
|
33
|
+
- 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.
|
|
34
|
+
- 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.
|
|
35
|
+
- await cell.sleep(ms) performs a cancellable Host-side delay up to 30000 ms and remains subject to the cell deadline.
|
|
36
|
+
- tools, out, state, catalog and cell are frozen bindings. Do not shadow their names.
|
|
37
|
+
- Input/text output max 1 MiB, 128 calls, 120 seconds. Failures do not roll back completed tool work; do not replay successful operations blindly.
|
|
38
|
+
|
|
39
|
+
Examples (copy the JavaScript source, not the fences; use only tools available in the current directory):
|
|
40
|
+
Independent reads, emitting only source text:
|
|
41
|
+
\`\`\`js
|
|
42
|
+
const [a, b] = await Promise.all([
|
|
43
|
+
tools.read({ reads: [{ path: "a.txt" }] }),
|
|
44
|
+
tools.read({ reads: [{ path: "b.txt" }] })
|
|
45
|
+
]);
|
|
46
|
+
out.text({ a: a.data.results[0].text, b: b.data.results[0].text });
|
|
47
|
+
\`\`\`
|
|
48
|
+
Inspect before a dependent edit; successful await needs no invented success flag:
|
|
49
|
+
\`\`\`js
|
|
50
|
+
const inspected = await tools.read({ reads: [{ path: "source.txt" }] });
|
|
51
|
+
const sourceText = inspected.data.results[0].text;
|
|
52
|
+
if (!sourceText?.includes("original=1")) throw new Error("Unexpected source");
|
|
53
|
+
const patched = await tools.apply_patch("*** Begin Patch\\n*** Update File: source.txt\\n@@\\n original=1\\n+updated=2\\n*** End Patch");
|
|
54
|
+
out.text({ files: patched.data.files.length });
|
|
55
|
+
\`\`\``,
|
|
11
56
|
inputMode: 'freeform',
|
|
12
57
|
inputSchema: {
|
|
13
58
|
type: 'object',
|
|
@@ -15,71 +60,79 @@ export const codeModeToolDefinition = {
|
|
|
15
60
|
required: ['code'],
|
|
16
61
|
additionalProperties: false
|
|
17
62
|
},
|
|
63
|
+
allowedCallers: ['direct'],
|
|
18
64
|
parallelSafety: 'serial'
|
|
19
65
|
};
|
|
20
|
-
/**
|
|
21
|
-
export function
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
\`\`\``;
|
|
45
|
-
return tools.map((tool) => (tool.name === 'code_mode' ? { ...tool, description } : tool));
|
|
66
|
+
/** Deferred definitions travel in search results, not in the stable Code Mode description. */
|
|
67
|
+
export function projectCodeModeTools(tools, residentTools = tools) {
|
|
68
|
+
const codeModeEnabled = tools.some((tool) => tool.name === 'code_mode' && allowsToolCaller(tool, 'direct'));
|
|
69
|
+
const direct = tools.filter((tool) => allowsDirectTool(tool, codeModeEnabled));
|
|
70
|
+
if (!codeModeEnabled)
|
|
71
|
+
return direct;
|
|
72
|
+
const programmatic = residentTools.filter((tool) => allowsToolCaller(tool, 'programmatic'));
|
|
73
|
+
const directory = JSON.stringify({
|
|
74
|
+
callableNames: programmatic.map((tool) => tool.name),
|
|
75
|
+
programmaticOnly: programmatic.map((tool) => ({
|
|
76
|
+
name: tool.name,
|
|
77
|
+
description: tool.description,
|
|
78
|
+
inputSchema: tool.inputSchema,
|
|
79
|
+
inputMode: tool.inputMode ?? 'json'
|
|
80
|
+
}))
|
|
81
|
+
});
|
|
82
|
+
if (Buffer.byteLength(directory) > 32 * 1024)
|
|
83
|
+
throw new MarAgentError('MAR_AGENT_TOOL_EXPOSURE_LIMIT', 'Programmatic tool directory is too large.');
|
|
84
|
+
return direct.map((tool) => tool.name === 'code_mode'
|
|
85
|
+
? {
|
|
86
|
+
...tool,
|
|
87
|
+
description: `${codeModeToolDefinition.description}\nDeferred MCP definitions are returned by direct tool_search and become callable from the next model response, not later in the same response; they are not appended to this description.\nProgrammatic tools (call only inside code_mode): ${directory}`
|
|
88
|
+
}
|
|
89
|
+
: tool);
|
|
46
90
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (
|
|
52
|
-
return
|
|
53
|
-
|
|
54
|
-
.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
.
|
|
60
|
-
.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return
|
|
81
|
-
|
|
82
|
-
:
|
|
91
|
+
/** Preserve native search definitions while providing the same discovery evidence to other protocols. */
|
|
92
|
+
export function projectCodeModeSearchResult(message, codeModeEnabled) {
|
|
93
|
+
if (!message.toolSearchTools)
|
|
94
|
+
return message;
|
|
95
|
+
if (!codeModeEnabled)
|
|
96
|
+
return {
|
|
97
|
+
...message,
|
|
98
|
+
toolSearchTools: message.toolSearchTools.filter((tool) => allowsToolCaller(tool, 'direct'))
|
|
99
|
+
};
|
|
100
|
+
const tools = message.toolSearchTools.map((tool) => ({
|
|
101
|
+
name: tool.name,
|
|
102
|
+
description: allowsToolCaller(tool, 'programmatic')
|
|
103
|
+
? `Call only as tools.${tool.name} inside code_mode, never as a direct model tool.\n${tool.description}`
|
|
104
|
+
: tool.description,
|
|
105
|
+
inputSchema: tool.inputSchema,
|
|
106
|
+
inputMode: tool.inputMode ?? 'json',
|
|
107
|
+
caller: allowsToolCaller(tool, 'programmatic') ? 'programmatic' : 'direct'
|
|
108
|
+
}));
|
|
109
|
+
return {
|
|
110
|
+
...message,
|
|
111
|
+
content: JSON.stringify({ tools }),
|
|
112
|
+
toolSearchTools: tools.map(({ caller: _caller, ...tool }) => tool)
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function defaultEngineFactory() {
|
|
116
|
+
const core = import.meta.resolve('quickjs-emscripten-core');
|
|
117
|
+
const variant = import.meta.resolve('@jitl/quickjs-wasmfile-release-sync');
|
|
118
|
+
const ffi = pathToFileURL(createRequire(core).resolve('@jitl/quickjs-ffi-types')).href;
|
|
119
|
+
const dependencyRoot = (url) => {
|
|
120
|
+
const root = dirname(dirname(fileURLToPath(url)));
|
|
121
|
+
// pnpm's sibling dependencies are symlinks; keep the package-local node_modules tree visible.
|
|
122
|
+
return root.includes(`${sep}.pnpm${sep}`) ? dirname(dirname(root)) : root;
|
|
123
|
+
};
|
|
124
|
+
return {
|
|
125
|
+
moduleUrl: new URL('./code-mode/quickjs-engine.js', import.meta.url).href,
|
|
126
|
+
runtimeDirectories: [
|
|
127
|
+
...new Set([
|
|
128
|
+
fileURLToPath(new URL('./code-mode/', import.meta.url)),
|
|
129
|
+
dependencyRoot(core),
|
|
130
|
+
dependencyRoot(variant),
|
|
131
|
+
dependencyRoot(ffi)
|
|
132
|
+
])
|
|
133
|
+
],
|
|
134
|
+
options: { coreModuleUrl: core, variantModuleUrl: variant }
|
|
135
|
+
};
|
|
83
136
|
}
|
|
84
137
|
const environmentKeys = [
|
|
85
138
|
'PATH',
|
|
@@ -96,11 +149,13 @@ export class CodeModeTool {
|
|
|
96
149
|
paths;
|
|
97
150
|
environment;
|
|
98
151
|
executor;
|
|
152
|
+
engineFactory;
|
|
99
153
|
#active = new Map();
|
|
100
|
-
constructor(paths, environment = {}, executor = directLocalProcessExecutor) {
|
|
154
|
+
constructor(paths, environment = {}, executor = directLocalProcessExecutor, engineFactory = defaultEngineFactory()) {
|
|
101
155
|
this.paths = paths;
|
|
102
156
|
this.environment = environment;
|
|
103
157
|
this.executor = executor;
|
|
158
|
+
this.engineFactory = engineFactory;
|
|
104
159
|
}
|
|
105
160
|
async execute(value, context) {
|
|
106
161
|
const code = typeof value === 'string'
|
|
@@ -157,12 +212,13 @@ export class CodeModeTool {
|
|
|
157
212
|
`--max-old-space-size=${limits.codeHeapMegabytes}`,
|
|
158
213
|
'--input-type=module',
|
|
159
214
|
'--eval',
|
|
160
|
-
|
|
215
|
+
await readFile(new URL('./code-mode/worker.js', import.meta.url), 'utf8')
|
|
161
216
|
],
|
|
162
217
|
cwd,
|
|
163
218
|
shell: false,
|
|
164
219
|
environment,
|
|
165
220
|
environmentKeys: Object.keys(environment),
|
|
221
|
+
runtimeDirectories: this.engineFactory.runtimeDirectories,
|
|
166
222
|
detached: process.platform !== 'win32',
|
|
167
223
|
owner: { sessionId: context.sessionId, executionId: context.executionId },
|
|
168
224
|
signal: context.signal
|
|
@@ -173,6 +229,7 @@ export class CodeModeTool {
|
|
|
173
229
|
let transportBytes = 0;
|
|
174
230
|
let calls = 0;
|
|
175
231
|
let complete = false;
|
|
232
|
+
let stateMutations = [];
|
|
176
233
|
let failure;
|
|
177
234
|
let stderr = '';
|
|
178
235
|
let buffered = '';
|
|
@@ -212,7 +269,9 @@ export class CodeModeTool {
|
|
|
212
269
|
context.signal.throwIfAborted();
|
|
213
270
|
return context.codeMode.invoke(call, context.signal);
|
|
214
271
|
});
|
|
215
|
-
const available = new Set(context
|
|
272
|
+
const available = new Set(context
|
|
273
|
+
.codeMode.tools.filter((tool) => allowsToolCaller(tool, 'programmatic'))
|
|
274
|
+
.map((tool) => tool.name));
|
|
216
275
|
const receive = (frame) => {
|
|
217
276
|
if (complete)
|
|
218
277
|
throw new MarAgentError('MAR_AGENT_CODE_PROTOCOL_ERROR', 'Code Mode sent data after completion.');
|
|
@@ -266,6 +325,7 @@ export class CodeModeTool {
|
|
|
266
325
|
// Child completion cannot undo Host tool effects from calls it did not await.
|
|
267
326
|
if (pending.size)
|
|
268
327
|
throw new MarAgentError('MAR_AGENT_CODE_INCOMPLETE', 'Code Mode returned with unawaited tool calls; completed operations are not rolled back.');
|
|
328
|
+
stateMutations = parseCodeModeStateMutations(frame.stateMutations);
|
|
269
329
|
complete = true;
|
|
270
330
|
void signalProcessTree(child, 'SIGKILL').catch(fail);
|
|
271
331
|
}
|
|
@@ -324,12 +384,39 @@ export class CodeModeTool {
|
|
|
324
384
|
if (context.signal.aborted)
|
|
325
385
|
abort();
|
|
326
386
|
else
|
|
327
|
-
await write({
|
|
387
|
+
await write({
|
|
388
|
+
code,
|
|
389
|
+
tools: [...available],
|
|
390
|
+
catalog: context
|
|
391
|
+
.codeMode.tools.filter((tool) => available.has(tool.name))
|
|
392
|
+
.map((tool) => ({
|
|
393
|
+
name: tool.name,
|
|
394
|
+
description: tool.description,
|
|
395
|
+
inputSchema: tool.inputSchema,
|
|
396
|
+
inputMode: tool.inputMode ?? 'json'
|
|
397
|
+
})),
|
|
398
|
+
state: context.codeMode.state ?? [],
|
|
399
|
+
engine: this.engineFactory,
|
|
400
|
+
limits: {
|
|
401
|
+
memoryBytes: limits.codeMemoryBytes,
|
|
402
|
+
stackBytes: limits.codeStackBytes,
|
|
403
|
+
timeoutMs: limits.codeTimeoutMs,
|
|
404
|
+
outputBytes: limits.codeMaxOutputBytes,
|
|
405
|
+
stateEntries: limits.codeStateMaxEntries,
|
|
406
|
+
stateMutations: limits.codeStateMaxMutations,
|
|
407
|
+
stateKeyBytes: limits.codeStateMaxKeyBytes,
|
|
408
|
+
stateValueBytes: limits.codeStateMaxValueBytes,
|
|
409
|
+
stateTotalBytes: limits.codeStateMaxTotalBytes,
|
|
410
|
+
sleepMs: limits.codeSleepMaxMs
|
|
411
|
+
}
|
|
412
|
+
});
|
|
328
413
|
await exit;
|
|
329
414
|
if (failure !== undefined)
|
|
330
415
|
throw failure;
|
|
331
416
|
if (!complete)
|
|
332
417
|
throw new MarAgentError('MAR_AGENT_CODE_INCOMPLETE', 'Code Mode exited without a completion message.');
|
|
418
|
+
if (stateMutations.length)
|
|
419
|
+
await context.codeMode.commitState?.(stateMutations);
|
|
333
420
|
return {
|
|
334
421
|
content: text.join('\n') || 'Code Mode completed without emitted text.',
|
|
335
422
|
data: { toolCalls: calls },
|
|
@@ -367,56 +454,3 @@ function parseImage(value) {
|
|
|
367
454
|
throw invalid();
|
|
368
455
|
return { mimeType: image.mimeType, dataBase64: image.dataBase64 };
|
|
369
456
|
}
|
|
370
|
-
// The cell runs only in a Host-managed child process, never in the credential-bearing runtime.
|
|
371
|
-
const nodeCell = String.raw `
|
|
372
|
-
import { createInterface } from 'node:readline';
|
|
373
|
-
import { formatWithOptions } from 'node:util';
|
|
374
|
-
const lines = createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
375
|
-
const send = message => process.stdout.write(JSON.stringify(message) + '\n');
|
|
376
|
-
const requests = new Map();
|
|
377
|
-
let sequence = 0;
|
|
378
|
-
const tools = new Proxy(Object.create(null), {
|
|
379
|
-
get: (_, name) => name === 'then' ? undefined : arguments_ => new Promise((resolve, reject) => {
|
|
380
|
-
const id = ++sequence;
|
|
381
|
-
requests.set(id, { resolve, reject });
|
|
382
|
-
send({ kind: 'call', id, name, arguments: arguments_ });
|
|
383
|
-
})
|
|
384
|
-
});
|
|
385
|
-
const format = value => {
|
|
386
|
-
if (typeof value === 'string') return value;
|
|
387
|
-
try {
|
|
388
|
-
const json = JSON.stringify(value);
|
|
389
|
-
if (json !== undefined) return json;
|
|
390
|
-
} catch {}
|
|
391
|
-
return formatWithOptions({ colors: false }, value);
|
|
392
|
-
};
|
|
393
|
-
const text = value => send({ kind: 'text', value: format(value) });
|
|
394
|
-
const image = value => send({ kind: 'image', value });
|
|
395
|
-
for (const name of ['log', 'info', 'warn', 'error', 'debug'])
|
|
396
|
-
console[name] = (...values) => text(formatWithOptions({ colors: false }, ...values));
|
|
397
|
-
let started = false;
|
|
398
|
-
lines.on('line', async line => {
|
|
399
|
-
try {
|
|
400
|
-
const frame = JSON.parse(line);
|
|
401
|
-
if (!started) {
|
|
402
|
-
started = true;
|
|
403
|
-
const AsyncFunction = Object.getPrototypeOf(async function() {}).constructor;
|
|
404
|
-
try {
|
|
405
|
-
await new AsyncFunction('tools', 'text', 'image', frame.code)(tools, text, image);
|
|
406
|
-
await new Promise(resolve => process.stdout.write(JSON.stringify({ kind: 'done' }) + '\n', resolve));
|
|
407
|
-
} catch (error) {
|
|
408
|
-
await new Promise(resolve => process.stdout.write(JSON.stringify({
|
|
409
|
-
kind: 'error', code: typeof error?.code === 'string' ? error.code : 'MAR_AGENT_CODE_FAILED',
|
|
410
|
-
message: String(error?.message ?? error)
|
|
411
|
-
}) + '\n', resolve));
|
|
412
|
-
}
|
|
413
|
-
} else {
|
|
414
|
-
const request = requests.get(frame.id);
|
|
415
|
-
if (!request) return;
|
|
416
|
-
requests.delete(frame.id);
|
|
417
|
-
if (frame.ok) request.resolve(frame.output);
|
|
418
|
-
else request.reject(Object.assign(new Error(frame.error.message), { code: frame.error.code }));
|
|
419
|
-
}
|
|
420
|
-
} catch { process.exit(1); }
|
|
421
|
-
});
|
|
422
|
-
`;
|
package/dist/tools/exec.js
CHANGED
|
@@ -5,6 +5,7 @@ import { MarAgentError } from '../error.js';
|
|
|
5
5
|
import { TOOL_EXECUTION_LIMITS } from './execution-limits.js';
|
|
6
6
|
export const execToolDefinition = {
|
|
7
7
|
name: 'exec',
|
|
8
|
+
allowedCallers: ['direct', 'programmatic'],
|
|
8
9
|
parallelSafety: 'safe',
|
|
9
10
|
description: 'Unrestricted general system execution. Providing command starts any platform-native command, script, text/file tool, builder, generator, network client, or program in workspace/default cwd; action may be omitted for start. poll waits up to yieldMs for new output or termination and returns incremental stdout/stderr while running; after termination, poll returns a bounded cached result with earlier output for up to five minutes while the Session remains hosted. write sends stdin to running processes; cancel terminates a running process or removes a completed result. Returns status, processId, stdout/stderr, cumulative stdoutBytes/stderrBytes, per-result dropped bytes, exitCode, and truncated; a completed status does not imply exitCode 0. Always inspect stderr/exitCode and consume terminal output or cancel.',
|
|
10
11
|
outputSchema: {
|
|
@@ -21,7 +21,15 @@ export declare const TOOL_EXECUTION_LIMITS: Readonly<{
|
|
|
21
21
|
codeMaxTransportBytes: 67108864;
|
|
22
22
|
codeMaxCalls: 128;
|
|
23
23
|
codeMaxConcurrentCells: 4;
|
|
24
|
+
codeStateMaxEntries: 128;
|
|
25
|
+
codeStateMaxMutations: 128;
|
|
26
|
+
codeStateMaxKeyBytes: 256;
|
|
27
|
+
codeStateMaxValueBytes: 65536;
|
|
28
|
+
codeStateMaxTotalBytes: 1048576;
|
|
29
|
+
codeSleepMaxMs: 30000;
|
|
24
30
|
codeHeapMegabytes: 128;
|
|
31
|
+
codeMemoryBytes: 33554432;
|
|
32
|
+
codeStackBytes: 524288;
|
|
25
33
|
codeTimeoutMs: 120000;
|
|
26
34
|
patchMaxBytes: 4194304;
|
|
27
35
|
patchMaxFiles: 100;
|
|
@@ -21,7 +21,15 @@ export const TOOL_EXECUTION_LIMITS = Object.freeze({
|
|
|
21
21
|
codeMaxTransportBytes: 67_108_864,
|
|
22
22
|
codeMaxCalls: 128,
|
|
23
23
|
codeMaxConcurrentCells: 4,
|
|
24
|
+
codeStateMaxEntries: 128,
|
|
25
|
+
codeStateMaxMutations: 128,
|
|
26
|
+
codeStateMaxKeyBytes: 256,
|
|
27
|
+
codeStateMaxValueBytes: 65_536,
|
|
28
|
+
codeStateMaxTotalBytes: 1_048_576,
|
|
29
|
+
codeSleepMaxMs: 30_000,
|
|
24
30
|
codeHeapMegabytes: 128,
|
|
31
|
+
codeMemoryBytes: 33_554_432,
|
|
32
|
+
codeStackBytes: 524_288,
|
|
25
33
|
codeTimeoutMs: 120_000,
|
|
26
34
|
patchMaxBytes: 4_194_304,
|
|
27
35
|
patchMaxFiles: 100,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CodeModeEngineFactory } from './code-mode/engine.js';
|
|
1
2
|
import type { LocalProcessExecutor } from '../host/local-process-executor.js';
|
|
2
3
|
import type { ToolCall, ToolExecutionContext, ToolExecutionResult } from '../sdk/types.js';
|
|
3
4
|
import { type WorkspacePathMount } from './shared/path-resolver.js';
|
|
@@ -11,6 +12,7 @@ export declare class LocalToolRegistry {
|
|
|
11
12
|
webFetch?: boolean;
|
|
12
13
|
allowUntrustedTls?: boolean;
|
|
13
14
|
processExecutor?: LocalProcessExecutor;
|
|
15
|
+
codeModeEngineFactory?: CodeModeEngineFactory;
|
|
14
16
|
restrictPaths?: boolean;
|
|
15
17
|
workspaceWritable?: boolean;
|
|
16
18
|
pathMounts?: readonly WorkspacePathMount[];
|
|
@@ -23,7 +23,7 @@ export class LocalToolRegistry {
|
|
|
23
23
|
const viewImage = new ViewImageTool(paths);
|
|
24
24
|
const patch = new ApplyPatchTool(paths);
|
|
25
25
|
this.#exec = new ExecTool(paths, undefined, undefined, environment, shell, web.processExecutor);
|
|
26
|
-
this.#code = new CodeModeTool(paths, environment, web.processExecutor);
|
|
26
|
+
this.#code = new CodeModeTool(paths, environment, web.processExecutor, web.codeModeEngineFactory);
|
|
27
27
|
this.#handlers = new Map([
|
|
28
28
|
['code_mode', (arguments_, context) => this.#code.execute(arguments_, context)],
|
|
29
29
|
[
|
package/dist/tools/question.js
CHANGED
|
@@ -3,6 +3,7 @@ import { MarAgentError } from '../error.js';
|
|
|
3
3
|
import { TOOL_EXECUTION_LIMITS } from './execution-limits.js';
|
|
4
4
|
export const questionToolDefinition = {
|
|
5
5
|
name: 'question',
|
|
6
|
+
allowedCallers: ['direct'],
|
|
6
7
|
parallelSafety: 'serial',
|
|
7
8
|
description: 'Pause for one to three tightly related user-owned decisions that materially change the result and cannot be inferred from the request, conversation, or relevant safe discovery. Prefer asking over guessing in Plan mode; do not avoid clarification by inventing configuration, branches, abstractions, or support for multiple outcomes. Provide 2-3 mutually exclusive options with consequences, put the recommended option first and identify it in its label or description, and use another question round if key ambiguity remains. This is not a permission/approval tool and should not interrupt routine in-scope work.',
|
|
8
9
|
inputSchema: {
|
package/dist/tools/read.js
CHANGED
|
@@ -5,6 +5,7 @@ import { MarAgentError } from '../error.js';
|
|
|
5
5
|
import { TOOL_EXECUTION_LIMITS } from './execution-limits.js';
|
|
6
6
|
export const readToolDefinition = {
|
|
7
7
|
name: 'read',
|
|
8
|
+
allowedCallers: ['direct', 'programmatic'],
|
|
8
9
|
parallelSafety: 'safe',
|
|
9
10
|
outputSchema: {
|
|
10
11
|
type: 'object',
|
package/dist/tools/registry.js
CHANGED
|
@@ -13,8 +13,10 @@ import { executeTodoWrite, todoWriteToolDefinition } from './todo-write.js';
|
|
|
13
13
|
import { webFetchToolDefinition } from './web-fetch.js';
|
|
14
14
|
import { webSearchToolDefinition } from './web-search.js';
|
|
15
15
|
import { executeSkill, skillToolDefinition } from './skill.js';
|
|
16
|
+
import { executeToolSearch, toolSearchToolDefinition } from './tool-search.js';
|
|
16
17
|
export const BUILTIN_TOOL_DEFINITIONS = [
|
|
17
18
|
skillToolDefinition,
|
|
19
|
+
toolSearchToolDefinition,
|
|
18
20
|
readToolDefinition,
|
|
19
21
|
viewImageToolDefinition,
|
|
20
22
|
execToolDefinition,
|
|
@@ -32,6 +34,7 @@ export const BUILTIN_TOOL_DEFINITIONS = [
|
|
|
32
34
|
];
|
|
33
35
|
export const AGENT_TOOL_HANDLERS = new Map([
|
|
34
36
|
['skill', executeSkill],
|
|
37
|
+
['tool_search', executeToolSearch],
|
|
35
38
|
['question', executeQuestion],
|
|
36
39
|
['todo_read', (_arguments, context) => executeTodoRead(context)],
|
|
37
40
|
['todo_write', executeTodoWrite],
|
|
@@ -47,5 +47,7 @@ export interface ToolRuntimeContext {
|
|
|
47
47
|
codeMode?: import('../sdk/types.js').ToolExecutionContext['codeMode'];
|
|
48
48
|
skills: ReadonlyMap<string, AgentSkill>;
|
|
49
49
|
recentImages?: readonly ToolRuntimeImage[];
|
|
50
|
+
searchMcpTools?: (input: unknown, signal: AbortSignal) => Promise<import('../sdk/types.js').ToolExecutionResult>;
|
|
51
|
+
expectedMcpTool?: import('../sdk/types.js').McpToolCallContext['expectedTool'];
|
|
50
52
|
emit(event: ToolRuntimeEvent): Promise<void>;
|
|
51
53
|
}
|
package/dist/tools/runtime.js
CHANGED
|
@@ -10,7 +10,9 @@ export async function executeRegisteredTool(name, arguments_, callId, context) {
|
|
|
10
10
|
throw new MarAgentError('MAR_AGENT_MCP_FAILED', 'MCP execution is unavailable.');
|
|
11
11
|
return context.host.callMcpTool(call, context.signal, {
|
|
12
12
|
sessionId: context.sessionId,
|
|
13
|
-
executionId: context.executionId
|
|
13
|
+
executionId: context.executionId,
|
|
14
|
+
mode: context.mode,
|
|
15
|
+
...(context.expectedMcpTool ? { expectedTool: context.expectedMcpTool } : {})
|
|
14
16
|
});
|
|
15
17
|
}
|
|
16
18
|
return context.host.executeTool(call, {
|
package/dist/tools/skill.js
CHANGED
|
@@ -2,6 +2,7 @@ import { MarAgentError } from '../error.js';
|
|
|
2
2
|
import { agentSkillSource, loadAgentSkill } from '../runtime/instructions.js';
|
|
3
3
|
export const skillToolDefinition = {
|
|
4
4
|
name: 'skill',
|
|
5
|
+
allowedCallers: ['direct', 'programmatic'],
|
|
5
6
|
parallelSafety: 'safe',
|
|
6
7
|
description: 'Load a specialized Skill when the task matches one listed in the system prompt. Returns its instructions and source; file-based Skills also include a base directory and resource-path sample. Host-provided skills have no filesystem base. The name must exactly match the advertised catalog.',
|
|
7
8
|
inputSchema: {
|
package/dist/tools/todo-read.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export const todoReadToolDefinition = {
|
|
2
2
|
name: 'todo_read',
|
|
3
|
+
allowedCallers: ['direct', 'programmatic'],
|
|
3
4
|
parallelSafety: 'safe',
|
|
4
5
|
description: 'Read this session’s current Todo revision and items. Use before updating when the revision may have changed. Do not read an empty or new Todo merely to decide whether straightforward bounded work needs one.',
|
|
5
6
|
inputSchema: { type: 'object', properties: {}, additionalProperties: false }
|
package/dist/tools/todo-write.js
CHANGED
|
@@ -2,6 +2,7 @@ import { MarAgentError } from '../error.js';
|
|
|
2
2
|
import { TOOL_EXECUTION_LIMITS } from './execution-limits.js';
|
|
3
3
|
export const todoWriteToolDefinition = {
|
|
4
4
|
name: 'todo_write',
|
|
5
|
+
allowedCallers: ['direct', 'programmatic'],
|
|
5
6
|
parallelSafety: 'serial',
|
|
6
7
|
description: 'Replace this session’s entire Todo list using optimistic expectedRevision. Preserve stable IDs and statuses only when extending the same objective. For a materially different objective, include only the new objective’s items. Do not retain completed items from an earlier objective; when all current items are completed, default a substantive new request to replacement unless the user explicitly asks to continue, extend, verify, or follow up. Use only after Todo has been chosen for coordination-heavy work; straightforward bounded work does not need it. Keep at most one in_progress item and update statuses after meaningful stage changes. When another substantive tool call is already ready and does not depend on the Todo result, include both in the same model response instead of spending a response only for Todo bookkeeping.',
|
|
7
8
|
inputSchema: {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ClientToolDefinition } from '../model/contracts.js';
|
|
2
|
+
import type { McpCatalogTool, McpToolCatalog, ToolExecutionResult } from '../sdk/types.js';
|
|
3
|
+
import type { ToolRuntimeContext } from './runtime-context.js';
|
|
4
|
+
export declare const TOOL_SEARCH_LIMITS: Readonly<{
|
|
5
|
+
defaultLimit: 5;
|
|
6
|
+
maximumLimit: 20;
|
|
7
|
+
queryBytes: 4096;
|
|
8
|
+
catalogBytes: number;
|
|
9
|
+
maximumDefinitionTokens: 16384;
|
|
10
|
+
definitionWindowFraction: 0.25;
|
|
11
|
+
minimumContinuationTokens: 1024;
|
|
12
|
+
}>;
|
|
13
|
+
export declare const toolSearchToolDefinition: ClientToolDefinition;
|
|
14
|
+
export declare function parseToolSearchInput(input: unknown): {
|
|
15
|
+
query: string;
|
|
16
|
+
limit: number;
|
|
17
|
+
};
|
|
18
|
+
/** Deferred discovery state reconstructed from the current post-GC model history. */
|
|
19
|
+
export declare class DeferredMcpRegistry {
|
|
20
|
+
#private;
|
|
21
|
+
constructor(discoveredNames: readonly string[]);
|
|
22
|
+
restore(discoveredNames: readonly string[]): void;
|
|
23
|
+
update(catalog: McpToolCatalog, eligible: (tool: McpCatalogTool) => boolean): void;
|
|
24
|
+
get hasDeferred(): boolean;
|
|
25
|
+
snapshot(): readonly string[];
|
|
26
|
+
expectedTool(name: string): {
|
|
27
|
+
sourceIdentity: string;
|
|
28
|
+
definitionRevision: string;
|
|
29
|
+
} | undefined;
|
|
30
|
+
restoredDefinitions(names: readonly string[]): readonly ClientToolDefinition[];
|
|
31
|
+
projectDirect(base: readonly ClientToolDefinition[]): ClientToolDefinition[];
|
|
32
|
+
project(base: readonly ClientToolDefinition[], selection?: readonly string[], executionSelection?: Set<string>): ClientToolDefinition[];
|
|
33
|
+
search(query: string, limit: number): McpCatalogTool[];
|
|
34
|
+
expose(input: unknown, context: {
|
|
35
|
+
signal: AbortSignal;
|
|
36
|
+
base: readonly ClientToolDefinition[];
|
|
37
|
+
window: number;
|
|
38
|
+
system: string;
|
|
39
|
+
}): Promise<ToolExecutionResult>;
|
|
40
|
+
assertBudget(base: readonly ClientToolDefinition[], window: number, system: string, selection?: readonly string[], executionSelection?: ReadonlySet<string>): void;
|
|
41
|
+
navigation(): string | undefined;
|
|
42
|
+
}
|
|
43
|
+
export declare function executeToolSearch(input: unknown, context: ToolRuntimeContext): Promise<ToolExecutionResult>;
|