@myagentroam/agent 0.9.142 → 0.9.143
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/model/anthropic-messages.js +24 -13
- package/dist/agent-core/model/contracts.d.ts +4 -0
- package/dist/agent-core/model/openai-responses.js +16 -9
- package/dist/agent-core/runtime/context/gc-tokens.js +4 -2
- package/dist/agent-core/runtime/context/gc.js +146 -13
- package/dist/agent-core/runtime/context/projection.js +31 -0
- package/dist/agent-core/runtime/events.d.ts +1 -0
- package/dist/agent-core/runtime/execution.js +4 -0
- package/dist/agent-core/session/context-gc-checkpoint.d.ts +3 -0
- package/dist/agent-core/session/context-gc-checkpoint.js +121 -22
- package/dist/agent-core/session/context-gc-observations.d.ts +38 -0
- package/dist/agent-core/session/context-gc-observations.js +150 -0
- package/dist/agent-core/session/context-gc-replacements.d.ts +1 -1
- package/dist/agent-core/session/context-gc-replacements.js +6 -2
- package/dist/agent-core/tools/code-mode/cells.d.ts +3 -0
- package/dist/agent-core/tools/code-mode/cells.js +59 -5
- package/dist/agent-core/tools/code-mode/dispatch.js +7 -4
- package/dist/agent-core/tools/code-mode/engine.d.ts +12 -0
- package/dist/agent-core/tools/code-mode/index.js +176 -13
- package/dist/agent-core/tools/code-mode/observations.d.ts +103 -0
- package/dist/agent-core/tools/code-mode/observations.js +195 -0
- package/dist/agent-core/tools/code-mode/quickjs-engine.js +91 -17
- package/dist/agent-core/tools/code-mode/worker.js +8 -1
- package/dist/agent-core/tools/contracts.d.ts +4 -0
- package/dist/agent-core/tools/execution.d.ts +2 -0
- package/dist/agent-core/tools/execution.js +10 -1
- package/dist/agent-core/tools/output-projection.js +35 -1
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { observationModelParts } from '../tools/code-mode/observations.js';
|
|
1
2
|
import { randomUUID } from 'node:crypto';
|
|
2
3
|
import { MarAgentError } from '../error.js';
|
|
3
4
|
import { resolveModelDefaultReasoningEffort } from './configuration.js';
|
|
@@ -475,19 +476,29 @@ function anthropicMessages(messages, images, tools = [], modelId) {
|
|
|
475
476
|
const block = {
|
|
476
477
|
type: 'tool_result',
|
|
477
478
|
tool_use_id: message.callId,
|
|
478
|
-
content: message.
|
|
479
|
-
?
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
479
|
+
content: observationModelParts(message)?.map((part) => part.type === 'text'
|
|
480
|
+
? { type: 'text', text: part.text }
|
|
481
|
+
: {
|
|
482
|
+
type: 'image',
|
|
483
|
+
source: {
|
|
484
|
+
type: 'base64',
|
|
485
|
+
media_type: part.image.mimeType,
|
|
486
|
+
data: part.image.dataBase64
|
|
487
|
+
}
|
|
488
|
+
}) ??
|
|
489
|
+
(message.images?.length
|
|
490
|
+
? [
|
|
491
|
+
{ type: 'text', text: message.content },
|
|
492
|
+
...message.images.map((image) => ({
|
|
493
|
+
type: 'image',
|
|
494
|
+
source: {
|
|
495
|
+
type: 'base64',
|
|
496
|
+
media_type: image.mimeType,
|
|
497
|
+
data: image.dataBase64
|
|
498
|
+
}
|
|
499
|
+
}))
|
|
500
|
+
]
|
|
501
|
+
: message.content)
|
|
491
502
|
};
|
|
492
503
|
const previous = result.at(-1);
|
|
493
504
|
if (previous?.role === 'user' && Array.isArray(previous.content))
|
|
@@ -2,6 +2,7 @@ import type { ClientToolDefinition } from '../tools/contracts.js';
|
|
|
2
2
|
import type { MarAgentModelConfiguration, MarAgentReasoningEffort, ModelCredentialAcquireReason } from './configuration.js';
|
|
3
3
|
export type { ClientToolDefinition, ToolCaller } from '../tools/contracts.js';
|
|
4
4
|
export interface ModelMessage {
|
|
5
|
+
calls?: readonly import('../tools/code-mode/observations.js').CodeToolCallRecord[];
|
|
5
6
|
role: 'user' | 'assistant' | 'tool' | 'tool_call' | 'provider';
|
|
6
7
|
content: string;
|
|
7
8
|
contextKind?: 'environment' | 'private';
|
|
@@ -18,6 +19,9 @@ export interface ModelMessage {
|
|
|
18
19
|
mimeType: string;
|
|
19
20
|
dataBase64: string;
|
|
20
21
|
}[];
|
|
22
|
+
observations?: readonly import('../tools/code-mode/observations.js').CodeObservation[];
|
|
23
|
+
/** Runtime-only location used by the GC evidence adapter, never a Provider call. */
|
|
24
|
+
observationId?: string;
|
|
21
25
|
}
|
|
22
26
|
export interface ModelAttemptDiagnostic {
|
|
23
27
|
protocol: MarAgentModelConfiguration['protocol'];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { observationModelParts } from '../tools/code-mode/observations.js';
|
|
1
2
|
import { isDeepStrictEqual } from 'node:util';
|
|
2
3
|
import { createHash, randomUUID } from 'node:crypto';
|
|
3
4
|
import { describeMarAgentError, MarAgentError } from '../error.js';
|
|
@@ -1811,15 +1812,21 @@ function openAiInputItem(message, images, customCallIds = new Set(), nativeToolS
|
|
|
1811
1812
|
? 'custom_tool_call_output'
|
|
1812
1813
|
: 'function_call_output',
|
|
1813
1814
|
call_id: message.callId,
|
|
1814
|
-
output: message.
|
|
1815
|
-
?
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1815
|
+
output: observationModelParts(message)?.map((part) => part.type === 'text'
|
|
1816
|
+
? { type: 'input_text', text: part.text }
|
|
1817
|
+
: {
|
|
1818
|
+
type: 'input_image',
|
|
1819
|
+
image_url: `data:${part.image.mimeType};base64,${part.image.dataBase64}`
|
|
1820
|
+
}) ??
|
|
1821
|
+
(message.images?.length
|
|
1822
|
+
? [
|
|
1823
|
+
{ type: 'input_text', text: message.content },
|
|
1824
|
+
...message.images.map((image) => ({
|
|
1825
|
+
type: 'input_image',
|
|
1826
|
+
image_url: `data:${image.mimeType};base64,${image.dataBase64}`
|
|
1827
|
+
}))
|
|
1828
|
+
]
|
|
1829
|
+
: message.content)
|
|
1823
1830
|
};
|
|
1824
1831
|
return {
|
|
1825
1832
|
role: message.role,
|
|
@@ -14,8 +14,10 @@ function serializedEntries(input, messages) {
|
|
|
14
14
|
(input.messages ?? messages).some((message) => message.provider === 'OPENAI_RESPONSES'));
|
|
15
15
|
const values = responses
|
|
16
16
|
? openAiInput(messages, undefined, input.modelId, true, true, input.responsesConfigurationUpdates !== false)
|
|
17
|
-
: messages
|
|
18
|
-
(message.
|
|
17
|
+
: messages
|
|
18
|
+
.filter((message) => message.role !== 'provider' ||
|
|
19
|
+
(message.provider === 'ANTHROPIC_MESSAGES' && message.providerModelId === input.modelId))
|
|
20
|
+
.map(({ observations: _observations, observationId: _observationId, ...message }) => message);
|
|
19
21
|
return values.map((value, index) => {
|
|
20
22
|
const item = value;
|
|
21
23
|
const callId = item.call_id ?? item.callId;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { countModelTokens } from '../token-budget.js';
|
|
2
|
+
import { renderObservations } from '../../tools/code-mode/observations.js';
|
|
3
|
+
import { codeCallEvidence, codeObservationEvidence, retainedCodeInputs } from '../../session/context-gc-observations.js';
|
|
1
4
|
import { ContextGcCheckpointCache, contextGcBaseFromRecords, contextGcLogicalPathKey, contextGcMinimumUsageGrowth, contextGcRecordSourceHash, contextGcTargetKey, normalizeContextGcReplacements } from '../../session/context-gc-checkpoint.js';
|
|
2
5
|
import { codeCellCompletionSequence, contextGcApplyPatchInputReplacement, contextGcCodeModeInputReplacement, contextGcCodeModeOutputReplacement, contextGcExecInputReplacement, contextGcExecOutputReplacement, contextGcPatchResultFromCompletedPayload, contextGcStaleReadReplacement, contextGcWebOutputReplacement, normalizeContextGcCodeModeInput, normalizeContextGcExecResult } from '../../session/context-gc-replacements.js';
|
|
3
6
|
import { contextGcSubagentNeedsRetainedPriorFinal, contextGcSubagentOutputReplacement, contextGcSubagentPriorFinalIsRetained, contextGcSubagentSnapshotIsPreciselyCovered, contextGcSubagentSnapshotIsSuperseded, contextGcSubagentSnapshotTurnId, normalizeContextGcSubagentSnapshot } from '../../session/context-gc-subagent.js';
|
|
@@ -258,6 +261,37 @@ function collectCodeModeCandidates(input, groups, existingTargets, usageRatio) {
|
|
|
258
261
|
: LARGE_TERMINAL_OUTPUT_TOKENS;
|
|
259
262
|
if (visibleTokens < minimumVisibleTokens)
|
|
260
263
|
continue;
|
|
264
|
+
for (const observation of group.result.message.observations ?? []) {
|
|
265
|
+
if (observation.type !== 'value' ||
|
|
266
|
+
countModelTokens(observation.value) < minimumVisibleTokens)
|
|
267
|
+
continue;
|
|
268
|
+
const target = targetFor(group.result.record, {
|
|
269
|
+
...group.result.message,
|
|
270
|
+
observationId: observation.id
|
|
271
|
+
});
|
|
272
|
+
if (!target || existingTargets.has(contextGcTargetKey(target)))
|
|
273
|
+
continue;
|
|
274
|
+
const evidenceSequence = group.result.record.sequence;
|
|
275
|
+
const candidate = {
|
|
276
|
+
replacements: [
|
|
277
|
+
{
|
|
278
|
+
kind: 'CODE_MODE_OUTPUT',
|
|
279
|
+
callId: group.callId,
|
|
280
|
+
target,
|
|
281
|
+
replacementContent: contextGcCodeModeOutputReplacement(observation.value, observation.truncated === true),
|
|
282
|
+
evidenceSequence
|
|
283
|
+
}
|
|
284
|
+
],
|
|
285
|
+
observedRollouts: successfulRolloutsAfter(input.records, Math.max(evidenceSequence, completionSequence), input.modelId, input.contextWindowTokens),
|
|
286
|
+
evidenceSequence
|
|
287
|
+
};
|
|
288
|
+
if (candidate.observedRollouts >= CONTEXT_GC_POLICY.largeExecProtectionRollouts)
|
|
289
|
+
eligible.push(candidate);
|
|
290
|
+
else {
|
|
291
|
+
protectedTokens += candidateTokens(input, candidate);
|
|
292
|
+
retryAfterRollouts = Math.min(retryAfterRollouts, CONTEXT_GC_POLICY.largeExecProtectionRollouts - candidate.observedRollouts);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
261
295
|
const callTarget = targetFor(group.call.record, group.call.message);
|
|
262
296
|
const resultTarget = targetFor(group.result.record, group.result.message);
|
|
263
297
|
if (!callTarget || !resultTarget)
|
|
@@ -270,13 +304,14 @@ function collectCodeModeCandidates(input, groups, existingTargets, usageRatio) {
|
|
|
270
304
|
toolName: group.toolName,
|
|
271
305
|
callId: group.callId,
|
|
272
306
|
target: callTarget,
|
|
273
|
-
replacementArguments: contextGcCodeModeInputReplacement(code),
|
|
307
|
+
replacementArguments: contextGcCodeModeInputReplacement(code, group.result.message.observations ? retainedCodeInputs(input.records, group.callId) : []),
|
|
274
308
|
providerAliasTargets: group.aliases
|
|
275
309
|
.map(({ record, message }) => targetFor(record, message))
|
|
276
310
|
.filter((target) => target !== undefined),
|
|
277
311
|
evidenceSequence
|
|
278
312
|
});
|
|
279
|
-
if (!
|
|
313
|
+
if (!group.result.message.observations &&
|
|
314
|
+
!existingTargets.has(contextGcTargetKey(resultTarget)))
|
|
280
315
|
replacements.push({
|
|
281
316
|
kind: 'CODE_MODE_OUTPUT',
|
|
282
317
|
callId: group.callId,
|
|
@@ -503,7 +538,7 @@ function collectStageACandidates(input, groups, existingReplacements, existingTa
|
|
|
503
538
|
const reads = [...groups.values()].filter((group) => group.toolName === 'read' &&
|
|
504
539
|
group.call?.message.role === 'tool_call' &&
|
|
505
540
|
group.result?.message.role === 'tool');
|
|
506
|
-
const claimedReadItems = new Set([...existingReadReplacements.values()].flatMap((replacement) => replacement.items.map((item) => `${replacement.target.recordId}:${item.index}`)));
|
|
541
|
+
const claimedReadItems = new Set([...existingReadReplacements.values()].flatMap((replacement) => replacement.items.map((item) => `${replacement.target.recordId}:${replacement.target.observationId ?? ''}:${item.index}`)));
|
|
507
542
|
const patches = [...groups.values()]
|
|
508
543
|
.flatMap((patch) => {
|
|
509
544
|
if (patch.toolName !== 'apply_patch' ||
|
|
@@ -534,7 +569,7 @@ function collectStageACandidates(input, groups, existingReplacements, existingTa
|
|
|
534
569
|
evidenceSequence
|
|
535
570
|
});
|
|
536
571
|
for (const read of reads) {
|
|
537
|
-
if (read.result.record.sequence >=
|
|
572
|
+
if ((read.completed?.sequence ?? read.result.record.sequence) >= patch.completed.sequence)
|
|
538
573
|
continue;
|
|
539
574
|
const parsed = parseReadContextOutput(read.result.message.content);
|
|
540
575
|
if (!parsed)
|
|
@@ -542,7 +577,7 @@ function collectStageACandidates(input, groups, existingReplacements, existingTa
|
|
|
542
577
|
const selected = parsed.items.flatMap((item) => {
|
|
543
578
|
if (item.pathTruncated)
|
|
544
579
|
return [];
|
|
545
|
-
const itemKey = `${read.result.record.recordId}:${item.index}`;
|
|
580
|
+
const itemKey = `${read.result.record.recordId}:${read.result.message.observationId ?? ''}:${item.index}`;
|
|
546
581
|
if (claimedReadItems.has(itemKey))
|
|
547
582
|
return [];
|
|
548
583
|
const pathKey = contextGcLogicalPathKey(item.path, input.workspace, input.platform);
|
|
@@ -562,7 +597,8 @@ function collectStageACandidates(input, groups, existingReplacements, existingTa
|
|
|
562
597
|
supersededByCallId: patch.callId,
|
|
563
598
|
operation: matched.operation
|
|
564
599
|
}),
|
|
565
|
-
evidenceSequence
|
|
600
|
+
evidenceSequence,
|
|
601
|
+
...(read.result.message.observationId ? { supersededByCallId: patch.callId } : {})
|
|
566
602
|
}
|
|
567
603
|
];
|
|
568
604
|
});
|
|
@@ -616,8 +652,10 @@ function collectSubagentCandidates(input, groups, existingTargets) {
|
|
|
616
652
|
const turnId = snapshot && contextGcSubagentSnapshotTurnId(snapshot);
|
|
617
653
|
return snapshot && turnId ? [{ group, snapshot, turnId }] : [];
|
|
618
654
|
})
|
|
619
|
-
.sort((left, right) => left.group.
|
|
655
|
+
.sort((left, right) => left.group.completed.sequence - right.group.completed.sequence);
|
|
620
656
|
for (const [index, source] of invocations.entries()) {
|
|
657
|
+
if (source.group.evidenceOnly)
|
|
658
|
+
continue;
|
|
621
659
|
if (source.group.toolName !== 'agent_wait' &&
|
|
622
660
|
source.group.toolName !== 'agent_message' &&
|
|
623
661
|
source.group.toolName !== 'agent_cancel')
|
|
@@ -759,7 +797,9 @@ function collectExecCandidates(input, groups, existingTargets, usageRatio) {
|
|
|
759
797
|
if (!terminal || (processId && input.activeProcessIds.has(processId)))
|
|
760
798
|
continue;
|
|
761
799
|
const final = lifecycle.at(-1);
|
|
762
|
-
const visibleTokens = contextGcMessageTokens(input, lifecycle
|
|
800
|
+
const visibleTokens = contextGcMessageTokens(input, lifecycle
|
|
801
|
+
.filter((invocation) => !invocation.group.evidenceOnly)
|
|
802
|
+
.flatMap((invocation) => [
|
|
763
803
|
invocation.group.call.message,
|
|
764
804
|
invocation.group.result.message,
|
|
765
805
|
...invocation.group.aliases.map((alias) => alias.message)
|
|
@@ -773,13 +813,15 @@ function collectExecCandidates(input, groups, existingTargets, usageRatio) {
|
|
|
773
813
|
const observedRollouts = successfulRolloutsAfter(input.records, evidenceSequence, input.modelId, input.contextWindowTokens);
|
|
774
814
|
const replacements = [];
|
|
775
815
|
for (const invocation of lifecycle) {
|
|
816
|
+
if (invocation.group.evidenceOnly)
|
|
817
|
+
continue;
|
|
776
818
|
const callTarget = targetFor(invocation.group.call.record, invocation.group.call.message);
|
|
777
819
|
const resultTarget = targetFor(invocation.group.result.record, invocation.group.result.message);
|
|
778
|
-
if (!
|
|
820
|
+
if (!resultTarget) {
|
|
779
821
|
replacements.splice(0);
|
|
780
822
|
break;
|
|
781
823
|
}
|
|
782
|
-
if (!existingTargets.has(contextGcTargetKey(callTarget)))
|
|
824
|
+
if (callTarget && !existingTargets.has(contextGcTargetKey(callTarget)))
|
|
783
825
|
replacements.push({
|
|
784
826
|
kind: 'TOOL_CALL_INPUT',
|
|
785
827
|
toolName: invocation.group.toolName,
|
|
@@ -794,6 +836,7 @@ function collectExecCandidates(input, groups, existingTargets, usageRatio) {
|
|
|
794
836
|
if (!existingTargets.has(contextGcTargetKey(resultTarget)))
|
|
795
837
|
replacements.push({
|
|
796
838
|
kind: 'EXEC_OUTPUT',
|
|
839
|
+
...(resultTarget.observationId ? { terminalCallId: final.group.callId } : {}),
|
|
797
840
|
callId: invocation.group.callId,
|
|
798
841
|
target: resultTarget,
|
|
799
842
|
replacementContent: contextGcExecOutputReplacement(invocation.result),
|
|
@@ -918,6 +961,89 @@ function buildToolGroups(records, messages, sources) {
|
|
|
918
961
|
else if (type === 'tool.failed')
|
|
919
962
|
current.failed = record;
|
|
920
963
|
}
|
|
964
|
+
for (const [index, message] of messages.entries()) {
|
|
965
|
+
if (!message.observations || message.role !== 'tool')
|
|
966
|
+
continue;
|
|
967
|
+
const outer = message.callId ? groups.get(message.callId) : undefined;
|
|
968
|
+
if (!outer?.completed ||
|
|
969
|
+
outer.failed ||
|
|
970
|
+
codeCellCompletionSequence(records, outer.completed) === undefined)
|
|
971
|
+
continue;
|
|
972
|
+
const record = sources[index];
|
|
973
|
+
for (const entry of message.calls ?? []) {
|
|
974
|
+
if (![
|
|
975
|
+
'apply_patch',
|
|
976
|
+
'exec',
|
|
977
|
+
'exec_wait',
|
|
978
|
+
'agent_start',
|
|
979
|
+
'agent_wait',
|
|
980
|
+
'agent_message',
|
|
981
|
+
'agent_cancel'
|
|
982
|
+
].includes(entry.toolName) ||
|
|
983
|
+
message.observations.some((value) => value.type === 'tool_result' && value.source.callId === entry.callId))
|
|
984
|
+
continue;
|
|
985
|
+
const evidence = codeCallEvidence(records, record, entry);
|
|
986
|
+
if (!evidence)
|
|
987
|
+
continue;
|
|
988
|
+
groups.set(`execution:${evidence.callId}`, {
|
|
989
|
+
evidenceOnly: true,
|
|
990
|
+
callId: evidence.callId,
|
|
991
|
+
toolName: entry.toolName,
|
|
992
|
+
aliases: [],
|
|
993
|
+
completed: evidence.completed,
|
|
994
|
+
call: {
|
|
995
|
+
record: evidence.call,
|
|
996
|
+
message: {
|
|
997
|
+
role: 'tool_call',
|
|
998
|
+
callId: evidence.callId,
|
|
999
|
+
name: entry.toolName,
|
|
1000
|
+
content: '',
|
|
1001
|
+
arguments: entry.input
|
|
1002
|
+
}
|
|
1003
|
+
},
|
|
1004
|
+
result: {
|
|
1005
|
+
record,
|
|
1006
|
+
message: {
|
|
1007
|
+
role: 'tool',
|
|
1008
|
+
callId: message.callId,
|
|
1009
|
+
content: evidence.result.payload.content
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
for (const observation of message.observations) {
|
|
1015
|
+
if (observation.type !== 'tool_result')
|
|
1016
|
+
continue;
|
|
1017
|
+
const evidence = codeObservationEvidence(records, record, observation);
|
|
1018
|
+
if (!evidence)
|
|
1019
|
+
continue;
|
|
1020
|
+
groups.set(`${evidence.callId}:${observation.id}`, {
|
|
1021
|
+
callId: evidence.callId,
|
|
1022
|
+
toolName: observation.source.toolName,
|
|
1023
|
+
aliases: [],
|
|
1024
|
+
completed: evidence.completed,
|
|
1025
|
+
call: {
|
|
1026
|
+
record: evidence.call,
|
|
1027
|
+
message: {
|
|
1028
|
+
role: 'tool_call',
|
|
1029
|
+
callId: evidence.callId,
|
|
1030
|
+
name: observation.source.toolName,
|
|
1031
|
+
content: '',
|
|
1032
|
+
arguments: observation.source.input
|
|
1033
|
+
}
|
|
1034
|
+
},
|
|
1035
|
+
result: {
|
|
1036
|
+
record,
|
|
1037
|
+
message: {
|
|
1038
|
+
role: 'tool',
|
|
1039
|
+
callId: message.callId,
|
|
1040
|
+
content: observation.result.content,
|
|
1041
|
+
observationId: observation.id
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
921
1047
|
return groups;
|
|
922
1048
|
}
|
|
923
1049
|
function successfulRolloutsAfter(records, evidenceSequence, modelId, contextWindowTokens) {
|
|
@@ -1111,9 +1237,15 @@ function candidateTokens(input, candidate) {
|
|
|
1111
1237
|
? replacement.providerAliasTargets.map(contextGcTargetKey)
|
|
1112
1238
|
: [])
|
|
1113
1239
|
]));
|
|
1114
|
-
return contextGcMessageTokens(input, input.messages.
|
|
1240
|
+
return contextGcMessageTokens(input, input.messages.flatMap((message, index) => {
|
|
1115
1241
|
const target = targetFor(input.messageSources[index], message);
|
|
1116
|
-
|
|
1242
|
+
if (target && targets.has(contextGcTargetKey(target)))
|
|
1243
|
+
return [message];
|
|
1244
|
+
const selected = target &&
|
|
1245
|
+
message.observations?.filter((value) => targets.has(contextGcTargetKey({ ...target, observationId: value.id })));
|
|
1246
|
+
return selected?.length
|
|
1247
|
+
? [{ ...message, observations: selected, content: renderObservations(selected) }]
|
|
1248
|
+
: [];
|
|
1117
1249
|
}));
|
|
1118
1250
|
}
|
|
1119
1251
|
function targetFor(record, message) {
|
|
@@ -1128,7 +1260,8 @@ function targetFor(record, message) {
|
|
|
1128
1260
|
role: message.role,
|
|
1129
1261
|
...(callId === undefined ? {} : { callId }),
|
|
1130
1262
|
...(toolName === undefined ? {} : { toolName }),
|
|
1131
|
-
sourceHash: contextGcRecordSourceHash(record)
|
|
1263
|
+
sourceHash: contextGcRecordSourceHash(record),
|
|
1264
|
+
...(message.observationId ? { observationId: message.observationId } : {})
|
|
1132
1265
|
};
|
|
1133
1266
|
}
|
|
1134
1267
|
function modelContextUsage(value) {
|
|
@@ -2,6 +2,7 @@ import { anthropicThinkingBlock } from '../../model/anthropic-thinking.js';
|
|
|
2
2
|
import { contextGcRecordSourceHash, contextGcTargetKey, latestValidContextGcCheckpoint } from '../../session/context-gc-checkpoint.js';
|
|
3
3
|
import { TOOL_EXECUTION_LIMITS } from '../../tools/execution-limits.js';
|
|
4
4
|
import { replaceReadContextItems } from '../../tools/local/read-context.js';
|
|
5
|
+
import { parseCodeCalls, parseObservations, renderObservationResult } from '../../tools/code-mode/observations.js';
|
|
5
6
|
const MAX_MODEL_CONTEXT_BYTES = 1024 * 1024;
|
|
6
7
|
export function buildContextProjection(records, workspace, checkpointCache) {
|
|
7
8
|
let activeModelId;
|
|
@@ -50,6 +51,32 @@ export function applyContextGcReplacementsToMessages(messages, messageSources, r
|
|
|
50
51
|
continue;
|
|
51
52
|
const replacement = target ? direct.get(contextGcTargetKey(target)) : undefined;
|
|
52
53
|
let next = cloneMessage(message);
|
|
54
|
+
if (next.observations && target) {
|
|
55
|
+
const observations = next.observations.map((value) => {
|
|
56
|
+
const itemTarget = { ...target, observationId: value.id };
|
|
57
|
+
const item = direct.get(contextGcTargetKey(itemTarget));
|
|
58
|
+
if (!item || !targetMatchesReplacement(itemTarget, item.target))
|
|
59
|
+
return value;
|
|
60
|
+
if (item.kind === 'READ_OUTPUT_ITEMS' && value.type === 'tool_result')
|
|
61
|
+
return {
|
|
62
|
+
...value,
|
|
63
|
+
result: {
|
|
64
|
+
...value.result,
|
|
65
|
+
content: replaceReadContextItems(value.result.content, item.items)
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
if ('replacementContent' in item)
|
|
69
|
+
return value.type === 'tool_result'
|
|
70
|
+
? { ...value, result: { ...value.result, content: item.replacementContent } }
|
|
71
|
+
: { ...value, value: item.replacementContent };
|
|
72
|
+
return value;
|
|
73
|
+
});
|
|
74
|
+
next = {
|
|
75
|
+
...next,
|
|
76
|
+
observations,
|
|
77
|
+
content: renderObservationResult(observations, next.content)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
53
80
|
if (replacement && target && targetMatchesReplacement(target, replacement.target)) {
|
|
54
81
|
if (replacement.kind === 'READ_OUTPUT_ITEMS' &&
|
|
55
82
|
next.role === 'tool' &&
|
|
@@ -122,6 +149,10 @@ export function restoreModelContext(payload, providerModelId) {
|
|
|
122
149
|
role: 'tool',
|
|
123
150
|
content: payload.content,
|
|
124
151
|
callId: payload.callId,
|
|
152
|
+
...(parseCodeCalls(payload.calls) ? { calls: parseCodeCalls(payload.calls) } : {}),
|
|
153
|
+
...(parseObservations(payload.observations)
|
|
154
|
+
? { observations: parseObservations(payload.observations) }
|
|
155
|
+
: {}),
|
|
125
156
|
...(Array.isArray(payload.toolSearchTools)
|
|
126
157
|
? {
|
|
127
158
|
toolSearchTools: payload.toolSearchTools.filter((tool) => isRecord(tool) &&
|
|
@@ -82,6 +82,7 @@ export type MarAgentEvent = MarAgentEventBase & ({
|
|
|
82
82
|
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;
|
|
83
83
|
} | {
|
|
84
84
|
type: 'tool.failed';
|
|
85
|
+
data?: import('../tools/contracts.js').CodeCellEventData;
|
|
85
86
|
toolName: string;
|
|
86
87
|
callId: string;
|
|
87
88
|
parentCallId?: string;
|
|
@@ -312,6 +312,8 @@ export class ExecutionLoop {
|
|
|
312
312
|
role: 'tool',
|
|
313
313
|
callId: result.call.callId,
|
|
314
314
|
content: result.content,
|
|
315
|
+
...(result.calls ? { calls: result.calls } : {}),
|
|
316
|
+
...(result.observations ? { observations: result.observations } : {}),
|
|
315
317
|
...(toolSearchTools === undefined ? {} : { toolSearchTools }),
|
|
316
318
|
...('images' in result && result.images?.length ? { images: result.images } : {})
|
|
317
319
|
};
|
|
@@ -320,6 +322,8 @@ export class ExecutionLoop {
|
|
|
320
322
|
role: message.role,
|
|
321
323
|
callId: result.call.callId,
|
|
322
324
|
content: message.content,
|
|
325
|
+
...(message.calls ? { calls: message.calls } : {}),
|
|
326
|
+
...(message.observations ? { observations: message.observations } : {}),
|
|
323
327
|
...(message.toolSearchTools === undefined
|
|
324
328
|
? {}
|
|
325
329
|
: { toolSearchTools: message.toolSearchTools })
|
|
@@ -29,6 +29,7 @@ export type ContextGcBase = {
|
|
|
29
29
|
readonly recordId: string;
|
|
30
30
|
};
|
|
31
31
|
export interface ContextGcTarget {
|
|
32
|
+
readonly observationId?: string;
|
|
32
33
|
readonly sequence: number;
|
|
33
34
|
readonly recordId: string;
|
|
34
35
|
readonly role: 'tool_call' | 'tool' | 'provider';
|
|
@@ -37,6 +38,7 @@ export interface ContextGcTarget {
|
|
|
37
38
|
readonly sourceHash: string;
|
|
38
39
|
}
|
|
39
40
|
export interface ContextGcReadItemReplacement {
|
|
41
|
+
readonly supersededByCallId?: string;
|
|
40
42
|
readonly index: number;
|
|
41
43
|
readonly path: string;
|
|
42
44
|
readonly replacement: string;
|
|
@@ -58,6 +60,7 @@ export type ContextGcReplacement = {
|
|
|
58
60
|
readonly evidenceSequence: number;
|
|
59
61
|
} | {
|
|
60
62
|
readonly kind: 'EXEC_OUTPUT';
|
|
63
|
+
readonly terminalCallId?: string;
|
|
61
64
|
readonly callId: string;
|
|
62
65
|
readonly target: ContextGcTarget;
|
|
63
66
|
readonly replacementContent: string;
|