feat(router): proper grounded system prompts for chat and narration

Replace the placeholder "You are a routing assistant" one-liner with two
purpose-written prompts: a conversational prompt that frames the router as
correx's operator-facing interface to the event-sourced engine (grounded in
workflow state, no fabrication, concise, steering-aware), and a dedicated
narrator prompt for buildNarrationContext that asks for one or two present-tense
sentences naming the stage and outcome.

The longer protected frame shifted token budgets, so the two L2 eviction tests
now size their budget from the measured protected-frame + per-entry cost instead
of hard-coded magic numbers, making them robust to prompt length.
This commit is contained in:
2026-06-03 22:44:32 +04:00
parent ad3ec1965d
commit e6084dcbda
2 changed files with 47 additions and 12 deletions
@@ -41,8 +41,30 @@ class DefaultRouterContextBuilder(
) : RouterContextBuilder {
companion object {
private const val SYSTEM_PROMPT =
"You are a routing assistant. Provide guidance based on workflow state and conversation context."
private val SYSTEM_PROMPT =
"""
You are correx's router — the conversational interface between the operator and a
local, event-sourced workflow engine. You are not the engine: stages, tools, and
approvals are run by the kernel and recorded as events. Your job is to help the
operator understand and steer what the engine is doing.
Ground every statement in the workflow state and conversation context you are given.
Never invent stages, tool results, file contents, or status you have not been shown;
if something is not in context, say you do not have it. Be concise and direct — plain
sentences, no filler. When the operator is steering an approval, help them state
clearly what they want changed.
""".trimIndent()
private val NARRATION_SYSTEM_PROMPT =
"""
You are correx's router, narrating a running workflow to the operator in their live
feed. In one or two short sentences, in your own voice, say what just happened and
what comes next. Be concrete and grounded in the workflow state you are given — name
the stage, the outcome, and the reason for any failure or pause. Do not use lists,
headings, or preamble, and do not invent details you were not given. Speak in the
present, as events unfold.
""".trimIndent()
private const val RECALLED_MEMORY_PREFIX = "[recalled memory]"
}
@@ -288,8 +310,8 @@ class DefaultRouterContextBuilder(
): ContextPack {
val systemPromptEntry = buildContextEntry(
sourceType = "systemPrompt",
sourceId = "router-system",
content = SYSTEM_PROMPT,
sourceId = "router-narration-system",
content = NARRATION_SYSTEM_PROMPT,
layer = ContextLayer.L0,
role = EntryRole.SYSTEM,
)