acp-kernel 0.0.11 → 0.0.13

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.
@@ -1 +1 @@
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,CAoN7D;AAgpBD,OAAO,EAAE,kBAAkB,EAAE,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,CAwN7D;AAwqBD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -11,4 +11,33 @@ export interface RestoredPreviewResult {
11
11
  restoredCount: number;
12
12
  }
13
13
  export declare function buildRestoredContentPreview(messages: CoreMessage[], beforeActiveMessageIds: Set<string>, state: CompressionState): RestoredPreviewResult;
14
+ export interface CollectedContentResult {
15
+ /** Rendered, human-readable content string (empty when count is 0). */
16
+ text: string;
17
+ /** Number of items rendered: direct messages + nested summaries (full=false) or all messages (full=true). */
18
+ count: number;
19
+ }
20
+ export interface CollectContentOptions {
21
+ /** When true, recurse through all nested tiers to original messages. Default: false (one tier up — nested active children stay folded, their summaries shown). */
22
+ full?: boolean;
23
+ }
24
+ /**
25
+ * Collect a block's content as a readable string WITHOUT modifying state.
26
+ *
27
+ * This is the cache-safe decompress primitive: the block stays compressed
28
+ * (folded), its summary stays in place, and the full content is returned as
29
+ * text for the caller to surface (e.g. as a tool result appended to the
30
+ * conversation). Unlike deactivateBlock + prune, this does not mutate the
31
+ * message-array prefix, so prompt cache is preserved.
32
+ *
33
+ * full=false (default): one tier up. Nested ACTIVE children of this block
34
+ * stay folded; their summaries are rendered in place of their messages.
35
+ * The block's own direct messages (not covered by any active child) are
36
+ * rendered in full.
37
+ * full=true: recurse through all nested tiers; every effective message is
38
+ * rendered in full.
39
+ *
40
+ * Returns { text: "", count: 0 } when the block covers no messages.
41
+ */
42
+ export declare function collectBlockContent(state: CompressionState, block: CompressionBlock, messages: CoreMessage[], options?: CollectContentOptions): CollectedContentResult;
14
43
  //# sourceMappingURL=decompress.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decompress.d.ts","sourceRoot":"","sources":["../src/decompress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAElF,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO1D;AAED,wBAAgB,6BAA6B,CACzC,KAAK,EAAE,gBAAgB,EACvB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GACxB,gBAAgB,EAAE,CAUpB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiB1F;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,eAAe,CAC3B,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,GAAE,iBAAsB,GAChC,gBAAgB,CAkClB;AAED,MAAM,WAAW,qBAAqB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,2BAA2B,CACvC,QAAQ,EAAE,WAAW,EAAE,EACvB,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,EACnC,KAAK,EAAE,gBAAgB,GACxB,qBAAqB,CA8BvB"}
1
+ {"version":3,"file":"decompress.d.ts","sourceRoot":"","sources":["../src/decompress.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAElF,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAO1D;AAED,wBAAgB,6BAA6B,CACzC,KAAK,EAAE,gBAAgB,EACvB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GACxB,gBAAgB,EAAE,CAUpB;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiB1F;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,eAAe,CAC3B,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,GAAE,iBAAsB,GAChC,gBAAgB,CAkClB;AAED,MAAM,WAAW,qBAAqB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,2BAA2B,CACvC,QAAQ,EAAE,WAAW,EAAE,EACvB,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,EACnC,KAAK,EAAE,gBAAgB,GACxB,qBAAqB,CA8BvB;AAED,MAAM,WAAW,sBAAsB;IACnC,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,6GAA6G;IAC7G,KAAK,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IAClC,kKAAkK;IAClK,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAC/B,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,GAAE,qBAA0B,GACpC,sBAAsB,CAsCxB"}
package/dist/index.d.ts CHANGED
@@ -16,8 +16,8 @@ export { truncateLargeToolOutputs } from "./truncate-tools.js";
16
16
  export type { TruncateOptions, TruncateResult } from "./truncate-tools.js";
17
17
  export { resolveKeepMarkers } from "./keep-markers.js";
18
18
  export type { KeepMarkerResult } from "./keep-markers.js";
19
- export { parseBlockIdArg, findBlocksOverlappingMessages, findActiveAncestor, deactivateBlock, buildRestoredContentPreview, } from "./decompress.js";
20
- export type { DeactivateOptions } from "./decompress.js";
19
+ export { parseBlockIdArg, findBlocksOverlappingMessages, findActiveAncestor, deactivateBlock, buildRestoredContentPreview, collectBlockContent, } from "./decompress.js";
20
+ export type { DeactivateOptions, CollectedContentResult, CollectContentOptions } from "./decompress.js";
21
21
  export { buildStatusReport, buildRecap } from "./report.js";
22
22
  export type { StatusReportOptions } from "./report.js";
23
23
  export { hideConsumedCompressCalls } from "./hide-consumed.js";
@@ -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,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAChE,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"}
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,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAChE,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,EAC3B,mBAAmB,GACtB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxG,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
@@ -706,6 +706,14 @@ var renderRefsNode = {
706
706
 
707
707
  // src/protected.ts
708
708
  var ALWAYS_PROTECTED_TOOLS = ["compress"];
709
+ var NEVER_PRESERVE_RECENT_TOOLS = ["decompress"];
710
+ function isNeverPreserveRecent(msg) {
711
+ if (msg.contentType !== "tool-call" && msg.contentType !== "tool-result") {
712
+ return false;
713
+ }
714
+ if (!msg.toolName) return false;
715
+ return NEVER_PRESERVE_RECENT_TOOLS.includes(msg.toolName);
716
+ }
709
717
  function matchToolPattern(toolName, pattern) {
710
718
  if (pattern.endsWith("*")) {
711
719
  return toolName.startsWith(pattern.slice(0, -1));
@@ -802,6 +810,7 @@ function computeProtectedRefs(messages, state, config) {
802
810
  const visible = [];
803
811
  for (const msg of messages) {
804
812
  if (isSyntheticOrPruned(msg, state)) continue;
813
+ if (isNeverPreserveRecent(msg)) continue;
805
814
  const ref = state.messageRefs.byRaw[msg.id];
806
815
  if (!ref || ref === "BLOCKED") continue;
807
816
  visible.push({ ref, tokens: estimateMessageTokens(msg) });
@@ -946,6 +955,7 @@ function createCore(ports = {}) {
946
955
  let blocksCreated = 0;
947
956
  let tokensCompressed = 0;
948
957
  const errors = [];
958
+ const warnings = [];
949
959
  const protectedMessageIds = input.protectedMessageIds ?? computeProtectedRefs(input.messages, input.state, input.config);
950
960
  const preExistingCoverage = collectCoverage(state);
951
961
  const rangeIndexSets = [];
@@ -984,7 +994,8 @@ function createCore(ports = {}) {
984
994
  tokensCompressed: 0,
985
995
  errors: [
986
996
  `content: range (${prev.spec.startRef}..${prev.spec.endRef}) overlaps (${curr.spec.startRef}..${curr.spec.endRef}). Overlapping ranges cannot be compressed in the same batch.`
987
- ]
997
+ ],
998
+ warnings: []
988
999
  }
989
1000
  };
990
1001
  }
@@ -1021,14 +1032,15 @@ function createCore(ports = {}) {
1021
1032
  tokensCompressed: 0,
1022
1033
  errors: [
1023
1034
  `Total compressible content too small (${totalRangeChars} chars across ${input.ranges.length} range(s), min ${input.config.compress.minCompressRange}). Combine more messages into your range(s) to meet the threshold.`
1024
- ]
1035
+ ],
1036
+ warnings: []
1025
1037
  }
1026
1038
  };
1027
1039
  }
1028
1040
  }
1029
1041
  for (const spec of input.ranges) {
1030
1042
  try {
1031
- const compressed = applySingleRange({
1043
+ const outcome = applySingleRange({
1032
1044
  spec,
1033
1045
  messages: input.messages,
1034
1046
  state,
@@ -1039,7 +1051,8 @@ function createCore(ports = {}) {
1039
1051
  preExistingCoverage
1040
1052
  });
1041
1053
  blocksCreated++;
1042
- tokensCompressed += compressed;
1054
+ tokensCompressed += outcome.tokens;
1055
+ warnings.push(...outcome.warnings);
1043
1056
  } catch (error) {
1044
1057
  errors.push(error instanceof Error ? error.message : String(error));
1045
1058
  }
@@ -1051,7 +1064,7 @@ function createCore(ports = {}) {
1051
1064
  state.nudge.lastNudgeShownTokens = 0;
1052
1065
  state.nudge.lastShownByTier = {};
1053
1066
  }
1054
- return { state, result: { blocksCreated, tokensCompressed, errors } };
1067
+ return { state, result: { blocksCreated, tokensCompressed, errors, warnings } };
1055
1068
  }
1056
1069
  function processTurn(input) {
1057
1070
  const configErrors = validateConfig(input.config);
@@ -1234,6 +1247,7 @@ var emergencyTruncateNode = {
1234
1247
  }
1235
1248
  };
1236
1249
  function applySingleRange(input) {
1250
+ const warnings = [];
1237
1251
  const resolved = resolveBoundaries({
1238
1252
  startRef: input.spec.startRef,
1239
1253
  endRef: input.spec.endRef,
@@ -1281,7 +1295,7 @@ function applySingleRange(input) {
1281
1295
  const directMessageIds = [...effectiveMessageIds].filter(
1282
1296
  (id) => !input.preExistingCoverage.has(id)
1283
1297
  );
1284
- const filteredIds = filterProtectedToolMessages(
1298
+ let filteredIds = filterProtectedToolMessages(
1285
1299
  directMessageIds,
1286
1300
  input.messages,
1287
1301
  input.config
@@ -1292,12 +1306,22 @@ function applySingleRange(input) {
1292
1306
  return ref !== void 0 && protectedRefs.has(ref);
1293
1307
  }) : [];
1294
1308
  if (hitProtectedRaw.length > 0) {
1295
- const recentN = input.config.preserveRecentMessages;
1296
- const hitRefs = hitProtectedRaw.map((id) => input.state.messageRefs.byRaw[id]).filter(Boolean);
1297
- throw new Error(
1298
- `Range includes protected messages (the last ${recentN} messages and/or the most recent user message) which must not be compressed: ${hitRefs.join(
1309
+ const protectedSet = new Set(hitProtectedRaw);
1310
+ filteredIds = filteredIds.filter((id) => !protectedSet.has(id));
1311
+ for (const id of hitProtectedRaw) effectiveMessageIds.delete(id);
1312
+ const hitRefs = hitProtectedRaw.map((id) => input.state.messageRefs.byRaw[id]).filter((v) => typeof v === "string");
1313
+ if (filteredIds.length === 0 && consumedBlockIds.length === 0) {
1314
+ const recentN = input.config.preserveRecentMessages;
1315
+ throw new Error(
1316
+ `Range is entirely within the protected zone (the last ${recentN} messages and/or the most recent user message): ${hitRefs.join(
1317
+ ", "
1318
+ )}. Adjust startId/endId to older messages.`
1319
+ );
1320
+ }
1321
+ warnings.push(
1322
+ `Excluded ${hitProtectedRaw.length} protected message(s) ${hitRefs.join(
1299
1323
  ", "
1300
- )}. Adjust startId/endId to exclude them.`
1324
+ )} from compression range (recent/last-user zone).`
1301
1325
  );
1302
1326
  }
1303
1327
  validateCompressionRange(input, filteredIds, consumedBlockIds.length);
@@ -1334,7 +1358,7 @@ function applySingleRange(input) {
1334
1358
  const consumed = blockById(input.state, consumedId);
1335
1359
  if (consumed) consumed.active = false;
1336
1360
  }
1337
- return compressedTokens;
1361
+ return { tokens: compressedTokens, warnings };
1338
1362
  }
1339
1363
  function applyToolPairAdjustment(resolved, messages) {
1340
1364
  if (resolved.boundaryKind === "block") {
@@ -1500,7 +1524,7 @@ function decideNudge(input) {
1500
1524
  if (parts.length === 0) parts.push(`max compressible ${maxPending}, growth ${growthSinceReference}`);
1501
1525
  reason = `${parts.join("; ")}${readyHint}${blockedHint}`;
1502
1526
  }
1503
- const ctxBreakdown = computeContextBreakdown(input.messages, tokenCount, growthSinceReference);
1527
+ const ctxBreakdown = computeContextBreakdown(input.messages, tokenCount, growthSinceReference, countTokens);
1504
1528
  return {
1505
1529
  shouldInject,
1506
1530
  reason,
@@ -1525,10 +1549,11 @@ function decideNudge(input) {
1525
1549
  contextBreakdown: ctxBreakdown
1526
1550
  };
1527
1551
  }
1528
- function computeContextBreakdown(messages, total, growth) {
1552
+ function computeContextBreakdown(messages, total, growth, countTokens) {
1553
+ const count = countTokens ?? ((t) => Math.ceil(t.length / 4));
1529
1554
  let system = 0, tool = 0, summaries = 0, code = 0, text = 0;
1530
1555
  for (const msg of messages) {
1531
- const tokens = Math.ceil((msg.text ?? "").length / 4);
1556
+ const tokens = count(msg.text ?? "");
1532
1557
  if (msg.text?.startsWith("[Compressed conversation section]")) {
1533
1558
  summaries += tokens;
1534
1559
  } else if (msg.contentType === "tool-call" || msg.contentType === "tool-result") {
@@ -2021,6 +2046,48 @@ function buildRestoredContentPreview(messages, beforeActiveMessageIds, state) {
2021
2046
  }
2022
2047
  return { preview: lines.join("\n"), restoredCount: restored.length };
2023
2048
  }
2049
+ function collectBlockContent(state, block, messages, options = {}) {
2050
+ const full = options.full ?? false;
2051
+ const targetIds = new Set(block.effectiveMessageIds);
2052
+ if (full) {
2053
+ const msgs = messages.filter((m) => targetIds.has(m.id));
2054
+ if (msgs.length === 0) return { text: "", count: 0 };
2055
+ return { text: msgs.map(formatMessage).join("\n\n"), count: msgs.length };
2056
+ }
2057
+ const nestedChildren = [];
2058
+ const nestedCovered = /* @__PURE__ */ new Set();
2059
+ for (const childId of block.directBlockIds) {
2060
+ const child = state.blocks.find((b) => b.blockId === childId);
2061
+ if (!child?.active) continue;
2062
+ nestedChildren.push(child);
2063
+ for (const id of child.effectiveMessageIds) nestedCovered.add(id);
2064
+ }
2065
+ const parts = [];
2066
+ for (const child of nestedChildren) {
2067
+ const label = child.topic ? `${child.blockId}: ${child.topic}` : child.blockId;
2068
+ parts.push(`${SUMMARY_HEADER} \u2014 ${label}
2069
+ ${child.summary}`);
2070
+ }
2071
+ let directCount = 0;
2072
+ for (const m of messages) {
2073
+ if (targetIds.has(m.id) && !nestedCovered.has(m.id)) {
2074
+ parts.push(formatMessage(m));
2075
+ directCount++;
2076
+ }
2077
+ }
2078
+ const count = directCount + nestedChildren.length;
2079
+ if (count === 0) return { text: "", count: 0 };
2080
+ return { text: parts.join("\n\n"), count };
2081
+ }
2082
+ function formatMessage(message) {
2083
+ const text = message.text ?? "";
2084
+ if (message.toolName && message.contentType !== "text") {
2085
+ return `[${message.role} \u2022 ${message.toolName}]
2086
+ ${text}`;
2087
+ }
2088
+ return `[${message.role}]
2089
+ ${text}`;
2090
+ }
2024
2091
  function numericPart(blockId) {
2025
2092
  const match = /^b(\d+)$/.exec(blockId);
2026
2093
  return match && match[1] !== void 0 ? Number(match[1]) : 0;
@@ -2042,15 +2109,8 @@ function numericPart2(blockId) {
2042
2109
  function summaryTokensOf(block, countTokens) {
2043
2110
  return countTokens(block.summary);
2044
2111
  }
2045
- function effectiveCompressedTokens(block, state, countTokens, visited = /* @__PURE__ */ new Set()) {
2046
- if (visited.has(block.blockId)) return 0;
2047
- visited.add(block.blockId);
2048
- let total = block.compressedTokens;
2049
- for (const nestedId of block.directBlockIds) {
2050
- const nested = state.blocks.find((b) => b.blockId === nestedId);
2051
- if (nested) total += effectiveCompressedTokens(nested, state, countTokens, visited);
2052
- }
2053
- return total;
2112
+ function effectiveCompressedTokens(block, _state, _countTokens) {
2113
+ return block.compressedTokens;
2054
2114
  }
2055
2115
  function tierLabel(block) {
2056
2116
  return `T${block.tier}`;
@@ -2387,6 +2447,7 @@ export {
2387
2447
  buildRestoredContentPreview,
2388
2448
  buildStatusReport,
2389
2449
  clearMessageFilters,
2450
+ collectBlockContent,
2390
2451
  coveredMessageIds,
2391
2452
  createBpeTokenizer,
2392
2453
  createCore,