dsh-context-compression-improved 0.1.1
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 +21 -0
- package/README.md +26 -0
- package/README.zh.md +26 -0
- package/THIRD_PARTY_NOTICES.md +38 -0
- package/assets/deepseek-v4/LICENSE.DeepSeek-V4-Pro.txt +21 -0
- package/assets/deepseek-v4/manifest.json +23 -0
- package/assets/deepseek-v4/tokenizer.json +267359 -0
- package/assets/deepseek-v4/tokenizer_config.json +34 -0
- package/assets/deepseek-v4-vision-exp/LICENSE.DeepSeek-V4-Flash-Vision-Exp.txt +21 -0
- package/assets/deepseek-v4-vision-exp/manifest.json +22 -0
- package/assets/deepseek-v4-vision-exp/tokenizer.json +267359 -0
- package/assets/deepseek-v4-vision-exp/tokenizer_config.json +34 -0
- package/assets/screenshots/context-compression-selector-profiles.jpg +0 -0
- package/assets/screenshots/context-compression-selector-settings.png +0 -0
- package/cordis.patch.yml +19 -0
- package/dsh.plugin.json +16 -0
- package/lib/client.d.ts +229 -0
- package/lib/client.js +1462 -0
- package/lib/config.js +842 -0
- package/lib/index.d.ts +38 -0
- package/lib/index.js +645 -0
- package/lib/invariant.d.ts +10 -0
- package/lib/invariant.js +70 -0
- package/lib/pruner.d.ts +684 -0
- package/lib/pruner.js +3807 -0
- package/lib/tail-trim.js +136 -0
- package/package.json +115 -0
- package/screenshots.json +6 -0
package/lib/config.js
ADDED
|
@@ -0,0 +1,842 @@
|
|
|
1
|
+
import z from "@deepseek-ai/schemastery";
|
|
2
|
+
//#region src/runtime/types.ts
|
|
3
|
+
/** User-facing mixed strategy profile. */
|
|
4
|
+
const COMPRESSION_PROFILES = [
|
|
5
|
+
"off",
|
|
6
|
+
"native",
|
|
7
|
+
"balanced",
|
|
8
|
+
"cache-strict",
|
|
9
|
+
"savings",
|
|
10
|
+
"adaptive",
|
|
11
|
+
"tokenpilot-inspired",
|
|
12
|
+
"custom"
|
|
13
|
+
];
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/runtime/value.ts
|
|
16
|
+
/** Version-neutral immutable-value and closed-union helpers for the plugin runtime. */
|
|
17
|
+
/**
|
|
18
|
+
* Freeze an object graph in place without relying on a Harness utility export.
|
|
19
|
+
* Live AbortSignals remain mutable so request cancellation continues to work.
|
|
20
|
+
* @param value - Value to freeze recursively.
|
|
21
|
+
* @returns The same deeply frozen value.
|
|
22
|
+
*/
|
|
23
|
+
function deepFreeze(value) {
|
|
24
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
25
|
+
const pending = [{
|
|
26
|
+
kind: "visit",
|
|
27
|
+
node: value
|
|
28
|
+
}];
|
|
29
|
+
while (pending.length > 0) {
|
|
30
|
+
const task = pending.pop();
|
|
31
|
+
/* v8 ignore next -- the loop condition guarantees one pending task. */
|
|
32
|
+
if (task === void 0) continue;
|
|
33
|
+
if (task.kind === "property") {
|
|
34
|
+
pending.push({
|
|
35
|
+
kind: "visit",
|
|
36
|
+
node: task.source[task.key]
|
|
37
|
+
});
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const node = task.node;
|
|
41
|
+
if (node === null || typeof node !== "object" || node instanceof AbortSignal || seen.has(node)) continue;
|
|
42
|
+
seen.add(node);
|
|
43
|
+
Object.freeze(node);
|
|
44
|
+
const keys = Object.keys(node);
|
|
45
|
+
for (let index = keys.length - 1; index >= 0; index--) {
|
|
46
|
+
const key = keys[index];
|
|
47
|
+
/* v8 ignore next -- the loop is bounded by the captured key count. */
|
|
48
|
+
if (key === void 0) continue;
|
|
49
|
+
pending.push({
|
|
50
|
+
kind: "property",
|
|
51
|
+
source: node,
|
|
52
|
+
key
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Throw for an impossible member of a closed discriminated union.
|
|
60
|
+
* @param value - Value that escaped its closed union type.
|
|
61
|
+
* @param context - Optional switch-site label.
|
|
62
|
+
* @returns Never returns.
|
|
63
|
+
*/
|
|
64
|
+
function assertNever(value, context) {
|
|
65
|
+
const rendered = JSON.stringify(value) ?? String(value);
|
|
66
|
+
throw new Error(`unreachable variant${context === void 0 ? "" : ` in ${context}`}: ${rendered}`);
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/runtime/custom-policy.ts
|
|
70
|
+
/** Strict versioned Custom policy parsing and effective-token resolution. */
|
|
71
|
+
const budgetSchema = z.object({
|
|
72
|
+
enabled: z.boolean().required(),
|
|
73
|
+
trigger: z.number().required(),
|
|
74
|
+
target: z.number().required()
|
|
75
|
+
}).required();
|
|
76
|
+
const legacyHistorySchema = z.object({
|
|
77
|
+
enabled: z.boolean().required(),
|
|
78
|
+
trigger: z.number().required(),
|
|
79
|
+
keepRecentTurns: z.number().step(1).min(0).required(),
|
|
80
|
+
keepRecent: z.number().required(),
|
|
81
|
+
minReclaim: z.number().required()
|
|
82
|
+
}).required();
|
|
83
|
+
const historySchema = z.object({
|
|
84
|
+
enabled: z.boolean().required(),
|
|
85
|
+
trigger: z.number().required(),
|
|
86
|
+
keepRecentToolCalls: z.number().step(1).min(0).required(),
|
|
87
|
+
keepRecentTokens: z.number().required(),
|
|
88
|
+
minReclaim: z.number().required()
|
|
89
|
+
}).required();
|
|
90
|
+
const tailTrimSchema = z.object({
|
|
91
|
+
enabled: z.boolean().required(),
|
|
92
|
+
trigger: z.number().required()
|
|
93
|
+
}).required();
|
|
94
|
+
const customCompressionPolicyV1InputSchema = z.object({
|
|
95
|
+
version: z.const(1).required(),
|
|
96
|
+
unit: z.union(["tokens", "context-percent"]).required(),
|
|
97
|
+
fresh: budgetSchema,
|
|
98
|
+
aggregate: budgetSchema,
|
|
99
|
+
history: legacyHistorySchema,
|
|
100
|
+
prefixPolicy: z.union(["preserve", "pressure-break"]).required()
|
|
101
|
+
}).required();
|
|
102
|
+
const customCompressionPolicyV2InputSchema = z.object({
|
|
103
|
+
version: z.const(2).required(),
|
|
104
|
+
unit: z.union(["tokens", "context-percent"]).required(),
|
|
105
|
+
fresh: budgetSchema,
|
|
106
|
+
aggregate: budgetSchema,
|
|
107
|
+
history: legacyHistorySchema,
|
|
108
|
+
prefixPolicy: z.union(["preserve", "pressure-break"]).required(),
|
|
109
|
+
tailTrim: tailTrimSchema
|
|
110
|
+
}).required();
|
|
111
|
+
const customCompressionPolicyV3InputSchema = z.object({
|
|
112
|
+
version: z.const(3).required(),
|
|
113
|
+
unit: z.union(["tokens", "context-percent"]).required(),
|
|
114
|
+
fresh: budgetSchema,
|
|
115
|
+
aggregate: budgetSchema,
|
|
116
|
+
history: historySchema,
|
|
117
|
+
prefixPolicy: z.union(["preserve", "pressure-break"]).required(),
|
|
118
|
+
tailTrim: tailTrimSchema
|
|
119
|
+
}).required();
|
|
120
|
+
/** Canonical Custom document accepted by Host settings and the runtime resolver. */
|
|
121
|
+
const CustomCompressionPolicySchema = z.transform(z.any().required(), (value) => {
|
|
122
|
+
assertExactPolicyShape(value);
|
|
123
|
+
const canonical = canonicalizeCustomPolicy(value.version === 1 ? customCompressionPolicyV1InputSchema(value) : value.version === 2 ? customCompressionPolicyV2InputSchema(value) : customCompressionPolicyV3InputSchema(value));
|
|
124
|
+
assertCanonicalRelations(canonical);
|
|
125
|
+
return deepFreeze(structuredClone(canonical));
|
|
126
|
+
});
|
|
127
|
+
/** Balanced-equivalent Custom policy stored as one token-canonical document. */
|
|
128
|
+
const DEFAULT_CUSTOM_COMPRESSION_POLICY = deepFreeze({
|
|
129
|
+
version: 3,
|
|
130
|
+
unit: "tokens",
|
|
131
|
+
fresh: {
|
|
132
|
+
enabled: true,
|
|
133
|
+
trigger: 8192,
|
|
134
|
+
target: 3072
|
|
135
|
+
},
|
|
136
|
+
aggregate: {
|
|
137
|
+
enabled: true,
|
|
138
|
+
trigger: 32768,
|
|
139
|
+
target: 12288
|
|
140
|
+
},
|
|
141
|
+
history: {
|
|
142
|
+
enabled: true,
|
|
143
|
+
trigger: 5e5,
|
|
144
|
+
keepRecentToolCalls: 10,
|
|
145
|
+
keepRecentTokens: 64e3,
|
|
146
|
+
minReclaim: 96e3
|
|
147
|
+
},
|
|
148
|
+
prefixPolicy: "pressure-break",
|
|
149
|
+
tailTrim: {
|
|
150
|
+
enabled: false,
|
|
151
|
+
trigger: 7e5
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
/**
|
|
155
|
+
* Resolve one validated Custom document to the same token policy used by public presets.
|
|
156
|
+
* @param value - untrusted or typed Custom settings value.
|
|
157
|
+
* @param options - routed model capacity for context-percent documents.
|
|
158
|
+
* @returns a detached deeply immutable effective token policy.
|
|
159
|
+
*/
|
|
160
|
+
function resolveCustomPolicy(value, options = {}) {
|
|
161
|
+
const policy = canonicalizeCustomPolicy(CustomCompressionPolicySchema(value));
|
|
162
|
+
const effective = (name, amount) => {
|
|
163
|
+
if (policy.unit === "tokens") return amount;
|
|
164
|
+
const contextWindow = options.contextWindowTokens;
|
|
165
|
+
if (!Number.isSafeInteger(contextWindow) || contextWindow === void 0 || contextWindow <= 0) throw new Error("Custom context-percent policy requires a resolved positive model context window");
|
|
166
|
+
const tokens = Math.floor(contextWindow * amount / 100);
|
|
167
|
+
if (!Number.isSafeInteger(tokens) || amount > 0 && tokens <= 0) throw new Error(`Custom ${name} has no valid effective token value for this model`);
|
|
168
|
+
return tokens;
|
|
169
|
+
};
|
|
170
|
+
const resolved = {
|
|
171
|
+
profile: "custom",
|
|
172
|
+
nativeToolResultEnabled: false,
|
|
173
|
+
freshEnabled: policy.fresh.enabled,
|
|
174
|
+
aggregateEnabled: policy.aggregate.enabled,
|
|
175
|
+
historyMode: !policy.history.enabled ? "disabled" : policy.prefixPolicy === "preserve" ? "capacity-pressure" : "routine",
|
|
176
|
+
nativeTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
177
|
+
nativeTargetTokens: Number.MAX_SAFE_INTEGER,
|
|
178
|
+
freshTriggerTokens: effective("Fresh trigger", policy.fresh.trigger),
|
|
179
|
+
freshTargetTokens: effective("Fresh target", policy.fresh.target),
|
|
180
|
+
aggregateTriggerTokens: effective("Aggregate trigger", policy.aggregate.trigger),
|
|
181
|
+
aggregateTargetTokens: effective("Aggregate target", policy.aggregate.target),
|
|
182
|
+
historyTriggerTokens: effective("History trigger", policy.history.trigger),
|
|
183
|
+
historyKeepRecentToolCalls: policy.history.keepRecentToolCalls,
|
|
184
|
+
historyKeepRecentTokens: effective("History recent token tail", policy.history.keepRecentTokens),
|
|
185
|
+
historyMinReclaimTokens: effective("History min-reclaim", policy.history.minReclaim),
|
|
186
|
+
tailTrim: {
|
|
187
|
+
enabled: policy.tailTrim.enabled,
|
|
188
|
+
triggerTokens: effective("TailTrim trigger", policy.tailTrim.trigger)
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
assertEffectiveRelations(resolved);
|
|
192
|
+
return deepFreeze(resolved);
|
|
193
|
+
}
|
|
194
|
+
function canonicalizeCustomPolicy(policy) {
|
|
195
|
+
if (policy.version === 3) return policy;
|
|
196
|
+
return {
|
|
197
|
+
version: 3,
|
|
198
|
+
unit: policy.unit,
|
|
199
|
+
fresh: policy.fresh,
|
|
200
|
+
aggregate: policy.aggregate,
|
|
201
|
+
history: {
|
|
202
|
+
enabled: policy.history.enabled,
|
|
203
|
+
trigger: policy.history.trigger,
|
|
204
|
+
keepRecentToolCalls: 10,
|
|
205
|
+
keepRecentTokens: policy.history.keepRecent,
|
|
206
|
+
minReclaim: policy.history.minReclaim
|
|
207
|
+
},
|
|
208
|
+
prefixPolicy: policy.prefixPolicy,
|
|
209
|
+
tailTrim: policy.version === 1 ? {
|
|
210
|
+
enabled: false,
|
|
211
|
+
trigger: 7e5
|
|
212
|
+
} : policy.tailTrim
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function measuredValues(policy) {
|
|
216
|
+
return [
|
|
217
|
+
policy.fresh.trigger,
|
|
218
|
+
policy.fresh.target,
|
|
219
|
+
policy.aggregate.trigger,
|
|
220
|
+
policy.aggregate.target,
|
|
221
|
+
policy.history.trigger,
|
|
222
|
+
policy.history.keepRecentTokens,
|
|
223
|
+
policy.history.minReclaim,
|
|
224
|
+
policy.tailTrim.trigger
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
function validMeasuredValues(policy) {
|
|
228
|
+
const values = measuredValues(policy);
|
|
229
|
+
if (![
|
|
230
|
+
policy.fresh.trigger,
|
|
231
|
+
policy.fresh.target,
|
|
232
|
+
policy.aggregate.trigger,
|
|
233
|
+
policy.aggregate.target,
|
|
234
|
+
policy.history.trigger,
|
|
235
|
+
policy.history.minReclaim,
|
|
236
|
+
policy.tailTrim.trigger
|
|
237
|
+
].every((value) => value > 0) || policy.history.keepRecentTokens < 0 || !Number.isSafeInteger(policy.history.keepRecentToolCalls) || policy.history.keepRecentToolCalls < 0) return false;
|
|
238
|
+
return policy.unit === "tokens" ? values.every(Number.isSafeInteger) : values.every((value) => Number.isFinite(value) && value <= 100);
|
|
239
|
+
}
|
|
240
|
+
function assertCanonicalRelations(policy) {
|
|
241
|
+
if (!validMeasuredValues(policy)) throw new TypeError("Custom measured values must use the selected canonical unit");
|
|
242
|
+
if (policy.fresh.target >= policy.fresh.trigger) throw new TypeError("Custom Fresh target must be below trigger");
|
|
243
|
+
if (policy.aggregate.target >= policy.aggregate.trigger) throw new TypeError("Custom Aggregate target must be below trigger");
|
|
244
|
+
if (policy.history.minReclaim > policy.history.trigger) throw new TypeError("Custom History min-reclaim must not exceed its trigger");
|
|
245
|
+
}
|
|
246
|
+
function assertExactPolicyShape(value) {
|
|
247
|
+
if (!isPlainRecord$1(value)) throw new TypeError("Custom must be a plain object");
|
|
248
|
+
if (value.version !== 1 && value.version !== 2 && value.version !== 3) throw new TypeError("Custom version must be 1, 2, or 3");
|
|
249
|
+
assertExactKeys(value, value.version === 1 ? [
|
|
250
|
+
"version",
|
|
251
|
+
"unit",
|
|
252
|
+
"fresh",
|
|
253
|
+
"aggregate",
|
|
254
|
+
"history",
|
|
255
|
+
"prefixPolicy"
|
|
256
|
+
] : [
|
|
257
|
+
"version",
|
|
258
|
+
"unit",
|
|
259
|
+
"fresh",
|
|
260
|
+
"aggregate",
|
|
261
|
+
"history",
|
|
262
|
+
"prefixPolicy",
|
|
263
|
+
"tailTrim"
|
|
264
|
+
], "Custom");
|
|
265
|
+
assertExactKeys(value.fresh, [
|
|
266
|
+
"enabled",
|
|
267
|
+
"trigger",
|
|
268
|
+
"target"
|
|
269
|
+
], "Custom Fresh");
|
|
270
|
+
assertExactKeys(value.aggregate, [
|
|
271
|
+
"enabled",
|
|
272
|
+
"trigger",
|
|
273
|
+
"target"
|
|
274
|
+
], "Custom Aggregate");
|
|
275
|
+
assertExactKeys(value.history, value.version === 3 ? [
|
|
276
|
+
"enabled",
|
|
277
|
+
"trigger",
|
|
278
|
+
"keepRecentToolCalls",
|
|
279
|
+
"keepRecentTokens",
|
|
280
|
+
"minReclaim"
|
|
281
|
+
] : [
|
|
282
|
+
"enabled",
|
|
283
|
+
"trigger",
|
|
284
|
+
"keepRecentTurns",
|
|
285
|
+
"keepRecent",
|
|
286
|
+
"minReclaim"
|
|
287
|
+
], "Custom History");
|
|
288
|
+
if (value.version !== 1) assertExactKeys(value.tailTrim, ["enabled", "trigger"], "Custom TailTrim");
|
|
289
|
+
}
|
|
290
|
+
function assertExactKeys(value, allowed, label) {
|
|
291
|
+
if (!isPlainRecord$1(value)) throw new TypeError(`${label} must be a plain object`);
|
|
292
|
+
const allowedKeys = new Set(allowed);
|
|
293
|
+
const unknown = Object.keys(value).find((key) => !allowedKeys.has(key));
|
|
294
|
+
if (unknown !== void 0) throw new TypeError(`${label}: unknown key "${unknown}"`);
|
|
295
|
+
}
|
|
296
|
+
function isPlainRecord$1(value) {
|
|
297
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
298
|
+
const prototype = Object.getPrototypeOf(value);
|
|
299
|
+
return prototype === Object.prototype || prototype === null;
|
|
300
|
+
}
|
|
301
|
+
function assertEffectiveRelations(policy) {
|
|
302
|
+
if (policy.freshTargetTokens >= policy.freshTriggerTokens) throw new Error("Custom effective Fresh target must be below trigger");
|
|
303
|
+
if (policy.aggregateTargetTokens >= policy.aggregateTriggerTokens) throw new Error("Custom effective Aggregate target must be below trigger");
|
|
304
|
+
if (policy.historyMinReclaimTokens > policy.historyTriggerTokens) throw new Error("Custom effective History min-reclaim must not exceed its trigger");
|
|
305
|
+
}
|
|
306
|
+
//#endregion
|
|
307
|
+
//#region src/runtime/config.ts
|
|
308
|
+
/** Configuration resolution for the mixed deterministic context-compression selector. */
|
|
309
|
+
/** Settings namespace shared by the Host service and browser selector. */
|
|
310
|
+
const CONTEXT_COMPRESSION_SETTINGS_NAMESPACE = "context-compression";
|
|
311
|
+
/** Fixed native fallback marker. */
|
|
312
|
+
const PRUNE_MARKER = "\n\n[... tool result middle pruned ...]\n\n";
|
|
313
|
+
/**
|
|
314
|
+
* The one Auto Compact threshold contract shared by the settings UI, the
|
|
315
|
+
* persisted settings schema, and the runtime resolver. Every integer in the
|
|
316
|
+
* range is valid and entered directly in the UI.
|
|
317
|
+
*/
|
|
318
|
+
const AUTO_COMPACT_THRESHOLD_LIMITS = deepFreeze({
|
|
319
|
+
min: 50,
|
|
320
|
+
max: 90,
|
|
321
|
+
step: 1,
|
|
322
|
+
default: 80
|
|
323
|
+
});
|
|
324
|
+
/** Narrow one untrusted value to a valid Auto Compact threshold percent. */
|
|
325
|
+
function isValidAutoCompactThresholdPercent(value) {
|
|
326
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= AUTO_COMPACT_THRESHOLD_LIMITS.min && value <= AUTO_COMPACT_THRESHOLD_LIMITS.max;
|
|
327
|
+
}
|
|
328
|
+
const AUTO_COMPACT_DEFAULT = deepFreeze({ thresholdPercent: AUTO_COMPACT_THRESHOLD_LIMITS.default });
|
|
329
|
+
/** Accept JSON-object records while rejecting class instances and exotic prototypes. */
|
|
330
|
+
function isPlainRecord(value) {
|
|
331
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
332
|
+
const prototype = Object.getPrototypeOf(value);
|
|
333
|
+
return prototype === Object.prototype || prototype === null;
|
|
334
|
+
}
|
|
335
|
+
/** Reject exotic prototypes anywhere in the JSON-like settings tree. */
|
|
336
|
+
function assertPlainDataTree(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
337
|
+
if (value === null || typeof value !== "object") return;
|
|
338
|
+
if (seen.has(value)) return;
|
|
339
|
+
seen.add(value);
|
|
340
|
+
if (Array.isArray(value)) {
|
|
341
|
+
for (const entry of value) assertPlainDataTree(entry, seen);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (!isPlainRecord(value)) throw new TypeError("Context-compression settings must contain only plain objects");
|
|
345
|
+
for (const entry of Object.values(value)) assertPlainDataTree(entry, seen);
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Strictly parse the persisted autoCompact section. Schemastery object
|
|
349
|
+
* defaults silently absorb null, empty, and extra-key sections, so this stays
|
|
350
|
+
* hand-validated beside the top-level unknown-key check.
|
|
351
|
+
*/
|
|
352
|
+
function parseAutoCompactSettings(value) {
|
|
353
|
+
if (value === void 0) return AUTO_COMPACT_DEFAULT;
|
|
354
|
+
if (!isPlainRecord(value)) throw new TypeError("Context-compression autoCompact must be a plain object");
|
|
355
|
+
const keys = Object.keys(value);
|
|
356
|
+
if (keys.length !== 1 || keys[0] !== "thresholdPercent") throw new TypeError(`Context-compression autoCompact: expected exactly "thresholdPercent", got "${keys.join("\", \"")}"`);
|
|
357
|
+
const thresholdPercent = value.thresholdPercent;
|
|
358
|
+
if (!isValidAutoCompactThresholdPercent(thresholdPercent)) throw new TypeError(`Context-compression autoCompact.thresholdPercent (${String(thresholdPercent)}) must be an integer between ${String(AUTO_COMPACT_THRESHOLD_LIMITS.min)} and ${String(AUTO_COMPACT_THRESHOLD_LIMITS.max)}`);
|
|
359
|
+
return { thresholdPercent };
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Strictly parse the persisted codeSkeleton section. The gate is orthogonal
|
|
363
|
+
* to every profile: absent inherits the lossless `false` default, while a
|
|
364
|
+
* present-but-invalid section is an explicitly invalid document.
|
|
365
|
+
*/
|
|
366
|
+
function parseCodeSkeletonSettings(value) {
|
|
367
|
+
if (value === void 0) return { enabled: false };
|
|
368
|
+
if (!isPlainRecord(value)) throw new TypeError("Context-compression codeSkeleton must be a plain object");
|
|
369
|
+
const keys = Object.keys(value);
|
|
370
|
+
if (keys.length !== 1 || keys[0] !== "enabled") throw new TypeError(`Context-compression codeSkeleton: expected exactly "enabled", got "${keys.join("\", \"")}"`);
|
|
371
|
+
const enabled = value.enabled;
|
|
372
|
+
if (typeof enabled !== "boolean") throw new TypeError("Context-compression codeSkeleton.enabled must be a boolean");
|
|
373
|
+
return { enabled };
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Parse the optional tokenpilot-inspired preset sub-capability section. Absent
|
|
377
|
+
* inherits the preset defaults; present-but-invalid is rejected, mirroring the
|
|
378
|
+
* codeSkeleton section semantics.
|
|
379
|
+
*/
|
|
380
|
+
function parsePresetOptionsSettings(value) {
|
|
381
|
+
if (value === void 0) return void 0;
|
|
382
|
+
if (!isPlainRecord(value)) throw new TypeError("Context-compression presetOptions must be a plain object");
|
|
383
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
384
|
+
"dedupeToolResults",
|
|
385
|
+
"summaryLocator",
|
|
386
|
+
"prefixStabilizer",
|
|
387
|
+
"readState",
|
|
388
|
+
"estimatorMode",
|
|
389
|
+
"estimatorProvider",
|
|
390
|
+
"estimatorModel",
|
|
391
|
+
"estimatorBaseUrl",
|
|
392
|
+
"estimatorApiKey",
|
|
393
|
+
"estimatorTimeoutMs"
|
|
394
|
+
]);
|
|
395
|
+
const unknown = Object.keys(value).find((key) => !allowed.has(key));
|
|
396
|
+
if (unknown !== void 0) throw new TypeError(`Context-compression presetOptions: unknown key "${unknown}"`);
|
|
397
|
+
for (const key of [
|
|
398
|
+
"dedupeToolResults",
|
|
399
|
+
"summaryLocator",
|
|
400
|
+
"prefixStabilizer",
|
|
401
|
+
"readState"
|
|
402
|
+
]) {
|
|
403
|
+
const entry = value[key];
|
|
404
|
+
if (entry !== void 0 && typeof entry !== "boolean") throw new TypeError(`Context-compression presetOptions.${key} must be a boolean`);
|
|
405
|
+
}
|
|
406
|
+
const estimatorMode = value.estimatorMode;
|
|
407
|
+
if (estimatorMode !== void 0 && estimatorMode !== "" && estimatorMode !== "host" && estimatorMode !== "direct") throw new TypeError("Context-compression presetOptions.estimatorMode must be \"\", \"host\", or \"direct\"");
|
|
408
|
+
const estimatorTimeoutMs = value.estimatorTimeoutMs;
|
|
409
|
+
if (estimatorTimeoutMs !== void 0 && (typeof estimatorTimeoutMs !== "number" || !Number.isSafeInteger(estimatorTimeoutMs) || estimatorTimeoutMs < 100 || estimatorTimeoutMs > 6e4)) throw new TypeError("Context-compression presetOptions.estimatorTimeoutMs must be an integer between 100 and 60000");
|
|
410
|
+
for (const key of [
|
|
411
|
+
"estimatorProvider",
|
|
412
|
+
"estimatorModel",
|
|
413
|
+
"estimatorBaseUrl",
|
|
414
|
+
"estimatorApiKey"
|
|
415
|
+
]) {
|
|
416
|
+
const entry = value[key];
|
|
417
|
+
if (entry !== void 0 && typeof entry !== "string") throw new TypeError(`Context-compression presetOptions.${key} must be a string`);
|
|
418
|
+
}
|
|
419
|
+
const result = {};
|
|
420
|
+
if (value.dedupeToolResults !== void 0) result.dedupeToolResults = value.dedupeToolResults;
|
|
421
|
+
if (value.summaryLocator !== void 0) result.summaryLocator = value.summaryLocator;
|
|
422
|
+
if (value.prefixStabilizer !== void 0) result.prefixStabilizer = value.prefixStabilizer;
|
|
423
|
+
if (value.readState !== void 0) result.readState = value.readState;
|
|
424
|
+
if (estimatorMode !== void 0) result.estimatorMode = estimatorMode;
|
|
425
|
+
if (value.estimatorProvider !== void 0) result.estimatorProvider = value.estimatorProvider;
|
|
426
|
+
if (value.estimatorModel !== void 0) result.estimatorModel = value.estimatorModel;
|
|
427
|
+
if (value.estimatorBaseUrl !== void 0) result.estimatorBaseUrl = value.estimatorBaseUrl;
|
|
428
|
+
if (value.estimatorApiKey !== void 0) result.estimatorApiKey = value.estimatorApiKey;
|
|
429
|
+
if (estimatorTimeoutMs !== void 0) result.estimatorTimeoutMs = estimatorTimeoutMs;
|
|
430
|
+
return result;
|
|
431
|
+
}
|
|
432
|
+
/** Settings schema used by the user-facing profile selector. */
|
|
433
|
+
const contextCompressionSettingsInputSchema = z.object({
|
|
434
|
+
profile: z.union([...COMPRESSION_PROFILES]).default("balanced"),
|
|
435
|
+
custom: CustomCompressionPolicySchema.default(DEFAULT_CUSTOM_COMPRESSION_POLICY)
|
|
436
|
+
});
|
|
437
|
+
/**
|
|
438
|
+
* Reject a section that is PRESENT but not a usable value. Schemastery
|
|
439
|
+
* `.default(...)` silently substitutes null and undefined, which would turn a
|
|
440
|
+
* hand-corrupted store into the (lossy) default policy; only genuinely absent
|
|
441
|
+
* keys may inherit defaults, and that distinction must be made before any
|
|
442
|
+
* default can fire.
|
|
443
|
+
*/
|
|
444
|
+
function assertPresentSection(candidate, key, valid) {
|
|
445
|
+
if (!Object.hasOwn(candidate, key)) return;
|
|
446
|
+
if (!valid(candidate[key])) throw new TypeError(`Context-compression settings: "${key}" is present but invalid (${String(candidate[key])})`);
|
|
447
|
+
}
|
|
448
|
+
const isSupportedProfile = (value) => typeof value === "string" && COMPRESSION_PROFILES.includes(value);
|
|
449
|
+
const isUsableCustomDocument = (value) => isPlainRecord(value);
|
|
450
|
+
const DEFAULT_CONTEXT_COMPRESSION_SETTINGS = {
|
|
451
|
+
profile: "balanced",
|
|
452
|
+
custom: structuredClone(DEFAULT_CUSTOM_COMPRESSION_POLICY),
|
|
453
|
+
autoCompact: { thresholdPercent: AUTO_COMPACT_THRESHOLD_LIMITS.default },
|
|
454
|
+
codeSkeleton: { enabled: false }
|
|
455
|
+
};
|
|
456
|
+
/**
|
|
457
|
+
* Parse one settings document with the persisted-section semantics: `undefined`
|
|
458
|
+
* inherits the defaults (an absent section), while `null` is an explicitly
|
|
459
|
+
* invalid document and must never silently become the default policy.
|
|
460
|
+
*/
|
|
461
|
+
function parseContextCompressionSettings(value) {
|
|
462
|
+
if (!isPlainRecord(value)) throw new TypeError("Context-compression settings must be a plain object");
|
|
463
|
+
const keys = Object.keys(value);
|
|
464
|
+
if (keys.length === 0 || !keys.includes("profile") || !keys.includes("custom")) throw new TypeError("Context-compression settings document is missing its complete shape");
|
|
465
|
+
return ContextCompressionSettingsSchema(value);
|
|
466
|
+
}
|
|
467
|
+
/** Settings schema used by the user-facing profile selector. */
|
|
468
|
+
const ContextCompressionSettingsSchema = z.transform(z.any().required(), (value) => {
|
|
469
|
+
if (!isPlainRecord(value)) throw new TypeError("Context-compression settings must be a plain object");
|
|
470
|
+
assertPlainDataTree(value);
|
|
471
|
+
const candidate = structuredClone(value);
|
|
472
|
+
const unknown = Object.keys(candidate).find((key) => key !== "profile" && key !== "custom" && key !== "autoCompact" && key !== "codeSkeleton" && key !== "presetOptions");
|
|
473
|
+
if (unknown !== void 0) throw new TypeError(`Context-compression settings: unknown key "${unknown}"`);
|
|
474
|
+
assertPresentSection(candidate, "profile", isSupportedProfile);
|
|
475
|
+
assertPresentSection(candidate, "custom", isUsableCustomDocument);
|
|
476
|
+
const autoCompact = parseAutoCompactSettings(candidate.autoCompact);
|
|
477
|
+
const codeSkeleton = parseCodeSkeletonSettings(candidate.codeSkeleton);
|
|
478
|
+
const presetOptions = parsePresetOptionsSettings(candidate.presetOptions);
|
|
479
|
+
return {
|
|
480
|
+
...contextCompressionSettingsInputSchema(candidate),
|
|
481
|
+
autoCompact,
|
|
482
|
+
codeSkeleton,
|
|
483
|
+
...presetOptions === void 0 ? {} : { presetOptions }
|
|
484
|
+
};
|
|
485
|
+
}).default(DEFAULT_CONTEXT_COMPRESSION_SETTINGS);
|
|
486
|
+
/** Low-friction defaults; token budgets live in resolved profile policy. */
|
|
487
|
+
const DEFAULTS = deepFreeze({
|
|
488
|
+
profile: "balanced",
|
|
489
|
+
headChars: 4096,
|
|
490
|
+
tailChars: 1024
|
|
491
|
+
});
|
|
492
|
+
const CONFIG_KEYS = /* @__PURE__ */ new Set([
|
|
493
|
+
"profile",
|
|
494
|
+
"headChars",
|
|
495
|
+
"tailChars",
|
|
496
|
+
"nativeTriggerTokens",
|
|
497
|
+
"nativeTargetTokens",
|
|
498
|
+
"freshTriggerTokens",
|
|
499
|
+
"freshTargetTokens",
|
|
500
|
+
"aggregateTriggerTokens",
|
|
501
|
+
"aggregateTargetTokens",
|
|
502
|
+
"historyTriggerTokens",
|
|
503
|
+
"historyKeepRecentToolCalls",
|
|
504
|
+
"historyKeepRecentTokens",
|
|
505
|
+
"historyMinReclaimTokens",
|
|
506
|
+
"autoCompactThresholdPercent",
|
|
507
|
+
"presetOptions"
|
|
508
|
+
]);
|
|
509
|
+
const LEGACY_GATE_REPLACEMENTS = Object.freeze({
|
|
510
|
+
thresholdChars: "nativeTriggerTokens",
|
|
511
|
+
freshThresholdChars: "freshTriggerTokens",
|
|
512
|
+
freshTargetChars: "freshTargetTokens",
|
|
513
|
+
freshBatchTriggerChars: "aggregateTriggerTokens",
|
|
514
|
+
freshBatchTargetChars: "aggregateTargetTokens",
|
|
515
|
+
historyTriggerChars: "historyTriggerTokens",
|
|
516
|
+
historyKeepRecentChars: "historyKeepRecentTokens",
|
|
517
|
+
historyMinReclaimChars: "historyMinReclaimTokens",
|
|
518
|
+
historyKeepRecentTurns: "historyKeepRecentToolCalls"
|
|
519
|
+
});
|
|
520
|
+
/**
|
|
521
|
+
* Count Unicode code points without splitting surrogate pairs.
|
|
522
|
+
* @param text - text whose code points are counted.
|
|
523
|
+
* @returns the number of Unicode code points.
|
|
524
|
+
*/
|
|
525
|
+
function codePointLength(text) {
|
|
526
|
+
let length = 0;
|
|
527
|
+
for (const _point of text) length++;
|
|
528
|
+
return length;
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Test whether a settings value names a supported compression profile.
|
|
532
|
+
* @param value - untrusted settings value.
|
|
533
|
+
* @returns whether the value is a supported compression profile.
|
|
534
|
+
*/
|
|
535
|
+
function isCompressionProfile(value) {
|
|
536
|
+
return typeof value === "string" && COMPRESSION_PROFILES.includes(value);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Resolve and validate plugin configuration.
|
|
540
|
+
* @param config - optional composition overrides.
|
|
541
|
+
* @returns a detached, deeply immutable configuration snapshot.
|
|
542
|
+
*/
|
|
543
|
+
function resolveConfig(config = {}) {
|
|
544
|
+
for (const key of Object.keys(config)) {
|
|
545
|
+
const replacement = LEGACY_GATE_REPLACEMENTS[key];
|
|
546
|
+
if (replacement !== void 0) throw new Error(`ToolResultPruneConfig: legacy gate "${key}" is no longer accepted; choose "${replacement}" manually in tokens (no character conversion is applied)`);
|
|
547
|
+
if (!CONFIG_KEYS.has(key)) throw new Error(`ToolResultPruneConfig: unknown key "${key}"`);
|
|
548
|
+
}
|
|
549
|
+
const resolved = {
|
|
550
|
+
profile: config.profile ?? DEFAULTS.profile,
|
|
551
|
+
headChars: config.headChars ?? DEFAULTS.headChars,
|
|
552
|
+
tailChars: config.tailChars ?? DEFAULTS.tailChars,
|
|
553
|
+
...config.nativeTriggerTokens === void 0 ? {} : { nativeTriggerTokens: config.nativeTriggerTokens },
|
|
554
|
+
...config.nativeTargetTokens === void 0 ? {} : { nativeTargetTokens: config.nativeTargetTokens },
|
|
555
|
+
...config.freshTriggerTokens === void 0 ? {} : { freshTriggerTokens: config.freshTriggerTokens },
|
|
556
|
+
...config.freshTargetTokens === void 0 ? {} : { freshTargetTokens: config.freshTargetTokens },
|
|
557
|
+
...config.aggregateTriggerTokens === void 0 ? {} : { aggregateTriggerTokens: config.aggregateTriggerTokens },
|
|
558
|
+
...config.aggregateTargetTokens === void 0 ? {} : { aggregateTargetTokens: config.aggregateTargetTokens },
|
|
559
|
+
...config.historyTriggerTokens === void 0 ? {} : { historyTriggerTokens: config.historyTriggerTokens },
|
|
560
|
+
...config.historyKeepRecentToolCalls === void 0 ? {} : { historyKeepRecentToolCalls: config.historyKeepRecentToolCalls },
|
|
561
|
+
...config.historyKeepRecentTokens === void 0 ? {} : { historyKeepRecentTokens: config.historyKeepRecentTokens },
|
|
562
|
+
...config.historyMinReclaimTokens === void 0 ? {} : { historyMinReclaimTokens: config.historyMinReclaimTokens },
|
|
563
|
+
...config.autoCompactThresholdPercent === void 0 ? {} : { autoCompactThresholdPercent: config.autoCompactThresholdPercent },
|
|
564
|
+
...config.presetOptions === void 0 ? {} : { presetOptions: config.presetOptions }
|
|
565
|
+
};
|
|
566
|
+
if (!isCompressionProfile(resolved.profile)) throw new Error(`ToolResultPruneConfig: unsupported profile "${String(resolved.profile)}"`);
|
|
567
|
+
assertNonNegativeInteger("headChars", resolved.headChars);
|
|
568
|
+
assertNonNegativeInteger("tailChars", resolved.tailChars);
|
|
569
|
+
for (const key of [
|
|
570
|
+
"nativeTriggerTokens",
|
|
571
|
+
"nativeTargetTokens",
|
|
572
|
+
"freshTriggerTokens",
|
|
573
|
+
"freshTargetTokens",
|
|
574
|
+
"aggregateTriggerTokens",
|
|
575
|
+
"aggregateTargetTokens",
|
|
576
|
+
"historyTriggerTokens",
|
|
577
|
+
"historyMinReclaimTokens"
|
|
578
|
+
]) {
|
|
579
|
+
const value = resolved[key];
|
|
580
|
+
if (value !== void 0) assertPositiveInteger(key, value);
|
|
581
|
+
}
|
|
582
|
+
if (resolved.historyKeepRecentToolCalls !== void 0) assertNonNegativeInteger("historyKeepRecentToolCalls", resolved.historyKeepRecentToolCalls);
|
|
583
|
+
if (resolved.historyKeepRecentTokens !== void 0) assertNonNegativeInteger("historyKeepRecentTokens", resolved.historyKeepRecentTokens);
|
|
584
|
+
if (resolved.autoCompactThresholdPercent !== void 0 && !isValidAutoCompactThresholdPercent(resolved.autoCompactThresholdPercent)) throw new Error(`ToolResultPruneConfig: autoCompactThresholdPercent (${String(resolved.autoCompactThresholdPercent)}) must be an integer between ${String(AUTO_COMPACT_THRESHOLD_LIMITS.min)} and ${String(AUTO_COMPACT_THRESHOLD_LIMITS.max)}`);
|
|
585
|
+
assertTargetBelowTrigger("native", resolved.nativeTargetTokens, resolved.nativeTriggerTokens);
|
|
586
|
+
assertTargetBelowTrigger("fresh", resolved.freshTargetTokens, resolved.freshTriggerTokens);
|
|
587
|
+
assertTargetBelowTrigger("aggregate", resolved.aggregateTargetTokens, resolved.aggregateTriggerTokens);
|
|
588
|
+
return deepFreeze(structuredClone(resolved));
|
|
589
|
+
}
|
|
590
|
+
/** Per-profile History linkage ratios applied to the Auto Compact watermark. */
|
|
591
|
+
const AUTO_COMPACT_HISTORY_RATIOS = Object.freeze({
|
|
592
|
+
balanced: Object.freeze({
|
|
593
|
+
trigger: .625,
|
|
594
|
+
minReclaim: .12,
|
|
595
|
+
keepRecentTokens: .08
|
|
596
|
+
}),
|
|
597
|
+
savings: Object.freeze({
|
|
598
|
+
trigger: .5,
|
|
599
|
+
minReclaim: .16,
|
|
600
|
+
keepRecentTokens: .08
|
|
601
|
+
}),
|
|
602
|
+
"cache-strict": Object.freeze({
|
|
603
|
+
trigger: .75,
|
|
604
|
+
minReclaim: .16,
|
|
605
|
+
keepRecentTokens: .08
|
|
606
|
+
}),
|
|
607
|
+
adaptive: Object.freeze({
|
|
608
|
+
trigger: .625,
|
|
609
|
+
minReclaim: .12,
|
|
610
|
+
keepRecentTokens: .08
|
|
611
|
+
}),
|
|
612
|
+
"tokenpilot-inspired": Object.freeze({
|
|
613
|
+
trigger: .625,
|
|
614
|
+
minReclaim: .12,
|
|
615
|
+
keepRecentTokens: .08
|
|
616
|
+
})
|
|
617
|
+
});
|
|
618
|
+
/** Micro-compact last-chance ratio: `D = floor(A × 0.875)`. */
|
|
619
|
+
const MICRO_DEADLINE_RATIO = .875;
|
|
620
|
+
/**
|
|
621
|
+
* TokenPilot-inspired sub-capability defaults. Every capability is on except
|
|
622
|
+
* the estimator, which requires an explicit endpoint channel (host or direct)
|
|
623
|
+
* before any consumer may leave its rule-only fallback.
|
|
624
|
+
*/
|
|
625
|
+
const PRESET_OPTION_DEFAULTS = deepFreeze({
|
|
626
|
+
noNetSavingsGuard: true,
|
|
627
|
+
skipReductionRecovery: true,
|
|
628
|
+
dedupeToolResults: true,
|
|
629
|
+
summaryLocator: true,
|
|
630
|
+
prefixStabilizer: true,
|
|
631
|
+
readState: true,
|
|
632
|
+
estimator: { mode: "" }
|
|
633
|
+
});
|
|
634
|
+
/**
|
|
635
|
+
* Merge persisted presetOptions overrides over the tokenpilot-inspired
|
|
636
|
+
* defaults. Persisted booleans are three-state (undefined = inherit); the
|
|
637
|
+
* estimator channel overrides the default empty mode wholesale.
|
|
638
|
+
*/
|
|
639
|
+
function mergePresetOptions(overrides) {
|
|
640
|
+
if (overrides === void 0) return PRESET_OPTION_DEFAULTS;
|
|
641
|
+
return deepFreeze({
|
|
642
|
+
noNetSavingsGuard: true,
|
|
643
|
+
skipReductionRecovery: true,
|
|
644
|
+
dedupeToolResults: overrides.dedupeToolResults ?? PRESET_OPTION_DEFAULTS.dedupeToolResults,
|
|
645
|
+
summaryLocator: overrides.summaryLocator ?? PRESET_OPTION_DEFAULTS.summaryLocator,
|
|
646
|
+
prefixStabilizer: overrides.prefixStabilizer ?? PRESET_OPTION_DEFAULTS.prefixStabilizer,
|
|
647
|
+
readState: overrides.readState ?? PRESET_OPTION_DEFAULTS.readState,
|
|
648
|
+
estimator: { mode: overrides.estimatorMode ?? PRESET_OPTION_DEFAULTS.estimator.mode }
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Resolve the Auto-Compact-linked History watermarks for one standard profile.
|
|
653
|
+
*
|
|
654
|
+
* `A = floor(C × a)` is the Auto Compact token watermark for the routed
|
|
655
|
+
* context window `C` and the user threshold `a = p / 100`; the History
|
|
656
|
+
* trigger, minimum reclaim, and recent-token tail scale with `A`, and the
|
|
657
|
+
* micro-compact last-chance deadline is `D = floor(A × 0.875)`. At the shipped
|
|
658
|
+
* defaults (`C = 1,000,000`, `p = 80`) the ratios reproduce the previous fixed
|
|
659
|
+
* preset numbers exactly. Custom stays manual and Off/Native run no History,
|
|
660
|
+
* so none of them link.
|
|
661
|
+
*/
|
|
662
|
+
function resolveAutoCompactLinkage(profile, options) {
|
|
663
|
+
const ratios = profile === "custom" ? void 0 : AUTO_COMPACT_HISTORY_RATIOS[profile];
|
|
664
|
+
const contextWindow = options.contextWindowTokens;
|
|
665
|
+
const threshold = options.autoCompactThresholdPercent;
|
|
666
|
+
if (ratios === void 0) return void 0;
|
|
667
|
+
if (!isValidAutoCompactThresholdPercent(threshold)) return void 0;
|
|
668
|
+
if (!Number.isSafeInteger(contextWindow) || contextWindow === void 0 || contextWindow <= 0) return void 0;
|
|
669
|
+
const autoCompactTokens = Math.floor(contextWindow * (threshold / 100));
|
|
670
|
+
if (!Number.isSafeInteger(autoCompactTokens) || autoCompactTokens <= 0) return void 0;
|
|
671
|
+
const linked = {
|
|
672
|
+
autoCompactTokens,
|
|
673
|
+
microDeadlineTokens: Math.floor(autoCompactTokens * MICRO_DEADLINE_RATIO),
|
|
674
|
+
historyTriggerTokens: Math.floor(ratios.trigger * autoCompactTokens),
|
|
675
|
+
historyMinReclaimTokens: Math.floor(ratios.minReclaim * autoCompactTokens),
|
|
676
|
+
historyKeepRecentTokens: Math.floor(ratios.keepRecentTokens * autoCompactTokens)
|
|
677
|
+
};
|
|
678
|
+
for (const value of Object.values(linked)) if (!Number.isSafeInteger(value) || value <= 0) return void 0;
|
|
679
|
+
return linked;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Resolve one public profile into a complete mixed-strategy policy.
|
|
683
|
+
* @param config - validated composition configuration.
|
|
684
|
+
* @param profile - profile frozen for the target Session.
|
|
685
|
+
* @param custom - versioned Custom document used only by the `custom` profile.
|
|
686
|
+
* @param options - routed capacity and the frozen Auto Compact threshold used
|
|
687
|
+
* to resolve context-percent Custom values and standard-profile linkage.
|
|
688
|
+
* @returns the effective deterministic compression policy.
|
|
689
|
+
*/
|
|
690
|
+
function resolvePolicy(config, profile, custom = DEFAULT_CUSTOM_COMPRESSION_POLICY, options = {}) {
|
|
691
|
+
if (profile === "custom") return resolveCustomPolicy(custom, options);
|
|
692
|
+
const preset = {
|
|
693
|
+
off: {
|
|
694
|
+
nativeToolResultEnabled: false,
|
|
695
|
+
freshEnabled: false,
|
|
696
|
+
aggregateEnabled: false,
|
|
697
|
+
historyMode: "disabled",
|
|
698
|
+
nativeTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
699
|
+
nativeTargetTokens: Number.MAX_SAFE_INTEGER,
|
|
700
|
+
freshTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
701
|
+
freshTargetTokens: Number.MAX_SAFE_INTEGER,
|
|
702
|
+
aggregateTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
703
|
+
aggregateTargetTokens: Number.MAX_SAFE_INTEGER,
|
|
704
|
+
historyTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
705
|
+
historyKeepRecentToolCalls: 10,
|
|
706
|
+
historyKeepRecentTokens: 64e3,
|
|
707
|
+
historyMinReclaimTokens: Number.MAX_SAFE_INTEGER
|
|
708
|
+
},
|
|
709
|
+
native: {
|
|
710
|
+
nativeToolResultEnabled: true,
|
|
711
|
+
freshEnabled: false,
|
|
712
|
+
aggregateEnabled: false,
|
|
713
|
+
historyMode: "disabled",
|
|
714
|
+
nativeTriggerTokens: 4096,
|
|
715
|
+
nativeTargetTokens: 2048,
|
|
716
|
+
freshTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
717
|
+
freshTargetTokens: Number.MAX_SAFE_INTEGER,
|
|
718
|
+
aggregateTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
719
|
+
aggregateTargetTokens: Number.MAX_SAFE_INTEGER,
|
|
720
|
+
historyTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
721
|
+
historyKeepRecentToolCalls: 10,
|
|
722
|
+
historyKeepRecentTokens: 64e3,
|
|
723
|
+
historyMinReclaimTokens: Number.MAX_SAFE_INTEGER
|
|
724
|
+
},
|
|
725
|
+
balanced: {
|
|
726
|
+
nativeToolResultEnabled: false,
|
|
727
|
+
freshEnabled: true,
|
|
728
|
+
aggregateEnabled: true,
|
|
729
|
+
historyMode: "routine",
|
|
730
|
+
nativeTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
731
|
+
nativeTargetTokens: Number.MAX_SAFE_INTEGER,
|
|
732
|
+
freshTriggerTokens: 8192,
|
|
733
|
+
freshTargetTokens: 3072,
|
|
734
|
+
aggregateTriggerTokens: 32768,
|
|
735
|
+
aggregateTargetTokens: 12288,
|
|
736
|
+
historyTriggerTokens: 5e5,
|
|
737
|
+
historyKeepRecentToolCalls: 10,
|
|
738
|
+
historyKeepRecentTokens: 64e3,
|
|
739
|
+
historyMinReclaimTokens: 96e3
|
|
740
|
+
},
|
|
741
|
+
"cache-strict": {
|
|
742
|
+
nativeToolResultEnabled: false,
|
|
743
|
+
freshEnabled: true,
|
|
744
|
+
aggregateEnabled: true,
|
|
745
|
+
historyMode: "capacity-pressure",
|
|
746
|
+
nativeTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
747
|
+
nativeTargetTokens: Number.MAX_SAFE_INTEGER,
|
|
748
|
+
freshTriggerTokens: 8192,
|
|
749
|
+
freshTargetTokens: 3072,
|
|
750
|
+
aggregateTriggerTokens: 32768,
|
|
751
|
+
aggregateTargetTokens: 12288,
|
|
752
|
+
historyTriggerTokens: 6e5,
|
|
753
|
+
historyKeepRecentToolCalls: 10,
|
|
754
|
+
historyKeepRecentTokens: 64e3,
|
|
755
|
+
historyMinReclaimTokens: 128e3
|
|
756
|
+
},
|
|
757
|
+
savings: {
|
|
758
|
+
nativeToolResultEnabled: false,
|
|
759
|
+
freshEnabled: true,
|
|
760
|
+
aggregateEnabled: true,
|
|
761
|
+
historyMode: "routine",
|
|
762
|
+
nativeTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
763
|
+
nativeTargetTokens: Number.MAX_SAFE_INTEGER,
|
|
764
|
+
freshTriggerTokens: 4096,
|
|
765
|
+
freshTargetTokens: 1536,
|
|
766
|
+
aggregateTriggerTokens: 16384,
|
|
767
|
+
aggregateTargetTokens: 4096,
|
|
768
|
+
historyTriggerTokens: 4e5,
|
|
769
|
+
historyKeepRecentToolCalls: 10,
|
|
770
|
+
historyKeepRecentTokens: 64e3,
|
|
771
|
+
historyMinReclaimTokens: 128e3
|
|
772
|
+
},
|
|
773
|
+
adaptive: {
|
|
774
|
+
nativeToolResultEnabled: false,
|
|
775
|
+
freshEnabled: true,
|
|
776
|
+
aggregateEnabled: true,
|
|
777
|
+
historyMode: "adaptive",
|
|
778
|
+
nativeTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
779
|
+
nativeTargetTokens: Number.MAX_SAFE_INTEGER,
|
|
780
|
+
freshTriggerTokens: 8192,
|
|
781
|
+
freshTargetTokens: 3072,
|
|
782
|
+
aggregateTriggerTokens: 32768,
|
|
783
|
+
aggregateTargetTokens: 12288,
|
|
784
|
+
historyTriggerTokens: 5e5,
|
|
785
|
+
historyKeepRecentToolCalls: 10,
|
|
786
|
+
historyKeepRecentTokens: 64e3,
|
|
787
|
+
historyMinReclaimTokens: 96e3
|
|
788
|
+
},
|
|
789
|
+
"tokenpilot-inspired": {
|
|
790
|
+
nativeToolResultEnabled: false,
|
|
791
|
+
freshEnabled: true,
|
|
792
|
+
aggregateEnabled: true,
|
|
793
|
+
historyMode: "routine",
|
|
794
|
+
nativeTriggerTokens: Number.MAX_SAFE_INTEGER,
|
|
795
|
+
nativeTargetTokens: Number.MAX_SAFE_INTEGER,
|
|
796
|
+
freshTriggerTokens: 8192,
|
|
797
|
+
freshTargetTokens: 3072,
|
|
798
|
+
aggregateTriggerTokens: 32768,
|
|
799
|
+
aggregateTargetTokens: 12288,
|
|
800
|
+
historyTriggerTokens: 5e5,
|
|
801
|
+
historyKeepRecentToolCalls: 10,
|
|
802
|
+
historyKeepRecentTokens: 64e3,
|
|
803
|
+
historyMinReclaimTokens: 96e3
|
|
804
|
+
}
|
|
805
|
+
}[profile];
|
|
806
|
+
const linkage = resolveAutoCompactLinkage(profile, options);
|
|
807
|
+
const policy = {
|
|
808
|
+
profile,
|
|
809
|
+
...preset,
|
|
810
|
+
nativeTriggerTokens: config.nativeTriggerTokens ?? preset.nativeTriggerTokens,
|
|
811
|
+
nativeTargetTokens: config.nativeTargetTokens ?? preset.nativeTargetTokens,
|
|
812
|
+
freshTriggerTokens: config.freshTriggerTokens ?? preset.freshTriggerTokens,
|
|
813
|
+
freshTargetTokens: config.freshTargetTokens ?? preset.freshTargetTokens,
|
|
814
|
+
aggregateTriggerTokens: config.aggregateTriggerTokens ?? preset.aggregateTriggerTokens,
|
|
815
|
+
aggregateTargetTokens: config.aggregateTargetTokens ?? preset.aggregateTargetTokens,
|
|
816
|
+
historyTriggerTokens: config.historyTriggerTokens ?? linkage?.historyTriggerTokens ?? preset.historyTriggerTokens,
|
|
817
|
+
historyKeepRecentToolCalls: config.historyKeepRecentToolCalls ?? preset.historyKeepRecentToolCalls,
|
|
818
|
+
historyKeepRecentTokens: config.historyKeepRecentTokens ?? linkage?.historyKeepRecentTokens ?? preset.historyKeepRecentTokens,
|
|
819
|
+
historyMinReclaimTokens: config.historyMinReclaimTokens ?? linkage?.historyMinReclaimTokens ?? preset.historyMinReclaimTokens,
|
|
820
|
+
...linkage === void 0 ? {} : {
|
|
821
|
+
autoCompactTokens: linkage.autoCompactTokens,
|
|
822
|
+
microDeadlineTokens: linkage.microDeadlineTokens
|
|
823
|
+
},
|
|
824
|
+
...profile === "tokenpilot-inspired" ? { presetOptions: mergePresetOptions(config.presetOptions) } : {}
|
|
825
|
+
};
|
|
826
|
+
if (policy.nativeTargetTokens >= policy.nativeTriggerTokens && profile === "native") throw new Error("context compression policy: native target must be below trigger");
|
|
827
|
+
if (policy.freshTargetTokens >= policy.freshTriggerTokens && policy.freshEnabled) throw new Error("context compression policy: fresh target must be below trigger");
|
|
828
|
+
if (policy.aggregateTargetTokens >= policy.aggregateTriggerTokens && policy.freshEnabled) throw new Error("context compression policy: aggregate target must be below trigger");
|
|
829
|
+
return deepFreeze(policy);
|
|
830
|
+
}
|
|
831
|
+
function assertTargetBelowTrigger(label, target, trigger) {
|
|
832
|
+
if (target === void 0 !== (trigger === void 0)) throw new Error(`ToolResultPruneConfig: ${label} target and trigger tokens must be provided together`);
|
|
833
|
+
if (target !== void 0 && trigger !== void 0 && target >= trigger) throw new Error(`ToolResultPruneConfig: ${label} target tokens must be below trigger tokens`);
|
|
834
|
+
}
|
|
835
|
+
function assertPositiveInteger(name, value) {
|
|
836
|
+
if (!Number.isSafeInteger(value) || value <= 0) throw new Error(`ToolResultPruneConfig: ${name} (${String(value)}) must be a positive safe integer`);
|
|
837
|
+
}
|
|
838
|
+
function assertNonNegativeInteger(name, value) {
|
|
839
|
+
if (!Number.isSafeInteger(value) || value < 0) throw new Error(`ToolResultPruneConfig: ${name} (${String(value)}) must be a non-negative safe integer`);
|
|
840
|
+
}
|
|
841
|
+
//#endregion
|
|
842
|
+
export { COMPRESSION_PROFILES as _, PRUNE_MARKER as a, isValidAutoCompactThresholdPercent as c, resolvePolicy as d, CustomCompressionPolicySchema as f, deepFreeze as g, assertNever as h, DEFAULTS as i, parseContextCompressionSettings as l, resolveCustomPolicy as m, CONTEXT_COMPRESSION_SETTINGS_NAMESPACE as n, codePointLength as o, DEFAULT_CUSTOM_COMPRESSION_POLICY as p, ContextCompressionSettingsSchema as r, isCompressionProfile as s, AUTO_COMPACT_THRESHOLD_LIMITS as t, resolveConfig as u };
|