feat(kernel): label reviewer artifacts as critic feedback on back-edge re-entry
This commit is contained in:
@@ -6,11 +6,14 @@ package com.correx.core.kernel.orchestration
|
||||
import com.correx.core.context.model.ContextEntry
|
||||
import com.correx.core.context.model.ContextLayer
|
||||
import com.correx.core.context.model.EntryRole
|
||||
import com.correx.core.events.events.RefinementIterationEvent
|
||||
import com.correx.core.events.events.RetryAttemptedEvent
|
||||
import com.correx.core.events.events.StoredEvent
|
||||
import com.correx.core.events.types.ArtifactId
|
||||
import com.correx.core.events.types.ContextEntryId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.core.sessions.BoundProjectProfile
|
||||
import com.correx.core.transitions.graph.WorkflowGraph
|
||||
import java.util.UUID
|
||||
|
||||
fun buildRetryFeedbackEntry(events: List<StoredEvent>, stageId: StageId): ContextEntry? {
|
||||
@@ -32,6 +35,18 @@ fun buildRetryFeedbackEntry(events: List<StoredEvent>, stageId: StageId): Contex
|
||||
)
|
||||
}
|
||||
|
||||
fun criticArtifactIds(
|
||||
events: List<StoredEvent>,
|
||||
graph: WorkflowGraph,
|
||||
stageId: StageId,
|
||||
): Set<ArtifactId> {
|
||||
val cycle = events
|
||||
.mapNotNull { it.payload as? RefinementIterationEvent }
|
||||
.lastOrNull { it.cycleKey.endsWith("->${stageId.value}") } ?: return emptySet()
|
||||
val fromStage = StageId(cycle.cycleKey.substringBefore("->"))
|
||||
return graph.stages[fromStage]?.produces?.map { it.name }?.toSet() ?: emptySet()
|
||||
}
|
||||
|
||||
fun buildProjectProfileEntry(profile: BoundProjectProfile): ContextEntry {
|
||||
val content = buildString {
|
||||
append("## Project profile\n")
|
||||
|
||||
+19
-4
@@ -23,6 +23,7 @@ import com.correx.core.context.model.ContextPack
|
||||
import com.correx.core.context.model.TokenBudget
|
||||
import com.correx.core.context.model.EntryRole
|
||||
import com.correx.core.events.events.ApprovalDecisionResolvedEvent
|
||||
import com.correx.core.events.events.RefinementIterationEvent
|
||||
import com.correx.core.events.events.ApprovalRequestedEvent
|
||||
import com.correx.core.events.events.ArtifactContentStoredEvent
|
||||
import com.correx.core.events.events.ArtifactCreatedEvent
|
||||
@@ -347,7 +348,13 @@ abstract class SessionOrchestrator(
|
||||
),
|
||||
)
|
||||
val repoMapEntries = buildRepoMapEntries(sessionId)
|
||||
val needsEntries = buildNeedsArtifactEntries(sessionId, stageConfig)
|
||||
val sessionEvents = eventStore.read(sessionId)
|
||||
val criticIds = criticArtifactIds(sessionEvents, graph, stageId)
|
||||
val criticFrom = sessionEvents
|
||||
.mapNotNull { it.payload as? RefinementIterationEvent }
|
||||
.lastOrNull { it.cycleKey.endsWith("->${stageId.value}") }
|
||||
?.cycleKey?.substringBefore("->")
|
||||
val needsEntries = buildNeedsArtifactEntries(sessionId, stageConfig, criticIds, criticFrom)
|
||||
val profileEntries = session.state.boundProfile?.about
|
||||
?.takeIf { it.isNotBlank() }
|
||||
?.let { about ->
|
||||
@@ -365,7 +372,7 @@ abstract class SessionOrchestrator(
|
||||
} ?: emptyList()
|
||||
val projectProfileEntries = session.state.boundProjectProfile
|
||||
?.let { listOf(buildProjectProfileEntry(it)) } ?: emptyList()
|
||||
val retryFeedbackEntries = buildRetryFeedbackEntry(eventStore.read(sessionId), stageId)
|
||||
val retryFeedbackEntries = buildRetryFeedbackEntry(sessionEvents, stageId)
|
||||
?.let { listOf(it) } ?: emptyList()
|
||||
var accumulatedEntries =
|
||||
systemPrompt + profileEntries + projectProfileEntries + journalEntries + repoMapEntries +
|
||||
@@ -1015,16 +1022,24 @@ abstract class SessionOrchestrator(
|
||||
private suspend fun buildNeedsArtifactEntries(
|
||||
sessionId: SessionId,
|
||||
stageConfig: StageConfig,
|
||||
criticIds: Set<ArtifactId> = emptySet(),
|
||||
criticFromStage: String? = null,
|
||||
): List<ContextEntry> {
|
||||
return stageConfig.needs.mapNotNull { needed ->
|
||||
val cached = artifactContentCache["${sessionId.value}:${needed.value}"]
|
||||
?.takeIf { it.isNotBlank() } ?: return@mapNotNull null
|
||||
val content = "## Input artifact: ${needed.value}\n$cached"
|
||||
val content = if (needed in criticIds) {
|
||||
"## Critic feedback from stage '${criticFromStage ?: "reviewer"}': ${needed.value}\n" +
|
||||
"This is reviewer feedback on your previous attempt. " +
|
||||
"Address every finding before completing the stage.\n$cached"
|
||||
} else {
|
||||
"## Input artifact: ${needed.value}\n$cached"
|
||||
}
|
||||
ContextEntry(
|
||||
id = ContextEntryId(UUID.randomUUID().toString()),
|
||||
layer = ContextLayer.L1,
|
||||
content = content,
|
||||
sourceType = "neededArtifact",
|
||||
sourceType = if (needed in criticIds) "criticFeedback" else "neededArtifact",
|
||||
sourceId = needed.value,
|
||||
tokenEstimate = estimateTokens(content),
|
||||
role = EntryRole.USER,
|
||||
|
||||
Reference in New Issue
Block a user