acp-kernel 0.0.18 → 0.0.19

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/index.js CHANGED
@@ -306,7 +306,7 @@ function defaultConfig(modelContextLimit, overrides = {}) {
306
306
  iterationThreshold: 15,
307
307
  force: "soft",
308
308
  growthRatio: 0.05,
309
- growthFloor: Math.max(2e4, Math.round(modelContextLimit * 0.05)),
309
+ growthFloor: 5e4,
310
310
  growthCap: 5e4,
311
311
  minGrowthFloor: 2e4,
312
312
  minGrowthRatio: 0.45,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/refs.ts","../src/state.ts","../src/prune.ts","../src/sync.ts","../src/tokenize.ts","../src/config.ts","../src/boundaries.ts","../src/truncate-tools.ts","../src/hide-consumed.ts","../src/filter/registry.ts","../src/filter/apply.ts","../src/render-refs.ts","../src/protected.ts","../src/tool-pairs.ts","../src/recommend.ts","../src/pipeline.ts","../src/compress.ts","../src/compression-rules.ts","../src/nudge-text.ts","../src/decompress.ts","../src/report.ts","../src/rebuild.ts","../src/search/algorithms/substring.ts","../src/search/stemmer.ts","../src/search/tokenizer.ts","../src/search/algorithms/bm25.ts","../src/search/algorithms/fuzzy.ts","../src/search/algorithms/hybrid.ts","../src/search/registry.ts","../src/search/types.ts","../src/search/index.ts"],"sourcesContent":["import type { CoreMessage, MessageRefMap } from \"./types.js\";\n\nconst REF_WIDTH = 5;\nconst MIN_INDEX = 1;\nconst MAX_INDEX = 99999;\nconst REF_PATTERN = /^m0*(\\d{1,5})$/;\n\nexport const BLOCKED_REF = \"BLOCKED\";\n\nexport function emptyRefMap(): MessageRefMap {\n return { byRaw: {}, byRef: {} };\n}\n\nexport function indexToRef(index: number): string {\n if (!Number.isInteger(index) || index < MIN_INDEX || index > MAX_INDEX) {\n throw new RangeError(\n `ref index out of bounds: ${index} (allowed ${MIN_INDEX}-${MAX_INDEX})`,\n );\n }\n return `m${String(index).padStart(REF_WIDTH, \"0\")}`;\n}\n\nexport function refToIndex(ref: string): number | null {\n const match = REF_PATTERN.exec(ref.trim().toLowerCase());\n if (!match) return null;\n const index = Number(match[1]);\n if (index < MIN_INDEX || index > MAX_INDEX) return null;\n return index;\n}\n\nexport function refForRaw(map: MessageRefMap, rawId: string): string | null {\n return map.byRaw[rawId] ?? null;\n}\n\nexport function rawForRef(map: MessageRefMap, ref: string): string | null {\n return map.byRef[ref] ?? null;\n}\n\nexport interface AssignRefsResult {\n map: MessageRefMap;\n nextIndex: number;\n newlyAssigned: number;\n}\n\nexport interface AssignRefsOptions {\n existing: MessageRefMap;\n nextIndex: number;\n isProtected?: (message: CoreMessage) => boolean;\n shouldSkip?: (message: CoreMessage) => boolean;\n}\n\nexport function assignRefs(\n messages: CoreMessage[],\n options: AssignRefsOptions,\n): AssignRefsResult {\n const map: MessageRefMap = {\n byRaw: { ...options.existing.byRaw },\n byRef: { ...options.existing.byRef },\n };\n let cursor =\n Number.isInteger(options.nextIndex) && options.nextIndex >= MIN_INDEX\n ? options.nextIndex\n : MIN_INDEX;\n let newlyAssigned = 0;\n\n for (const message of messages) {\n if (!message.id || options.shouldSkip?.(message)) continue;\n\n if (map.byRaw[message.id]) continue;\n\n if (options.isProtected?.(message)) {\n map.byRaw[message.id] = BLOCKED_REF;\n continue;\n }\n\n const ref = allocateFreeRef(map, cursor);\n cursor = ref.index + 1;\n map.byRaw[message.id] = ref.text;\n map.byRef[ref.text] = message.id;\n newlyAssigned++;\n }\n\n return { map, nextIndex: cursor, newlyAssigned };\n}\n\nfunction allocateFreeRef(\n map: MessageRefMap,\n start: number,\n): { text: string; index: number } {\n let candidate = Math.max(start, MIN_INDEX);\n while (candidate <= MAX_INDEX) {\n const text = indexToRef(candidate);\n if (!map.byRef[text]) {\n return { text, index: candidate };\n }\n candidate++;\n }\n throw new Error(\n `ref capacity exhausted: cannot allocate beyond ${indexToRef(MAX_INDEX)}`,\n );\n}\n\nexport function rebuildRefIndex(map: MessageRefMap): MessageRefMap {\n const byRef: Record<string, string> = {};\n for (const [rawId, ref] of Object.entries(map.byRaw)) {\n if (ref !== BLOCKED_REF) byRef[ref] = rawId;\n }\n return { byRaw: { ...map.byRaw }, byRef };\n}\n\nexport function highestUsedIndex(map: MessageRefMap): number {\n let highest = 0;\n for (const ref of Object.values(map.byRaw)) {\n const index = ref === BLOCKED_REF ? null : refToIndex(ref);\n if (index !== null && index > highest) highest = index;\n }\n return highest;\n}\n","import type { CompressionBlock, CompressionState } from \"./types.js\";\n\nexport function createInitialState(): CompressionState {\n return {\n blocks: [],\n messageRefs: { byRaw: {}, byRef: {} },\n nudge: {\n lastPerMessageNudgeTokens: 0,\n lastNudgeShownTokens: 0,\n baselineTokens: 0,\n anchors: {},\n lastShownByTier: {},\n },\n stats: { tokensCompressed: 0, compressionCount: 0 },\n nextBlockId: 1,\n nextRunId: 1,\n };\n}\n\nexport function allocateBlockId(state: CompressionState): string {\n const id = state.nextBlockId;\n state.nextBlockId = Math.max(1, id) + 1;\n return `b${id}`;\n}\n\nexport function allocateRunId(state: CompressionState): string {\n const id = state.nextRunId;\n state.nextRunId = Math.max(1, id) + 1;\n return `r${id}`;\n}\n\nexport function blockById(\n state: CompressionState,\n blockId: string,\n): CompressionBlock | undefined {\n return state.blocks.find((block) => block.blockId === blockId);\n}\n\nexport function activeBlocks(state: CompressionState): CompressionBlock[] {\n return state.blocks.filter((block) => block.active);\n}\n\nexport function coveredMessageIds(state: CompressionState): Set<string> {\n const covered = new Set<string>();\n for (const block of state.blocks) {\n if (!block.active) continue;\n for (const id of block.effectiveMessageIds) covered.add(id);\n }\n return covered;\n}\n\nexport function highestActiveTier(state: CompressionState): 0 | 1 | 2 | 3 {\n let highest: 0 | 1 | 2 | 3 = 0;\n for (const block of state.blocks) {\n if (block.active && block.tier > highest) highest = block.tier;\n }\n return highest;\n}\n\nexport function advanceSurvival(\n state: CompressionState,\n promotionThreshold: number,\n): void {\n for (const block of state.blocks) {\n if (!block.active) continue;\n block.survivedCount += 1;\n if (block.survivedCount >= promotionThreshold) {\n block.generation = \"old\";\n }\n }\n}\n","import { activeBlocks, coveredMessageIds } from \"./state.js\";\nimport type { CompressionState, CoreMessage } from \"./types.js\";\n\nexport const SUMMARY_HEADER = \"[Compressed conversation section]\";\n\nexport interface PruneOptions {\n injectSummaries?: boolean;\n}\n\nexport function prune(\n messages: CoreMessage[],\n state: CompressionState,\n options: PruneOptions = {},\n): CoreMessage[] {\n const covered = coveredMessageIds(state);\n if (covered.size === 0) return [...messages];\n\n const inject = options.injectSummaries ?? true;\n const firstUserIndex = messages.findIndex(\n (message) => message.role === \"user\",\n );\n\n const indexById = new Map<string, number>();\n messages.forEach((message, index) => indexById.set(message.id, index));\n\n const anchors = inject ? collectSummaryAnchors(state, indexById) : [];\n\n return stripOrphanedToolResults(\n stripOrphanedToolCalls(\n rebuildMessages(messages, covered, firstUserIndex, anchors),\n ),\n );\n}\n\ninterface SummaryAnchor {\n blockId: string;\n summary: string;\n topic?: string;\n insertAt: number;\n}\n\nfunction collectSummaryAnchors(\n state: CompressionState,\n indexById: Map<string, number>,\n): SummaryAnchor[] {\n const anchors: SummaryAnchor[] = [];\n for (const block of activeBlocks(state)) {\n let earliest: number | null = null;\n for (const id of block.effectiveMessageIds) {\n const index = indexById.get(id);\n if (index !== undefined && (earliest === null || index < earliest)) {\n earliest = index;\n }\n }\n anchors.push({\n blockId: block.blockId,\n summary: block.summary,\n topic: block.topic,\n insertAt: earliest ?? 0,\n });\n }\n anchors.sort((left, right) => left.insertAt - right.insertAt);\n return anchors;\n}\n\nfunction rebuildMessages(\n messages: CoreMessage[],\n covered: Set<string>,\n firstUserIndex: number,\n anchors: SummaryAnchor[],\n): CoreMessage[] {\n const result: CoreMessage[] = [];\n const pending = [...anchors];\n\n for (let index = 0; index < messages.length; index++) {\n while (pending.length > 0 && pending[0]!.insertAt === index) {\n result.push(renderSummary(pending.shift()!));\n }\n if (index === firstUserIndex && firstUserIndex >= 0) {\n result.push(messages[index]!);\n continue;\n }\n if (covered.has(messages[index]!.id)) continue;\n result.push(messages[index]!);\n }\n\n while (pending.length > 0) {\n result.push(renderSummary(pending.shift()!));\n }\n\n return result;\n}\n\nfunction renderSummary(anchor: SummaryAnchor): CoreMessage {\n const body = anchor.summary.trim();\n const topicLine = anchor.topic\n ? `${SUMMARY_HEADER} — ${anchor.topic}`\n : SUMMARY_HEADER;\n const text = body.length === 0 ? topicLine : `${topicLine}\\n${body}`;\n return {\n id: `acp_summary_${anchor.blockId}`,\n role: \"system\",\n contentType: \"text\",\n text,\n };\n}\n\nfunction stripOrphanedToolResults(messages: CoreMessage[]): CoreMessage[] {\n const knownCallIds = new Set<string>();\n for (const m of messages) {\n if (m.contentType === \"tool-call\" && m.toolCallId) {\n knownCallIds.add(m.toolCallId);\n }\n }\n return messages.filter(\n (m) =>\n m.contentType !== \"tool-result\" ||\n !m.toolCallId ||\n knownCallIds.has(m.toolCallId),\n );\n}\n\nfunction stripOrphanedToolCalls(messages: CoreMessage[]): CoreMessage[] {\n const knownResultIds = new Set<string>();\n for (const m of messages) {\n if (m.contentType === \"tool-result\" && m.toolCallId) {\n knownResultIds.add(m.toolCallId);\n }\n }\n return messages.filter(\n (m) =>\n m.contentType !== \"tool-call\" ||\n !m.toolCallId ||\n m.toolName === \"compress\" ||\n knownResultIds.has(m.toolCallId),\n );\n}\n","import type { CompressionState, CoreMessage } from \"./types.js\";\n\nexport interface SyncResult {\n state: CompressionState;\n deactivated: string[];\n}\n\nexport function syncBlocks(\n messages: CoreMessage[],\n state: CompressionState,\n): SyncResult {\n const presentIds = new Set(messages.map((message) => message.id));\n const deactivated: string[] = [];\n // Deep-clone (not just `{...state}`) so the caller's input state is never\n // mutated: processTurn stamps `state.nudge.*` and reassigns `messageRefs`,\n // and block sub-arrays must not alias the input. Previously nudge/stats/\n // messageRefs were shared references → input-state mutation leak.\n const result: CompressionState = {\n blocks: state.blocks.map((block) => ({\n ...block,\n directMessageIds: [...block.directMessageIds],\n effectiveMessageIds: [...block.effectiveMessageIds],\n directBlockIds: [...block.directBlockIds],\n })),\n messageRefs: {\n byRaw: { ...state.messageRefs.byRaw },\n byRef: { ...state.messageRefs.byRef },\n },\n nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },\n stats: { ...state.stats },\n nextBlockId: state.nextBlockId,\n nextRunId: state.nextRunId,\n };\n\n const consumedBlockIds = new Set<string>();\n for (const block of result.blocks) {\n for (const consumedId of block.directBlockIds) {\n consumedBlockIds.add(consumedId);\n }\n }\n\n for (const block of result.blocks) {\n if (consumedBlockIds.has(block.blockId)) {\n block.active = false;\n continue;\n }\n block.active = true;\n const stillPresent = block.effectiveMessageIds.some((id) =>\n presentIds.has(id),\n );\n if (!stillPresent) {\n block.active = false;\n deactivated.push(block.blockId);\n }\n }\n\n return { state: result, deactivated };\n}\n","import { createRequire } from \"node:module\";\n\nconst require = createRequire(import.meta.url);\n\nexport function defaultCountTokens(text: string): number {\n if (!text) return 0;\n // CJK chars tokenize ~1:1 (chars/4 badly underestimates them). Count them\n // directly, then estimate the non-CJK remainder with chars/4 so digits,\n // punctuation, and symbols in code/JSON are not dropped to zero.\n const cjk = text.match(/[\\u4e00-\\u9fff\\u3040-\\u30ff\\uac00-\\ud7af]/g);\n const cjkCount = cjk?.length ?? 0;\n return cjkCount + Math.ceil((text.length - cjkCount) / 4);\n}\n\nexport function estimateMessageTokens(text: string | undefined): number {\n return defaultCountTokens(text ?? \"\");\n}\n\nexport function estimateTokensFast(text: string): number {\n if (!text) return 0;\n return Math.ceil(text.length / 4);\n}\n\nexport type TokenCountFn = (text: string) => number;\n\nexport function createBpeTokenizer(): TokenCountFn {\n try {\n const mod = require(\"@anthropic-ai/tokenizer\");\n const bpeCount = mod.countTokens ?? mod.default?.countTokens;\n if (typeof bpeCount !== \"function\") return defaultCountTokens;\n return (text: string) => {\n try {\n return bpeCount(text);\n } catch {\n return defaultCountTokens(text);\n }\n };\n } catch {\n return defaultCountTokens;\n }\n}\n","import type { Config } from \"./types.js\";\n\nexport function defaultConfig(\n modelContextLimit: number,\n overrides: Partial<Config> = {},\n): Config {\n const base: Config = {\n tiers: { enabled: true, tier2Trigger: 5, tier3Trigger: 10 },\n nudge: {\n maxContextLimitPct: 0.55,\n minContextLimitPct: 0.45,\n frequency: 5,\n iterationThreshold: 15,\n force: \"soft\",\n growthRatio: 0.05,\n growthFloor: Math.max(20000, Math.round(modelContextLimit * 0.05)),\n growthCap: 50000,\n minGrowthFloor: 20000,\n minGrowthRatio: 0.45,\n emergencyThresholdPct: 0.80,\n },\n promotionThreshold: 5,\n truncate: { threshold: 1 },\n compress: {\n minCompressRange: 5000,\n maxSummaryLength: 20000,\n minSummaryLength: 50,\n },\n protectedTools: [],\n preserveRecentMessages: 5,\n preserveRecentTokens: 5000,\n modelContextLimit,\n };\n return {\n ...base,\n ...overrides,\n tiers: { ...base.tiers, ...overrides.tiers },\n nudge: { ...base.nudge, ...overrides.nudge },\n truncate: { ...base.truncate, ...overrides.truncate },\n compress: { ...base.compress, ...overrides.compress },\n };\n}\n\nexport function validateConfig(config: Config): string[] {\n const errors: string[] = [];\n if (\n !Number.isFinite(config.modelContextLimit) ||\n config.modelContextLimit <= 0\n ) {\n errors.push(\"modelContextLimit must be a positive number\");\n }\n if (config.nudge.minContextLimitPct > config.nudge.maxContextLimitPct) {\n errors.push(\n \"nudge.minContextLimitPct must not exceed nudge.maxContextLimitPct\",\n );\n }\n if (config.promotionThreshold < 1) {\n errors.push(\"promotionThreshold must be >= 1\");\n }\n if (config.truncate.threshold <= 0 || config.truncate.threshold > 1) {\n errors.push(\"truncate.threshold must be in (0, 1]\");\n }\n for (const tier of [config.tiers.tier2Trigger, config.tiers.tier3Trigger]) {\n if (tier < 1) errors.push(\"tier triggers must be >= 1\");\n }\n if (config.tiers.tier3Trigger <= config.tiers.tier2Trigger) {\n errors.push(\"tiers.tier3Trigger must be greater than tiers.tier2Trigger\");\n }\n return errors;\n}\n","import { activeBlocks, blockById } from \"./state.js\";\nimport type {\n CompressionState,\n CoreMessage,\n ResolvedBoundary,\n} from \"./types.js\";\n\nexport type BoundaryKind = \"message\" | \"block\";\n\nexport interface ParsedBoundary {\n kind: BoundaryKind;\n numericId: number;\n raw: string;\n}\n\nconst MESSAGE_REF_PATTERN = /^m0*(\\d{1,5})$/;\nconst BLOCK_REF_PATTERN = /^b(\\d{1,9})$/;\n\nexport function parseBoundary(ref: string): ParsedBoundary | null {\n const normalized = ref.trim().toLowerCase();\n const messageMatch = MESSAGE_REF_PATTERN.exec(normalized);\n if (messageMatch) {\n const numericId = Number(messageMatch[1]);\n if (numericId >= 1 && numericId <= 99999) {\n return { kind: \"message\", numericId, raw: normalized };\n }\n }\n const blockMatch = BLOCK_REF_PATTERN.exec(normalized);\n if (blockMatch) {\n const numericId = Number(blockMatch[1]);\n if (numericId >= 1) return { kind: \"block\", numericId, raw: normalized };\n }\n return null;\n}\n\nexport interface ResolveBoundariesInput {\n startRef: string;\n endRef: string;\n messages: CoreMessage[];\n state: CompressionState;\n}\n\nexport interface ResolvedRange {\n startIndex: number;\n endIndex: number;\n messageIds: string[];\n nestedBlockIds: string[];\n boundaryKind: BoundaryKind;\n protectedGaps: number[];\n}\n\nexport function resolveBoundaries(\n input: ResolveBoundariesInput,\n): ResolvedRange {\n const start = parseBoundary(input.startRef);\n const end = parseBoundary(input.endRef);\n if (!start || !end) {\n throw new Error(\n `Invalid boundary ref(s): startId=\"${input.startRef}\", endId=\"${input.endRef}\". Use mNNNNN or bN.`,\n );\n }\n\n const indexByRawId = new Map<string, number>();\n input.messages.forEach((message, index) =>\n indexByRawId.set(message.id, index),\n );\n\n let startIndex = resolveAnchorIndex(start, input.state, indexByRawId);\n let endIndex = resolveAnchorIndex(end, input.state, indexByRawId);\n\n if (startIndex === null || endIndex === null) {\n throw new Error(\n `Boundary not found in visible context (likely consumed by an existing block). ` +\n `startId=\"${input.startRef}\", endId=\"${input.endRef}\".`,\n );\n }\n\n if (startIndex > endIndex) {\n [startIndex, endIndex] = [endIndex, startIndex];\n }\n\n const messageIds: string[] = [];\n for (let index = startIndex; index <= endIndex; index++) {\n const message = input.messages[index];\n if (message) messageIds.push(message.id);\n }\n\n const boundaryKind: BoundaryKind =\n start.kind === \"block\" || end.kind === \"block\" ? \"block\" : \"message\";\n\n const nestedBlockIds: string[] = [];\n const nestedSeen = new Set<string>();\n for (const block of activeBlocks(input.state)) {\n const anchor = earliestIndexOfIds(block.effectiveMessageIds, indexByRawId);\n if (anchor !== null && anchor >= startIndex && anchor <= endIndex) {\n if (!nestedSeen.has(block.blockId)) {\n nestedSeen.add(block.blockId);\n nestedBlockIds.push(block.blockId);\n }\n }\n }\n\n const protectedGaps: number[] = [];\n\n return {\n startIndex,\n endIndex,\n messageIds,\n nestedBlockIds,\n boundaryKind,\n protectedGaps,\n };\n}\n\nfunction resolveAnchorIndex(\n boundary: ParsedBoundary,\n state: CompressionState,\n indexByRawId: Map<string, number>,\n): number | null {\n if (boundary.kind === \"message\") {\n const rawId =\n state.messageRefs.byRef[boundary.raw] ??\n state.messageRefs.byRef[formatPaddedRef(boundary.numericId)];\n if (!rawId) return null;\n const index = indexByRawId.get(rawId);\n return index === undefined ? null : index;\n }\n\n const block = blockById(state, `b${boundary.numericId}`);\n if (!block || !block.active) return null;\n return earliestIndexOfIds(block.effectiveMessageIds, indexByRawId);\n}\n\nfunction formatPaddedRef(index: number): string {\n return `m${String(index).padStart(5, \"0\")}`;\n}\n\nexport function earliestIndexOfIds(\n ids: string[],\n indexByRawId: Map<string, number>,\n): number | null {\n let earliest: number | null = null;\n for (const id of ids) {\n const index = indexByRawId.get(id);\n if (index !== undefined && (earliest === null || index < earliest)) {\n earliest = index;\n }\n }\n return earliest;\n}\n\nexport function toResolvedBoundary(range: ResolvedRange): ResolvedBoundary {\n return {\n startIndex: range.startIndex,\n endIndex: range.endIndex,\n protectedGaps: range.protectedGaps,\n };\n}\n","import type { Config, CoreMessage } from \"./types.js\";\n\nexport interface TruncateOptions {\n minOutputTokens?: number;\n keepPrefixChars?: number;\n keepSuffixChars?: number;\n protectRecentMessages?: number;\n}\n\nexport interface TruncateResult {\n messages: CoreMessage[];\n truncatedCount: number;\n savedTokens: number;\n}\n\nconst TRUNCATION_MARKER = \"[truncated for context space]\";\nconst DEFAULTS = {\n minOutputTokens: 1000,\n keepPrefixChars: 2000,\n keepSuffixChars: 2000,\n protectRecentMessages: 3,\n} as const;\n\nexport function truncateLargeToolOutputs(\n messages: CoreMessage[],\n tokenCount: number,\n config: Config,\n countTokens: (text: string) => number,\n options: TruncateOptions = {},\n): TruncateResult {\n const opts = { ...DEFAULTS, ...options };\n if (config.modelContextLimit <= 0) return { messages, truncatedCount: 0, savedTokens: 0 };\n\n const threshold = config.truncate.threshold * config.modelContextLimit;\n if (tokenCount < threshold) return { messages, truncatedCount: 0, savedTokens: 0 };\n\n const protectedIndex = messages.length - opts.protectRecentMessages;\n const candidates: Array<{ index: number; tokens: number }> = [];\n\n for (let index = 0; index < messages.length; index++) {\n if (index >= protectedIndex) break;\n const message = messages[index]!;\n if (message.contentType !== \"tool-result\") continue;\n const text = message.text ?? \"\";\n if (text.length === 0 || text.includes(TRUNCATION_MARKER)) continue;\n const tokens = countTokens(text);\n if (tokens < opts.minOutputTokens) continue;\n candidates.push({ index, tokens });\n }\n\n if (candidates.length === 0) return { messages, truncatedCount: 0, savedTokens: 0 };\n candidates.sort((left, right) => right.tokens - left.tokens);\n\n const targetTokens = threshold * 0.9;\n let savedTokens = 0;\n const edits = new Map<number, string>();\n let truncatedCount = 0;\n\n for (const candidate of candidates) {\n if (tokenCount - savedTokens <= targetTokens) break;\n const original = messages[candidate.index]!.text ?? \"\";\n if (original.length <= opts.keepPrefixChars + opts.keepSuffixChars) continue;\n\n const prefix = original.slice(0, opts.keepPrefixChars);\n const suffix = original.slice(-opts.keepSuffixChars);\n const replacement =\n prefix +\n `\\n\\n...${TRUNCATION_MARKER} — original ~${candidate.tokens} tokens]...\\n\\n` +\n suffix;\n edits.set(candidate.index, replacement);\n savedTokens += candidate.tokens - countTokens(replacement);\n truncatedCount++;\n }\n\n if (truncatedCount === 0) return { messages, truncatedCount: 0, savedTokens: 0 };\n\n const updated = messages.map((message, index) =>\n edits.has(index) ? { ...message, text: edits.get(index)! } : message,\n );\n return { messages: updated, truncatedCount, savedTokens };\n}\n","import type { CompressionState, CoreMessage } from \"./types.js\";\n\nconst KEEP_LAST_ORPHANED = 0;\n\nexport interface HideConsumedResult {\n messages: CoreMessage[];\n hidden: number;\n}\n\nfunction rangeKey(startRef: string, endRef: string): string {\n return `${startRef}::${endRef}`;\n}\n\nfunction rewriteCompressText(text: string | undefined, liveKeys: Set<string>): string | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text ?? \"\");\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== \"object\") return null;\n const obj = parsed as { content?: unknown };\n const content = obj.content;\n if (!Array.isArray(content) || content.length === 0) return null;\n\n const kept = content.filter((entry): entry is Record<string, unknown> => {\n if (!entry || typeof entry !== \"object\") return false;\n const s = typeof entry.startId === \"string\" ? entry.startId : typeof entry.messageId === \"string\" ? entry.messageId : \"\";\n const e = typeof entry.endId === \"string\" ? entry.endId : typeof entry.messageId === \"string\" ? entry.messageId : \"\";\n return liveKeys.has(rangeKey(s, e));\n });\n\n if (kept.length === content.length || kept.length === 0) return null;\n\n return JSON.stringify({ ...obj, content: kept });\n}\n\nexport function hideConsumedCompressCalls(\n state: CompressionState,\n messages: CoreMessage[],\n): HideConsumedResult {\n const allBlockCallIds = new Set<string>();\n const activeCallIds = new Set<string>();\n const liveRangeKeysByCallId = new Map<string, Set<string>>();\n const legacyLiveByCallId = new Set<string>();\n for (const block of state.blocks) {\n if (!block.compressCallId) continue;\n allBlockCallIds.add(block.compressCallId);\n if (!block.active) continue;\n activeCallIds.add(block.compressCallId);\n if (block.startRef === undefined || block.endRef === undefined) {\n legacyLiveByCallId.add(block.compressCallId);\n continue;\n }\n let keys = liveRangeKeysByCallId.get(block.compressCallId);\n if (!keys) {\n keys = new Set<string>();\n liveRangeKeysByCallId.set(block.compressCallId, keys);\n }\n keys.add(rangeKey(block.startRef, block.endRef));\n }\n\n const lastOrphanedCallIds: string[] = [];\n for (let i = messages.length - 1; i >= 0 && lastOrphanedCallIds.length < KEEP_LAST_ORPHANED; i--) {\n const message = messages[i]!;\n if (message.toolName !== \"compress\" || message.contentType !== \"tool-call\") continue;\n const callId = message.toolCallId;\n if (callId && !allBlockCallIds.has(callId)) {\n lastOrphanedCallIds.push(callId);\n }\n }\n\n const keepCallIds = new Set([...activeCallIds, ...lastOrphanedCallIds]);\n\n const hiddenCallIds = new Set<string>();\n for (const message of messages) {\n if (\n message.toolName === \"compress\" &&\n message.contentType === \"tool-call\" &&\n (!message.toolCallId || !keepCallIds.has(message.toolCallId))\n ) {\n if (message.toolCallId) hiddenCallIds.add(message.toolCallId);\n }\n }\n\n let hidden = 0;\n const result: CoreMessage[] = [];\n for (const message of messages) {\n if (\n message.toolName === \"compress\" &&\n message.contentType === \"tool-call\" &&\n (!message.toolCallId || !keepCallIds.has(message.toolCallId))\n ) {\n hidden++;\n continue;\n }\n if (\n message.contentType === \"tool-result\" &&\n message.toolCallId &&\n hiddenCallIds.has(message.toolCallId)\n ) {\n hidden++;\n continue;\n }\n if (\n message.toolName === \"compress\" &&\n message.contentType === \"tool-call\" &&\n message.toolCallId &&\n keepCallIds.has(message.toolCallId)\n ) {\n const liveKeys = liveRangeKeysByCallId.get(message.toolCallId);\n if (liveKeys && liveKeys.size > 0 && !legacyLiveByCallId.has(message.toolCallId)) {\n const rewritten = rewriteCompressText(message.text, liveKeys);\n if (rewritten !== null) {\n result.push({ ...message, text: rewritten });\n continue;\n }\n }\n }\n result.push(message);\n }\n\n return { messages: result, hidden };\n}\n","import type { MessageFilter } from \"./types.js\";\n\nconst registry = new Map<string, MessageFilter>();\n\nexport function registerMessageFilter(filter: MessageFilter): void {\n const existing = registry.get(filter.name);\n if (existing && existing.version !== filter.version) {\n throw new Error(\n `Message filter \"${filter.name}\" already registered with version ${existing.version}, cannot register version ${filter.version}.`,\n );\n }\n registry.set(filter.name, filter);\n}\n\nexport function getMessageFilter(name: string): MessageFilter | undefined {\n return registry.get(name);\n}\n\nexport function listMessageFilters(): MessageFilter[] {\n return [...registry.values()];\n}\n\nexport function clearMessageFilters(): void {\n registry.clear();\n}\n","import { listMessageFilters } from \"./registry.js\";\nimport type { CoreMessage } from \"../types.js\";\nimport type { FilterResult, MessageFilterContext, MessageFiltersConfig } from \"./types.js\";\n\nexport interface ApplyResult {\n messages: CoreMessage[];\n partsFiltered: number;\n partsDropped: number;\n partsModified: number;\n}\n\nexport function applyMessageFilters(\n messages: CoreMessage[],\n config: MessageFiltersConfig | undefined,\n): ApplyResult {\n if (!config?.enabled) {\n return { messages, partsFiltered: 0, partsDropped: 0, partsModified: 0 };\n }\n\n const active = listMessageFilters().filter(\n (filter) => config.filters?.[filter.name]?.enabled !== false,\n );\n if (active.length === 0) {\n return { messages, partsFiltered: 0, partsDropped: 0, partsModified: 0 };\n }\n\n let working = messages.map((message) => ({ ...message }));\n const tally = { partsFiltered: 0, partsDropped: 0, partsModified: 0 };\n const total = working.length;\n\n const immediate = active.filter((filter) => !filter.keepLastOnly);\n for (let index = 0; index < working.length; index++) {\n const message = working[index]!;\n const text = message.text ?? \"\";\n if (text.length === 0) continue;\n let current = text;\n const baseCtx: MessageFilterContext = {\n text: current,\n role: message.role,\n messageIndex: index,\n totalMessages: total,\n toolName: message.toolName,\n };\n for (const filter of immediate) {\n let decision: FilterResult;\n try {\n decision = filter.filter(baseCtx);\n } catch {\n continue;\n }\n if (decision.action === \"keep\") continue;\n tally.partsFiltered++;\n if (decision.action === \"drop\") {\n current = \"\";\n tally.partsDropped++;\n } else if (decision.action === \"modify\" && decision.text !== undefined) {\n current = decision.text;\n tally.partsModified++;\n }\n baseCtx.text = current;\n }\n if (current !== text) working[index] = { ...message, text: current };\n }\n\n const keepLast = active.filter((filter) => filter.keepLastOnly);\n for (const filter of keepLast) {\n let foundLast = false;\n for (let index = working.length - 1; index >= 0; index--) {\n const message = working[index]!;\n const text = message.text ?? \"\";\n if (text.length === 0) continue;\n const ctx: MessageFilterContext = {\n text,\n role: message.role,\n messageIndex: index,\n totalMessages: total,\n toolName: message.toolName,\n };\n let decision: FilterResult;\n try {\n decision = filter.filter(ctx);\n } catch {\n continue;\n }\n if (decision.action !== \"drop\" && decision.action !== \"modify\") continue;\n if (foundLast) {\n tally.partsFiltered++;\n tally.partsDropped++;\n working[index] = { ...message, text: \"\" };\n } else {\n foundLast = true;\n if (decision.action === \"modify\" && decision.text !== undefined) {\n tally.partsFiltered++;\n tally.partsModified++;\n working[index] = { ...message, text: decision.text };\n }\n }\n }\n }\n\n return { messages: working, ...tally };\n}\n","import type { CoreMessage, CompressionState, MessageRefMap } from \"./types.js\";\nimport { refForRaw, BLOCKED_REF } from \"./refs.js\";\nimport type { PipelineNode, PipelineContext, NodeIO } from \"./pipeline.js\";\n\n/**\n * Controls which messages get an <acp> ref tag injected into their text.\n * Ref assignment (assignRefsNode) is unconditional — every message always\n * receives a ref in state.messageRefs regardless of this setting. This only\n * governs text rendering:\n * - \"all\": tag every mapped message (in-process hosts like pai-acp)\n * - \"text-only\": tag only user/assistant text; leave tool-call args and\n * tool-result content pristine (proxy hosts — structured content must not\n * be polluted)\n * - \"none\": leave all text untouched (hosts that read the ref map directly)\n */\nexport type RenderStrategy = \"all\" | \"text-only\" | \"none\";\n\n/** Format token count: <1K raw, <10K \"X.YK\", >=10K \"XK\". */\nfunction formatTokens(tokens: number): string {\n if (tokens < 1000) return String(tokens);\n if (tokens < 10000) return (tokens / 1000).toFixed(1) + \"K\";\n return Math.round(tokens / 1000) + \"K\";\n}\n\nfunction classifyType(message: CoreMessage): string {\n if (\n message.contentType === \"tool-call\" ||\n message.contentType === \"tool-result\"\n ) {\n return message.toolName || \"tool\";\n }\n return message.contentType;\n}\n\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nconst LT = \"\\x3c\";\nconst GT = \"\\x3e\";\nconst TAG_OPEN = LT + \"acp \";\nconst TAG_CLOSE = LT + \"/acp\" + GT;\n\nfunction acpTag(ref: string, tokens: number, type: string): string {\n return TAG_OPEN + 'tokens=\"' + formatTokens(tokens) + '\" type=\"' + type + '\"' + GT + ref + TAG_CLOSE;\n}\n\nfunction renderMessage(\n message: CoreMessage,\n map: MessageRefMap,\n countTokens: (text: string) => number,\n strategy: RenderStrategy,\n): CoreMessage {\n const ref = refForRaw(map, message.id);\n if (!ref || ref === BLOCKED_REF) return message;\n\n // \"none\": host reads the ref map directly — never pollute text.\n if (strategy === \"none\") return message;\n\n // text-only: never tag structured tool content. Refs are still assigned.\n if (strategy === \"text-only\" && message.contentType !== \"text\") {\n return message;\n }\n\n // Strip own stale tag BEFORE computing tokens (idempotency).\n // Match the message's own ref only — foreign tags survive (content-corruption fix).\n const ownTagRe = new RegExp(\n \"^\" + escapeRegex(TAG_OPEN) + \"[^>]*\" + GT + escapeRegex(ref) + escapeRegex(TAG_CLOSE) + \"\\\\n?\",\n );\n const cleanText = (message.text || \"\").replace(ownTagRe, \"\");\n\n const tokens = countTokens(cleanText);\n const type = classifyType(message);\n const prefix = acpTag(ref, tokens, type) + \"\\n\";\n\n if (!cleanText) return { ...message, text: prefix };\n return { ...message, text: prefix + cleanText };\n}\n\nexport function renderVisibleRefs(\n messages: CoreMessage[],\n state: CompressionState,\n countTokens: (text: string) => number = (text) =>\n Math.ceil(text.length / 4),\n strategy: RenderStrategy = \"all\",\n): CoreMessage[] {\n const map = state.messageRefs;\n return messages.map((message) =>\n renderMessage(message, map, countTokens, strategy),\n );\n}\n\n/** Factory: build a render-refs node bound to a specific render strategy. */\nexport function createRenderRefsNode(strategy: RenderStrategy): PipelineNode {\n return {\n name: \"render-refs\",\n run(io: NodeIO, ctx: PipelineContext): NodeIO {\n return {\n ...io,\n messages: renderVisibleRefs(io.messages, io.state, ctx.countTokens, strategy),\n };\n },\n };\n}\n\n/** Backward compat: default render-refs node using strategy \"all\". */\nexport const renderRefsNode: PipelineNode = createRenderRefsNode(\"all\");\n","import type { Config, CoreMessage } from \"./types.js\";\n\n/** Tools that are ALWAYS protected, regardless of user config. These are ACP's\n * own metadata tools whose records must remain in context: compress calls\n * carry the summaries that decompress/search rely on, and the system prompt\n * treats past compress calls as load-bearing metadata. Letting them be\n * compressed away breaks decompress and the \"summary is historical\" contract. */\nexport const ALWAYS_PROTECTED_TOOLS = [\"compress\"] as const;\n\n/** Tool results that must NEVER participate in the soft-protected recent zone\n * (preserveRecentMessages / preserveRecentTokens / last user message).\n *\n * These tools return large content (restored blocks, search hits, file bodies,\n * command output). If such a result lands in the last-N window it becomes\n * un-compressible: the model cannot reclaim that context, and it never appears\n * in the compressible-ranges recommendation list. Excluding these tools from\n * the protected zone lets the model compress them again immediately, while\n * still leaving them visible (the host's preserveRecent is about not\n * compressing the active working set, not about which tool results are in\n * scope).\n *\n * - `decompress`: large restored content as an inline tool result.\n * - `search_context`: large result lists (10 ranked hits with previews).\n * - `read`: file/image contents — the largest common source of context bloat.\n * - `bash`: command output (build/test/logs) — frequently large and spent.\n *\n * Note: this only affects the recent-zone computation. Such messages remain\n * fully visible and compressible like any ordinary message. */\nexport const NEVER_PRESERVE_RECENT_TOOLS = [\n \"decompress\",\n \"search_context\",\n \"read\",\n \"bash\",\n] as const;\n\n/** True for tool-call / tool-result messages whose toolName is in the\n * NEVER_PRESERVE_RECENT_TOOLS list — i.e. tool results (like decompress)\n * that should be excluded from the soft-protected recent zone. */\nexport function isNeverPreserveRecent(msg: CoreMessage): boolean {\n if (msg.contentType !== \"tool-call\" && msg.contentType !== \"tool-result\") {\n return false;\n }\n if (!msg.toolName) return false;\n return (NEVER_PRESERVE_RECENT_TOOLS as readonly string[]).includes(msg.toolName);\n}\n\nexport function matchToolPattern(toolName: string, pattern: string): boolean {\n if (pattern.endsWith(\"*\")) {\n return toolName.startsWith(pattern.slice(0, -1));\n }\n return toolName === pattern;\n}\n\nexport function isMessageProtected(\n msg: CoreMessage,\n config: Pick<Config, \"protectedTools\" | \"isToolProtected\">,\n): boolean {\n // tool-result carries the same toolName as its tool-call (the host projects\n // it), so checking toolName covers both sides of a tool exchange.\n if (\n (msg.contentType !== \"tool-call\" && msg.contentType !== \"tool-result\") ||\n !msg.toolName\n ) {\n return false;\n }\n\n // Hard-coded protection: ACP metadata tools are never compressible.\n if ((ALWAYS_PROTECTED_TOOLS as readonly string[]).includes(msg.toolName)) {\n return true;\n }\n\n for (const pattern of config.protectedTools) {\n if (matchToolPattern(msg.toolName, pattern)) return true;\n }\n\n if (config.isToolProtected?.(msg.toolName, msg.text)) return true;\n\n return false;\n}\n\n/** Build the set of toolCallIds whose tool-call is protected. Use this to also\n * protect tool-results that lack a toolName (common when the host projects a\n * tool-result with only toolCallId). Without it, the result half of a\n * protected tool exchange leaks into compressible ranges. */\nexport function collectProtectedToolCallIds(\n messages: CoreMessage[],\n config: Pick<Config, \"protectedTools\" | \"isToolProtected\">,\n): Set<string> {\n const ids = new Set<string>();\n for (const m of messages) {\n if (m.contentType === \"tool-call\" && m.toolCallId && isMessageProtected(m, config)) {\n ids.add(m.toolCallId);\n }\n }\n return ids;\n}\n\n/** Like isMessageProtected, but also matches tool-results by toolCallId against\n * the protected call set. Use when you have the full message list available. */\nexport function isMessageProtectedWithPairing(\n msg: CoreMessage,\n config: Pick<Config, \"protectedTools\" | \"isToolProtected\">,\n protectedCallIds: Set<string>,\n): boolean {\n if (isMessageProtected(msg, config)) return true;\n if (\n msg.contentType === \"tool-result\" &&\n msg.toolCallId &&\n protectedCallIds.has(msg.toolCallId)\n ) {\n return true;\n }\n return false;\n}\n","import type { CoreMessage } from \"./types.js\";\n\n/**\n * Adjust compression range boundaries to include tool-call/result pairs.\n *\n * PREVENTIVE approach (adapted from opencode-acp PR #248): before compression\n * is applied, scan for tool-call or tool-result messages whose matching half\n * (the result for a call in range, or the call for a result in range) sits\n * outside the requested range. Pull the orphan half INTO the range so the\n * pair is compressed together — zero information loss.\n *\n * Only MESSAGE-boundary ranges are adjusted. Block-boundary ranges (bN) are\n * left untouched to preserve tier-detection correctness.\n *\n * @returns Adjusted { startIndex, endIndex } — may be wider than input.\n */\nexport function adjustBoundariesForToolPairs(\n startIndex: number,\n endIndex: number,\n messages: CoreMessage[],\n maxScan: number = 20,\n): { startIndex: number; endIndex: number } {\n // Collect all toolCallIds in range (both tool-call and tool-result messages).\n // Skip compress tool — it's force-protected and always survives pruning.\n const callIdsInRange = new Set<string>();\n for (let i = startIndex; i <= endIndex; i++) {\n const msg = messages[i];\n if (!msg || !msg.toolCallId) continue;\n if (msg.toolName === \"compress\") continue;\n callIdsInRange.add(msg.toolCallId);\n }\n\n if (callIdsInRange.size === 0) {\n return { startIndex, endIndex };\n }\n\n // Extend FORWARD: tool-results typically follow their tool-call.\n // Stop at the first gap after finding at least one matching message.\n let newEndIndex = endIndex;\n for (let i = endIndex + 1; i < messages.length && i <= endIndex + maxScan; i++) {\n const msg = messages[i];\n if (!msg) break;\n if (msg.toolCallId && callIdsInRange.has(msg.toolCallId)) {\n newEndIndex = i;\n } else if (newEndIndex > endIndex) {\n break;\n }\n }\n\n // Extend BACKWARD: tool-calls typically precede their tool-result.\n let newStartIndex = startIndex;\n for (let i = startIndex - 1; i >= 0 && i >= startIndex - maxScan; i--) {\n const msg = messages[i];\n if (!msg) break;\n if (msg.toolCallId && callIdsInRange.has(msg.toolCallId)) {\n newStartIndex = i;\n } else if (newStartIndex < startIndex) {\n break;\n }\n }\n\n return { startIndex: newStartIndex, endIndex: newEndIndex };\n}\n","/**\n * Recommendation engine — compression protection + recommendation.\n *\n * Clean-room reimplementation of the recommendation algorithm (MIT, ours).\n * These pure functions answer two questions every turn:\n *\n * 1. **Protection** — which messages must NOT be compressed? (protected tools,\n * recent messages, recent tokens)\n * 2. **Recommendation** — which remaining ranges are actually WORTH compressing?\n * (growth-aware threshold; suppress nudges when ranges are too small)\n *\n * Called by the `recommend` pipeline node. No side effects, no state mutation.\n */\n\nimport type {\n CompressibleRange,\n Config,\n ContextRanges,\n CoreMessage,\n ProtectedRange,\n} from \"./types.js\";\nimport type { CompressionState } from \"./types.js\";\nimport {\n collectProtectedToolCallIds,\n isMessageProtectedWithPairing,\n isNeverPreserveRecent,\n} from \"./protected.js\";\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction refNum(ref: string): number {\n const n = parseInt(ref.slice(1), 10);\n return Number.isNaN(n) ? -1 : n;\n}\n\nfunction estimateTextTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nfunction isToolMessage(message: CoreMessage): boolean {\n return message.contentType === \"tool-call\" || message.contentType === \"tool-result\";\n}\n\n\nfunction isSyntheticOrPruned(\n message: CoreMessage,\n state: CompressionState,\n): boolean {\n if (message.text?.startsWith(\"[Compressed conversation section]\")) return true;\n for (const block of state.blocks) {\n if (block.active && block.effectiveMessageIds.includes(message.id)) return true;\n }\n return false;\n}\n\n// ─── 1. Protected Refs (soft protection zone) ─────────────────────────────────\n\n/**\n * Compute the set of protected message refs (mNNNNN) that form the\n * \"soft-protected zone\" at the tail of the conversation.\n *\n * Combines two rules:\n * 1. Last N messages (`config.preserveRecentMessages`)\n * 2. Last N tokens expanding backward (`config.preserveRecentTokens`)\n *\n * Only considers visible, non-synthetic, non-pruned messages that have refs.\n */\nexport function computeProtectedRefs(\n messages: CoreMessage[],\n state: CompressionState,\n config: Config,\n countTokens: (text: string) => number = estimateTextTokens,\n): Set<string> {\n const preserveN = config.preserveRecentMessages;\n const preserveTokens = config.preserveRecentTokens;\n\n const result = new Set<string>();\n const visible: { ref: string; tokens: number }[] = [];\n\n for (const msg of messages) {\n if (isSyntheticOrPruned(msg, state)) continue;\n // Exclude decompress-style tool results from the recent-zone window.\n // These are large inline restorations that the model should be free to\n // compress again immediately; counting them toward the last-N window\n // would make them un-compressible and hide them from recommendations.\n // The message stays fully visible — this only affects protection scope.\n if (isNeverPreserveRecent(msg)) continue;\n const ref = state.messageRefs.byRaw[msg.id];\n if (!ref || ref === \"BLOCKED\") continue;\n visible.push({ ref, tokens: countTokens(msg.text ?? \"\") });\n }\n\n // Rule 1: last N messages\n if (preserveN > 0) {\n for (const m of visible.slice(-preserveN)) {\n result.add(m.ref);\n }\n }\n\n // Rule 2: last N tokens (expand backward from tail)\n if (preserveTokens > 0) {\n let tokenAccum = 0;\n for (let i = visible.length - 1; i >= 0 && tokenAccum < preserveTokens; i--) {\n result.add(visible[i]!.ref);\n tokenAccum += visible[i]!.tokens;\n }\n }\n\n // Rule 3: last visible user message. Protected whenever recent-message\n // protection is on (preserveRecentMessages > 0) — this couples it to the\n // same switch as Rule 1, so setting preserveRecentMessages = 0 fully opts\n // out (needed by tests that compress the tail). Production defaultConfig\n // uses 5, so the last user message is always protected in practice.\n // Note: we scan the raw messages array (not `visible`) here so the last\n // user message is still found even when a decompress tool result was\n // skipped above — user intent is always protected regardless of recent\n // tool results.\n if (preserveN > 0) {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role !== \"user\" || isSyntheticOrPruned(msg, state)) continue;\n const ref = state.messageRefs.byRaw[msg.id];\n if (ref && ref !== \"BLOCKED\") result.add(ref);\n break;\n }\n }\n\n return result;\n}\n\n// ─── 2. Build Compressible + Protected Ranges ────────────────────────────────\n\n/**\n * Build compressible and protected range groups from the message list.\n *\n * Messages are classified into:\n * - **compressible**: normal messages outside the protected zone\n * - **protected**: messages from protected tools (e.g., skill, task)\n * - **skipped**: covered by blocks, synthetic, or in the protected zone\n *\n * Compressible messages are grouped into contiguous ranges. The protected\n * zone (from `computeProtectedRefs`) splits groups — the unprotected head\n * survives as its own range.\n */\nexport function buildCompressibleRanges(\n messages: CoreMessage[],\n state: CompressionState,\n config: Config,\n protectedZoneRefs?: Set<string>,\n countTokens: (text: string) => number = estimateTextTokens,\n): ContextRanges {\n const compressibleMsgs: {\n ref: string;\n refNum: number;\n tokens: number;\n isTool: boolean;\n isUser: boolean;\n }[] = [];\n const protectedMsgs: {\n ref: string;\n refNum: number;\n tokens: number;\n tools: string[];\n }[] = [];\n\n // Pairing: a tool-result may carry only toolCallId (no toolName). Collect the\n // callIds of protected tool-calls first, then protect matching results too.\n const protectedCallIds = collectProtectedToolCallIds(messages, config);\n\n for (const msg of messages) {\n if (isSyntheticOrPruned(msg, state)) continue;\n const ref = state.messageRefs.byRaw[msg.id];\n if (!ref || ref === \"BLOCKED\") continue;\n\n const rn = refNum(ref);\n\n if (isMessageProtectedWithPairing(msg, config, protectedCallIds)) {\n protectedMsgs.push({\n ref,\n refNum: rn,\n tokens: countTokens(msg.text ?? \"\"),\n tools: msg.toolName ? [msg.toolName] : [],\n });\n continue;\n }\n\n if (protectedZoneRefs?.has(ref)) {\n continue;\n }\n\n compressibleMsgs.push({\n ref,\n refNum: rn,\n tokens: countTokens(msg.text ?? \"\"),\n isTool: isToolMessage(msg),\n isUser: msg.role === \"user\",\n });\n }\n\n // Build compressible groups (contiguous, split at ref gaps and at user\n // messages once a group has >= 3 messages). Splitting at user boundaries\n // keeps each compressible range aligned to roughly one user turn, instead\n // of producing one giant range spanning many turns (or, conversely, a\n // fragment per message when ref gaps appear). Mirrors opencode-acp's\n // buildCompressibleRanges condition.\n const compressible: CompressibleRange[] = [];\n let cur: CompressibleRange | null = null;\n let prevRefNum = -2;\n\n for (const info of compressibleMsgs) {\n const hasGap = info.refNum > prevRefNum + 1;\n if (cur && ((info.isUser && cur.count >= 3) || hasGap)) {\n compressible.push(cur);\n cur = null;\n }\n prevRefNum = info.refNum;\n if (!cur) {\n cur = {\n startRef: info.ref,\n endRef: info.ref,\n count: 1,\n tokens: info.tokens,\n toolPct: info.isTool ? 100 : 0,\n textPct: info.isTool ? 0 : 100,\n };\n } else {\n cur.endRef = info.ref;\n cur.count++;\n cur.tokens += info.tokens;\n if (info.isTool) {\n cur.toolPct = Math.round((cur.toolPct * (cur.count - 1) + 100) / cur.count);\n } else {\n cur.toolPct = Math.round((cur.toolPct * (cur.count - 1)) / cur.count);\n }\n cur.textPct = 100 - cur.toolPct;\n }\n }\n if (cur) compressible.push(cur);\n\n // Build protected groups (contiguous)\n const protectedRanges: ProtectedRange[] = [];\n let pcur: ProtectedRange | null = null;\n let pPrevRefNum = -2;\n\n for (const info of protectedMsgs) {\n const hasGap = info.refNum > pPrevRefNum + 1;\n if (pcur && hasGap) {\n protectedRanges.push(pcur);\n pcur = null;\n }\n pPrevRefNum = info.refNum;\n if (!pcur) {\n pcur = {\n startRef: info.ref,\n endRef: info.ref,\n count: 1,\n tokens: info.tokens,\n tools: [...info.tools],\n };\n } else {\n pcur.endRef = info.ref;\n pcur.count++;\n pcur.tokens += info.tokens;\n for (const t of info.tools) {\n if (!pcur!.tools.includes(t)) pcur!.tools.push(t);\n }\n }\n }\n if (pcur) protectedRanges.push(pcur);\n\n return {\n compressible: compressible.filter((g) => g.tokens > 0),\n protected: protectedRanges,\n };\n}\n","import type { CompressionState, CoreMessage, NudgeDecision } from \"./types.js\";\n\nexport interface PipelineContext {\n readonly config: import(\"./types.js\").Config;\n readonly tokenCount: number;\n readonly countTokens: (text: string) => number;\n}\n\nexport interface NodeEffects {\n nudge?: NudgeDecision;\n recommendation?: import(\"./types.js\").Recommendation;\n truncatedCount?: number;\n readonly [key: string]: unknown;\n}\n\nexport interface NodeIO {\n messages: CoreMessage[];\n state: CompressionState;\n effects: NodeEffects;\n}\n\nexport interface PipelineNode {\n readonly name: string;\n run(io: NodeIO, ctx: PipelineContext): NodeIO;\n enabled?: (io: NodeIO, ctx: PipelineContext) => boolean;\n}\n\nexport function makeIO(\n messages: CoreMessage[],\n state: CompressionState,\n effects: NodeEffects = {},\n): NodeIO {\n return { messages, state, effects };\n}\n\nexport function runPipeline(\n nodes: readonly PipelineNode[],\n initial: NodeIO,\n ctx: PipelineContext,\n): NodeIO {\n let io = initial;\n for (const node of nodes) {\n if (node.enabled && !node.enabled(io, ctx)) continue;\n io = node.run(io, ctx);\n }\n return io;\n}\n","import { assignRefs, highestUsedIndex } from \"./refs.js\";\nimport { prune } from \"./prune.js\";\nimport { syncBlocks } from \"./sync.js\";\nimport { advanceSurvival, activeBlocks, blockById } from \"./state.js\";\nimport {\n allocateBlockId,\n allocateRunId,\n createInitialState,\n} from \"./state.js\";\nimport { defaultCountTokens } from \"./tokenize.js\";\nimport { validateConfig } from \"./config.js\";\nimport { resolveBoundaries, earliestIndexOfIds } from \"./boundaries.js\";\nimport { truncateLargeToolOutputs } from \"./truncate-tools.js\";\nimport { hideConsumedCompressCalls } from \"./hide-consumed.js\";\nimport { applyMessageFilters, listMessageFilters } from \"./filter/index.js\";\nimport { createRenderRefsNode } from \"./render-refs.js\";\nimport type { RenderStrategy } from \"./render-refs.js\";\nimport { isMessageProtected } from \"./protected.js\";\nimport { adjustBoundariesForToolPairs } from \"./tool-pairs.js\";\nimport {\n computeProtectedRefs,\n buildCompressibleRanges,\n} from \"./recommend.js\";\nimport {\n runPipeline,\n type PipelineContext,\n type PipelineNode,\n type NodeIO,\n} from \"./pipeline.js\";\nimport type {\n ApplyCompressionResult,\n CompressionBlock,\n CompressionState,\n CompressionTier,\n Config,\n ContextBreakdown,\n CoreMessage,\n NudgeConfig,\n NudgeDecision,\n ProcessTurnResult,\n Recommendation,\n StatusReport,\n} from \"./types.js\";\n\nexport interface Ports {\n countTokens?: (text: string) => number;\n}\n\nexport interface CompressionCore {\n processTurn(input: ProcessTurnInput): ProcessTurnResult;\n applyCompression(input: ApplyCompressionInput): ApplyCompressionResult;\n defaultNodes(): PipelineNode[];\n decompress(\n blockId: string,\n state: CompressionState,\n ): CompressionBlock | undefined;\n search(query: string, state: CompressionState): CompressionBlock[];\n status(\n state: CompressionState,\n tokenCount: number,\n config: Config,\n ): StatusReport;\n}\n\nexport interface ProcessTurnInput {\n messages: CoreMessage[];\n state: CompressionState;\n config: Config;\n tokenCount: number;\n /**\n * Which messages get an <acp> ref tag injected into their text\n * (the render-refs pipeline node). Refs are ALWAYS assigned regardless\n * (assign-refs node runs unconditionally).\n * - \"all\" (default): tag every mapped message — in-process hosts\n * like pai-acp want tags for the LLM to reference compress ranges.\n * - \"text-only\": tag only user/assistant text; leave tool-call args\n * and tool-result content pristine — proxy hosts where structured\n * content must not be polluted.\n * - \"none\": leave all text untouched — hosts that read the ref map\n * directly from result.state.messageRefs.\n */\n renderTags?: RenderStrategy;\n}\n\nexport interface ApplyCompressionInput {\n ranges: {\n startRef: string;\n endRef: string;\n summary: string;\n topic?: string;\n compressCallId?: string;\n summaryMaxChars?: number;\n }[];\n messages: CoreMessage[];\n state: CompressionState;\n config: Config;\n protectedMessageIds?: Set<string>;\n}\n\nexport function createCore(ports: Ports = {}): CompressionCore {\n const countTokens = ports.countTokens ?? defaultCountTokens;\n\n function applyCompression(\n input: ApplyCompressionInput,\n ): ApplyCompressionResult {\n const state: CompressionState = cloneState(input.state);\n const runId = allocateRunId(state);\n let blocksCreated = 0;\n let tokensCompressed = 0;\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Default to the soft-protected zone (recent-N + last user message) when the\n // caller doesn't pass an explicit set. This makes applyCompression safe by\n // default; applySingleRange enforces it as a hard backstop.\n const protectedMessageIds =\n input.protectedMessageIds ??\n computeProtectedRefs(input.messages, input.state, input.config, countTokens);\n\n const preExistingCoverage = collectCoverage(state);\n\n const rangeIndexSets: { spec: typeof input.ranges[number]; indices: number[] }[] = [];\n for (const spec of input.ranges) {\n let resolved;\n try {\n resolved = resolveBoundaries({\n startRef: spec.startRef,\n endRef: spec.endRef,\n messages: input.messages,\n state,\n });\n } catch {\n continue;\n }\n const indices = resolved.messageIds.map((id) =>\n input.messages.findIndex((m) => m.id === id),\n ).filter((i) => i >= 0);\n rangeIndexSets.push({ spec, indices });\n }\n const sortedRanges = [...rangeIndexSets].sort((a, b) => {\n const aMin = a.indices.length > 0 ? Math.min(...a.indices) : Infinity;\n const bMin = b.indices.length > 0 ? Math.min(...b.indices) : Infinity;\n return aMin - bMin;\n });\n // Overlapping ranges warn+skip (earliest wins) rather than aborting the\n // whole batch — see ISSUE-42 / dog/billion-context-pi#21.\n const skipSpecs = new Set<typeof input.ranges[number]>();\n let acceptedMaxIndex = -1;\n for (const entry of sortedRanges) {\n const entryMax = entry.indices.length > 0 ? Math.max(...entry.indices) : -1;\n const entryMin = entry.indices.length > 0 ? Math.min(...entry.indices) : -1;\n if (entryMin >= 0 && entryMin <= acceptedMaxIndex) {\n skipSpecs.add(entry.spec);\n warnings.push(\n `Skipped range (${entry.spec.startRef}..${entry.spec.endRef}) — overlaps an earlier range in the batch; the earlier range takes precedence. Keep ranges disjoint.`,\n );\n continue;\n }\n if (entryMax > acceptedMaxIndex) acceptedMaxIndex = entryMax;\n }\n\n if (input.config.compress.minCompressRange > 0 && input.ranges.length > 0) {\n let totalRangeChars = 0;\n let hasBlockBoundaryRange = false;\n for (const spec of input.ranges) {\n if (skipSpecs.has(spec)) continue;\n let resolved;\n try {\n resolved = resolveBoundaries({\n startRef: spec.startRef,\n endRef: spec.endRef,\n messages: input.messages,\n state,\n });\n } catch {\n continue;\n }\n if (resolved.boundaryKind === \"block\") {\n hasBlockBoundaryRange = true;\n continue;\n }\n for (const id of resolved.messageIds) {\n const msg = input.messages.find((m) => m.id === id);\n totalRangeChars += msg?.text?.length ?? 0;\n }\n }\n if (!hasBlockBoundaryRange && totalRangeChars < input.config.compress.minCompressRange) {\n return {\n state: input.state,\n result: {\n blocksCreated: 0,\n tokensCompressed: 0,\n errors: [\n `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.`,\n ],\n warnings: [],\n },\n };\n }\n }\n\n for (const spec of input.ranges) {\n if (skipSpecs.has(spec)) continue;\n try {\n const outcome = applySingleRange({\n spec,\n messages: input.messages,\n state,\n runId,\n config: input.config,\n protectedMessageIds,\n countTokens,\n preExistingCoverage,\n });\n blocksCreated++;\n tokensCompressed += outcome.tokens;\n warnings.push(...outcome.warnings);\n } catch (error) {\n errors.push(error instanceof Error ? error.message : String(error));\n }\n }\n\n state.stats.compressionCount += blocksCreated;\n state.stats.tokensCompressed += tokensCompressed;\n\n if (blocksCreated > 0) {\n // Compress succeeded: clear the growth baseline so the next turn\n // re-establishes it at the new (lower) token count. Without this the\n // nudge re-fires in a feedback loop (the §5.7 baseline-reset bug).\n state.nudge.lastPerMessageNudgeTokens = 0;\n state.nudge.lastNudgeShownTokens = 0;\n // Clearing the per-tier cadence too: after a successful compression\n // (which may have consumed blocks of tier N to produce tier N+1), every\n // tier should be eligible to re-evaluate from the new token count.\n state.nudge.lastShownByTier = {};\n }\n\n return { state, result: { blocksCreated, tokensCompressed, errors, warnings } };\n }\n\n function processTurn(input: ProcessTurnInput): ProcessTurnResult {\n const configErrors = validateConfig(input.config);\n if (configErrors.length > 0) {\n console.warn(`[acp-kernel] Config validation warnings: ${configErrors.join(\"; \")}. Thresholds may not fire correctly.`);\n }\n const ctx: PipelineContext = {\n config: input.config,\n tokenCount: input.tokenCount,\n countTokens,\n };\n const initial: NodeIO = {\n messages: input.messages,\n state: input.state,\n effects: {},\n };\n // Conversion (assign-refs) and rendering (render-refs) are separate\n // concerns. Refs are always assigned; renderTags only controls which\n // message texts receive an <acp> tag.\n const strategy: RenderStrategy = input.renderTags ?? \"all\";\n const nodes = buildNodes(strategy);\n const result = runPipeline(nodes, initial, ctx);\n return {\n messages: result.messages,\n state: result.state,\n nudge: result.effects.nudge,\n };\n }\n\n function decompress(blockId: string, state: CompressionState) {\n return blockById(state, blockId);\n }\n\n function search(query: string, state: CompressionState): CompressionBlock[] {\n const terms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((term) => term.length > 0);\n if (terms.length === 0) return [];\n const scored = activeBlocks(state)\n .map((block) => ({ block, score: scoreRelevance(block, terms) }))\n .filter((entry) => entry.score > 0.1)\n .sort((left, right) => right.score - left.score);\n return scored.map((entry) => entry.block);\n }\n\n function status(\n state: CompressionState,\n tokenCount: number,\n config: Config,\n ): StatusReport {\n const active = activeBlocks(state);\n const usage =\n config.modelContextLimit > 0 ? tokenCount / config.modelContextLimit : 0;\n return {\n contextUsage: usage,\n tokenCount,\n modelContextLimit: config.modelContextLimit,\n activeBlocks: active.length,\n totalBlocks: state.blocks.length,\n tokensCompressed: state.stats.tokensCompressed,\n breakdown: { active: active.length, total: state.blocks.length },\n };\n }\n\n function defaultNodes(): PipelineNode[] {\n return buildNodes(\"all\");\n }\n\n /** Build the pipeline node list for a given render strategy. \"none\" omits\n * the render-refs node entirely; \"all\"/\"text-only\" append a render-refs\n * node bound to that strategy. */\n function buildNodes(strategy: RenderStrategy): PipelineNode[] {\n const base: PipelineNode[] = [\n assignRefsNode,\n syncBlocksNode,\n pruneNode,\n filterNode,\n hideCompressCallsNode,\n recommendNode,\n nudgeNode,\n emergencyTruncateNode,\n ];\n if (strategy === \"none\") return base;\n return [...base, createRenderRefsNode(strategy)];\n }\n\n return { processTurn, applyCompression, defaultNodes, decompress, search, status };\n}\n\n// --- Pipeline nodes -------------------------------------------------------\n// Each node owns ONE concern. The ref map has a SINGLE writer (assignRefsNode);\n// tags are DERIVED at the end (renderRefsNode) — no dual source of truth, so\n// the old stripHallucinations band-aid is gone. Truncation is the LAST\n// token-reducing safety valve; render-refs is the final annotation pass.\n\nconst assignRefsNode: PipelineNode = {\n name: \"assign-refs\",\n run(io, ctx) {\n const hasProtection =\n ctx.config.protectedTools.length > 0 || !!ctx.config.isToolProtected;\n const protectedFn = hasProtection\n ? (m: CoreMessage) => isMessageProtected(m, ctx.config)\n : undefined;\n const refResult = assignRefs(io.messages, {\n existing: io.state.messageRefs,\n nextIndex: highestUsedIndex(io.state.messageRefs) + 1,\n isProtected: protectedFn,\n });\n return { ...io, state: { ...io.state, messageRefs: refResult.map } };\n },\n};\n\nconst syncBlocksNode: PipelineNode = {\n name: \"sync-blocks\",\n run(io, ctx) {\n const synced = syncBlocks(io.messages, io.state);\n advanceSurvival(synced.state, ctx.config.promotionThreshold);\n return { ...io, state: synced.state };\n },\n};\n\nconst pruneNode: PipelineNode = {\n name: \"prune\",\n run(io) {\n return { ...io, messages: prune(io.messages, io.state) };\n },\n};\n\nconst filterNode: PipelineNode = {\n name: \"filter\",\n enabled: (_io, ctx) =>\n !!ctx.config.messageFilters?.enabled && listMessageFilters().length > 0,\n run(io, ctx) {\n const applied = applyMessageFilters(io.messages, ctx.config.messageFilters);\n return { ...io, messages: applied.messages };\n },\n};\n\nconst hideCompressCallsNode: PipelineNode = {\n name: \"hide-compress-calls\",\n run(io) {\n const hidden = hideConsumedCompressCalls(io.state, io.messages);\n return { ...io, messages: hidden.messages };\n },\n};\n\nconst recommendNode: PipelineNode = {\n name: \"recommend\",\n run(io, ctx) {\n const protectedRefs = computeProtectedRefs(\n io.messages,\n io.state,\n ctx.config,\n ctx.countTokens,\n );\n const contextRanges = buildCompressibleRanges(\n io.messages,\n io.state,\n ctx.config,\n protectedRefs,\n ctx.countTokens,\n );\n const nothingToCompress = contextRanges.compressible.length === 0;\n const recommendation: Recommendation = {\n contextRanges,\n recommendedRanges: contextRanges.compressible,\n nothingToCompress,\n };\n return { ...io, effects: { ...io.effects, recommendation } };\n },\n};\n\nconst nudgeNode: PipelineNode = {\n name: \"nudge-inject\",\n run(io, ctx) {\n const nudge = decideNudge({\n tokenCount: ctx.tokenCount,\n config: ctx.config,\n state: io.state,\n messages: io.messages,\n recommendation: io.effects.recommendation,\n countTokens: ctx.countTokens,\n });\n\n const baseline = io.state.nudge.lastPerMessageNudgeTokens;\n const nudgeGrowthTokens = resolveAdaptiveGrowth(\n ctx.config.modelContextLimit,\n ctx.config.nudge,\n );\n\n let stamped = { ...io.state.nudge };\n\n if (\n baseline > 0 &&\n ctx.tokenCount < baseline - nudgeGrowthTokens\n ) {\n stamped.lastPerMessageNudgeTokens = ctx.tokenCount;\n stamped.lastNudgeShownTokens = 0;\n }\n\n if (stamped.lastPerMessageNudgeTokens === 0) {\n stamped.lastPerMessageNudgeTokens = ctx.tokenCount;\n }\n\n if (nudge.shouldInject) {\n stamped.lastNudgeShownTokens = ctx.tokenCount;\n // Record the injected tier's own cadence baseline. Shared baseline\n // (lastNudgeShownTokens) suppresses lower-priority tiers within this\n // turn; the per-tier entry throttles re-firing of the SAME tier.\n if (nudge.tier !== null) {\n stamped.lastShownByTier = { ...stamped.lastShownByTier, [nudge.tier]: ctx.tokenCount };\n }\n }\n\n return {\n ...io,\n state: { ...io.state, nudge: stamped },\n effects: { ...io.effects, nudge },\n };\n },\n};\n\nconst emergencyTruncateNode: PipelineNode = {\n name: \"emergency-truncate\",\n run(io, ctx) {\n const usage =\n ctx.config.modelContextLimit > 0\n ? ctx.tokenCount / ctx.config.modelContextLimit\n : 0;\n if (usage < ctx.config.truncate.threshold) return io;\n const trunc = truncateLargeToolOutputs(\n io.messages,\n ctx.tokenCount,\n ctx.config,\n ctx.countTokens,\n { protectRecentMessages: ctx.config.preserveRecentMessages },\n );\n return {\n ...io,\n messages: trunc.messages,\n effects: { ...io.effects, truncatedCount: trunc.truncatedCount },\n };\n },\n};\n\ninterface SingleRangeInput {\n spec: { startRef: string; endRef: string; summary: string; topic?: string; compressCallId?: string; summaryMaxChars?: number };\n messages: CoreMessage[];\n state: CompressionState;\n runId: string;\n config: Config;\n protectedMessageIds?: Set<string>;\n countTokens: (text: string) => number;\n preExistingCoverage: Set<string>;\n}\n\ninterface SingleRangeOutcome {\n tokens: number;\n warnings: string[];\n}\n\nfunction applySingleRange(input: SingleRangeInput): SingleRangeOutcome {\n const warnings: string[] = [];\n const resolved = resolveBoundaries({\n startRef: input.spec.startRef,\n endRef: input.spec.endRef,\n messages: input.messages,\n state: input.state,\n });\n\n const rangeMessageIds = applyToolPairAdjustment(\n resolved,\n input.messages,\n );\n\n // Re-scan for nested blocks in the ADJUSTED range (tool-pair extension may\n // have pulled in messages that are anchors of existing blocks).\n if (rangeMessageIds.length > resolved.messageIds.length) {\n const indexByRawId = new Map<string, number>();\n input.messages.forEach((m, i) => indexByRawId.set(m.id, i));\n const adjustedStart = indexByRawId.get(rangeMessageIds[0]!) ?? resolved.startIndex;\n const adjustedEnd = indexByRawId.get(rangeMessageIds[rangeMessageIds.length - 1]!) ?? resolved.endIndex;\n const nestedSeen = new Set(resolved.nestedBlockIds);\n for (const block of activeBlocks(input.state)) {\n if (nestedSeen.has(block.blockId)) continue;\n const anchor = earliestIndexOfIds(block.effectiveMessageIds, indexByRawId);\n if (anchor !== null && anchor >= adjustedStart && anchor <= adjustedEnd) {\n nestedSeen.add(block.blockId);\n resolved.nestedBlockIds.push(block.blockId);\n }\n }\n }\n\n const isBlockBoundary = resolved.boundaryKind === \"block\";\n const targetTier = resolveTargetTier(\n input.state,\n resolved.nestedBlockIds,\n isBlockBoundary,\n );\n const outputTier = isBlockBoundary\n ? (Math.min(3, targetTier + 1) as CompressionTier)\n : 1;\n\n const consumedBlockIds = resolved.nestedBlockIds.filter((id) => {\n const block = blockById(input.state, id);\n return block?.active && block.tier === targetTier;\n });\n\n const effectiveMessageIds = new Set<string>(rangeMessageIds);\n for (const consumedId of consumedBlockIds) {\n const consumed = blockById(input.state, consumedId);\n if (consumed) {\n for (const id of consumed.effectiveMessageIds)\n effectiveMessageIds.add(id);\n }\n }\n\n const directMessageIds = [...effectiveMessageIds].filter(\n (id) => !input.preExistingCoverage.has(id),\n );\n\n let filteredIds = filterProtectedToolMessages(\n directMessageIds,\n input.messages,\n input.config,\n );\n\n // filterProtectedToolMessages drops protected tool calls (and their paired\n // results) from the compressible set. They must also leave effectiveMessageIds,\n // otherwise the block would record them as covered and hide them from view.\n // (Bug 39: protected tool messages folded into a block.)\n if (filteredIds.length < directMessageIds.length) {\n const kept = new Set(filteredIds);\n for (const id of directMessageIds) {\n if (!kept.has(id)) effectiveMessageIds.delete(id);\n }\n }\n\n // SOFT PROTECTION: the recent-N / last-user-message zone is advisory-only at\n // compress time. Instead of failing the whole range when it brushes protected\n // messages, exclude those messages and proceed with the rest (so the model\n // isn't blocked when it picks a range that slightly overlaps the recent\n // window). If excluding them empties the range entirely AND there are no\n // consumed blocks to merge, we still fail — there is genuinely nothing to\n // compress. `protectedMessageIds` holds REF ids (mNNNNN) from\n // computeProtectedRefs; filteredIds holds RAW message ids, so convert via\n // state.messageRefs.byRaw before testing membership.\n const protectedRefs = input.protectedMessageIds;\n const hitProtectedRaw = protectedRefs\n ? filteredIds.filter((id) => {\n const ref = input.state.messageRefs.byRaw[id];\n return ref !== undefined && protectedRefs.has(ref);\n })\n : [];\n if (hitProtectedRaw.length > 0) {\n const protectedSet = new Set(hitProtectedRaw);\n filteredIds = filteredIds.filter((id) => !protectedSet.has(id));\n // Remove protected messages from effective coverage too, so they are NOT\n // hidden by the new block (they must stay fully visible).\n for (const id of hitProtectedRaw) effectiveMessageIds.delete(id);\n\n const hitRefs = hitProtectedRaw\n .map((id) => input.state.messageRefs.byRaw[id])\n .filter((v): v is string => typeof v === \"string\");\n\n if (filteredIds.length === 0 && consumedBlockIds.length === 0) {\n const recentN = input.config.preserveRecentMessages;\n throw new Error(\n `Range is entirely within the protected zone (the last ${recentN} messages and/or the most recent user message): ${hitRefs.join(\n \", \",\n )}. Adjust startId/endId to older messages.`,\n );\n }\n warnings.push(\n `Excluded ${hitProtectedRaw.length} protected message(s) ${hitRefs.join(\n \", \",\n )} from compression range (recent/last-user zone).`,\n );\n }\n\n validateCompressionRange(input, filteredIds, consumedBlockIds.length);\n\n let compressedTokens = 0;\n for (const id of filteredIds) {\n const message = input.messages.find((entry) => entry.id === id);\n compressedTokens += input.countTokens(message?.text ?? \"\");\n }\n for (const consumedId of consumedBlockIds) {\n const consumed = blockById(input.state, consumedId);\n if (consumed) {\n compressedTokens += input.countTokens(consumed.summary);\n }\n }\n\n const blockId = allocateBlockId(input.state);\n const block: CompressionBlock = {\n blockId,\n runId: input.runId,\n tier: outputTier,\n topic: input.spec.topic,\n summary: input.spec.summary,\n directMessageIds: filteredIds,\n effectiveMessageIds: [...effectiveMessageIds],\n directBlockIds: [...consumedBlockIds],\n compressedTokens,\n createdAt: Date.now(),\n survivedCount: 0,\n generation: \"young\",\n active: true,\n compressCallId: input.spec.compressCallId,\n startRef: input.spec.startRef,\n endRef: input.spec.endRef,\n };\n input.state.blocks.push(block);\n\n for (const consumedId of consumedBlockIds) {\n const consumed = blockById(input.state, consumedId);\n if (consumed) consumed.active = false;\n }\n\n return { tokens: compressedTokens, warnings };\n}\n\nfunction applyToolPairAdjustment(\n resolved: { startIndex: number; endIndex: number; messageIds: string[]; boundaryKind: string },\n messages: CoreMessage[],\n): string[] {\n if (resolved.boundaryKind === \"block\") {\n return resolved.messageIds;\n }\n const adjusted = adjustBoundariesForToolPairs(\n resolved.startIndex,\n resolved.endIndex,\n messages,\n );\n if (\n adjusted.startIndex === resolved.startIndex &&\n adjusted.endIndex === resolved.endIndex\n ) {\n return resolved.messageIds;\n }\n const ids: string[] = [];\n for (let i = adjusted.startIndex; i <= adjusted.endIndex; i++) {\n const msg = messages[i];\n if (msg) ids.push(msg.id);\n }\n return ids;\n}\n\nfunction validateCompressionRange(\n input: SingleRangeInput,\n directMessageIds: string[],\n consumedBlockCount: number,\n): void {\n const cfg = input.config.compress;\n const summary = input.spec.summary?.trim() ?? \"\";\n\n if (summary.length === 0) {\n throw new Error(\n \"Summary is empty — provide a meaningful summary of the compressed range.\",\n );\n }\n\n if (cfg.minSummaryLength > 0 && summary.length < cfg.minSummaryLength) {\n throw new Error(\n `Summary too short (${summary.length} chars, min ${cfg.minSummaryLength}). The summary must capture the compressed range's key information.`,\n );\n }\n\n const effectiveMax = input.spec.summaryMaxChars ?? cfg.maxSummaryLength;\n if (\n effectiveMax > 0 &&\n summary.length > effectiveMax\n ) {\n throw new Error(\n `Summary too long (${summary.length} chars, max ${effectiveMax}). Strip noise — keep critical paths, decisions, errors, and code references. Or pass summaryMaxChars to increase the limit — don't lose critical info just to fit.`,\n );\n }\n\n if (directMessageIds.length === 0 && consumedBlockCount === 0) {\n throw new Error(\n \"Range contains no compressible messages — all are already covered by active blocks or protected.\",\n );\n }\n}\n\nfunction filterProtectedToolMessages(\n directMessageIds: string[],\n messages: CoreMessage[],\n config: Config,\n): string[] {\n // Protected tool calls (and their results, paired by toolCallId) stay in\n // visible context and are simply dropped from the compressible set. They are\n // NOT folded into the summary — the summary reflects what the author wrote,\n // nothing auto-appended.\n const protectedCallIds = new Set<string>();\n const removedIds = new Set<string>();\n for (const msg of messages) {\n if (isMessageProtected(msg, config) && msg.toolCallId) {\n protectedCallIds.add(msg.toolCallId);\n }\n }\n\n for (const id of directMessageIds) {\n const msg = messages.find((m) => m.id === id);\n if (!msg) continue;\n if (isMessageProtected(msg, config)) {\n removedIds.add(id);\n if (msg.toolCallId) protectedCallIds.add(msg.toolCallId);\n }\n }\n\n for (const id of directMessageIds) {\n if (removedIds.has(id)) continue;\n const msg = messages.find((m) => m.id === id);\n if (!msg) continue;\n if (\n msg.contentType === \"tool-result\" &&\n msg.toolCallId &&\n protectedCallIds.has(msg.toolCallId)\n ) {\n removedIds.add(id);\n }\n }\n\n return directMessageIds.filter((id) => !removedIds.has(id));\n}\n\nfunction resolveTargetTier(\n state: CompressionState,\n nestedBlockIds: string[],\n isBlockBoundary: boolean,\n): CompressionTier {\n if (!isBlockBoundary) return 1;\n if (nestedBlockIds.length === 0) return 1;\n let minTier: CompressionTier = 3;\n for (const id of nestedBlockIds) {\n const block = blockById(state, id);\n if (block && block.tier < minTier) minTier = block.tier;\n }\n return minTier;\n}\n\nfunction collectCoverage(state: CompressionState): Set<string> {\n const coverage = new Set<string>();\n for (const block of activeBlocks(state)) {\n for (const id of block.effectiveMessageIds) coverage.add(id);\n }\n return coverage;\n}\n\ninterface NudgeInput {\n tokenCount: number;\n config: Config;\n state: CompressionState;\n messages: CoreMessage[];\n recommendation?: Recommendation;\n countTokens: (t: string) => number;\n}\n\nfunction resolveAdaptiveGrowth(\n modelContextLimit: number,\n nudge: NudgeConfig,\n): number {\n if (!modelContextLimit || modelContextLimit <= 0) return nudge.growthFloor;\n return Math.min(\n nudge.growthCap,\n Math.max(\n nudge.growthFloor,\n Math.round(modelContextLimit * nudge.growthRatio),\n ),\n );\n}\n\n/** Compressible amount for each tier — all tiers use the SAME definition\n * (\"how much can be compressed at this tier\"), so they are handled by one\n * unified loop. T1 = compressible raw-message tokens (excludes protected /\n * already-covered); T2 = total summary tokens of all active tier-1 blocks;\n * T3 = total summary tokens of all active tier-2 blocks. The \"zero filter\"\n * for block tiers is simply that all blocks are compressible by default. */\nfunction pendingByTier(\n state: CompressionState,\n recommendation: Recommendation | undefined,\n countTokens: (t: string) => number,\n): Record<number, { pending: number; targetBlocks: CompressionBlock[] }> {\n const out: Record<number, { pending: number; targetBlocks: CompressionBlock[] }> = {};\n const compressible = recommendation?.contextRanges.compressible ?? [];\n out[1] = { pending: compressible.reduce((s, r) => s + r.tokens, 0), targetBlocks: [] };\n const active = activeBlocks(state);\n const t1 = active.filter((b) => b.tier === 1);\n const t2 = active.filter((b) => b.tier === 2);\n out[2] = { pending: t1.reduce((s, b) => s + countTokens(b.summary), 0), targetBlocks: t1 };\n out[3] = { pending: t2.reduce((s, b) => s + countTokens(b.summary), 0), targetBlocks: t2 };\n return out;\n}\n\nfunction decideNudge(input: NudgeInput): NudgeDecision {\n const { config, state, tokenCount, recommendation, countTokens } = input;\n const limit = config.modelContextLimit;\n const usage = limit > 0 ? tokenCount / limit : 0;\n\n const nudgeGrowthTokens = resolveAdaptiveGrowth(limit, config.nudge);\n\n const emergencyOverride = usage >= config.nudge.emergencyThresholdPct;\n\n const baseline = state.nudge.lastPerMessageNudgeTokens;\n const hadPendingNudge = state.nudge.lastNudgeShownTokens > 0;\n\n const hasPendingNudge = hadPendingNudge;\n const effectiveThreshold = hasPendingNudge\n ? Math.floor(nudgeGrowthTokens / 2)\n : nudgeGrowthTokens;\n\n const growthReference =\n state.nudge.lastNudgeShownTokens > 0\n ? state.nudge.lastNudgeShownTokens\n : baseline > 0\n ? baseline\n : tokenCount;\n\n const growthFloor = Math.max(\n config.nudge.minGrowthFloor,\n config.nudge.minGrowthRatio * nudgeGrowthTokens,\n );\n\n const growthSinceReference = tokenCount - growthReference;\n\n const rec = recommendation;\n const tiers = pendingByTier(state, rec, countTokens);\n\n // Unified injection arbitration, priority T1 > T2 > T3 (ascending). Each\n // tier has its OWN cadence (lastShownByTier) so firing one doesn't block\n // another across turns; within a turn we inject at most the FIRST eligible\n // tier and stop, which raises the shared baseline (lastNudgeShownTokens) so\n // lower-priority tiers see a higher reference and naturally defer.\n let injectedTier: CompressionTier | null = null;\n let injectedReason = \"\";\n // growth acts as the \"has accumulated since baseline\" signal; pending is the\n // \"there is enough compressible content\" signal. Both must hold for a\n // non-emergency injection. This keeps the first turn (growth 0) from firing\n // immediately even if a lot is compressible — it just establishes baseline.\n const growthReady = growthSinceReference >= growthFloor;\n if (!emergencyOverride && growthReady) {\n for (const tier of [1, 2, 3] as const) {\n if (!config.tiers.enabled && tier > 1) break;\n const info = tiers[tier];\n if (!info || info.pending < nudgeGrowthTokens) continue;\n const lastShown = state.nudge.lastShownByTier[tier] ?? 0;\n // Per-tier cadence: even with growth, a tier that fired recently waits\n // for its own cadence window. First time (lastShown===0) is always met.\n const cadenceMet = lastShown === 0 || tokenCount - lastShown >= growthFloor;\n if (!cadenceMet) continue;\n injectedTier = tier;\n injectedReason = tier === 1\n ? `T1 compressible ${info.pending} >= ${nudgeGrowthTokens}, growth ${growthSinceReference}, usage ${Math.round(usage * 100)}%`\n : `T${tier} distill ready: ${info.targetBlocks.length} tier-${tier - 1} blocks (${info.pending} tokens) >= ${nudgeGrowthTokens}, usage ${Math.round(usage * 100)}%`;\n break;\n }\n }\n\n const shouldInject = emergencyOverride || injectedTier !== null;\n\n let reason: string;\n if (emergencyOverride) {\n reason = `EMERGENCY: usage ${Math.round(usage * 100)}% >= ${Math.round(config.nudge.emergencyThresholdPct * 100)}%`;\n } else if (injectedTier !== null) {\n reason = injectedReason;\n } else {\n const tiersList = [1, 2, 3] as const;\n const eligible = tiersList.filter((t) => config.tiers.enabled || t === 1);\n const ready = eligible\n .filter((t) => (tiers[t]?.pending ?? 0) >= nudgeGrowthTokens)\n .map((t) => `T${t} ${tiers[t]!.pending}`);\n const readyHint = ready.length > 0 ? `, ready: ${ready.join(\", \")}` : \"\";\n const blocked = eligible\n .filter((t) => (tiers[t]?.pending ?? 0) >= nudgeGrowthTokens && (state.nudge.lastShownByTier[t] ?? 0) > 0 && tokenCount - (state.nudge.lastShownByTier[t] ?? 0) < growthFloor)\n .map((t) => `T${t} (cadence)`);\n const blockedHint = blocked.length > 0 ? `, blocked: ${blocked.join(\", \")}` : \"\";\n const maxPending = Math.max(0, ...Object.values(tiers).map((t) => t.pending));\n // Report the ACTUAL blocking condition, not a fixed template. A session\n // can have plenty to compress (pending >= threshold) but still not\n // inject because growth/floor/cadence isn't met — the old fixed\n // \"< threshold\" string lied in that case.\n const pendingShort = maxPending < nudgeGrowthTokens;\n const growthShort = growthSinceReference < growthFloor;\n const parts: string[] = [];\n if (pendingShort) parts.push(`max compressible ${maxPending} < threshold ${nudgeGrowthTokens}`);\n if (growthShort) parts.push(`growth ${growthSinceReference} < floor ${growthFloor}`);\n if (parts.length === 0) parts.push(`max compressible ${maxPending}, growth ${growthSinceReference}`);\n reason = `${parts.join(\"; \")}${readyHint}${blockedHint}`;\n }\n\n const ctxBreakdown = computeContextBreakdown(input.messages, tokenCount, growthSinceReference, countTokens);\n\n return {\n shouldInject,\n reason,\n compressibleRanges: rec?.recommendedRanges ?? [],\n protectedRanges: rec?.contextRanges.protected ?? [],\n tierTargetBlocks: injectedTier ? tiers[injectedTier]!.targetBlocks : [],\n contextUsage: usage,\n tier: injectedTier,\n breakdown: {\n usage,\n growth: growthSinceReference,\n growthReference,\n effectiveThreshold,\n nudgeGrowthTokens,\n growthFloor,\n hasPendingNudge: hasPendingNudge ? 1 : 0,\n emergencyOverride: emergencyOverride ? 1 : 0,\n pendingT1: tiers[1]!.pending,\n pendingT2: tiers[2]!.pending,\n pendingT3: tiers[3]!.pending,\n },\n contextBreakdown: ctxBreakdown,\n };\n}\n\nfunction computeContextBreakdown(messages: CoreMessage[], total: number, growth: number, countTokens: (t: string) => number): ContextBreakdown {\n const count = countTokens ?? ((t: string) => Math.ceil(t.length / 4));\n let system = 0, tool = 0, summaries = 0, code = 0, text = 0;\n for (const msg of messages) {\n const tokens = count(msg.text ?? \"\");\n if (msg.text?.startsWith(\"[Compressed conversation section]\")) {\n summaries += tokens;\n } else if (msg.contentType === \"tool-call\" || msg.contentType === \"tool-result\") {\n tool += tokens;\n } else if (msg.role === \"system\") {\n system += tokens;\n } else if (msg.text?.includes(\"```\")) {\n code += tokens;\n } else {\n text += tokens;\n }\n }\n return { system, tool, summaries, code, text, total, growth };\n}\n\nfunction cloneState(state: CompressionState): CompressionState {\n return {\n blocks: state.blocks.map((block) => ({\n ...block,\n directMessageIds: [...block.directMessageIds],\n effectiveMessageIds: [...block.effectiveMessageIds],\n directBlockIds: [...block.directBlockIds],\n })),\n messageRefs: {\n byRaw: { ...state.messageRefs.byRaw },\n byRef: { ...state.messageRefs.byRef },\n },\n nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },\n stats: { ...state.stats },\n nextBlockId: state.nextBlockId,\n nextRunId: state.nextRunId,\n };\n}\n\nfunction scoreRelevance(block: CompressionBlock, terms: string[]): number {\n const topic = (block.topic ?? \"\").toLowerCase();\n const summary = block.summary.toLowerCase();\n let score = 0;\n for (const term of terms) {\n const topicHits = countOccurrences(topic, term);\n if (topicHits > 0) score += Math.min(topicHits * 0.15, 0.45);\n const summaryHits = countOccurrences(summary, term);\n if (summaryHits > 0) score += Math.min(summaryHits * 0.04, 0.2);\n }\n return Math.min(score, 1);\n}\n\nfunction countOccurrences(haystack: string, needle: string): number {\n if (!haystack || !needle) return 0;\n let count = 0;\n let position = 0;\n while ((position = haystack.indexOf(needle, position)) !== -1) {\n count++;\n position += needle.length;\n }\n return count;\n}\n\nexport { createInitialState };\n","/**\n * Compression rule texts — VERBATIM copy from context-compress-algorithms (MIT, ours).\n * These were tuned over months of production use.\n *\n * DO NOT modify the wording — it is the result of extensive tuning.\n */\n\nexport const COMPRESS_PHILOSOPHY = `Compression Philosophy:\n- All compression serves the primary task, but be frugal.\n- Context capacity is precious. Save context by compressing consumed outputs, not by avoiding tools.\n- Compress by need, not by percentage.\n- Work from summaries, not raw tool outputs. All listed ranges (user prompts, tool outputs, code, logs, exploration, intermediate steps) should be compressed to summary format — the ONLY exceptions are protected content, content the current step is actively using, or critical content you cannot reconstruct.`;\n\nexport const HOW_TO_COMPRESS_RULES = `HOW TO COMPRESS\n\nWhen you call \\`compress\\`, the summary you write becomes the only record of the replaced conversation. Make it self-contained and complete: every user request, experiment purpose, and work task in the range must be accurately captured. A later reader (or you, after decompressing) should be able to continue the task WITHOUT needing the original.\n\nKEEP VERBATIM — never paraphrase or abbreviate these:\n- Full file paths with line numbers, directory prefix on every mention (\\`lib/hooks.ts:347\\`, \\`src/index.ts:12-18\\`, \\`gatenet_v3/model.py:45\\`). Never abbreviate to a bare filename (\\`hooks.ts\\`, \\`model.py\\`) — they are ambiguous and cannot be grepped or decompressed-to later.\n- Function, class, and type signatures (exact names, params, return types) AND critical code lines that encode logic — the line that IS the finding, not just the function name (e.g. \\`kv_keys += define_gate * a_key[i](emb)\\` is more useful than \"see model_kvnet.py\").\n- Error messages and stack traces (exact text — you need the literal string to grep for it later).\n- Key details from reports and analyses — not just the conclusion. Keep the comparison numbers and the mechanism, not \"X is worse\" alone (write \"1.76× PPL gap because KV store is static\", not \"KVNet underperforms\").\n- Decisions and their rationale (\"chose X over Y because Z\" — the \"because\" is load-bearing; without it the decision looks arbitrary).\n- Constraints discovered (\"must support Node 22\", \"no new dependencies\", \"AGENTS.md forbids \\`as any\\`\").\n- Exact values: versions, config keys, thresholds, magic numbers.\n- User intent — quote short user messages verbatim. When the message is too long to quote, preserve intent with extra care: do not change scope, constraints, priorities, acceptance criteria, or requested outcomes. Mark them clearly as past quotes (e.g., \"User said: ...\"), not as current directives. Losing these changes the task itself.\n- The user's overall goal and any changes to it — the big-picture objective plus how it evolved during the compressed range. Each summary must reflect the goal as it stood at the end of the range, including pivots (e.g., \"initially: fix bug X → pivoted to: refactor module Y after discovering root cause\"). Losing the goal or its evolution makes all subsequent work appear unmotivated.\n- Purpose behind each significant action — preserve not just what was done but why: the hypothesis behind each experiment, the question behind each exploration, the task goal behind each work action. Without purpose, the summary reads as disconnected technical steps with no through-line.\n- Open questions and unresolved TODOs — losing these changes what work appears to remain.\n- Message refs of key anchors (\\`m00420\\`, \\`m00510–m00520\\`) — they let you or a later reader jump back via decompress to the exact original.\n\nDROP — extract the signal, discard the vessel:\n- Verbose logs (build/test/\\`npm\\` output) once you have captured the error line or the result.\n- Duplicate file reads once the needed content is recorded.\n- Consumed exploration — search hits, agent return values, successful tool outputs — once you have extracted the facts you need (same rule as dead-ends, but nothing went wrong; the content is simply spent).\n- Dead-end exploration — but PRESERVE the lesson in one line: \"tried X, failed because Y\".\n- Back-and-forth discussion and self-corrections once the final position is captured (keep the outcome, drop the journey to it).\n- Repeated status checks (\\`git status\\`, \\`ls\\`) once state is known.\n\nFor each significant item you DROP (scripts, reports, large analyses, long tool outputs), add a one-line CONTENT description of what it covers — not where it lives. Bad: \"probe script at /path/probe_kvnet.py\". Good: \"probe_kvnet.py: tests n-gram baseline, generation quality, long-range dependency, position sensitivity, op pipeline, QUERY attention.\" This lets a later decompress target the right block by relevance, not by guessing locations.\n\nPRIORITY — when the summary must be compact, preserve in this order:\n1. User's overall goal, goal evolution, intent, and hard constraints (losing these changes the task).\n2. Decisions and rationale.\n3. Exact technical artifacts: paths, signatures, errors, values.\n4. Conclusions and key findings.\n5. Lessons learned: what failed and why.\n\nWrite dense, scannable bullets — not narrative prose. If the range spans distinct concerns (request → findings → decision), group bullets under short thematic headers so a reader can scan to the part they need. Every line must earn its place. Do not mimic the style of existing summaries in context; follow these rules.`;\n\nexport const TIER2_DISTILL_RULES = `TIER 2 COMPRESSION — DISTILLATION\n\nYou are compressing historical summaries (not raw conversation). These summaries have already captured the details. Your job is to DISTILL them: extract only what matters for future work, discard the process.\n\nKEEP — these are the only things that survive distillation:\n- Decisions and their rationale (\"chose X over Y because Z\" — the \"because\" is load-bearing).\n- Final outcomes: version numbers shipped, PR numbers merged/closed, bugs fixed or deferred.\n- Key lessons: what failed and why (\"tried X, failed because Y\"). These prevent repeating mistakes.\n- Critical constraints discovered (\"must support Node 22\", \"AGENTS.md forbids as any\").\n- Design decisions with architectural impact (\"chose compress-as-anchor over synthetic messages because prefix cache\").\n- Whether content is OBSOLETE or SUPERSEDED — mark with one line: \"[SUPERSEDED by PR #NNN]\" or \"[OBSOLETE: deleted in vX.Y.Z]\". Do NOT keep the obsolete content's details — just the marker and reason.\n- Function/class/type names and module paths that are the SUBJECT of the work — e.g., \"fixed filterCompressedRanges in prune.ts\", \"added SessionStateRegistry in state.ts\". Not exact line numbers or full signatures — just enough to LOCATE the code without searching.\n- Exploration findings: if a block was exploratory with no decision, keep the CONCLUSION in one line (\"explored X, not viable because Y\"). Do not keep the exploration process.\n\nDROP — these were useful during the work but are no longer needed:\n- Exact line numbers, diffs, verbose function signatures, full code listings.\n- Build/deploy process details, test execution steps.\n- Review process details (who reviewed, what rounds, test counts).\n- Verbose logs, command output, intermediate debugging steps.\n\nFORMAT:\n- Start each distilled block with a source header line:\n \\`Source: bN+bM+... (XK→YK tok, Zx). [original topic]\\`\n Example: \\`Source: b5+b7 (56K+44K→268 tok, 375x). [Tool-result recap + publish]\\`\n- 3-5 bullet points per source block, each a self-contained fact.\n- Dense, scannable — no narrative prose.\n- Start with the outcome, not the process: \"v1.13.0 shipped (7 PRs bundled)\" not \"implemented 7 PRs then reviewed then merged\".\n- Cross-block synthesis: if multiple source blocks cover the same topic (same PR, same feature, same bug), MERGE them into a single group of bullets. Do not repeat the same fact from different blocks — keep it once under the most relevant source header.\n\nSIZE TARGET: 50-150 tokens per source block (excluding the header). If you can't fit it in 150 tokens, you're keeping too much process. If a block has nothing worth keeping (pure noise), output just the header followed by \"[no actionable content].\"`;\n\nexport const TIER3_CONDENSE_RULES = `TIER 3 COMPRESSION — ULTRA-CONDENSATION\n\nYou are compressing distilled summaries (Tier 2) into ultra-condensed facts (Tier 3). The distilled summaries already contain only decisions and outcomes. Your job is to reduce them to bare factual references.\n\nPRIORITY — when a source block has more facts than the size target allows, keep in this order:\n1. Shipped outcomes (versions released, PRs merged) — these are permanent record.\n2. Open work (PRs/issues still pending) — these may need follow-up.\n3. Key decisions with architectural impact (\"chose X over Y because Z\").\n4. Critical constraints (\"must support Node 22\").\nDrop everything else. Tier 3 is a lookup index, not a knowledge base.\n\nFORMAT:\n- Start with a source header line:\n \\`Source: bN+bM+... (XK→YK tok, Zx). [original topic]\\`\n- Output 1-3 facts per source block. Each fact is a single line: subject + outcome.\n- No explanations, no rationale, no process — just the fact.\n- Format: \"[PR/Issue/Version] — [outcome in ≤8 words]\"\n- Merge related facts from different source blocks if they concern the same topic.\n\nEXAMPLES:\n- \"v1.13.0 shipped — quality gate + GC fix (7 PRs)\"\n- \"PR #196 merged — preserve-first-user (supersedes #169)\"\n- \"Bug 1214 fixed — compress consumed all user messages\"\n- \"Chose compress-as-anchor — prefix cache benefit over synthetic injection\"\n- \"Constraint: AGENTS.md forbids as any — never suppress types\"\n\nDROP:\n- Multi-sentence context. If a fact needs >1 sentence, it's too detailed for Tier 3.\n- Lessons learned (\"tried X, failed because Y\") — drop UNLESS the failure is likely to recur and the block is <30 days old.\n- Design rationale details — keep the decision, drop the \"because\" unless it's a critical constraint.\n- Anything marked [OBSOLETE] or [SUPERSEDED] — drop entirely, note \"[N blocks obsolete]\" in the summary.\n\nSIZE TARGET: 30-60 tokens per source block (including header). For a batch of N source blocks, total output ≈ N × 40 tokens. If a source block has only one trivial fact, output just the header + one line.`;\n","import type { NudgeDecision, CompressibleRange, ProtectedRange, ContextBreakdown, CompressionBlock } from \"./types.js\";\nimport { COMPRESS_PHILOSOPHY, HOW_TO_COMPRESS_RULES, TIER2_DISTILL_RULES, TIER3_CONDENSE_RULES } from \"./compression-rules.js\";\n\nexport type NudgeVoice = \"gentle\" | \"emergency\";\n\nexport interface RenderedNudge {\n voice: NudgeVoice;\n text: string;\n}\n\nconst EFFICIENCY_NOTE = `This is an efficiency nudge to compress early and keep context lean — not an overflow warning. A separate, stronger alert will appear if the context is actually full.\\n\\n${COMPRESS_PHILOSOPHY}`;\n\nconst EMERGENCY_HEADER = `⚠️ Context limit reached — compress now. Prioritize consumed tool outputs.\\n\\n${COMPRESS_PHILOSOPHY}`;\n\nfunction formatK(n: number): string {\n if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;\n return `${n}`;\n}\n\nfunction formatBreakdown(bd?: ContextBreakdown): string {\n if (!bd) return \"\";\n const parts: string[] = [];\n if (bd.system > 0) parts.push(`${formatK(bd.system)} system`);\n if (bd.tool > 0) parts.push(`${formatK(bd.tool)} tool`);\n if (bd.summaries > 0) parts.push(`${formatK(bd.summaries)} summaries`);\n if (bd.code > 0) parts.push(`${formatK(bd.code)} code`);\n if (bd.text > 0) parts.push(`${formatK(bd.text)} text`);\n const growth = bd.growth > 0 ? `\\n+${formatK(bd.growth)} since last nudge` : \"\";\n return `Context breakdown: ${parts.join(\" | \")}${growth}`;\n}\n\n\n\nfunction formatTierTargetBlocks(blocks: CompressionBlock[]): string {\n if (blocks.length === 0) {\n return \"Target blocks: (none — no tier blocks found)\";\n }\n const lines = blocks.map((b) => {\n const summaryTokens = Math.ceil((b.summary ?? \"\").length / 4);\n const topic = b.topic ? ` \"${b.topic}\"` : \"\";\n return ` ${b.blockId} ${b.effectiveMessageIds.length} msgs ${formatK(b.compressedTokens)}→${formatK(summaryTokens)}${topic}`;\n });\n return `Target ${blocks[0]!.tier === 1 ? \"tier-1\" : \"tier-2\"} blocks to distill (${blocks.length}):\\n${lines.join(\"\\n\")}`;\n}\n\nexport function formatRanges(compressible: CompressibleRange[], protectedRanges: ProtectedRange[]): string {\n if (compressible.length === 0 && protectedRanges.length === 0) {\n return \"[No specific ranges detected — compress any consumed content.]\";\n }\n\n // Merge compressible + protected into a single oldest-first list, mirroring\n // opencode-acp's formatCompressibleRanges. Splitting them into two sections\n // lost the time order and hid overlaps; a range can be partly compressible\n // and partly protected, which only the merged view shows correctly.\n interface Merged {\n startRef: string; endRef: string; startNum: number; endNum: number;\n count: number; tokens: number;\n compressibleTokens: number; compressibleCount: number;\n protectedTokens: number; protectedCount: number; protectedTools: string[];\n toolPct: number; textPct: number; dangerous: boolean;\n }\n const refNum = (ref: string): number => {\n const m = ref.match(/\\d+/);\n return m ? parseInt(m[0], 10) : 0;\n };\n const entries: Merged[] = [];\n for (const r of compressible) {\n entries.push({\n startRef: r.startRef, endRef: r.endRef, startNum: refNum(r.startRef), endNum: refNum(r.endRef),\n count: r.count, tokens: r.tokens, toolPct: r.toolPct, textPct: r.textPct,\n compressibleTokens: r.tokens, compressibleCount: r.count,\n protectedTokens: 0, protectedCount: 0, protectedTools: [], dangerous: r.dangerous ?? false,\n });\n }\n for (const r of protectedRanges) {\n entries.push({\n startRef: r.startRef, endRef: r.endRef, startNum: refNum(r.startRef), endNum: refNum(r.endRef),\n count: r.count, tokens: r.tokens, toolPct: 0, textPct: 0,\n compressibleTokens: 0, compressibleCount: 0,\n protectedTokens: r.tokens, protectedCount: r.count, protectedTools: [...r.tools], dangerous: false,\n });\n }\n entries.sort((a, b) => a.startNum - b.startNum);\n // Merge adjacent/overlapping ranges (gap ≤ 1 ref).\n const merged: Merged[] = [];\n for (const e of entries) {\n const last = merged[merged.length - 1];\n if (last && e.startNum <= last.endNum + 1) {\n last.endRef = e.endRef;\n last.endNum = Math.max(last.endNum, e.endNum);\n last.count += e.count;\n last.tokens += e.tokens;\n last.compressibleTokens += e.compressibleTokens;\n last.compressibleCount += e.compressibleCount;\n last.protectedTokens += e.protectedTokens;\n last.protectedCount += e.protectedCount;\n if (e.dangerous) last.dangerous = true;\n for (const t of e.protectedTools) {\n if (!last.protectedTools.includes(t)) last.protectedTools.push(t);\n }\n } else {\n merged.push({ ...e });\n }\n }\n const lines = merged.map((e) => {\n const suffix = e.dangerous && e.compressibleTokens > 0 ? \" ⚠️ NOT recommended unless you are certain.\" : \"\";\n if (e.protectedTokens > 0 && e.compressibleTokens === 0) {\n return ` ${e.startRef}–${e.endRef} ${e.count} msgs ${formatK(e.tokens)} [PROTECTED: ${e.protectedTools.join(\", \")} — not compressible]${suffix}`;\n }\n if (e.protectedTokens > 0 && e.compressibleTokens > 0) {\n return ` ${e.startRef}–${e.endRef} ${e.count} msgs ${formatK(e.tokens)} [${formatK(e.compressibleTokens)} compressible | ${formatK(e.protectedTokens)} protected: ${e.protectedTools.join(\", \")}]${suffix}`;\n }\n return ` ${e.startRef}–${e.endRef} ${e.count} msgs ${formatK(e.tokens)} [tool ${e.toolPct}% | text ${e.textPct}%]${suffix}`;\n });\n return `Compressible ranges (${merged.length}, oldest first):\\n${lines.join(\"\\n\")}`;\n}\n\nexport function renderNudgeText(decision: NudgeDecision): RenderedNudge {\n const breakdownStr = formatBreakdown(decision.contextBreakdown);\n const rangesStr = formatRanges(decision.compressibleRanges, decision.protectedRanges ?? []);\n\n if (decision.tier !== null && decision.tier >= 2) {\n const isT2 = decision.tier === 2;\n const targets = decision.tierTargetBlocks ?? [];\n const blockList = formatTierTargetBlocks(targets);\n const startId = targets[0]?.blockId ?? \"b1\";\n const endId = targets[targets.length - 1]?.blockId ?? \"b5\";\n return {\n voice: \"gentle\",\n text: [\n EFFICIENCY_NOTE,\n \"\",\n breakdownStr,\n \"\",\n `[TIER ${decision.tier} ${isT2 ? \"DISTILLATION\" : \"CONDENSATION\"} TRIGGER]`,\n isT2\n ? `Your tier-1 compression summaries have accumulated. Distill them into a single denser tier-2 summary. Use block IDs as boundaries (startId and endId as bN). Any raw (uncompressed) messages sitting between the boundary blocks are absorbed into the tier-2 block as well — apply HOW TO COMPRESS to those raw messages and the TIER 2 distillation rules to the existing summaries, so the whole span is covered and nothing is lost.`\n : `Your tier-2 compression summaries have accumulated. Condense them further into a tier-3 ultra-condensed summary. Use block IDs as boundaries (startId and endId as bN). Any raw (uncompressed) messages sitting between the boundary blocks are absorbed into the tier-3 block as well — apply HOW TO COMPRESS to those raw messages and the TIER 3 condensation rules to the existing summaries, so the whole span is covered and nothing is lost.`,\n blockList,\n `Example: compress({ content: [{ startId: \"${startId}\", endId: \"${endId}\", summary: \"...\" }] })`,\n \"\",\n HOW_TO_COMPRESS_RULES,\n \"\",\n isT2 ? TIER2_DISTILL_RULES : TIER3_CONDENSE_RULES,\n ].join(\"\\n\"),\n };\n }\n\n const isEmergency = !!decision.breakdown?.emergencyOverride;\n\n if (isEmergency) {\n return {\n voice: \"emergency\",\n text: [\n EMERGENCY_HEADER,\n \"\",\n breakdownStr,\n \"\",\n HOW_TO_COMPRESS_RULES,\n \"\",\n `{ \"topic\": \"...\", \"content\": [{ \"startId\": \"<ID>\", \"endId\": \"<ID>\", \"summary\": \"...\" }] }`,\n \"Only use IDs from visible messages above. Compress older work first.\",\n \"\",\n rangesStr,\n ].join(\"\\n\"),\n };\n }\n\n return {\n voice: \"gentle\",\n text: [\n EFFICIENCY_NOTE,\n \"\",\n breakdownStr,\n \"\",\n HOW_TO_COMPRESS_RULES,\n \"\",\n rangesStr,\n \"\",\n `💡 Compress all ranges in one call (pass multiple content entries: \\`content: [{...}, {...}]\\`).`,\n ].join(\"\\n\"),\n };\n}\n","import { SUMMARY_HEADER } from \"./prune.js\";\nimport type { CompressionBlock, CompressionState, CoreMessage } from \"./types.js\";\n\nexport function parseBlockIdArg(arg: string): string | null {\n const normalized = arg.trim().toLowerCase();\n const refMatch = /^b0*(\\d+)$/.exec(normalized);\n if (refMatch && refMatch[1] !== undefined) return `b${refMatch[1]}`;\n const numMatch = /^(\\d+)$/.exec(normalized);\n if (numMatch && numMatch[1] !== undefined) return `b${numMatch[1]}`;\n return null;\n}\n\nexport function findBlocksOverlappingMessages(\n state: CompressionState,\n messageIds: Set<string>,\n): CompressionBlock[] {\n if (messageIds.size === 0) return [];\n const matched: CompressionBlock[] = [];\n for (const block of state.blocks) {\n if (!block.active) continue;\n if (block.effectiveMessageIds.some((id) => messageIds.has(id))) {\n matched.push(block);\n }\n }\n return matched.sort((a, b) => numericPart(a.blockId) - numericPart(b.blockId));\n}\n\nexport function findActiveAncestor(state: CompressionState, blockId: string): string | null {\n const start = state.blocks.find((b) => b.blockId === blockId);\n if (!start) return null;\n const queue: string[] = [...start.directBlockIds];\n const visited = new Set<string>();\n while (queue.length > 0) {\n const currentId = queue.shift()!;\n if (visited.has(currentId)) continue;\n visited.add(currentId);\n const current = state.blocks.find((b) => b.blockId === currentId);\n if (!current) continue;\n if (current.active) return current.blockId;\n for (const ancestorId of current.directBlockIds) {\n if (!visited.has(ancestorId)) queue.push(ancestorId);\n }\n }\n return null;\n}\n\nexport interface DeactivateOptions {\n deep?: boolean;\n}\n\nexport function deactivateBlock(\n state: CompressionState,\n blockIds: string[],\n options: DeactivateOptions = {},\n): CompressionState {\n const targets = new Set(blockIds);\n\n const updated = state.blocks.map((block) => {\n if (!targets.has(block.blockId) || !block.active) return block;\n return {\n ...block,\n active: false,\n durationMs: block.durationMs,\n createdAt: block.createdAt,\n };\n });\n\n let final = updated;\n if (options.deep) {\n const visited = new Set<string>();\n const queue: string[] = [];\n for (const id of blockIds) {\n const block = updated.find((b) => b.blockId === id);\n if (block) queue.push(...block.directBlockIds);\n }\n while (queue.length > 0) {\n const id = queue.shift()!;\n if (visited.has(id)) continue;\n visited.add(id);\n final = final.map((block) => {\n if (block.blockId !== id) return block;\n queue.push(...block.directBlockIds);\n return block.active ? { ...block, active: false } : block;\n });\n }\n }\n\n return { ...state, blocks: final };\n}\n\nexport interface RestoredPreviewResult {\n preview: string;\n restoredCount: number;\n}\n\nexport function buildRestoredContentPreview(\n messages: CoreMessage[],\n beforeActiveMessageIds: Set<string>,\n state: CompressionState,\n): RestoredPreviewResult {\n const restored: CoreMessage[] = [];\n for (const message of messages) {\n if (!beforeActiveMessageIds.has(message.id)) continue;\n const stillCovered = state.blocks.some(\n (b) => b.active && b.effectiveMessageIds.includes(message.id),\n );\n if (!stillCovered) restored.push(message);\n }\n\n if (restored.length === 0) return { preview: \"\", restoredCount: 0 };\n\n const lines: string[] = [];\n let totalLength = 0;\n const MAX_PREVIEW = 2000;\n const MAX_PER_MESSAGE = 200;\n\n for (const message of restored) {\n if (totalLength >= MAX_PREVIEW) break;\n const text = message.text ?? \"\";\n const truncated = text.length > MAX_PER_MESSAGE ? text.slice(0, MAX_PER_MESSAGE) + \"...\" : text;\n const label =\n message.toolName && message.contentType !== \"text\"\n ? `${message.toolName}: ${truncated}`\n : `[${message.role}] ${truncated}`;\n lines.push(label);\n totalLength += label.length + 1;\n }\n\n return { preview: lines.join(\"\\n\"), restoredCount: restored.length };\n}\n\nexport interface CollectedContentResult {\n /** Rendered, human-readable content string (empty when count is 0). */\n text: string;\n /** Number of items rendered: direct messages + nested summaries (full=false) or all messages (full=true). */\n count: number;\n}\n\nexport interface CollectContentOptions {\n /** When true, recurse through all nested tiers to original messages. Default: false (one tier up — nested active children stay folded, their summaries shown). */\n full?: boolean;\n}\n\n/**\n * Collect a block's content as a readable string WITHOUT modifying state.\n *\n * This is the cache-safe decompress primitive: the block stays compressed\n * (folded), its summary stays in place, and the full content is returned as\n * text for the caller to surface (e.g. as a tool result appended to the\n * conversation). Unlike deactivateBlock + prune, this does not mutate the\n * message-array prefix, so prompt cache is preserved.\n *\n * full=false (default): one tier up. Nested ACTIVE children of this block\n * stay folded; their summaries are rendered in place of their messages.\n * The block's own direct messages (not covered by any active child) are\n * rendered in full.\n * full=true: recurse through all nested tiers; every effective message is\n * rendered in full.\n *\n * Returns { text: \"\", count: 0 } when the block covers no messages.\n */\nexport function collectBlockContent(\n state: CompressionState,\n block: CompressionBlock,\n messages: CoreMessage[],\n options: CollectContentOptions = {},\n): CollectedContentResult {\n const full = options.full ?? false;\n const targetIds = new Set(block.effectiveMessageIds);\n\n if (full) {\n const msgs = messages.filter((m) => targetIds.has(m.id));\n if (msgs.length === 0) return { text: \"\", count: 0 };\n return { text: msgs.map(formatMessage).join(\"\\n\\n\"), count: msgs.length };\n }\n\n // One tier up: messages covered by nested ACTIVE children stay folded\n // (their summaries shown); the block's own direct messages shown in full.\n const nestedChildren: CompressionBlock[] = [];\n const nestedCovered = new Set<string>();\n for (const childId of block.directBlockIds) {\n const child = state.blocks.find((b) => b.blockId === childId);\n if (!child?.active) continue;\n nestedChildren.push(child);\n for (const id of child.effectiveMessageIds) nestedCovered.add(id);\n }\n\n const parts: string[] = [];\n for (const child of nestedChildren) {\n const label = child.topic ? `${child.blockId}: ${child.topic}` : child.blockId;\n parts.push(`${SUMMARY_HEADER} — ${label}\\n${child.summary}`);\n }\n\n let directCount = 0;\n for (const m of messages) {\n if (targetIds.has(m.id) && !nestedCovered.has(m.id)) {\n parts.push(formatMessage(m));\n directCount++;\n }\n }\n\n const count = directCount + nestedChildren.length;\n if (count === 0) return { text: \"\", count: 0 };\n return { text: parts.join(\"\\n\\n\"), count };\n}\n\nfunction formatMessage(message: CoreMessage): string {\n const text = message.text ?? \"\";\n if (message.toolName && message.contentType !== \"text\") {\n return `[${message.role} • ${message.toolName}]\\n${text}`;\n }\n return `[${message.role}]\\n${text}`;\n}\n\nfunction numericPart(blockId: string): number {\n const match = /^b(\\d+)$/.exec(blockId);\n return match && match[1] !== undefined ? Number(match[1]) : 0;\n}\n","import { refForRaw } from \"./refs.js\";\nimport type { CompressionBlock, CompressionState, CoreMessage } from \"./types.js\";\n\nfunction formatTokens(n: number): string {\n if (!Number.isFinite(n) || n <= 0) return \"0\";\n return n >= 1000 ? `${(n / 1000).toFixed(1)}K` : String(n);\n}\n\nfunction pct(n: number, total: number): number {\n if (n <= 0 || total <= 0) return 0;\n return Math.max(1, Math.round((n / total) * 100));\n}\n\nfunction numericPart(blockId: string): number {\n const match = /^b(\\d+)$/.exec(blockId);\n return match && match[1] !== undefined ? Number(match[1]) : 0;\n}\n\nfunction summaryTokensOf(block: CompressionBlock, countTokens: (t: string) => number): number {\n return countTokens(block.summary);\n}\n\nfunction effectiveCompressedTokens(\n block: CompressionBlock,\n _state: CompressionState,\n _countTokens: (t: string) => number,\n): number {\n // block.compressedTokens already records the full input token count of the\n // operation that created this block: for a tier-1 block that is the raw\n // messages; for a tier-2 block it is the tier-1 summaries + the new\n // messages it spans. Recursing into directBlockIds and summing children's\n // compressedTokens double-counts the consumed children, so we return the\n // block's own value directly. (The previous recursion inflated tier-2+\n // \"original\" figures and mis-ordered the status report.)\n return block.compressedTokens;\n}\n\nfunction tierLabel(block: CompressionBlock): string {\n return `T${block.tier}`;\n}\n\nfunction tierBreakdown(\n blocks: CompressionBlock[],\n countTokens: (t: string) => number,\n): string | null {\n const tierTokens: Record<number, number> = {};\n for (const block of blocks) {\n tierTokens[block.tier] = (tierTokens[block.tier] ?? 0) + summaryTokensOf(block, countTokens);\n }\n const tiers = Object.keys(tierTokens).map(Number);\n if (tiers.length <= 1) return null;\n const parts: string[] = [];\n for (const tier of [1, 2, 3]) {\n if (tierTokens[tier]) parts.push(`T${tier}: ${formatTokens(tierTokens[tier])}`);\n }\n return parts.join(\" | \");\n}\n\ninterface VisibleMessageInfo {\n ref: string;\n tokens: number;\n tool: string;\n index: number;\n}\n\nfunction collectVisible(\n messages: CoreMessage[],\n state: CompressionState,\n countTokens: (t: string) => number,\n): { visible: VisibleMessageInfo[]; summaryTokens: number } {\n const coveredIds = new Set<string>();\n for (const block of state.blocks) {\n if (!block.active) continue;\n for (const id of block.effectiveMessageIds) coveredIds.add(id);\n }\n let summaryTokens = 0;\n for (const block of state.blocks) {\n if (block.active) summaryTokens += summaryTokensOf(block, countTokens);\n }\n const visible: VisibleMessageInfo[] = [];\n messages.forEach((message, index) => {\n if (coveredIds.has(message.id)) return;\n const ref = refForRaw(state.messageRefs, message.id);\n if (!ref) return;\n const tokens = countTokens(message.text ?? \"\");\n const tool = message.toolName ?? \"text\";\n if (tokens > 0) visible.push({ ref, tokens, tool, index });\n });\n return { visible, summaryTokens };\n}\n\nexport interface StatusReportOptions {\n scope?: \"compressed\" | \"uncompressed\";\n view?: \"ranges\" | \"messages\";\n tool?: string;\n sort?: \"size\" | \"time\" | \"tool\" | \"age\";\n limit?: number;\n}\n\nexport function buildStatusReport(\n state: CompressionState,\n messages: CoreMessage[],\n countTokens: (t: string) => number,\n options: StatusReportOptions = {},\n): string {\n const scope = options.scope;\n const view = options.view ?? \"ranges\";\n const toolFilter = options.tool;\n const sort = options.sort ?? \"size\";\n const limit = options.limit ?? 30;\n\n const activeBlocks = state.blocks\n .filter((b) => b.active)\n .sort((a, b) => numericPart(a.blockId) - numericPart(b.blockId));\n\n if (scope === \"compressed\") {\n return renderCompressedDrilldown(activeBlocks, state, sort, limit, countTokens);\n }\n\n const { visible, summaryTokens } = collectVisible(messages, state, countTokens);\n\n if (scope === \"uncompressed\") {\n if (view === \"messages\") {\n return renderMessageDrilldown(visible, toolFilter, sort, limit);\n }\n return renderUncompressedRanges(visible);\n }\n\n return renderOverview(visible, summaryTokens, activeBlocks, state, countTokens, limit);\n}\n\nfunction renderOverview(\n visible: VisibleMessageInfo[],\n summaryTokens: number,\n blocks: CompressionBlock[],\n state: CompressionState,\n countTokens: (t: string) => number,\n limit: number,\n): string {\n const lines: string[] = [];\n const toolTypeMap = new Map<string, number>();\n for (const message of visible) {\n toolTypeMap.set(message.tool, (toolTypeMap.get(message.tool) ?? 0) + message.tokens);\n }\n const topTool = [...toolTypeMap.entries()].sort((a, b) => b[1] - a[1])[0]?.[0];\n\n const totalTool = visible\n .filter((m) => m.tool !== \"text\")\n .reduce((sum, m) => sum + m.tokens, 0);\n const totalText = visible\n .filter((m) => m.tool === \"text\")\n .reduce((sum, m) => sum + m.tokens, 0);\n const total = summaryTokens + totalTool + totalText;\n\n lines.push(\"CONTEXT BREAKDOWN\");\n lines.push(\n ` ${formatTokens(totalTool)} tool (${pct(totalTool, total)}%) | ${formatTokens(totalText)} text (${pct(totalText, total)}%) | ${formatTokens(summaryTokens)} summaries (${pct(summaryTokens, total)}%)`,\n );\n const topTypes = [...toolTypeMap.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 3);\n if (topTypes.length > 0) {\n lines.push(` Top tools: ${topTypes.map(([t, n]) => `${t} (${pct(n, total)}%)`).join(\", \")}`);\n }\n\n lines.push(\"\");\n if (blocks.length === 0) {\n lines.push(\"COMPRESSED BLOCKS\");\n lines.push(\" No compressed blocks.\");\n } else {\n const totalSummary = blocks.reduce((s, b) => s + summaryTokensOf(b, countTokens), 0);\n const totalEffective = blocks.reduce(\n (s, b) => s + effectiveCompressedTokens(b, state, countTokens),\n 0,\n );\n lines.push(\n `COMPRESSED BLOCKS — ${blocks.length} active (${formatTokens(totalSummary)} summary, ${formatTokens(totalEffective)} original)`,\n );\n const breakdown = tierBreakdown(blocks, countTokens);\n if (breakdown) lines.push(` Tier usage: ${breakdown}`);\n lines.push(\"\");\n const sorted = [...blocks].sort(\n (a, b) =>\n effectiveCompressedTokens(b, state, countTokens) -\n effectiveCompressedTokens(a, state, countTokens) ||\n b.createdAt - a.createdAt,\n );\n for (const block of sorted.slice(0, limit)) {\n const topic = block.topic ?? \"(no topic)\";\n const eff = effectiveCompressedTokens(block, state, countTokens);\n lines.push(\n ` ${block.blockId} (${tierLabel(block)}) ${formatTokens(eff)}→${formatTokens(summaryTokensOf(block, countTokens))} ${block.effectiveMessageIds.length} msgs \"${topic}\"`,\n );\n }\n }\n\n lines.push(\"\");\n lines.push(\n `Tip: buildStatusReport({scope:\"uncompressed\", view:\"messages\", tool:\"${topTool ?? \"bash\"}\"}) for per-message listing`,\n );\n return lines.join(\"\\n\");\n}\n\nfunction renderUncompressedRanges(visible: VisibleMessageInfo[]): string {\n const lines: string[] = [];\n const totalTokens = visible.reduce((s, m) => s + m.tokens, 0);\n lines.push(`UNCOMPRESSED — ${formatTokens(totalTokens)} | ${visible.length} visible messages`);\n lines.push(\"\");\n if (visible.length === 0) {\n lines.push(\" (no uncompressed messages)\");\n return lines.join(\"\\n\");\n }\n // Merge consecutive messages into ranges (by numeric ref), aggregating\n // token counts and dominant tool so the view reads as blocks, not a\n // per-message firehose — mirroring the Compressible Ranges output.\n interface Merged { startRef: string; endRef: string; startNum: number; count: number; tokens: number; tool: string; }\n const refNum = (ref: string): number => {\n const m = ref.match(/\\d+/);\n return m ? parseInt(m[0], 10) : 0;\n };\n const merged: Merged[] = [];\n for (const m of visible) {\n const num = refNum(m.ref);\n const last = merged[merged.length - 1];\n if (last && num === last.startNum + last.count) {\n last.endRef = m.ref;\n last.count += 1;\n last.tokens += m.tokens;\n } else {\n merged.push({ startRef: m.ref, endRef: m.ref, startNum: num, count: 1, tokens: m.tokens, tool: m.tool });\n }\n }\n for (const r of merged.slice(0, 30)) {\n const range = r.count === 1 ? r.startRef : `${r.startRef}–${r.endRef}`;\n lines.push(` ${range} (${r.count} msgs, ${formatTokens(r.tokens)}${r.count > 1 ? ` (${Math.round(r.tokens / r.count)}/msg)` : \"\"}) ${r.tool}`);\n }\n if (merged.length > 30) {\n lines.push(` ... and ${merged.length - 30} more ranges`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction renderMessageDrilldown(\n visible: VisibleMessageInfo[],\n toolFilter: string | undefined,\n sort: string,\n limit: number,\n): string {\n let filtered = visible;\n if (toolFilter) filtered = filtered.filter((m) => m.tool === toolFilter);\n\n if (sort === \"time\") filtered.sort((a, b) => a.index - b.index);\n else if (sort === \"tool\") filtered.sort((a, b) => a.tool.localeCompare(b.tool) || b.tokens - a.tokens);\n else filtered.sort((a, b) => b.tokens - a.tokens);\n\n const totalTokens = filtered.reduce((s, m) => s + m.tokens, 0);\n const allTokens = visible.reduce((s, m) => s + m.tokens, 0);\n const header = toolFilter\n ? `UNCOMPRESSED — ${toolFilter}: ${formatTokens(totalTokens)} | ${filtered.length} msgs | ${pct(totalTokens, allTokens)}% of visible`\n : `UNCOMPRESSED — ${formatTokens(totalTokens)} | ${filtered.length} msgs`;\n const lines = [header, `Sorted by ${sort}`, \"\"];\n const shown = filtered.slice(0, limit);\n for (const message of shown) {\n lines.push(` ${message.ref} (${formatTokens(message.tokens)}) ${message.tool}`);\n }\n if (filtered.length > shown.length) {\n lines.push(\"\");\n lines.push(`${shown.length} of ${filtered.length} shown.`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction renderCompressedDrilldown(\n blocks: CompressionBlock[],\n state: CompressionState,\n sort: string,\n limit: number,\n countTokens: (t: string) => number,\n): string {\n let sorted = [...blocks];\n if (sort === \"time\") sorted.sort((a, b) => a.createdAt - b.createdAt);\n else if (sort === \"age\") sorted.sort((a, b) => b.survivedCount - a.survivedCount);\n else\n sorted.sort(\n (a, b) =>\n effectiveCompressedTokens(b, state, countTokens) -\n effectiveCompressedTokens(a, state, countTokens) ||\n b.createdAt - a.createdAt,\n );\n\n const totalSummary = sorted.reduce((s, b) => s + summaryTokensOf(b, countTokens), 0);\n const totalEffective = sorted.reduce(\n (s, b) => s + effectiveCompressedTokens(b, state, countTokens),\n 0,\n );\n const lines = [\n `COMPRESSED — ${sorted.length} blocks | ${formatTokens(totalEffective)} original → ${formatTokens(totalSummary)} summary`,\n ];\n const breakdown = tierBreakdown(sorted, countTokens);\n if (breakdown) lines.push(`Tier usage: ${breakdown}`);\n lines.push(\"\");\n const shown = sorted.slice(0, limit);\n for (const block of shown) {\n const nested = block.directBlockIds.length > 0 ? ` nested=[${block.directBlockIds.join(\",\")}]` : \"\";\n const topic = block.topic ?? \"(no topic)\";\n const eff = effectiveCompressedTokens(block, state, countTokens);\n lines.push(\n ` ${block.blockId} (${tierLabel(block)}) ${formatTokens(eff)}→${formatTokens(summaryTokensOf(block, countTokens))} ${block.effectiveMessageIds.length} msgs age=${block.survivedCount} ${block.generation}${nested}`,\n );\n lines.push(` \"${topic}\"`);\n }\n if (sorted.length > shown.length) {\n lines.push(\"\");\n lines.push(`${shown.length} of ${sorted.length} shown.`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function buildRecap(\n state: CompressionState,\n blockId?: string,\n): string {\n const activeBlocks = state.blocks\n .filter((b) => b.active)\n .sort((a, b) => numericPart(a.blockId) - numericPart(b.blockId));\n\n if (blockId !== undefined) {\n const block = state.blocks.find((b) => b.blockId === blockId);\n if (!block) {\n const activeList = activeBlocks.map((b) => b.blockId).join(\", \");\n return `Block ${blockId} not found. Active blocks: ${activeList}`;\n }\n if (!block.active) {\n return `Block ${blockId} is inactive (deactivated by nested compression).`;\n }\n const range = `${block.effectiveMessageIds.length} messages`;\n return `[Compressed conversation section]\\n${block.summary}\\n\\n[${blockId} | ${range} | topic: \"${block.topic ?? \"(none)\"}\"]`;\n }\n\n if (activeBlocks.length === 0) return \"No active compression blocks.\";\n\n const lines = [`Active compression blocks (${activeBlocks.length}):`];\n for (const block of activeBlocks) {\n const range = `${block.effectiveMessageIds.length} messages`;\n const preview = block.summary.slice(0, 200);\n lines.push(`\\n${block.blockId} | ${range} | \"${block.topic ?? \"(none)\"}\"`);\n lines.push(` ${preview}${block.summary.length > 200 ? \"...\" : \"\"}`);\n }\n lines.push(`\\nCall with blockId to get the full summary.`);\n return lines.join(\"\\n\");\n}\n","import { createCore } from \"./compress.js\";\nimport { assignRefs, highestUsedIndex } from \"./refs.js\";\nimport { defaultCountTokens } from \"./tokenize.js\";\nimport type { CompressionState, CoreMessage } from \"./types.js\";\n\nexport interface CompressInputEntry {\n startId?: string;\n endId?: string;\n messageId?: string;\n summary: string;\n topic?: string;\n}\n\nexport interface RebuildResult {\n state: CompressionState;\n blocksRebuilt: number;\n}\n\nexport interface RebuildPorts {\n countTokens?: (text: string) => number;\n}\n\n/**\n * Fork-recovery: reconstruct compression state by replaying historical\n * `compress` tool-call messages. Message refs (mNNNNN) are assigned by\n * message order, so they are fork-stable — a ref in a historical compress\n * input points to the same logical message after a fork regenerates IDs.\n * The rebuilt state is an approximation: only raw model summaries are\n * replayed (no protected-content enrichments).\n */\nexport function rebuildCompressionState(\n state: CompressionState,\n messages: CoreMessage[],\n config: import(\"./types.js\").Config,\n ports: RebuildPorts = {},\n): RebuildResult {\n const core = createCore({ countTokens: ports.countTokens ?? defaultCountTokens });\n const refResult = assignRefs(messages, {\n existing: state.messageRefs,\n nextIndex: highestUsedIndex(state.messageRefs) + 1,\n });\n let working: CompressionState = { ...state, messageRefs: refResult.map };\n\n const invocations = collectCompressInvocations(messages);\n let blocksRebuilt = 0;\n\n for (const invocation of invocations) {\n const ranges = extractRanges(invocation.input, invocation.callId);\n if (ranges.length === 0) continue;\n const result = core.applyCompression({ ranges, messages, state: working, config });\n working = result.state;\n blocksRebuilt += result.result.blocksCreated;\n }\n\n return { state: working, blocksRebuilt };\n}\n\ninterface CompressInvocation {\n callId: string | undefined;\n input: unknown;\n}\n\nfunction collectCompressInvocations(messages: CoreMessage[]): CompressInvocation[] {\n const invocations: CompressInvocation[] = [];\n for (const message of messages) {\n if (message.toolName !== \"compress\" || message.contentType !== \"tool-call\") continue;\n let input: unknown;\n try {\n input = JSON.parse(message.text ?? \"\");\n } catch {\n continue;\n }\n invocations.push({ callId: message.toolCallId, input });\n }\n return invocations;\n}\n\nfunction extractRanges(\n input: unknown,\n callId: string | undefined,\n): Array<{\n startRef: string;\n endRef: string;\n summary: string;\n topic?: string;\n compressCallId?: string;\n}> {\n const content = (input as { content?: unknown[] })?.content;\n if (!Array.isArray(content)) return [];\n const ranges = [];\n for (const entry of content) {\n if (!entry || typeof entry !== \"object\") continue;\n const e = entry as CompressInputEntry;\n if (typeof e.summary !== \"string\") continue;\n const start = e.startId ?? e.messageId;\n const end = e.endId ?? e.messageId;\n if (typeof start !== \"string\" || typeof end !== \"string\") continue;\n ranges.push({\n startRef: start,\n endRef: end,\n summary: e.summary,\n topic: typeof e.topic === \"string\" ? e.topic : undefined,\n compressCallId: callId,\n });\n }\n return ranges;\n}\n","import type { SearchAlgorithm, SearchDoc, ScoredBlock } from \"../types.js\";\n\n/**\n * Substring counting — the original baseline algorithm.\n * Exact, lowercased substring occurrence counts. Predictable but blind to\n * morphology, typos, and CJK word boundaries. Kept for backward compat and\n * as a deterministic reference.\n */\nexport const substringAlgorithm: SearchAlgorithm = {\n name: \"substring\",\n description: \"Exact substring counting (original baseline). Predictable, no normalization.\",\n score(docs: SearchDoc[], query: string): ScoredBlock[] {\n const terms = query.toLowerCase().trim().split(/\\s+/).filter((t) => t.length > 0);\n if (terms.length === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));\n return docs.map((d) => {\n const haystack = d.text.toLowerCase();\n let score = 0;\n for (const term of terms) score += countOccurrences(haystack, term);\n return { ref: d.ref, score };\n });\n },\n};\n\nfunction countOccurrences(haystack: string, needle: string): number {\n if (!needle) return 0;\n return haystack.split(needle).length - 1;\n}\n","/**\n * Lightweight English stemmer (suffix stripping, Porter-inspired).\n * Zero dependencies. Good enough for IR morphology normalization:\n * tokens → token, running → runn, compressed → compress,\n * authentication → authentic, handling → handl, subagents → subagent\n *\n * Not a full Porter stemmer — intentionally simpler and faster. CJK is\n * untouched (handled by bigram tokenization, not stemming).\n */\nexport function stem(word: string): string {\n let w = word;\n if (w.length <= 3) return w;\n if (w.endsWith(\"ies\")) w = w.slice(0, -3) + \"y\";\n else if (w.endsWith(\"ses\") || w.endsWith(\"xes\") || w.endsWith(\"zes\")) w = w.slice(0, -2);\n else if (w.endsWith(\"ches\") || w.endsWith(\"shes\")) w = w.slice(0, -2);\n else if (w.endsWith(\"s\") && !w.endsWith(\"ss\")) w = w.slice(0, -1);\n if (w.endsWith(\"ing\") && w.length > 5) w = w.slice(0, -3);\n if (w.endsWith(\"ed\") && w.length > 4) w = w.slice(0, -2);\n if (w.endsWith(\"ation\") && w.length > 6) w = w.slice(0, -3);\n else if (w.endsWith(\"tion\") && w.length > 5) w = w.slice(0, -4) + \"t\";\n else if (w.endsWith(\"ion\") && w.length > 4) w = w.slice(0, -3);\n if (w.endsWith(\"ment\") && w.length > 6) w = w.slice(0, -4);\n if (w.endsWith(\"ness\") && w.length > 6) w = w.slice(0, -4);\n if (w.endsWith(\"ly\") && w.length > 4) w = w.slice(0, -2);\n return w;\n}\n","/**\n * Search tokenizer.\n *\n * Handles mixed Latin + CJK content — the single biggest quality lever\n * over plain substring search. Latin is split on non-word boundaries;\n * CJK (no spaces) is decomposed into overlapping bigrams so a query like\n * \"身份验证\" still scores against doc text \"身份验证流程\".\n */\n\nconst CJK = /[\\u3400-\\u9fff\\uf900-\\ufaff\\u3040-\\u30ff\\uac00-\\ud7af]/;\nconst CJK_RUN = new RegExp(`${CJK.source}+`, \"g\");\nconst LATIN_WORD = /[a-z][a-z0-9_]*[a-z0-9]|[a-z0-9]/g;\n\nimport { stem } from \"./stemmer.js\";\n\nexport interface TokenizeOptions {\n stem?: boolean;\n}\n\nexport function tokenize(text: string, opts: TokenizeOptions = {}): string[] {\n const lower = text.toLowerCase();\n const tokens: string[] = [];\n\n const latin = lower.match(LATIN_WORD) ?? [];\n for (let w of latin) {\n if (w.length >= 2) {\n if (opts.stem) w = stem(w);\n tokens.push(w);\n }\n }\n\n const cjkRuns = lower.match(CJK_RUN) ?? [];\n for (const run of cjkRuns) {\n if (run.length === 1) {\n tokens.push(run);\n } else {\n for (let i = 0; i < run.length - 1; i++) tokens.push(run.slice(i, i + 2));\n for (const ch of run) tokens.push(ch);\n }\n }\n\n return tokens;\n}\n\n/** Character bigrams over arbitrary text — used by fuzzy matching. */\nexport function charBigrams(text: string): string[] {\n const grams: string[] = [];\n for (let i = 0; i < text.length - 1; i++) {\n const pair = text.slice(i, i + 2);\n if (pair.trim().length === pair.length) grams.push(pair);\n }\n return grams;\n}\n\n/** Term-frequency map. */\nexport function tfMap(text: string, stem: boolean): Map<string, number> {\n const m = new Map<string, number>();\n for (const t of tokenize(text, { stem })) m.set(t, (m.get(t) ?? 0) + 1);\n return m;\n}\n","import type { SearchAlgorithm, SearchDoc, ScoredBlock } from \"../types.js\";\nimport { tokenize, tfMap } from \"../tokenizer.js\";\n\n/**\n * BM25 with stemming + CJK bigram tokenization.\n *\n * k1=1.2, b=0.75 (standard IR). IDF down-weights terms common across the\n * corpus; length normalization prevents long summaries from dominating by\n * raw term count. Stemming collapses English morphology\n * (compress/compressed/compression → ~compress).\n *\n * On a 30-block mixed EN/CJK benchmark: MRR 0.812 vs 0.821 for substring\n * alone — not better in isolation, but a strong precision component when\n * combined with fuzzy recall (see hybrid.ts).\n */\nexport const bm25Algorithm: SearchAlgorithm = {\n name: \"bm25\",\n description: \"BM25 with stemming + CJK bigram tokenization. IR-standard relevance ranking.\",\n score(docs: SearchDoc[], query: string): ScoredBlock[] {\n const N = docs.length;\n const k1 = 1.2;\n const b = 0.75;\n const parsed = docs.map((d) => {\n const text = d.text;\n const tf = tfMap(text, true);\n let len = 0;\n for (const v of tf.values()) len += v;\n return { id: d.ref, tf, len };\n });\n const avgdl = parsed.reduce((s, d) => s + d.len, 0) / (N || 1);\n\n const qTerms = tokenize(query, { stem: true });\n if (qTerms.length === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));\n\n const idf = new Map<string, number>();\n for (const t of new Set(qTerms)) {\n let df = 0;\n for (const d of parsed) if (d.tf.has(t)) df++;\n idf.set(t, Math.log(1 + (N - df + 0.5) / (df + 0.5)));\n }\n\n return parsed.map((d) => {\n let score = 0;\n for (const t of qTerms) {\n const f = d.tf.get(t) ?? 0;\n if (f === 0) continue;\n const idfT = idf.get(t) ?? 0;\n score += (idfT * (f * (k1 + 1))) / (f + k1 * (1 - b + (b * d.len) / (avgdl || 1)));\n }\n return { ref: d.id, score };\n });\n },\n};\n","import type { SearchAlgorithm, SearchDoc, ScoredBlock } from \"../types.js\";\nimport { charBigrams } from \"../tokenizer.js\";\n\n/**\n * Fuzzy character-bigram matching (Jaccard-style).\n *\n * Decomposes the query into character bigrams and measures overlap with\n * each doc. Robust to typos (tokan≈token), partial words, and works\n * uniformly across all scripts (CJK benefits most). Only considers query\n * tokens of length >= 4 to avoid noise from short common-character pairs.\n *\n * On benchmark: highest recall@3 (0.913) of any single algorithm — it is\n * the recall boost in the hybrid default.\n */\nexport const fuzzyAlgorithm: SearchAlgorithm = {\n name: \"fuzzy\",\n description: \"Character bigram overlap. Typo-tolerant, script-agnostic, high recall.\",\n score(docs: SearchDoc[], query: string): ScoredBlock[] {\n const qTokens = query.toLowerCase().split(/[\\s,]+/).filter((t) => t.length >= 4);\n if (qTokens.length === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));\n\n const qGrams = new Set<string>();\n for (const t of qTokens) for (const g of charBigrams(t)) qGrams.add(g);\n if (qGrams.size === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));\n\n return docs.map((d) => {\n const haystack = d.text.toLowerCase();\n const docGrams = new Set(charBigrams(haystack));\n let hits = 0;\n for (const g of qGrams) if (docGrams.has(g)) hits++;\n return { ref: d.ref, score: hits / qGrams.size };\n });\n },\n};\n","import type { SearchAlgorithm, SearchDoc, ScoredBlock } from \"../types.js\";\nimport { bm25Algorithm } from \"./bm25.js\";\nimport { fuzzyAlgorithm } from \"./fuzzy.js\";\n\n/**\n * Hybrid: normalized BM25(stem) + fuzzy n-gram, weighted 0.7 / 0.3.\n *\n * BM25 supplies precision on real terms (with morphology + IDF + length\n * norm); fuzzy supplies recall on typos, partials, and cross-script.\n * Each component is max-normalized to [0,1] before weighting so their\n * scales are comparable regardless of corpus size.\n *\n * Benchmark (30 blocks, 45 mixed EN/CJK queries):\n * substring MRR 0.821 R@1 0.804 R@3 0.826\n * bm25 MRR 0.812 R@1 0.804 R@3 0.826\n * fuzzy MRR 0.834 R@1 0.761 R@3 0.913\n * hybrid MRR 0.881 R@1 0.848 R@3 0.913 ← best on every metric\n *\n * The weight ratio is robust: 0.6–0.8 for BM25 all score within 0.001 MRR.\n */\n\nconst W_BM25 = 0.7;\nconst W_FUZZY = 0.3;\n\nexport const hybridAlgorithm: SearchAlgorithm = {\n name: \"hybrid\",\n description: \"Weighted BM25(stem) + fuzzy n-gram. Default — best precision + recall.\",\n score(docs: SearchDoc[], query: string): ScoredBlock[] {\n const bm = bm25Algorithm.score(docs, query);\n const fz = fuzzyAlgorithm.score(docs, query);\n const maxBm = Math.max(...bm.map((r) => r.score), 1e-9);\n const maxFz = Math.max(...fz.map((r) => r.score), 1e-9);\n const bmMap = new Map(bm.map((r) => [r.ref, r.score / maxBm]));\n const fzMap = new Map(fz.map((r) => [r.ref, r.score / maxFz]));\n return docs.map((d) => ({\n ref: d.ref,\n score: W_BM25 * (bmMap.get(d.ref) ?? 0) + W_FUZZY * (fzMap.get(d.ref) ?? 0),\n }));\n },\n};\n","/**\n * Algorithm registry. Builtins are pre-registered; hosts may register\n * additional algorithms (e.g. an embedding-based semantic provider) via\n * registerSearchAlgorithm and reference them by name in SearchOptions.\n */\nimport type { AnySearchAlgorithm } from \"./types.js\";\nimport { substringAlgorithm } from \"./algorithms/substring.js\";\nimport { bm25Algorithm } from \"./algorithms/bm25.js\";\nimport { fuzzyAlgorithm } from \"./algorithms/fuzzy.js\";\nimport { hybridAlgorithm } from \"./algorithms/hybrid.js\";\n\nconst registry = new Map<string, AnySearchAlgorithm>();\n\nexport function registerSearchAlgorithm(algo: AnySearchAlgorithm): void {\n registry.set(algo.name, algo);\n}\n\nexport function getSearchAlgorithm(name: string): AnySearchAlgorithm | undefined {\n return registry.get(name);\n}\n\nexport function listSearchAlgorithms(): AnySearchAlgorithm[] {\n return [...registry.values()];\n}\n\n// Pre-register builtins. Hybrid is the default (see types.ts DEFAULT_ALGORITHM).\nregisterSearchAlgorithm(substringAlgorithm);\nregisterSearchAlgorithm(bm25Algorithm);\nregisterSearchAlgorithm(fuzzyAlgorithm);\nregisterSearchAlgorithm(hybridAlgorithm);\n","/**\n * Search type definitions.\n *\n * Two data sources are searchable:\n * - Compressed blocks (summary text; ref = \"b{id}\")\n * - Historical messages (original text from the append-only session log;\n * ref = \"m{NNNNN}\"). These let the model locate detail that compression\n * turned into a short summary — search to pinpoint, then decompress the\n * owning block for the full content.\n *\n * A SearchAlgorithm is a stateless scorer over a unified SearchDoc[]. Roles\n * carry a configurable weight (user intent > assistant reasoning > tool noise).\n */\n\n/** Where a searchable document came from. */\nexport type SearchDocKind = \"block\" | \"message\";\n\nexport type MessageRole = \"user\" | \"assistant\" | \"tool\";\n\n/** A unified searchable document — either a block summary or a message. */\nexport interface SearchDoc {\n kind: SearchDocKind;\n /** Stable ref for decompress: \"b3\" for a block, \"m00350\" for a message. */\n ref: string;\n /** Text this doc is scored against (topic+summary for blocks; content for messages). */\n text: string;\n /** For preview/title display. */\n title: string;\n /** Message role (messages only); undefined for blocks. Drives role weighting. */\n role?: MessageRole;\n /** Block owning this doc. For blocks: the block itself. For messages: the block\n * that compressed it (so the model knows which block to decompress for detail). */\n blockId?: string;\n /** Tier of the owning block (display + grouping). */\n tier?: number;\n /** Approx token size (for \"how big is this\" display). */\n tokens?: number;\n}\n\n/** Per-role score multipliers. Defaults favor user intent over tool noise. */\nexport interface RoleWeights {\n user?: number;\n assistant?: number;\n tool?: number;\n block?: number;\n}\n\nexport const DEFAULT_ROLE_WEIGHTS: Required<RoleWeights> = {\n user: 1.5,\n assistant: 1.0,\n tool: 0.6,\n block: 1.0,\n};\n\nexport interface ScoredBlock {\n ref: string;\n score: number;\n}\n\nexport interface SearchAlgorithm {\n name: string;\n description: string;\n score(docs: SearchDoc[], query: string): ScoredBlock[];\n}\n\nexport interface AsyncSearchAlgorithm {\n name: string;\n description: string;\n score(docs: SearchDoc[], query: string): Promise<ScoredBlock[]>;\n}\n\nexport type AnySearchAlgorithm = SearchAlgorithm | AsyncSearchAlgorithm;\n\nexport interface SearchResult {\n /** \"block\" or \"message\". */\n kind: SearchDocKind;\n /** Ref to pass to decompress: \"b3\" or \"m00350\". */\n ref: string;\n /** Owning block id (for messages: the block that compressed it). */\n blockId?: string;\n tier: number;\n score: number;\n title: string;\n preview: string;\n role?: MessageRole;\n tokens?: number;\n}\n\nexport interface SearchOptions {\n algorithm?: string;\n limit?: number;\n previewLength?: number;\n minScore?: number;\n /** Per-role weights (default DEFAULT_ROLE_WEIGHTS). */\n roleWeights?: RoleWeights;\n}\n\n/** Host-supplied historical message, turned into a message SearchDoc. */\nexport interface MessageInput {\n ref: string;\n role: MessageRole;\n text: string;\n tokens?: number;\n /** Block id that compressed this message (undefined if still visible). */\n blockId?: string;\n tier?: number;\n}\n\nexport const DEFAULT_ALGORITHM = \"hybrid\";\n","/**\n * searchBlocks — public search entry point.\n *\n * Scores a unified document set (block summaries + historical messages)\n * and returns ranked results. The model uses search to cheaply locate\n * detail that compression folded into summaries, then decompresses the\n * owning block for the full content.\n *\n * Two entry points:\n * - searchBlocks() — sync. Works for all lexical algorithms.\n * - searchBlocksAsync() — async. Also supports embedding-based semantic\n * algorithms whose score() returns a Promise.\n */\n\nimport type { CompressionState, CompressionBlock } from \"../types.js\";\nimport { getSearchAlgorithm } from \"./registry.js\";\nimport type { SearchDoc, ScoredBlock, MessageInput } from \"./types.js\";\nimport type { SearchResult, SearchOptions, RoleWeights } from \"./types.js\";\nimport { DEFAULT_ALGORITHM, DEFAULT_ROLE_WEIGHTS } from \"./types.js\";\n\n/** Build SearchDoc[] from all blocks (active AND inactive) of the state. */\nexport function blockDocs(state: CompressionState): SearchDoc[] {\n return state.blocks.map((b: CompressionBlock): SearchDoc => ({\n kind: \"block\",\n ref: b.blockId,\n text: `${b.topic ?? \"\"} ${b.summary ?? \"\"}`,\n title: b.topic ?? b.blockId,\n blockId: b.blockId,\n tier: b.tier ?? 1,\n tokens: b.compressedTokens,\n }));\n}\n\n/**\n * Build SearchDoc[] from historical messages supplied by the host. The host\n * (pai-acp) reads these from the append-only session log — they include the\n * original text of messages that compression later folded into block summaries.\n *\n * `ownerOf(ref)` maps a message ref to the block id that compressed it, so a\n * message hit tells the model exactly which block to decompress for detail.\n */\nexport function messageDocs(msgs: MessageInput[]): SearchDoc[] {\n return msgs.map((m): SearchDoc => ({\n kind: \"message\",\n ref: m.ref,\n text: m.text,\n title: `${m.role}: ${m.text.slice(0, 60)}`,\n role: m.role,\n blockId: m.blockId,\n tier: m.tier,\n tokens: m.tokens,\n }));\n}\n\nfunction applyRoleWeight(scored: ScoredBlock[], docs: SearchDoc[], rw: Required<RoleWeights>): ScoredBlock[] {\n if (docs.length === 0) return scored;\n const docByRef = new Map(docs.map((d) => [d.ref, d]));\n return scored.map((s) => {\n const doc = docByRef.get(s.ref);\n if (!doc) return s;\n const w =\n doc.kind === \"message\"\n ? doc.role === \"user\"\n ? rw.user\n : doc.role === \"assistant\"\n ? rw.assistant\n : rw.tool\n : rw.block;\n return { ref: s.ref, score: s.score * w };\n });\n}\n\nfunction runSearch(\n docs: SearchDoc[],\n query: string,\n options: SearchOptions,\n): SearchResult[] | Promise<SearchResult[]> {\n const limit = options.limit ?? 10;\n const previewLength = options.previewLength ?? 200;\n const minScore = options.minScore ?? 0.01;\n const algoName = options.algorithm ?? DEFAULT_ALGORITHM;\n const rw = { ...DEFAULT_ROLE_WEIGHTS, ...options.roleWeights };\n\n const algo = getSearchAlgorithm(algoName);\n if (!algo) return [];\n if (docs.length === 0) return [];\n\n const scoredOrPromise = algo.score(docs, query);\n\n const buildResults = (weighted: ScoredBlock[]): SearchResult[] => {\n const byRef = new Map(docs.map((d) => [d.ref, d]));\n return weighted\n .map((s): SearchResult | null => {\n const doc = byRef.get(s.ref);\n if (!doc) return null;\n return {\n kind: doc.kind,\n ref: doc.ref,\n blockId: doc.blockId,\n tier: doc.tier ?? 1,\n score: s.score,\n title: doc.title,\n preview: makePreview(doc.text, query, previewLength),\n role: doc.role,\n tokens: doc.tokens,\n };\n })\n .filter((r): r is SearchResult => r !== null && r.score >= minScore)\n .sort((a, b) => b.score - a.score)\n .slice(0, limit);\n };\n\n if (scoredOrPromise instanceof Promise) {\n return scoredOrPromise.then((raw) => buildResults(applyRoleWeight(raw, docs, rw)));\n }\n return buildResults(applyRoleWeight(scoredOrPromise, docs, rw));\n}\n\n/** Sync entry — throws for async algorithms. Pass docs from blockDocs() + messageDocs(). */\nexport function searchBlocks(docs: SearchDoc[], query: string, options: SearchOptions = {}): SearchResult[] {\n const result = runSearch(docs, query, options);\n if (result instanceof Promise) {\n throw new Error(\n `searchBlocks: algorithm \"${options.algorithm ?? DEFAULT_ALGORITHM}\" is async (e.g. semantic). Use searchBlocksAsync() instead.`,\n );\n }\n return result;\n}\n\nexport async function searchBlocksAsync(docs: SearchDoc[], query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n return await runSearch(docs, query, options);\n}\n\n/**\n * Preview centered on the first query-term hit (case-insensitive).\n * Falls back to the head when no term hits.\n */\nfunction makePreview(text: string, query: string, len: number): string {\n if (!text) return \"\";\n const terms = query.toLowerCase().trim().split(/\\s+/).filter((t) => t.length > 1);\n if (terms.length === 0) return text.slice(0, len);\n\n const lower = text.toLowerCase();\n let hitIdx = -1;\n for (const term of terms) {\n const idx = lower.indexOf(term);\n if (idx >= 0) {\n hitIdx = idx;\n break;\n }\n }\n\n if (hitIdx < 0) return text.slice(0, len);\n\n const half = Math.max(0, Math.floor(len / 2) - 10);\n const start = Math.max(0, hitIdx - half);\n const end = Math.min(text.length, start + len);\n const prefix = start > 0 ? \"…\" : \"\";\n const suffix = end < text.length ? \"…\" : \"\";\n return prefix + text.slice(start, end).trim() + suffix;\n}\n"],"mappings":"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","names":["require","require","block","refNum","formatTokens","numericPart","activeBlocks","refNum","countOccurrences","stem","registry"]}
1
+ {"version":3,"sources":["../src/refs.ts","../src/state.ts","../src/prune.ts","../src/sync.ts","../src/tokenize.ts","../src/config.ts","../src/boundaries.ts","../src/truncate-tools.ts","../src/hide-consumed.ts","../src/filter/registry.ts","../src/filter/apply.ts","../src/render-refs.ts","../src/protected.ts","../src/tool-pairs.ts","../src/recommend.ts","../src/pipeline.ts","../src/compress.ts","../src/compression-rules.ts","../src/nudge-text.ts","../src/decompress.ts","../src/report.ts","../src/rebuild.ts","../src/search/algorithms/substring.ts","../src/search/stemmer.ts","../src/search/tokenizer.ts","../src/search/algorithms/bm25.ts","../src/search/algorithms/fuzzy.ts","../src/search/algorithms/hybrid.ts","../src/search/registry.ts","../src/search/types.ts","../src/search/index.ts"],"sourcesContent":["import type { CoreMessage, MessageRefMap } from \"./types.js\";\n\nconst REF_WIDTH = 5;\nconst MIN_INDEX = 1;\nconst MAX_INDEX = 99999;\nconst REF_PATTERN = /^m0*(\\d{1,5})$/;\n\nexport const BLOCKED_REF = \"BLOCKED\";\n\nexport function emptyRefMap(): MessageRefMap {\n return { byRaw: {}, byRef: {} };\n}\n\nexport function indexToRef(index: number): string {\n if (!Number.isInteger(index) || index < MIN_INDEX || index > MAX_INDEX) {\n throw new RangeError(\n `ref index out of bounds: ${index} (allowed ${MIN_INDEX}-${MAX_INDEX})`,\n );\n }\n return `m${String(index).padStart(REF_WIDTH, \"0\")}`;\n}\n\nexport function refToIndex(ref: string): number | null {\n const match = REF_PATTERN.exec(ref.trim().toLowerCase());\n if (!match) return null;\n const index = Number(match[1]);\n if (index < MIN_INDEX || index > MAX_INDEX) return null;\n return index;\n}\n\nexport function refForRaw(map: MessageRefMap, rawId: string): string | null {\n return map.byRaw[rawId] ?? null;\n}\n\nexport function rawForRef(map: MessageRefMap, ref: string): string | null {\n return map.byRef[ref] ?? null;\n}\n\nexport interface AssignRefsResult {\n map: MessageRefMap;\n nextIndex: number;\n newlyAssigned: number;\n}\n\nexport interface AssignRefsOptions {\n existing: MessageRefMap;\n nextIndex: number;\n isProtected?: (message: CoreMessage) => boolean;\n shouldSkip?: (message: CoreMessage) => boolean;\n}\n\nexport function assignRefs(\n messages: CoreMessage[],\n options: AssignRefsOptions,\n): AssignRefsResult {\n const map: MessageRefMap = {\n byRaw: { ...options.existing.byRaw },\n byRef: { ...options.existing.byRef },\n };\n let cursor =\n Number.isInteger(options.nextIndex) && options.nextIndex >= MIN_INDEX\n ? options.nextIndex\n : MIN_INDEX;\n let newlyAssigned = 0;\n\n for (const message of messages) {\n if (!message.id || options.shouldSkip?.(message)) continue;\n\n if (map.byRaw[message.id]) continue;\n\n if (options.isProtected?.(message)) {\n map.byRaw[message.id] = BLOCKED_REF;\n continue;\n }\n\n const ref = allocateFreeRef(map, cursor);\n cursor = ref.index + 1;\n map.byRaw[message.id] = ref.text;\n map.byRef[ref.text] = message.id;\n newlyAssigned++;\n }\n\n return { map, nextIndex: cursor, newlyAssigned };\n}\n\nfunction allocateFreeRef(\n map: MessageRefMap,\n start: number,\n): { text: string; index: number } {\n let candidate = Math.max(start, MIN_INDEX);\n while (candidate <= MAX_INDEX) {\n const text = indexToRef(candidate);\n if (!map.byRef[text]) {\n return { text, index: candidate };\n }\n candidate++;\n }\n throw new Error(\n `ref capacity exhausted: cannot allocate beyond ${indexToRef(MAX_INDEX)}`,\n );\n}\n\nexport function rebuildRefIndex(map: MessageRefMap): MessageRefMap {\n const byRef: Record<string, string> = {};\n for (const [rawId, ref] of Object.entries(map.byRaw)) {\n if (ref !== BLOCKED_REF) byRef[ref] = rawId;\n }\n return { byRaw: { ...map.byRaw }, byRef };\n}\n\nexport function highestUsedIndex(map: MessageRefMap): number {\n let highest = 0;\n for (const ref of Object.values(map.byRaw)) {\n const index = ref === BLOCKED_REF ? null : refToIndex(ref);\n if (index !== null && index > highest) highest = index;\n }\n return highest;\n}\n","import type { CompressionBlock, CompressionState } from \"./types.js\";\n\nexport function createInitialState(): CompressionState {\n return {\n blocks: [],\n messageRefs: { byRaw: {}, byRef: {} },\n nudge: {\n lastPerMessageNudgeTokens: 0,\n lastNudgeShownTokens: 0,\n baselineTokens: 0,\n anchors: {},\n lastShownByTier: {},\n },\n stats: { tokensCompressed: 0, compressionCount: 0 },\n nextBlockId: 1,\n nextRunId: 1,\n };\n}\n\nexport function allocateBlockId(state: CompressionState): string {\n const id = state.nextBlockId;\n state.nextBlockId = Math.max(1, id) + 1;\n return `b${id}`;\n}\n\nexport function allocateRunId(state: CompressionState): string {\n const id = state.nextRunId;\n state.nextRunId = Math.max(1, id) + 1;\n return `r${id}`;\n}\n\nexport function blockById(\n state: CompressionState,\n blockId: string,\n): CompressionBlock | undefined {\n return state.blocks.find((block) => block.blockId === blockId);\n}\n\nexport function activeBlocks(state: CompressionState): CompressionBlock[] {\n return state.blocks.filter((block) => block.active);\n}\n\nexport function coveredMessageIds(state: CompressionState): Set<string> {\n const covered = new Set<string>();\n for (const block of state.blocks) {\n if (!block.active) continue;\n for (const id of block.effectiveMessageIds) covered.add(id);\n }\n return covered;\n}\n\nexport function highestActiveTier(state: CompressionState): 0 | 1 | 2 | 3 {\n let highest: 0 | 1 | 2 | 3 = 0;\n for (const block of state.blocks) {\n if (block.active && block.tier > highest) highest = block.tier;\n }\n return highest;\n}\n\nexport function advanceSurvival(\n state: CompressionState,\n promotionThreshold: number,\n): void {\n for (const block of state.blocks) {\n if (!block.active) continue;\n block.survivedCount += 1;\n if (block.survivedCount >= promotionThreshold) {\n block.generation = \"old\";\n }\n }\n}\n","import { activeBlocks, coveredMessageIds } from \"./state.js\";\nimport type { CompressionState, CoreMessage } from \"./types.js\";\n\nexport const SUMMARY_HEADER = \"[Compressed conversation section]\";\n\nexport interface PruneOptions {\n injectSummaries?: boolean;\n}\n\nexport function prune(\n messages: CoreMessage[],\n state: CompressionState,\n options: PruneOptions = {},\n): CoreMessage[] {\n const covered = coveredMessageIds(state);\n if (covered.size === 0) return [...messages];\n\n const inject = options.injectSummaries ?? true;\n const firstUserIndex = messages.findIndex(\n (message) => message.role === \"user\",\n );\n\n const indexById = new Map<string, number>();\n messages.forEach((message, index) => indexById.set(message.id, index));\n\n const anchors = inject ? collectSummaryAnchors(state, indexById) : [];\n\n return stripOrphanedToolResults(\n stripOrphanedToolCalls(\n rebuildMessages(messages, covered, firstUserIndex, anchors),\n ),\n );\n}\n\ninterface SummaryAnchor {\n blockId: string;\n summary: string;\n topic?: string;\n insertAt: number;\n}\n\nfunction collectSummaryAnchors(\n state: CompressionState,\n indexById: Map<string, number>,\n): SummaryAnchor[] {\n const anchors: SummaryAnchor[] = [];\n for (const block of activeBlocks(state)) {\n let earliest: number | null = null;\n for (const id of block.effectiveMessageIds) {\n const index = indexById.get(id);\n if (index !== undefined && (earliest === null || index < earliest)) {\n earliest = index;\n }\n }\n anchors.push({\n blockId: block.blockId,\n summary: block.summary,\n topic: block.topic,\n insertAt: earliest ?? 0,\n });\n }\n anchors.sort((left, right) => left.insertAt - right.insertAt);\n return anchors;\n}\n\nfunction rebuildMessages(\n messages: CoreMessage[],\n covered: Set<string>,\n firstUserIndex: number,\n anchors: SummaryAnchor[],\n): CoreMessage[] {\n const result: CoreMessage[] = [];\n const pending = [...anchors];\n\n for (let index = 0; index < messages.length; index++) {\n while (pending.length > 0 && pending[0]!.insertAt === index) {\n result.push(renderSummary(pending.shift()!));\n }\n if (index === firstUserIndex && firstUserIndex >= 0) {\n result.push(messages[index]!);\n continue;\n }\n if (covered.has(messages[index]!.id)) continue;\n result.push(messages[index]!);\n }\n\n while (pending.length > 0) {\n result.push(renderSummary(pending.shift()!));\n }\n\n return result;\n}\n\nfunction renderSummary(anchor: SummaryAnchor): CoreMessage {\n const body = anchor.summary.trim();\n const topicLine = anchor.topic\n ? `${SUMMARY_HEADER} — ${anchor.topic}`\n : SUMMARY_HEADER;\n const text = body.length === 0 ? topicLine : `${topicLine}\\n${body}`;\n return {\n id: `acp_summary_${anchor.blockId}`,\n role: \"system\",\n contentType: \"text\",\n text,\n };\n}\n\nfunction stripOrphanedToolResults(messages: CoreMessage[]): CoreMessage[] {\n const knownCallIds = new Set<string>();\n for (const m of messages) {\n if (m.contentType === \"tool-call\" && m.toolCallId) {\n knownCallIds.add(m.toolCallId);\n }\n }\n return messages.filter(\n (m) =>\n m.contentType !== \"tool-result\" ||\n !m.toolCallId ||\n knownCallIds.has(m.toolCallId),\n );\n}\n\nfunction stripOrphanedToolCalls(messages: CoreMessage[]): CoreMessage[] {\n const knownResultIds = new Set<string>();\n for (const m of messages) {\n if (m.contentType === \"tool-result\" && m.toolCallId) {\n knownResultIds.add(m.toolCallId);\n }\n }\n return messages.filter(\n (m) =>\n m.contentType !== \"tool-call\" ||\n !m.toolCallId ||\n m.toolName === \"compress\" ||\n knownResultIds.has(m.toolCallId),\n );\n}\n","import type { CompressionState, CoreMessage } from \"./types.js\";\n\nexport interface SyncResult {\n state: CompressionState;\n deactivated: string[];\n}\n\nexport function syncBlocks(\n messages: CoreMessage[],\n state: CompressionState,\n): SyncResult {\n const presentIds = new Set(messages.map((message) => message.id));\n const deactivated: string[] = [];\n // Deep-clone (not just `{...state}`) so the caller's input state is never\n // mutated: processTurn stamps `state.nudge.*` and reassigns `messageRefs`,\n // and block sub-arrays must not alias the input. Previously nudge/stats/\n // messageRefs were shared references → input-state mutation leak.\n const result: CompressionState = {\n blocks: state.blocks.map((block) => ({\n ...block,\n directMessageIds: [...block.directMessageIds],\n effectiveMessageIds: [...block.effectiveMessageIds],\n directBlockIds: [...block.directBlockIds],\n })),\n messageRefs: {\n byRaw: { ...state.messageRefs.byRaw },\n byRef: { ...state.messageRefs.byRef },\n },\n nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },\n stats: { ...state.stats },\n nextBlockId: state.nextBlockId,\n nextRunId: state.nextRunId,\n };\n\n const consumedBlockIds = new Set<string>();\n for (const block of result.blocks) {\n for (const consumedId of block.directBlockIds) {\n consumedBlockIds.add(consumedId);\n }\n }\n\n for (const block of result.blocks) {\n if (consumedBlockIds.has(block.blockId)) {\n block.active = false;\n continue;\n }\n block.active = true;\n const stillPresent = block.effectiveMessageIds.some((id) =>\n presentIds.has(id),\n );\n if (!stillPresent) {\n block.active = false;\n deactivated.push(block.blockId);\n }\n }\n\n return { state: result, deactivated };\n}\n","import { createRequire } from \"node:module\";\n\nconst require = createRequire(import.meta.url);\n\nexport function defaultCountTokens(text: string): number {\n if (!text) return 0;\n // CJK chars tokenize ~1:1 (chars/4 badly underestimates them). Count them\n // directly, then estimate the non-CJK remainder with chars/4 so digits,\n // punctuation, and symbols in code/JSON are not dropped to zero.\n const cjk = text.match(/[\\u4e00-\\u9fff\\u3040-\\u30ff\\uac00-\\ud7af]/g);\n const cjkCount = cjk?.length ?? 0;\n return cjkCount + Math.ceil((text.length - cjkCount) / 4);\n}\n\nexport function estimateMessageTokens(text: string | undefined): number {\n return defaultCountTokens(text ?? \"\");\n}\n\nexport function estimateTokensFast(text: string): number {\n if (!text) return 0;\n return Math.ceil(text.length / 4);\n}\n\nexport type TokenCountFn = (text: string) => number;\n\nexport function createBpeTokenizer(): TokenCountFn {\n try {\n const mod = require(\"@anthropic-ai/tokenizer\");\n const bpeCount = mod.countTokens ?? mod.default?.countTokens;\n if (typeof bpeCount !== \"function\") return defaultCountTokens;\n return (text: string) => {\n try {\n return bpeCount(text);\n } catch {\n return defaultCountTokens(text);\n }\n };\n } catch {\n return defaultCountTokens;\n }\n}\n","import type { Config } from \"./types.js\";\n\nexport function defaultConfig(\n modelContextLimit: number,\n overrides: Partial<Config> = {},\n): Config {\n const base: Config = {\n tiers: { enabled: true, tier2Trigger: 5, tier3Trigger: 10 },\n nudge: {\n maxContextLimitPct: 0.55,\n minContextLimitPct: 0.45,\n frequency: 5,\n iterationThreshold: 15,\n force: \"soft\",\n growthRatio: 0.05,\n growthFloor: 50000,\n growthCap: 50000,\n minGrowthFloor: 20000,\n minGrowthRatio: 0.45,\n emergencyThresholdPct: 0.80,\n },\n promotionThreshold: 5,\n truncate: { threshold: 1 },\n compress: {\n minCompressRange: 5000,\n maxSummaryLength: 20000,\n minSummaryLength: 50,\n },\n protectedTools: [],\n preserveRecentMessages: 5,\n preserveRecentTokens: 5000,\n modelContextLimit,\n };\n return {\n ...base,\n ...overrides,\n tiers: { ...base.tiers, ...overrides.tiers },\n nudge: { ...base.nudge, ...overrides.nudge },\n truncate: { ...base.truncate, ...overrides.truncate },\n compress: { ...base.compress, ...overrides.compress },\n };\n}\n\nexport function validateConfig(config: Config): string[] {\n const errors: string[] = [];\n if (\n !Number.isFinite(config.modelContextLimit) ||\n config.modelContextLimit <= 0\n ) {\n errors.push(\"modelContextLimit must be a positive number\");\n }\n if (config.nudge.minContextLimitPct > config.nudge.maxContextLimitPct) {\n errors.push(\n \"nudge.minContextLimitPct must not exceed nudge.maxContextLimitPct\",\n );\n }\n if (config.promotionThreshold < 1) {\n errors.push(\"promotionThreshold must be >= 1\");\n }\n if (config.truncate.threshold <= 0 || config.truncate.threshold > 1) {\n errors.push(\"truncate.threshold must be in (0, 1]\");\n }\n for (const tier of [config.tiers.tier2Trigger, config.tiers.tier3Trigger]) {\n if (tier < 1) errors.push(\"tier triggers must be >= 1\");\n }\n if (config.tiers.tier3Trigger <= config.tiers.tier2Trigger) {\n errors.push(\"tiers.tier3Trigger must be greater than tiers.tier2Trigger\");\n }\n return errors;\n}\n","import { activeBlocks, blockById } from \"./state.js\";\nimport type {\n CompressionState,\n CoreMessage,\n ResolvedBoundary,\n} from \"./types.js\";\n\nexport type BoundaryKind = \"message\" | \"block\";\n\nexport interface ParsedBoundary {\n kind: BoundaryKind;\n numericId: number;\n raw: string;\n}\n\nconst MESSAGE_REF_PATTERN = /^m0*(\\d{1,5})$/;\nconst BLOCK_REF_PATTERN = /^b(\\d{1,9})$/;\n\nexport function parseBoundary(ref: string): ParsedBoundary | null {\n const normalized = ref.trim().toLowerCase();\n const messageMatch = MESSAGE_REF_PATTERN.exec(normalized);\n if (messageMatch) {\n const numericId = Number(messageMatch[1]);\n if (numericId >= 1 && numericId <= 99999) {\n return { kind: \"message\", numericId, raw: normalized };\n }\n }\n const blockMatch = BLOCK_REF_PATTERN.exec(normalized);\n if (blockMatch) {\n const numericId = Number(blockMatch[1]);\n if (numericId >= 1) return { kind: \"block\", numericId, raw: normalized };\n }\n return null;\n}\n\nexport interface ResolveBoundariesInput {\n startRef: string;\n endRef: string;\n messages: CoreMessage[];\n state: CompressionState;\n}\n\nexport interface ResolvedRange {\n startIndex: number;\n endIndex: number;\n messageIds: string[];\n nestedBlockIds: string[];\n boundaryKind: BoundaryKind;\n protectedGaps: number[];\n}\n\nexport function resolveBoundaries(\n input: ResolveBoundariesInput,\n): ResolvedRange {\n const start = parseBoundary(input.startRef);\n const end = parseBoundary(input.endRef);\n if (!start || !end) {\n throw new Error(\n `Invalid boundary ref(s): startId=\"${input.startRef}\", endId=\"${input.endRef}\". Use mNNNNN or bN.`,\n );\n }\n\n const indexByRawId = new Map<string, number>();\n input.messages.forEach((message, index) =>\n indexByRawId.set(message.id, index),\n );\n\n let startIndex = resolveAnchorIndex(start, input.state, indexByRawId);\n let endIndex = resolveAnchorIndex(end, input.state, indexByRawId);\n\n if (startIndex === null || endIndex === null) {\n throw new Error(\n `Boundary not found in visible context (likely consumed by an existing block). ` +\n `startId=\"${input.startRef}\", endId=\"${input.endRef}\".`,\n );\n }\n\n if (startIndex > endIndex) {\n [startIndex, endIndex] = [endIndex, startIndex];\n }\n\n const messageIds: string[] = [];\n for (let index = startIndex; index <= endIndex; index++) {\n const message = input.messages[index];\n if (message) messageIds.push(message.id);\n }\n\n const boundaryKind: BoundaryKind =\n start.kind === \"block\" || end.kind === \"block\" ? \"block\" : \"message\";\n\n const nestedBlockIds: string[] = [];\n const nestedSeen = new Set<string>();\n for (const block of activeBlocks(input.state)) {\n const anchor = earliestIndexOfIds(block.effectiveMessageIds, indexByRawId);\n if (anchor !== null && anchor >= startIndex && anchor <= endIndex) {\n if (!nestedSeen.has(block.blockId)) {\n nestedSeen.add(block.blockId);\n nestedBlockIds.push(block.blockId);\n }\n }\n }\n\n const protectedGaps: number[] = [];\n\n return {\n startIndex,\n endIndex,\n messageIds,\n nestedBlockIds,\n boundaryKind,\n protectedGaps,\n };\n}\n\nfunction resolveAnchorIndex(\n boundary: ParsedBoundary,\n state: CompressionState,\n indexByRawId: Map<string, number>,\n): number | null {\n if (boundary.kind === \"message\") {\n const rawId =\n state.messageRefs.byRef[boundary.raw] ??\n state.messageRefs.byRef[formatPaddedRef(boundary.numericId)];\n if (!rawId) return null;\n const index = indexByRawId.get(rawId);\n return index === undefined ? null : index;\n }\n\n const block = blockById(state, `b${boundary.numericId}`);\n if (!block || !block.active) return null;\n return earliestIndexOfIds(block.effectiveMessageIds, indexByRawId);\n}\n\nfunction formatPaddedRef(index: number): string {\n return `m${String(index).padStart(5, \"0\")}`;\n}\n\nexport function earliestIndexOfIds(\n ids: string[],\n indexByRawId: Map<string, number>,\n): number | null {\n let earliest: number | null = null;\n for (const id of ids) {\n const index = indexByRawId.get(id);\n if (index !== undefined && (earliest === null || index < earliest)) {\n earliest = index;\n }\n }\n return earliest;\n}\n\nexport function toResolvedBoundary(range: ResolvedRange): ResolvedBoundary {\n return {\n startIndex: range.startIndex,\n endIndex: range.endIndex,\n protectedGaps: range.protectedGaps,\n };\n}\n","import type { Config, CoreMessage } from \"./types.js\";\n\nexport interface TruncateOptions {\n minOutputTokens?: number;\n keepPrefixChars?: number;\n keepSuffixChars?: number;\n protectRecentMessages?: number;\n}\n\nexport interface TruncateResult {\n messages: CoreMessage[];\n truncatedCount: number;\n savedTokens: number;\n}\n\nconst TRUNCATION_MARKER = \"[truncated for context space]\";\nconst DEFAULTS = {\n minOutputTokens: 1000,\n keepPrefixChars: 2000,\n keepSuffixChars: 2000,\n protectRecentMessages: 3,\n} as const;\n\nexport function truncateLargeToolOutputs(\n messages: CoreMessage[],\n tokenCount: number,\n config: Config,\n countTokens: (text: string) => number,\n options: TruncateOptions = {},\n): TruncateResult {\n const opts = { ...DEFAULTS, ...options };\n if (config.modelContextLimit <= 0) return { messages, truncatedCount: 0, savedTokens: 0 };\n\n const threshold = config.truncate.threshold * config.modelContextLimit;\n if (tokenCount < threshold) return { messages, truncatedCount: 0, savedTokens: 0 };\n\n const protectedIndex = messages.length - opts.protectRecentMessages;\n const candidates: Array<{ index: number; tokens: number }> = [];\n\n for (let index = 0; index < messages.length; index++) {\n if (index >= protectedIndex) break;\n const message = messages[index]!;\n if (message.contentType !== \"tool-result\") continue;\n const text = message.text ?? \"\";\n if (text.length === 0 || text.includes(TRUNCATION_MARKER)) continue;\n const tokens = countTokens(text);\n if (tokens < opts.minOutputTokens) continue;\n candidates.push({ index, tokens });\n }\n\n if (candidates.length === 0) return { messages, truncatedCount: 0, savedTokens: 0 };\n candidates.sort((left, right) => right.tokens - left.tokens);\n\n const targetTokens = threshold * 0.9;\n let savedTokens = 0;\n const edits = new Map<number, string>();\n let truncatedCount = 0;\n\n for (const candidate of candidates) {\n if (tokenCount - savedTokens <= targetTokens) break;\n const original = messages[candidate.index]!.text ?? \"\";\n if (original.length <= opts.keepPrefixChars + opts.keepSuffixChars) continue;\n\n const prefix = original.slice(0, opts.keepPrefixChars);\n const suffix = original.slice(-opts.keepSuffixChars);\n const replacement =\n prefix +\n `\\n\\n...${TRUNCATION_MARKER} — original ~${candidate.tokens} tokens]...\\n\\n` +\n suffix;\n edits.set(candidate.index, replacement);\n savedTokens += candidate.tokens - countTokens(replacement);\n truncatedCount++;\n }\n\n if (truncatedCount === 0) return { messages, truncatedCount: 0, savedTokens: 0 };\n\n const updated = messages.map((message, index) =>\n edits.has(index) ? { ...message, text: edits.get(index)! } : message,\n );\n return { messages: updated, truncatedCount, savedTokens };\n}\n","import type { CompressionState, CoreMessage } from \"./types.js\";\n\nconst KEEP_LAST_ORPHANED = 0;\n\nexport interface HideConsumedResult {\n messages: CoreMessage[];\n hidden: number;\n}\n\nfunction rangeKey(startRef: string, endRef: string): string {\n return `${startRef}::${endRef}`;\n}\n\nfunction rewriteCompressText(text: string | undefined, liveKeys: Set<string>): string | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text ?? \"\");\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== \"object\") return null;\n const obj = parsed as { content?: unknown };\n const content = obj.content;\n if (!Array.isArray(content) || content.length === 0) return null;\n\n const kept = content.filter((entry): entry is Record<string, unknown> => {\n if (!entry || typeof entry !== \"object\") return false;\n const s = typeof entry.startId === \"string\" ? entry.startId : typeof entry.messageId === \"string\" ? entry.messageId : \"\";\n const e = typeof entry.endId === \"string\" ? entry.endId : typeof entry.messageId === \"string\" ? entry.messageId : \"\";\n return liveKeys.has(rangeKey(s, e));\n });\n\n if (kept.length === content.length || kept.length === 0) return null;\n\n return JSON.stringify({ ...obj, content: kept });\n}\n\nexport function hideConsumedCompressCalls(\n state: CompressionState,\n messages: CoreMessage[],\n): HideConsumedResult {\n const allBlockCallIds = new Set<string>();\n const activeCallIds = new Set<string>();\n const liveRangeKeysByCallId = new Map<string, Set<string>>();\n const legacyLiveByCallId = new Set<string>();\n for (const block of state.blocks) {\n if (!block.compressCallId) continue;\n allBlockCallIds.add(block.compressCallId);\n if (!block.active) continue;\n activeCallIds.add(block.compressCallId);\n if (block.startRef === undefined || block.endRef === undefined) {\n legacyLiveByCallId.add(block.compressCallId);\n continue;\n }\n let keys = liveRangeKeysByCallId.get(block.compressCallId);\n if (!keys) {\n keys = new Set<string>();\n liveRangeKeysByCallId.set(block.compressCallId, keys);\n }\n keys.add(rangeKey(block.startRef, block.endRef));\n }\n\n const lastOrphanedCallIds: string[] = [];\n for (let i = messages.length - 1; i >= 0 && lastOrphanedCallIds.length < KEEP_LAST_ORPHANED; i--) {\n const message = messages[i]!;\n if (message.toolName !== \"compress\" || message.contentType !== \"tool-call\") continue;\n const callId = message.toolCallId;\n if (callId && !allBlockCallIds.has(callId)) {\n lastOrphanedCallIds.push(callId);\n }\n }\n\n const keepCallIds = new Set([...activeCallIds, ...lastOrphanedCallIds]);\n\n const hiddenCallIds = new Set<string>();\n for (const message of messages) {\n if (\n message.toolName === \"compress\" &&\n message.contentType === \"tool-call\" &&\n (!message.toolCallId || !keepCallIds.has(message.toolCallId))\n ) {\n if (message.toolCallId) hiddenCallIds.add(message.toolCallId);\n }\n }\n\n let hidden = 0;\n const result: CoreMessage[] = [];\n for (const message of messages) {\n if (\n message.toolName === \"compress\" &&\n message.contentType === \"tool-call\" &&\n (!message.toolCallId || !keepCallIds.has(message.toolCallId))\n ) {\n hidden++;\n continue;\n }\n if (\n message.contentType === \"tool-result\" &&\n message.toolCallId &&\n hiddenCallIds.has(message.toolCallId)\n ) {\n hidden++;\n continue;\n }\n if (\n message.toolName === \"compress\" &&\n message.contentType === \"tool-call\" &&\n message.toolCallId &&\n keepCallIds.has(message.toolCallId)\n ) {\n const liveKeys = liveRangeKeysByCallId.get(message.toolCallId);\n if (liveKeys && liveKeys.size > 0 && !legacyLiveByCallId.has(message.toolCallId)) {\n const rewritten = rewriteCompressText(message.text, liveKeys);\n if (rewritten !== null) {\n result.push({ ...message, text: rewritten });\n continue;\n }\n }\n }\n result.push(message);\n }\n\n return { messages: result, hidden };\n}\n","import type { MessageFilter } from \"./types.js\";\n\nconst registry = new Map<string, MessageFilter>();\n\nexport function registerMessageFilter(filter: MessageFilter): void {\n const existing = registry.get(filter.name);\n if (existing && existing.version !== filter.version) {\n throw new Error(\n `Message filter \"${filter.name}\" already registered with version ${existing.version}, cannot register version ${filter.version}.`,\n );\n }\n registry.set(filter.name, filter);\n}\n\nexport function getMessageFilter(name: string): MessageFilter | undefined {\n return registry.get(name);\n}\n\nexport function listMessageFilters(): MessageFilter[] {\n return [...registry.values()];\n}\n\nexport function clearMessageFilters(): void {\n registry.clear();\n}\n","import { listMessageFilters } from \"./registry.js\";\nimport type { CoreMessage } from \"../types.js\";\nimport type { FilterResult, MessageFilterContext, MessageFiltersConfig } from \"./types.js\";\n\nexport interface ApplyResult {\n messages: CoreMessage[];\n partsFiltered: number;\n partsDropped: number;\n partsModified: number;\n}\n\nexport function applyMessageFilters(\n messages: CoreMessage[],\n config: MessageFiltersConfig | undefined,\n): ApplyResult {\n if (!config?.enabled) {\n return { messages, partsFiltered: 0, partsDropped: 0, partsModified: 0 };\n }\n\n const active = listMessageFilters().filter(\n (filter) => config.filters?.[filter.name]?.enabled !== false,\n );\n if (active.length === 0) {\n return { messages, partsFiltered: 0, partsDropped: 0, partsModified: 0 };\n }\n\n let working = messages.map((message) => ({ ...message }));\n const tally = { partsFiltered: 0, partsDropped: 0, partsModified: 0 };\n const total = working.length;\n\n const immediate = active.filter((filter) => !filter.keepLastOnly);\n for (let index = 0; index < working.length; index++) {\n const message = working[index]!;\n const text = message.text ?? \"\";\n if (text.length === 0) continue;\n let current = text;\n const baseCtx: MessageFilterContext = {\n text: current,\n role: message.role,\n messageIndex: index,\n totalMessages: total,\n toolName: message.toolName,\n };\n for (const filter of immediate) {\n let decision: FilterResult;\n try {\n decision = filter.filter(baseCtx);\n } catch {\n continue;\n }\n if (decision.action === \"keep\") continue;\n tally.partsFiltered++;\n if (decision.action === \"drop\") {\n current = \"\";\n tally.partsDropped++;\n } else if (decision.action === \"modify\" && decision.text !== undefined) {\n current = decision.text;\n tally.partsModified++;\n }\n baseCtx.text = current;\n }\n if (current !== text) working[index] = { ...message, text: current };\n }\n\n const keepLast = active.filter((filter) => filter.keepLastOnly);\n for (const filter of keepLast) {\n let foundLast = false;\n for (let index = working.length - 1; index >= 0; index--) {\n const message = working[index]!;\n const text = message.text ?? \"\";\n if (text.length === 0) continue;\n const ctx: MessageFilterContext = {\n text,\n role: message.role,\n messageIndex: index,\n totalMessages: total,\n toolName: message.toolName,\n };\n let decision: FilterResult;\n try {\n decision = filter.filter(ctx);\n } catch {\n continue;\n }\n if (decision.action !== \"drop\" && decision.action !== \"modify\") continue;\n if (foundLast) {\n tally.partsFiltered++;\n tally.partsDropped++;\n working[index] = { ...message, text: \"\" };\n } else {\n foundLast = true;\n if (decision.action === \"modify\" && decision.text !== undefined) {\n tally.partsFiltered++;\n tally.partsModified++;\n working[index] = { ...message, text: decision.text };\n }\n }\n }\n }\n\n return { messages: working, ...tally };\n}\n","import type { CoreMessage, CompressionState, MessageRefMap } from \"./types.js\";\nimport { refForRaw, BLOCKED_REF } from \"./refs.js\";\nimport type { PipelineNode, PipelineContext, NodeIO } from \"./pipeline.js\";\n\n/**\n * Controls which messages get an <acp> ref tag injected into their text.\n * Ref assignment (assignRefsNode) is unconditional — every message always\n * receives a ref in state.messageRefs regardless of this setting. This only\n * governs text rendering:\n * - \"all\": tag every mapped message (in-process hosts like pai-acp)\n * - \"text-only\": tag only user/assistant text; leave tool-call args and\n * tool-result content pristine (proxy hosts — structured content must not\n * be polluted)\n * - \"none\": leave all text untouched (hosts that read the ref map directly)\n */\nexport type RenderStrategy = \"all\" | \"text-only\" | \"none\";\n\n/** Format token count: <1K raw, <10K \"X.YK\", >=10K \"XK\". */\nfunction formatTokens(tokens: number): string {\n if (tokens < 1000) return String(tokens);\n if (tokens < 10000) return (tokens / 1000).toFixed(1) + \"K\";\n return Math.round(tokens / 1000) + \"K\";\n}\n\nfunction classifyType(message: CoreMessage): string {\n if (\n message.contentType === \"tool-call\" ||\n message.contentType === \"tool-result\"\n ) {\n return message.toolName || \"tool\";\n }\n return message.contentType;\n}\n\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nconst LT = \"\\x3c\";\nconst GT = \"\\x3e\";\nconst TAG_OPEN = LT + \"acp \";\nconst TAG_CLOSE = LT + \"/acp\" + GT;\n\nfunction acpTag(ref: string, tokens: number, type: string): string {\n return TAG_OPEN + 'tokens=\"' + formatTokens(tokens) + '\" type=\"' + type + '\"' + GT + ref + TAG_CLOSE;\n}\n\nfunction renderMessage(\n message: CoreMessage,\n map: MessageRefMap,\n countTokens: (text: string) => number,\n strategy: RenderStrategy,\n): CoreMessage {\n const ref = refForRaw(map, message.id);\n if (!ref || ref === BLOCKED_REF) return message;\n\n // \"none\": host reads the ref map directly — never pollute text.\n if (strategy === \"none\") return message;\n\n // text-only: never tag structured tool content. Refs are still assigned.\n if (strategy === \"text-only\" && message.contentType !== \"text\") {\n return message;\n }\n\n // Strip own stale tag BEFORE computing tokens (idempotency).\n // Match the message's own ref only — foreign tags survive (content-corruption fix).\n const ownTagRe = new RegExp(\n \"^\" + escapeRegex(TAG_OPEN) + \"[^>]*\" + GT + escapeRegex(ref) + escapeRegex(TAG_CLOSE) + \"\\\\n?\",\n );\n const cleanText = (message.text || \"\").replace(ownTagRe, \"\");\n\n const tokens = countTokens(cleanText);\n const type = classifyType(message);\n const prefix = acpTag(ref, tokens, type) + \"\\n\";\n\n if (!cleanText) return { ...message, text: prefix };\n return { ...message, text: prefix + cleanText };\n}\n\nexport function renderVisibleRefs(\n messages: CoreMessage[],\n state: CompressionState,\n countTokens: (text: string) => number = (text) =>\n Math.ceil(text.length / 4),\n strategy: RenderStrategy = \"all\",\n): CoreMessage[] {\n const map = state.messageRefs;\n return messages.map((message) =>\n renderMessage(message, map, countTokens, strategy),\n );\n}\n\n/** Factory: build a render-refs node bound to a specific render strategy. */\nexport function createRenderRefsNode(strategy: RenderStrategy): PipelineNode {\n return {\n name: \"render-refs\",\n run(io: NodeIO, ctx: PipelineContext): NodeIO {\n return {\n ...io,\n messages: renderVisibleRefs(io.messages, io.state, ctx.countTokens, strategy),\n };\n },\n };\n}\n\n/** Backward compat: default render-refs node using strategy \"all\". */\nexport const renderRefsNode: PipelineNode = createRenderRefsNode(\"all\");\n","import type { Config, CoreMessage } from \"./types.js\";\n\n/** Tools that are ALWAYS protected, regardless of user config. These are ACP's\n * own metadata tools whose records must remain in context: compress calls\n * carry the summaries that decompress/search rely on, and the system prompt\n * treats past compress calls as load-bearing metadata. Letting them be\n * compressed away breaks decompress and the \"summary is historical\" contract. */\nexport const ALWAYS_PROTECTED_TOOLS = [\"compress\"] as const;\n\n/** Tool results that must NEVER participate in the soft-protected recent zone\n * (preserveRecentMessages / preserveRecentTokens / last user message).\n *\n * These tools return large content (restored blocks, search hits, file bodies,\n * command output). If such a result lands in the last-N window it becomes\n * un-compressible: the model cannot reclaim that context, and it never appears\n * in the compressible-ranges recommendation list. Excluding these tools from\n * the protected zone lets the model compress them again immediately, while\n * still leaving them visible (the host's preserveRecent is about not\n * compressing the active working set, not about which tool results are in\n * scope).\n *\n * - `decompress`: large restored content as an inline tool result.\n * - `search_context`: large result lists (10 ranked hits with previews).\n * - `read`: file/image contents — the largest common source of context bloat.\n * - `bash`: command output (build/test/logs) — frequently large and spent.\n *\n * Note: this only affects the recent-zone computation. Such messages remain\n * fully visible and compressible like any ordinary message. */\nexport const NEVER_PRESERVE_RECENT_TOOLS = [\n \"decompress\",\n \"search_context\",\n \"read\",\n \"bash\",\n] as const;\n\n/** True for tool-call / tool-result messages whose toolName is in the\n * NEVER_PRESERVE_RECENT_TOOLS list — i.e. tool results (like decompress)\n * that should be excluded from the soft-protected recent zone. */\nexport function isNeverPreserveRecent(msg: CoreMessage): boolean {\n if (msg.contentType !== \"tool-call\" && msg.contentType !== \"tool-result\") {\n return false;\n }\n if (!msg.toolName) return false;\n return (NEVER_PRESERVE_RECENT_TOOLS as readonly string[]).includes(msg.toolName);\n}\n\nexport function matchToolPattern(toolName: string, pattern: string): boolean {\n if (pattern.endsWith(\"*\")) {\n return toolName.startsWith(pattern.slice(0, -1));\n }\n return toolName === pattern;\n}\n\nexport function isMessageProtected(\n msg: CoreMessage,\n config: Pick<Config, \"protectedTools\" | \"isToolProtected\">,\n): boolean {\n // tool-result carries the same toolName as its tool-call (the host projects\n // it), so checking toolName covers both sides of a tool exchange.\n if (\n (msg.contentType !== \"tool-call\" && msg.contentType !== \"tool-result\") ||\n !msg.toolName\n ) {\n return false;\n }\n\n // Hard-coded protection: ACP metadata tools are never compressible.\n if ((ALWAYS_PROTECTED_TOOLS as readonly string[]).includes(msg.toolName)) {\n return true;\n }\n\n for (const pattern of config.protectedTools) {\n if (matchToolPattern(msg.toolName, pattern)) return true;\n }\n\n if (config.isToolProtected?.(msg.toolName, msg.text)) return true;\n\n return false;\n}\n\n/** Build the set of toolCallIds whose tool-call is protected. Use this to also\n * protect tool-results that lack a toolName (common when the host projects a\n * tool-result with only toolCallId). Without it, the result half of a\n * protected tool exchange leaks into compressible ranges. */\nexport function collectProtectedToolCallIds(\n messages: CoreMessage[],\n config: Pick<Config, \"protectedTools\" | \"isToolProtected\">,\n): Set<string> {\n const ids = new Set<string>();\n for (const m of messages) {\n if (m.contentType === \"tool-call\" && m.toolCallId && isMessageProtected(m, config)) {\n ids.add(m.toolCallId);\n }\n }\n return ids;\n}\n\n/** Like isMessageProtected, but also matches tool-results by toolCallId against\n * the protected call set. Use when you have the full message list available. */\nexport function isMessageProtectedWithPairing(\n msg: CoreMessage,\n config: Pick<Config, \"protectedTools\" | \"isToolProtected\">,\n protectedCallIds: Set<string>,\n): boolean {\n if (isMessageProtected(msg, config)) return true;\n if (\n msg.contentType === \"tool-result\" &&\n msg.toolCallId &&\n protectedCallIds.has(msg.toolCallId)\n ) {\n return true;\n }\n return false;\n}\n","import type { CoreMessage } from \"./types.js\";\n\n/**\n * Adjust compression range boundaries to include tool-call/result pairs.\n *\n * PREVENTIVE approach (adapted from opencode-acp PR #248): before compression\n * is applied, scan for tool-call or tool-result messages whose matching half\n * (the result for a call in range, or the call for a result in range) sits\n * outside the requested range. Pull the orphan half INTO the range so the\n * pair is compressed together — zero information loss.\n *\n * Only MESSAGE-boundary ranges are adjusted. Block-boundary ranges (bN) are\n * left untouched to preserve tier-detection correctness.\n *\n * @returns Adjusted { startIndex, endIndex } — may be wider than input.\n */\nexport function adjustBoundariesForToolPairs(\n startIndex: number,\n endIndex: number,\n messages: CoreMessage[],\n maxScan: number = 20,\n): { startIndex: number; endIndex: number } {\n // Collect all toolCallIds in range (both tool-call and tool-result messages).\n // Skip compress tool — it's force-protected and always survives pruning.\n const callIdsInRange = new Set<string>();\n for (let i = startIndex; i <= endIndex; i++) {\n const msg = messages[i];\n if (!msg || !msg.toolCallId) continue;\n if (msg.toolName === \"compress\") continue;\n callIdsInRange.add(msg.toolCallId);\n }\n\n if (callIdsInRange.size === 0) {\n return { startIndex, endIndex };\n }\n\n // Extend FORWARD: tool-results typically follow their tool-call.\n // Stop at the first gap after finding at least one matching message.\n let newEndIndex = endIndex;\n for (let i = endIndex + 1; i < messages.length && i <= endIndex + maxScan; i++) {\n const msg = messages[i];\n if (!msg) break;\n if (msg.toolCallId && callIdsInRange.has(msg.toolCallId)) {\n newEndIndex = i;\n } else if (newEndIndex > endIndex) {\n break;\n }\n }\n\n // Extend BACKWARD: tool-calls typically precede their tool-result.\n let newStartIndex = startIndex;\n for (let i = startIndex - 1; i >= 0 && i >= startIndex - maxScan; i--) {\n const msg = messages[i];\n if (!msg) break;\n if (msg.toolCallId && callIdsInRange.has(msg.toolCallId)) {\n newStartIndex = i;\n } else if (newStartIndex < startIndex) {\n break;\n }\n }\n\n return { startIndex: newStartIndex, endIndex: newEndIndex };\n}\n","/**\n * Recommendation engine — compression protection + recommendation.\n *\n * Clean-room reimplementation of the recommendation algorithm (MIT, ours).\n * These pure functions answer two questions every turn:\n *\n * 1. **Protection** — which messages must NOT be compressed? (protected tools,\n * recent messages, recent tokens)\n * 2. **Recommendation** — which remaining ranges are actually WORTH compressing?\n * (growth-aware threshold; suppress nudges when ranges are too small)\n *\n * Called by the `recommend` pipeline node. No side effects, no state mutation.\n */\n\nimport type {\n CompressibleRange,\n Config,\n ContextRanges,\n CoreMessage,\n ProtectedRange,\n} from \"./types.js\";\nimport type { CompressionState } from \"./types.js\";\nimport {\n collectProtectedToolCallIds,\n isMessageProtectedWithPairing,\n isNeverPreserveRecent,\n} from \"./protected.js\";\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction refNum(ref: string): number {\n const n = parseInt(ref.slice(1), 10);\n return Number.isNaN(n) ? -1 : n;\n}\n\nfunction estimateTextTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nfunction isToolMessage(message: CoreMessage): boolean {\n return message.contentType === \"tool-call\" || message.contentType === \"tool-result\";\n}\n\n\nfunction isSyntheticOrPruned(\n message: CoreMessage,\n state: CompressionState,\n): boolean {\n if (message.text?.startsWith(\"[Compressed conversation section]\")) return true;\n for (const block of state.blocks) {\n if (block.active && block.effectiveMessageIds.includes(message.id)) return true;\n }\n return false;\n}\n\n// ─── 1. Protected Refs (soft protection zone) ─────────────────────────────────\n\n/**\n * Compute the set of protected message refs (mNNNNN) that form the\n * \"soft-protected zone\" at the tail of the conversation.\n *\n * Combines two rules:\n * 1. Last N messages (`config.preserveRecentMessages`)\n * 2. Last N tokens expanding backward (`config.preserveRecentTokens`)\n *\n * Only considers visible, non-synthetic, non-pruned messages that have refs.\n */\nexport function computeProtectedRefs(\n messages: CoreMessage[],\n state: CompressionState,\n config: Config,\n countTokens: (text: string) => number = estimateTextTokens,\n): Set<string> {\n const preserveN = config.preserveRecentMessages;\n const preserveTokens = config.preserveRecentTokens;\n\n const result = new Set<string>();\n const visible: { ref: string; tokens: number }[] = [];\n\n for (const msg of messages) {\n if (isSyntheticOrPruned(msg, state)) continue;\n // Exclude decompress-style tool results from the recent-zone window.\n // These are large inline restorations that the model should be free to\n // compress again immediately; counting them toward the last-N window\n // would make them un-compressible and hide them from recommendations.\n // The message stays fully visible — this only affects protection scope.\n if (isNeverPreserveRecent(msg)) continue;\n const ref = state.messageRefs.byRaw[msg.id];\n if (!ref || ref === \"BLOCKED\") continue;\n visible.push({ ref, tokens: countTokens(msg.text ?? \"\") });\n }\n\n // Rule 1: last N messages\n if (preserveN > 0) {\n for (const m of visible.slice(-preserveN)) {\n result.add(m.ref);\n }\n }\n\n // Rule 2: last N tokens (expand backward from tail)\n if (preserveTokens > 0) {\n let tokenAccum = 0;\n for (let i = visible.length - 1; i >= 0 && tokenAccum < preserveTokens; i--) {\n result.add(visible[i]!.ref);\n tokenAccum += visible[i]!.tokens;\n }\n }\n\n // Rule 3: last visible user message. Protected whenever recent-message\n // protection is on (preserveRecentMessages > 0) — this couples it to the\n // same switch as Rule 1, so setting preserveRecentMessages = 0 fully opts\n // out (needed by tests that compress the tail). Production defaultConfig\n // uses 5, so the last user message is always protected in practice.\n // Note: we scan the raw messages array (not `visible`) here so the last\n // user message is still found even when a decompress tool result was\n // skipped above — user intent is always protected regardless of recent\n // tool results.\n if (preserveN > 0) {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i]!;\n if (msg.role !== \"user\" || isSyntheticOrPruned(msg, state)) continue;\n const ref = state.messageRefs.byRaw[msg.id];\n if (ref && ref !== \"BLOCKED\") result.add(ref);\n break;\n }\n }\n\n return result;\n}\n\n// ─── 2. Build Compressible + Protected Ranges ────────────────────────────────\n\n/**\n * Build compressible and protected range groups from the message list.\n *\n * Messages are classified into:\n * - **compressible**: normal messages outside the protected zone\n * - **protected**: messages from protected tools (e.g., skill, task)\n * - **skipped**: covered by blocks, synthetic, or in the protected zone\n *\n * Compressible messages are grouped into contiguous ranges. The protected\n * zone (from `computeProtectedRefs`) splits groups — the unprotected head\n * survives as its own range.\n */\nexport function buildCompressibleRanges(\n messages: CoreMessage[],\n state: CompressionState,\n config: Config,\n protectedZoneRefs?: Set<string>,\n countTokens: (text: string) => number = estimateTextTokens,\n): ContextRanges {\n const compressibleMsgs: {\n ref: string;\n refNum: number;\n tokens: number;\n isTool: boolean;\n isUser: boolean;\n }[] = [];\n const protectedMsgs: {\n ref: string;\n refNum: number;\n tokens: number;\n tools: string[];\n }[] = [];\n\n // Pairing: a tool-result may carry only toolCallId (no toolName). Collect the\n // callIds of protected tool-calls first, then protect matching results too.\n const protectedCallIds = collectProtectedToolCallIds(messages, config);\n\n for (const msg of messages) {\n if (isSyntheticOrPruned(msg, state)) continue;\n const ref = state.messageRefs.byRaw[msg.id];\n if (!ref || ref === \"BLOCKED\") continue;\n\n const rn = refNum(ref);\n\n if (isMessageProtectedWithPairing(msg, config, protectedCallIds)) {\n protectedMsgs.push({\n ref,\n refNum: rn,\n tokens: countTokens(msg.text ?? \"\"),\n tools: msg.toolName ? [msg.toolName] : [],\n });\n continue;\n }\n\n if (protectedZoneRefs?.has(ref)) {\n continue;\n }\n\n compressibleMsgs.push({\n ref,\n refNum: rn,\n tokens: countTokens(msg.text ?? \"\"),\n isTool: isToolMessage(msg),\n isUser: msg.role === \"user\",\n });\n }\n\n // Build compressible groups (contiguous, split at ref gaps and at user\n // messages once a group has >= 3 messages). Splitting at user boundaries\n // keeps each compressible range aligned to roughly one user turn, instead\n // of producing one giant range spanning many turns (or, conversely, a\n // fragment per message when ref gaps appear). Mirrors opencode-acp's\n // buildCompressibleRanges condition.\n const compressible: CompressibleRange[] = [];\n let cur: CompressibleRange | null = null;\n let prevRefNum = -2;\n\n for (const info of compressibleMsgs) {\n const hasGap = info.refNum > prevRefNum + 1;\n if (cur && ((info.isUser && cur.count >= 3) || hasGap)) {\n compressible.push(cur);\n cur = null;\n }\n prevRefNum = info.refNum;\n if (!cur) {\n cur = {\n startRef: info.ref,\n endRef: info.ref,\n count: 1,\n tokens: info.tokens,\n toolPct: info.isTool ? 100 : 0,\n textPct: info.isTool ? 0 : 100,\n };\n } else {\n cur.endRef = info.ref;\n cur.count++;\n cur.tokens += info.tokens;\n if (info.isTool) {\n cur.toolPct = Math.round((cur.toolPct * (cur.count - 1) + 100) / cur.count);\n } else {\n cur.toolPct = Math.round((cur.toolPct * (cur.count - 1)) / cur.count);\n }\n cur.textPct = 100 - cur.toolPct;\n }\n }\n if (cur) compressible.push(cur);\n\n // Build protected groups (contiguous)\n const protectedRanges: ProtectedRange[] = [];\n let pcur: ProtectedRange | null = null;\n let pPrevRefNum = -2;\n\n for (const info of protectedMsgs) {\n const hasGap = info.refNum > pPrevRefNum + 1;\n if (pcur && hasGap) {\n protectedRanges.push(pcur);\n pcur = null;\n }\n pPrevRefNum = info.refNum;\n if (!pcur) {\n pcur = {\n startRef: info.ref,\n endRef: info.ref,\n count: 1,\n tokens: info.tokens,\n tools: [...info.tools],\n };\n } else {\n pcur.endRef = info.ref;\n pcur.count++;\n pcur.tokens += info.tokens;\n for (const t of info.tools) {\n if (!pcur!.tools.includes(t)) pcur!.tools.push(t);\n }\n }\n }\n if (pcur) protectedRanges.push(pcur);\n\n return {\n compressible: compressible.filter((g) => g.tokens > 0),\n protected: protectedRanges,\n };\n}\n","import type { CompressionState, CoreMessage, NudgeDecision } from \"./types.js\";\n\nexport interface PipelineContext {\n readonly config: import(\"./types.js\").Config;\n readonly tokenCount: number;\n readonly countTokens: (text: string) => number;\n}\n\nexport interface NodeEffects {\n nudge?: NudgeDecision;\n recommendation?: import(\"./types.js\").Recommendation;\n truncatedCount?: number;\n readonly [key: string]: unknown;\n}\n\nexport interface NodeIO {\n messages: CoreMessage[];\n state: CompressionState;\n effects: NodeEffects;\n}\n\nexport interface PipelineNode {\n readonly name: string;\n run(io: NodeIO, ctx: PipelineContext): NodeIO;\n enabled?: (io: NodeIO, ctx: PipelineContext) => boolean;\n}\n\nexport function makeIO(\n messages: CoreMessage[],\n state: CompressionState,\n effects: NodeEffects = {},\n): NodeIO {\n return { messages, state, effects };\n}\n\nexport function runPipeline(\n nodes: readonly PipelineNode[],\n initial: NodeIO,\n ctx: PipelineContext,\n): NodeIO {\n let io = initial;\n for (const node of nodes) {\n if (node.enabled && !node.enabled(io, ctx)) continue;\n io = node.run(io, ctx);\n }\n return io;\n}\n","import { assignRefs, highestUsedIndex } from \"./refs.js\";\nimport { prune } from \"./prune.js\";\nimport { syncBlocks } from \"./sync.js\";\nimport { advanceSurvival, activeBlocks, blockById } from \"./state.js\";\nimport {\n allocateBlockId,\n allocateRunId,\n createInitialState,\n} from \"./state.js\";\nimport { defaultCountTokens } from \"./tokenize.js\";\nimport { validateConfig } from \"./config.js\";\nimport { resolveBoundaries, earliestIndexOfIds } from \"./boundaries.js\";\nimport { truncateLargeToolOutputs } from \"./truncate-tools.js\";\nimport { hideConsumedCompressCalls } from \"./hide-consumed.js\";\nimport { applyMessageFilters, listMessageFilters } from \"./filter/index.js\";\nimport { createRenderRefsNode } from \"./render-refs.js\";\nimport type { RenderStrategy } from \"./render-refs.js\";\nimport { isMessageProtected } from \"./protected.js\";\nimport { adjustBoundariesForToolPairs } from \"./tool-pairs.js\";\nimport {\n computeProtectedRefs,\n buildCompressibleRanges,\n} from \"./recommend.js\";\nimport {\n runPipeline,\n type PipelineContext,\n type PipelineNode,\n type NodeIO,\n} from \"./pipeline.js\";\nimport type {\n ApplyCompressionResult,\n CompressionBlock,\n CompressionState,\n CompressionTier,\n Config,\n ContextBreakdown,\n CoreMessage,\n NudgeConfig,\n NudgeDecision,\n ProcessTurnResult,\n Recommendation,\n StatusReport,\n} from \"./types.js\";\n\nexport interface Ports {\n countTokens?: (text: string) => number;\n}\n\nexport interface CompressionCore {\n processTurn(input: ProcessTurnInput): ProcessTurnResult;\n applyCompression(input: ApplyCompressionInput): ApplyCompressionResult;\n defaultNodes(): PipelineNode[];\n decompress(\n blockId: string,\n state: CompressionState,\n ): CompressionBlock | undefined;\n search(query: string, state: CompressionState): CompressionBlock[];\n status(\n state: CompressionState,\n tokenCount: number,\n config: Config,\n ): StatusReport;\n}\n\nexport interface ProcessTurnInput {\n messages: CoreMessage[];\n state: CompressionState;\n config: Config;\n tokenCount: number;\n /**\n * Which messages get an <acp> ref tag injected into their text\n * (the render-refs pipeline node). Refs are ALWAYS assigned regardless\n * (assign-refs node runs unconditionally).\n * - \"all\" (default): tag every mapped message — in-process hosts\n * like pai-acp want tags for the LLM to reference compress ranges.\n * - \"text-only\": tag only user/assistant text; leave tool-call args\n * and tool-result content pristine — proxy hosts where structured\n * content must not be polluted.\n * - \"none\": leave all text untouched — hosts that read the ref map\n * directly from result.state.messageRefs.\n */\n renderTags?: RenderStrategy;\n}\n\nexport interface ApplyCompressionInput {\n ranges: {\n startRef: string;\n endRef: string;\n summary: string;\n topic?: string;\n compressCallId?: string;\n summaryMaxChars?: number;\n }[];\n messages: CoreMessage[];\n state: CompressionState;\n config: Config;\n protectedMessageIds?: Set<string>;\n}\n\nexport function createCore(ports: Ports = {}): CompressionCore {\n const countTokens = ports.countTokens ?? defaultCountTokens;\n\n function applyCompression(\n input: ApplyCompressionInput,\n ): ApplyCompressionResult {\n const state: CompressionState = cloneState(input.state);\n const runId = allocateRunId(state);\n let blocksCreated = 0;\n let tokensCompressed = 0;\n const errors: string[] = [];\n const warnings: string[] = [];\n\n // Default to the soft-protected zone (recent-N + last user message) when the\n // caller doesn't pass an explicit set. This makes applyCompression safe by\n // default; applySingleRange enforces it as a hard backstop.\n const protectedMessageIds =\n input.protectedMessageIds ??\n computeProtectedRefs(input.messages, input.state, input.config, countTokens);\n\n const preExistingCoverage = collectCoverage(state);\n\n const rangeIndexSets: { spec: typeof input.ranges[number]; indices: number[] }[] = [];\n for (const spec of input.ranges) {\n let resolved;\n try {\n resolved = resolveBoundaries({\n startRef: spec.startRef,\n endRef: spec.endRef,\n messages: input.messages,\n state,\n });\n } catch {\n continue;\n }\n const indices = resolved.messageIds.map((id) =>\n input.messages.findIndex((m) => m.id === id),\n ).filter((i) => i >= 0);\n rangeIndexSets.push({ spec, indices });\n }\n const sortedRanges = [...rangeIndexSets].sort((a, b) => {\n const aMin = a.indices.length > 0 ? Math.min(...a.indices) : Infinity;\n const bMin = b.indices.length > 0 ? Math.min(...b.indices) : Infinity;\n return aMin - bMin;\n });\n // Overlapping ranges warn+skip (earliest wins) rather than aborting the\n // whole batch — see ISSUE-42 / dog/billion-context-pi#21.\n const skipSpecs = new Set<typeof input.ranges[number]>();\n let acceptedMaxIndex = -1;\n for (const entry of sortedRanges) {\n const entryMax = entry.indices.length > 0 ? Math.max(...entry.indices) : -1;\n const entryMin = entry.indices.length > 0 ? Math.min(...entry.indices) : -1;\n if (entryMin >= 0 && entryMin <= acceptedMaxIndex) {\n skipSpecs.add(entry.spec);\n warnings.push(\n `Skipped range (${entry.spec.startRef}..${entry.spec.endRef}) — overlaps an earlier range in the batch; the earlier range takes precedence. Keep ranges disjoint.`,\n );\n continue;\n }\n if (entryMax > acceptedMaxIndex) acceptedMaxIndex = entryMax;\n }\n\n if (input.config.compress.minCompressRange > 0 && input.ranges.length > 0) {\n let totalRangeChars = 0;\n let hasBlockBoundaryRange = false;\n for (const spec of input.ranges) {\n if (skipSpecs.has(spec)) continue;\n let resolved;\n try {\n resolved = resolveBoundaries({\n startRef: spec.startRef,\n endRef: spec.endRef,\n messages: input.messages,\n state,\n });\n } catch {\n continue;\n }\n if (resolved.boundaryKind === \"block\") {\n hasBlockBoundaryRange = true;\n continue;\n }\n for (const id of resolved.messageIds) {\n const msg = input.messages.find((m) => m.id === id);\n totalRangeChars += msg?.text?.length ?? 0;\n }\n }\n if (!hasBlockBoundaryRange && totalRangeChars < input.config.compress.minCompressRange) {\n return {\n state: input.state,\n result: {\n blocksCreated: 0,\n tokensCompressed: 0,\n errors: [\n `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.`,\n ],\n warnings: [],\n },\n };\n }\n }\n\n for (const spec of input.ranges) {\n if (skipSpecs.has(spec)) continue;\n try {\n const outcome = applySingleRange({\n spec,\n messages: input.messages,\n state,\n runId,\n config: input.config,\n protectedMessageIds,\n countTokens,\n preExistingCoverage,\n });\n blocksCreated++;\n tokensCompressed += outcome.tokens;\n warnings.push(...outcome.warnings);\n } catch (error) {\n errors.push(error instanceof Error ? error.message : String(error));\n }\n }\n\n state.stats.compressionCount += blocksCreated;\n state.stats.tokensCompressed += tokensCompressed;\n\n if (blocksCreated > 0) {\n // Compress succeeded: clear the growth baseline so the next turn\n // re-establishes it at the new (lower) token count. Without this the\n // nudge re-fires in a feedback loop (the §5.7 baseline-reset bug).\n state.nudge.lastPerMessageNudgeTokens = 0;\n state.nudge.lastNudgeShownTokens = 0;\n // Clearing the per-tier cadence too: after a successful compression\n // (which may have consumed blocks of tier N to produce tier N+1), every\n // tier should be eligible to re-evaluate from the new token count.\n state.nudge.lastShownByTier = {};\n }\n\n return { state, result: { blocksCreated, tokensCompressed, errors, warnings } };\n }\n\n function processTurn(input: ProcessTurnInput): ProcessTurnResult {\n const configErrors = validateConfig(input.config);\n if (configErrors.length > 0) {\n console.warn(`[acp-kernel] Config validation warnings: ${configErrors.join(\"; \")}. Thresholds may not fire correctly.`);\n }\n const ctx: PipelineContext = {\n config: input.config,\n tokenCount: input.tokenCount,\n countTokens,\n };\n const initial: NodeIO = {\n messages: input.messages,\n state: input.state,\n effects: {},\n };\n // Conversion (assign-refs) and rendering (render-refs) are separate\n // concerns. Refs are always assigned; renderTags only controls which\n // message texts receive an <acp> tag.\n const strategy: RenderStrategy = input.renderTags ?? \"all\";\n const nodes = buildNodes(strategy);\n const result = runPipeline(nodes, initial, ctx);\n return {\n messages: result.messages,\n state: result.state,\n nudge: result.effects.nudge,\n };\n }\n\n function decompress(blockId: string, state: CompressionState) {\n return blockById(state, blockId);\n }\n\n function search(query: string, state: CompressionState): CompressionBlock[] {\n const terms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((term) => term.length > 0);\n if (terms.length === 0) return [];\n const scored = activeBlocks(state)\n .map((block) => ({ block, score: scoreRelevance(block, terms) }))\n .filter((entry) => entry.score > 0.1)\n .sort((left, right) => right.score - left.score);\n return scored.map((entry) => entry.block);\n }\n\n function status(\n state: CompressionState,\n tokenCount: number,\n config: Config,\n ): StatusReport {\n const active = activeBlocks(state);\n const usage =\n config.modelContextLimit > 0 ? tokenCount / config.modelContextLimit : 0;\n return {\n contextUsage: usage,\n tokenCount,\n modelContextLimit: config.modelContextLimit,\n activeBlocks: active.length,\n totalBlocks: state.blocks.length,\n tokensCompressed: state.stats.tokensCompressed,\n breakdown: { active: active.length, total: state.blocks.length },\n };\n }\n\n function defaultNodes(): PipelineNode[] {\n return buildNodes(\"all\");\n }\n\n /** Build the pipeline node list for a given render strategy. \"none\" omits\n * the render-refs node entirely; \"all\"/\"text-only\" append a render-refs\n * node bound to that strategy. */\n function buildNodes(strategy: RenderStrategy): PipelineNode[] {\n const base: PipelineNode[] = [\n assignRefsNode,\n syncBlocksNode,\n pruneNode,\n filterNode,\n hideCompressCallsNode,\n recommendNode,\n nudgeNode,\n emergencyTruncateNode,\n ];\n if (strategy === \"none\") return base;\n return [...base, createRenderRefsNode(strategy)];\n }\n\n return { processTurn, applyCompression, defaultNodes, decompress, search, status };\n}\n\n// --- Pipeline nodes -------------------------------------------------------\n// Each node owns ONE concern. The ref map has a SINGLE writer (assignRefsNode);\n// tags are DERIVED at the end (renderRefsNode) — no dual source of truth, so\n// the old stripHallucinations band-aid is gone. Truncation is the LAST\n// token-reducing safety valve; render-refs is the final annotation pass.\n\nconst assignRefsNode: PipelineNode = {\n name: \"assign-refs\",\n run(io, ctx) {\n const hasProtection =\n ctx.config.protectedTools.length > 0 || !!ctx.config.isToolProtected;\n const protectedFn = hasProtection\n ? (m: CoreMessage) => isMessageProtected(m, ctx.config)\n : undefined;\n const refResult = assignRefs(io.messages, {\n existing: io.state.messageRefs,\n nextIndex: highestUsedIndex(io.state.messageRefs) + 1,\n isProtected: protectedFn,\n });\n return { ...io, state: { ...io.state, messageRefs: refResult.map } };\n },\n};\n\nconst syncBlocksNode: PipelineNode = {\n name: \"sync-blocks\",\n run(io, ctx) {\n const synced = syncBlocks(io.messages, io.state);\n advanceSurvival(synced.state, ctx.config.promotionThreshold);\n return { ...io, state: synced.state };\n },\n};\n\nconst pruneNode: PipelineNode = {\n name: \"prune\",\n run(io) {\n return { ...io, messages: prune(io.messages, io.state) };\n },\n};\n\nconst filterNode: PipelineNode = {\n name: \"filter\",\n enabled: (_io, ctx) =>\n !!ctx.config.messageFilters?.enabled && listMessageFilters().length > 0,\n run(io, ctx) {\n const applied = applyMessageFilters(io.messages, ctx.config.messageFilters);\n return { ...io, messages: applied.messages };\n },\n};\n\nconst hideCompressCallsNode: PipelineNode = {\n name: \"hide-compress-calls\",\n run(io) {\n const hidden = hideConsumedCompressCalls(io.state, io.messages);\n return { ...io, messages: hidden.messages };\n },\n};\n\nconst recommendNode: PipelineNode = {\n name: \"recommend\",\n run(io, ctx) {\n const protectedRefs = computeProtectedRefs(\n io.messages,\n io.state,\n ctx.config,\n ctx.countTokens,\n );\n const contextRanges = buildCompressibleRanges(\n io.messages,\n io.state,\n ctx.config,\n protectedRefs,\n ctx.countTokens,\n );\n const nothingToCompress = contextRanges.compressible.length === 0;\n const recommendation: Recommendation = {\n contextRanges,\n recommendedRanges: contextRanges.compressible,\n nothingToCompress,\n };\n return { ...io, effects: { ...io.effects, recommendation } };\n },\n};\n\nconst nudgeNode: PipelineNode = {\n name: \"nudge-inject\",\n run(io, ctx) {\n const nudge = decideNudge({\n tokenCount: ctx.tokenCount,\n config: ctx.config,\n state: io.state,\n messages: io.messages,\n recommendation: io.effects.recommendation,\n countTokens: ctx.countTokens,\n });\n\n const baseline = io.state.nudge.lastPerMessageNudgeTokens;\n const nudgeGrowthTokens = resolveAdaptiveGrowth(\n ctx.config.modelContextLimit,\n ctx.config.nudge,\n );\n\n let stamped = { ...io.state.nudge };\n\n if (\n baseline > 0 &&\n ctx.tokenCount < baseline - nudgeGrowthTokens\n ) {\n stamped.lastPerMessageNudgeTokens = ctx.tokenCount;\n stamped.lastNudgeShownTokens = 0;\n }\n\n if (stamped.lastPerMessageNudgeTokens === 0) {\n stamped.lastPerMessageNudgeTokens = ctx.tokenCount;\n }\n\n if (nudge.shouldInject) {\n stamped.lastNudgeShownTokens = ctx.tokenCount;\n // Record the injected tier's own cadence baseline. Shared baseline\n // (lastNudgeShownTokens) suppresses lower-priority tiers within this\n // turn; the per-tier entry throttles re-firing of the SAME tier.\n if (nudge.tier !== null) {\n stamped.lastShownByTier = { ...stamped.lastShownByTier, [nudge.tier]: ctx.tokenCount };\n }\n }\n\n return {\n ...io,\n state: { ...io.state, nudge: stamped },\n effects: { ...io.effects, nudge },\n };\n },\n};\n\nconst emergencyTruncateNode: PipelineNode = {\n name: \"emergency-truncate\",\n run(io, ctx) {\n const usage =\n ctx.config.modelContextLimit > 0\n ? ctx.tokenCount / ctx.config.modelContextLimit\n : 0;\n if (usage < ctx.config.truncate.threshold) return io;\n const trunc = truncateLargeToolOutputs(\n io.messages,\n ctx.tokenCount,\n ctx.config,\n ctx.countTokens,\n { protectRecentMessages: ctx.config.preserveRecentMessages },\n );\n return {\n ...io,\n messages: trunc.messages,\n effects: { ...io.effects, truncatedCount: trunc.truncatedCount },\n };\n },\n};\n\ninterface SingleRangeInput {\n spec: { startRef: string; endRef: string; summary: string; topic?: string; compressCallId?: string; summaryMaxChars?: number };\n messages: CoreMessage[];\n state: CompressionState;\n runId: string;\n config: Config;\n protectedMessageIds?: Set<string>;\n countTokens: (text: string) => number;\n preExistingCoverage: Set<string>;\n}\n\ninterface SingleRangeOutcome {\n tokens: number;\n warnings: string[];\n}\n\nfunction applySingleRange(input: SingleRangeInput): SingleRangeOutcome {\n const warnings: string[] = [];\n const resolved = resolveBoundaries({\n startRef: input.spec.startRef,\n endRef: input.spec.endRef,\n messages: input.messages,\n state: input.state,\n });\n\n const rangeMessageIds = applyToolPairAdjustment(\n resolved,\n input.messages,\n );\n\n // Re-scan for nested blocks in the ADJUSTED range (tool-pair extension may\n // have pulled in messages that are anchors of existing blocks).\n if (rangeMessageIds.length > resolved.messageIds.length) {\n const indexByRawId = new Map<string, number>();\n input.messages.forEach((m, i) => indexByRawId.set(m.id, i));\n const adjustedStart = indexByRawId.get(rangeMessageIds[0]!) ?? resolved.startIndex;\n const adjustedEnd = indexByRawId.get(rangeMessageIds[rangeMessageIds.length - 1]!) ?? resolved.endIndex;\n const nestedSeen = new Set(resolved.nestedBlockIds);\n for (const block of activeBlocks(input.state)) {\n if (nestedSeen.has(block.blockId)) continue;\n const anchor = earliestIndexOfIds(block.effectiveMessageIds, indexByRawId);\n if (anchor !== null && anchor >= adjustedStart && anchor <= adjustedEnd) {\n nestedSeen.add(block.blockId);\n resolved.nestedBlockIds.push(block.blockId);\n }\n }\n }\n\n const isBlockBoundary = resolved.boundaryKind === \"block\";\n const targetTier = resolveTargetTier(\n input.state,\n resolved.nestedBlockIds,\n isBlockBoundary,\n );\n const outputTier = isBlockBoundary\n ? (Math.min(3, targetTier + 1) as CompressionTier)\n : 1;\n\n const consumedBlockIds = resolved.nestedBlockIds.filter((id) => {\n const block = blockById(input.state, id);\n return block?.active && block.tier === targetTier;\n });\n\n const effectiveMessageIds = new Set<string>(rangeMessageIds);\n for (const consumedId of consumedBlockIds) {\n const consumed = blockById(input.state, consumedId);\n if (consumed) {\n for (const id of consumed.effectiveMessageIds)\n effectiveMessageIds.add(id);\n }\n }\n\n const directMessageIds = [...effectiveMessageIds].filter(\n (id) => !input.preExistingCoverage.has(id),\n );\n\n let filteredIds = filterProtectedToolMessages(\n directMessageIds,\n input.messages,\n input.config,\n );\n\n // filterProtectedToolMessages drops protected tool calls (and their paired\n // results) from the compressible set. They must also leave effectiveMessageIds,\n // otherwise the block would record them as covered and hide them from view.\n // (Bug 39: protected tool messages folded into a block.)\n if (filteredIds.length < directMessageIds.length) {\n const kept = new Set(filteredIds);\n for (const id of directMessageIds) {\n if (!kept.has(id)) effectiveMessageIds.delete(id);\n }\n }\n\n // SOFT PROTECTION: the recent-N / last-user-message zone is advisory-only at\n // compress time. Instead of failing the whole range when it brushes protected\n // messages, exclude those messages and proceed with the rest (so the model\n // isn't blocked when it picks a range that slightly overlaps the recent\n // window). If excluding them empties the range entirely AND there are no\n // consumed blocks to merge, we still fail — there is genuinely nothing to\n // compress. `protectedMessageIds` holds REF ids (mNNNNN) from\n // computeProtectedRefs; filteredIds holds RAW message ids, so convert via\n // state.messageRefs.byRaw before testing membership.\n const protectedRefs = input.protectedMessageIds;\n const hitProtectedRaw = protectedRefs\n ? filteredIds.filter((id) => {\n const ref = input.state.messageRefs.byRaw[id];\n return ref !== undefined && protectedRefs.has(ref);\n })\n : [];\n if (hitProtectedRaw.length > 0) {\n const protectedSet = new Set(hitProtectedRaw);\n filteredIds = filteredIds.filter((id) => !protectedSet.has(id));\n // Remove protected messages from effective coverage too, so they are NOT\n // hidden by the new block (they must stay fully visible).\n for (const id of hitProtectedRaw) effectiveMessageIds.delete(id);\n\n const hitRefs = hitProtectedRaw\n .map((id) => input.state.messageRefs.byRaw[id])\n .filter((v): v is string => typeof v === \"string\");\n\n if (filteredIds.length === 0 && consumedBlockIds.length === 0) {\n const recentN = input.config.preserveRecentMessages;\n throw new Error(\n `Range is entirely within the protected zone (the last ${recentN} messages and/or the most recent user message): ${hitRefs.join(\n \", \",\n )}. Adjust startId/endId to older messages.`,\n );\n }\n warnings.push(\n `Excluded ${hitProtectedRaw.length} protected message(s) ${hitRefs.join(\n \", \",\n )} from compression range (recent/last-user zone).`,\n );\n }\n\n validateCompressionRange(input, filteredIds, consumedBlockIds.length);\n\n let compressedTokens = 0;\n for (const id of filteredIds) {\n const message = input.messages.find((entry) => entry.id === id);\n compressedTokens += input.countTokens(message?.text ?? \"\");\n }\n for (const consumedId of consumedBlockIds) {\n const consumed = blockById(input.state, consumedId);\n if (consumed) {\n compressedTokens += input.countTokens(consumed.summary);\n }\n }\n\n const blockId = allocateBlockId(input.state);\n const block: CompressionBlock = {\n blockId,\n runId: input.runId,\n tier: outputTier,\n topic: input.spec.topic,\n summary: input.spec.summary,\n directMessageIds: filteredIds,\n effectiveMessageIds: [...effectiveMessageIds],\n directBlockIds: [...consumedBlockIds],\n compressedTokens,\n createdAt: Date.now(),\n survivedCount: 0,\n generation: \"young\",\n active: true,\n compressCallId: input.spec.compressCallId,\n startRef: input.spec.startRef,\n endRef: input.spec.endRef,\n };\n input.state.blocks.push(block);\n\n for (const consumedId of consumedBlockIds) {\n const consumed = blockById(input.state, consumedId);\n if (consumed) consumed.active = false;\n }\n\n return { tokens: compressedTokens, warnings };\n}\n\nfunction applyToolPairAdjustment(\n resolved: { startIndex: number; endIndex: number; messageIds: string[]; boundaryKind: string },\n messages: CoreMessage[],\n): string[] {\n if (resolved.boundaryKind === \"block\") {\n return resolved.messageIds;\n }\n const adjusted = adjustBoundariesForToolPairs(\n resolved.startIndex,\n resolved.endIndex,\n messages,\n );\n if (\n adjusted.startIndex === resolved.startIndex &&\n adjusted.endIndex === resolved.endIndex\n ) {\n return resolved.messageIds;\n }\n const ids: string[] = [];\n for (let i = adjusted.startIndex; i <= adjusted.endIndex; i++) {\n const msg = messages[i];\n if (msg) ids.push(msg.id);\n }\n return ids;\n}\n\nfunction validateCompressionRange(\n input: SingleRangeInput,\n directMessageIds: string[],\n consumedBlockCount: number,\n): void {\n const cfg = input.config.compress;\n const summary = input.spec.summary?.trim() ?? \"\";\n\n if (summary.length === 0) {\n throw new Error(\n \"Summary is empty — provide a meaningful summary of the compressed range.\",\n );\n }\n\n if (cfg.minSummaryLength > 0 && summary.length < cfg.minSummaryLength) {\n throw new Error(\n `Summary too short (${summary.length} chars, min ${cfg.minSummaryLength}). The summary must capture the compressed range's key information.`,\n );\n }\n\n const effectiveMax = input.spec.summaryMaxChars ?? cfg.maxSummaryLength;\n if (\n effectiveMax > 0 &&\n summary.length > effectiveMax\n ) {\n throw new Error(\n `Summary too long (${summary.length} chars, max ${effectiveMax}). Strip noise — keep critical paths, decisions, errors, and code references. Or pass summaryMaxChars to increase the limit — don't lose critical info just to fit.`,\n );\n }\n\n if (directMessageIds.length === 0 && consumedBlockCount === 0) {\n throw new Error(\n \"Range contains no compressible messages — all are already covered by active blocks or protected.\",\n );\n }\n}\n\nfunction filterProtectedToolMessages(\n directMessageIds: string[],\n messages: CoreMessage[],\n config: Config,\n): string[] {\n // Protected tool calls (and their results, paired by toolCallId) stay in\n // visible context and are simply dropped from the compressible set. They are\n // NOT folded into the summary — the summary reflects what the author wrote,\n // nothing auto-appended.\n const protectedCallIds = new Set<string>();\n const removedIds = new Set<string>();\n for (const msg of messages) {\n if (isMessageProtected(msg, config) && msg.toolCallId) {\n protectedCallIds.add(msg.toolCallId);\n }\n }\n\n for (const id of directMessageIds) {\n const msg = messages.find((m) => m.id === id);\n if (!msg) continue;\n if (isMessageProtected(msg, config)) {\n removedIds.add(id);\n if (msg.toolCallId) protectedCallIds.add(msg.toolCallId);\n }\n }\n\n for (const id of directMessageIds) {\n if (removedIds.has(id)) continue;\n const msg = messages.find((m) => m.id === id);\n if (!msg) continue;\n if (\n msg.contentType === \"tool-result\" &&\n msg.toolCallId &&\n protectedCallIds.has(msg.toolCallId)\n ) {\n removedIds.add(id);\n }\n }\n\n return directMessageIds.filter((id) => !removedIds.has(id));\n}\n\nfunction resolveTargetTier(\n state: CompressionState,\n nestedBlockIds: string[],\n isBlockBoundary: boolean,\n): CompressionTier {\n if (!isBlockBoundary) return 1;\n if (nestedBlockIds.length === 0) return 1;\n let minTier: CompressionTier = 3;\n for (const id of nestedBlockIds) {\n const block = blockById(state, id);\n if (block && block.tier < minTier) minTier = block.tier;\n }\n return minTier;\n}\n\nfunction collectCoverage(state: CompressionState): Set<string> {\n const coverage = new Set<string>();\n for (const block of activeBlocks(state)) {\n for (const id of block.effectiveMessageIds) coverage.add(id);\n }\n return coverage;\n}\n\ninterface NudgeInput {\n tokenCount: number;\n config: Config;\n state: CompressionState;\n messages: CoreMessage[];\n recommendation?: Recommendation;\n countTokens: (t: string) => number;\n}\n\nfunction resolveAdaptiveGrowth(\n modelContextLimit: number,\n nudge: NudgeConfig,\n): number {\n if (!modelContextLimit || modelContextLimit <= 0) return nudge.growthFloor;\n return Math.min(\n nudge.growthCap,\n Math.max(\n nudge.growthFloor,\n Math.round(modelContextLimit * nudge.growthRatio),\n ),\n );\n}\n\n/** Compressible amount for each tier — all tiers use the SAME definition\n * (\"how much can be compressed at this tier\"), so they are handled by one\n * unified loop. T1 = compressible raw-message tokens (excludes protected /\n * already-covered); T2 = total summary tokens of all active tier-1 blocks;\n * T3 = total summary tokens of all active tier-2 blocks. The \"zero filter\"\n * for block tiers is simply that all blocks are compressible by default. */\nfunction pendingByTier(\n state: CompressionState,\n recommendation: Recommendation | undefined,\n countTokens: (t: string) => number,\n): Record<number, { pending: number; targetBlocks: CompressionBlock[] }> {\n const out: Record<number, { pending: number; targetBlocks: CompressionBlock[] }> = {};\n const compressible = recommendation?.contextRanges.compressible ?? [];\n out[1] = { pending: compressible.reduce((s, r) => s + r.tokens, 0), targetBlocks: [] };\n const active = activeBlocks(state);\n const t1 = active.filter((b) => b.tier === 1);\n const t2 = active.filter((b) => b.tier === 2);\n out[2] = { pending: t1.reduce((s, b) => s + countTokens(b.summary), 0), targetBlocks: t1 };\n out[3] = { pending: t2.reduce((s, b) => s + countTokens(b.summary), 0), targetBlocks: t2 };\n return out;\n}\n\nfunction decideNudge(input: NudgeInput): NudgeDecision {\n const { config, state, tokenCount, recommendation, countTokens } = input;\n const limit = config.modelContextLimit;\n const usage = limit > 0 ? tokenCount / limit : 0;\n\n const nudgeGrowthTokens = resolveAdaptiveGrowth(limit, config.nudge);\n\n const emergencyOverride = usage >= config.nudge.emergencyThresholdPct;\n\n const baseline = state.nudge.lastPerMessageNudgeTokens;\n const hadPendingNudge = state.nudge.lastNudgeShownTokens > 0;\n\n const hasPendingNudge = hadPendingNudge;\n const effectiveThreshold = hasPendingNudge\n ? Math.floor(nudgeGrowthTokens / 2)\n : nudgeGrowthTokens;\n\n const growthReference =\n state.nudge.lastNudgeShownTokens > 0\n ? state.nudge.lastNudgeShownTokens\n : baseline > 0\n ? baseline\n : tokenCount;\n\n const growthFloor = Math.max(\n config.nudge.minGrowthFloor,\n config.nudge.minGrowthRatio * nudgeGrowthTokens,\n );\n\n const growthSinceReference = tokenCount - growthReference;\n\n const rec = recommendation;\n const tiers = pendingByTier(state, rec, countTokens);\n\n // Unified injection arbitration, priority T1 > T2 > T3 (ascending). Each\n // tier has its OWN cadence (lastShownByTier) so firing one doesn't block\n // another across turns; within a turn we inject at most the FIRST eligible\n // tier and stop, which raises the shared baseline (lastNudgeShownTokens) so\n // lower-priority tiers see a higher reference and naturally defer.\n let injectedTier: CompressionTier | null = null;\n let injectedReason = \"\";\n // growth acts as the \"has accumulated since baseline\" signal; pending is the\n // \"there is enough compressible content\" signal. Both must hold for a\n // non-emergency injection. This keeps the first turn (growth 0) from firing\n // immediately even if a lot is compressible — it just establishes baseline.\n const growthReady = growthSinceReference >= growthFloor;\n if (!emergencyOverride && growthReady) {\n for (const tier of [1, 2, 3] as const) {\n if (!config.tiers.enabled && tier > 1) break;\n const info = tiers[tier];\n if (!info || info.pending < nudgeGrowthTokens) continue;\n const lastShown = state.nudge.lastShownByTier[tier] ?? 0;\n // Per-tier cadence: even with growth, a tier that fired recently waits\n // for its own cadence window. First time (lastShown===0) is always met.\n const cadenceMet = lastShown === 0 || tokenCount - lastShown >= growthFloor;\n if (!cadenceMet) continue;\n injectedTier = tier;\n injectedReason = tier === 1\n ? `T1 compressible ${info.pending} >= ${nudgeGrowthTokens}, growth ${growthSinceReference}, usage ${Math.round(usage * 100)}%`\n : `T${tier} distill ready: ${info.targetBlocks.length} tier-${tier - 1} blocks (${info.pending} tokens) >= ${nudgeGrowthTokens}, usage ${Math.round(usage * 100)}%`;\n break;\n }\n }\n\n const shouldInject = emergencyOverride || injectedTier !== null;\n\n let reason: string;\n if (emergencyOverride) {\n reason = `EMERGENCY: usage ${Math.round(usage * 100)}% >= ${Math.round(config.nudge.emergencyThresholdPct * 100)}%`;\n } else if (injectedTier !== null) {\n reason = injectedReason;\n } else {\n const tiersList = [1, 2, 3] as const;\n const eligible = tiersList.filter((t) => config.tiers.enabled || t === 1);\n const ready = eligible\n .filter((t) => (tiers[t]?.pending ?? 0) >= nudgeGrowthTokens)\n .map((t) => `T${t} ${tiers[t]!.pending}`);\n const readyHint = ready.length > 0 ? `, ready: ${ready.join(\", \")}` : \"\";\n const blocked = eligible\n .filter((t) => (tiers[t]?.pending ?? 0) >= nudgeGrowthTokens && (state.nudge.lastShownByTier[t] ?? 0) > 0 && tokenCount - (state.nudge.lastShownByTier[t] ?? 0) < growthFloor)\n .map((t) => `T${t} (cadence)`);\n const blockedHint = blocked.length > 0 ? `, blocked: ${blocked.join(\", \")}` : \"\";\n const maxPending = Math.max(0, ...Object.values(tiers).map((t) => t.pending));\n // Report the ACTUAL blocking condition, not a fixed template. A session\n // can have plenty to compress (pending >= threshold) but still not\n // inject because growth/floor/cadence isn't met — the old fixed\n // \"< threshold\" string lied in that case.\n const pendingShort = maxPending < nudgeGrowthTokens;\n const growthShort = growthSinceReference < growthFloor;\n const parts: string[] = [];\n if (pendingShort) parts.push(`max compressible ${maxPending} < threshold ${nudgeGrowthTokens}`);\n if (growthShort) parts.push(`growth ${growthSinceReference} < floor ${growthFloor}`);\n if (parts.length === 0) parts.push(`max compressible ${maxPending}, growth ${growthSinceReference}`);\n reason = `${parts.join(\"; \")}${readyHint}${blockedHint}`;\n }\n\n const ctxBreakdown = computeContextBreakdown(input.messages, tokenCount, growthSinceReference, countTokens);\n\n return {\n shouldInject,\n reason,\n compressibleRanges: rec?.recommendedRanges ?? [],\n protectedRanges: rec?.contextRanges.protected ?? [],\n tierTargetBlocks: injectedTier ? tiers[injectedTier]!.targetBlocks : [],\n contextUsage: usage,\n tier: injectedTier,\n breakdown: {\n usage,\n growth: growthSinceReference,\n growthReference,\n effectiveThreshold,\n nudgeGrowthTokens,\n growthFloor,\n hasPendingNudge: hasPendingNudge ? 1 : 0,\n emergencyOverride: emergencyOverride ? 1 : 0,\n pendingT1: tiers[1]!.pending,\n pendingT2: tiers[2]!.pending,\n pendingT3: tiers[3]!.pending,\n },\n contextBreakdown: ctxBreakdown,\n };\n}\n\nfunction computeContextBreakdown(messages: CoreMessage[], total: number, growth: number, countTokens: (t: string) => number): ContextBreakdown {\n const count = countTokens ?? ((t: string) => Math.ceil(t.length / 4));\n let system = 0, tool = 0, summaries = 0, code = 0, text = 0;\n for (const msg of messages) {\n const tokens = count(msg.text ?? \"\");\n if (msg.text?.startsWith(\"[Compressed conversation section]\")) {\n summaries += tokens;\n } else if (msg.contentType === \"tool-call\" || msg.contentType === \"tool-result\") {\n tool += tokens;\n } else if (msg.role === \"system\") {\n system += tokens;\n } else if (msg.text?.includes(\"```\")) {\n code += tokens;\n } else {\n text += tokens;\n }\n }\n return { system, tool, summaries, code, text, total, growth };\n}\n\nfunction cloneState(state: CompressionState): CompressionState {\n return {\n blocks: state.blocks.map((block) => ({\n ...block,\n directMessageIds: [...block.directMessageIds],\n effectiveMessageIds: [...block.effectiveMessageIds],\n directBlockIds: [...block.directBlockIds],\n })),\n messageRefs: {\n byRaw: { ...state.messageRefs.byRaw },\n byRef: { ...state.messageRefs.byRef },\n },\n nudge: { ...state.nudge, anchors: { ...state.nudge.anchors } },\n stats: { ...state.stats },\n nextBlockId: state.nextBlockId,\n nextRunId: state.nextRunId,\n };\n}\n\nfunction scoreRelevance(block: CompressionBlock, terms: string[]): number {\n const topic = (block.topic ?? \"\").toLowerCase();\n const summary = block.summary.toLowerCase();\n let score = 0;\n for (const term of terms) {\n const topicHits = countOccurrences(topic, term);\n if (topicHits > 0) score += Math.min(topicHits * 0.15, 0.45);\n const summaryHits = countOccurrences(summary, term);\n if (summaryHits > 0) score += Math.min(summaryHits * 0.04, 0.2);\n }\n return Math.min(score, 1);\n}\n\nfunction countOccurrences(haystack: string, needle: string): number {\n if (!haystack || !needle) return 0;\n let count = 0;\n let position = 0;\n while ((position = haystack.indexOf(needle, position)) !== -1) {\n count++;\n position += needle.length;\n }\n return count;\n}\n\nexport { createInitialState };\n","/**\n * Compression rule texts — VERBATIM copy from context-compress-algorithms (MIT, ours).\n * These were tuned over months of production use.\n *\n * DO NOT modify the wording — it is the result of extensive tuning.\n */\n\nexport const COMPRESS_PHILOSOPHY = `Compression Philosophy:\n- All compression serves the primary task, but be frugal.\n- Context capacity is precious. Save context by compressing consumed outputs, not by avoiding tools.\n- Compress by need, not by percentage.\n- Work from summaries, not raw tool outputs. All listed ranges (user prompts, tool outputs, code, logs, exploration, intermediate steps) should be compressed to summary format — the ONLY exceptions are protected content, content the current step is actively using, or critical content you cannot reconstruct.`;\n\nexport const HOW_TO_COMPRESS_RULES = `HOW TO COMPRESS\n\nWhen you call \\`compress\\`, the summary you write becomes the only record of the replaced conversation. Make it self-contained and complete: every user request, experiment purpose, and work task in the range must be accurately captured. A later reader (or you, after decompressing) should be able to continue the task WITHOUT needing the original.\n\nKEEP VERBATIM — never paraphrase or abbreviate these:\n- Full file paths with line numbers, directory prefix on every mention (\\`lib/hooks.ts:347\\`, \\`src/index.ts:12-18\\`, \\`gatenet_v3/model.py:45\\`). Never abbreviate to a bare filename (\\`hooks.ts\\`, \\`model.py\\`) — they are ambiguous and cannot be grepped or decompressed-to later.\n- Function, class, and type signatures (exact names, params, return types) AND critical code lines that encode logic — the line that IS the finding, not just the function name (e.g. \\`kv_keys += define_gate * a_key[i](emb)\\` is more useful than \"see model_kvnet.py\").\n- Error messages and stack traces (exact text — you need the literal string to grep for it later).\n- Key details from reports and analyses — not just the conclusion. Keep the comparison numbers and the mechanism, not \"X is worse\" alone (write \"1.76× PPL gap because KV store is static\", not \"KVNet underperforms\").\n- Decisions and their rationale (\"chose X over Y because Z\" — the \"because\" is load-bearing; without it the decision looks arbitrary).\n- Constraints discovered (\"must support Node 22\", \"no new dependencies\", \"AGENTS.md forbids \\`as any\\`\").\n- Exact values: versions, config keys, thresholds, magic numbers.\n- User intent — quote short user messages verbatim. When the message is too long to quote, preserve intent with extra care: do not change scope, constraints, priorities, acceptance criteria, or requested outcomes. Mark them clearly as past quotes (e.g., \"User said: ...\"), not as current directives. Losing these changes the task itself.\n- The user's overall goal and any changes to it — the big-picture objective plus how it evolved during the compressed range. Each summary must reflect the goal as it stood at the end of the range, including pivots (e.g., \"initially: fix bug X → pivoted to: refactor module Y after discovering root cause\"). Losing the goal or its evolution makes all subsequent work appear unmotivated.\n- Purpose behind each significant action — preserve not just what was done but why: the hypothesis behind each experiment, the question behind each exploration, the task goal behind each work action. Without purpose, the summary reads as disconnected technical steps with no through-line.\n- Open questions and unresolved TODOs — losing these changes what work appears to remain.\n- Message refs of key anchors (\\`m00420\\`, \\`m00510–m00520\\`) — they let you or a later reader jump back via decompress to the exact original.\n\nDROP — extract the signal, discard the vessel:\n- Verbose logs (build/test/\\`npm\\` output) once you have captured the error line or the result.\n- Duplicate file reads once the needed content is recorded.\n- Consumed exploration — search hits, agent return values, successful tool outputs — once you have extracted the facts you need (same rule as dead-ends, but nothing went wrong; the content is simply spent).\n- Dead-end exploration — but PRESERVE the lesson in one line: \"tried X, failed because Y\".\n- Back-and-forth discussion and self-corrections once the final position is captured (keep the outcome, drop the journey to it).\n- Repeated status checks (\\`git status\\`, \\`ls\\`) once state is known.\n\nFor each significant item you DROP (scripts, reports, large analyses, long tool outputs), add a one-line CONTENT description of what it covers — not where it lives. Bad: \"probe script at /path/probe_kvnet.py\". Good: \"probe_kvnet.py: tests n-gram baseline, generation quality, long-range dependency, position sensitivity, op pipeline, QUERY attention.\" This lets a later decompress target the right block by relevance, not by guessing locations.\n\nPRIORITY — when the summary must be compact, preserve in this order:\n1. User's overall goal, goal evolution, intent, and hard constraints (losing these changes the task).\n2. Decisions and rationale.\n3. Exact technical artifacts: paths, signatures, errors, values.\n4. Conclusions and key findings.\n5. Lessons learned: what failed and why.\n\nWrite dense, scannable bullets — not narrative prose. If the range spans distinct concerns (request → findings → decision), group bullets under short thematic headers so a reader can scan to the part they need. Every line must earn its place. Do not mimic the style of existing summaries in context; follow these rules.`;\n\nexport const TIER2_DISTILL_RULES = `TIER 2 COMPRESSION — DISTILLATION\n\nYou are compressing historical summaries (not raw conversation). These summaries have already captured the details. Your job is to DISTILL them: extract only what matters for future work, discard the process.\n\nKEEP — these are the only things that survive distillation:\n- Decisions and their rationale (\"chose X over Y because Z\" — the \"because\" is load-bearing).\n- Final outcomes: version numbers shipped, PR numbers merged/closed, bugs fixed or deferred.\n- Key lessons: what failed and why (\"tried X, failed because Y\"). These prevent repeating mistakes.\n- Critical constraints discovered (\"must support Node 22\", \"AGENTS.md forbids as any\").\n- Design decisions with architectural impact (\"chose compress-as-anchor over synthetic messages because prefix cache\").\n- Whether content is OBSOLETE or SUPERSEDED — mark with one line: \"[SUPERSEDED by PR #NNN]\" or \"[OBSOLETE: deleted in vX.Y.Z]\". Do NOT keep the obsolete content's details — just the marker and reason.\n- Function/class/type names and module paths that are the SUBJECT of the work — e.g., \"fixed filterCompressedRanges in prune.ts\", \"added SessionStateRegistry in state.ts\". Not exact line numbers or full signatures — just enough to LOCATE the code without searching.\n- Exploration findings: if a block was exploratory with no decision, keep the CONCLUSION in one line (\"explored X, not viable because Y\"). Do not keep the exploration process.\n\nDROP — these were useful during the work but are no longer needed:\n- Exact line numbers, diffs, verbose function signatures, full code listings.\n- Build/deploy process details, test execution steps.\n- Review process details (who reviewed, what rounds, test counts).\n- Verbose logs, command output, intermediate debugging steps.\n\nFORMAT:\n- Start each distilled block with a source header line:\n \\`Source: bN+bM+... (XK→YK tok, Zx). [original topic]\\`\n Example: \\`Source: b5+b7 (56K+44K→268 tok, 375x). [Tool-result recap + publish]\\`\n- 3-5 bullet points per source block, each a self-contained fact.\n- Dense, scannable — no narrative prose.\n- Start with the outcome, not the process: \"v1.13.0 shipped (7 PRs bundled)\" not \"implemented 7 PRs then reviewed then merged\".\n- Cross-block synthesis: if multiple source blocks cover the same topic (same PR, same feature, same bug), MERGE them into a single group of bullets. Do not repeat the same fact from different blocks — keep it once under the most relevant source header.\n\nSIZE TARGET: 50-150 tokens per source block (excluding the header). If you can't fit it in 150 tokens, you're keeping too much process. If a block has nothing worth keeping (pure noise), output just the header followed by \"[no actionable content].\"`;\n\nexport const TIER3_CONDENSE_RULES = `TIER 3 COMPRESSION — ULTRA-CONDENSATION\n\nYou are compressing distilled summaries (Tier 2) into ultra-condensed facts (Tier 3). The distilled summaries already contain only decisions and outcomes. Your job is to reduce them to bare factual references.\n\nPRIORITY — when a source block has more facts than the size target allows, keep in this order:\n1. Shipped outcomes (versions released, PRs merged) — these are permanent record.\n2. Open work (PRs/issues still pending) — these may need follow-up.\n3. Key decisions with architectural impact (\"chose X over Y because Z\").\n4. Critical constraints (\"must support Node 22\").\nDrop everything else. Tier 3 is a lookup index, not a knowledge base.\n\nFORMAT:\n- Start with a source header line:\n \\`Source: bN+bM+... (XK→YK tok, Zx). [original topic]\\`\n- Output 1-3 facts per source block. Each fact is a single line: subject + outcome.\n- No explanations, no rationale, no process — just the fact.\n- Format: \"[PR/Issue/Version] — [outcome in ≤8 words]\"\n- Merge related facts from different source blocks if they concern the same topic.\n\nEXAMPLES:\n- \"v1.13.0 shipped — quality gate + GC fix (7 PRs)\"\n- \"PR #196 merged — preserve-first-user (supersedes #169)\"\n- \"Bug 1214 fixed — compress consumed all user messages\"\n- \"Chose compress-as-anchor — prefix cache benefit over synthetic injection\"\n- \"Constraint: AGENTS.md forbids as any — never suppress types\"\n\nDROP:\n- Multi-sentence context. If a fact needs >1 sentence, it's too detailed for Tier 3.\n- Lessons learned (\"tried X, failed because Y\") — drop UNLESS the failure is likely to recur and the block is <30 days old.\n- Design rationale details — keep the decision, drop the \"because\" unless it's a critical constraint.\n- Anything marked [OBSOLETE] or [SUPERSEDED] — drop entirely, note \"[N blocks obsolete]\" in the summary.\n\nSIZE TARGET: 30-60 tokens per source block (including header). For a batch of N source blocks, total output ≈ N × 40 tokens. If a source block has only one trivial fact, output just the header + one line.`;\n","import type { NudgeDecision, CompressibleRange, ProtectedRange, ContextBreakdown, CompressionBlock } from \"./types.js\";\nimport { COMPRESS_PHILOSOPHY, HOW_TO_COMPRESS_RULES, TIER2_DISTILL_RULES, TIER3_CONDENSE_RULES } from \"./compression-rules.js\";\n\nexport type NudgeVoice = \"gentle\" | \"emergency\";\n\nexport interface RenderedNudge {\n voice: NudgeVoice;\n text: string;\n}\n\nconst EFFICIENCY_NOTE = `This is an efficiency nudge to compress early and keep context lean — not an overflow warning. A separate, stronger alert will appear if the context is actually full.\\n\\n${COMPRESS_PHILOSOPHY}`;\n\nconst EMERGENCY_HEADER = `⚠️ Context limit reached — compress now. Prioritize consumed tool outputs.\\n\\n${COMPRESS_PHILOSOPHY}`;\n\nfunction formatK(n: number): string {\n if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;\n return `${n}`;\n}\n\nfunction formatBreakdown(bd?: ContextBreakdown): string {\n if (!bd) return \"\";\n const parts: string[] = [];\n if (bd.system > 0) parts.push(`${formatK(bd.system)} system`);\n if (bd.tool > 0) parts.push(`${formatK(bd.tool)} tool`);\n if (bd.summaries > 0) parts.push(`${formatK(bd.summaries)} summaries`);\n if (bd.code > 0) parts.push(`${formatK(bd.code)} code`);\n if (bd.text > 0) parts.push(`${formatK(bd.text)} text`);\n const growth = bd.growth > 0 ? `\\n+${formatK(bd.growth)} since last nudge` : \"\";\n return `Context breakdown: ${parts.join(\" | \")}${growth}`;\n}\n\n\n\nfunction formatTierTargetBlocks(blocks: CompressionBlock[]): string {\n if (blocks.length === 0) {\n return \"Target blocks: (none — no tier blocks found)\";\n }\n const lines = blocks.map((b) => {\n const summaryTokens = Math.ceil((b.summary ?? \"\").length / 4);\n const topic = b.topic ? ` \"${b.topic}\"` : \"\";\n return ` ${b.blockId} ${b.effectiveMessageIds.length} msgs ${formatK(b.compressedTokens)}→${formatK(summaryTokens)}${topic}`;\n });\n return `Target ${blocks[0]!.tier === 1 ? \"tier-1\" : \"tier-2\"} blocks to distill (${blocks.length}):\\n${lines.join(\"\\n\")}`;\n}\n\nexport function formatRanges(compressible: CompressibleRange[], protectedRanges: ProtectedRange[]): string {\n if (compressible.length === 0 && protectedRanges.length === 0) {\n return \"[No specific ranges detected — compress any consumed content.]\";\n }\n\n // Merge compressible + protected into a single oldest-first list, mirroring\n // opencode-acp's formatCompressibleRanges. Splitting them into two sections\n // lost the time order and hid overlaps; a range can be partly compressible\n // and partly protected, which only the merged view shows correctly.\n interface Merged {\n startRef: string; endRef: string; startNum: number; endNum: number;\n count: number; tokens: number;\n compressibleTokens: number; compressibleCount: number;\n protectedTokens: number; protectedCount: number; protectedTools: string[];\n toolPct: number; textPct: number; dangerous: boolean;\n }\n const refNum = (ref: string): number => {\n const m = ref.match(/\\d+/);\n return m ? parseInt(m[0], 10) : 0;\n };\n const entries: Merged[] = [];\n for (const r of compressible) {\n entries.push({\n startRef: r.startRef, endRef: r.endRef, startNum: refNum(r.startRef), endNum: refNum(r.endRef),\n count: r.count, tokens: r.tokens, toolPct: r.toolPct, textPct: r.textPct,\n compressibleTokens: r.tokens, compressibleCount: r.count,\n protectedTokens: 0, protectedCount: 0, protectedTools: [], dangerous: r.dangerous ?? false,\n });\n }\n for (const r of protectedRanges) {\n entries.push({\n startRef: r.startRef, endRef: r.endRef, startNum: refNum(r.startRef), endNum: refNum(r.endRef),\n count: r.count, tokens: r.tokens, toolPct: 0, textPct: 0,\n compressibleTokens: 0, compressibleCount: 0,\n protectedTokens: r.tokens, protectedCount: r.count, protectedTools: [...r.tools], dangerous: false,\n });\n }\n entries.sort((a, b) => a.startNum - b.startNum);\n // Merge adjacent/overlapping ranges (gap ≤ 1 ref).\n const merged: Merged[] = [];\n for (const e of entries) {\n const last = merged[merged.length - 1];\n if (last && e.startNum <= last.endNum + 1) {\n last.endRef = e.endRef;\n last.endNum = Math.max(last.endNum, e.endNum);\n last.count += e.count;\n last.tokens += e.tokens;\n last.compressibleTokens += e.compressibleTokens;\n last.compressibleCount += e.compressibleCount;\n last.protectedTokens += e.protectedTokens;\n last.protectedCount += e.protectedCount;\n if (e.dangerous) last.dangerous = true;\n for (const t of e.protectedTools) {\n if (!last.protectedTools.includes(t)) last.protectedTools.push(t);\n }\n } else {\n merged.push({ ...e });\n }\n }\n const lines = merged.map((e) => {\n const suffix = e.dangerous && e.compressibleTokens > 0 ? \" ⚠️ NOT recommended unless you are certain.\" : \"\";\n if (e.protectedTokens > 0 && e.compressibleTokens === 0) {\n return ` ${e.startRef}–${e.endRef} ${e.count} msgs ${formatK(e.tokens)} [PROTECTED: ${e.protectedTools.join(\", \")} — not compressible]${suffix}`;\n }\n if (e.protectedTokens > 0 && e.compressibleTokens > 0) {\n return ` ${e.startRef}–${e.endRef} ${e.count} msgs ${formatK(e.tokens)} [${formatK(e.compressibleTokens)} compressible | ${formatK(e.protectedTokens)} protected: ${e.protectedTools.join(\", \")}]${suffix}`;\n }\n return ` ${e.startRef}–${e.endRef} ${e.count} msgs ${formatK(e.tokens)} [tool ${e.toolPct}% | text ${e.textPct}%]${suffix}`;\n });\n return `Compressible ranges (${merged.length}, oldest first):\\n${lines.join(\"\\n\")}`;\n}\n\nexport function renderNudgeText(decision: NudgeDecision): RenderedNudge {\n const breakdownStr = formatBreakdown(decision.contextBreakdown);\n const rangesStr = formatRanges(decision.compressibleRanges, decision.protectedRanges ?? []);\n\n if (decision.tier !== null && decision.tier >= 2) {\n const isT2 = decision.tier === 2;\n const targets = decision.tierTargetBlocks ?? [];\n const blockList = formatTierTargetBlocks(targets);\n const startId = targets[0]?.blockId ?? \"b1\";\n const endId = targets[targets.length - 1]?.blockId ?? \"b5\";\n return {\n voice: \"gentle\",\n text: [\n EFFICIENCY_NOTE,\n \"\",\n breakdownStr,\n \"\",\n `[TIER ${decision.tier} ${isT2 ? \"DISTILLATION\" : \"CONDENSATION\"} TRIGGER]`,\n isT2\n ? `Your tier-1 compression summaries have accumulated. Distill them into a single denser tier-2 summary. Use block IDs as boundaries (startId and endId as bN). Any raw (uncompressed) messages sitting between the boundary blocks are absorbed into the tier-2 block as well — apply HOW TO COMPRESS to those raw messages and the TIER 2 distillation rules to the existing summaries, so the whole span is covered and nothing is lost.`\n : `Your tier-2 compression summaries have accumulated. Condense them further into a tier-3 ultra-condensed summary. Use block IDs as boundaries (startId and endId as bN). Any raw (uncompressed) messages sitting between the boundary blocks are absorbed into the tier-3 block as well — apply HOW TO COMPRESS to those raw messages and the TIER 3 condensation rules to the existing summaries, so the whole span is covered and nothing is lost.`,\n blockList,\n `Example: compress({ content: [{ startId: \"${startId}\", endId: \"${endId}\", summary: \"...\" }] })`,\n \"\",\n HOW_TO_COMPRESS_RULES,\n \"\",\n isT2 ? TIER2_DISTILL_RULES : TIER3_CONDENSE_RULES,\n ].join(\"\\n\"),\n };\n }\n\n const isEmergency = !!decision.breakdown?.emergencyOverride;\n\n if (isEmergency) {\n return {\n voice: \"emergency\",\n text: [\n EMERGENCY_HEADER,\n \"\",\n breakdownStr,\n \"\",\n HOW_TO_COMPRESS_RULES,\n \"\",\n `{ \"topic\": \"...\", \"content\": [{ \"startId\": \"<ID>\", \"endId\": \"<ID>\", \"summary\": \"...\" }] }`,\n \"Only use IDs from visible messages above. Compress older work first.\",\n \"\",\n rangesStr,\n ].join(\"\\n\"),\n };\n }\n\n return {\n voice: \"gentle\",\n text: [\n EFFICIENCY_NOTE,\n \"\",\n breakdownStr,\n \"\",\n HOW_TO_COMPRESS_RULES,\n \"\",\n rangesStr,\n \"\",\n `💡 Compress all ranges in one call (pass multiple content entries: \\`content: [{...}, {...}]\\`).`,\n ].join(\"\\n\"),\n };\n}\n","import { SUMMARY_HEADER } from \"./prune.js\";\nimport type { CompressionBlock, CompressionState, CoreMessage } from \"./types.js\";\n\nexport function parseBlockIdArg(arg: string): string | null {\n const normalized = arg.trim().toLowerCase();\n const refMatch = /^b0*(\\d+)$/.exec(normalized);\n if (refMatch && refMatch[1] !== undefined) return `b${refMatch[1]}`;\n const numMatch = /^(\\d+)$/.exec(normalized);\n if (numMatch && numMatch[1] !== undefined) return `b${numMatch[1]}`;\n return null;\n}\n\nexport function findBlocksOverlappingMessages(\n state: CompressionState,\n messageIds: Set<string>,\n): CompressionBlock[] {\n if (messageIds.size === 0) return [];\n const matched: CompressionBlock[] = [];\n for (const block of state.blocks) {\n if (!block.active) continue;\n if (block.effectiveMessageIds.some((id) => messageIds.has(id))) {\n matched.push(block);\n }\n }\n return matched.sort((a, b) => numericPart(a.blockId) - numericPart(b.blockId));\n}\n\nexport function findActiveAncestor(state: CompressionState, blockId: string): string | null {\n const start = state.blocks.find((b) => b.blockId === blockId);\n if (!start) return null;\n const queue: string[] = [...start.directBlockIds];\n const visited = new Set<string>();\n while (queue.length > 0) {\n const currentId = queue.shift()!;\n if (visited.has(currentId)) continue;\n visited.add(currentId);\n const current = state.blocks.find((b) => b.blockId === currentId);\n if (!current) continue;\n if (current.active) return current.blockId;\n for (const ancestorId of current.directBlockIds) {\n if (!visited.has(ancestorId)) queue.push(ancestorId);\n }\n }\n return null;\n}\n\nexport interface DeactivateOptions {\n deep?: boolean;\n}\n\nexport function deactivateBlock(\n state: CompressionState,\n blockIds: string[],\n options: DeactivateOptions = {},\n): CompressionState {\n const targets = new Set(blockIds);\n\n const updated = state.blocks.map((block) => {\n if (!targets.has(block.blockId) || !block.active) return block;\n return {\n ...block,\n active: false,\n durationMs: block.durationMs,\n createdAt: block.createdAt,\n };\n });\n\n let final = updated;\n if (options.deep) {\n const visited = new Set<string>();\n const queue: string[] = [];\n for (const id of blockIds) {\n const block = updated.find((b) => b.blockId === id);\n if (block) queue.push(...block.directBlockIds);\n }\n while (queue.length > 0) {\n const id = queue.shift()!;\n if (visited.has(id)) continue;\n visited.add(id);\n final = final.map((block) => {\n if (block.blockId !== id) return block;\n queue.push(...block.directBlockIds);\n return block.active ? { ...block, active: false } : block;\n });\n }\n }\n\n return { ...state, blocks: final };\n}\n\nexport interface RestoredPreviewResult {\n preview: string;\n restoredCount: number;\n}\n\nexport function buildRestoredContentPreview(\n messages: CoreMessage[],\n beforeActiveMessageIds: Set<string>,\n state: CompressionState,\n): RestoredPreviewResult {\n const restored: CoreMessage[] = [];\n for (const message of messages) {\n if (!beforeActiveMessageIds.has(message.id)) continue;\n const stillCovered = state.blocks.some(\n (b) => b.active && b.effectiveMessageIds.includes(message.id),\n );\n if (!stillCovered) restored.push(message);\n }\n\n if (restored.length === 0) return { preview: \"\", restoredCount: 0 };\n\n const lines: string[] = [];\n let totalLength = 0;\n const MAX_PREVIEW = 2000;\n const MAX_PER_MESSAGE = 200;\n\n for (const message of restored) {\n if (totalLength >= MAX_PREVIEW) break;\n const text = message.text ?? \"\";\n const truncated = text.length > MAX_PER_MESSAGE ? text.slice(0, MAX_PER_MESSAGE) + \"...\" : text;\n const label =\n message.toolName && message.contentType !== \"text\"\n ? `${message.toolName}: ${truncated}`\n : `[${message.role}] ${truncated}`;\n lines.push(label);\n totalLength += label.length + 1;\n }\n\n return { preview: lines.join(\"\\n\"), restoredCount: restored.length };\n}\n\nexport interface CollectedContentResult {\n /** Rendered, human-readable content string (empty when count is 0). */\n text: string;\n /** Number of items rendered: direct messages + nested summaries (full=false) or all messages (full=true). */\n count: number;\n}\n\nexport interface CollectContentOptions {\n /** When true, recurse through all nested tiers to original messages. Default: false (one tier up — nested active children stay folded, their summaries shown). */\n full?: boolean;\n}\n\n/**\n * Collect a block's content as a readable string WITHOUT modifying state.\n *\n * This is the cache-safe decompress primitive: the block stays compressed\n * (folded), its summary stays in place, and the full content is returned as\n * text for the caller to surface (e.g. as a tool result appended to the\n * conversation). Unlike deactivateBlock + prune, this does not mutate the\n * message-array prefix, so prompt cache is preserved.\n *\n * full=false (default): one tier up. Nested ACTIVE children of this block\n * stay folded; their summaries are rendered in place of their messages.\n * The block's own direct messages (not covered by any active child) are\n * rendered in full.\n * full=true: recurse through all nested tiers; every effective message is\n * rendered in full.\n *\n * Returns { text: \"\", count: 0 } when the block covers no messages.\n */\nexport function collectBlockContent(\n state: CompressionState,\n block: CompressionBlock,\n messages: CoreMessage[],\n options: CollectContentOptions = {},\n): CollectedContentResult {\n const full = options.full ?? false;\n const targetIds = new Set(block.effectiveMessageIds);\n\n if (full) {\n const msgs = messages.filter((m) => targetIds.has(m.id));\n if (msgs.length === 0) return { text: \"\", count: 0 };\n return { text: msgs.map(formatMessage).join(\"\\n\\n\"), count: msgs.length };\n }\n\n // One tier up: messages covered by nested ACTIVE children stay folded\n // (their summaries shown); the block's own direct messages shown in full.\n const nestedChildren: CompressionBlock[] = [];\n const nestedCovered = new Set<string>();\n for (const childId of block.directBlockIds) {\n const child = state.blocks.find((b) => b.blockId === childId);\n if (!child?.active) continue;\n nestedChildren.push(child);\n for (const id of child.effectiveMessageIds) nestedCovered.add(id);\n }\n\n const parts: string[] = [];\n for (const child of nestedChildren) {\n const label = child.topic ? `${child.blockId}: ${child.topic}` : child.blockId;\n parts.push(`${SUMMARY_HEADER} — ${label}\\n${child.summary}`);\n }\n\n let directCount = 0;\n for (const m of messages) {\n if (targetIds.has(m.id) && !nestedCovered.has(m.id)) {\n parts.push(formatMessage(m));\n directCount++;\n }\n }\n\n const count = directCount + nestedChildren.length;\n if (count === 0) return { text: \"\", count: 0 };\n return { text: parts.join(\"\\n\\n\"), count };\n}\n\nfunction formatMessage(message: CoreMessage): string {\n const text = message.text ?? \"\";\n if (message.toolName && message.contentType !== \"text\") {\n return `[${message.role} • ${message.toolName}]\\n${text}`;\n }\n return `[${message.role}]\\n${text}`;\n}\n\nfunction numericPart(blockId: string): number {\n const match = /^b(\\d+)$/.exec(blockId);\n return match && match[1] !== undefined ? Number(match[1]) : 0;\n}\n","import { refForRaw } from \"./refs.js\";\nimport type { CompressionBlock, CompressionState, CoreMessage } from \"./types.js\";\n\nfunction formatTokens(n: number): string {\n if (!Number.isFinite(n) || n <= 0) return \"0\";\n return n >= 1000 ? `${(n / 1000).toFixed(1)}K` : String(n);\n}\n\nfunction pct(n: number, total: number): number {\n if (n <= 0 || total <= 0) return 0;\n return Math.max(1, Math.round((n / total) * 100));\n}\n\nfunction numericPart(blockId: string): number {\n const match = /^b(\\d+)$/.exec(blockId);\n return match && match[1] !== undefined ? Number(match[1]) : 0;\n}\n\nfunction summaryTokensOf(block: CompressionBlock, countTokens: (t: string) => number): number {\n return countTokens(block.summary);\n}\n\nfunction effectiveCompressedTokens(\n block: CompressionBlock,\n _state: CompressionState,\n _countTokens: (t: string) => number,\n): number {\n // block.compressedTokens already records the full input token count of the\n // operation that created this block: for a tier-1 block that is the raw\n // messages; for a tier-2 block it is the tier-1 summaries + the new\n // messages it spans. Recursing into directBlockIds and summing children's\n // compressedTokens double-counts the consumed children, so we return the\n // block's own value directly. (The previous recursion inflated tier-2+\n // \"original\" figures and mis-ordered the status report.)\n return block.compressedTokens;\n}\n\nfunction tierLabel(block: CompressionBlock): string {\n return `T${block.tier}`;\n}\n\nfunction tierBreakdown(\n blocks: CompressionBlock[],\n countTokens: (t: string) => number,\n): string | null {\n const tierTokens: Record<number, number> = {};\n for (const block of blocks) {\n tierTokens[block.tier] = (tierTokens[block.tier] ?? 0) + summaryTokensOf(block, countTokens);\n }\n const tiers = Object.keys(tierTokens).map(Number);\n if (tiers.length <= 1) return null;\n const parts: string[] = [];\n for (const tier of [1, 2, 3]) {\n if (tierTokens[tier]) parts.push(`T${tier}: ${formatTokens(tierTokens[tier])}`);\n }\n return parts.join(\" | \");\n}\n\ninterface VisibleMessageInfo {\n ref: string;\n tokens: number;\n tool: string;\n index: number;\n}\n\nfunction collectVisible(\n messages: CoreMessage[],\n state: CompressionState,\n countTokens: (t: string) => number,\n): { visible: VisibleMessageInfo[]; summaryTokens: number } {\n const coveredIds = new Set<string>();\n for (const block of state.blocks) {\n if (!block.active) continue;\n for (const id of block.effectiveMessageIds) coveredIds.add(id);\n }\n let summaryTokens = 0;\n for (const block of state.blocks) {\n if (block.active) summaryTokens += summaryTokensOf(block, countTokens);\n }\n const visible: VisibleMessageInfo[] = [];\n messages.forEach((message, index) => {\n if (coveredIds.has(message.id)) return;\n const ref = refForRaw(state.messageRefs, message.id);\n if (!ref) return;\n const tokens = countTokens(message.text ?? \"\");\n const tool = message.toolName ?? \"text\";\n if (tokens > 0) visible.push({ ref, tokens, tool, index });\n });\n return { visible, summaryTokens };\n}\n\nexport interface StatusReportOptions {\n scope?: \"compressed\" | \"uncompressed\";\n view?: \"ranges\" | \"messages\";\n tool?: string;\n sort?: \"size\" | \"time\" | \"tool\" | \"age\";\n limit?: number;\n}\n\nexport function buildStatusReport(\n state: CompressionState,\n messages: CoreMessage[],\n countTokens: (t: string) => number,\n options: StatusReportOptions = {},\n): string {\n const scope = options.scope;\n const view = options.view ?? \"ranges\";\n const toolFilter = options.tool;\n const sort = options.sort ?? \"size\";\n const limit = options.limit ?? 30;\n\n const activeBlocks = state.blocks\n .filter((b) => b.active)\n .sort((a, b) => numericPart(a.blockId) - numericPart(b.blockId));\n\n if (scope === \"compressed\") {\n return renderCompressedDrilldown(activeBlocks, state, sort, limit, countTokens);\n }\n\n const { visible, summaryTokens } = collectVisible(messages, state, countTokens);\n\n if (scope === \"uncompressed\") {\n if (view === \"messages\") {\n return renderMessageDrilldown(visible, toolFilter, sort, limit);\n }\n return renderUncompressedRanges(visible);\n }\n\n return renderOverview(visible, summaryTokens, activeBlocks, state, countTokens, limit);\n}\n\nfunction renderOverview(\n visible: VisibleMessageInfo[],\n summaryTokens: number,\n blocks: CompressionBlock[],\n state: CompressionState,\n countTokens: (t: string) => number,\n limit: number,\n): string {\n const lines: string[] = [];\n const toolTypeMap = new Map<string, number>();\n for (const message of visible) {\n toolTypeMap.set(message.tool, (toolTypeMap.get(message.tool) ?? 0) + message.tokens);\n }\n const topTool = [...toolTypeMap.entries()].sort((a, b) => b[1] - a[1])[0]?.[0];\n\n const totalTool = visible\n .filter((m) => m.tool !== \"text\")\n .reduce((sum, m) => sum + m.tokens, 0);\n const totalText = visible\n .filter((m) => m.tool === \"text\")\n .reduce((sum, m) => sum + m.tokens, 0);\n const total = summaryTokens + totalTool + totalText;\n\n lines.push(\"CONTEXT BREAKDOWN\");\n lines.push(\n ` ${formatTokens(totalTool)} tool (${pct(totalTool, total)}%) | ${formatTokens(totalText)} text (${pct(totalText, total)}%) | ${formatTokens(summaryTokens)} summaries (${pct(summaryTokens, total)}%)`,\n );\n const topTypes = [...toolTypeMap.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 3);\n if (topTypes.length > 0) {\n lines.push(` Top tools: ${topTypes.map(([t, n]) => `${t} (${pct(n, total)}%)`).join(\", \")}`);\n }\n\n lines.push(\"\");\n if (blocks.length === 0) {\n lines.push(\"COMPRESSED BLOCKS\");\n lines.push(\" No compressed blocks.\");\n } else {\n const totalSummary = blocks.reduce((s, b) => s + summaryTokensOf(b, countTokens), 0);\n const totalEffective = blocks.reduce(\n (s, b) => s + effectiveCompressedTokens(b, state, countTokens),\n 0,\n );\n lines.push(\n `COMPRESSED BLOCKS — ${blocks.length} active (${formatTokens(totalSummary)} summary, ${formatTokens(totalEffective)} original)`,\n );\n const breakdown = tierBreakdown(blocks, countTokens);\n if (breakdown) lines.push(` Tier usage: ${breakdown}`);\n lines.push(\"\");\n const sorted = [...blocks].sort(\n (a, b) =>\n effectiveCompressedTokens(b, state, countTokens) -\n effectiveCompressedTokens(a, state, countTokens) ||\n b.createdAt - a.createdAt,\n );\n for (const block of sorted.slice(0, limit)) {\n const topic = block.topic ?? \"(no topic)\";\n const eff = effectiveCompressedTokens(block, state, countTokens);\n lines.push(\n ` ${block.blockId} (${tierLabel(block)}) ${formatTokens(eff)}→${formatTokens(summaryTokensOf(block, countTokens))} ${block.effectiveMessageIds.length} msgs \"${topic}\"`,\n );\n }\n }\n\n lines.push(\"\");\n lines.push(\n `Tip: buildStatusReport({scope:\"uncompressed\", view:\"messages\", tool:\"${topTool ?? \"bash\"}\"}) for per-message listing`,\n );\n return lines.join(\"\\n\");\n}\n\nfunction renderUncompressedRanges(visible: VisibleMessageInfo[]): string {\n const lines: string[] = [];\n const totalTokens = visible.reduce((s, m) => s + m.tokens, 0);\n lines.push(`UNCOMPRESSED — ${formatTokens(totalTokens)} | ${visible.length} visible messages`);\n lines.push(\"\");\n if (visible.length === 0) {\n lines.push(\" (no uncompressed messages)\");\n return lines.join(\"\\n\");\n }\n // Merge consecutive messages into ranges (by numeric ref), aggregating\n // token counts and dominant tool so the view reads as blocks, not a\n // per-message firehose — mirroring the Compressible Ranges output.\n interface Merged { startRef: string; endRef: string; startNum: number; count: number; tokens: number; tool: string; }\n const refNum = (ref: string): number => {\n const m = ref.match(/\\d+/);\n return m ? parseInt(m[0], 10) : 0;\n };\n const merged: Merged[] = [];\n for (const m of visible) {\n const num = refNum(m.ref);\n const last = merged[merged.length - 1];\n if (last && num === last.startNum + last.count) {\n last.endRef = m.ref;\n last.count += 1;\n last.tokens += m.tokens;\n } else {\n merged.push({ startRef: m.ref, endRef: m.ref, startNum: num, count: 1, tokens: m.tokens, tool: m.tool });\n }\n }\n for (const r of merged.slice(0, 30)) {\n const range = r.count === 1 ? r.startRef : `${r.startRef}–${r.endRef}`;\n lines.push(` ${range} (${r.count} msgs, ${formatTokens(r.tokens)}${r.count > 1 ? ` (${Math.round(r.tokens / r.count)}/msg)` : \"\"}) ${r.tool}`);\n }\n if (merged.length > 30) {\n lines.push(` ... and ${merged.length - 30} more ranges`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction renderMessageDrilldown(\n visible: VisibleMessageInfo[],\n toolFilter: string | undefined,\n sort: string,\n limit: number,\n): string {\n let filtered = visible;\n if (toolFilter) filtered = filtered.filter((m) => m.tool === toolFilter);\n\n if (sort === \"time\") filtered.sort((a, b) => a.index - b.index);\n else if (sort === \"tool\") filtered.sort((a, b) => a.tool.localeCompare(b.tool) || b.tokens - a.tokens);\n else filtered.sort((a, b) => b.tokens - a.tokens);\n\n const totalTokens = filtered.reduce((s, m) => s + m.tokens, 0);\n const allTokens = visible.reduce((s, m) => s + m.tokens, 0);\n const header = toolFilter\n ? `UNCOMPRESSED — ${toolFilter}: ${formatTokens(totalTokens)} | ${filtered.length} msgs | ${pct(totalTokens, allTokens)}% of visible`\n : `UNCOMPRESSED — ${formatTokens(totalTokens)} | ${filtered.length} msgs`;\n const lines = [header, `Sorted by ${sort}`, \"\"];\n const shown = filtered.slice(0, limit);\n for (const message of shown) {\n lines.push(` ${message.ref} (${formatTokens(message.tokens)}) ${message.tool}`);\n }\n if (filtered.length > shown.length) {\n lines.push(\"\");\n lines.push(`${shown.length} of ${filtered.length} shown.`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction renderCompressedDrilldown(\n blocks: CompressionBlock[],\n state: CompressionState,\n sort: string,\n limit: number,\n countTokens: (t: string) => number,\n): string {\n let sorted = [...blocks];\n if (sort === \"time\") sorted.sort((a, b) => a.createdAt - b.createdAt);\n else if (sort === \"age\") sorted.sort((a, b) => b.survivedCount - a.survivedCount);\n else\n sorted.sort(\n (a, b) =>\n effectiveCompressedTokens(b, state, countTokens) -\n effectiveCompressedTokens(a, state, countTokens) ||\n b.createdAt - a.createdAt,\n );\n\n const totalSummary = sorted.reduce((s, b) => s + summaryTokensOf(b, countTokens), 0);\n const totalEffective = sorted.reduce(\n (s, b) => s + effectiveCompressedTokens(b, state, countTokens),\n 0,\n );\n const lines = [\n `COMPRESSED — ${sorted.length} blocks | ${formatTokens(totalEffective)} original → ${formatTokens(totalSummary)} summary`,\n ];\n const breakdown = tierBreakdown(sorted, countTokens);\n if (breakdown) lines.push(`Tier usage: ${breakdown}`);\n lines.push(\"\");\n const shown = sorted.slice(0, limit);\n for (const block of shown) {\n const nested = block.directBlockIds.length > 0 ? ` nested=[${block.directBlockIds.join(\",\")}]` : \"\";\n const topic = block.topic ?? \"(no topic)\";\n const eff = effectiveCompressedTokens(block, state, countTokens);\n lines.push(\n ` ${block.blockId} (${tierLabel(block)}) ${formatTokens(eff)}→${formatTokens(summaryTokensOf(block, countTokens))} ${block.effectiveMessageIds.length} msgs age=${block.survivedCount} ${block.generation}${nested}`,\n );\n lines.push(` \"${topic}\"`);\n }\n if (sorted.length > shown.length) {\n lines.push(\"\");\n lines.push(`${shown.length} of ${sorted.length} shown.`);\n }\n return lines.join(\"\\n\");\n}\n\nexport function buildRecap(\n state: CompressionState,\n blockId?: string,\n): string {\n const activeBlocks = state.blocks\n .filter((b) => b.active)\n .sort((a, b) => numericPart(a.blockId) - numericPart(b.blockId));\n\n if (blockId !== undefined) {\n const block = state.blocks.find((b) => b.blockId === blockId);\n if (!block) {\n const activeList = activeBlocks.map((b) => b.blockId).join(\", \");\n return `Block ${blockId} not found. Active blocks: ${activeList}`;\n }\n if (!block.active) {\n return `Block ${blockId} is inactive (deactivated by nested compression).`;\n }\n const range = `${block.effectiveMessageIds.length} messages`;\n return `[Compressed conversation section]\\n${block.summary}\\n\\n[${blockId} | ${range} | topic: \"${block.topic ?? \"(none)\"}\"]`;\n }\n\n if (activeBlocks.length === 0) return \"No active compression blocks.\";\n\n const lines = [`Active compression blocks (${activeBlocks.length}):`];\n for (const block of activeBlocks) {\n const range = `${block.effectiveMessageIds.length} messages`;\n const preview = block.summary.slice(0, 200);\n lines.push(`\\n${block.blockId} | ${range} | \"${block.topic ?? \"(none)\"}\"`);\n lines.push(` ${preview}${block.summary.length > 200 ? \"...\" : \"\"}`);\n }\n lines.push(`\\nCall with blockId to get the full summary.`);\n return lines.join(\"\\n\");\n}\n","import { createCore } from \"./compress.js\";\nimport { assignRefs, highestUsedIndex } from \"./refs.js\";\nimport { defaultCountTokens } from \"./tokenize.js\";\nimport type { CompressionState, CoreMessage } from \"./types.js\";\n\nexport interface CompressInputEntry {\n startId?: string;\n endId?: string;\n messageId?: string;\n summary: string;\n topic?: string;\n}\n\nexport interface RebuildResult {\n state: CompressionState;\n blocksRebuilt: number;\n}\n\nexport interface RebuildPorts {\n countTokens?: (text: string) => number;\n}\n\n/**\n * Fork-recovery: reconstruct compression state by replaying historical\n * `compress` tool-call messages. Message refs (mNNNNN) are assigned by\n * message order, so they are fork-stable — a ref in a historical compress\n * input points to the same logical message after a fork regenerates IDs.\n * The rebuilt state is an approximation: only raw model summaries are\n * replayed (no protected-content enrichments).\n */\nexport function rebuildCompressionState(\n state: CompressionState,\n messages: CoreMessage[],\n config: import(\"./types.js\").Config,\n ports: RebuildPorts = {},\n): RebuildResult {\n const core = createCore({ countTokens: ports.countTokens ?? defaultCountTokens });\n const refResult = assignRefs(messages, {\n existing: state.messageRefs,\n nextIndex: highestUsedIndex(state.messageRefs) + 1,\n });\n let working: CompressionState = { ...state, messageRefs: refResult.map };\n\n const invocations = collectCompressInvocations(messages);\n let blocksRebuilt = 0;\n\n for (const invocation of invocations) {\n const ranges = extractRanges(invocation.input, invocation.callId);\n if (ranges.length === 0) continue;\n const result = core.applyCompression({ ranges, messages, state: working, config });\n working = result.state;\n blocksRebuilt += result.result.blocksCreated;\n }\n\n return { state: working, blocksRebuilt };\n}\n\ninterface CompressInvocation {\n callId: string | undefined;\n input: unknown;\n}\n\nfunction collectCompressInvocations(messages: CoreMessage[]): CompressInvocation[] {\n const invocations: CompressInvocation[] = [];\n for (const message of messages) {\n if (message.toolName !== \"compress\" || message.contentType !== \"tool-call\") continue;\n let input: unknown;\n try {\n input = JSON.parse(message.text ?? \"\");\n } catch {\n continue;\n }\n invocations.push({ callId: message.toolCallId, input });\n }\n return invocations;\n}\n\nfunction extractRanges(\n input: unknown,\n callId: string | undefined,\n): Array<{\n startRef: string;\n endRef: string;\n summary: string;\n topic?: string;\n compressCallId?: string;\n}> {\n const content = (input as { content?: unknown[] })?.content;\n if (!Array.isArray(content)) return [];\n const ranges = [];\n for (const entry of content) {\n if (!entry || typeof entry !== \"object\") continue;\n const e = entry as CompressInputEntry;\n if (typeof e.summary !== \"string\") continue;\n const start = e.startId ?? e.messageId;\n const end = e.endId ?? e.messageId;\n if (typeof start !== \"string\" || typeof end !== \"string\") continue;\n ranges.push({\n startRef: start,\n endRef: end,\n summary: e.summary,\n topic: typeof e.topic === \"string\" ? e.topic : undefined,\n compressCallId: callId,\n });\n }\n return ranges;\n}\n","import type { SearchAlgorithm, SearchDoc, ScoredBlock } from \"../types.js\";\n\n/**\n * Substring counting — the original baseline algorithm.\n * Exact, lowercased substring occurrence counts. Predictable but blind to\n * morphology, typos, and CJK word boundaries. Kept for backward compat and\n * as a deterministic reference.\n */\nexport const substringAlgorithm: SearchAlgorithm = {\n name: \"substring\",\n description: \"Exact substring counting (original baseline). Predictable, no normalization.\",\n score(docs: SearchDoc[], query: string): ScoredBlock[] {\n const terms = query.toLowerCase().trim().split(/\\s+/).filter((t) => t.length > 0);\n if (terms.length === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));\n return docs.map((d) => {\n const haystack = d.text.toLowerCase();\n let score = 0;\n for (const term of terms) score += countOccurrences(haystack, term);\n return { ref: d.ref, score };\n });\n },\n};\n\nfunction countOccurrences(haystack: string, needle: string): number {\n if (!needle) return 0;\n return haystack.split(needle).length - 1;\n}\n","/**\n * Lightweight English stemmer (suffix stripping, Porter-inspired).\n * Zero dependencies. Good enough for IR morphology normalization:\n * tokens → token, running → runn, compressed → compress,\n * authentication → authentic, handling → handl, subagents → subagent\n *\n * Not a full Porter stemmer — intentionally simpler and faster. CJK is\n * untouched (handled by bigram tokenization, not stemming).\n */\nexport function stem(word: string): string {\n let w = word;\n if (w.length <= 3) return w;\n if (w.endsWith(\"ies\")) w = w.slice(0, -3) + \"y\";\n else if (w.endsWith(\"ses\") || w.endsWith(\"xes\") || w.endsWith(\"zes\")) w = w.slice(0, -2);\n else if (w.endsWith(\"ches\") || w.endsWith(\"shes\")) w = w.slice(0, -2);\n else if (w.endsWith(\"s\") && !w.endsWith(\"ss\")) w = w.slice(0, -1);\n if (w.endsWith(\"ing\") && w.length > 5) w = w.slice(0, -3);\n if (w.endsWith(\"ed\") && w.length > 4) w = w.slice(0, -2);\n if (w.endsWith(\"ation\") && w.length > 6) w = w.slice(0, -3);\n else if (w.endsWith(\"tion\") && w.length > 5) w = w.slice(0, -4) + \"t\";\n else if (w.endsWith(\"ion\") && w.length > 4) w = w.slice(0, -3);\n if (w.endsWith(\"ment\") && w.length > 6) w = w.slice(0, -4);\n if (w.endsWith(\"ness\") && w.length > 6) w = w.slice(0, -4);\n if (w.endsWith(\"ly\") && w.length > 4) w = w.slice(0, -2);\n return w;\n}\n","/**\n * Search tokenizer.\n *\n * Handles mixed Latin + CJK content — the single biggest quality lever\n * over plain substring search. Latin is split on non-word boundaries;\n * CJK (no spaces) is decomposed into overlapping bigrams so a query like\n * \"身份验证\" still scores against doc text \"身份验证流程\".\n */\n\nconst CJK = /[\\u3400-\\u9fff\\uf900-\\ufaff\\u3040-\\u30ff\\uac00-\\ud7af]/;\nconst CJK_RUN = new RegExp(`${CJK.source}+`, \"g\");\nconst LATIN_WORD = /[a-z][a-z0-9_]*[a-z0-9]|[a-z0-9]/g;\n\nimport { stem } from \"./stemmer.js\";\n\nexport interface TokenizeOptions {\n stem?: boolean;\n}\n\nexport function tokenize(text: string, opts: TokenizeOptions = {}): string[] {\n const lower = text.toLowerCase();\n const tokens: string[] = [];\n\n const latin = lower.match(LATIN_WORD) ?? [];\n for (let w of latin) {\n if (w.length >= 2) {\n if (opts.stem) w = stem(w);\n tokens.push(w);\n }\n }\n\n const cjkRuns = lower.match(CJK_RUN) ?? [];\n for (const run of cjkRuns) {\n if (run.length === 1) {\n tokens.push(run);\n } else {\n for (let i = 0; i < run.length - 1; i++) tokens.push(run.slice(i, i + 2));\n for (const ch of run) tokens.push(ch);\n }\n }\n\n return tokens;\n}\n\n/** Character bigrams over arbitrary text — used by fuzzy matching. */\nexport function charBigrams(text: string): string[] {\n const grams: string[] = [];\n for (let i = 0; i < text.length - 1; i++) {\n const pair = text.slice(i, i + 2);\n if (pair.trim().length === pair.length) grams.push(pair);\n }\n return grams;\n}\n\n/** Term-frequency map. */\nexport function tfMap(text: string, stem: boolean): Map<string, number> {\n const m = new Map<string, number>();\n for (const t of tokenize(text, { stem })) m.set(t, (m.get(t) ?? 0) + 1);\n return m;\n}\n","import type { SearchAlgorithm, SearchDoc, ScoredBlock } from \"../types.js\";\nimport { tokenize, tfMap } from \"../tokenizer.js\";\n\n/**\n * BM25 with stemming + CJK bigram tokenization.\n *\n * k1=1.2, b=0.75 (standard IR). IDF down-weights terms common across the\n * corpus; length normalization prevents long summaries from dominating by\n * raw term count. Stemming collapses English morphology\n * (compress/compressed/compression → ~compress).\n *\n * On a 30-block mixed EN/CJK benchmark: MRR 0.812 vs 0.821 for substring\n * alone — not better in isolation, but a strong precision component when\n * combined with fuzzy recall (see hybrid.ts).\n */\nexport const bm25Algorithm: SearchAlgorithm = {\n name: \"bm25\",\n description: \"BM25 with stemming + CJK bigram tokenization. IR-standard relevance ranking.\",\n score(docs: SearchDoc[], query: string): ScoredBlock[] {\n const N = docs.length;\n const k1 = 1.2;\n const b = 0.75;\n const parsed = docs.map((d) => {\n const text = d.text;\n const tf = tfMap(text, true);\n let len = 0;\n for (const v of tf.values()) len += v;\n return { id: d.ref, tf, len };\n });\n const avgdl = parsed.reduce((s, d) => s + d.len, 0) / (N || 1);\n\n const qTerms = tokenize(query, { stem: true });\n if (qTerms.length === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));\n\n const idf = new Map<string, number>();\n for (const t of new Set(qTerms)) {\n let df = 0;\n for (const d of parsed) if (d.tf.has(t)) df++;\n idf.set(t, Math.log(1 + (N - df + 0.5) / (df + 0.5)));\n }\n\n return parsed.map((d) => {\n let score = 0;\n for (const t of qTerms) {\n const f = d.tf.get(t) ?? 0;\n if (f === 0) continue;\n const idfT = idf.get(t) ?? 0;\n score += (idfT * (f * (k1 + 1))) / (f + k1 * (1 - b + (b * d.len) / (avgdl || 1)));\n }\n return { ref: d.id, score };\n });\n },\n};\n","import type { SearchAlgorithm, SearchDoc, ScoredBlock } from \"../types.js\";\nimport { charBigrams } from \"../tokenizer.js\";\n\n/**\n * Fuzzy character-bigram matching (Jaccard-style).\n *\n * Decomposes the query into character bigrams and measures overlap with\n * each doc. Robust to typos (tokan≈token), partial words, and works\n * uniformly across all scripts (CJK benefits most). Only considers query\n * tokens of length >= 4 to avoid noise from short common-character pairs.\n *\n * On benchmark: highest recall@3 (0.913) of any single algorithm — it is\n * the recall boost in the hybrid default.\n */\nexport const fuzzyAlgorithm: SearchAlgorithm = {\n name: \"fuzzy\",\n description: \"Character bigram overlap. Typo-tolerant, script-agnostic, high recall.\",\n score(docs: SearchDoc[], query: string): ScoredBlock[] {\n const qTokens = query.toLowerCase().split(/[\\s,]+/).filter((t) => t.length >= 4);\n if (qTokens.length === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));\n\n const qGrams = new Set<string>();\n for (const t of qTokens) for (const g of charBigrams(t)) qGrams.add(g);\n if (qGrams.size === 0) return docs.map((d) => ({ ref: d.ref, score: 0 }));\n\n return docs.map((d) => {\n const haystack = d.text.toLowerCase();\n const docGrams = new Set(charBigrams(haystack));\n let hits = 0;\n for (const g of qGrams) if (docGrams.has(g)) hits++;\n return { ref: d.ref, score: hits / qGrams.size };\n });\n },\n};\n","import type { SearchAlgorithm, SearchDoc, ScoredBlock } from \"../types.js\";\nimport { bm25Algorithm } from \"./bm25.js\";\nimport { fuzzyAlgorithm } from \"./fuzzy.js\";\n\n/**\n * Hybrid: normalized BM25(stem) + fuzzy n-gram, weighted 0.7 / 0.3.\n *\n * BM25 supplies precision on real terms (with morphology + IDF + length\n * norm); fuzzy supplies recall on typos, partials, and cross-script.\n * Each component is max-normalized to [0,1] before weighting so their\n * scales are comparable regardless of corpus size.\n *\n * Benchmark (30 blocks, 45 mixed EN/CJK queries):\n * substring MRR 0.821 R@1 0.804 R@3 0.826\n * bm25 MRR 0.812 R@1 0.804 R@3 0.826\n * fuzzy MRR 0.834 R@1 0.761 R@3 0.913\n * hybrid MRR 0.881 R@1 0.848 R@3 0.913 ← best on every metric\n *\n * The weight ratio is robust: 0.6–0.8 for BM25 all score within 0.001 MRR.\n */\n\nconst W_BM25 = 0.7;\nconst W_FUZZY = 0.3;\n\nexport const hybridAlgorithm: SearchAlgorithm = {\n name: \"hybrid\",\n description: \"Weighted BM25(stem) + fuzzy n-gram. Default — best precision + recall.\",\n score(docs: SearchDoc[], query: string): ScoredBlock[] {\n const bm = bm25Algorithm.score(docs, query);\n const fz = fuzzyAlgorithm.score(docs, query);\n const maxBm = Math.max(...bm.map((r) => r.score), 1e-9);\n const maxFz = Math.max(...fz.map((r) => r.score), 1e-9);\n const bmMap = new Map(bm.map((r) => [r.ref, r.score / maxBm]));\n const fzMap = new Map(fz.map((r) => [r.ref, r.score / maxFz]));\n return docs.map((d) => ({\n ref: d.ref,\n score: W_BM25 * (bmMap.get(d.ref) ?? 0) + W_FUZZY * (fzMap.get(d.ref) ?? 0),\n }));\n },\n};\n","/**\n * Algorithm registry. Builtins are pre-registered; hosts may register\n * additional algorithms (e.g. an embedding-based semantic provider) via\n * registerSearchAlgorithm and reference them by name in SearchOptions.\n */\nimport type { AnySearchAlgorithm } from \"./types.js\";\nimport { substringAlgorithm } from \"./algorithms/substring.js\";\nimport { bm25Algorithm } from \"./algorithms/bm25.js\";\nimport { fuzzyAlgorithm } from \"./algorithms/fuzzy.js\";\nimport { hybridAlgorithm } from \"./algorithms/hybrid.js\";\n\nconst registry = new Map<string, AnySearchAlgorithm>();\n\nexport function registerSearchAlgorithm(algo: AnySearchAlgorithm): void {\n registry.set(algo.name, algo);\n}\n\nexport function getSearchAlgorithm(name: string): AnySearchAlgorithm | undefined {\n return registry.get(name);\n}\n\nexport function listSearchAlgorithms(): AnySearchAlgorithm[] {\n return [...registry.values()];\n}\n\n// Pre-register builtins. Hybrid is the default (see types.ts DEFAULT_ALGORITHM).\nregisterSearchAlgorithm(substringAlgorithm);\nregisterSearchAlgorithm(bm25Algorithm);\nregisterSearchAlgorithm(fuzzyAlgorithm);\nregisterSearchAlgorithm(hybridAlgorithm);\n","/**\n * Search type definitions.\n *\n * Two data sources are searchable:\n * - Compressed blocks (summary text; ref = \"b{id}\")\n * - Historical messages (original text from the append-only session log;\n * ref = \"m{NNNNN}\"). These let the model locate detail that compression\n * turned into a short summary — search to pinpoint, then decompress the\n * owning block for the full content.\n *\n * A SearchAlgorithm is a stateless scorer over a unified SearchDoc[]. Roles\n * carry a configurable weight (user intent > assistant reasoning > tool noise).\n */\n\n/** Where a searchable document came from. */\nexport type SearchDocKind = \"block\" | \"message\";\n\nexport type MessageRole = \"user\" | \"assistant\" | \"tool\";\n\n/** A unified searchable document — either a block summary or a message. */\nexport interface SearchDoc {\n kind: SearchDocKind;\n /** Stable ref for decompress: \"b3\" for a block, \"m00350\" for a message. */\n ref: string;\n /** Text this doc is scored against (topic+summary for blocks; content for messages). */\n text: string;\n /** For preview/title display. */\n title: string;\n /** Message role (messages only); undefined for blocks. Drives role weighting. */\n role?: MessageRole;\n /** Block owning this doc. For blocks: the block itself. For messages: the block\n * that compressed it (so the model knows which block to decompress for detail). */\n blockId?: string;\n /** Tier of the owning block (display + grouping). */\n tier?: number;\n /** Approx token size (for \"how big is this\" display). */\n tokens?: number;\n}\n\n/** Per-role score multipliers. Defaults favor user intent over tool noise. */\nexport interface RoleWeights {\n user?: number;\n assistant?: number;\n tool?: number;\n block?: number;\n}\n\nexport const DEFAULT_ROLE_WEIGHTS: Required<RoleWeights> = {\n user: 1.5,\n assistant: 1.0,\n tool: 0.6,\n block: 1.0,\n};\n\nexport interface ScoredBlock {\n ref: string;\n score: number;\n}\n\nexport interface SearchAlgorithm {\n name: string;\n description: string;\n score(docs: SearchDoc[], query: string): ScoredBlock[];\n}\n\nexport interface AsyncSearchAlgorithm {\n name: string;\n description: string;\n score(docs: SearchDoc[], query: string): Promise<ScoredBlock[]>;\n}\n\nexport type AnySearchAlgorithm = SearchAlgorithm | AsyncSearchAlgorithm;\n\nexport interface SearchResult {\n /** \"block\" or \"message\". */\n kind: SearchDocKind;\n /** Ref to pass to decompress: \"b3\" or \"m00350\". */\n ref: string;\n /** Owning block id (for messages: the block that compressed it). */\n blockId?: string;\n tier: number;\n score: number;\n title: string;\n preview: string;\n role?: MessageRole;\n tokens?: number;\n}\n\nexport interface SearchOptions {\n algorithm?: string;\n limit?: number;\n previewLength?: number;\n minScore?: number;\n /** Per-role weights (default DEFAULT_ROLE_WEIGHTS). */\n roleWeights?: RoleWeights;\n}\n\n/** Host-supplied historical message, turned into a message SearchDoc. */\nexport interface MessageInput {\n ref: string;\n role: MessageRole;\n text: string;\n tokens?: number;\n /** Block id that compressed this message (undefined if still visible). */\n blockId?: string;\n tier?: number;\n}\n\nexport const DEFAULT_ALGORITHM = \"hybrid\";\n","/**\n * searchBlocks — public search entry point.\n *\n * Scores a unified document set (block summaries + historical messages)\n * and returns ranked results. The model uses search to cheaply locate\n * detail that compression folded into summaries, then decompresses the\n * owning block for the full content.\n *\n * Two entry points:\n * - searchBlocks() — sync. Works for all lexical algorithms.\n * - searchBlocksAsync() — async. Also supports embedding-based semantic\n * algorithms whose score() returns a Promise.\n */\n\nimport type { CompressionState, CompressionBlock } from \"../types.js\";\nimport { getSearchAlgorithm } from \"./registry.js\";\nimport type { SearchDoc, ScoredBlock, MessageInput } from \"./types.js\";\nimport type { SearchResult, SearchOptions, RoleWeights } from \"./types.js\";\nimport { DEFAULT_ALGORITHM, DEFAULT_ROLE_WEIGHTS } from \"./types.js\";\n\n/** Build SearchDoc[] from all blocks (active AND inactive) of the state. */\nexport function blockDocs(state: CompressionState): SearchDoc[] {\n return state.blocks.map((b: CompressionBlock): SearchDoc => ({\n kind: \"block\",\n ref: b.blockId,\n text: `${b.topic ?? \"\"} ${b.summary ?? \"\"}`,\n title: b.topic ?? b.blockId,\n blockId: b.blockId,\n tier: b.tier ?? 1,\n tokens: b.compressedTokens,\n }));\n}\n\n/**\n * Build SearchDoc[] from historical messages supplied by the host. The host\n * (pai-acp) reads these from the append-only session log — they include the\n * original text of messages that compression later folded into block summaries.\n *\n * `ownerOf(ref)` maps a message ref to the block id that compressed it, so a\n * message hit tells the model exactly which block to decompress for detail.\n */\nexport function messageDocs(msgs: MessageInput[]): SearchDoc[] {\n return msgs.map((m): SearchDoc => ({\n kind: \"message\",\n ref: m.ref,\n text: m.text,\n title: `${m.role}: ${m.text.slice(0, 60)}`,\n role: m.role,\n blockId: m.blockId,\n tier: m.tier,\n tokens: m.tokens,\n }));\n}\n\nfunction applyRoleWeight(scored: ScoredBlock[], docs: SearchDoc[], rw: Required<RoleWeights>): ScoredBlock[] {\n if (docs.length === 0) return scored;\n const docByRef = new Map(docs.map((d) => [d.ref, d]));\n return scored.map((s) => {\n const doc = docByRef.get(s.ref);\n if (!doc) return s;\n const w =\n doc.kind === \"message\"\n ? doc.role === \"user\"\n ? rw.user\n : doc.role === \"assistant\"\n ? rw.assistant\n : rw.tool\n : rw.block;\n return { ref: s.ref, score: s.score * w };\n });\n}\n\nfunction runSearch(\n docs: SearchDoc[],\n query: string,\n options: SearchOptions,\n): SearchResult[] | Promise<SearchResult[]> {\n const limit = options.limit ?? 10;\n const previewLength = options.previewLength ?? 200;\n const minScore = options.minScore ?? 0.01;\n const algoName = options.algorithm ?? DEFAULT_ALGORITHM;\n const rw = { ...DEFAULT_ROLE_WEIGHTS, ...options.roleWeights };\n\n const algo = getSearchAlgorithm(algoName);\n if (!algo) return [];\n if (docs.length === 0) return [];\n\n const scoredOrPromise = algo.score(docs, query);\n\n const buildResults = (weighted: ScoredBlock[]): SearchResult[] => {\n const byRef = new Map(docs.map((d) => [d.ref, d]));\n return weighted\n .map((s): SearchResult | null => {\n const doc = byRef.get(s.ref);\n if (!doc) return null;\n return {\n kind: doc.kind,\n ref: doc.ref,\n blockId: doc.blockId,\n tier: doc.tier ?? 1,\n score: s.score,\n title: doc.title,\n preview: makePreview(doc.text, query, previewLength),\n role: doc.role,\n tokens: doc.tokens,\n };\n })\n .filter((r): r is SearchResult => r !== null && r.score >= minScore)\n .sort((a, b) => b.score - a.score)\n .slice(0, limit);\n };\n\n if (scoredOrPromise instanceof Promise) {\n return scoredOrPromise.then((raw) => buildResults(applyRoleWeight(raw, docs, rw)));\n }\n return buildResults(applyRoleWeight(scoredOrPromise, docs, rw));\n}\n\n/** Sync entry — throws for async algorithms. Pass docs from blockDocs() + messageDocs(). */\nexport function searchBlocks(docs: SearchDoc[], query: string, options: SearchOptions = {}): SearchResult[] {\n const result = runSearch(docs, query, options);\n if (result instanceof Promise) {\n throw new Error(\n `searchBlocks: algorithm \"${options.algorithm ?? DEFAULT_ALGORITHM}\" is async (e.g. semantic). Use searchBlocksAsync() instead.`,\n );\n }\n return result;\n}\n\nexport async function searchBlocksAsync(docs: SearchDoc[], query: string, options: SearchOptions = {}): Promise<SearchResult[]> {\n return await runSearch(docs, query, options);\n}\n\n/**\n * Preview centered on the first query-term hit (case-insensitive).\n * Falls back to the head when no term hits.\n */\nfunction makePreview(text: string, query: string, len: number): string {\n if (!text) return \"\";\n const terms = query.toLowerCase().trim().split(/\\s+/).filter((t) => t.length > 1);\n if (terms.length === 0) return text.slice(0, len);\n\n const lower = text.toLowerCase();\n let hitIdx = -1;\n for (const term of terms) {\n const idx = lower.indexOf(term);\n if (idx >= 0) {\n hitIdx = idx;\n break;\n }\n }\n\n if (hitIdx < 0) return text.slice(0, len);\n\n const half = Math.max(0, Math.floor(len / 2) - 10);\n const start = Math.max(0, hitIdx - half);\n const end = Math.min(text.length, start + len);\n const prefix = start > 0 ? \"…\" : \"\";\n const suffix = end < text.length ? \"…\" : \"\";\n return prefix + text.slice(start, end).trim() + suffix;\n}\n"],"mappings":"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","names":["require","require","block","refNum","formatTokens","numericPart","activeBlocks","refNum","countOccurrences","stem","registry"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "acp-kernel",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
4
4
  "description": "Framework-agnostic context-compression engine (model-driven, 3-tier LSM). Pure core: no host dependency.",
5
5
  "license": "MIT",
6
6
  "author": "ranxianglei",