@myagentroam/agent 0.9.139 → 0.9.141
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 +3 -1
- package/dist/host/local-agent-host.js +29 -3
- package/dist/model/anthropic-messages.js +24 -7
- package/dist/model/contracts.d.ts +4 -0
- package/dist/model/openai-responses.js +28 -10
- package/dist/model/sse.d.ts +2 -0
- package/dist/model/sse.js +11 -1
- package/dist/prompts/resources.js +4 -2
- package/dist/prompts/workflow.js +2 -0
- package/dist/runtime/context-gc.js +25 -8
- package/dist/sdk/agent.js +68 -42
- package/dist/session/context-gc-checkpoint.d.ts +1 -1
- package/dist/session/context-gc-checkpoint.js +8 -5
- package/dist/session/context-gc-replacements.d.ts +1 -1
- package/dist/session/context-gc-replacements.js +5 -3
- package/dist/tools/agent-wait.js +1 -1
- package/dist/tools/apply-patch.js +1 -1
- package/dist/tools/callers.js +1 -1
- package/dist/tools/code-mode/cells.d.ts +7 -1
- package/dist/tools/code-mode/cells.js +32 -8
- package/dist/tools/code-mode/engine.d.ts +5 -2
- package/dist/tools/code-mode/quickjs-engine.js +116 -18
- package/dist/tools/code-mode/text-output.d.ts +21 -0
- package/dist/tools/code-mode/text-output.js +75 -0
- package/dist/tools/code-mode/worker.js +1 -1
- package/dist/tools/code-mode.js +36 -18
- package/dist/tools/exec.d.ts +3 -0
- package/dist/tools/exec.js +56 -15
- package/dist/tools/execution-limits.d.ts +4 -1
- package/dist/tools/execution-limits.js +4 -1
- package/dist/tools/local-registry.js +5 -5
- package/dist/tools/registry.js +2 -1
- package/dist/tools/skill.js +1 -1
- package/dist/tools/tool-search.js +5 -3
- package/package.json +1 -1
package/dist/sdk/agent.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
2
|
import { isDeepStrictEqual } from 'node:util';
|
|
3
3
|
import { describeMarAgentError, MarAgentError } from '../error.js';
|
|
4
|
+
import { CodeCellExecutionError } from '../tools/code-mode/cells.js';
|
|
4
5
|
import { negotiateHost } from '../host/contracts.js';
|
|
5
6
|
import { AnthropicMessagesAdapter, isAnthropicRecoverableStreamError } from '../model/anthropic-messages.js';
|
|
6
7
|
import { marAgentReasoningEffortSchema, resolveModelDefaultReasoningEffort, usesResponsesConfigurationUpdates } from '../model/configuration.js';
|
|
@@ -36,8 +37,8 @@ import { createCodeToolDispatch } from '../tools/code-mode/dispatch.js';
|
|
|
36
37
|
import { createSessionToolScheduler, scheduleToolCallBatch } from '../tools/scheduler.js';
|
|
37
38
|
import { projectCodeModeSearchResult, projectCodeModeTools } from '../tools/code-mode.js';
|
|
38
39
|
import { allowsDirectTool, allowsToolCaller, toolCallers } from '../tools/callers.js';
|
|
40
|
+
import { modelStreamEventObservedAt } from '../model/sse.js';
|
|
39
41
|
import { SubagentSessionController } from '../subagent/session-controller.js';
|
|
40
|
-
const MODEL_PERFORMANCE_MIN_INTERVAL_MS = 1_000;
|
|
41
42
|
/** Retry only classified recoverable failures within the attempt budget; never retry cancellation. */
|
|
42
43
|
async function recoverModelStream(error, retryState, signal) {
|
|
43
44
|
if (signal.aborted ||
|
|
@@ -612,7 +613,14 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
612
613
|
instructionContent: renderAgentInstructions(instructionEntries, compactMayContainAgentInstructions ||
|
|
613
614
|
contextualWorldState.instructionSnapshot !== undefined),
|
|
614
615
|
resourceSnapshot: currentResourceSnapshot,
|
|
615
|
-
previousMayContainResources: compactMayContainRetainedResources
|
|
616
|
+
previousMayContainResources: (!contextualWorldState.initialized && compactMayContainRetainedResources) ||
|
|
617
|
+
(options.host.listSessionResources !== undefined &&
|
|
618
|
+
currentResourceSnapshot === undefined &&
|
|
619
|
+
messages
|
|
620
|
+
.slice(contextualWorldState.entries.findLast((entry) => entry.kind === 'resources')
|
|
621
|
+
?.index ?? 0)
|
|
622
|
+
.some((message) => message.role === 'tool_call' &&
|
|
623
|
+
['exec', 'code_exec', 'code_mode', 'agent_start'].includes(message.name ?? '')))
|
|
616
624
|
});
|
|
617
625
|
sessionRuntime.contextualWorldState = contextualWorldState;
|
|
618
626
|
if (!isDeepStrictEqual(previousContextualWorldState, contextualWorldState))
|
|
@@ -898,40 +906,39 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
898
906
|
let sawModelSemanticEvent = false;
|
|
899
907
|
let requestStartedAt;
|
|
900
908
|
let firstModelResponseAt;
|
|
909
|
+
let firstOutputDeltaAt;
|
|
910
|
+
let lastOutputDeltaAt;
|
|
901
911
|
let requestCompletedAt;
|
|
902
912
|
let requestOutputTokens;
|
|
903
|
-
let outputTokenRevision = 0;
|
|
904
|
-
let lastPerformanceEmittedAt;
|
|
905
|
-
let lastPublishedOutputTokenRevision = 0;
|
|
906
|
-
let performanceEmitted = false;
|
|
907
913
|
const roundMessageCount = messages.length;
|
|
908
|
-
const
|
|
914
|
+
const emitLatency = async () => {
|
|
909
915
|
if (mode === 'compact' || firstModelResponseAt === undefined)
|
|
910
916
|
return;
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
917
|
+
await emit({
|
|
918
|
+
type: 'model.performance',
|
|
919
|
+
latencyMs: Math.max(0, Math.round(firstModelResponseAt - requestStartedAt))
|
|
920
|
+
});
|
|
921
|
+
};
|
|
922
|
+
const emitFinalPerformance = async (completedAt) => {
|
|
923
|
+
if (mode === 'compact' ||
|
|
924
|
+
firstModelResponseAt === undefined ||
|
|
925
|
+
firstOutputDeltaAt === undefined ||
|
|
926
|
+
lastOutputDeltaAt === undefined ||
|
|
927
|
+
lastOutputDeltaAt - firstOutputDeltaAt < 1)
|
|
919
928
|
return;
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
929
|
+
const outputDuration = completedAt - firstOutputDeltaAt;
|
|
930
|
+
const outputTokens = requestOutputTokens;
|
|
931
|
+
if (outputTokens === undefined ||
|
|
932
|
+
outputDuration < 1 ||
|
|
933
|
+
completedAt < lastOutputDeltaAt)
|
|
923
934
|
return;
|
|
924
935
|
await emit({
|
|
925
936
|
type: 'model.performance',
|
|
926
937
|
latencyMs: Math.max(0, Math.round(firstModelResponseAt - requestStartedAt)),
|
|
927
|
-
|
|
928
|
-
outputDurationMs,
|
|
929
|
-
|
|
938
|
+
outputTokens,
|
|
939
|
+
outputDurationMs: Math.round(outputDuration),
|
|
940
|
+
tokensPerSecond: Number(((outputTokens * 1000) / outputDuration).toFixed(2))
|
|
930
941
|
});
|
|
931
|
-
performanceEmitted = true;
|
|
932
|
-
lastPerformanceEmittedAt = sampledAt;
|
|
933
|
-
if (tokensPerSecond !== undefined)
|
|
934
|
-
lastPublishedOutputTokenRevision = outputTokenRevision;
|
|
935
942
|
};
|
|
936
943
|
const persistToolCalls = async (calls) => {
|
|
937
944
|
for (const call of calls) {
|
|
@@ -978,10 +985,25 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
978
985
|
...(modelInputImages?.length ? { images: modelInputImages } : {}),
|
|
979
986
|
onAttemptDiagnostic: recordModelAttempt(mode === 'compact' ? 'COMPACTION' : 'EXECUTION')
|
|
980
987
|
})) {
|
|
981
|
-
|
|
988
|
+
if (event.type === 'output.reset') {
|
|
989
|
+
firstOutputDeltaAt = undefined;
|
|
990
|
+
lastOutputDeltaAt = undefined;
|
|
991
|
+
requestOutputTokens = undefined;
|
|
992
|
+
continue;
|
|
993
|
+
}
|
|
994
|
+
const modelResponseAt = mode !== 'compact' && isModelResponseEvent(event)
|
|
995
|
+
? Math.max(requestStartedAt, modelStreamEventObservedAt(event) ?? performance.now())
|
|
996
|
+
: undefined;
|
|
997
|
+
const isFirstModelResponse = modelResponseAt !== undefined && firstModelResponseAt === undefined;
|
|
982
998
|
if (modelResponseAt !== undefined) {
|
|
983
|
-
|
|
999
|
+
if (event.type !== 'output.delta')
|
|
1000
|
+
sawModelSemanticEvent = true;
|
|
984
1001
|
firstModelResponseAt ??= modelResponseAt;
|
|
1002
|
+
if (event.type === 'output.delta' ||
|
|
1003
|
+
(event.type === 'text.delta' && event.delta.length > 0)) {
|
|
1004
|
+
firstOutputDeltaAt ??= modelResponseAt;
|
|
1005
|
+
lastOutputDeltaAt = modelResponseAt;
|
|
1006
|
+
}
|
|
985
1007
|
}
|
|
986
1008
|
if (event.type === 'response.item') {
|
|
987
1009
|
// Compaction keeps only its successful checkpoint, never intermediate native output.
|
|
@@ -1070,7 +1092,6 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
1070
1092
|
: undefined;
|
|
1071
1093
|
if (outputTokens !== undefined) {
|
|
1072
1094
|
requestOutputTokens = outputTokens;
|
|
1073
|
-
outputTokenRevision++;
|
|
1074
1095
|
}
|
|
1075
1096
|
const reportedContext = event.usage.contextInputTokens ?? event.usage.inputTokens;
|
|
1076
1097
|
if (reportedContext !== undefined &&
|
|
@@ -1119,14 +1140,14 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
1119
1140
|
}
|
|
1120
1141
|
else if (event.type === 'completed') {
|
|
1121
1142
|
stop = event.reason;
|
|
1122
|
-
requestCompletedAt = performance.now();
|
|
1143
|
+
requestCompletedAt = modelStreamEventObservedAt(event) ?? performance.now();
|
|
1123
1144
|
}
|
|
1124
|
-
if (
|
|
1125
|
-
await
|
|
1145
|
+
if (isFirstModelResponse)
|
|
1146
|
+
await emitLatency();
|
|
1126
1147
|
}
|
|
1127
1148
|
if (mode !== 'compact' && firstModelResponseAt !== undefined) {
|
|
1128
1149
|
const completedAt = requestCompletedAt ?? performance.now();
|
|
1129
|
-
await
|
|
1150
|
+
await emitFinalPerformance(completedAt);
|
|
1130
1151
|
}
|
|
1131
1152
|
pendingOutputContinuation = undefined;
|
|
1132
1153
|
incompleteToolCall = pendingTools.some((call) => call.argumentError !== undefined);
|
|
@@ -1291,6 +1312,7 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
1291
1312
|
}
|
|
1292
1313
|
catch (error) {
|
|
1293
1314
|
const diagnostic = describeMarAgentError(error, 'MAR_AGENT_HOST_OPERATION_FAILED');
|
|
1315
|
+
const partial = error instanceof CodeCellExecutionError ? error.result : undefined;
|
|
1294
1316
|
await emit({
|
|
1295
1317
|
type: 'tool.failed',
|
|
1296
1318
|
toolName: call.name,
|
|
@@ -1301,13 +1323,16 @@ export async function createMarAgentWithAdapter(options) {
|
|
|
1301
1323
|
});
|
|
1302
1324
|
return {
|
|
1303
1325
|
call,
|
|
1304
|
-
content:
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1326
|
+
content: partial === undefined
|
|
1327
|
+
? JSON.stringify({
|
|
1328
|
+
error: diagnostic.code,
|
|
1329
|
+
message: diagnostic.message,
|
|
1330
|
+
...(error instanceof MarAgentError && error.retryable
|
|
1331
|
+
? { retryable: true }
|
|
1332
|
+
: {})
|
|
1333
|
+
})
|
|
1334
|
+
: boundedModelToolOutput(call.name, partial.content, partial.data).content,
|
|
1335
|
+
...(partial?.images?.length ? { images: partial.images } : {}),
|
|
1311
1336
|
failed: true,
|
|
1312
1337
|
error
|
|
1313
1338
|
};
|
|
@@ -2237,7 +2262,7 @@ function updateContextualWorldState(state, index, current) {
|
|
|
2237
2262
|
if (current.instructionContent !== undefined)
|
|
2238
2263
|
entries.push({ index, kind: 'instructions', content: current.instructionContent });
|
|
2239
2264
|
}
|
|
2240
|
-
const resourceContent = retainedSessionResourcesUpdate(current.resourceSnapshot, state.initialized ? state.resourceSnapshot : undefined,
|
|
2265
|
+
const resourceContent = retainedSessionResourcesUpdate(current.resourceSnapshot, state.initialized ? state.resourceSnapshot : undefined, current.previousMayContainResources);
|
|
2241
2266
|
if (resourceContent !== undefined)
|
|
2242
2267
|
entries.push({ index, kind: 'resources', content: resourceContent });
|
|
2243
2268
|
return {
|
|
@@ -2283,7 +2308,7 @@ function estimatedRequestTokens(system, messages, tools, images) {
|
|
|
2283
2308
|
transientImageCount * AGENT_EXECUTION_POLICY.estimatedTokensPerImage);
|
|
2284
2309
|
}
|
|
2285
2310
|
function boundedModelToolOutput(toolName, value, data) {
|
|
2286
|
-
const execDiagnostics = toolName === 'exec' &&
|
|
2311
|
+
const execDiagnostics = (toolName === 'exec' || toolName === 'exec_wait') &&
|
|
2287
2312
|
isRecord(data) &&
|
|
2288
2313
|
typeof data.stdout === 'string' &&
|
|
2289
2314
|
typeof data.stderr === 'string'
|
|
@@ -2390,7 +2415,7 @@ function structuredToolEventData(toolName, value) {
|
|
|
2390
2415
|
typeof value.sha256 === 'string' &&
|
|
2391
2416
|
/^[a-f0-9]{64}$/u.test(value.sha256))
|
|
2392
2417
|
return value;
|
|
2393
|
-
if (toolName === 'exec' &&
|
|
2418
|
+
if ((toolName === 'exec' || toolName === 'exec_wait') &&
|
|
2394
2419
|
(value.status === 'running' || value.status === 'completed' || value.status === 'cancelled') &&
|
|
2395
2420
|
typeof value.stdout === 'string' &&
|
|
2396
2421
|
typeof value.stderr === 'string' &&
|
|
@@ -2457,6 +2482,7 @@ function isModelResponseEvent(event) {
|
|
|
2457
2482
|
if (event.type === 'text.completed' || event.type === 'reasoning.summary')
|
|
2458
2483
|
return event.text.length > 0;
|
|
2459
2484
|
return (event.type === 'response.item' ||
|
|
2485
|
+
event.type === 'output.delta' ||
|
|
2460
2486
|
event.type === 'client_tool.call' ||
|
|
2461
2487
|
event.type === 'hosted_tool' ||
|
|
2462
2488
|
event.type === 'citation');
|
|
@@ -50,7 +50,7 @@ export type ContextGcReplacement = {
|
|
|
50
50
|
readonly evidenceSequences: readonly number[];
|
|
51
51
|
} | {
|
|
52
52
|
readonly kind: 'TOOL_CALL_INPUT';
|
|
53
|
-
readonly toolName: 'apply_patch' | 'exec' | 'code_mode' | 'code_exec';
|
|
53
|
+
readonly toolName: 'apply_patch' | 'exec' | 'exec_wait' | 'code_mode' | 'code_exec';
|
|
54
54
|
readonly callId: string;
|
|
55
55
|
readonly target: ContextGcTarget;
|
|
56
56
|
readonly replacementArguments: unknown;
|
|
@@ -350,8 +350,9 @@ function replacementMatchesRecords(replacement, records, recordsBySequence, work
|
|
|
350
350
|
if (!isSuccessfulExecLifecycleEvidence(replacement, source, records, recordsBySequence))
|
|
351
351
|
return false;
|
|
352
352
|
if (replacement.kind === 'TOOL_CALL_INPUT')
|
|
353
|
-
return isDeepStrictEqual(replacement.replacementArguments, contextGcExecInputReplacement(source.payload.arguments, execInputReplacementFormatVersion(replacement.replacementArguments)));
|
|
354
|
-
const targetEvidence = successfulToolEvidence(records, recordsBySequence, source.sequence, 'exec')
|
|
353
|
+
return isDeepStrictEqual(replacement.replacementArguments, contextGcExecInputReplacement(source.payload.arguments, execInputReplacementFormatVersion(replacement.replacementArguments), replacement.toolName));
|
|
354
|
+
const targetEvidence = successfulToolEvidence(records, recordsBySequence, source.sequence, 'exec') ??
|
|
355
|
+
successfulToolEvidence(records, recordsBySequence, source.sequence, 'exec_wait');
|
|
355
356
|
const result = normalizeContextGcExecResult(source.payload.content, targetEvidence?.completed.payload);
|
|
356
357
|
return (result !== undefined &&
|
|
357
358
|
replacement.replacementContent ===
|
|
@@ -474,7 +475,8 @@ function successfulPatchEvidenceForPath(records, recordsBySequence, evidenceSequ
|
|
|
474
475
|
: undefined;
|
|
475
476
|
}
|
|
476
477
|
function isSuccessfulExecLifecycleEvidence(replacement, source, records, recordsBySequence) {
|
|
477
|
-
const evidence = successfulToolEvidence(records, recordsBySequence, replacement.evidenceSequence, 'exec')
|
|
478
|
+
const evidence = successfulToolEvidence(records, recordsBySequence, replacement.evidenceSequence, 'exec') ??
|
|
479
|
+
successfulToolEvidence(records, recordsBySequence, replacement.evidenceSequence, 'exec_wait');
|
|
478
480
|
if (!evidence || !isRecord(evidence.call.payload) || !isRecord(evidence.result.payload))
|
|
479
481
|
return false;
|
|
480
482
|
const finalResult = normalizeContextGcExecResult(evidence.result.payload.content, evidence.completed.payload);
|
|
@@ -487,7 +489,7 @@ function isSuccessfulExecLifecycleEvidence(replacement, source, records, records
|
|
|
487
489
|
targetCall.sequence > evidence.call.sequence ||
|
|
488
490
|
!isRecord(targetCall.payload) ||
|
|
489
491
|
targetCall.payload.role !== 'tool_call' ||
|
|
490
|
-
targetCall.payload.name !== 'exec' ||
|
|
492
|
+
(targetCall.payload.name !== 'exec' && targetCall.payload.name !== 'exec_wait') ||
|
|
491
493
|
targetCall.payload.callId !== replacement.callId)
|
|
492
494
|
return false;
|
|
493
495
|
const targetResult = replacement.kind === 'EXEC_OUTPUT'
|
|
@@ -495,7 +497,7 @@ function isSuccessfulExecLifecycleEvidence(replacement, source, records, records
|
|
|
495
497
|
: modelToolResultForCall(records, targetCall, evidence.result.sequence);
|
|
496
498
|
if (!targetResult)
|
|
497
499
|
return false;
|
|
498
|
-
const targetEvidence = successfulToolEvidence(records, recordsBySequence, targetResult.sequence,
|
|
500
|
+
const targetEvidence = successfulToolEvidence(records, recordsBySequence, targetResult.sequence, targetCall.payload.name);
|
|
499
501
|
if (!targetEvidence || targetEvidence.call.sequence !== targetCall.sequence)
|
|
500
502
|
return false;
|
|
501
503
|
if (targetEvidence.callId === evidence.callId)
|
|
@@ -631,6 +633,7 @@ function isContextGcReplacement(value) {
|
|
|
631
633
|
value.target.role === 'tool_call' &&
|
|
632
634
|
(value.toolName === 'apply_patch' ||
|
|
633
635
|
value.toolName === 'exec' ||
|
|
636
|
+
value.toolName === 'exec_wait' ||
|
|
634
637
|
value.toolName === 'code_mode' ||
|
|
635
638
|
value.toolName === 'code_exec') &&
|
|
636
639
|
value.target.toolName === value.toolName &&
|
|
@@ -56,7 +56,7 @@ export declare function contextGcStaleReadReplacement(input: {
|
|
|
56
56
|
readonly formatVersion?: 1 | 2;
|
|
57
57
|
}): string;
|
|
58
58
|
export declare function contextGcWebOutputReplacement(toolName: ContextGcWebToolName, originalContent: string, truncated: boolean): string;
|
|
59
|
-
export declare function contextGcExecInputReplacement(arguments_: unknown, formatVersion?: 1 | 2 | 3): unknown;
|
|
59
|
+
export declare function contextGcExecInputReplacement(arguments_: unknown, formatVersion?: 1 | 2 | 3, toolName?: string): unknown;
|
|
60
60
|
export declare function contextGcExecOutputReplacement(result: ContextGcExecResult, formatVersion?: 1 | 2 | 3): string;
|
|
61
61
|
export declare function normalizeContextGcExecResult(modelContent: unknown, completedPayload: unknown): ContextGcExecResult | undefined;
|
|
62
62
|
export declare function parseContextGcExecResult(value: unknown): ContextGcExecResult | undefined;
|
|
@@ -97,14 +97,16 @@ export function contextGcWebOutputReplacement(toolName, originalContent, truncat
|
|
|
97
97
|
contextGc: 'Detailed web tool output was reclaimed after six successful rollouts. An incomplete preview is not the complete search result or page, and GC did not access the network.'
|
|
98
98
|
});
|
|
99
99
|
}
|
|
100
|
-
export function contextGcExecInputReplacement(arguments_, formatVersion = 3) {
|
|
100
|
+
export function contextGcExecInputReplacement(arguments_, formatVersion = 3, toolName = 'exec') {
|
|
101
101
|
if (!isRecord(arguments_))
|
|
102
102
|
return `<context_gc kind="terminal_exec_input"${formatVersion === 3 ? ' formatVersion="3"' : ''} originalBytes="${Buffer.byteLength(stableJson(arguments_))}"${formatVersion === 3 ? '' : ` originalSha256="${sha256(stableJson(arguments_))}"`} />`;
|
|
103
103
|
const action = typeof arguments_.action === 'string'
|
|
104
104
|
? arguments_.action
|
|
105
105
|
: typeof arguments_.command === 'string'
|
|
106
106
|
? 'start'
|
|
107
|
-
: '
|
|
107
|
+
: toolName === 'exec_wait'
|
|
108
|
+
? 'poll'
|
|
109
|
+
: 'unknown';
|
|
108
110
|
const original = stableJson(arguments_);
|
|
109
111
|
const retained = {
|
|
110
112
|
action,
|
|
@@ -190,7 +192,7 @@ export function normalizeContextGcExecResult(modelContent, completedPayload) {
|
|
|
190
192
|
if (typeof modelContent !== 'string' ||
|
|
191
193
|
!isRecord(completedPayload) ||
|
|
192
194
|
completedPayload.type !== 'tool.completed' ||
|
|
193
|
-
completedPayload.toolName !== 'exec' ||
|
|
195
|
+
(completedPayload.toolName !== 'exec' && completedPayload.toolName !== 'exec_wait') ||
|
|
194
196
|
completedPayload.truncated !== true)
|
|
195
197
|
return undefined;
|
|
196
198
|
const data = completedPayload.data;
|
package/dist/tools/agent-wait.js
CHANGED
|
@@ -4,7 +4,7 @@ export const agentWaitToolDefinition = {
|
|
|
4
4
|
name: 'agent_wait',
|
|
5
5
|
allowedCallers: ['direct', 'programmatic'],
|
|
6
6
|
parallelSafety: 'serial',
|
|
7
|
-
description: 'Read or wait a bounded time for a child agent result. waitFor defaults to "completion"; use "message" only when a fresh public commentary/final message would change the next decision. Omit agentId to wait for whichever live child returns first, matching Codex-style untargeted waiting and avoiding UUID transcription; provide the exact agentId returned by agent_start only when observing a specific child. If no child is live, untargeted waiting reads the most recently created child. For an exec processId, use
|
|
7
|
+
description: 'Read or wait a bounded time for a child agent result. waitFor defaults to "completion"; use "message" only when a fresh public commentary/final message would change the next decision. Omit agentId to wait for whichever live child returns first, matching Codex-style untargeted waiting and avoiding UUID transcription; provide the exact agentId returned by agent_start only when observing a specific child. If no child is live, untargeted waiting reads the most recently created child. For an exec processId, use exec_wait instead (tools.exec_wait in Code Mode). Omitting waitMs waits up to 30 seconds by default; waitMs=0 returns the current snapshot immediately. Positive waits range up to 5 minutes, and positive values below 10 seconds are raised to 10 seconds. When blocked on a live child result, prefer one 300000 ms completion wait rather than repeated short waits. Every result includes waitOutcome as snapshot, message, completion, or timeout plus the real agentId and description. A message, timeout with unread progress, or first terminal completion result includes the newly observed latest public commentary/final message; snapshots and repeated observations omit previously observed message text. latestActivity can still identify a public message or bounded tool started/completed/failed status. A queued or running result is not completion. A message wait consumes only the latest unread public message in the current Session runtime; tool activity does not wake it, and parent cancellation preserves unread progress for a later Execution. Do not use message waits as heartbeat checks or request progress merely to confirm that a child is still running. First terminal results include bounded summary, changedFiles, verification, and read evidence with path/line ranges; use that evidence to avoid repeating the full exploration, while independently checking consequential edits and claims.',
|
|
8
8
|
inputSchema: {
|
|
9
9
|
type: 'object',
|
|
10
10
|
properties: {
|
|
@@ -8,7 +8,7 @@ export const applyPatchToolDefinition = {
|
|
|
8
8
|
name: 'apply_patch',
|
|
9
9
|
allowedCallers: ['direct', 'programmatic'],
|
|
10
10
|
parallelSafety: 'serial',
|
|
11
|
-
description: `Preferred for precise, reviewable local edits. Do not batch all task files merely to reduce tool calls. Group only a few tightly coupled edits whose combined patch is quick to generate and review; split broad or independent work into successive bounded patches before composing them. Submit a raw *** Begin Patch / *** End Patch patch. Supports Add File, Update File, Delete File, and Move to. Add File may replace an existing regular file, and Move to may replace an existing regular destination; duplicate operations on the same resolved path remain invalid. Update hunks accept @@ or @@ <change context>; context-only hunks may also be used as ordered anchors before a later changing hunk. Context is searched forward with Codex-style exact, whitespace-tolerant, then common Unicode punctuation-tolerant matching. Syntax and resolved paths are validated before writing, then file units are committed in order. Each file unit is atomic, and a Move keeps its source and destination atomic. On MAR_AGENT_PATCH_PARTIAL, earlier files remain applied; the error lists applied, failed, and pending paths, so retry only failed and pending paths. Existing file permissions, line endings, and final-newline state are preserved. Returns changed file paths and operations with per-file and total line counts when all units succeed. In Code Mode, the Promise resolves on success and rejects with code/message on failure; the returned envelope has data.files and data.totals, not an ok or success flag. Oversized patches are rejected without advertising defensive limits as recommended patch sizes. A first-unit MAR_AGENT_PATCH_CONFLICT applies nothing; hunk match conflicts identify the affected path and hunk so you can reread only that file before retrying.`,
|
|
11
|
+
description: `Preferred for precise, reviewable local edits. Do not batch all task files merely to reduce tool calls. Group only a few tightly coupled edits whose combined patch is quick to generate and review; split broad or independent work into successive bounded patches before composing them. Submit a raw *** Begin Patch / *** End Patch patch. Supports Add File, Update File, Delete File, and Move to. Add File may replace an existing regular file, and Move to may replace an existing regular destination; duplicate operations on the same resolved path remain invalid. Update hunks accept @@ or @@ <change context>; context-only hunks may also be used as ordered anchors before a later changing hunk. Omit unchanged file sections: an Update File must change or move the file, and its last hunk must not be context-only. Context is searched forward with Codex-style exact, whitespace-tolerant, then common Unicode punctuation-tolerant matching. Syntax and resolved paths are validated before writing, then file units are committed in order. Each file unit is atomic, and a Move keeps its source and destination atomic. On MAR_AGENT_PATCH_PARTIAL, earlier files remain applied; the error lists applied, failed, and pending paths, so retry only failed and pending paths. Existing file permissions, line endings, and final-newline state are preserved. Returns changed file paths and operations with per-file and total line counts when all units succeed. In Code Mode, the Promise resolves on success and rejects with code/message on failure; the returned envelope has data.files and data.totals, not an ok or success flag. Oversized patches are rejected without advertising defensive limits as recommended patch sizes. A first-unit MAR_AGENT_PATCH_CONFLICT applies nothing; hunk match conflicts identify the affected path and hunk so you can reread only that file before retrying.`,
|
|
12
12
|
inputMode: 'freeform',
|
|
13
13
|
outputSchema: {
|
|
14
14
|
type: 'object',
|
package/dist/tools/callers.js
CHANGED
|
@@ -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'].includes(tool.name))
|
|
16
|
+
['code_exec', 'code_exec_wait', 'code_mode', 'tool_search', 'question', 'skill'].includes(tool.name))
|
|
17
17
|
return false;
|
|
18
18
|
return toolCallers(tool).includes(caller);
|
|
19
19
|
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import { MarAgentError } from '../../error.js';
|
|
1
2
|
import type { ToolExecutionContext, ToolExecutionResult } from '../../sdk/types.js';
|
|
2
3
|
export interface CellOutput {
|
|
3
|
-
text(value: string): void;
|
|
4
|
+
text(value: string, originalBytes?: number): void;
|
|
4
5
|
image(value: NonNullable<ToolExecutionResult['images']>[number]): void;
|
|
5
6
|
yield(): void;
|
|
6
7
|
}
|
|
8
|
+
/** Keeps a failed tool call observable without discarding earlier explicit output. */
|
|
9
|
+
export declare class CodeCellExecutionError extends MarAgentError {
|
|
10
|
+
readonly result: ToolExecutionResult;
|
|
11
|
+
constructor(error: unknown, result: ToolExecutionResult);
|
|
12
|
+
}
|
|
7
13
|
type Status = 'running' | 'completed' | 'failed' | 'cancelled';
|
|
8
14
|
/** Session-owned execution, separate from the cancellable model-tool wait. */
|
|
9
15
|
export declare class CodeCells {
|
|
@@ -2,6 +2,19 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { MarAgentError, describeMarAgentError } from '../../error.js';
|
|
3
3
|
import { TOOL_EXECUTION_LIMITS as limits } from '../execution-limits.js';
|
|
4
4
|
import { truncateModelText } from '../../runtime/token-budget.js';
|
|
5
|
+
import { BoundedTextOutput, renderCapturedText } from './text-output.js';
|
|
6
|
+
/** Keeps a failed tool call observable without discarding earlier explicit output. */
|
|
7
|
+
export class CodeCellExecutionError extends MarAgentError {
|
|
8
|
+
result;
|
|
9
|
+
constructor(error, result) {
|
|
10
|
+
const diagnostic = describeMarAgentError(error, 'MAR_AGENT_CODE_FAILED');
|
|
11
|
+
super(diagnostic.code, diagnostic.message.replace(`${diagnostic.code}: `, ''), {
|
|
12
|
+
cause: error,
|
|
13
|
+
...(error instanceof MarAgentError ? { retryable: error.retryable } : {})
|
|
14
|
+
});
|
|
15
|
+
this.result = result;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
5
18
|
function options(value, wait) {
|
|
6
19
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
7
20
|
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Code Exec options must be an object.');
|
|
@@ -11,11 +24,11 @@ function options(value, wait) {
|
|
|
11
24
|
: ['yieldMs', 'maxOutputTokens'];
|
|
12
25
|
if (Object.keys(input).some((key) => !keys.includes(key)))
|
|
13
26
|
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Unknown Code Exec option.');
|
|
14
|
-
const yieldMs = input.yieldMs ?? limits.codeDefaultYieldMs;
|
|
27
|
+
const yieldMs = input.yieldMs ?? (wait ? limits.codeDefaultWaitYieldMs : limits.codeDefaultYieldMs);
|
|
15
28
|
const maxOutputTokens = input.maxOutputTokens ?? limits.codeMaxOutputTokens;
|
|
16
29
|
if (!Number.isSafeInteger(yieldMs) ||
|
|
17
30
|
Number(yieldMs) < 0 ||
|
|
18
|
-
Number(yieldMs) > limits.codeMaxYieldMs ||
|
|
31
|
+
Number(yieldMs) > (wait ? limits.codeMaxWaitYieldMs : limits.codeMaxYieldMs) ||
|
|
19
32
|
!Number.isSafeInteger(maxOutputTokens) ||
|
|
20
33
|
Number(maxOutputTokens) < 1 ||
|
|
21
34
|
Number(maxOutputTokens) > limits.codeMaxOutputTokens ||
|
|
@@ -73,9 +86,10 @@ export class CodeCells {
|
|
|
73
86
|
executionId: context.executionId,
|
|
74
87
|
controller,
|
|
75
88
|
status: 'running',
|
|
76
|
-
text:
|
|
89
|
+
text: new BoundedTextOutput(limits.codeMaxOutputBytes),
|
|
77
90
|
images: [],
|
|
78
91
|
yielded: false,
|
|
92
|
+
truncated: false,
|
|
79
93
|
listeners: new Set(),
|
|
80
94
|
done: Promise.resolve()
|
|
81
95
|
};
|
|
@@ -90,7 +104,7 @@ export class CodeCells {
|
|
|
90
104
|
.then(async () => {
|
|
91
105
|
releaseSession = await context.codeMode?.retainSession?.();
|
|
92
106
|
return run(source, { ...context, signal: controller.signal }, {
|
|
93
|
-
text: (text) => cell.text.
|
|
107
|
+
text: (text, originalBytes) => cell.text.append(text, originalBytes),
|
|
94
108
|
image: (image) => cell.images.push(image),
|
|
95
109
|
yield: () => {
|
|
96
110
|
cell.yielded = true;
|
|
@@ -187,7 +201,12 @@ export class CodeCells {
|
|
|
187
201
|
if (cell.terminal) {
|
|
188
202
|
const snapshot = cell.terminal.data;
|
|
189
203
|
const bounded = truncateModelText(snapshot.output, input.maxOutputTokens);
|
|
190
|
-
const data = {
|
|
204
|
+
const data = {
|
|
205
|
+
...snapshot,
|
|
206
|
+
output: bounded.content,
|
|
207
|
+
truncated: cell.terminal.truncated || bounded.truncated,
|
|
208
|
+
cached: true
|
|
209
|
+
};
|
|
191
210
|
return {
|
|
192
211
|
...cell.terminal,
|
|
193
212
|
data,
|
|
@@ -195,10 +214,12 @@ export class CodeCells {
|
|
|
195
214
|
truncated: cell.terminal.truncated || bounded.truncated
|
|
196
215
|
};
|
|
197
216
|
}
|
|
198
|
-
const
|
|
217
|
+
const captured = cell.text.drain();
|
|
199
218
|
const images = cell.images.splice(0);
|
|
219
|
+
const text = renderCapturedText(captured, images.length);
|
|
200
220
|
cell.yielded = false;
|
|
201
221
|
const bounded = truncateModelText(text, input.maxOutputTokens);
|
|
222
|
+
cell.truncated ||= captured.droppedBytes > 0 || bounded.truncated;
|
|
202
223
|
const error = cell.error === undefined
|
|
203
224
|
? undefined
|
|
204
225
|
: describeMarAgentError(cell.error, 'MAR_AGENT_CODE_FAILED');
|
|
@@ -207,13 +228,16 @@ export class CodeCells {
|
|
|
207
228
|
status: cell.status,
|
|
208
229
|
output: bounded.content,
|
|
209
230
|
...cell.result?.data,
|
|
231
|
+
outputBytes: captured.originalBytes,
|
|
232
|
+
outputDroppedBytes: captured.droppedBytes,
|
|
233
|
+
truncated: cell.truncated,
|
|
210
234
|
...(error ? { error: { code: error.code, message: error.message } } : {}),
|
|
211
235
|
cached: false
|
|
212
236
|
};
|
|
213
237
|
const result = {
|
|
214
238
|
content: JSON.stringify(data),
|
|
215
239
|
data,
|
|
216
|
-
truncated:
|
|
240
|
+
truncated: cell.truncated,
|
|
217
241
|
...(images.length ? { images } : {})
|
|
218
242
|
};
|
|
219
243
|
if (cell.status !== 'running')
|
|
@@ -221,7 +245,7 @@ export class CodeCells {
|
|
|
221
245
|
// Keep synchronous completion compatible; retained waits always include explicit lifecycle metadata.
|
|
222
246
|
if (initial && cell.status !== 'running') {
|
|
223
247
|
if (cell.error !== undefined)
|
|
224
|
-
throw cell.error;
|
|
248
|
+
throw new CodeCellExecutionError(cell.error, result);
|
|
225
249
|
return { ...result, content: bounded.content || 'Code Exec completed without emitted text.' };
|
|
226
250
|
}
|
|
227
251
|
return result;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { ToolCall, ToolExecutionResult } from '../../sdk/types.js';
|
|
2
2
|
import type { CodeModeStateEntry, CodeModeStateMutation } from './state.js';
|
|
3
|
+
export type ProgrammaticToolResult = Omit<ToolExecutionResult, 'content'> & {
|
|
4
|
+
content?: string;
|
|
5
|
+
};
|
|
3
6
|
export interface CodeModeCatalogEntry {
|
|
4
7
|
readonly name: string;
|
|
5
8
|
readonly description: string;
|
|
@@ -26,8 +29,8 @@ export interface CodeModeEngine {
|
|
|
26
29
|
stateTotalBytes: number;
|
|
27
30
|
sleepMs: number;
|
|
28
31
|
};
|
|
29
|
-
onToolCall(call: ToolCall): Promise<
|
|
30
|
-
onText(value: string): void;
|
|
32
|
+
onToolCall(call: ToolCall): Promise<ProgrammaticToolResult>;
|
|
33
|
+
onText(value: string, originalBytes?: number): void;
|
|
31
34
|
onImage(value: unknown): void;
|
|
32
35
|
onYield(): void;
|
|
33
36
|
}): Promise<{
|