mirror of
https://github.com/wassname/pi-dynamic-context-pruning.git
synced 2026-06-27 16:46:12 +08:00
feat: report valid compressible gap ranges on overlap error
When a compress call overlaps existing blocks, the error message now includes the exact mNNN..mNNN ranges that are available for compression (before, after, and between existing blocks). This lets the model immediately retry with valid ranges instead of guessing.
This commit is contained in:
+50
-5
@@ -150,6 +150,7 @@ export function registerCompressTool(
|
||||
}
|
||||
|
||||
// ── Overlap check against existing active blocks ─────────────────
|
||||
const overlappingBlocks: CompressionBlock[] = []
|
||||
for (const existing of state.compressionBlocks) {
|
||||
if (!existing.active) continue
|
||||
// Skip blocks with corrupted timestamps
|
||||
@@ -160,15 +161,59 @@ export function registerCompressTool(
|
||||
startTimestamp <= existing.endTimestamp &&
|
||||
existing.startTimestamp <= endTimestamp
|
||||
if (overlaps) {
|
||||
overlappingBlocks.push(existing)
|
||||
}
|
||||
}
|
||||
|
||||
if (overlappingBlocks.length > 0) {
|
||||
// Compute valid compressible gaps: raw message ranges not covered by any active block.
|
||||
const activeBlocks = state.compressionBlocks
|
||||
.filter(b => b.active && Number.isFinite(b.startTimestamp) && Number.isFinite(b.endTimestamp))
|
||||
.sort((a, b) => a.startTimestamp - b.startTimestamp)
|
||||
|
||||
const sortedEntries = [...state.messageIdSnapshot.entries()]
|
||||
.filter(([id]) => id.startsWith('m')) // only mNNN ids
|
||||
.sort((a, b) => a[1] - b[1])
|
||||
|
||||
// Walk sorted messages, grouping consecutive uncovered ones into gap ranges
|
||||
const gaps: string[] = []
|
||||
let gapStart: string | null = null
|
||||
let gapEnd: string | null = null
|
||||
|
||||
for (const [id, ts] of sortedEntries) {
|
||||
const covered = activeBlocks.some(
|
||||
b => ts >= b.startTimestamp && ts <= b.endTimestamp
|
||||
)
|
||||
if (!covered) {
|
||||
if (gapStart === null) gapStart = id
|
||||
gapEnd = id
|
||||
} else {
|
||||
if (gapStart !== null) {
|
||||
gaps.push(`${gapStart}..${gapEnd}`)
|
||||
gapStart = null
|
||||
gapEnd = null
|
||||
}
|
||||
}
|
||||
}
|
||||
// Close trailing gap
|
||||
if (gapStart !== null && gapEnd !== null) {
|
||||
gaps.push(`${gapStart}..${gapEnd}`)
|
||||
}
|
||||
|
||||
const overlapInfo = overlappingBlocks
|
||||
.map(b => `b${b.id} "${b.topic}"`)
|
||||
.join(', ')
|
||||
|
||||
const gapInfo = gaps.length > 0
|
||||
? gaps.join('; ')
|
||||
: 'None — all visible messages are covered by existing blocks'
|
||||
|
||||
throw new Error(
|
||||
`Overlapping compression ranges are not supported. ` +
|
||||
`New range (${startId}..${endId}) overlaps existing block ` +
|
||||
`b${existing.id} "${existing.topic}" ` +
|
||||
`(b${existing.id} covers ${existing.startTimestamp}..${existing.endTimestamp}, ` +
|
||||
`new range covers ${startTimestamp}..${endTimestamp})`,
|
||||
`New range (${startId}..${endId}) overlaps existing block(s): ${overlapInfo}. ` +
|
||||
`Valid compressible ranges: ${gapInfo}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ── Anchor: first raw message after the range ────────────────────
|
||||
const anchorTimestamp = resolveAnchorTimestamp(endTimestamp, state)
|
||||
|
||||
Reference in New Issue
Block a user