feat(context): compression pipeline stage 1 — level policy + deterministic stages

Additive CompressionPolicy (levels 1-9), ProtectedSpanTagger (regex
load-bearing spans), FormatCompressor (json→dotted lines), ContextClassifier
(static/structured/freeform). Stage 1 (FORMAT_COMPRESS) wired into
DefaultContextPackBuilder behind the policy; structured entries only, lossless.
PromptRenderer repetition-anchoring of steering directives.
This commit is contained in:
2026-07-01 13:53:19 +04:00
parent 4be8f292ae
commit 61be90070f
8 changed files with 302 additions and 2 deletions
@@ -37,9 +37,18 @@ object PromptRenderer {
val conversationMessages = conversationEntries
.sortedWith(compareBy({ it.second.ordinal }, { layerPriority(it.first) }))
.map { (_, entry) -> entry.toChatMessage() }
// Repetition anchoring: steering directives fold into the leading system message, far
// from the final query — weak local models forget them (lost-in-the-middle). Restate
// them once as a trailing user turn, where models attend strongest. Template-safe: a
// user message at the end never trips strict system-must-be-first templates.
val anchor = systemEntries
.filter { it.second.sourceType == "steeringNote" }
.joinToString("\n") { it.second.content }
.takeIf { it.isNotBlank() }
val messages = buildList {
systemContent?.let { add(ChatMessage("system", it)) }
addAll(conversationMessages)
anchor?.let { add(ChatMessage("user", "Reminder — active steering directive(s):\n$it")) }
}
return messages.ifEmpty { listOf(ChatMessage("user", "")) }
}