feat(router): inject available-workflows and project-profile into router L0 context
This commit is contained in:
@@ -17,11 +17,17 @@ import com.correx.core.router.model.RouterL2Entry
|
|||||||
import com.correx.core.router.model.RouterState
|
import com.correx.core.router.model.RouterState
|
||||||
import com.correx.core.router.model.RouterTurn
|
import com.correx.core.router.model.RouterTurn
|
||||||
import com.correx.core.router.model.TurnRole
|
import com.correx.core.router.model.TurnRole
|
||||||
|
import com.correx.core.router.model.WorkflowSummary
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
|
|
||||||
interface RouterContextBuilder {
|
interface RouterContextBuilder {
|
||||||
suspend fun build(state: RouterState, budget: TokenBudget): ContextPack
|
suspend fun build(
|
||||||
|
state: RouterState,
|
||||||
|
budget: TokenBudget,
|
||||||
|
availableWorkflows: List<WorkflowSummary> = emptyList(),
|
||||||
|
projectProfileText: String? = null,
|
||||||
|
): ContextPack
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a minimal [ContextPack] for a narration inference call.
|
* Builds a minimal [ContextPack] for a narration inference call.
|
||||||
@@ -32,7 +38,7 @@ interface RouterContextBuilder {
|
|||||||
* without needing a stub override.
|
* without needing a stub override.
|
||||||
*/
|
*/
|
||||||
suspend fun buildNarrationContext(state: RouterState, trigger: NarrationTrigger, budget: TokenBudget): ContextPack =
|
suspend fun buildNarrationContext(state: RouterState, trigger: NarrationTrigger, budget: TokenBudget): ContextPack =
|
||||||
build(state, budget)
|
build(state, budget, emptyList(), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
class DefaultRouterContextBuilder(
|
class DefaultRouterContextBuilder(
|
||||||
@@ -68,7 +74,12 @@ class DefaultRouterContextBuilder(
|
|||||||
private const val RECALLED_MEMORY_PREFIX = "[recalled memory]"
|
private const val RECALLED_MEMORY_PREFIX = "[recalled memory]"
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack {
|
override suspend fun build(
|
||||||
|
state: RouterState,
|
||||||
|
budget: TokenBudget,
|
||||||
|
availableWorkflows: List<WorkflowSummary>,
|
||||||
|
projectProfileText: String?,
|
||||||
|
): ContextPack {
|
||||||
// Protected frame: system prompt and workflow status are ALWAYS included regardless of budget.
|
// Protected frame: system prompt and workflow status are ALWAYS included regardless of budget.
|
||||||
val systemPrompt = buildContextEntry(
|
val systemPrompt = buildContextEntry(
|
||||||
sourceType = "systemPrompt",
|
sourceType = "systemPrompt",
|
||||||
@@ -84,14 +95,39 @@ class DefaultRouterContextBuilder(
|
|||||||
layer = ContextLayer.L0,
|
layer = ContextLayer.L0,
|
||||||
role = EntryRole.SYSTEM,
|
role = EntryRole.SYSTEM,
|
||||||
)
|
)
|
||||||
|
val availableWorkflowsEntry: ContextEntry? = availableWorkflows
|
||||||
|
.takeIf { it.isNotEmpty() }
|
||||||
|
?.let {
|
||||||
|
buildContextEntry(
|
||||||
|
sourceType = "availableWorkflows",
|
||||||
|
sourceId = "available-workflows",
|
||||||
|
content = buildAvailableWorkflowsContent(it),
|
||||||
|
layer = ContextLayer.L0,
|
||||||
|
role = EntryRole.SYSTEM,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val projectProfileEntry: ContextEntry? = projectProfileText
|
||||||
|
?.takeIf { it.isNotBlank() }
|
||||||
|
?.let {
|
||||||
|
buildContextEntry(
|
||||||
|
sourceType = "projectProfile",
|
||||||
|
sourceId = "project-profile",
|
||||||
|
content = it,
|
||||||
|
layer = ContextLayer.L0,
|
||||||
|
role = EntryRole.SYSTEM,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Compute remaining budget after protected frame.
|
// Compute remaining budget after protected frame.
|
||||||
val protectedTokens = systemPrompt.tokenEstimate + workflowStatusEntry.tokenEstimate
|
val protectedTokens = systemPrompt.tokenEstimate + workflowStatusEntry.tokenEstimate +
|
||||||
|
(availableWorkflowsEntry?.tokenEstimate ?: 0) + (projectProfileEntry?.tokenEstimate ?: 0)
|
||||||
var remainingBudget = (budget.limit - protectedTokens).coerceAtLeast(0)
|
var remainingBudget = (budget.limit - protectedTokens).coerceAtLeast(0)
|
||||||
|
|
||||||
val allEntries = mutableListOf<ContextEntry>()
|
val allEntries = mutableListOf<ContextEntry>()
|
||||||
allEntries += systemPrompt
|
allEntries += systemPrompt
|
||||||
allEntries += workflowStatusEntry
|
allEntries += workflowStatusEntry
|
||||||
|
availableWorkflowsEntry?.let { allEntries += it }
|
||||||
|
projectProfileEntry?.let { allEntries += it }
|
||||||
|
|
||||||
var droppedCount = 0
|
var droppedCount = 0
|
||||||
val truncatedLayers = mutableSetOf<ContextLayer>()
|
val truncatedLayers = mutableSetOf<ContextLayer>()
|
||||||
@@ -258,6 +294,14 @@ class DefaultRouterContextBuilder(
|
|||||||
return base + reason + steering
|
return base + reason + steering
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun buildAvailableWorkflowsContent(workflows: List<WorkflowSummary>): String =
|
||||||
|
buildString {
|
||||||
|
append("## Available workflows\n")
|
||||||
|
workflows.forEach { wf ->
|
||||||
|
append("- ${wf.id}: ${wf.description} (stages: ${wf.stageIds.joinToString(" → ")})\n")
|
||||||
|
}
|
||||||
|
}.trimEnd()
|
||||||
|
|
||||||
private suspend fun buildContextEntry(
|
private suspend fun buildContextEntry(
|
||||||
sourceType: String,
|
sourceType: String,
|
||||||
sourceId: String,
|
sourceId: String,
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.correx.core.router.model
|
||||||
|
|
||||||
|
data class WorkflowSummary(
|
||||||
|
val id: String,
|
||||||
|
val description: String,
|
||||||
|
val stageIds: List<String>,
|
||||||
|
)
|
||||||
@@ -7,6 +7,7 @@ import com.correx.core.events.types.SessionId
|
|||||||
import com.correx.core.events.types.StageId
|
import com.correx.core.events.types.StageId
|
||||||
import com.correx.core.router.DefaultRouterContextBuilder
|
import com.correx.core.router.DefaultRouterContextBuilder
|
||||||
import com.correx.core.router.model.RouterConfig
|
import com.correx.core.router.model.RouterConfig
|
||||||
|
import com.correx.core.router.model.WorkflowSummary
|
||||||
import com.correx.core.router.model.RouterL2Entry
|
import com.correx.core.router.model.RouterL2Entry
|
||||||
import com.correx.core.router.model.RouterState
|
import com.correx.core.router.model.RouterState
|
||||||
import com.correx.core.router.model.RouterTurn
|
import com.correx.core.router.model.RouterTurn
|
||||||
@@ -19,6 +20,7 @@ import kotlinx.datetime.Instant
|
|||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import org.junit.jupiter.api.Assertions.assertFalse
|
import org.junit.jupiter.api.Assertions.assertFalse
|
||||||
import org.junit.jupiter.api.Assertions.assertNotNull
|
import org.junit.jupiter.api.Assertions.assertNotNull
|
||||||
|
import org.junit.jupiter.api.Assertions.assertNull
|
||||||
import org.junit.jupiter.api.Assertions.assertTrue
|
import org.junit.jupiter.api.Assertions.assertTrue
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
@@ -805,6 +807,40 @@ class RouterContextBuilderTest {
|
|||||||
assertTrue(pack.compressionMetadata.entriesDropped >= 2)
|
assertTrue(pack.compressionMetadata.entriesDropped >= 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
// A2: availableWorkflows and projectProfileText L0 injection
|
||||||
|
// --------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `available workflows entry is injected into L0 when non-empty`() {
|
||||||
|
val workflows = listOf(WorkflowSummary("healthcheck", "Runs the health check pipeline", listOf("collect", "report")))
|
||||||
|
val pack = runBlocking { builder.build(RouterState(), TokenBudget(limit = 10000), availableWorkflows = workflows) }
|
||||||
|
val entry = (pack.layers[ContextLayer.L0] ?: emptyList()).find { it.sourceType == "availableWorkflows" }
|
||||||
|
assertNotNull(entry)
|
||||||
|
assertTrue(entry!!.content.contains("## Available workflows"))
|
||||||
|
assertTrue(entry.content.contains("healthcheck: Runs the health check pipeline (stages: collect → report)"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `available workflows entry is omitted when list is empty`() {
|
||||||
|
val pack = runBlocking { builder.build(RouterState(), TokenBudget(limit = 10000)) }
|
||||||
|
assertNull((pack.layers[ContextLayer.L0] ?: emptyList()).find { it.sourceType == "availableWorkflows" })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `project profile text is injected into L0 when non-null`() {
|
||||||
|
val text = "## Project profile\nA Kotlin service.\n### Conventions\n- Use runCatching"
|
||||||
|
val pack = runBlocking { builder.build(RouterState(), TokenBudget(limit = 10000), projectProfileText = text) }
|
||||||
|
val entry = (pack.layers[ContextLayer.L0] ?: emptyList()).find { it.sourceType == "projectProfile" }
|
||||||
|
assertEquals(text, entry!!.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `project profile text is omitted when null or blank`() {
|
||||||
|
val pack = runBlocking { builder.build(RouterState(), TokenBudget(limit = 10000), projectProfileText = " ") }
|
||||||
|
assertNull((pack.layers[ContextLayer.L0] ?: emptyList()).find { it.sourceType == "projectProfile" })
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `truncatedLayers populated with affected layers when drops occur`() {
|
fun `truncatedLayers populated with affected layers when drops occur`() {
|
||||||
val longText = "x".repeat(800)
|
val longText = "x".repeat(800)
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import com.correx.core.router.model.RouterResponse
|
|||||||
import com.correx.core.router.model.RouterState
|
import com.correx.core.router.model.RouterState
|
||||||
import com.correx.core.router.model.RouterTurn
|
import com.correx.core.router.model.RouterTurn
|
||||||
import com.correx.core.router.model.TurnRole
|
import com.correx.core.router.model.TurnRole
|
||||||
|
import com.correx.core.router.model.WorkflowSummary
|
||||||
import com.correx.core.router.model.WorkflowStatus
|
import com.correx.core.router.model.WorkflowStatus
|
||||||
import com.correx.core.sessions.projections.replay.DefaultEventReplayer
|
import com.correx.core.sessions.projections.replay.DefaultEventReplayer
|
||||||
import com.correx.testing.fixtures.EventFixtures
|
import com.correx.testing.fixtures.EventFixtures
|
||||||
@@ -142,7 +143,7 @@ class RouterFacadeTest {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter("steering response"),
|
inferenceRouter = mockInferenceRouter("steering response"),
|
||||||
eventStore = mockStore,
|
eventStore = mockStore,
|
||||||
@@ -175,7 +176,7 @@ class RouterFacadeTest {
|
|||||||
replayer.rebuild(sessionId)
|
replayer.rebuild(sessionId)
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack {
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack {
|
||||||
capturedStates.add(state)
|
capturedStates.add(state)
|
||||||
return emptyContextPack()
|
return emptyContextPack()
|
||||||
}
|
}
|
||||||
@@ -215,7 +216,7 @@ class RouterFacadeTest {
|
|||||||
replayer.rebuild(sessionId)
|
replayer.rebuild(sessionId)
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack {
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack {
|
||||||
capturedStates.add(state)
|
capturedStates.add(state)
|
||||||
return emptyContextPack()
|
return emptyContextPack()
|
||||||
}
|
}
|
||||||
@@ -245,7 +246,7 @@ class RouterFacadeTest {
|
|||||||
fun `state is passed through to context builder`(): Unit = runBlocking {
|
fun `state is passed through to context builder`(): Unit = runBlocking {
|
||||||
val capturedState = mutableListOf<RouterState>()
|
val capturedState = mutableListOf<RouterState>()
|
||||||
val mockContextBuilder = object : RouterContextBuilder {
|
val mockContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack {
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack {
|
||||||
capturedState.add(state)
|
capturedState.add(state)
|
||||||
return emptyContextPack()
|
return emptyContextPack()
|
||||||
}
|
}
|
||||||
@@ -276,7 +277,7 @@ class RouterFacadeTest {
|
|||||||
fun `budget is passed through to context builder`(): Unit = runBlocking {
|
fun `budget is passed through to context builder`(): Unit = runBlocking {
|
||||||
val capturedBudget = mutableListOf<TokenBudget>()
|
val capturedBudget = mutableListOf<TokenBudget>()
|
||||||
val mockContextBuilder = object : RouterContextBuilder {
|
val mockContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack {
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack {
|
||||||
capturedBudget.add(budget)
|
capturedBudget.add(budget)
|
||||||
return emptyContextPack()
|
return emptyContextPack()
|
||||||
}
|
}
|
||||||
@@ -319,7 +320,7 @@ class RouterFacadeTest {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter,
|
inferenceRouter = mockInferenceRouter,
|
||||||
eventStore = mockEventStore(),
|
eventStore = mockEventStore(),
|
||||||
@@ -352,7 +353,7 @@ class RouterFacadeTest {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter,
|
inferenceRouter = mockInferenceRouter,
|
||||||
eventStore = mockEventStore(),
|
eventStore = mockEventStore(),
|
||||||
@@ -380,7 +381,7 @@ class RouterFacadeTest {
|
|||||||
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter,
|
inferenceRouter = mockInferenceRouter,
|
||||||
eventStore = mockEventStore(),
|
eventStore = mockEventStore(),
|
||||||
@@ -410,7 +411,7 @@ class RouterFacadeTest {
|
|||||||
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter,
|
inferenceRouter = mockInferenceRouter,
|
||||||
eventStore = mockEventStore(),
|
eventStore = mockEventStore(),
|
||||||
@@ -433,7 +434,7 @@ class RouterFacadeTest {
|
|||||||
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack {
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack {
|
||||||
val pack = ContextPack(
|
val pack = ContextPack(
|
||||||
id = ContextPackId("test-pack"),
|
id = ContextPackId("test-pack"),
|
||||||
sessionId = state.sessionId ?: SessionId("unknown"),
|
sessionId = state.sessionId ?: SessionId("unknown"),
|
||||||
@@ -490,7 +491,7 @@ class RouterFacadeTest {
|
|||||||
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = object : InferenceRouter {
|
inferenceRouter = object : InferenceRouter {
|
||||||
override suspend fun route(
|
override suspend fun route(
|
||||||
@@ -578,7 +579,7 @@ class RouterFacadeTest {
|
|||||||
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = object : InferenceRouter {
|
inferenceRouter = object : InferenceRouter {
|
||||||
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider =
|
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider =
|
||||||
@@ -636,7 +637,7 @@ class RouterFacadeTest {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter("inference response"),
|
inferenceRouter = mockInferenceRouter("inference response"),
|
||||||
eventStore = eventStore,
|
eventStore = eventStore,
|
||||||
@@ -769,7 +770,7 @@ class RouterFacadeTest {
|
|||||||
replayer.rebuild(sessionId)
|
replayer.rebuild(sessionId)
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter("router reply"),
|
inferenceRouter = mockInferenceRouter("router reply"),
|
||||||
eventStore = eventStore,
|
eventStore = eventStore,
|
||||||
@@ -847,7 +848,7 @@ class RouterFacadeTest {
|
|||||||
replayer.rebuild(sessionId)
|
replayer.rebuild(sessionId)
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter("router reply"),
|
inferenceRouter = mockInferenceRouter("router reply"),
|
||||||
eventStore = eventStore,
|
eventStore = eventStore,
|
||||||
@@ -878,7 +879,7 @@ class RouterFacadeTest {
|
|||||||
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter("response"),
|
inferenceRouter = mockInferenceRouter("response"),
|
||||||
eventStore = eventStore,
|
eventStore = eventStore,
|
||||||
@@ -1093,7 +1094,7 @@ class RouterFacadeTest {
|
|||||||
private val real = DefaultRouterContextBuilder(
|
private val real = DefaultRouterContextBuilder(
|
||||||
config = RouterConfig(tokenBudget = TokenBudget(limit = 10000)),
|
config = RouterConfig(tokenBudget = TokenBudget(limit = 10000)),
|
||||||
)
|
)
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack {
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack {
|
||||||
capturedStates.add(state)
|
capturedStates.add(state)
|
||||||
return real.build(state, budget)
|
return real.build(state, budget)
|
||||||
}
|
}
|
||||||
@@ -1165,7 +1166,7 @@ class RouterFacadeTest {
|
|||||||
private val real = DefaultRouterContextBuilder(
|
private val real = DefaultRouterContextBuilder(
|
||||||
config = RouterConfig(tokenBudget = TokenBudget(limit = 10000)),
|
config = RouterConfig(tokenBudget = TokenBudget(limit = 10000)),
|
||||||
)
|
)
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack =
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack =
|
||||||
real.build(state, budget).also { capturedPacks.add(it) }
|
real.build(state, budget).also { capturedPacks.add(it) }
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter("router reply"),
|
inferenceRouter = mockInferenceRouter("router reply"),
|
||||||
@@ -1213,7 +1214,7 @@ class RouterFacadeTest {
|
|||||||
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter,
|
inferenceRouter = mockInferenceRouter,
|
||||||
eventStore = mockEventStore(),
|
eventStore = mockEventStore(),
|
||||||
@@ -1258,7 +1259,7 @@ class RouterFacadeTest {
|
|||||||
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
override suspend fun getRouterState(sessionId: SessionId): RouterState = RouterState()
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter,
|
inferenceRouter = mockInferenceRouter,
|
||||||
eventStore = mockEventStore(),
|
eventStore = mockEventStore(),
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import com.correx.core.router.model.NarrationTrigger
|
|||||||
import com.correx.core.router.model.RouterConfig
|
import com.correx.core.router.model.RouterConfig
|
||||||
import com.correx.core.router.model.RouterState
|
import com.correx.core.router.model.RouterState
|
||||||
import com.correx.core.router.model.WorkflowStatus
|
import com.correx.core.router.model.WorkflowStatus
|
||||||
|
import com.correx.core.router.model.WorkflowSummary
|
||||||
import com.correx.testing.fixtures.inference.MockTokenizer
|
import com.correx.testing.fixtures.inference.MockTokenizer
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
@@ -141,7 +142,7 @@ class RouterNarrationTest {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
routerContextBuilder = object : RouterContextBuilder {
|
routerContextBuilder = object : RouterContextBuilder {
|
||||||
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun build(state: RouterState, budget: TokenBudget, availableWorkflows: List<WorkflowSummary>, projectProfileText: String?): ContextPack = emptyContextPack()
|
||||||
override suspend fun buildNarrationContext(state: RouterState, trigger: NarrationTrigger, budget: TokenBudget): ContextPack = emptyContextPack()
|
override suspend fun buildNarrationContext(state: RouterState, trigger: NarrationTrigger, budget: TokenBudget): ContextPack = emptyContextPack()
|
||||||
},
|
},
|
||||||
inferenceRouter = mockInferenceRouter("stage narration", latencyMs = 10L, tokensUsed = TokenUsage(1, 1)),
|
inferenceRouter = mockInferenceRouter("stage narration", latencyMs = 10L, tokensUsed = TokenUsage(1, 1)),
|
||||||
|
|||||||
Reference in New Issue
Block a user