@myagentroam/agent 0.11.43 → 0.11.44
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/tools/code-mode/cells.d.ts +1 -1
- package/dist/tools/code-mode/cells.js +27 -3
- package/dist/tools/code-mode/dispatch.js +3 -0
- package/dist/tools/code-mode/engine.d.ts +2 -0
- package/dist/tools/code-mode/index.js +37 -5
- package/dist/tools/code-mode/quickjs-engine.js +5 -1
- package/dist/tools/code-mode/text-output.d.ts +2 -1
- package/dist/tools/code-mode/text-output.js +15 -2
- package/dist/tools/output-projection.d.ts +2 -0
- package/dist/tools/output-projection.js +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import type { ToolExecutionContext, ToolExecutionResult } from '../contracts.js'
|
|
|
3
3
|
import type { CodeObservation, CodeToolCallRecord } from '../../session/code-observation-contract.js';
|
|
4
4
|
export interface CellOutput {
|
|
5
5
|
call(value: CodeToolCallRecord): void;
|
|
6
|
-
observe(value: CodeObservation): void;
|
|
6
|
+
observe(value: CodeObservation, display?: CodeObservation, displayHeadTruncated?: boolean): void;
|
|
7
7
|
text(value: string, originalBytes?: number): void;
|
|
8
8
|
image(value: NonNullable<ToolExecutionResult['images']>[number]): void;
|
|
9
9
|
yield(): void;
|
|
@@ -6,6 +6,7 @@ import { TOOL_EXECUTION_LIMITS as limits } from '../execution-limits.js';
|
|
|
6
6
|
import { waitForToolCondition, waitMetadata } from '../wait.js';
|
|
7
7
|
import { BoundedTextOutput, renderCapturedText } from './text-output.js';
|
|
8
8
|
import { boundObservations, newObservationId } from './observations.js';
|
|
9
|
+
import { publicCodeObservations } from '../output-projection.js';
|
|
9
10
|
import { selectObservationImages, visibleObservation } from '../../session/code-observation-projection.js';
|
|
10
11
|
/** Keeps a failed tool call observable without discarding earlier explicit output. */
|
|
11
12
|
export class CodeCellExecutionError extends AgentError {
|
|
@@ -214,7 +215,18 @@ export class CodeCells {
|
|
|
214
215
|
releaseSession = await context.codeMode?.retainSession?.();
|
|
215
216
|
return run(source, { ...context, signal: controller.signal, waitInterrupt: undefined }, {
|
|
216
217
|
call: (value) => cell.calls.set(value.callId, value),
|
|
217
|
-
observe: (value) =>
|
|
218
|
+
observe: (value, display = value, displayHeadTruncated = false) => {
|
|
219
|
+
cell.observations.push(value);
|
|
220
|
+
const observations = [...(cell.display?.observations ?? []), display];
|
|
221
|
+
cell.display = publicCodeObservations(observations, {
|
|
222
|
+
cellId: cell.cellId,
|
|
223
|
+
status: cell.status,
|
|
224
|
+
observations,
|
|
225
|
+
...(cell.display?.outputHeadTruncated || displayHeadTruncated
|
|
226
|
+
? { outputHeadTruncated: true }
|
|
227
|
+
: {})
|
|
228
|
+
});
|
|
229
|
+
},
|
|
218
230
|
text: (text, originalBytes) => cell.text.append(text, originalBytes),
|
|
219
231
|
image: (image) => cell.images.push(image),
|
|
220
232
|
yield: () => {
|
|
@@ -359,7 +371,14 @@ export class CodeCells {
|
|
|
359
371
|
observations: visible.observations.map(visibleObservation)
|
|
360
372
|
}),
|
|
361
373
|
data,
|
|
362
|
-
eventData: {
|
|
374
|
+
eventData: {
|
|
375
|
+
...data,
|
|
376
|
+
...cell.display,
|
|
377
|
+
status: cell.status,
|
|
378
|
+
cached: true,
|
|
379
|
+
...wait,
|
|
380
|
+
executionSource: cell.source
|
|
381
|
+
},
|
|
363
382
|
truncated: data.truncated
|
|
364
383
|
};
|
|
365
384
|
}
|
|
@@ -430,7 +449,12 @@ export class CodeCells {
|
|
|
430
449
|
calls: [...cell.calls.values()],
|
|
431
450
|
observations: remapped,
|
|
432
451
|
data,
|
|
433
|
-
eventData: {
|
|
452
|
+
eventData: {
|
|
453
|
+
...data,
|
|
454
|
+
...cell.display,
|
|
455
|
+
status: cell.status,
|
|
456
|
+
executionSource: cell.source
|
|
457
|
+
},
|
|
434
458
|
truncated: cell.truncated || structured.truncated,
|
|
435
459
|
...(visibleImages.length ? { images: visibleImages } : {})
|
|
436
460
|
};
|
|
@@ -49,6 +49,9 @@ export function createCodeToolDispatch(input) {
|
|
|
49
49
|
const { eventData: _eventData, ...guestResult } = result;
|
|
50
50
|
return {
|
|
51
51
|
...guestResult,
|
|
52
|
+
...((call.name === 'exec' || call.name === 'exec_wait') && data !== undefined
|
|
53
|
+
? { eventData: { ...data } }
|
|
54
|
+
: {}),
|
|
52
55
|
content: bounded.content,
|
|
53
56
|
truncated: result.truncated === true || bounded.truncated
|
|
54
57
|
};
|
|
@@ -300,7 +300,7 @@ export class CodeModeTool {
|
|
|
300
300
|
const images = [];
|
|
301
301
|
const observations = [];
|
|
302
302
|
let observationBytes = 0;
|
|
303
|
-
const appendObservation = (value, originalBytes) => {
|
|
303
|
+
const appendObservation = (value, originalBytes, display) => {
|
|
304
304
|
const capture = new BoundedTextOutput(Math.max(0, limits.codeMaxOutputBytes - observationBytes), '');
|
|
305
305
|
const body = value.type === 'tool_result' ? value.result.content : value.value;
|
|
306
306
|
capture.append(body);
|
|
@@ -323,7 +323,10 @@ export class CodeModeTool {
|
|
|
323
323
|
truncated: value.truncated === true || bounded.droppedBytes > 0
|
|
324
324
|
};
|
|
325
325
|
observations.push(observation);
|
|
326
|
-
output?.observe(observation
|
|
326
|
+
output?.observe(observation, display ?? value, display !== undefined &&
|
|
327
|
+
(display.type === 'tool_result'
|
|
328
|
+
? display.result.truncated === true
|
|
329
|
+
: display.truncated === true));
|
|
327
330
|
};
|
|
328
331
|
const toolResults = new Map();
|
|
329
332
|
let transportBytes = 0;
|
|
@@ -389,6 +392,7 @@ export class CodeModeTool {
|
|
|
389
392
|
return index;
|
|
390
393
|
};
|
|
391
394
|
let observation;
|
|
395
|
+
let displayObservation;
|
|
392
396
|
if (value.type === 'tool_result' && typeof value.operationId === 'string') {
|
|
393
397
|
const original = toolResults.get(value.operationId);
|
|
394
398
|
if (!original)
|
|
@@ -423,6 +427,23 @@ export class CodeModeTool {
|
|
|
423
427
|
...(indices?.length ? { imageIndices: indices } : {})
|
|
424
428
|
}
|
|
425
429
|
};
|
|
430
|
+
const display = original.result.eventData?.displayOutput;
|
|
431
|
+
if ((original.source.toolName === 'exec' || original.source.toolName === 'exec_wait') &&
|
|
432
|
+
display !== null &&
|
|
433
|
+
typeof display === 'object' &&
|
|
434
|
+
'stdout' in display &&
|
|
435
|
+
'stderr' in display &&
|
|
436
|
+
typeof display.stdout === 'string' &&
|
|
437
|
+
typeof display.stderr === 'string')
|
|
438
|
+
displayObservation = {
|
|
439
|
+
...observation,
|
|
440
|
+
result: {
|
|
441
|
+
content: '',
|
|
442
|
+
data: { stdout: display.stdout, stderr: display.stderr },
|
|
443
|
+
truncated: ('stdoutDroppedBytes' in display && Number(display.stdoutDroppedBytes) > 0) ||
|
|
444
|
+
('stderrDroppedBytes' in display && Number(display.stderrDroppedBytes) > 0)
|
|
445
|
+
}
|
|
446
|
+
};
|
|
426
447
|
}
|
|
427
448
|
else if (value.type === 'image') {
|
|
428
449
|
observation = {
|
|
@@ -444,12 +465,22 @@ export class CodeModeTool {
|
|
|
444
465
|
truncated: typeof value.originalBytes === 'number' &&
|
|
445
466
|
value.originalBytes > Buffer.byteLength(value.value)
|
|
446
467
|
};
|
|
468
|
+
if (typeof value.displayValue === 'string') {
|
|
469
|
+
if (Buffer.byteLength(value.displayValue) > 10_000)
|
|
470
|
+
throw new AgentError('MAR_AGENT_CODE_PROTOCOL_ERROR', 'Code Mode sent oversized display text.');
|
|
471
|
+
displayObservation = {
|
|
472
|
+
...observation,
|
|
473
|
+
value: value.displayValue,
|
|
474
|
+
truncated: typeof value.originalBytes === 'number' &&
|
|
475
|
+
value.originalBytes > Buffer.byteLength(value.displayValue)
|
|
476
|
+
};
|
|
477
|
+
}
|
|
447
478
|
}
|
|
448
479
|
else
|
|
449
480
|
throw new AgentError('MAR_AGENT_CODE_PROTOCOL_ERROR', 'Invalid observation frame.');
|
|
450
481
|
appendObservation(observation, value.type === 'value' && typeof value.originalBytes === 'number'
|
|
451
482
|
? value.originalBytes
|
|
452
|
-
: undefined);
|
|
483
|
+
: undefined, displayObservation);
|
|
453
484
|
}
|
|
454
485
|
else if (frame.kind === 'text' && typeof frame.value === 'string') {
|
|
455
486
|
const originalBytes = frame.originalBytes ?? Buffer.byteLength(frame.value);
|
|
@@ -527,10 +558,11 @@ export class CodeModeTool {
|
|
|
527
558
|
: undefined
|
|
528
559
|
}
|
|
529
560
|
});
|
|
530
|
-
const {
|
|
561
|
+
const { eventData: _eventData, ...guestOutput } = output;
|
|
562
|
+
const { content, ...structured } = guestOutput;
|
|
531
563
|
const projected = output.data !== undefined && content === JSON.stringify(output.data)
|
|
532
564
|
? structured
|
|
533
|
-
:
|
|
565
|
+
: guestOutput;
|
|
534
566
|
await write({ id, ok: true, output: projected });
|
|
535
567
|
}
|
|
536
568
|
catch (error) {
|
|
@@ -354,6 +354,7 @@ export async function createCodeModeEngine(options) {
|
|
|
354
354
|
}
|
|
355
355
|
const separatorBytes = textCalls ? 1 : 0;
|
|
356
356
|
const capture = new BoundedTextOutput(Math.max(0, input.limits.outputBytes - outputBytes - separatorBytes), '');
|
|
357
|
+
const display = new BoundedTextOutput(10_000, '', 'tail');
|
|
357
358
|
const emit = vm.newFunction('textChunk', (chunk) => {
|
|
358
359
|
if (!chunk || vm.typeof(chunk) !== 'string')
|
|
359
360
|
return {
|
|
@@ -366,7 +367,9 @@ export async function createCodeModeEngine(options) {
|
|
|
366
367
|
return {
|
|
367
368
|
error: guestError('MAR_AGENT_TOOL_OUTPUT_LIMIT', 'Text serialization chunk limit exceeded.')
|
|
368
369
|
};
|
|
369
|
-
|
|
370
|
+
const text = vm.getString(chunk);
|
|
371
|
+
capture.append(text);
|
|
372
|
+
display.append(text);
|
|
370
373
|
return vm.undefined;
|
|
371
374
|
});
|
|
372
375
|
const result = callGuest(formatText, vm.undefined, handle ?? vm.undefined, emit);
|
|
@@ -381,6 +384,7 @@ export async function createCodeModeEngine(options) {
|
|
|
381
384
|
type: 'value',
|
|
382
385
|
format: handle && vm.typeof(handle) === 'object' ? 'json' : 'text',
|
|
383
386
|
value: captured.text,
|
|
387
|
+
displayValue: display.snapshot().text,
|
|
384
388
|
originalBytes: captured.originalBytes
|
|
385
389
|
});
|
|
386
390
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export function renderCapturedText(snapshot: any, imageCount?: number): string;
|
|
2
2
|
/** Bounded UTF-8 capture shared by trusted engines, the bridge and retained cells. */
|
|
3
3
|
export class BoundedTextOutput {
|
|
4
|
-
constructor(maximumBytes: any, separator?: string);
|
|
4
|
+
constructor(maximumBytes: any, separator?: string, retention?: string);
|
|
5
5
|
maximumBytes: any;
|
|
6
6
|
separator: string;
|
|
7
|
+
retention: string;
|
|
7
8
|
append(value: any, originalBytes?: number): void;
|
|
8
9
|
snapshot(): {
|
|
9
10
|
text: string;
|
|
@@ -6,9 +6,10 @@ export class BoundedTextOutput {
|
|
|
6
6
|
#retained = 0;
|
|
7
7
|
#hasValue = false;
|
|
8
8
|
#sealed = false;
|
|
9
|
-
constructor(maximumBytes, separator = '\n') {
|
|
9
|
+
constructor(maximumBytes, separator = '\n', retention = 'head') {
|
|
10
10
|
this.maximumBytes = maximumBytes;
|
|
11
11
|
this.separator = separator;
|
|
12
|
+
this.retention = retention;
|
|
12
13
|
}
|
|
13
14
|
append(value, originalBytes = Buffer.byteLength(value)) {
|
|
14
15
|
const separator = this.#hasValue ? this.separator : '';
|
|
@@ -16,10 +17,22 @@ export class BoundedTextOutput {
|
|
|
16
17
|
this.#original += Buffer.byteLength(separator) + originalBytes;
|
|
17
18
|
this.#capture(separator);
|
|
18
19
|
this.#capture(value);
|
|
19
|
-
if (originalBytes > Buffer.byteLength(value))
|
|
20
|
+
if (this.retention === 'head' && originalBytes > Buffer.byteLength(value))
|
|
20
21
|
this.#sealed = true;
|
|
21
22
|
}
|
|
22
23
|
#capture(value) {
|
|
24
|
+
if (this.retention === 'tail') {
|
|
25
|
+
let start = Math.max(0, value.length - this.maximumBytes);
|
|
26
|
+
if (start > 0 && /[\uDC00-\uDFFF]/u.test(value[start]))
|
|
27
|
+
start++;
|
|
28
|
+
const bytes = Buffer.from(this.#chunks.join('') + value.slice(start));
|
|
29
|
+
let offset = Math.max(0, bytes.length - this.maximumBytes);
|
|
30
|
+
while (offset < bytes.length && (bytes[offset] & 0xc0) === 0x80)
|
|
31
|
+
offset++;
|
|
32
|
+
this.#chunks = [bytes.subarray(offset).toString('utf8')];
|
|
33
|
+
this.#retained = bytes.length - offset;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
23
36
|
const remaining = Math.max(0, this.maximumBytes - this.#used);
|
|
24
37
|
if (this.#sealed || !value.length)
|
|
25
38
|
return;
|
|
@@ -12,6 +12,8 @@ export declare function boundedModelToolOutput(toolName: string, value: string,
|
|
|
12
12
|
};
|
|
13
13
|
/** The opted-in allowlist fails closed and never mutates the invocation arguments. */
|
|
14
14
|
export declare function publicToolEventInput(value: unknown, fields: readonly string[]): Readonly<Record<string, unknown>>;
|
|
15
|
+
/** Explicit observations are public, but their event projection must remain bounded. */
|
|
16
|
+
export declare function publicCodeObservations(values: unknown, data: CodeCellEventData): CodeCellEventData;
|
|
15
17
|
/** Project only known, validated tool result shapes into public structured events. */
|
|
16
18
|
export declare function structuredToolEventData(toolName: string, value: unknown): CodeCellEventData | ExecResult | ApplyPatchResult | ReadEventData | ViewImageResult | SleepResult | PublicToolMetadata | undefined;
|
|
17
19
|
/** Partial patch facts are allowlisted; arbitrary error details never become public event data. */
|
|
@@ -68,7 +68,7 @@ export function publicToolEventInput(value, fields) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
/** Explicit observations are public, but their event projection must remain bounded. */
|
|
71
|
-
function publicCodeObservations(values, data) {
|
|
71
|
+
export function publicCodeObservations(values, data) {
|
|
72
72
|
if (!Array.isArray(values))
|
|
73
73
|
return data;
|
|
74
74
|
const retained = new Set(data.observations ?? []);
|