@myagentroam/agent 0.9.137 → 0.9.138
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/host/local-agent-host.d.ts +5 -0
- package/dist/host/local-agent-host.js +2 -1
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.js +1 -1
- package/dist/prompts/resources.d.ts +1 -0
- package/dist/prompts/resources.js +8 -2
- package/dist/prompts/workflow.js +2 -2
- package/dist/runtime/context-gc.js +10 -6
- package/dist/runtime/context-projection.js +1 -1
- package/dist/sdk/agent.js +88 -53
- package/dist/sdk/types.d.ts +13 -1
- package/dist/session/context-gc-checkpoint.d.ts +1 -1
- package/dist/session/context-gc-checkpoint.js +11 -5
- package/dist/session/context-gc-replacements.d.ts +2 -0
- package/dist/session/context-gc-replacements.js +18 -0
- package/dist/session/jsonl-store.d.ts +5 -2
- package/dist/session/jsonl-store.js +105 -12
- package/dist/subagent/session-controller.d.ts +2 -0
- package/dist/subagent/session-controller.js +23 -6
- package/dist/tools/callers.js +2 -1
- package/dist/tools/code-mode/cells.d.ts +20 -0
- package/dist/tools/code-mode/cells.js +250 -0
- package/dist/tools/code-mode/dispatch.d.ts +21 -0
- package/dist/tools/code-mode/dispatch.js +53 -0
- package/dist/tools/code-mode/engine.d.ts +1 -0
- package/dist/tools/code-mode/quickjs-engine.js +4 -0
- package/dist/tools/code-mode/worker.js +1 -0
- package/dist/tools/code-mode.d.ts +10 -1
- package/dist/tools/code-mode.js +51 -10
- package/dist/tools/execution-limits.d.ts +5 -0
- package/dist/tools/execution-limits.js +5 -0
- package/dist/tools/local-registry.d.ts +5 -0
- package/dist/tools/local-registry.js +5 -1
- package/dist/tools/registry.js +2 -1
- package/dist/tools/scheduler.d.ts +2 -0
- package/dist/tools/scheduler.js +11 -0
- package/dist/tools/tool-search.js +2 -2
- package/package.json +1 -1
package/dist/tools/code-mode.js
CHANGED
|
@@ -11,9 +11,10 @@ import { TOOL_EXECUTION_LIMITS as limits } from './execution-limits.js';
|
|
|
11
11
|
import { createToolCallScheduler } from './scheduler.js';
|
|
12
12
|
import { detectImageMime } from './view-image.js';
|
|
13
13
|
import { allowsDirectTool, allowsToolCaller } from './callers.js';
|
|
14
|
+
import { CodeCells } from './code-mode/cells.js';
|
|
14
15
|
import { parseCodeModeStateMutations } from './code-mode/state.js';
|
|
15
16
|
export const codeModeToolDefinition = {
|
|
16
|
-
name: '
|
|
17
|
+
name: 'code_exec',
|
|
17
18
|
description: `Run JavaScript to orchestrate or compose tool calls.
|
|
18
19
|
- 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
20
|
- Use bounded combinations, parallel independent calls, and filtering of large intermediate results to reduce model round trips.
|
|
@@ -25,7 +26,7 @@ Tool calls:
|
|
|
25
26
|
- 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
27
|
- 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
28
|
- 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,
|
|
29
|
+
- tool_search, question, code_exec, code_exec_wait 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
|
|
|
30
31
|
Built-in namespaces:
|
|
31
32
|
- 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.
|
|
@@ -33,6 +34,9 @@ Built-in namespaces:
|
|
|
33
34
|
- 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
35
|
- 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
36
|
- await cell.sleep(ms) performs a cancellable Host-side delay up to 30000 ms and remains subject to the cell deadline.
|
|
37
|
+
- await cell.yield_control() returns accumulated output to the model immediately while this cell continues running.
|
|
38
|
+
- Optionally start source with // @options: {"yieldMs": 10000, "maxOutputTokens": 10000}. yieldMs is a wait window (0..30000), not a cell timeout. A running result includes cellId; use direct code_exec_wait for new output, completion or termination.
|
|
39
|
+
- Registered cells are Session warm resources: ending or cancelling the model Execution cancels its wait, not the cell. Reuse retained cellId; do not start duplicate work. Host cleanup or explicit termination stops the cell.
|
|
36
40
|
- tools, out, state, catalog and cell are frozen bindings. Do not shadow their names.
|
|
37
41
|
- 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
42
|
|
|
@@ -63,9 +67,30 @@ out.text({ files: patched.data.files.length });
|
|
|
63
67
|
allowedCallers: ['direct'],
|
|
64
68
|
parallelSafety: 'serial'
|
|
65
69
|
};
|
|
70
|
+
export const codeExecWaitToolDefinition = {
|
|
71
|
+
name: 'code_exec_wait',
|
|
72
|
+
description: 'Wait for a retained Code Exec cell by cellId. Returns only new output, or a bounded terminal snapshot marked cached on repeat reads. yieldMs is a wait window, not a timeout. action defaults to poll (wait); action cancel stops the cell and waits for cleanup. Cancelling this wait does not cancel the cell. Cells belong to the current Session and cannot survive Host restart. Call directly, never inside code_exec.',
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: 'object',
|
|
75
|
+
properties: {
|
|
76
|
+
cellId: { type: 'string' },
|
|
77
|
+
yieldMs: { type: 'integer', minimum: 0, maximum: limits.codeMaxYieldMs },
|
|
78
|
+
maxOutputTokens: { type: 'integer', minimum: 1, maximum: limits.codeMaxOutputTokens },
|
|
79
|
+
action: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
enum: ['poll', 'cancel'],
|
|
82
|
+
description: 'Defaults to poll; cancel terminates the cell rather than just its current wait.'
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
required: ['cellId'],
|
|
86
|
+
additionalProperties: false
|
|
87
|
+
},
|
|
88
|
+
allowedCallers: ['direct'],
|
|
89
|
+
parallelSafety: 'safe'
|
|
90
|
+
};
|
|
66
91
|
/** Deferred definitions travel in search results, not in the stable Code Mode description. */
|
|
67
92
|
export function projectCodeModeTools(tools, residentTools = tools) {
|
|
68
|
-
const codeModeEnabled = tools.some((tool) => tool.name === '
|
|
93
|
+
const codeModeEnabled = tools.some((tool) => tool.name === 'code_exec' && allowsToolCaller(tool, 'direct'));
|
|
69
94
|
const direct = tools.filter((tool) => allowsDirectTool(tool, codeModeEnabled));
|
|
70
95
|
if (!codeModeEnabled)
|
|
71
96
|
return direct;
|
|
@@ -81,10 +106,10 @@ export function projectCodeModeTools(tools, residentTools = tools) {
|
|
|
81
106
|
});
|
|
82
107
|
if (Buffer.byteLength(directory) > 32 * 1024)
|
|
83
108
|
throw new MarAgentError('MAR_AGENT_TOOL_EXPOSURE_LIMIT', 'Programmatic tool directory is too large.');
|
|
84
|
-
return direct.map((tool) => tool.name === '
|
|
109
|
+
return direct.map((tool) => tool.name === 'code_exec'
|
|
85
110
|
? {
|
|
86
111
|
...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
|
|
112
|
+
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_exec): ${directory}`
|
|
88
113
|
}
|
|
89
114
|
: tool);
|
|
90
115
|
}
|
|
@@ -100,7 +125,7 @@ export function projectCodeModeSearchResult(message, codeModeEnabled) {
|
|
|
100
125
|
const tools = message.toolSearchTools.map((tool) => ({
|
|
101
126
|
name: tool.name,
|
|
102
127
|
description: allowsToolCaller(tool, 'programmatic')
|
|
103
|
-
? `Call only as tools.${tool.name} inside
|
|
128
|
+
? `Call only as tools.${tool.name} inside code_exec, never as a direct model tool.\n${tool.description}`
|
|
104
129
|
: tool.description,
|
|
105
130
|
inputSchema: tool.inputSchema,
|
|
106
131
|
inputMode: tool.inputMode ?? 'json',
|
|
@@ -150,6 +175,16 @@ export class CodeModeTool {
|
|
|
150
175
|
environment;
|
|
151
176
|
executor;
|
|
152
177
|
engineFactory;
|
|
178
|
+
#cells = new CodeCells();
|
|
179
|
+
start(value, context) {
|
|
180
|
+
return this.#cells.start(value, context, (code, detached, output) => this.execute(code, detached, output));
|
|
181
|
+
}
|
|
182
|
+
wait(value, context) {
|
|
183
|
+
return this.#cells.wait(value, context);
|
|
184
|
+
}
|
|
185
|
+
listSessionResources(sessionId) {
|
|
186
|
+
return this.#cells.snapshot(sessionId);
|
|
187
|
+
}
|
|
153
188
|
#active = new Map();
|
|
154
189
|
constructor(paths, environment = {}, executor = directLocalProcessExecutor, engineFactory = defaultEngineFactory()) {
|
|
155
190
|
this.paths = paths;
|
|
@@ -157,7 +192,7 @@ export class CodeModeTool {
|
|
|
157
192
|
this.executor = executor;
|
|
158
193
|
this.engineFactory = engineFactory;
|
|
159
194
|
}
|
|
160
|
-
async execute(value, context) {
|
|
195
|
+
async execute(value, context, output) {
|
|
161
196
|
const code = typeof value === 'string'
|
|
162
197
|
? value
|
|
163
198
|
: value &&
|
|
@@ -185,7 +220,7 @@ export class CodeModeTool {
|
|
|
185
220
|
this.#active.set(controller, { sessionId: context.sessionId, done });
|
|
186
221
|
const timer = setTimeout(() => controller.abort(new MarAgentError('MAR_AGENT_CODE_TIMEOUT', 'Code Mode exceeded its execution time limit.')), limits.codeTimeoutMs);
|
|
187
222
|
try {
|
|
188
|
-
return await this.#run(code, { ...context, signal }, controller);
|
|
223
|
+
return await this.#run(code, { ...context, signal }, controller, output);
|
|
189
224
|
}
|
|
190
225
|
finally {
|
|
191
226
|
clearTimeout(timer);
|
|
@@ -194,12 +229,13 @@ export class CodeModeTool {
|
|
|
194
229
|
}
|
|
195
230
|
}
|
|
196
231
|
async dispose(sessionId) {
|
|
232
|
+
await this.#cells.dispose(sessionId);
|
|
197
233
|
const active = [...this.#active].filter(([, entry]) => sessionId === undefined || entry.sessionId === sessionId);
|
|
198
234
|
for (const [controller] of active)
|
|
199
235
|
controller.abort(new MarAgentError('MAR_AGENT_CODE_CANCELLED', 'Code Mode resources were released.'));
|
|
200
236
|
await Promise.all(active.map(([, entry]) => entry.done));
|
|
201
237
|
}
|
|
202
|
-
async #run(code, context, controller) {
|
|
238
|
+
async #run(code, context, controller, output) {
|
|
203
239
|
const cwd = await this.paths.resolve('.');
|
|
204
240
|
context.signal.throwIfAborted();
|
|
205
241
|
const environment = Object.fromEntries(environmentKeys.flatMap((key) => {
|
|
@@ -280,6 +316,7 @@ export class CodeModeTool {
|
|
|
280
316
|
if (outputBytes > limits.codeMaxOutputBytes)
|
|
281
317
|
throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Code Mode emitted too much text.');
|
|
282
318
|
text.push(frame.value);
|
|
319
|
+
output?.text(frame.value);
|
|
283
320
|
}
|
|
284
321
|
else if (frame.kind === 'image') {
|
|
285
322
|
if (!context.codeMode?.supportsImages)
|
|
@@ -288,6 +325,10 @@ export class CodeModeTool {
|
|
|
288
325
|
if (images.length >= 5)
|
|
289
326
|
throw new MarAgentError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Code Mode emitted too many images.');
|
|
290
327
|
images.push(image);
|
|
328
|
+
output?.image(image);
|
|
329
|
+
}
|
|
330
|
+
else if (frame.kind === 'yield') {
|
|
331
|
+
output?.yield();
|
|
291
332
|
}
|
|
292
333
|
else if (frame.kind === 'call' &&
|
|
293
334
|
Number.isSafeInteger(frame.id) &&
|
|
@@ -298,7 +339,7 @@ export class CodeModeTool {
|
|
|
298
339
|
seen.add(id);
|
|
299
340
|
const job = (async () => {
|
|
300
341
|
try {
|
|
301
|
-
if (frame.name === '
|
|
342
|
+
if (frame.name === 'code_exec' || !available.has(frame.name))
|
|
302
343
|
throw new MarAgentError('MAR_AGENT_TOOL_NOT_AVAILABLE', 'The requested nested tool is unavailable.');
|
|
303
344
|
const output = await invoke({
|
|
304
345
|
name: frame.name,
|
|
@@ -21,6 +21,11 @@ export declare const TOOL_EXECUTION_LIMITS: Readonly<{
|
|
|
21
21
|
codeMaxTransportBytes: 67108864;
|
|
22
22
|
codeMaxCalls: 128;
|
|
23
23
|
codeMaxConcurrentCells: 4;
|
|
24
|
+
codeDefaultYieldMs: 10000;
|
|
25
|
+
codeMaxYieldMs: 30000;
|
|
26
|
+
codeMaxOutputTokens: 10000;
|
|
27
|
+
codeCompletedRetentionMs: 300000;
|
|
28
|
+
codeMaxCompletedResults: 16;
|
|
24
29
|
codeStateMaxEntries: 128;
|
|
25
30
|
codeStateMaxMutations: 128;
|
|
26
31
|
codeStateMaxKeyBytes: 256;
|
|
@@ -21,6 +21,11 @@ export const TOOL_EXECUTION_LIMITS = Object.freeze({
|
|
|
21
21
|
codeMaxTransportBytes: 67_108_864,
|
|
22
22
|
codeMaxCalls: 128,
|
|
23
23
|
codeMaxConcurrentCells: 4,
|
|
24
|
+
codeDefaultYieldMs: 10_000,
|
|
25
|
+
codeMaxYieldMs: 30_000,
|
|
26
|
+
codeMaxOutputTokens: 10_000,
|
|
27
|
+
codeCompletedRetentionMs: 300_000,
|
|
28
|
+
codeMaxCompletedResults: 16,
|
|
24
29
|
codeStateMaxEntries: 128,
|
|
25
30
|
codeStateMaxMutations: 128,
|
|
26
31
|
codeStateMaxKeyBytes: 256,
|
|
@@ -24,6 +24,11 @@ export declare class LocalToolRegistry {
|
|
|
24
24
|
command: string;
|
|
25
25
|
cwd: string;
|
|
26
26
|
}[];
|
|
27
|
+
listCodeCells(sessionId: string): {
|
|
28
|
+
cellId: string;
|
|
29
|
+
status: "completed" | "cancelled" | "running" | "failed";
|
|
30
|
+
executionId: string;
|
|
31
|
+
}[];
|
|
27
32
|
disposeSessionResources(sessionId: string): Promise<void>;
|
|
28
33
|
dispose(): Promise<void>;
|
|
29
34
|
}
|
|
@@ -25,7 +25,8 @@ export class LocalToolRegistry {
|
|
|
25
25
|
this.#exec = new ExecTool(paths, undefined, undefined, environment, shell, web.processExecutor);
|
|
26
26
|
this.#code = new CodeModeTool(paths, environment, web.processExecutor, web.codeModeEngineFactory);
|
|
27
27
|
this.#handlers = new Map([
|
|
28
|
-
['
|
|
28
|
+
['code_exec', (arguments_, context) => this.#code.start(arguments_, context)],
|
|
29
|
+
['code_exec_wait', (arguments_, context) => this.#code.wait(arguments_, context)],
|
|
29
30
|
[
|
|
30
31
|
'read',
|
|
31
32
|
async (arguments_, context) => {
|
|
@@ -124,6 +125,9 @@ export class LocalToolRegistry {
|
|
|
124
125
|
listSessionResources(sessionId) {
|
|
125
126
|
return this.#exec.listSessionResources(sessionId);
|
|
126
127
|
}
|
|
128
|
+
listCodeCells(sessionId) {
|
|
129
|
+
return this.#code.listSessionResources(sessionId);
|
|
130
|
+
}
|
|
127
131
|
async disposeSessionResources(sessionId) {
|
|
128
132
|
await Promise.all([this.#exec.disposeSession(sessionId), this.#code.dispose(sessionId)]);
|
|
129
133
|
}
|
package/dist/tools/registry.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { applyPatchToolDefinition } from './apply-patch.js';
|
|
2
2
|
import { execToolDefinition } from './exec.js';
|
|
3
|
-
import { codeModeToolDefinition } from './code-mode.js';
|
|
3
|
+
import { codeModeToolDefinition, codeExecWaitToolDefinition } from './code-mode.js';
|
|
4
4
|
import { executeQuestion, questionToolDefinition } from './question.js';
|
|
5
5
|
import { readToolDefinition } from './read.js';
|
|
6
6
|
import { viewImageToolDefinition } from './view-image.js';
|
|
@@ -21,6 +21,7 @@ export const BUILTIN_TOOL_DEFINITIONS = [
|
|
|
21
21
|
viewImageToolDefinition,
|
|
22
22
|
execToolDefinition,
|
|
23
23
|
codeModeToolDefinition,
|
|
24
|
+
codeExecWaitToolDefinition,
|
|
24
25
|
applyPatchToolDefinition,
|
|
25
26
|
questionToolDefinition,
|
|
26
27
|
todoReadToolDefinition,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ClientToolDefinition } from '../model/contracts.js';
|
|
2
|
+
/** One barrier domain for foreground tools and all retained cells in a Session. */
|
|
3
|
+
export declare function createSessionToolScheduler(): <T>(definition: ClientToolDefinition | undefined, run: () => Promise<T>) => Promise<T>;
|
|
2
4
|
/** Schedules an incremental stream while preserving the same safe/serial barriers as batches. */
|
|
3
5
|
export declare function createToolCallScheduler<TCall extends {
|
|
4
6
|
readonly name: string;
|
package/dist/tools/scheduler.js
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/** One barrier domain for foreground tools and all retained cells in a Session. */
|
|
2
|
+
export function createSessionToolScheduler() {
|
|
3
|
+
const schedule = createToolCallScheduler([
|
|
4
|
+
{ name: 'safe', parallelSafety: 'safe' },
|
|
5
|
+
{ name: 'serial', parallelSafety: 'serial' }
|
|
6
|
+
], (job) => job.run());
|
|
7
|
+
return (definition, run) => schedule({
|
|
8
|
+
name: definition?.parallelSafety === 'safe' ? 'safe' : 'serial',
|
|
9
|
+
run
|
|
10
|
+
});
|
|
11
|
+
}
|
|
1
12
|
/** Schedules an incremental stream while preserving the same safe/serial barriers as batches. */
|
|
2
13
|
export function createToolCallScheduler(definitions, execute) {
|
|
3
14
|
const safety = new Map(definitions.map((definition) => [definition.name, definition.parallelSafety]));
|
|
@@ -13,7 +13,7 @@ export const TOOL_SEARCH_LIMITS = Object.freeze({
|
|
|
13
13
|
});
|
|
14
14
|
export const toolSearchToolDefinition = {
|
|
15
15
|
name: 'tool_search',
|
|
16
|
-
description: 'Search deferred MCP metadata and return matching tool definitions for the next model call. Use the full callable name for exact selection, or keywords for BM25 search. Never executes the discovered tools. With Code Mode Only, programmatic tools must be called through
|
|
16
|
+
description: 'Search deferred MCP metadata and return matching tool definitions for the next model call. Use the full callable name for exact selection, or keywords for BM25 search. Never executes the discovered tools. With Code Mode Only, programmatic tools must be called through code_exec, not directly. Already exposed tools need not be searched again. The selected definitions must fit the exposure budget or the search fails atomically.',
|
|
17
17
|
inputSchema: {
|
|
18
18
|
type: 'object',
|
|
19
19
|
properties: {
|
|
@@ -207,7 +207,7 @@ export class DeferredMcpRegistry {
|
|
|
207
207
|
const direct = projectCodeModeTools(resident);
|
|
208
208
|
const residentNames = new Set(resident.map((tool) => tool.name));
|
|
209
209
|
const definitions = active.filter((tool) => !residentNames.has(tool.name));
|
|
210
|
-
const searchResult = projectCodeModeSearchResult({ role: 'tool', content: '', toolSearchTools: definitions }, base.some((tool) => tool.name === '
|
|
210
|
+
const searchResult = projectCodeModeSearchResult({ role: 'tool', content: '', toolSearchTools: definitions }, base.some((tool) => tool.name === 'code_exec'));
|
|
211
211
|
// Search-result definitions still consume context even when Only mode hides direct tools.
|
|
212
212
|
const estimated = countModelTokens(searchResult.content || JSON.stringify(searchResult.toolSearchTools));
|
|
213
213
|
const full = Math.max(countModelTokens(JSON.stringify(tools)), countModelTokens(JSON.stringify(direct)) + estimated);
|