@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.
- package/LICENSE +202 -0
- package/NOTICE +4 -0
- package/dist/cli/codex-auth-file.js +268 -3
- package/dist/cli/main.js +427 -2
- package/dist/error.js +66 -2
- package/dist/host/contracts.js +20 -2
- package/dist/host/local-agent-host.js +146 -2
- package/dist/host/local-process-executor.js +39 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +12 -2
- package/dist/model/anthropic-messages.js +474 -2
- package/dist/model/anthropic-thinking.js +33 -2
- package/dist/model/catalog-file.js +88 -2
- package/dist/model/configuration.js +137 -2
- package/dist/model/contracts.d.ts +2 -0
- package/dist/model/contracts.js +1 -2
- package/dist/model/http.js +529 -2
- package/dist/model/openai-responses.d.ts +2 -0
- package/dist/model/openai-responses.js +1602 -2
- package/dist/model/runtime-credential.js +35 -2
- package/dist/model/sse.js +199 -2
- package/dist/prompts/compact.js +25 -2
- package/dist/prompts/core.js +37 -2
- package/dist/prompts/execution-budget.js +10 -2
- package/dist/prompts/index.d.ts +3 -2
- package/dist/prompts/index.js +47 -2
- package/dist/prompts/modes.js +25 -2
- package/dist/prompts/output.js +1 -2
- package/dist/prompts/resources.d.ts +1 -1
- package/dist/prompts/resources.js +31 -2
- package/dist/prompts/subagent.d.ts +6 -0
- package/dist/prompts/subagent.js +29 -2
- package/dist/prompts/title.js +9 -2
- package/dist/prompts/workflow.js +32 -2
- package/dist/runtime/async-queue.js +62 -2
- package/dist/runtime/builtin-skills.js +19 -2
- package/dist/runtime/byted-ark-imagegen-skill.js +18 -2
- package/dist/runtime/codex-imagegen-skill.js +35 -2
- package/dist/runtime/compact.js +225 -2
- package/dist/runtime/context-gc-runtime.d.ts +35 -0
- package/dist/runtime/context-gc-runtime.js +163 -0
- package/dist/runtime/context-gc-tokens.d.ts +24 -0
- package/dist/runtime/context-gc-tokens.js +83 -0
- package/dist/runtime/context-gc.d.ts +66 -0
- package/dist/runtime/context-gc.js +909 -0
- package/dist/runtime/context-projection.d.ts +23 -0
- package/dist/runtime/context-projection.js +203 -0
- package/dist/runtime/environment-context.js +41 -2
- package/dist/runtime/execution-policy.js +13 -2
- package/dist/runtime/instructions.js +298 -2
- package/dist/runtime/normalize.js +40 -2
- package/dist/runtime/plan-output.js +95 -2
- package/dist/runtime/rollout-budget.d.ts +2 -0
- package/dist/runtime/rollout-budget.js +92 -2
- package/dist/runtime/token-budget.d.ts +2 -0
- package/dist/runtime/token-budget.js +44 -2
- package/dist/sdk/agent.js +1804 -2
- package/dist/sdk/types.d.ts +15 -5
- package/dist/sdk/types.js +1 -2
- package/dist/session/catalog.d.ts +5 -4
- package/dist/session/catalog.js +133 -2
- package/dist/session/context-gc-checkpoint.d.ts +148 -0
- package/dist/session/context-gc-checkpoint.js +665 -0
- package/dist/session/context-gc-replacements.d.ts +52 -0
- package/dist/session/context-gc-replacements.js +226 -0
- package/dist/session/context-gc-subagent.d.ts +43 -0
- package/dist/session/context-gc-subagent.js +267 -0
- package/dist/session/jsonl-store.d.ts +42 -4
- package/dist/session/jsonl-store.js +1657 -2
- package/dist/subagent/scheduler.d.ts +35 -2
- package/dist/subagent/scheduler.js +249 -2
- package/dist/subagent/session-controller.d.ts +94 -0
- package/dist/subagent/session-controller.js +675 -0
- package/dist/tools/agent-cancel.js +28 -2
- package/dist/tools/{task.d.ts → agent-message.d.ts} +2 -2
- package/dist/tools/agent-message.js +51 -0
- package/dist/tools/agent-start.js +84 -2
- package/dist/tools/agent-wait.js +53 -2
- package/dist/tools/apply-patch.js +478 -2
- package/dist/tools/code-mode.js +370 -2
- package/dist/tools/codex-image-gen.js +312 -2
- package/dist/tools/exec.js +455 -2
- package/dist/tools/execution-limits.d.ts +1 -0
- package/dist/tools/execution-limits.js +44 -2
- package/dist/tools/local-registry.js +233 -2
- package/dist/tools/local-workspace-tools.js +28 -2
- package/dist/tools/question.js +124 -2
- package/dist/tools/read-context.d.ts +16 -0
- package/dist/tools/read-context.js +85 -0
- package/dist/tools/read.d.ts +13 -0
- package/dist/tools/read.js +294 -2
- package/dist/tools/registry.js +76 -2
- package/dist/tools/runtime-context.d.ts +9 -2
- package/dist/tools/runtime-context.js +1 -2
- package/dist/tools/runtime.js +21 -2
- package/dist/tools/scheduler.js +41 -2
- package/dist/tools/shared/path-resolver.js +133 -2
- package/dist/tools/skill.js +37 -2
- package/dist/tools/todo-read.js +10 -2
- package/dist/tools/todo-write.js +65 -2
- package/dist/tools/todo.js +67 -2
- package/dist/tools/view-image.js +81 -2
- package/dist/tools/web-fetch.js +11 -2
- package/dist/tools/web-search.js +14 -2
- package/package.json +9 -7
- package/README.md +0 -3
- package/dist/runtime/prompt.d.ts +0 -9
- package/dist/runtime/prompt.js +0 -2
- package/dist/tools/shared/secret-redaction.d.ts +0 -4
- package/dist/tools/shared/secret-redaction.js +0 -2
- package/dist/tools/task-cancel.d.ts +0 -7
- package/dist/tools/task-cancel.js +0 -2
- package/dist/tools/task-output.d.ts +0 -7
- package/dist/tools/task-output.js +0 -2
- package/dist/tools/task-tools.d.ts +0 -36
- package/dist/tools/task-tools.js +0 -2
- package/dist/tools/task.js +0 -2
- package/dist/tools/todo-tools.d.ts +0 -25
- 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
|
+
}
|