@myagentroam/agent 0.9.62 → 0.9.64

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.
Files changed (119) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +4 -0
  3. package/dist/cli/codex-auth-file.js +268 -3
  4. package/dist/cli/main.js +427 -2
  5. package/dist/error.js +66 -2
  6. package/dist/host/contracts.js +20 -2
  7. package/dist/host/local-agent-host.js +146 -2
  8. package/dist/host/local-process-executor.js +39 -2
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.js +12 -2
  11. package/dist/model/anthropic-messages.js +474 -2
  12. package/dist/model/anthropic-thinking.js +33 -2
  13. package/dist/model/catalog-file.js +88 -2
  14. package/dist/model/configuration.js +137 -2
  15. package/dist/model/contracts.d.ts +2 -0
  16. package/dist/model/contracts.js +1 -2
  17. package/dist/model/http.js +529 -2
  18. package/dist/model/openai-responses.d.ts +2 -0
  19. package/dist/model/openai-responses.js +1602 -2
  20. package/dist/model/runtime-credential.js +35 -2
  21. package/dist/model/sse.js +199 -2
  22. package/dist/prompts/compact.js +25 -2
  23. package/dist/prompts/core.js +37 -2
  24. package/dist/prompts/execution-budget.js +10 -2
  25. package/dist/prompts/index.d.ts +3 -2
  26. package/dist/prompts/index.js +47 -2
  27. package/dist/prompts/modes.js +25 -2
  28. package/dist/prompts/output.js +1 -2
  29. package/dist/prompts/resources.d.ts +1 -1
  30. package/dist/prompts/resources.js +31 -2
  31. package/dist/prompts/subagent.d.ts +6 -0
  32. package/dist/prompts/subagent.js +29 -2
  33. package/dist/prompts/title.js +9 -2
  34. package/dist/prompts/workflow.js +32 -2
  35. package/dist/runtime/async-queue.js +62 -2
  36. package/dist/runtime/builtin-skills.js +19 -2
  37. package/dist/runtime/byted-ark-imagegen-skill.js +18 -2
  38. package/dist/runtime/codex-imagegen-skill.js +35 -2
  39. package/dist/runtime/compact.js +225 -2
  40. package/dist/runtime/context-gc-runtime.d.ts +35 -0
  41. package/dist/runtime/context-gc-runtime.js +163 -0
  42. package/dist/runtime/context-gc-tokens.d.ts +24 -0
  43. package/dist/runtime/context-gc-tokens.js +83 -0
  44. package/dist/runtime/context-gc.d.ts +66 -0
  45. package/dist/runtime/context-gc.js +909 -0
  46. package/dist/runtime/context-projection.d.ts +23 -0
  47. package/dist/runtime/context-projection.js +203 -0
  48. package/dist/runtime/environment-context.js +41 -2
  49. package/dist/runtime/execution-policy.js +13 -2
  50. package/dist/runtime/instructions.js +298 -2
  51. package/dist/runtime/normalize.js +40 -2
  52. package/dist/runtime/plan-output.js +95 -2
  53. package/dist/runtime/rollout-budget.d.ts +2 -0
  54. package/dist/runtime/rollout-budget.js +92 -2
  55. package/dist/runtime/token-budget.d.ts +2 -0
  56. package/dist/runtime/token-budget.js +44 -2
  57. package/dist/sdk/agent.js +1804 -2
  58. package/dist/sdk/types.d.ts +15 -5
  59. package/dist/sdk/types.js +1 -2
  60. package/dist/session/catalog.d.ts +5 -4
  61. package/dist/session/catalog.js +133 -2
  62. package/dist/session/context-gc-checkpoint.d.ts +148 -0
  63. package/dist/session/context-gc-checkpoint.js +665 -0
  64. package/dist/session/context-gc-replacements.d.ts +52 -0
  65. package/dist/session/context-gc-replacements.js +226 -0
  66. package/dist/session/context-gc-subagent.d.ts +43 -0
  67. package/dist/session/context-gc-subagent.js +267 -0
  68. package/dist/session/jsonl-store.d.ts +42 -4
  69. package/dist/session/jsonl-store.js +1657 -2
  70. package/dist/subagent/scheduler.d.ts +35 -2
  71. package/dist/subagent/scheduler.js +249 -2
  72. package/dist/subagent/session-controller.d.ts +94 -0
  73. package/dist/subagent/session-controller.js +675 -0
  74. package/dist/tools/agent-cancel.js +28 -2
  75. package/dist/tools/{task.d.ts → agent-message.d.ts} +2 -2
  76. package/dist/tools/agent-message.js +51 -0
  77. package/dist/tools/agent-start.js +84 -2
  78. package/dist/tools/agent-wait.js +53 -2
  79. package/dist/tools/apply-patch.js +478 -2
  80. package/dist/tools/code-mode.js +370 -2
  81. package/dist/tools/codex-image-gen.js +312 -2
  82. package/dist/tools/exec.js +455 -2
  83. package/dist/tools/execution-limits.d.ts +1 -0
  84. package/dist/tools/execution-limits.js +44 -2
  85. package/dist/tools/local-registry.js +233 -2
  86. package/dist/tools/local-workspace-tools.js +28 -2
  87. package/dist/tools/question.js +124 -2
  88. package/dist/tools/read-context.d.ts +16 -0
  89. package/dist/tools/read-context.js +85 -0
  90. package/dist/tools/read.d.ts +13 -0
  91. package/dist/tools/read.js +294 -2
  92. package/dist/tools/registry.js +76 -2
  93. package/dist/tools/runtime-context.d.ts +9 -2
  94. package/dist/tools/runtime-context.js +1 -2
  95. package/dist/tools/runtime.js +21 -2
  96. package/dist/tools/scheduler.js +41 -2
  97. package/dist/tools/shared/path-resolver.js +133 -2
  98. package/dist/tools/skill.js +37 -2
  99. package/dist/tools/todo-read.js +10 -2
  100. package/dist/tools/todo-write.js +65 -2
  101. package/dist/tools/todo.js +67 -2
  102. package/dist/tools/view-image.js +81 -2
  103. package/dist/tools/web-fetch.js +11 -2
  104. package/dist/tools/web-search.js +14 -2
  105. package/package.json +9 -7
  106. package/README.md +0 -3
  107. package/dist/runtime/prompt.d.ts +0 -9
  108. package/dist/runtime/prompt.js +0 -2
  109. package/dist/tools/shared/secret-redaction.d.ts +0 -4
  110. package/dist/tools/shared/secret-redaction.js +0 -2
  111. package/dist/tools/task-cancel.d.ts +0 -7
  112. package/dist/tools/task-cancel.js +0 -2
  113. package/dist/tools/task-output.d.ts +0 -7
  114. package/dist/tools/task-output.js +0 -2
  115. package/dist/tools/task-tools.d.ts +0 -36
  116. package/dist/tools/task-tools.js +0 -2
  117. package/dist/tools/task.js +0 -2
  118. package/dist/tools/todo-tools.d.ts +0 -25
  119. package/dist/tools/todo-tools.js +0 -2
@@ -0,0 +1,665 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { posix, win32 } from 'node:path';
3
+ import { isDeepStrictEqual } from 'node:util';
4
+ import { parseReadContextOutput } from '../tools/read-context.js';
5
+ import { contextGcApplyPatchInputReplacement, contextGcExecInputReplacement, contextGcExecOutputReplacement, contextGcPatchResultFromCompletedPayload, contextGcStaleReadReplacement, normalizeContextGcExecResult } from './context-gc-replacements.js';
6
+ import { contextGcSubagentNeedsRetainedPriorFinal, contextGcSubagentOutputReplacement, contextGcSubagentSnapshotIsSuperseded, normalizeContextGcSubagentSnapshot } from './context-gc-subagent.js';
7
+ export const CONTEXT_GC_CHECKPOINT_VERSION = 1;
8
+ export const CONTEXT_GC_MAX_TARGETS = 4_096;
9
+ /** Disposable memoization for one evaluation's immutable record snapshot. */
10
+ export class ContextGcCheckpointCache {
11
+ #snapshot;
12
+ read(records, boundarySequence = records.at(-1)?.sequence ?? 0, workspace = sessionWorkspace(records)) {
13
+ const cached = this.#snapshot;
14
+ if (cached?.records === records &&
15
+ cached.boundarySequence === boundarySequence &&
16
+ cached.workspace === workspace)
17
+ return cached.value;
18
+ const value = latestValidContextGcCheckpoint(records, boundarySequence, workspace);
19
+ this.#snapshot = { records, boundarySequence, workspace, value };
20
+ return value;
21
+ }
22
+ }
23
+ export function contextGcMinimumUsageGrowth(contextWindowTokens) {
24
+ return Math.max(2_000, Math.floor(contextWindowTokens * 0.05));
25
+ }
26
+ const PROJECTION_RECORD_TYPES = new Set([
27
+ 'compact.completed',
28
+ 'context.environment',
29
+ 'execution.header',
30
+ 'message.completed',
31
+ 'model.context',
32
+ 'plan.completed',
33
+ 'turn.user'
34
+ ]);
35
+ export function contextGcRecordSourceHash(record) {
36
+ return createHash('sha256').update(stableJson(record.payload)).digest('hex');
37
+ }
38
+ export function contextGcLogicalPathKey(path, workspace, platform) {
39
+ if (!path || !workspace || path.includes('\0') || workspace.includes('\0'))
40
+ return undefined;
41
+ const windows = platform === 'win32' ||
42
+ (platform === undefined &&
43
+ (/^[a-zA-Z]:[\\/]/u.test(workspace) || /^[\\/]{2}/u.test(workspace)));
44
+ if (windows) {
45
+ const root = win32.resolve(workspace.replaceAll('/', '\\'));
46
+ const resolved = win32.resolve(root, path.replaceAll('/', '\\'));
47
+ const relative = win32.relative(root, resolved);
48
+ if (relative === '..' || relative.startsWith(`..${win32.sep}`) || win32.isAbsolute(relative))
49
+ return undefined;
50
+ return resolved.replaceAll('\\', '/').toLowerCase();
51
+ }
52
+ const root = posix.resolve(workspace);
53
+ const resolved = posix.resolve(root, path);
54
+ const relative = posix.relative(root, resolved);
55
+ if (relative === '..' || relative.startsWith('../') || posix.isAbsolute(relative))
56
+ return undefined;
57
+ return resolved;
58
+ }
59
+ export function contextGcTargetKey(target) {
60
+ return `${target.sequence}:${target.recordId}:${target.role}:${target.callId ?? ''}:${target.toolName ?? ''}`;
61
+ }
62
+ export function contextGcReplacementKey(replacement) {
63
+ return contextGcTargetKey(replacement.target);
64
+ }
65
+ export function contextGcBaseFromRecords(records, boundarySequence = records.at(-1)?.sequence ?? 0) {
66
+ const compact = records.findLast((record) => record.sequence <= boundarySequence &&
67
+ record.type === 'compact.completed' &&
68
+ isNonemptyString(record.payload?.summary));
69
+ if (compact)
70
+ return { type: 'COMPACT', sequence: compact.sequence, recordId: compact.recordId };
71
+ const first = records.find((record) => record.sequence <= boundarySequence && record.type === 'session.created');
72
+ return first ? { type: 'SESSION_START', firstSequence: first.sequence } : undefined;
73
+ }
74
+ export function contextGcBaseSequence(base) {
75
+ return base.type === 'COMPACT' ? base.sequence : base.firstSequence;
76
+ }
77
+ export function contextGcSourceProjectionHash(records, boundarySequence, base = contextGcBaseFromRecords(records, boundarySequence)) {
78
+ if (!base || !isValidBoundary(boundarySequence))
79
+ return undefined;
80
+ const baseSequence = contextGcBaseSequence(base);
81
+ if (!sameContextGcBase(base, contextGcBaseFromRecords(records, boundarySequence)))
82
+ return undefined;
83
+ const source = records
84
+ .filter((record) => record.sequence >= baseSequence &&
85
+ record.sequence <= boundarySequence &&
86
+ PROJECTION_RECORD_TYPES.has(record.type))
87
+ .map((record) => ({
88
+ sequence: record.sequence,
89
+ recordId: record.recordId,
90
+ type: record.type,
91
+ payload: record.payload
92
+ }));
93
+ return createHash('sha256').update(stableJson(source)).digest('hex');
94
+ }
95
+ export function normalizeContextGcReplacements(replacements) {
96
+ const normalized = new Map();
97
+ for (const replacement of replacements) {
98
+ if (!isContextGcReplacement(replacement))
99
+ return undefined;
100
+ normalized.set(contextGcReplacementKey(replacement), structuredClone(replacement));
101
+ }
102
+ const values = [...normalized.values()];
103
+ const targets = new Set(values.flatMap((replacement) => [
104
+ contextGcTargetKey(replacement.target),
105
+ ...(replacement.kind === 'TOOL_CALL_INPUT'
106
+ ? replacement.providerAliasTargets.map(contextGcTargetKey)
107
+ : [])
108
+ ]));
109
+ if (targets.size > CONTEXT_GC_MAX_TARGETS)
110
+ return undefined;
111
+ return values.sort((left, right) => left.target.sequence - right.target.sequence ||
112
+ contextGcReplacementKey(left).localeCompare(contextGcReplacementKey(right)));
113
+ }
114
+ export function parseContextGcCheckpoint(record) {
115
+ if (record?.type !== 'context.gc.completed' || !isRecord(record.payload))
116
+ return undefined;
117
+ const payload = record.payload;
118
+ if (payload.version !== CONTEXT_GC_CHECKPOINT_VERSION ||
119
+ !isNonemptyString(payload.checkpointId) ||
120
+ !isPositiveInteger(payload.generation) ||
121
+ !isContextGcBase(payload.base) ||
122
+ !isPositiveInteger(payload.boundarySequence) ||
123
+ !isSha256(payload.sourceProjectionHash) ||
124
+ !Array.isArray(payload.replacements) ||
125
+ payload.replacements.length === 0 ||
126
+ !isContextGcTrigger(payload.trigger) ||
127
+ !isContextGcEconomicsPolicy(payload.economics) ||
128
+ !isContextGcMetrics(payload.metrics))
129
+ return undefined;
130
+ const replacements = normalizeContextGcReplacements(payload.replacements);
131
+ if (!replacements || replacements.length !== payload.replacements.length)
132
+ return undefined;
133
+ return {
134
+ version: 1,
135
+ checkpointId: payload.checkpointId,
136
+ generation: payload.generation,
137
+ base: structuredClone(payload.base),
138
+ boundarySequence: payload.boundarySequence,
139
+ sourceProjectionHash: payload.sourceProjectionHash,
140
+ replacements,
141
+ trigger: structuredClone(payload.trigger),
142
+ economics: structuredClone(payload.economics),
143
+ metrics: structuredClone(payload.metrics)
144
+ };
145
+ }
146
+ export function validateContextGcCheckpoint(records, record, workspace = sessionWorkspace(records)) {
147
+ const payload = parseContextGcCheckpoint(record);
148
+ if (!payload || payload.boundarySequence >= record.sequence)
149
+ return undefined;
150
+ const base = contextGcBaseFromRecords(records, payload.boundarySequence);
151
+ if (!sameContextGcBase(payload.base, base))
152
+ return undefined;
153
+ const baseSequence = contextGcBaseSequence(payload.base);
154
+ if (contextGcSourceProjectionHash(records, payload.boundarySequence, payload.base) !==
155
+ payload.sourceProjectionHash)
156
+ return undefined;
157
+ const recordsBySequence = new Map(records.map((item) => [item.sequence, item]));
158
+ if (!triggerMatchesRecords(records, recordsBySequence, payload))
159
+ return undefined;
160
+ const targets = payload.replacements.flatMap((replacement) => [
161
+ replacement.target,
162
+ ...(replacement.kind === 'TOOL_CALL_INPUT' ? replacement.providerAliasTargets : [])
163
+ ]);
164
+ if (new Set(targets.map(contextGcTargetKey)).size !== targets.length)
165
+ return undefined;
166
+ for (const target of targets) {
167
+ const source = recordsBySequence.get(target.sequence);
168
+ if (!source ||
169
+ source.sequence > payload.boundarySequence ||
170
+ !targetMatchesRecord(target, source))
171
+ return undefined;
172
+ }
173
+ for (const replacement of payload.replacements) {
174
+ const evidence = replacement.kind === 'READ_OUTPUT_ITEMS'
175
+ ? replacement.evidenceSequences
176
+ : [
177
+ replacement.evidenceSequence,
178
+ ...(replacement.kind === 'SUBAGENT_OUTPUT' &&
179
+ replacement.retainedPriorFinal !== undefined
180
+ ? [replacement.retainedPriorFinal.evidenceSequence]
181
+ : [])
182
+ ];
183
+ if (evidence.some((sequence) => !isPositiveInteger(sequence) ||
184
+ sequence < baseSequence ||
185
+ sequence > payload.boundarySequence ||
186
+ !recordsBySequence.has(sequence)))
187
+ return undefined;
188
+ if (!replacementMatchesRecords(replacement, records, recordsBySequence, workspace, payload.trigger.platform))
189
+ return undefined;
190
+ }
191
+ return payload;
192
+ }
193
+ export function latestValidContextGcCheckpoint(records, boundarySequence = records.at(-1)?.sequence ?? 0, workspace = sessionWorkspace(records)) {
194
+ const base = contextGcBaseFromRecords(records, boundarySequence);
195
+ if (!base)
196
+ return undefined;
197
+ const candidates = records
198
+ .filter((record) => record.sequence <= boundarySequence &&
199
+ record.sequence >= contextGcBaseSequence(base) &&
200
+ record.type === 'context.gc.completed')
201
+ .toReversed();
202
+ for (const record of candidates) {
203
+ const payload = validateContextGcCheckpoint(records, record, workspace);
204
+ if (payload && sameContextGcBase(payload.base, base))
205
+ return { record, payload };
206
+ }
207
+ return undefined;
208
+ }
209
+ export function sameContextGcBase(left, right) {
210
+ if (!left || !right || left.type !== right.type)
211
+ return false;
212
+ return left.type === 'SESSION_START'
213
+ ? left.firstSequence ===
214
+ right.firstSequence
215
+ : left.sequence === right.sequence &&
216
+ left.recordId === right.recordId;
217
+ }
218
+ function targetMatchesRecord(target, record) {
219
+ if (record.type !== 'model.context' ||
220
+ record.recordId !== target.recordId ||
221
+ contextGcRecordSourceHash(record) !== target.sourceHash ||
222
+ !isRecord(record.payload) ||
223
+ record.payload.role !== target.role)
224
+ return false;
225
+ const messageCallId = modelContextCallId(record.payload);
226
+ const messageToolName = modelContextToolName(record.payload);
227
+ return ((target.callId === undefined || target.callId === messageCallId) &&
228
+ (target.toolName === undefined || target.toolName === messageToolName));
229
+ }
230
+ function replacementMatchesRecords(replacement, records, recordsBySequence, workspace, platform) {
231
+ const source = recordsBySequence.get(replacement.target.sequence);
232
+ if (!source || !isRecord(source.payload))
233
+ return false;
234
+ if (replacement.kind === 'READ_OUTPUT_ITEMS') {
235
+ if (!workspace || toolNameForCallId(records, replacement.callId, source.sequence) !== 'read')
236
+ return false;
237
+ const parsed = typeof source.payload.content === 'string'
238
+ ? parseReadContextOutput(source.payload.content)
239
+ : undefined;
240
+ if (!parsed)
241
+ return false;
242
+ const originalItems = new Map(parsed.items.map((item) => [item.index, item]));
243
+ return replacement.items.every((item) => {
244
+ const original = originalItems.get(item.index);
245
+ const evidence = successfulPatchEvidenceForPath(records, recordsBySequence, item.evidenceSequence, item.path, workspace, platform);
246
+ return (original?.path === item.path &&
247
+ evidence !== undefined &&
248
+ item.replacement ===
249
+ contextGcStaleReadReplacement({
250
+ path: item.path,
251
+ content: original.content,
252
+ evidenceSequence: item.evidenceSequence,
253
+ supersededByCallId: evidence.callId,
254
+ operation: evidence.file.operation
255
+ }));
256
+ });
257
+ }
258
+ if (replacement.kind === 'TOOL_CALL_INPUT' && replacement.toolName === 'apply_patch') {
259
+ const evidence = successfulToolEvidence(records, recordsBySequence, replacement.evidenceSequence, 'apply_patch');
260
+ const result = contextGcPatchResultFromCompletedPayload(evidence?.completed.payload);
261
+ return (evidence?.callId === replacement.callId &&
262
+ evidence.call.sequence === replacement.target.sequence &&
263
+ result !== undefined &&
264
+ isDeepStrictEqual(replacement.replacementArguments, contextGcApplyPatchInputReplacement(source.payload.arguments, result, replacement.evidenceSequence)));
265
+ }
266
+ if (replacement.kind === 'SUBAGENT_OUTPUT') {
267
+ const retainedPriorFinal = replacement.retainedPriorFinal;
268
+ const sourceEvidence = successfulToolEvidence(records, recordsBySequence, source.sequence, replacement.toolName);
269
+ const terminalEvidence = successfulToolEvidence(records, recordsBySequence, replacement.evidenceSequence, replacement.terminalToolName);
270
+ if (!sourceEvidence ||
271
+ sourceEvidence.callId !== replacement.callId ||
272
+ !terminalEvidence ||
273
+ terminalEvidence.callId !== replacement.terminalCallId ||
274
+ !isRecord(terminalEvidence.result.payload) ||
275
+ !isRecord(sourceEvidence.result.payload))
276
+ return false;
277
+ let retainedPriorFinalEvidence;
278
+ let retainedPriorFinalSnapshot;
279
+ if (retainedPriorFinal !== undefined) {
280
+ retainedPriorFinalEvidence = successfulToolEvidence(records, recordsBySequence, retainedPriorFinal.evidenceSequence, retainedPriorFinal.toolName);
281
+ if (!retainedPriorFinalEvidence ||
282
+ retainedPriorFinalEvidence.callId !== retainedPriorFinal.callId ||
283
+ !isRecord(retainedPriorFinalEvidence.result.payload))
284
+ return false;
285
+ retainedPriorFinalSnapshot = normalizeContextGcSubagentSnapshot(retainedPriorFinalEvidence.result.payload.content, retainedPriorFinalEvidence.completed.payload, retainedPriorFinal.toolName);
286
+ }
287
+ const sourceSnapshot = normalizeContextGcSubagentSnapshot(sourceEvidence.result.payload.content, sourceEvidence.completed.payload, replacement.toolName);
288
+ const terminalSnapshot = normalizeContextGcSubagentSnapshot(terminalEvidence.result.payload.content, terminalEvidence.completed.payload, replacement.terminalToolName);
289
+ return (sourceSnapshot !== undefined &&
290
+ terminalSnapshot !== undefined &&
291
+ contextGcSubagentNeedsRetainedPriorFinal(sourceSnapshot) ===
292
+ (retainedPriorFinal !== undefined) &&
293
+ (retainedPriorFinalEvidence === undefined ||
294
+ retainedPriorFinalEvidence.result.sequence < sourceEvidence.result.sequence) &&
295
+ sourceEvidence.result.sequence < terminalEvidence.result.sequence &&
296
+ contextGcSubagentSnapshotIsSuperseded(sourceSnapshot, terminalSnapshot, retainedPriorFinalSnapshot) &&
297
+ replacement.replacementContent ===
298
+ contextGcSubagentOutputReplacement({
299
+ sourceContent: sourceEvidence.result.payload.content,
300
+ source: sourceSnapshot,
301
+ terminal: terminalSnapshot,
302
+ terminalCallId: replacement.terminalCallId,
303
+ evidenceSequence: replacement.evidenceSequence
304
+ }));
305
+ }
306
+ if (!isSuccessfulExecLifecycleEvidence(replacement, source, records, recordsBySequence))
307
+ return false;
308
+ if (replacement.kind === 'TOOL_CALL_INPUT')
309
+ return isDeepStrictEqual(replacement.replacementArguments, contextGcExecInputReplacement(source.payload.arguments));
310
+ const targetEvidence = successfulToolEvidence(records, recordsBySequence, source.sequence, 'exec');
311
+ const result = normalizeContextGcExecResult(source.payload.content, targetEvidence?.completed.payload);
312
+ return (result !== undefined &&
313
+ replacement.replacementContent === contextGcExecOutputReplacement(result));
314
+ }
315
+ function toolNameForCallId(records, callId, beforeSequence) {
316
+ const call = modelToolCallForCallId(records, callId, beforeSequence);
317
+ return call && isRecord(call.payload) && typeof call.payload.name === 'string'
318
+ ? call.payload.name
319
+ : undefined;
320
+ }
321
+ function successfulToolEvidence(records, recordsBySequence, evidenceSequence, toolName) {
322
+ const result = recordsBySequence.get(evidenceSequence);
323
+ if (result?.type !== 'model.context' ||
324
+ !isRecord(result.payload) ||
325
+ result.payload.role !== 'tool' ||
326
+ typeof result.payload.callId !== 'string')
327
+ return undefined;
328
+ const callId = result.payload.callId;
329
+ const call = modelToolCallForCallId(records, callId, result.sequence);
330
+ if (!call || !isRecord(call.payload) || call.payload.name !== toolName)
331
+ return undefined;
332
+ const completed = records.findLast((record) => record.sequence > call.sequence &&
333
+ record.sequence < result.sequence &&
334
+ record.type === 'tool.completed' &&
335
+ isRecord(record.payload) &&
336
+ record.payload.type === 'tool.completed' &&
337
+ record.payload.callId === callId &&
338
+ record.payload.toolName === toolName);
339
+ return completed ? { callId, call, completed, result } : undefined;
340
+ }
341
+ function modelToolCallForCallId(records, callId, beforeSequence) {
342
+ return records.findLast((record) => record.sequence < beforeSequence &&
343
+ record.type === 'model.context' &&
344
+ isRecord(record.payload) &&
345
+ record.payload.role === 'tool_call' &&
346
+ record.payload.callId === callId);
347
+ }
348
+ function modelToolResultForCall(records, call, beforeSequence) {
349
+ if (!isRecord(call.payload) || typeof call.payload.callId !== 'string')
350
+ return undefined;
351
+ const callId = call.payload.callId;
352
+ return records.find((record) => record.sequence > call.sequence &&
353
+ record.sequence <= beforeSequence &&
354
+ record.type === 'model.context' &&
355
+ isRecord(record.payload) &&
356
+ record.payload.role === 'tool' &&
357
+ record.payload.callId === callId);
358
+ }
359
+ function successfulPatchEvidenceForPath(records, recordsBySequence, evidenceSequence, path, workspace, platform) {
360
+ const evidence = successfulToolEvidence(records, recordsBySequence, evidenceSequence, 'apply_patch');
361
+ if (!evidence || !isRecord(evidence.completed.payload))
362
+ return undefined;
363
+ const result = contextGcPatchResultFromCompletedPayload(evidence.completed.payload);
364
+ if (!result)
365
+ return undefined;
366
+ const expected = contextGcLogicalPathKey(path, workspace, platform);
367
+ if (!expected)
368
+ return undefined;
369
+ const file = result.files.find((file) => file.operation !== 'added' &&
370
+ contextGcLogicalPathKey(file.path, workspace, platform) === expected);
371
+ return file && file.operation !== 'added'
372
+ ? { callId: evidence.callId, file: { operation: file.operation } }
373
+ : undefined;
374
+ }
375
+ function isSuccessfulExecLifecycleEvidence(replacement, source, records, recordsBySequence) {
376
+ const evidence = successfulToolEvidence(records, recordsBySequence, replacement.evidenceSequence, 'exec');
377
+ if (!evidence || !isRecord(evidence.call.payload) || !isRecord(evidence.result.payload))
378
+ return false;
379
+ const finalResult = normalizeContextGcExecResult(evidence.result.payload.content, evidence.completed.payload);
380
+ if (!finalResult || finalResult.status === 'running')
381
+ return false;
382
+ const targetCall = replacement.kind === 'TOOL_CALL_INPUT'
383
+ ? source
384
+ : modelToolCallForCallId(records, replacement.callId, source.sequence);
385
+ if (!targetCall ||
386
+ targetCall.sequence > evidence.call.sequence ||
387
+ !isRecord(targetCall.payload) ||
388
+ targetCall.payload.role !== 'tool_call' ||
389
+ targetCall.payload.name !== 'exec' ||
390
+ targetCall.payload.callId !== replacement.callId)
391
+ return false;
392
+ const targetResult = replacement.kind === 'EXEC_OUTPUT'
393
+ ? source
394
+ : modelToolResultForCall(records, targetCall, evidence.result.sequence);
395
+ if (!targetResult)
396
+ return false;
397
+ const targetEvidence = successfulToolEvidence(records, recordsBySequence, targetResult.sequence, 'exec');
398
+ if (!targetEvidence || targetEvidence.call.sequence !== targetCall.sequence)
399
+ return false;
400
+ if (targetEvidence.callId === evidence.callId)
401
+ return targetEvidence.call.sequence === evidence.call.sequence;
402
+ const evidenceInput = evidence.call.payload.arguments;
403
+ const targetInput = targetCall.payload.arguments;
404
+ if (!isRecord(evidenceInput) || !isRecord(targetInput))
405
+ return false;
406
+ const evidenceProcessId = evidenceInput.processId;
407
+ const targetOutput = isRecord(targetResult.payload) && targetEvidence
408
+ ? normalizeContextGcExecResult(targetResult.payload.content, targetEvidence.completed.payload)
409
+ : undefined;
410
+ const targetProcessId = typeof targetInput.processId === 'string'
411
+ ? targetInput.processId
412
+ : typeof targetOutput?.processId === 'string'
413
+ ? targetOutput.processId
414
+ : undefined;
415
+ return (typeof evidenceProcessId === 'string' &&
416
+ targetProcessId === evidenceProcessId &&
417
+ targetResult.sequence <= evidence.result.sequence);
418
+ }
419
+ function triggerMatchesRecords(records, recordsBySequence, payload) {
420
+ if (payload.trigger.usageSequence < contextGcBaseSequence(payload.base) ||
421
+ payload.trigger.usageSequence > payload.boundarySequence)
422
+ return false;
423
+ const usageRecord = recordsBySequence.get(payload.trigger.usageSequence);
424
+ if (!usageRecord ||
425
+ !isRecord(usageRecord.payload) ||
426
+ usageRecord.payload.type !== 'usage.updated' ||
427
+ modelContextUsage(usageRecord.payload) !== payload.trigger.contextInputTokens)
428
+ return false;
429
+ const baseSequence = contextGcBaseSequence(payload.base);
430
+ let modelId;
431
+ let contextWindowTokens;
432
+ let triggerConfigurationMatches = false;
433
+ let latestMatchingUsageSequence;
434
+ let normalRolloutOrdinal = 0;
435
+ for (const record of records) {
436
+ if (record.sequence < baseSequence)
437
+ continue;
438
+ if (record.sequence > payload.boundarySequence)
439
+ break;
440
+ if ((record.type === 'execution.header' || record.type === 'compact.completed') &&
441
+ isRecord(record.payload)) {
442
+ if (typeof record.payload.modelId === 'string')
443
+ modelId = record.payload.modelId;
444
+ if (isPositiveInteger(record.payload.contextWindowTokens))
445
+ contextWindowTokens = record.payload.contextWindowTokens;
446
+ }
447
+ const matchingConfiguration = modelId === payload.trigger.modelId &&
448
+ contextWindowTokens === payload.trigger.contextWindowTokens;
449
+ if (record.sequence === usageRecord.sequence)
450
+ triggerConfigurationMatches = matchingConfiguration;
451
+ if (matchingConfiguration &&
452
+ isRecord(record.payload) &&
453
+ record.payload.type === 'usage.updated' &&
454
+ modelContextUsage(record.payload) !== undefined)
455
+ latestMatchingUsageSequence = record.sequence;
456
+ if (matchingConfiguration &&
457
+ record.type === 'model.attempt' &&
458
+ isRecord(record.payload) &&
459
+ record.payload.purpose === 'EXECUTION' &&
460
+ record.payload.state === 'SUCCEEDED')
461
+ normalRolloutOrdinal++;
462
+ }
463
+ return (triggerConfigurationMatches &&
464
+ latestMatchingUsageSequence === payload.trigger.usageSequence &&
465
+ normalRolloutOrdinal === payload.trigger.normalRolloutOrdinal);
466
+ }
467
+ function modelContextUsage(value) {
468
+ const context = value.contextInputTokens ?? value.inputTokens;
469
+ return isNonnegativeInteger(context) ? context : undefined;
470
+ }
471
+ function sessionWorkspace(records) {
472
+ const created = records.find((record) => record.type === 'session.created' && isRecord(record.payload));
473
+ return created && isRecord(created.payload) && isNonemptyString(created.payload.workspace)
474
+ ? created.payload.workspace
475
+ : undefined;
476
+ }
477
+ function modelContextCallId(payload) {
478
+ if (typeof payload.callId === 'string')
479
+ return payload.callId;
480
+ if (payload.role !== 'provider' || !isRecord(payload.item))
481
+ return undefined;
482
+ const value = payload.item.call_id;
483
+ return typeof value === 'string' ? value : undefined;
484
+ }
485
+ function modelContextToolName(payload) {
486
+ if (payload.role === 'tool_call' && typeof payload.name === 'string')
487
+ return payload.name;
488
+ if (payload.role !== 'provider' || !isRecord(payload.item))
489
+ return undefined;
490
+ const value = payload.item.name;
491
+ return typeof value === 'string' ? value : undefined;
492
+ }
493
+ function isContextGcReplacement(value) {
494
+ if (!isRecord(value) ||
495
+ !isContextGcTarget(value.target) ||
496
+ !isNonemptyString(value.callId) ||
497
+ value.target.callId !== value.callId)
498
+ return false;
499
+ if (value.kind === 'READ_OUTPUT_ITEMS') {
500
+ const items = value.items;
501
+ const evidenceSequences = value.evidenceSequences;
502
+ return (value.target.role === 'tool' &&
503
+ Array.isArray(items) &&
504
+ items.length > 0 &&
505
+ items.every((item) => isRecord(item) &&
506
+ isNonnegativeInteger(item.index) &&
507
+ isNonemptyString(item.path) &&
508
+ isNonemptyString(item.replacement) &&
509
+ isPositiveInteger(item.evidenceSequence)) &&
510
+ Array.isArray(evidenceSequences) &&
511
+ evidenceSequences.length > 0 &&
512
+ evidenceSequences.every(isPositiveInteger) &&
513
+ new Set(items.map((item) => item.index)).size === items.length &&
514
+ new Set(evidenceSequences).size === evidenceSequences.length &&
515
+ items.every((item) => evidenceSequences.includes(item.evidenceSequence)) &&
516
+ evidenceSequences.every((sequence) => items.some((item) => item.evidenceSequence === sequence)));
517
+ }
518
+ if (value.kind === 'TOOL_CALL_INPUT')
519
+ return (value.target.role === 'tool_call' &&
520
+ (value.toolName === 'apply_patch' || value.toolName === 'exec') &&
521
+ value.target.toolName === value.toolName &&
522
+ Array.isArray(value.providerAliasTargets) &&
523
+ value.providerAliasTargets.every((target) => isContextGcTarget(target) &&
524
+ target.role === 'provider' &&
525
+ target.callId === value.callId &&
526
+ target.toolName === value.toolName) &&
527
+ isPositiveInteger(value.evidenceSequence) &&
528
+ value.replacementArguments !== undefined);
529
+ if (value.kind === 'SUBAGENT_OUTPUT')
530
+ return (value.target.role === 'tool' &&
531
+ (value.toolName === 'agent_wait' || value.toolName === 'agent_message') &&
532
+ (value.target.toolName === undefined || value.target.toolName === value.toolName) &&
533
+ isNonemptyString(value.replacementContent) &&
534
+ (value.terminalToolName === 'agent_start' ||
535
+ value.terminalToolName === 'agent_wait' ||
536
+ value.terminalToolName === 'agent_message' ||
537
+ value.terminalToolName === 'agent_cancel') &&
538
+ isNonemptyString(value.terminalCallId) &&
539
+ isPositiveInteger(value.evidenceSequence) &&
540
+ (value.retainedPriorFinal === undefined ||
541
+ (isRecord(value.retainedPriorFinal) &&
542
+ Object.keys(value.retainedPriorFinal).every((key) => ['toolName', 'callId', 'evidenceSequence'].includes(key)) &&
543
+ (value.retainedPriorFinal.toolName === 'agent_start' ||
544
+ value.retainedPriorFinal.toolName === 'agent_wait' ||
545
+ value.retainedPriorFinal.toolName === 'agent_message' ||
546
+ value.retainedPriorFinal.toolName === 'agent_cancel') &&
547
+ isNonemptyString(value.retainedPriorFinal.callId) &&
548
+ isPositiveInteger(value.retainedPriorFinal.evidenceSequence))));
549
+ return (value.kind === 'EXEC_OUTPUT' &&
550
+ value.target.role === 'tool' &&
551
+ isNonemptyString(value.replacementContent) &&
552
+ isPositiveInteger(value.evidenceSequence));
553
+ }
554
+ function isContextGcTarget(value) {
555
+ return (isRecord(value) &&
556
+ isPositiveInteger(value.sequence) &&
557
+ isNonemptyString(value.recordId) &&
558
+ (value.role === 'tool_call' || value.role === 'tool' || value.role === 'provider') &&
559
+ (value.callId === undefined || isNonemptyString(value.callId)) &&
560
+ (value.toolName === undefined || isNonemptyString(value.toolName)) &&
561
+ isSha256(value.sourceHash));
562
+ }
563
+ function isContextGcBase(value) {
564
+ return (isRecord(value) &&
565
+ ((value.type === 'SESSION_START' && isPositiveInteger(value.firstSequence)) ||
566
+ (value.type === 'COMPACT' &&
567
+ isPositiveInteger(value.sequence) &&
568
+ isNonemptyString(value.recordId))));
569
+ }
570
+ function isContextGcTrigger(value) {
571
+ return (isRecord(value) &&
572
+ isPositiveInteger(value.usageSequence) &&
573
+ isNonnegativeInteger(value.contextInputTokens) &&
574
+ isPositiveInteger(value.contextWindowTokens) &&
575
+ isNonnegativeInteger(value.normalRolloutOrdinal) &&
576
+ isNonemptyString(value.modelId) &&
577
+ (value.platform === 'linux' || value.platform === 'darwin' || value.platform === 'win32'));
578
+ }
579
+ function isContextGcEconomicsPolicy(value) {
580
+ return (isRecord(value) &&
581
+ value.version === 1 &&
582
+ [
583
+ 'immediatePaybackRollouts',
584
+ 'maximumPaybackRollouts',
585
+ 'contextGrowthSampleWindow',
586
+ 'minimumContextGrowthSamples',
587
+ 'minimumObservationRollouts',
588
+ 'stageAProtectionRollouts',
589
+ 'largeExecProtectionRollouts'
590
+ ].every((key) => isNonnegativeInteger(value[key])) &&
591
+ [
592
+ 'normalInputCostRate',
593
+ 'cacheReadCostRate',
594
+ 'cacheWriteCostRate',
595
+ 'outputCostRate',
596
+ 'minimumGrossReductionRate',
597
+ 'minimumCacheInvestmentRoi'
598
+ ].every((key) => isNonnegativeFinite(value[key])));
599
+ }
600
+ function isContextGcMetrics(value) {
601
+ if (!isRecord(value) || (value.stage !== 'STAGE_A' && value.stage !== 'STAGE_A_AND_EXEC'))
602
+ return false;
603
+ const nonnegative = [
604
+ 'beforeTokens',
605
+ 'afterTokens',
606
+ 'reclaimedTokens',
607
+ 'grossReductionRate',
608
+ 'cacheRebuildPenaltyCostUnits',
609
+ 'compactDeferralCreditCostUnits',
610
+ 'requiredPositiveNetRollouts',
611
+ 'requiredTargetRoiRollouts',
612
+ 'projectedRolloutsUntilCompactAfterGc',
613
+ 'contextGrowthSampleCount',
614
+ 'contextGrowthP75Tokens',
615
+ 'minimumObservedRollouts',
616
+ 'protectedCandidateTokens',
617
+ 'eligibleCandidateCount',
618
+ 'eligibleTargetCount'
619
+ ];
620
+ const optionalNonnegative = [
621
+ 'effectiveMinimumGrossReductionRate',
622
+ 'minimumRequiredReclaimedTokens',
623
+ 'imminentCompactAvoidanceCreditCostUnits',
624
+ 'appliedCompactCreditCostUnits',
625
+ 'projectedTokensBeforeGc',
626
+ 'projectedTokensAfterGc'
627
+ ];
628
+ return (nonnegative.every((key) => isNonnegativeFinite(value[key])) &&
629
+ optionalNonnegative.every((key) => value[key] === undefined || isNonnegativeFinite(value[key])) &&
630
+ Number.isFinite(value.expectedNetSavedCostUnits) &&
631
+ Number.isFinite(value.cacheInvestmentRoi) &&
632
+ (value.tokenEstimator === undefined || value.tokenEstimator === 'UTF8_BYTES_V1') &&
633
+ (value.cachePenaltyKnown === undefined || typeof value.cachePenaltyKnown === 'boolean'));
634
+ }
635
+ function isRecord(value) {
636
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
637
+ }
638
+ function isNonemptyString(value) {
639
+ return typeof value === 'string' && value.length > 0;
640
+ }
641
+ function isSha256(value) {
642
+ return typeof value === 'string' && /^[a-f0-9]{64}$/u.test(value);
643
+ }
644
+ function isPositiveInteger(value) {
645
+ return Number.isSafeInteger(value) && Number(value) > 0;
646
+ }
647
+ function isNonnegativeInteger(value) {
648
+ return Number.isSafeInteger(value) && Number(value) >= 0;
649
+ }
650
+ function isNonnegativeFinite(value) {
651
+ return typeof value === 'number' && Number.isFinite(value) && value >= 0;
652
+ }
653
+ function isValidBoundary(value) {
654
+ return Number.isSafeInteger(value) && value > 0;
655
+ }
656
+ function stableJson(value) {
657
+ if (Array.isArray(value))
658
+ return `[${value.map(stableJson).join(',')}]`;
659
+ if (value !== null && typeof value === 'object')
660
+ return `{${Object.entries(value)
661
+ .sort(([left], [right]) => left.localeCompare(right))
662
+ .map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`)
663
+ .join(',')}}`;
664
+ return JSON.stringify(value) ?? 'undefined';
665
+ }