feat(context): reasoning-thread continuity, L3 doc filtering, and gate hardening

Threads reasoning_content across inference calls and journal renders, filters
markdown noise out of L3 repo-knowledge retrieval, adds PlanLinter H3 checks,
and tightens filesystem tool output/dir-listing behavior surfaced by prior
live QA (see project_readloop_campaign memory).
This commit is contained in:
2026-07-10 11:13:43 +04:00
parent f51a8dada4
commit 3d5e05c1fb
32 changed files with 742 additions and 85 deletions
@@ -134,10 +134,10 @@ class DefaultContextPackBuilderTest {
// layer reads call, result, call, result — not all calls then all results.
val entries = listOf(
entry("task", ContextLayer.L1, 10).copy(sourceType = "agentPrompt"),
entry("call1", ContextLayer.L2, 10).copy(sourceType = "assistantToolCall"),
entry("result1", ContextLayer.L2, 10).copy(sourceType = "toolResult"),
entry("call2", ContextLayer.L2, 10).copy(sourceType = "assistantToolCall"),
entry("result2", ContextLayer.L2, 10).copy(sourceType = "toolResult"),
entry("call1", ContextLayer.L2, 10).copy(sourceType = "assistantToolCall", sourceId = "tool1"),
entry("result1", ContextLayer.L2, 10).copy(sourceType = "toolResult", sourceId = "tool1"),
entry("call2", ContextLayer.L2, 10).copy(sourceType = "assistantToolCall", sourceId = "tool2"),
entry("result2", ContextLayer.L2, 10).copy(sourceType = "toolResult", sourceId = "tool2"),
)
val pack = builder.build(packId, sessionId, stageId, entries, TokenBudget(limit = 4000))
val l2Ids = pack.layers[ContextLayer.L2]!!.map { it.id.value }
@@ -18,15 +18,16 @@ class PromptRendererOrderingTest {
private val sessionId = SessionId("s1")
private val stageId = StageId("stage-1")
private fun entry(id: String, layer: ContextLayer, role: EntryRole, sourceType: String) = ContextEntry(
id = ContextEntryId(id),
layer = layer,
content = id,
sourceType = sourceType,
sourceId = id,
tokenEstimate = 10,
role = role,
)
private fun entry(id: String, layer: ContextLayer, role: EntryRole, sourceType: String, sourceId: String = id) =
ContextEntry(
id = ContextEntryId(id),
layer = layer,
content = id,
sourceType = sourceType,
sourceId = sourceId,
tokenEstimate = 10,
role = role,
)
@Test
fun `stage tool loop renders chronologically with the task before tool turns`() = kotlinx.coroutines.runBlocking {
@@ -36,10 +37,10 @@ class PromptRendererOrderingTest {
val entries = listOf(
entry("sys", ContextLayer.L0, EntryRole.SYSTEM, "systemPrompt"),
entry("task", ContextLayer.L1, EntryRole.USER, "agentPrompt"),
entry("call1", ContextLayer.L2, EntryRole.ASSISTANT, "assistantToolCall"),
entry("result1", ContextLayer.L2, EntryRole.TOOL, "toolResult"),
entry("call2", ContextLayer.L2, EntryRole.ASSISTANT, "assistantToolCall"),
entry("result2", ContextLayer.L2, EntryRole.TOOL, "toolResult"),
entry("call1", ContextLayer.L2, EntryRole.ASSISTANT, "assistantToolCall", sourceId = "tool1"),
entry("result1", ContextLayer.L2, EntryRole.TOOL, "toolResult", sourceId = "tool1"),
entry("call2", ContextLayer.L2, EntryRole.ASSISTANT, "assistantToolCall", sourceId = "tool2"),
entry("result2", ContextLayer.L2, EntryRole.TOOL, "toolResult", sourceId = "tool2"),
)
val pack = builder.build(ContextPackId("p"), sessionId, stageId, entries, TokenBudget(limit = 4000))