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:
wassname
2026-04-16 12:57:59 +08:00
parent e475cb6bf0
commit 32e9d67fa9
+52 -7
View File
@@ -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,16 +161,60 @@ export function registerCompressTool(
startTimestamp <= existing.endTimestamp &&
existing.startTimestamp <= endTimestamp
if (overlaps) {
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})`,
)
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(s): ${overlapInfo}. ` +
`Valid compressible ranges: ${gapInfo}`,
)
}
// ── Anchor: first raw message after the range ────────────────────
const anchorTimestamp = resolveAnchorTimestamp(endTimestamp, state)