@myagentroam/agent 0.10.1 → 0.10.2
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/agent-core/runtime/context/gc.js +22 -20
- package/dist/agent-core/runtime/events.d.ts +1 -1
- package/dist/agent-core/session/context-gc-checkpoint.js +46 -9
- package/dist/agent-core/session/context-gc-observations.d.ts +23 -1
- package/dist/agent-core/session/context-gc-observations.js +67 -28
- package/dist/agent-core/session/context-gc-replacements.d.ts +1 -0
- package/dist/agent-core/session/context-gc-replacements.js +10 -38
- package/dist/agent-core/tools/code-mode/dispatch.js +4 -2
- package/dist/agent-core/tools/code-mode/index.js +8 -1
- package/dist/agent-core/tools/contracts.d.ts +4 -0
- package/dist/agent-core/tools/execution.js +10 -8
- package/dist/agent-core/tools/local/apply-patch.js +11 -1
- package/dist/agent-core/tools/output-projection.d.ts +3 -1
- package/dist/agent-core/tools/output-projection.js +11 -17
- package/dist/agent-core/tools/shared/patch-result.d.ts +4 -0
- package/dist/agent-core/tools/shared/patch-result.js +66 -0
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { codeCallEvidence, codeObservationEvidence, retainedCodeInputs } from '../../session/context-gc-observations.js';
|
|
1
|
+
import { codeCallEvidence, codePartialPatchCallEvidence, codeObservationEvidence, retainedCodeInputs } from '../../session/context-gc-observations.js';
|
|
2
2
|
import { ContextGcCheckpointCache, contextGcBaseFromRecords, contextGcLogicalPathKey, contextGcMinimumUsageGrowth, contextGcRecordSourceHash, contextGcTargetKey, normalizeContextGcReplacements } from '../../session/context-gc-checkpoint.js';
|
|
3
|
-
import { codeCellCompletionSequence, contextGcApplyPatchInputReplacement, contextGcCodeModeInputReplacement, contextGcCodeModeOutputReplacement, contextGcExecInputReplacement, contextGcExecOutputReplacement, contextGcPatchResultFromCompletedPayload, contextGcStaleReadReplacement, contextGcWebOutputReplacement, normalizeContextGcCodeModeInput, normalizeContextGcExecResult } from '../../session/context-gc-replacements.js';
|
|
3
|
+
import { codeCellCompletionSequence, contextGcApplyPatchInputReplacement, contextGcCodeModeInputReplacement, contextGcCodeModeOutputReplacement, contextGcExecInputReplacement, contextGcExecOutputReplacement, contextGcPatchResultFromCompletedPayload, contextGcPatchResultFromFailedPayload, contextGcStaleReadReplacement, contextGcWebOutputReplacement, normalizeContextGcCodeModeInput, normalizeContextGcExecResult } from '../../session/context-gc-replacements.js';
|
|
4
4
|
import { contextGcSubagentNeedsRetainedPriorFinal, contextGcSubagentOutputReplacement, contextGcSubagentPriorFinalIsRetained, contextGcSubagentSnapshotIsPreciselyCovered, contextGcSubagentSnapshotIsSuperseded, contextGcSubagentSnapshotTurnId, normalizeContextGcSubagentSnapshot } from '../../session/context-gc-subagent.js';
|
|
5
5
|
import { parseReadContextOutput } from '../../tools/local/read-context.js';
|
|
6
6
|
import { CONTEXT_GC_TOKEN_ESTIMATOR, contextGcCacheImpact, contextGcMessageTokens, contextGcPrefixTokens, contextGcReclaimedTokens } from './gc-tokens.js';
|
|
@@ -533,23 +533,26 @@ function collectStageACandidates(input, groups, existingReplacements, existingTa
|
|
|
533
533
|
const claimedReadItems = new Set([...existingReadReplacements.values()].flatMap((replacement) => replacement.items.map((item) => `${replacement.target.recordId}:${replacement.target.observationId ?? ''}:${item.index}`)));
|
|
534
534
|
const patches = [...groups.values()]
|
|
535
535
|
.flatMap((patch) => {
|
|
536
|
-
if (patch.toolName !== 'apply_patch' ||
|
|
537
|
-
!patch.call ||
|
|
538
|
-
!patch.result ||
|
|
539
|
-
patch.failed ||
|
|
540
|
-
!patch.completed)
|
|
536
|
+
if (patch.toolName !== 'apply_patch' || !patch.call || !patch.result)
|
|
541
537
|
return [];
|
|
542
|
-
const
|
|
543
|
-
|
|
538
|
+
const terminal = patch.failed ?? patch.completed;
|
|
539
|
+
if (!terminal)
|
|
540
|
+
return [];
|
|
541
|
+
const result = patch.failed
|
|
542
|
+
? contextGcPatchResultFromFailedPayload(terminal.payload)
|
|
543
|
+
: contextGcPatchResultFromCompletedPayload(terminal.payload);
|
|
544
|
+
return result
|
|
545
|
+
? [{ patch, result, terminal, evidenceSequence: patch.result.record.sequence }]
|
|
546
|
+
: [];
|
|
544
547
|
})
|
|
545
548
|
.sort((left, right) => left.evidenceSequence - right.evidenceSequence);
|
|
546
|
-
for (const { patch, result, evidenceSequence } of patches) {
|
|
549
|
+
for (const { patch, result, terminal, evidenceSequence } of patches) {
|
|
547
550
|
const patchCall = patch.call;
|
|
548
551
|
const observedRollouts = successfulRolloutsAfter(input.records, evidenceSequence, input.modelId, input.contextWindowTokens);
|
|
549
552
|
const replacements = [];
|
|
550
553
|
const candidateReadItems = new Set();
|
|
551
554
|
const patchTarget = targetFor(patchCall.record, patchCall.message);
|
|
552
|
-
if (patchTarget && !existingTargets.has(contextGcTargetKey(patchTarget)))
|
|
555
|
+
if (!patch.failed && patchTarget && !existingTargets.has(contextGcTargetKey(patchTarget)))
|
|
553
556
|
replacements.push({
|
|
554
557
|
kind: 'TOOL_CALL_INPUT',
|
|
555
558
|
toolName: 'apply_patch',
|
|
@@ -562,7 +565,7 @@ function collectStageACandidates(input, groups, existingReplacements, existingTa
|
|
|
562
565
|
evidenceSequence
|
|
563
566
|
});
|
|
564
567
|
for (const read of reads) {
|
|
565
|
-
if ((read.completed?.sequence ?? read.result.record.sequence) >=
|
|
568
|
+
if ((read.completed?.sequence ?? read.result.record.sequence) >= terminal.sequence)
|
|
566
569
|
continue;
|
|
567
570
|
const parsed = parseReadContextOutput(read.result.message.content);
|
|
568
571
|
if (!parsed)
|
|
@@ -953,11 +956,6 @@ function buildToolGroups(records, messages, sources) {
|
|
|
953
956
|
for (const [index, message] of messages.entries()) {
|
|
954
957
|
if (!message.observations || message.role !== 'tool')
|
|
955
958
|
continue;
|
|
956
|
-
const outer = message.callId ? groups.get(message.callId) : undefined;
|
|
957
|
-
if (!outer?.completed ||
|
|
958
|
-
outer.failed ||
|
|
959
|
-
codeCellCompletionSequence(records, outer.completed) === undefined)
|
|
960
|
-
continue;
|
|
961
959
|
const record = sources[index];
|
|
962
960
|
for (const entry of message.calls ?? []) {
|
|
963
961
|
if (![
|
|
@@ -969,9 +967,11 @@ function buildToolGroups(records, messages, sources) {
|
|
|
969
967
|
'agent_message',
|
|
970
968
|
'agent_cancel'
|
|
971
969
|
].includes(entry.toolName) ||
|
|
972
|
-
|
|
970
|
+
(entry.status === 'completed' &&
|
|
971
|
+
message.observations.some((value) => value.type === 'tool_result' && value.source.callId === entry.callId)))
|
|
973
972
|
continue;
|
|
974
|
-
const evidence = codeCallEvidence(records, record, entry)
|
|
973
|
+
const evidence = codeCallEvidence(records, record, entry) ??
|
|
974
|
+
codePartialPatchCallEvidence(records, record, entry);
|
|
975
975
|
if (!evidence)
|
|
976
976
|
continue;
|
|
977
977
|
groups.set(`execution:${evidence.callId}`, {
|
|
@@ -979,7 +979,9 @@ function buildToolGroups(records, messages, sources) {
|
|
|
979
979
|
callId: evidence.callId,
|
|
980
980
|
toolName: entry.toolName,
|
|
981
981
|
aliases: [],
|
|
982
|
-
completed
|
|
982
|
+
...('completed' in evidence
|
|
983
|
+
? { completed: evidence.completed }
|
|
984
|
+
: { failed: evidence.failed }),
|
|
983
985
|
call: {
|
|
984
986
|
record: evidence.call,
|
|
985
987
|
message: {
|
|
@@ -84,7 +84,7 @@ export type MarAgentEvent = MarAgentEventBase & ({
|
|
|
84
84
|
data?: CodeCellEventData | import('../tools/contracts.js').ExecResult | Omit<import('../tools/contracts.js').ExecResult, 'stdout' | 'stderr'> | import('../tools/contracts.js').ApplyPatchResult | import('../tools/contracts.js').ReadEventData | import('../tools/contracts.js').ViewImageResult | import('../subagent/contracts.js').SubagentTaskSnapshot;
|
|
85
85
|
} | {
|
|
86
86
|
type: 'tool.failed';
|
|
87
|
-
data?: import('../tools/contracts.js').
|
|
87
|
+
data?: CodeCellEventData | import('../tools/contracts.js').ApplyPatchPartialResult;
|
|
88
88
|
toolName: string;
|
|
89
89
|
callId: string;
|
|
90
90
|
parentCallId?: string;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { posix, win32 } from 'node:path';
|
|
3
3
|
import { isDeepStrictEqual } from 'node:util';
|
|
4
|
-
import { codeCallEvidence, callsFromRecord, codeObservationEvidence, observationsFromRecord, retainedCodeInputs } from './context-gc-observations.js';
|
|
4
|
+
import { codeCallEvidence, codePartialPatchCallEvidence, callsFromRecord, codeObservationEvidence, observationsFromRecord, retainedCodeInputs } from './context-gc-observations.js';
|
|
5
5
|
import { parseReadContextOutput } from '../tools/local/read-context.js';
|
|
6
|
-
import { codeCellCompletionSequence, contextGcApplyPatchInputReplacement, contextGcCodeModeInputReplacement, contextGcCodeModeOutputReplacement, contextGcExecInputReplacement, contextGcExecOutputReplacement, contextGcPatchResultFromCompletedPayload, contextGcStaleReadReplacement, contextGcWebOutputReplacement, normalizeContextGcCodeModeInput, normalizeContextGcExecResult } from './context-gc-replacements.js';
|
|
6
|
+
import { codeCellCompletionSequence, contextGcApplyPatchInputReplacement, contextGcCodeModeInputReplacement, contextGcCodeModeOutputReplacement, contextGcExecInputReplacement, contextGcExecOutputReplacement, contextGcPatchResultFromCompletedPayload, contextGcPatchResultFromFailedPayload, contextGcStaleReadReplacement, contextGcWebOutputReplacement, normalizeContextGcCodeModeInput, normalizeContextGcExecResult } from './context-gc-replacements.js';
|
|
7
7
|
import { contextGcSubagentNeedsRetainedPriorFinal, contextGcSubagentOutputReplacement, contextGcSubagentSnapshotIsPreciselyCovered, contextGcSubagentSnapshotIsSuperseded, normalizeContextGcSubagentSnapshot } from './context-gc-subagent.js';
|
|
8
8
|
export const CONTEXT_GC_CHECKPOINT_VERSION = 1;
|
|
9
9
|
export const CONTEXT_GC_MAX_TARGETS = 4_096;
|
|
@@ -239,6 +239,7 @@ function replacementMatchesRecords(replacement, records, recordsBySequence, work
|
|
|
239
239
|
let source = recordsBySequence.get(replacement.target.sequence);
|
|
240
240
|
if (!source || !isRecord(source.payload))
|
|
241
241
|
return false;
|
|
242
|
+
let sourceToolSequence = source.sequence;
|
|
242
243
|
if (replacement.target.observationId) {
|
|
243
244
|
const selected = observationsFromRecord(source)?.find((value) => value.id === replacement.target.observationId);
|
|
244
245
|
if (!selected)
|
|
@@ -247,6 +248,7 @@ function replacementMatchesRecords(replacement, records, recordsBySequence, work
|
|
|
247
248
|
const evidence = codeObservationEvidence(records, source, selected);
|
|
248
249
|
if (!evidence)
|
|
249
250
|
return false;
|
|
251
|
+
sourceToolSequence = evidence.completed.sequence;
|
|
250
252
|
source = {
|
|
251
253
|
...source,
|
|
252
254
|
payload: {
|
|
@@ -273,7 +275,7 @@ function replacementMatchesRecords(replacement, records, recordsBySequence, work
|
|
|
273
275
|
const originalItems = new Map(parsed.items.map((item) => [item.index, item]));
|
|
274
276
|
return replacement.items.every((item) => {
|
|
275
277
|
const original = originalItems.get(item.index);
|
|
276
|
-
const evidence =
|
|
278
|
+
const evidence = appliedPatchEvidenceForPath(records, recordsBySequence, item.evidenceSequence, item.path, workspace, platform, sourceToolSequence, item.supersededByCallId);
|
|
277
279
|
return (original?.pathTruncated === false &&
|
|
278
280
|
original?.path === item.path &&
|
|
279
281
|
evidence !== undefined &&
|
|
@@ -531,12 +533,47 @@ function modelToolResultForCall(records, call, beforeSequence) {
|
|
|
531
533
|
record.payload.role === 'tool' &&
|
|
532
534
|
record.payload.callId === callId);
|
|
533
535
|
}
|
|
534
|
-
function
|
|
535
|
-
const
|
|
536
|
-
if (
|
|
536
|
+
function partialPatchEvidence(records, recordsBySequence, evidenceSequence, expectedCallId) {
|
|
537
|
+
const result = recordsBySequence.get(evidenceSequence);
|
|
538
|
+
if (result?.type !== 'model.context' ||
|
|
539
|
+
!isRecord(result.payload) ||
|
|
540
|
+
result.payload.role !== 'tool' ||
|
|
541
|
+
typeof result.payload.callId !== 'string')
|
|
537
542
|
return undefined;
|
|
538
|
-
const
|
|
539
|
-
|
|
543
|
+
const callId = result.payload.callId;
|
|
544
|
+
const call = modelToolCallForCallId(records, callId, result.sequence);
|
|
545
|
+
if (!call ||
|
|
546
|
+
!isRecord(call.payload) ||
|
|
547
|
+
call.payload.name !== 'apply_patch' ||
|
|
548
|
+
(expectedCallId && callId !== expectedCallId)) {
|
|
549
|
+
for (const entry of callsFromRecord(result) ?? []) {
|
|
550
|
+
if (expectedCallId && entry.callId !== expectedCallId)
|
|
551
|
+
continue;
|
|
552
|
+
const evidence = codePartialPatchCallEvidence(records, result, entry);
|
|
553
|
+
if (evidence)
|
|
554
|
+
return evidence;
|
|
555
|
+
}
|
|
556
|
+
return undefined;
|
|
557
|
+
}
|
|
558
|
+
const failed = records.findLast((record) => record.sequence > call.sequence &&
|
|
559
|
+
record.sequence < result.sequence &&
|
|
560
|
+
record.type === 'tool.failed' &&
|
|
561
|
+
isRecord(record.payload) &&
|
|
562
|
+
record.payload.callId === callId &&
|
|
563
|
+
contextGcPatchResultFromFailedPayload(record.payload) !== undefined);
|
|
564
|
+
return failed ? { callId, call, failed, result } : undefined;
|
|
565
|
+
}
|
|
566
|
+
function appliedPatchEvidenceForPath(records, recordsBySequence, evidenceSequence, path, workspace, platform, readSequence, expectedCallId) {
|
|
567
|
+
const evidence = successfulToolEvidence(records, recordsBySequence, evidenceSequence, 'apply_patch', expectedCallId);
|
|
568
|
+
const partial = evidence
|
|
569
|
+
? undefined
|
|
570
|
+
: partialPatchEvidence(records, recordsBySequence, evidenceSequence, expectedCallId);
|
|
571
|
+
const callId = evidence?.callId ?? partial?.callId;
|
|
572
|
+
const terminalSequence = evidence?.completed.sequence ?? partial?.failed.sequence;
|
|
573
|
+
const result = evidence
|
|
574
|
+
? contextGcPatchResultFromCompletedPayload(evidence.completed.payload)
|
|
575
|
+
: contextGcPatchResultFromFailedPayload(partial?.failed.payload);
|
|
576
|
+
if (!result || !callId || terminalSequence === undefined || readSequence >= terminalSequence)
|
|
540
577
|
return undefined;
|
|
541
578
|
const expected = contextGcLogicalPathKey(path, workspace, platform);
|
|
542
579
|
if (!expected)
|
|
@@ -544,7 +581,7 @@ function successfulPatchEvidenceForPath(records, recordsBySequence, evidenceSequ
|
|
|
544
581
|
const file = result.files.find((file) => file.operation !== 'added' &&
|
|
545
582
|
contextGcLogicalPathKey(file.path, workspace, platform) === expected);
|
|
546
583
|
return file && file.operation !== 'added'
|
|
547
|
-
? { callId
|
|
584
|
+
? { callId, file: { operation: file.operation } }
|
|
548
585
|
: undefined;
|
|
549
586
|
}
|
|
550
587
|
function isSuccessfulExecLifecycleEvidence(replacement, source, records, recordsBySequence) {
|
|
@@ -7,7 +7,22 @@ export declare function codeObservationEvidence(records: readonly SessionRecord[
|
|
|
7
7
|
callId: string;
|
|
8
8
|
call: SessionRecord;
|
|
9
9
|
completed: SessionRecord;
|
|
10
|
-
result:
|
|
10
|
+
result: {
|
|
11
|
+
payload: {
|
|
12
|
+
role: string;
|
|
13
|
+
callId: string;
|
|
14
|
+
content: string;
|
|
15
|
+
observationId: string;
|
|
16
|
+
};
|
|
17
|
+
schemaVersion: 1;
|
|
18
|
+
recordId: string;
|
|
19
|
+
sequence: number;
|
|
20
|
+
timestamp: string;
|
|
21
|
+
sessionId: string;
|
|
22
|
+
executionId?: string;
|
|
23
|
+
turnId?: string;
|
|
24
|
+
type: string;
|
|
25
|
+
};
|
|
11
26
|
} | undefined;
|
|
12
27
|
export declare function observationsFromRecord(record: SessionRecord): CodeObservation[] | undefined;
|
|
13
28
|
export declare function codeCallEvidence(records: readonly SessionRecord[], result: SessionRecord, entry: CodeToolCallRecord): {
|
|
@@ -30,6 +45,13 @@ export declare function codeCallEvidence(records: readonly SessionRecord[], resu
|
|
|
30
45
|
call: SessionRecord;
|
|
31
46
|
completed: SessionRecord;
|
|
32
47
|
} | undefined;
|
|
48
|
+
/** Failed patch calls can prove applied file units, never successful input reclamation. */
|
|
49
|
+
export declare function codePartialPatchCallEvidence(records: readonly SessionRecord[], result: SessionRecord, entry: CodeToolCallRecord): {
|
|
50
|
+
callId: string;
|
|
51
|
+
call: SessionRecord;
|
|
52
|
+
failed: SessionRecord;
|
|
53
|
+
result: SessionRecord;
|
|
54
|
+
} | undefined;
|
|
33
55
|
export declare function callsFromRecord(record: SessionRecord): CodeToolCallRecord[] | undefined;
|
|
34
56
|
export declare function retainedCodeInputs(records: readonly SessionRecord[], parentCallId: string): {
|
|
35
57
|
callId: unknown;
|
|
@@ -1,17 +1,36 @@
|
|
|
1
1
|
import { isDeepStrictEqual } from 'node:util';
|
|
2
|
-
import { codeCellCompletionSequence, contextGcPatchResultFromCompletedPayload } from './context-gc-replacements.js';
|
|
2
|
+
import { codeCellCompletionSequence, contextGcPatchResultFromCompletedPayload, contextGcPatchResultFromFailedPayload } from './context-gc-replacements.js';
|
|
3
3
|
import { parseCodeCalls, parseObservations } from '../tools/code-mode/observations.js';
|
|
4
4
|
/** Resolve private observation identity to real dispatch facts, not Provider tool calls. */
|
|
5
5
|
export function codeObservationEvidence(records, result, observation) {
|
|
6
6
|
if (observation.outcome !== 'completed')
|
|
7
7
|
return undefined;
|
|
8
|
+
const evidence = codeToolEvidence(records, result, observation.source, 'completed');
|
|
9
|
+
if (!evidence)
|
|
10
|
+
return undefined;
|
|
11
|
+
return {
|
|
12
|
+
callId: evidence.callId,
|
|
13
|
+
call: evidence.call,
|
|
14
|
+
completed: evidence.terminal,
|
|
15
|
+
result: {
|
|
16
|
+
...result,
|
|
17
|
+
payload: {
|
|
18
|
+
role: 'tool',
|
|
19
|
+
callId: evidence.callId,
|
|
20
|
+
content: observation.result.content,
|
|
21
|
+
observationId: observation.id
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function codeToolEvidence(records, result, source, outcome) {
|
|
8
27
|
const started = records.findLast((record) => record.sequence < result.sequence &&
|
|
9
28
|
record.type === 'tool.started' &&
|
|
10
29
|
isRecord(record.payload) &&
|
|
11
|
-
record.payload.callId ===
|
|
12
|
-
record.payload.toolName ===
|
|
30
|
+
record.payload.callId === source.callId &&
|
|
31
|
+
record.payload.toolName === source.toolName &&
|
|
13
32
|
typeof record.payload.parentCallId === 'string' &&
|
|
14
|
-
isDeepStrictEqual(record.payload.input,
|
|
33
|
+
isDeepStrictEqual(record.payload.input, source.input));
|
|
15
34
|
if (!started || !isRecord(started.payload))
|
|
16
35
|
return undefined;
|
|
17
36
|
const parentId = started.payload.parentCallId;
|
|
@@ -28,16 +47,20 @@ export function codeObservationEvidence(records, result, observation) {
|
|
|
28
47
|
return undefined;
|
|
29
48
|
const outerId = original.payload.callId;
|
|
30
49
|
const outer = records.findLast((record) => record.sequence < result.sequence &&
|
|
31
|
-
record.type === 'tool.completed'
|
|
50
|
+
(record.type === 'tool.completed' ||
|
|
51
|
+
(outcome === 'failed' && record.type === 'tool.failed')) &&
|
|
32
52
|
isRecord(record.payload) &&
|
|
33
53
|
record.payload.callId === outerId &&
|
|
34
54
|
(record.payload.toolName === 'code_exec' || record.payload.toolName === 'code_exec_wait'));
|
|
35
55
|
if (!outer ||
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
record.
|
|
56
|
+
(outcome === 'completed'
|
|
57
|
+
? codeCellCompletionSequence(records, outer)
|
|
58
|
+
: partialPatchCellTerminalSequence(records, outer)) === undefined ||
|
|
59
|
+
(outcome === 'completed' &&
|
|
60
|
+
records.some((record) => record.sequence < result.sequence &&
|
|
61
|
+
record.type === 'tool.failed' &&
|
|
62
|
+
isRecord(record.payload) &&
|
|
63
|
+
record.payload.callId === outerId)))
|
|
41
64
|
return undefined;
|
|
42
65
|
if (original.payload.callId !== parentId) {
|
|
43
66
|
const initial = records.find((record) => record.sequence < outer.sequence &&
|
|
@@ -56,37 +79,44 @@ export function codeObservationEvidence(records, result, observation) {
|
|
|
56
79
|
}
|
|
57
80
|
const completed = records.findLast((record) => record.sequence > started.sequence &&
|
|
58
81
|
record.sequence < result.sequence &&
|
|
59
|
-
record.type ===
|
|
82
|
+
record.type === `tool.${outcome}` &&
|
|
60
83
|
isRecord(record.payload) &&
|
|
61
|
-
record.payload.callId ===
|
|
62
|
-
record.payload.toolName ===
|
|
84
|
+
record.payload.callId === source.callId &&
|
|
85
|
+
record.payload.toolName === source.toolName &&
|
|
63
86
|
record.payload.parentCallId === parentId);
|
|
64
87
|
if (!completed ||
|
|
65
88
|
records.some((record) => record.sequence > started.sequence &&
|
|
66
89
|
record.sequence < result.sequence &&
|
|
67
|
-
record.type === 'tool.failed' &&
|
|
90
|
+
record.type === (outcome === 'completed' ? 'tool.failed' : 'tool.completed') &&
|
|
68
91
|
isRecord(record.payload) &&
|
|
69
|
-
record.payload.callId ===
|
|
92
|
+
record.payload.callId === source.callId))
|
|
70
93
|
return undefined;
|
|
71
94
|
const call = {
|
|
72
95
|
...started,
|
|
73
96
|
payload: {
|
|
74
97
|
role: 'tool_call',
|
|
75
|
-
name:
|
|
76
|
-
callId:
|
|
77
|
-
arguments:
|
|
98
|
+
name: source.toolName,
|
|
99
|
+
callId: source.callId,
|
|
100
|
+
arguments: source.input
|
|
78
101
|
}
|
|
79
102
|
};
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
103
|
+
return { callId: source.callId, call, terminal: completed, result };
|
|
104
|
+
}
|
|
105
|
+
function partialPatchCellTerminalSequence(records, result) {
|
|
106
|
+
if (!isRecord(result.payload) || !isRecord(result.payload.data))
|
|
107
|
+
return undefined;
|
|
108
|
+
const data = result.payload.data;
|
|
109
|
+
if (typeof data.cellId !== 'string')
|
|
110
|
+
return undefined;
|
|
111
|
+
const terminal = (status) => status === 'completed' || status === 'failed' || status === 'cancelled';
|
|
112
|
+
if (terminal(data.status))
|
|
113
|
+
return result.sequence;
|
|
114
|
+
if (data.status !== 'running')
|
|
115
|
+
return undefined;
|
|
116
|
+
return records.findLast((record) => record.type === 'code.cell.completed' &&
|
|
117
|
+
isRecord(record.payload) &&
|
|
118
|
+
record.payload.cellId === data.cellId &&
|
|
119
|
+
terminal(record.payload.status))?.sequence;
|
|
90
120
|
}
|
|
91
121
|
export function observationsFromRecord(record) {
|
|
92
122
|
return isRecord(record.payload) ? parseObservations(record.payload.observations) : undefined;
|
|
@@ -115,6 +145,15 @@ export function codeCallEvidence(records, result, entry) {
|
|
|
115
145
|
}
|
|
116
146
|
};
|
|
117
147
|
}
|
|
148
|
+
/** Failed patch calls can prove applied file units, never successful input reclamation. */
|
|
149
|
+
export function codePartialPatchCallEvidence(records, result, entry) {
|
|
150
|
+
if (entry.status !== 'failed' || entry.toolName !== 'apply_patch')
|
|
151
|
+
return undefined;
|
|
152
|
+
const evidence = codeToolEvidence(records, result, { callId: entry.callId, toolName: entry.toolName, input: entry.input }, 'failed');
|
|
153
|
+
if (!evidence || !contextGcPatchResultFromFailedPayload(evidence.terminal.payload))
|
|
154
|
+
return undefined;
|
|
155
|
+
return { callId: evidence.callId, call: evidence.call, failed: evidence.terminal, result };
|
|
156
|
+
}
|
|
118
157
|
export function callsFromRecord(record) {
|
|
119
158
|
return isRecord(record.payload) ? parseCodeCalls(record.payload.calls) : undefined;
|
|
120
159
|
}
|
|
@@ -46,6 +46,7 @@ export type ContextGcExecResult = {
|
|
|
46
46
|
readonly modelContextContent: string;
|
|
47
47
|
};
|
|
48
48
|
export declare function contextGcPatchResultFromCompletedPayload(payload: unknown): ContextGcPatchResult | undefined;
|
|
49
|
+
export declare function contextGcPatchResultFromFailedPayload(payload: unknown): ContextGcPatchResult | undefined;
|
|
49
50
|
export declare function contextGcApplyPatchInputReplacement(arguments_: unknown, result: ContextGcPatchResult, evidenceSequence: number, formatVersion?: 1 | 2): string;
|
|
50
51
|
export declare function contextGcStaleReadReplacement(input: {
|
|
51
52
|
readonly path: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
+
import { parseApplyPatchResult, parseApplyPatchPartialResult } from '../tools/shared/patch-result.js';
|
|
2
3
|
const RAW_MODEL_CONTEXT_PREVIEW_CHARACTERS = 256;
|
|
3
4
|
const EXEC_INPUT_COMPLETE_CHARACTERS = 512;
|
|
4
5
|
const EXEC_INPUT_PREVIEW_CHARACTERS = 256;
|
|
@@ -36,45 +37,16 @@ export function contextGcCodeModeOutputReplacement(originalContent, truncated) {
|
|
|
36
37
|
export function contextGcPatchResultFromCompletedPayload(payload) {
|
|
37
38
|
if (!isRecord(payload) || payload.type !== 'tool.completed')
|
|
38
39
|
return undefined;
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
file.operation === 'moved') &&
|
|
48
|
-
(file.targetPath === undefined || isNonemptyString(file.targetPath)) &&
|
|
49
|
-
isNonnegativeInteger(file.addedLines) &&
|
|
50
|
-
isNonnegativeInteger(file.deletedLines)
|
|
51
|
-
? [
|
|
52
|
-
{
|
|
53
|
-
path: file.path,
|
|
54
|
-
...(typeof file.targetPath === 'string' ? { targetPath: file.targetPath } : {}),
|
|
55
|
-
operation: file.operation,
|
|
56
|
-
addedLines: file.addedLines,
|
|
57
|
-
deletedLines: file.deletedLines
|
|
58
|
-
}
|
|
59
|
-
]
|
|
60
|
-
: []);
|
|
61
|
-
if (files.length !== data.files.length ||
|
|
62
|
-
files.length === 0 ||
|
|
63
|
-
!isNonnegativeInteger(data.totals.files) ||
|
|
64
|
-
!isNonnegativeInteger(data.totals.addedLines) ||
|
|
65
|
-
!isNonnegativeInteger(data.totals.deletedLines) ||
|
|
66
|
-
data.totals.files !== files.length ||
|
|
67
|
-
data.totals.addedLines !== files.reduce((total, file) => total + file.addedLines, 0) ||
|
|
68
|
-
data.totals.deletedLines !== files.reduce((total, file) => total + file.deletedLines, 0))
|
|
40
|
+
const result = parseApplyPatchResult(payload.data);
|
|
41
|
+
return result?.files.length ? result : undefined;
|
|
42
|
+
}
|
|
43
|
+
export function contextGcPatchResultFromFailedPayload(payload) {
|
|
44
|
+
if (!isRecord(payload) ||
|
|
45
|
+
payload.type !== 'tool.failed' ||
|
|
46
|
+
payload.toolName !== 'apply_patch' ||
|
|
47
|
+
payload.code !== 'MAR_AGENT_PATCH_PARTIAL')
|
|
69
48
|
return undefined;
|
|
70
|
-
return
|
|
71
|
-
files,
|
|
72
|
-
totals: {
|
|
73
|
-
files: data.totals.files,
|
|
74
|
-
addedLines: data.totals.addedLines,
|
|
75
|
-
deletedLines: data.totals.deletedLines
|
|
76
|
-
}
|
|
77
|
-
};
|
|
49
|
+
return parseApplyPatchPartialResult(payload.data);
|
|
78
50
|
}
|
|
79
51
|
export function contextGcApplyPatchInputReplacement(arguments_, result, evidenceSequence, formatVersion = 2) {
|
|
80
52
|
const original = typeof arguments_ === 'string' ? arguments_ : stableJson(arguments_);
|
|
@@ -2,7 +2,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { MarAgentError, describeMarAgentError } from '../../error.js';
|
|
3
3
|
import { AGENT_EXECUTION_POLICY } from '../../runtime/execution-policy.js';
|
|
4
4
|
import { allowsToolCaller } from '../callers.js';
|
|
5
|
-
import { boundedModelToolOutput, structuredToolEventData } from '../output-projection.js';
|
|
5
|
+
import { boundedModelToolOutput, structuredToolEventData, structuredToolFailureData } from '../output-projection.js';
|
|
6
6
|
import { executeRegisteredTool } from '../runtime.js';
|
|
7
7
|
/** Capture only the cell's immutable dispatch identity, never the model loop or its AbortSignal. */
|
|
8
8
|
export function createCodeToolDispatch(input) {
|
|
@@ -56,11 +56,13 @@ export function createCodeToolDispatch(input) {
|
|
|
56
56
|
throw error;
|
|
57
57
|
}
|
|
58
58
|
const diagnostic = describeMarAgentError(error, 'MAR_AGENT_HOST_OPERATION_FAILED');
|
|
59
|
+
const data = structuredToolFailureData(call.name, error);
|
|
59
60
|
await input.emit({
|
|
60
61
|
type: 'tool.failed',
|
|
61
62
|
...identity,
|
|
62
63
|
code: diagnostic.code,
|
|
63
|
-
message: diagnostic.message
|
|
64
|
+
message: diagnostic.message,
|
|
65
|
+
...(data === undefined ? {} : { data })
|
|
64
66
|
});
|
|
65
67
|
throw error;
|
|
66
68
|
}
|
|
@@ -15,6 +15,7 @@ import { BoundedTextOutput, renderCapturedText } from './text-output.js';
|
|
|
15
15
|
import { TOOL_EXECUTION_LIMITS as limits } from '../execution-limits.js';
|
|
16
16
|
import { createToolCallScheduler } from '../scheduler.js';
|
|
17
17
|
import { detectImageMime } from '../local/view-image.js';
|
|
18
|
+
import { structuredToolFailureData } from '../output-projection.js';
|
|
18
19
|
export const codeModeToolDefinition = {
|
|
19
20
|
name: 'code_exec',
|
|
20
21
|
description: `Run JavaScript to orchestrate or compose tool calls.
|
|
@@ -511,6 +512,7 @@ export class CodeModeTool {
|
|
|
511
512
|
if (context.signal.aborted)
|
|
512
513
|
return;
|
|
513
514
|
const diagnostic = describeMarAgentError(error, 'MAR_AGENT_HOST_OPERATION_FAILED');
|
|
515
|
+
const data = structuredToolFailureData(source.toolName, error);
|
|
514
516
|
recordCall({
|
|
515
517
|
...source,
|
|
516
518
|
status: 'failed',
|
|
@@ -520,7 +522,12 @@ export class CodeModeTool {
|
|
|
520
522
|
source,
|
|
521
523
|
outcome: 'failed',
|
|
522
524
|
result: {
|
|
523
|
-
content: JSON.stringify({
|
|
525
|
+
content: JSON.stringify({
|
|
526
|
+
error: diagnostic.code,
|
|
527
|
+
message: diagnostic.message,
|
|
528
|
+
...(data === undefined ? {} : { data })
|
|
529
|
+
}),
|
|
530
|
+
...(data === undefined ? {} : { data })
|
|
524
531
|
}
|
|
525
532
|
});
|
|
526
533
|
await write({
|
|
@@ -132,6 +132,10 @@ export interface ApplyPatchResult {
|
|
|
132
132
|
deletedLines: number;
|
|
133
133
|
};
|
|
134
134
|
}
|
|
135
|
+
export interface ApplyPatchPartialResult extends ApplyPatchResult {
|
|
136
|
+
failedFile: string;
|
|
137
|
+
pendingFiles: string[];
|
|
138
|
+
}
|
|
135
139
|
export interface ReadEventData {
|
|
136
140
|
mode: 'batch';
|
|
137
141
|
results: Array<{
|
|
@@ -3,7 +3,7 @@ import { AGENT_EXECUTION_POLICY } from '../runtime/execution-policy.js';
|
|
|
3
3
|
import { allowsToolCaller } from './callers.js';
|
|
4
4
|
import { CodeCellExecutionError } from './code-mode/cells.js';
|
|
5
5
|
import { createCodeToolDispatch } from './code-mode/dispatch.js';
|
|
6
|
-
import { boundedModelToolOutput, structuredToolArtifacts, structuredToolEventData } from './output-projection.js';
|
|
6
|
+
import { boundedModelToolOutput, structuredToolArtifacts, structuredToolEventData, structuredToolFailureData } from './output-projection.js';
|
|
7
7
|
import { executeRegisteredTool } from './runtime.js';
|
|
8
8
|
import { scheduleToolCallBatch } from './scheduler.js';
|
|
9
9
|
/** Shared raw context construction for physical tools and native calls in a real model round. */
|
|
@@ -114,6 +114,11 @@ export async function executeRoundTools(calls, scope) {
|
|
|
114
114
|
catch (error) {
|
|
115
115
|
const diagnostic = describeMarAgentError(error, 'MAR_AGENT_HOST_OPERATION_FAILED');
|
|
116
116
|
const partial = error instanceof CodeCellExecutionError ? error.result : undefined;
|
|
117
|
+
const failureData = structuredToolFailureData(call.name, error);
|
|
118
|
+
const eventData = failureData ??
|
|
119
|
+
(partial?.data === undefined
|
|
120
|
+
? undefined
|
|
121
|
+
: structuredToolEventData(call.name, partial.data));
|
|
117
122
|
await scope.emit({
|
|
118
123
|
type: 'tool.failed',
|
|
119
124
|
toolName: call.name,
|
|
@@ -121,20 +126,17 @@ export async function executeRoundTools(calls, scope) {
|
|
|
121
126
|
...(parentCallId === undefined ? {} : { parentCallId }),
|
|
122
127
|
code: diagnostic.code,
|
|
123
128
|
message: diagnostic.message,
|
|
124
|
-
...(
|
|
125
|
-
? {}
|
|
126
|
-
: {
|
|
127
|
-
data: structuredToolEventData(call.name, partial.data)
|
|
128
|
-
})
|
|
129
|
+
...(eventData === undefined ? {} : { data: eventData })
|
|
129
130
|
});
|
|
130
131
|
return {
|
|
131
132
|
call,
|
|
132
133
|
content: partial === undefined
|
|
133
|
-
? JSON.stringify({
|
|
134
|
+
? boundedModelToolOutput(call.name, JSON.stringify({
|
|
134
135
|
error: diagnostic.code,
|
|
135
136
|
message: diagnostic.message,
|
|
137
|
+
...(failureData === undefined ? {} : { data: failureData }),
|
|
136
138
|
...(error instanceof MarAgentError && error.retryable ? { retryable: true } : {})
|
|
137
|
-
})
|
|
139
|
+
}), failureData).content
|
|
138
140
|
: boundedModelToolOutput(call.name, partial.content, partial.data).content,
|
|
139
141
|
...(partial?.images?.length ? { images: partial.images } : {}),
|
|
140
142
|
failed: true,
|
|
@@ -526,7 +526,17 @@ function partialPatchError(cause, appliedResults, pendingChanges) {
|
|
|
526
526
|
return new MarAgentError('MAR_AGENT_PATCH_PARTIAL', `Patch partially applied. Applied: ${summarizePaths(appliedFiles)}. Failed: ${failedFile}. Pending: ${summarizePaths(pendingFiles)}. Retry only failed and pending paths.`, {
|
|
527
527
|
cause,
|
|
528
528
|
retryable: true,
|
|
529
|
-
details: {
|
|
529
|
+
details: {
|
|
530
|
+
appliedFiles,
|
|
531
|
+
failedFile,
|
|
532
|
+
pendingFiles,
|
|
533
|
+
files: appliedResults,
|
|
534
|
+
totals: {
|
|
535
|
+
files: appliedResults.length,
|
|
536
|
+
addedLines: appliedResults.reduce((total, file) => total + file.addedLines, 0),
|
|
537
|
+
deletedLines: appliedResults.reduce((total, file) => total + file.deletedLines, 0)
|
|
538
|
+
}
|
|
539
|
+
}
|
|
530
540
|
});
|
|
531
541
|
}
|
|
532
542
|
function resultPath(result) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SubagentTaskSnapshot } from '../subagent/contracts.js';
|
|
2
|
-
import type { ApplyPatchResult, CodeCellEventData, ExecResult, MarAgentToolArtifact, ToolExecutionResult, ReadEventData, ViewImageResult } from './contracts.js';
|
|
2
|
+
import type { ApplyPatchResult, ApplyPatchPartialResult, CodeCellEventData, ExecResult, MarAgentToolArtifact, ToolExecutionResult, ReadEventData, ViewImageResult } from './contracts.js';
|
|
3
3
|
import type { ToolRuntimeImage } from './runtime-context.js';
|
|
4
4
|
export declare function currentExecutionImages(modelInputImages: readonly {
|
|
5
5
|
readonly mimeType: string;
|
|
@@ -11,6 +11,8 @@ export declare function boundedModelToolOutput(toolName: string, value: string,
|
|
|
11
11
|
};
|
|
12
12
|
/** Project only known, validated tool result shapes into public structured events. */
|
|
13
13
|
export declare function structuredToolEventData(toolName: string, value: unknown): CodeCellEventData | ExecResult | ApplyPatchResult | ReadEventData | ViewImageResult | SubagentTaskSnapshot | undefined;
|
|
14
|
+
/** Partial patch facts are allowlisted; arbitrary error details never become public event data. */
|
|
15
|
+
export declare function structuredToolFailureData(toolName: string, error: unknown): ApplyPatchPartialResult | undefined;
|
|
14
16
|
export declare function structuredToolArtifacts(value: readonly MarAgentToolArtifact[] | undefined): readonly MarAgentToolArtifact[] | undefined;
|
|
15
17
|
/** Shared result contract for model, programmatic, and native API callers. */
|
|
16
18
|
export declare function validateToolResult(value: ToolExecutionResult): ToolExecutionResult;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { MarAgentError } from '../error.js';
|
|
2
|
+
import { parseApplyPatchResult, parseApplyPatchPartialResult } from './shared/patch-result.js';
|
|
2
3
|
import { AGENT_EXECUTION_POLICY } from '../runtime/execution-policy.js';
|
|
3
4
|
import { countModelTokens, countTextLines, truncateModelText } from '../runtime/token-budget.js';
|
|
4
5
|
import { TOOL_EXECUTION_LIMITS } from './execution-limits.js';
|
|
@@ -127,25 +128,18 @@ export function structuredToolEventData(toolName, value) {
|
|
|
127
128
|
isNonnegativeInteger(value.stdoutDroppedBytes) &&
|
|
128
129
|
isNonnegativeInteger(value.stderrDroppedBytes))
|
|
129
130
|
return value;
|
|
130
|
-
if (toolName === 'apply_patch'
|
|
131
|
-
|
|
132
|
-
value.files.every((file) => isRecord(file) &&
|
|
133
|
-
typeof file.path === 'string' &&
|
|
134
|
-
file.path.length > 0 &&
|
|
135
|
-
(file.targetPath === undefined || typeof file.targetPath === 'string') &&
|
|
136
|
-
(file.operation === 'added' ||
|
|
137
|
-
file.operation === 'modified' ||
|
|
138
|
-
file.operation === 'deleted' ||
|
|
139
|
-
file.operation === 'moved') &&
|
|
140
|
-
isNonnegativeInteger(file.addedLines) &&
|
|
141
|
-
isNonnegativeInteger(file.deletedLines)) &&
|
|
142
|
-
isRecord(value.totals) &&
|
|
143
|
-
isNonnegativeInteger(value.totals.files) &&
|
|
144
|
-
isNonnegativeInteger(value.totals.addedLines) &&
|
|
145
|
-
isNonnegativeInteger(value.totals.deletedLines))
|
|
146
|
-
return value;
|
|
131
|
+
if (toolName === 'apply_patch')
|
|
132
|
+
return parseApplyPatchResult(value);
|
|
147
133
|
return undefined;
|
|
148
134
|
}
|
|
135
|
+
/** Partial patch facts are allowlisted; arbitrary error details never become public event data. */
|
|
136
|
+
export function structuredToolFailureData(toolName, error) {
|
|
137
|
+
return toolName === 'apply_patch' &&
|
|
138
|
+
error instanceof MarAgentError &&
|
|
139
|
+
error.code === 'MAR_AGENT_PATCH_PARTIAL'
|
|
140
|
+
? parseApplyPatchPartialResult(error.details)
|
|
141
|
+
: undefined;
|
|
142
|
+
}
|
|
149
143
|
export function structuredToolArtifacts(value) {
|
|
150
144
|
if (value === undefined)
|
|
151
145
|
return undefined;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ApplyPatchPartialResult, ApplyPatchResult } from '../contracts.js';
|
|
2
|
+
/** Keep event projection and persisted GC evidence on the same file-result contract. */
|
|
3
|
+
export declare function parseApplyPatchResult(value: unknown): ApplyPatchResult | undefined;
|
|
4
|
+
export declare function parseApplyPatchPartialResult(value: unknown): ApplyPatchPartialResult | undefined;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { TOOL_EXECUTION_LIMITS } from '../execution-limits.js';
|
|
2
|
+
/** Keep event projection and persisted GC evidence on the same file-result contract. */
|
|
3
|
+
export function parseApplyPatchResult(value) {
|
|
4
|
+
if (!isRecord(value) ||
|
|
5
|
+
!Array.isArray(value.files) ||
|
|
6
|
+
value.files.length > TOOL_EXECUTION_LIMITS.patchMaxFiles ||
|
|
7
|
+
!isRecord(value.totals))
|
|
8
|
+
return undefined;
|
|
9
|
+
const files = [];
|
|
10
|
+
for (const file of value.files) {
|
|
11
|
+
if (!isRecord(file) ||
|
|
12
|
+
!isPath(file.path) ||
|
|
13
|
+
(file.operation !== 'added' &&
|
|
14
|
+
file.operation !== 'modified' &&
|
|
15
|
+
file.operation !== 'deleted' &&
|
|
16
|
+
file.operation !== 'moved') ||
|
|
17
|
+
(file.targetPath !== undefined && !isPath(file.targetPath)) ||
|
|
18
|
+
(file.operation === 'moved' && !isPath(file.targetPath)) ||
|
|
19
|
+
!isCount(file.addedLines) ||
|
|
20
|
+
!isCount(file.deletedLines))
|
|
21
|
+
return undefined;
|
|
22
|
+
files.push({
|
|
23
|
+
path: file.path,
|
|
24
|
+
operation: file.operation,
|
|
25
|
+
...(typeof file.targetPath === 'string' ? { targetPath: file.targetPath } : {}),
|
|
26
|
+
addedLines: file.addedLines,
|
|
27
|
+
deletedLines: file.deletedLines
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const totals = value.totals;
|
|
31
|
+
if (!isCount(totals.files) ||
|
|
32
|
+
!isCount(totals.addedLines) ||
|
|
33
|
+
!isCount(totals.deletedLines) ||
|
|
34
|
+
totals.files !== files.length ||
|
|
35
|
+
totals.addedLines !== files.reduce((n, file) => n + file.addedLines, 0) ||
|
|
36
|
+
totals.deletedLines !== files.reduce((n, file) => n + file.deletedLines, 0))
|
|
37
|
+
return undefined;
|
|
38
|
+
return {
|
|
39
|
+
files,
|
|
40
|
+
totals: {
|
|
41
|
+
files: totals.files,
|
|
42
|
+
addedLines: totals.addedLines,
|
|
43
|
+
deletedLines: totals.deletedLines
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function parseApplyPatchPartialResult(value) {
|
|
48
|
+
const result = parseApplyPatchResult(value);
|
|
49
|
+
if (!result?.files.length ||
|
|
50
|
+
!isRecord(value) ||
|
|
51
|
+
!isPath(value.failedFile) ||
|
|
52
|
+
!Array.isArray(value.pendingFiles) ||
|
|
53
|
+
!value.pendingFiles.every(isPath) ||
|
|
54
|
+
result.files.length + value.pendingFiles.length + 1 > TOOL_EXECUTION_LIMITS.patchMaxFiles)
|
|
55
|
+
return undefined;
|
|
56
|
+
return { ...result, failedFile: value.failedFile, pendingFiles: [...value.pendingFiles] };
|
|
57
|
+
}
|
|
58
|
+
function isRecord(value) {
|
|
59
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
60
|
+
}
|
|
61
|
+
function isPath(value) {
|
|
62
|
+
return typeof value === 'string' && value.length > 0 && !value.includes('\0');
|
|
63
|
+
}
|
|
64
|
+
function isCount(value) {
|
|
65
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
|
|
66
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export type { CoreProcessesApi, CoreProcessesBackend, CoreProcessInput, CoreProc
|
|
|
37
37
|
export type { CreateMarAgentOptions, CreateSessionInput, ExecutionHandle, MarAgent, MarAgentSession, SessionTitleUpdateInput } from './agent-core/sdk/types.js';
|
|
38
38
|
export { openMarAgentSessionCatalog, type MarAgentContextUsage, type MarAgentHistoryEntry, type MarAgentHistoryPage, type MarAgentSessionCatalog, type MarAgentSessionDeleteResult, type MarAgentSessionImage, type MarAgentSessionPage, type MarAgentSessionSummary } from './agent-core/session/catalog.js';
|
|
39
39
|
export type { SessionListInput, SessionSource } from './agent-core/session/types.js';
|
|
40
|
-
export type { ApplyPatchFileResult, ApplyPatchResult, ClientToolDefinition, MarAgentToolArtifact, MarAgentToolImageArtifact, McpCatalogTool, McpToolCallContext, McpToolCatalog, McpToolCatalogContext, ToolCall, ToolCaller, ToolExecutionContext, ToolExecutionResult } from './agent-core/tools/contracts.js';
|
|
40
|
+
export type { ApplyPatchFileResult, ApplyPatchResult, ApplyPatchPartialResult, ClientToolDefinition, MarAgentToolArtifact, MarAgentToolImageArtifact, McpCatalogTool, McpToolCallContext, McpToolCatalog, McpToolCatalogContext, ToolCall, ToolCaller, ToolExecutionContext, ToolExecutionResult } from './agent-core/tools/contracts.js';
|
|
41
41
|
export { MCP_DEFINITION_LIMITS, assertMcpToolCatalog, assertMcpToolDefinition } from './agent-core/tools/mcp/catalog.js';
|
|
42
42
|
export type { WorkspacePathMount } from './agent-core/tools/shared/path-resolver.js';
|
|
43
43
|
export type { CodeModeEngine, CodeModeEngineFactory, CreateCodeModeEngine } from './agent-core/tools/code-mode/engine.js';
|