feat(context,infra): compression pipeline stages 4-5 — token pruning + relevance + ToMe
- build() is now suspend: pipeline runs all stages in fixed order, each gated by level - TOKEN_PRUNE (level 3): TokenPruner interface + LLMLingua-2 sidecar (sidecars/llmlingua) + HttpTokenPruner adapter (fails open if sidecar down); prunes freeform, preserves protected spans, skips tier-0 turns when TIER_SPLIT on - TOME_MERGE (level 8): ToMeMerger collapses near-duplicate freeform turns (Jaccard) - Stage 5 selection: RelevanceScorer + EmbeddingRelevanceScorer (cosine over Embedder); query-conditioned reorder so least-relevant freeform drops first under budget - [orchestration] compression_level + token_pruner_url config, wired in Main - suspend ripple fixed across builder callers/stubs
This commit is contained in:
@@ -81,11 +81,11 @@ class CompressionPipelineStagesTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `builder pins a fact sheet at level 7 and omits it below`() {
|
||||
fun `builder pins a fact sheet at level 7 and omits it below`() = kotlinx.coroutines.runBlocking {
|
||||
val entries = listOf(entry("chat", ContextLayer.L1, EntryRole.USER, "deploy to 10.0.0.1"))
|
||||
val compressor = com.correx.core.context.compression.DefaultContextCompressor()
|
||||
|
||||
fun buildAt(level: Int) = com.correx.core.context.builder.DefaultContextPackBuilder(
|
||||
suspend fun buildAt(level: Int) = com.correx.core.context.builder.DefaultContextPackBuilder(
|
||||
compressor, CompressionPolicy(level)
|
||||
).build(
|
||||
com.correx.core.events.types.ContextPackId("p"),
|
||||
@@ -98,6 +98,43 @@ class CompressionPipelineStagesTest {
|
||||
val atSeven = buildAt(7).layers.values.flatten()
|
||||
assertTrue(atSeven.any { it.sourceType == "factSheet" && it.content.contains("10.0.0.1") })
|
||||
assertFalse(buildAt(6).layers.values.flatten().any { it.sourceType == "factSheet" })
|
||||
Unit
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `tome merges near-duplicate freeform turns keeping the newest`() {
|
||||
val merger = com.correx.core.context.compression.ToMeMerger(threshold = 0.8)
|
||||
val a = entry("chat", ContextLayer.L2, EntryRole.USER, "the deploy failed on host web").copy(ordinal = 0)
|
||||
val b = entry("chat", ContextLayer.L2, EntryRole.USER, "the deploy failed on host web again").copy(ordinal = 1)
|
||||
val c = entry("chat", ContextLayer.L2, EntryRole.USER, "totally unrelated content here").copy(ordinal = 2)
|
||||
val out = merger.merge(listOf(a, b, c))
|
||||
// a and b are near-duplicates -> only the newest (b) survives; c is distinct
|
||||
assertEquals(listOf(1, 2), out.map { it.ordinal })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `token pruning at level 3 rewrites freeform preserving protected spans`() = kotlinx.coroutines.runBlocking {
|
||||
val pruner = object : com.correx.core.context.compression.TokenPruner {
|
||||
override suspend fun prune(content: String, protectedSpans: List<String>, targetRatio: Double): String =
|
||||
"PRUNED " + protectedSpans.joinToString(" ")
|
||||
}
|
||||
val builder = com.correx.core.context.builder.DefaultContextPackBuilder(
|
||||
com.correx.core.context.compression.DefaultContextCompressor(),
|
||||
CompressionPolicy(3),
|
||||
tokenPruner = pruner,
|
||||
)
|
||||
val entries = listOf(entry("chat", ContextLayer.L1, EntryRole.USER, "please redeploy 10.0.0.1 now"))
|
||||
val pack = builder.build(
|
||||
com.correx.core.events.types.ContextPackId("p"),
|
||||
com.correx.core.events.types.SessionId("s"),
|
||||
com.correx.core.events.types.StageId("st"),
|
||||
entries,
|
||||
com.correx.core.context.model.TokenBudget(limit = 4000),
|
||||
)
|
||||
val content = pack.layers.values.flatten().first { it.sourceType == "chat" }.content
|
||||
assertTrue(content.startsWith("PRUNED"), content)
|
||||
assertTrue(content.contains("10.0.0.1"), content)
|
||||
Unit
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -20,7 +20,7 @@ class DecisionJournalPinningTest {
|
||||
private val packId = ContextPackId("pack-1")
|
||||
|
||||
@Test
|
||||
fun `decisionJournal entry survives an under-budget build`() {
|
||||
fun `decisionJournal entry survives an under-budget build`() = kotlinx.coroutines.runBlocking {
|
||||
val entries = listOf(
|
||||
ContextEntry(
|
||||
id = ContextEntryId("journal-1"),
|
||||
@@ -37,5 +37,6 @@ class DecisionJournalPinningTest {
|
||||
allRetained.any { it.sourceType == "decisionJournal" },
|
||||
"decisionJournal entry must be retained even when budget is exceeded"
|
||||
)
|
||||
Unit
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user