acp-kernel 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compress.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +100 -157
- package/dist/index.js.map +1 -1
- package/dist/nudge-text.d.ts.map +1 -1
- package/dist/pipeline.d.ts +0 -1
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/protected.d.ts +14 -0
- package/dist/protected.d.ts.map +1 -1
- package/dist/recommend.d.ts.map +1 -1
- package/dist/tokenize.d.ts.map +1 -1
- package/dist/types.d.ts +3 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/merge.d.ts +0 -9
- package/dist/merge.d.ts.map +0 -1
package/dist/compress.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,kBAAkB,EACnB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"compress.d.ts","sourceRoot":"","sources":["../src/compress.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAcpB,OAAO,EAGL,KAAK,YAAY,EAElB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,EAEhB,MAAM,EAEN,WAAW,EAGX,iBAAiB,EAEjB,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,KAAK;IACpB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;CACxC;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,CAAC;IACxD,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,CAAC;IACvE,YAAY,IAAI,YAAY,EAAE,CAAC;IAC/B,UAAU,CACR,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,gBAAgB,GACtB,gBAAgB,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,gBAAgB,EAAE,CAAC;IACnE,MAAM,CACJ,KAAK,EAAE,gBAAgB,EACvB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,YAAY,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,EAAE,CAAC;IACJ,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,EAAE,gBAAgB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACnC;AAED,wBAAgB,UAAU,CAAC,KAAK,GAAE,KAAU,GAAG,eAAe,CAgN7D;AA8lBD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,wBAAgB,aAAa,CAC3B,iBAAiB,EAAE,MAAM,EACzB,SAAS,GAAE,OAAO,CAAC,MAAM,CAAM,GAC9B,MAAM,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,wBAAgB,aAAa,CAC3B,iBAAiB,EAAE,MAAM,EACzB,SAAS,GAAE,OAAO,CAAC,MAAM,CAAM,GAC9B,MAAM,CAoCR;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CA0BvD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -22,8 +22,6 @@ export { buildStatusReport, buildRecap } from "./report.js";
|
|
|
22
22
|
export type { StatusReportOptions } from "./report.js";
|
|
23
23
|
export { hideConsumedCompressCalls } from "./hide-consumed.js";
|
|
24
24
|
export type { HideConsumedResult } from "./hide-consumed.js";
|
|
25
|
-
export { mergeMarkedBlocks, collectOldGenBlocks } from "./merge.js";
|
|
26
|
-
export type { MergeResult } from "./merge.js";
|
|
27
25
|
export { rebuildCompressionState } from "./rebuild.js";
|
|
28
26
|
export type { RebuildResult, RebuildPorts } from "./rebuild.js";
|
|
29
27
|
export { renderVisibleRefs, renderRefsNode } from "./render-refs.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,YAAY,EACV,KAAK,EACL,eAAe,EACf,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,UAAU,EACV,SAAS,EACT,SAAS,EACT,WAAW,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC3F,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC/H,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EACH,eAAe,EACf,6BAA6B,EAC7B,kBAAkB,EAClB,eAAe,EACf,2BAA2B,GAC9B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC5D,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,YAAY,EACV,KAAK,EACL,eAAe,EACf,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,UAAU,EACV,SAAS,EACT,SAAS,EACT,WAAW,GACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC3F,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC/H,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EACH,eAAe,EACf,6BAA6B,EAC7B,kBAAkB,EAClB,eAAe,EACf,2BAA2B,GAC9B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC5D,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EACL,WAAW,EACX,MAAM,EACN,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,MAAM,EACX,KAAK,WAAW,GACjB,MAAM,eAAe,CAAC;AACvB,cAAc,mBAAmB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -269,9 +269,9 @@ import { createRequire } from "module";
|
|
|
269
269
|
var require2 = createRequire(import.meta.url);
|
|
270
270
|
function defaultCountTokens(text) {
|
|
271
271
|
if (!text) return 0;
|
|
272
|
-
const ascii = text.match(/[a-zA-Z][a-zA-Z0-9_'-]*/g);
|
|
273
272
|
const cjk = text.match(/[\u4e00-\u9fff\u3040-\u30ff\uac00-\ud7af]/g);
|
|
274
|
-
|
|
273
|
+
const cjkCount = cjk?.length ?? 0;
|
|
274
|
+
return cjkCount + Math.ceil((text.length - cjkCount) / 4);
|
|
275
275
|
}
|
|
276
276
|
function estimateTokensFast(text) {
|
|
277
277
|
if (!text) return 0;
|
|
@@ -313,7 +313,6 @@ function defaultConfig(modelContextLimit, overrides = {}) {
|
|
|
313
313
|
},
|
|
314
314
|
promotionThreshold: 5,
|
|
315
315
|
truncate: { threshold: 1 },
|
|
316
|
-
merge: { maxSummaryLength: 3e3, minOldGenBlocks: 3 },
|
|
317
316
|
compress: {
|
|
318
317
|
minCompressRange: 5e3,
|
|
319
318
|
maxSummaryLength: 2e4,
|
|
@@ -330,7 +329,6 @@ function defaultConfig(modelContextLimit, overrides = {}) {
|
|
|
330
329
|
tiers: { ...base.tiers, ...overrides.tiers },
|
|
331
330
|
nudge: { ...base.nudge, ...overrides.nudge },
|
|
332
331
|
truncate: { ...base.truncate, ...overrides.truncate },
|
|
333
|
-
merge: { ...base.merge, ...overrides.merge },
|
|
334
332
|
compress: { ...base.compress, ...overrides.compress }
|
|
335
333
|
};
|
|
336
334
|
}
|
|
@@ -350,12 +348,6 @@ function validateConfig(config) {
|
|
|
350
348
|
if (config.truncate.threshold <= 0 || config.truncate.threshold > 1) {
|
|
351
349
|
errors.push("truncate.threshold must be in (0, 1]");
|
|
352
350
|
}
|
|
353
|
-
if (config.merge.maxSummaryLength < 1) {
|
|
354
|
-
errors.push("merge.maxSummaryLength must be >= 1");
|
|
355
|
-
}
|
|
356
|
-
if (config.merge.minOldGenBlocks < 1) {
|
|
357
|
-
errors.push("merge.minOldGenBlocks must be >= 1");
|
|
358
|
-
}
|
|
359
351
|
for (const tier of [config.tiers.tier2Trigger, config.tiers.tier3Trigger]) {
|
|
360
352
|
if (tier < 1) errors.push("tier triggers must be >= 1");
|
|
361
353
|
}
|
|
@@ -554,74 +546,6 @@ function hideConsumedCompressCalls(state, messages) {
|
|
|
554
546
|
return { messages: result, hidden };
|
|
555
547
|
}
|
|
556
548
|
|
|
557
|
-
// src/merge.ts
|
|
558
|
-
function numericPart(blockId) {
|
|
559
|
-
const match = /^b(\d+)$/.exec(blockId);
|
|
560
|
-
return match && match[1] !== void 0 ? Number(match[1]) : 0;
|
|
561
|
-
}
|
|
562
|
-
function truncateMergedSummary(merged, maxLength) {
|
|
563
|
-
if (merged.length <= maxLength) return merged;
|
|
564
|
-
const blocks = merged.split("\n---\n");
|
|
565
|
-
const headers = blocks.map((b) => b.split("\n")[0] ?? "").filter((h) => h.trim().length > 0);
|
|
566
|
-
const marker = "\n...\n[merged and truncated by batch cleanup]";
|
|
567
|
-
const budget = Math.max(0, maxLength - marker.length);
|
|
568
|
-
const headerJoin = headers.join("\n");
|
|
569
|
-
return headerJoin.length <= budget ? headerJoin + marker : headerJoin.slice(0, budget) + marker;
|
|
570
|
-
}
|
|
571
|
-
function mergeMarkedBlocks(state, markedIds, maxMergedLength, countTokens) {
|
|
572
|
-
const sortedIds = [...new Set(markedIds)].sort((a, b) => numericPart(a) - numericPart(b));
|
|
573
|
-
const sourceBlocks = sortedIds.map((id) => state.blocks.find((b) => b.blockId === id && b.active)).filter((b) => b !== void 0);
|
|
574
|
-
if (sourceBlocks.length < 2) {
|
|
575
|
-
return { state, mergedCount: 0, savedTokens: 0 };
|
|
576
|
-
}
|
|
577
|
-
const next = {
|
|
578
|
-
...state,
|
|
579
|
-
blocks: state.blocks.map((b) => ({ ...b }))
|
|
580
|
-
};
|
|
581
|
-
const newBlockId = allocateBlockId(next);
|
|
582
|
-
const newRunId = allocateRunId(next);
|
|
583
|
-
const bodies = sourceBlocks.map((block) => block.summary.trim());
|
|
584
|
-
const mergedSummary = truncateMergedSummary(bodies.join("\n---\n"), maxMergedLength);
|
|
585
|
-
const newSummaryTokens = countTokens(mergedSummary);
|
|
586
|
-
const effectiveMessageIds = /* @__PURE__ */ new Set();
|
|
587
|
-
const directMessageIds = /* @__PURE__ */ new Set();
|
|
588
|
-
for (const block of sourceBlocks) {
|
|
589
|
-
for (const id of block.effectiveMessageIds) effectiveMessageIds.add(id);
|
|
590
|
-
for (const id of block.directMessageIds) directMessageIds.add(id);
|
|
591
|
-
}
|
|
592
|
-
const sourceIds = sourceBlocks.map((b) => b.blockId);
|
|
593
|
-
const mergedBlock = {
|
|
594
|
-
blockId: newBlockId,
|
|
595
|
-
runId: newRunId,
|
|
596
|
-
tier: sourceBlocks.reduce((min, b) => b.tier < min ? b.tier : min, 3),
|
|
597
|
-
topic: "Batch merge cleanup",
|
|
598
|
-
summary: mergedSummary,
|
|
599
|
-
directMessageIds: [...directMessageIds],
|
|
600
|
-
effectiveMessageIds: [...effectiveMessageIds],
|
|
601
|
-
directBlockIds: [...sourceIds],
|
|
602
|
-
compressedTokens: sourceBlocks.reduce((sum, b) => sum + b.compressedTokens, 0),
|
|
603
|
-
createdAt: Date.now(),
|
|
604
|
-
survivedCount: 0,
|
|
605
|
-
generation: "old",
|
|
606
|
-
active: true
|
|
607
|
-
};
|
|
608
|
-
for (const block of next.blocks) {
|
|
609
|
-
if (sourceIds.includes(block.blockId)) block.active = false;
|
|
610
|
-
}
|
|
611
|
-
next.blocks.push(mergedBlock);
|
|
612
|
-
const sourceTokens = sourceBlocks.reduce(
|
|
613
|
-
(sum, block) => sum + countTokens(block.summary),
|
|
614
|
-
0
|
|
615
|
-
);
|
|
616
|
-
const savedTokens = Math.max(0, sourceTokens - newSummaryTokens);
|
|
617
|
-
return { state: next, mergedCount: sourceBlocks.length, savedTokens };
|
|
618
|
-
}
|
|
619
|
-
function collectOldGenBlocks(state, maxOldGenSummaryLength) {
|
|
620
|
-
return state.blocks.filter(
|
|
621
|
-
(b) => b.active && (b.generation === "old" || b.summary.length > maxOldGenSummaryLength)
|
|
622
|
-
).sort((a, b) => numericPart(a.blockId) - numericPart(b.blockId));
|
|
623
|
-
}
|
|
624
|
-
|
|
625
549
|
// src/filter/registry.ts
|
|
626
550
|
var registry = /* @__PURE__ */ new Map();
|
|
627
551
|
function registerMessageFilter(filter) {
|
|
@@ -780,6 +704,7 @@ var renderRefsNode = {
|
|
|
780
704
|
};
|
|
781
705
|
|
|
782
706
|
// src/protected.ts
|
|
707
|
+
var ALWAYS_PROTECTED_TOOLS = ["compress"];
|
|
783
708
|
function matchToolPattern(toolName, pattern) {
|
|
784
709
|
if (pattern.endsWith("*")) {
|
|
785
710
|
return toolName.startsWith(pattern.slice(0, -1));
|
|
@@ -787,13 +712,34 @@ function matchToolPattern(toolName, pattern) {
|
|
|
787
712
|
return toolName === pattern;
|
|
788
713
|
}
|
|
789
714
|
function isMessageProtected(msg, config) {
|
|
790
|
-
if (msg.contentType !== "tool-call" || !msg.toolName)
|
|
715
|
+
if (msg.contentType !== "tool-call" && msg.contentType !== "tool-result" || !msg.toolName) {
|
|
716
|
+
return false;
|
|
717
|
+
}
|
|
718
|
+
if (ALWAYS_PROTECTED_TOOLS.includes(msg.toolName)) {
|
|
719
|
+
return true;
|
|
720
|
+
}
|
|
791
721
|
for (const pattern of config.protectedTools) {
|
|
792
722
|
if (matchToolPattern(msg.toolName, pattern)) return true;
|
|
793
723
|
}
|
|
794
724
|
if (config.isToolProtected?.(msg.toolName, msg.text)) return true;
|
|
795
725
|
return false;
|
|
796
726
|
}
|
|
727
|
+
function collectProtectedToolCallIds(messages, config) {
|
|
728
|
+
const ids = /* @__PURE__ */ new Set();
|
|
729
|
+
for (const m of messages) {
|
|
730
|
+
if (m.contentType === "tool-call" && m.toolCallId && isMessageProtected(m, config)) {
|
|
731
|
+
ids.add(m.toolCallId);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return ids;
|
|
735
|
+
}
|
|
736
|
+
function isMessageProtectedWithPairing(msg, config, protectedCallIds) {
|
|
737
|
+
if (isMessageProtected(msg, config)) return true;
|
|
738
|
+
if (msg.contentType === "tool-result" && msg.toolCallId && protectedCallIds.has(msg.toolCallId)) {
|
|
739
|
+
return true;
|
|
740
|
+
}
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
797
743
|
|
|
798
744
|
// src/tool-pairs.ts
|
|
799
745
|
function adjustBoundariesForToolPairs(startIndex, endIndex, messages, maxScan = 20) {
|
|
@@ -871,24 +817,27 @@ function computeProtectedRefs(messages, state, config) {
|
|
|
871
817
|
tokenAccum += visible[i].tokens;
|
|
872
818
|
}
|
|
873
819
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
820
|
+
if (preserveN > 0) {
|
|
821
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
822
|
+
const msg = messages[i];
|
|
823
|
+
if (msg.role !== "user" || isSyntheticOrPruned(msg, state)) continue;
|
|
824
|
+
const ref = state.messageRefs.byRaw[msg.id];
|
|
825
|
+
if (ref && ref !== "BLOCKED") result.add(ref);
|
|
826
|
+
break;
|
|
827
|
+
}
|
|
880
828
|
}
|
|
881
829
|
return result;
|
|
882
830
|
}
|
|
883
831
|
function buildCompressibleRanges(messages, state, config, protectedZoneRefs) {
|
|
884
832
|
const compressibleMsgs = [];
|
|
885
833
|
const protectedMsgs = [];
|
|
834
|
+
const protectedCallIds = collectProtectedToolCallIds(messages, config);
|
|
886
835
|
for (const msg of messages) {
|
|
887
836
|
if (isSyntheticOrPruned(msg, state)) continue;
|
|
888
837
|
const ref = state.messageRefs.byRaw[msg.id];
|
|
889
838
|
if (!ref || ref === "BLOCKED") continue;
|
|
890
839
|
const rn = refNum(ref);
|
|
891
|
-
if (
|
|
840
|
+
if (isMessageProtectedWithPairing(msg, config, protectedCallIds)) {
|
|
892
841
|
protectedMsgs.push({
|
|
893
842
|
ref,
|
|
894
843
|
refNum: rn,
|
|
@@ -904,7 +853,8 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs) {
|
|
|
904
853
|
ref,
|
|
905
854
|
refNum: rn,
|
|
906
855
|
tokens: estimateMessageTokens(msg),
|
|
907
|
-
isTool: isToolMessage(msg)
|
|
856
|
+
isTool: isToolMessage(msg),
|
|
857
|
+
isUser: msg.role === "user"
|
|
908
858
|
});
|
|
909
859
|
}
|
|
910
860
|
const compressible = [];
|
|
@@ -912,7 +862,7 @@ function buildCompressibleRanges(messages, state, config, protectedZoneRefs) {
|
|
|
912
862
|
let prevRefNum = -2;
|
|
913
863
|
for (const info of compressibleMsgs) {
|
|
914
864
|
const hasGap = info.refNum > prevRefNum + 1;
|
|
915
|
-
if (cur && hasGap) {
|
|
865
|
+
if (cur && (info.isUser && cur.count >= 3 || hasGap)) {
|
|
916
866
|
compressible.push(cur);
|
|
917
867
|
cur = null;
|
|
918
868
|
}
|
|
@@ -995,6 +945,7 @@ function createCore(ports = {}) {
|
|
|
995
945
|
let blocksCreated = 0;
|
|
996
946
|
let tokensCompressed = 0;
|
|
997
947
|
const errors = [];
|
|
948
|
+
const protectedMessageIds = input.protectedMessageIds ?? computeProtectedRefs(input.messages, input.state, input.config);
|
|
998
949
|
const preExistingCoverage = collectCoverage(state);
|
|
999
950
|
const rangeIndexSets = [];
|
|
1000
951
|
for (const spec of input.ranges) {
|
|
@@ -1082,7 +1033,7 @@ function createCore(ports = {}) {
|
|
|
1082
1033
|
state,
|
|
1083
1034
|
runId,
|
|
1084
1035
|
config: input.config,
|
|
1085
|
-
protectedMessageIds
|
|
1036
|
+
protectedMessageIds,
|
|
1086
1037
|
countTokens,
|
|
1087
1038
|
preExistingCoverage
|
|
1088
1039
|
});
|
|
@@ -1148,7 +1099,6 @@ function createCore(ports = {}) {
|
|
|
1148
1099
|
return [
|
|
1149
1100
|
assignRefsNode,
|
|
1150
1101
|
syncBlocksNode,
|
|
1151
|
-
mergeBlocksNode,
|
|
1152
1102
|
pruneNode,
|
|
1153
1103
|
filterNode,
|
|
1154
1104
|
hideCompressCallsNode,
|
|
@@ -1181,29 +1131,6 @@ var syncBlocksNode = {
|
|
|
1181
1131
|
return { ...io, state: synced.state };
|
|
1182
1132
|
}
|
|
1183
1133
|
};
|
|
1184
|
-
var mergeBlocksNode = {
|
|
1185
|
-
name: "merge-blocks",
|
|
1186
|
-
run(io, ctx) {
|
|
1187
|
-
const oldGen = collectOldGenBlocks(
|
|
1188
|
-
io.state,
|
|
1189
|
-
ctx.config.merge.maxSummaryLength
|
|
1190
|
-
);
|
|
1191
|
-
if (oldGen.length < ctx.config.merge.minOldGenBlocks) return io;
|
|
1192
|
-
const ids = oldGen.map((b) => b.blockId);
|
|
1193
|
-
const merged = mergeMarkedBlocks(
|
|
1194
|
-
io.state,
|
|
1195
|
-
ids,
|
|
1196
|
-
ctx.config.merge.maxSummaryLength,
|
|
1197
|
-
ctx.countTokens
|
|
1198
|
-
);
|
|
1199
|
-
if (merged.mergedCount === 0) return io;
|
|
1200
|
-
return {
|
|
1201
|
-
...io,
|
|
1202
|
-
state: merged.state,
|
|
1203
|
-
effects: { ...io.effects, mergedCount: merged.mergedCount }
|
|
1204
|
-
};
|
|
1205
|
-
}
|
|
1206
|
-
};
|
|
1207
1134
|
var pruneNode = {
|
|
1208
1135
|
name: "prune",
|
|
1209
1136
|
run(io) {
|
|
@@ -1348,11 +1275,25 @@ function applySingleRange(input) {
|
|
|
1348
1275
|
const directMessageIds = [...effectiveMessageIds].filter(
|
|
1349
1276
|
(id) => !input.preExistingCoverage.has(id)
|
|
1350
1277
|
);
|
|
1351
|
-
const
|
|
1278
|
+
const filteredIds = filterProtectedToolMessages(
|
|
1352
1279
|
directMessageIds,
|
|
1353
1280
|
input.messages,
|
|
1354
1281
|
input.config
|
|
1355
1282
|
);
|
|
1283
|
+
const protectedRefs = input.protectedMessageIds;
|
|
1284
|
+
const hitProtectedRaw = protectedRefs ? filteredIds.filter((id) => {
|
|
1285
|
+
const ref = input.state.messageRefs.byRaw[id];
|
|
1286
|
+
return ref !== void 0 && protectedRefs.has(ref);
|
|
1287
|
+
}) : [];
|
|
1288
|
+
if (hitProtectedRaw.length > 0) {
|
|
1289
|
+
const recentN = input.config.preserveRecentMessages;
|
|
1290
|
+
const hitRefs = hitProtectedRaw.map((id) => input.state.messageRefs.byRaw[id]).filter(Boolean);
|
|
1291
|
+
throw new Error(
|
|
1292
|
+
`Range includes protected messages (the last ${recentN} messages and/or the most recent user message) which must not be compressed: ${hitRefs.join(
|
|
1293
|
+
", "
|
|
1294
|
+
)}. Adjust startId/endId to exclude them.`
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1356
1297
|
validateCompressionRange(input, filteredIds, consumedBlockIds.length);
|
|
1357
1298
|
let compressedTokens = 0;
|
|
1358
1299
|
for (const id of filteredIds) {
|
|
@@ -1366,22 +1307,12 @@ function applySingleRange(input) {
|
|
|
1366
1307
|
}
|
|
1367
1308
|
}
|
|
1368
1309
|
const blockId = allocateBlockId(input.state);
|
|
1369
|
-
const finalSummary = appendedProtectedText.length > 0 ? `${input.spec.summary}
|
|
1370
|
-
|
|
1371
|
-
The following protected tool calls were used in this conversation as well:
|
|
1372
|
-
${appendedProtectedText.join("")}` : input.spec.summary;
|
|
1373
|
-
const maxLen = input.spec.summaryMaxChars ?? input.config.compress.maxSummaryLength;
|
|
1374
|
-
if (maxLen > 0 && finalSummary.length > maxLen) {
|
|
1375
|
-
throw new Error(
|
|
1376
|
-
`Summary too long after appending protected content (${finalSummary.length} chars, max ${maxLen}). Reduce the summary or remove protected tools from the range.`
|
|
1377
|
-
);
|
|
1378
|
-
}
|
|
1379
1310
|
const block = {
|
|
1380
1311
|
blockId,
|
|
1381
1312
|
runId: input.runId,
|
|
1382
1313
|
tier: outputTier,
|
|
1383
1314
|
topic: input.spec.topic,
|
|
1384
|
-
summary:
|
|
1315
|
+
summary: input.spec.summary,
|
|
1385
1316
|
directMessageIds: filteredIds,
|
|
1386
1317
|
effectiveMessageIds: [...effectiveMessageIds],
|
|
1387
1318
|
directBlockIds: [...consumedBlockIds],
|
|
@@ -1444,41 +1375,30 @@ function validateCompressionRange(input, directMessageIds, consumedBlockCount) {
|
|
|
1444
1375
|
}
|
|
1445
1376
|
}
|
|
1446
1377
|
function filterProtectedToolMessages(directMessageIds, messages, config) {
|
|
1447
|
-
const
|
|
1448
|
-
const allProtectedCallIds = /* @__PURE__ */ new Set();
|
|
1378
|
+
const protectedCallIds = /* @__PURE__ */ new Set();
|
|
1449
1379
|
const removedIds = /* @__PURE__ */ new Set();
|
|
1450
|
-
const appendedProtectedText = [];
|
|
1451
1380
|
for (const msg of messages) {
|
|
1452
1381
|
if (isMessageProtected(msg, config) && msg.toolCallId) {
|
|
1453
|
-
|
|
1382
|
+
protectedCallIds.add(msg.toolCallId);
|
|
1454
1383
|
}
|
|
1455
1384
|
}
|
|
1456
1385
|
for (const id of directMessageIds) {
|
|
1457
1386
|
const msg = messages.find((m) => m.id === id);
|
|
1458
1387
|
if (!msg) continue;
|
|
1459
|
-
if (
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
if (msg.text) {
|
|
1463
|
-
appendedProtectedText.push(
|
|
1464
|
-
`
|
|
1465
|
-
### Protected: ${msg.toolName ?? "tool"}
|
|
1466
|
-
${msg.text}`
|
|
1467
|
-
);
|
|
1388
|
+
if (isMessageProtected(msg, config)) {
|
|
1389
|
+
removedIds.add(id);
|
|
1390
|
+
if (msg.toolCallId) protectedCallIds.add(msg.toolCallId);
|
|
1468
1391
|
}
|
|
1469
1392
|
}
|
|
1470
1393
|
for (const id of directMessageIds) {
|
|
1471
1394
|
if (removedIds.has(id)) continue;
|
|
1472
1395
|
const msg = messages.find((m) => m.id === id);
|
|
1473
1396
|
if (!msg) continue;
|
|
1474
|
-
if (msg.contentType === "tool-result" && msg.toolCallId &&
|
|
1397
|
+
if (msg.contentType === "tool-result" && msg.toolCallId && protectedCallIds.has(msg.toolCallId)) {
|
|
1475
1398
|
removedIds.add(id);
|
|
1476
1399
|
}
|
|
1477
1400
|
}
|
|
1478
|
-
return
|
|
1479
|
-
filteredIds: directMessageIds.filter((id) => !removedIds.has(id)),
|
|
1480
|
-
appendedProtectedText
|
|
1481
|
-
};
|
|
1401
|
+
return directMessageIds.filter((id) => !removedIds.has(id));
|
|
1482
1402
|
}
|
|
1483
1403
|
function resolveTargetTier(state, nestedBlockIds, isBlockBoundary) {
|
|
1484
1404
|
if (!isBlockBoundary) return 1;
|
|
@@ -1529,23 +1449,30 @@ function decideNudge(input) {
|
|
|
1529
1449
|
shouldContextNudge = growthSinceReference >= growthFloor;
|
|
1530
1450
|
}
|
|
1531
1451
|
let tier = null;
|
|
1452
|
+
let tierTargetBlocks = [];
|
|
1532
1453
|
if (config.tiers.enabled) {
|
|
1533
1454
|
const active = activeBlocks(state);
|
|
1534
1455
|
const activeT1 = active.filter((b) => b.tier === 1);
|
|
1535
1456
|
const activeT2 = active.filter((b) => b.tier === 2);
|
|
1536
|
-
if (activeT2.length >= config.tiers.tier3Trigger)
|
|
1537
|
-
|
|
1457
|
+
if (activeT2.length >= config.tiers.tier3Trigger) {
|
|
1458
|
+
tier = 3;
|
|
1459
|
+
tierTargetBlocks = activeT2;
|
|
1460
|
+
} else if (activeT1.length >= config.tiers.tier2Trigger) {
|
|
1461
|
+
tier = 2;
|
|
1462
|
+
tierTargetBlocks = activeT1;
|
|
1463
|
+
}
|
|
1538
1464
|
}
|
|
1539
1465
|
const rec = recommendation;
|
|
1540
1466
|
const nothingToCompress = rec ? rec.contextRanges.compressible.length === 0 : false;
|
|
1541
|
-
const shouldInject = shouldContextNudge
|
|
1467
|
+
const shouldInject = shouldContextNudge;
|
|
1542
1468
|
let reason;
|
|
1543
1469
|
if (!shouldInject) {
|
|
1544
|
-
|
|
1470
|
+
const tierHint = tier !== null ? `, tier-${tier} ready (distill when growth reaches threshold)` : "";
|
|
1471
|
+
reason = `growth ${growthSinceReference} < threshold ${effectiveThreshold}${hasPendingNudge ? " (halved)" : ""} (floor ${growthFloor})${tierHint}`;
|
|
1545
1472
|
} else if (emergencyOverride) {
|
|
1546
1473
|
reason = `EMERGENCY: usage ${Math.round(usage * 100)}% >= ${Math.round(config.nudge.emergencyThresholdPct * 100)}%`;
|
|
1547
1474
|
} else if (tier !== null) {
|
|
1548
|
-
reason = `tier-${tier} distillation
|
|
1475
|
+
reason = `growth ${growthSinceReference} >= ${effectiveThreshold}${hasPendingNudge ? " (halved)" : ""}, usage ${Math.round(usage * 100)}%, tier-${tier} distillation`;
|
|
1549
1476
|
} else if (nothingToCompress) {
|
|
1550
1477
|
reason = `growth ${growthSinceReference} >= ${effectiveThreshold} but no specific ranges worth compressing`;
|
|
1551
1478
|
} else {
|
|
@@ -1557,6 +1484,7 @@ function decideNudge(input) {
|
|
|
1557
1484
|
reason,
|
|
1558
1485
|
compressibleRanges: rec?.recommendedRanges ?? [],
|
|
1559
1486
|
protectedRanges: rec?.contextRanges.protected ?? [],
|
|
1487
|
+
tierTargetBlocks,
|
|
1560
1488
|
contextUsage: usage,
|
|
1561
1489
|
tier,
|
|
1562
1490
|
breakdown: {
|
|
@@ -1833,6 +1761,18 @@ function mergeRanges(compressible, protected_) {
|
|
|
1833
1761
|
}
|
|
1834
1762
|
return merged;
|
|
1835
1763
|
}
|
|
1764
|
+
function formatTierTargetBlocks(blocks) {
|
|
1765
|
+
if (blocks.length === 0) {
|
|
1766
|
+
return "Target blocks: (none \u2014 no tier blocks found)";
|
|
1767
|
+
}
|
|
1768
|
+
const lines = blocks.map((b) => {
|
|
1769
|
+
const summaryTokens = Math.ceil((b.summary ?? "").length / 4);
|
|
1770
|
+
const topic = b.topic ? ` "${b.topic}"` : "";
|
|
1771
|
+
return ` ${b.blockId} ${b.effectiveMessageIds.length} msgs ${formatK(b.compressedTokens)}\u2192${formatK(summaryTokens)}${topic}`;
|
|
1772
|
+
});
|
|
1773
|
+
return `Target ${blocks[0].tier === 1 ? "tier-1" : "tier-2"} blocks to distill (${blocks.length}):
|
|
1774
|
+
${lines.join("\n")}`;
|
|
1775
|
+
}
|
|
1836
1776
|
function formatRanges(compressible, protected_) {
|
|
1837
1777
|
const merged = mergeRanges(compressible, protected_);
|
|
1838
1778
|
if (merged.length === 0) {
|
|
@@ -1856,6 +1796,10 @@ function renderNudgeText(decision) {
|
|
|
1856
1796
|
const rangesStr = formatRanges(decision.compressibleRanges, decision.protectedRanges ?? []);
|
|
1857
1797
|
if (decision.tier !== null && decision.tier >= 2) {
|
|
1858
1798
|
const isT2 = decision.tier === 2;
|
|
1799
|
+
const targets = decision.tierTargetBlocks ?? [];
|
|
1800
|
+
const blockList = formatTierTargetBlocks(targets);
|
|
1801
|
+
const startId = targets[0]?.blockId ?? "b1";
|
|
1802
|
+
const endId = targets[targets.length - 1]?.blockId ?? "b5";
|
|
1859
1803
|
return {
|
|
1860
1804
|
voice: "gentle",
|
|
1861
1805
|
text: [
|
|
@@ -1864,8 +1808,9 @@ function renderNudgeText(decision) {
|
|
|
1864
1808
|
breakdownStr,
|
|
1865
1809
|
"",
|
|
1866
1810
|
`[TIER ${decision.tier} ${isT2 ? "DISTILLATION" : "CONDENSATION"} TRIGGER]`,
|
|
1867
|
-
isT2 ?
|
|
1868
|
-
|
|
1811
|
+
isT2 ? `Your tier-1 compression summaries have accumulated. Distill them into a single denser tier-2 summary. Use block IDs as boundaries.` : `Your tier-2 compression summaries have accumulated. Condense them further into a tier-3 ultra-condensed summary. Use block IDs as boundaries.`,
|
|
1812
|
+
blockList,
|
|
1813
|
+
`Example: compress({ content: [{ startId: "${startId}", endId: "${endId}", summary: "..." }] })`,
|
|
1869
1814
|
"",
|
|
1870
1815
|
HOW_TO_COMPRESS_RULES,
|
|
1871
1816
|
"",
|
|
@@ -1984,7 +1929,7 @@ function findBlocksOverlappingMessages(state, messageIds) {
|
|
|
1984
1929
|
matched.push(block);
|
|
1985
1930
|
}
|
|
1986
1931
|
}
|
|
1987
|
-
return matched.sort((a, b) =>
|
|
1932
|
+
return matched.sort((a, b) => numericPart(a.blockId) - numericPart(b.blockId));
|
|
1988
1933
|
}
|
|
1989
1934
|
function findActiveAncestor(state, blockId) {
|
|
1990
1935
|
const start = state.blocks.find((b) => b.blockId === blockId);
|
|
@@ -2060,7 +2005,7 @@ function buildRestoredContentPreview(messages, beforeActiveMessageIds, state) {
|
|
|
2060
2005
|
}
|
|
2061
2006
|
return { preview: lines.join("\n"), restoredCount: restored.length };
|
|
2062
2007
|
}
|
|
2063
|
-
function
|
|
2008
|
+
function numericPart(blockId) {
|
|
2064
2009
|
const match = /^b(\d+)$/.exec(blockId);
|
|
2065
2010
|
return match && match[1] !== void 0 ? Number(match[1]) : 0;
|
|
2066
2011
|
}
|
|
@@ -2074,7 +2019,7 @@ function pct(n, total) {
|
|
|
2074
2019
|
if (n <= 0 || total <= 0) return 0;
|
|
2075
2020
|
return Math.max(1, Math.round(n / total * 100));
|
|
2076
2021
|
}
|
|
2077
|
-
function
|
|
2022
|
+
function numericPart2(blockId) {
|
|
2078
2023
|
const match = /^b(\d+)$/.exec(blockId);
|
|
2079
2024
|
return match && match[1] !== void 0 ? Number(match[1]) : 0;
|
|
2080
2025
|
}
|
|
@@ -2134,7 +2079,7 @@ function buildStatusReport(state, messages, countTokens, options = {}) {
|
|
|
2134
2079
|
const toolFilter = options.tool;
|
|
2135
2080
|
const sort = options.sort ?? "size";
|
|
2136
2081
|
const limit = options.limit ?? 30;
|
|
2137
|
-
const activeBlocks2 = state.blocks.filter((b) => b.active).sort((a, b) =>
|
|
2082
|
+
const activeBlocks2 = state.blocks.filter((b) => b.active).sort((a, b) => numericPart2(a.blockId) - numericPart2(b.blockId));
|
|
2138
2083
|
if (scope === "compressed") {
|
|
2139
2084
|
return renderCompressedDrilldown(activeBlocks2, state, sort, limit, countTokens);
|
|
2140
2085
|
}
|
|
@@ -2268,7 +2213,7 @@ function renderCompressedDrilldown(blocks, state, sort, limit, countTokens) {
|
|
|
2268
2213
|
return lines.join("\n");
|
|
2269
2214
|
}
|
|
2270
2215
|
function buildRecap(state, blockId) {
|
|
2271
|
-
const activeBlocks2 = state.blocks.filter((b) => b.active).sort((a, b) =>
|
|
2216
|
+
const activeBlocks2 = state.blocks.filter((b) => b.active).sort((a, b) => numericPart2(a.blockId) - numericPart2(b.blockId));
|
|
2272
2217
|
if (blockId !== void 0) {
|
|
2273
2218
|
const block = state.blocks.find((b) => b.blockId === blockId);
|
|
2274
2219
|
if (!block) {
|
|
@@ -2406,7 +2351,6 @@ export {
|
|
|
2406
2351
|
buildRestoredContentPreview,
|
|
2407
2352
|
buildStatusReport,
|
|
2408
2353
|
clearMessageFilters,
|
|
2409
|
-
collectOldGenBlocks,
|
|
2410
2354
|
coveredMessageIds,
|
|
2411
2355
|
createBpeTokenizer,
|
|
2412
2356
|
createCore,
|
|
@@ -2427,7 +2371,6 @@ export {
|
|
|
2427
2371
|
listMessageFilters,
|
|
2428
2372
|
makeIO,
|
|
2429
2373
|
matchToolPattern,
|
|
2430
|
-
mergeMarkedBlocks,
|
|
2431
2374
|
parseBlockIdArg,
|
|
2432
2375
|
parseBoundary,
|
|
2433
2376
|
prune,
|