feat(server,kernel): repo-map indexer + droppable L3 context injection

This commit is contained in:
2026-06-04 01:48:05 +04:00
parent 0ca7d4c86b
commit 8b6eedcf87
9 changed files with 242 additions and 4 deletions
@@ -30,6 +30,7 @@ import com.correx.core.events.events.ArtifactValidatingEvent
import com.correx.core.events.events.EventMetadata
import com.correx.core.events.events.EventPayload
import com.correx.core.events.events.InferenceCompletedEvent
import com.correx.core.events.events.RepoMapComputedEvent
import com.correx.core.events.events.InferenceFailedEvent
import com.correx.core.events.events.InferenceStartedEvent
import com.correx.core.events.events.InferenceTimeoutEvent
@@ -117,6 +118,7 @@ import kotlin.coroutines.cancellation.CancellationException
private const val MAX_TOOL_ROUNDS = 10
private const val STAGE_COMPLETE_TOOL = "stage_complete"
private const val REPO_MAP_INJECT_TOP_K = 30
@SuppressWarnings(
"ForbiddenComment",
@@ -303,7 +305,9 @@ abstract class SessionOrchestrator(
role = EntryRole.SYSTEM,
),
)
var accumulatedEntries = systemPrompt + journalEntries + schemaEntries + promptEntries + steeringEntries
val repoMapEntries = buildRepoMapEntries(sessionId)
var accumulatedEntries =
systemPrompt + journalEntries + repoMapEntries + schemaEntries + promptEntries + steeringEntries
val contextPack = contextPackBuilder.build(
id = ContextPackId(UUID.randomUUID().toString()),
sessionId = sessionId,
@@ -807,6 +811,38 @@ abstract class SessionOrchestrator(
}
}
/**
* Renders a top-K slice of the recorded repo map as a droppable L3 context entry. Reads
* the latest [RepoMapComputedEvent] from the log (replay-safe — never re-scans the FS).
* Not pinned: under budget pressure this yields before the working set (paths + symbols
* only, so the model can `file_read` for detail).
*/
private suspend fun buildRepoMapEntries(sessionId: SessionId): List<ContextEntry> {
val map = eventStore.read(sessionId)
.mapNotNull { it.payload as? RepoMapComputedEvent }
.lastOrNull() ?: return emptyList()
val top = map.entries.sortedByDescending { it.score }.take(REPO_MAP_INJECT_TOP_K)
if (top.isEmpty()) return emptyList()
val content = buildString {
appendLine("## Repo map (top files by recency — read files for detail)")
top.forEach { entry ->
val symbols = if (entry.symbols.isEmpty()) "" else ": ${entry.symbols.joinToString(", ")}"
appendLine("- ${entry.path}$symbols")
}
}.trimEnd()
return listOf(
ContextEntry(
id = ContextEntryId(UUID.randomUUID().toString()),
layer = ContextLayer.L3,
content = content,
sourceType = "repoMap",
sourceId = "repo-map",
tokenEstimate = estimateTokens(content),
role = EntryRole.SYSTEM,
),
)
}
private suspend fun emitToolArtifacts(
sessionId: SessionId,
stageId: StageId,