refactor: rename the router subsystem to Talkie

The 'router' name was misleading — it's the always-on conversational front-end
(CHAT triage + STEERING into a running workflow), not a routing layer, and it's
distinct from InferenceRouter. Rename core:router -> core:talkie, package
com.correx.core.router -> com.correx.core.talkie, and RouterFacade/Config/State/
Repository/ContextBuilder/Projector/Reducer/Response -> Talkie*. Config section
[router] -> [talkie] (legacy [router] still read as fallback).

Persisted wire formats are preserved: ChatTurnRole.ROUTER and the
RouterNarrationEvent @SerialName("RouterNarration") stay, so existing event
logs still replay. RouterNarrationEvent the class is now TalkieNarrationEvent.
This commit is contained in:
2026-07-03 13:26:00 +04:00
parent 77c28ba313
commit 595ec187bc
84 changed files with 736 additions and 734 deletions
@@ -418,14 +418,14 @@ object ConfigLoader {
val toolsFileReadSection = sections["tools.file_read"] ?: emptyMap()
val toolsFileWriteSection = sections["tools.file_write"] ?: emptyMap()
val toolsFileEditSection = sections["tools.file_edit"] ?: emptyMap()
val routerSection = sections["router"] ?: emptyMap()
val routerSection = sections["talkie"] ?: sections["router"] ?: emptyMap()
// Embedder + L3 are shared infra (the orchestrator uses them for workflow repo-knowledge,
// not just the router chat layer). Prefer the top-level [embedder]/[l3] sections; fall back
// to the legacy [router.embedder]/[router.l3] so existing configs keep working.
val routerEmbedderSection = sections["embedder"] ?: sections["router.embedder"] ?: emptyMap()
val routerL3Section = sections["l3"] ?: sections["router.l3"] ?: emptyMap()
val routerGenerationSection = sections["router.generation"] ?: emptyMap()
val routerNarrationSection = sections["router.narration"] ?: emptyMap()
val routerGenerationSection = sections["talkie.generation"] ?: sections["router.generation"] ?: emptyMap()
val routerNarrationSection = sections["talkie.narration"] ?: sections["router.narration"] ?: emptyMap()
val modelsSection = sections["models"] ?: emptyMap()
val server = ServerConfig(
@@ -575,7 +575,7 @@ object ConfigLoader {
modelId = asStringOrNull(routerNarrationSection["model_id"]),
)
val router = RouterConfig(
val router = TalkieConfig(
embedder = embedder,
l3 = l3,
conversationKeepLast = asInt(routerSection["conversation_keep_last"], 6),
@@ -655,7 +655,7 @@ object ConfigLoader {
cli = cli,
tools = tools,
providers = providers,
router = router,
talkie = router,
models = models,
modelsSettings = modelsSettings,
artifacts = artifacts,
@@ -9,7 +9,7 @@ data class CorrexConfig(
val cli: CliConfig = CliConfig(),
val tools: ToolsConfig = ToolsConfig(),
val providers: List<ProviderConfig> = emptyList(),
val router: RouterConfig = RouterConfig(),
val talkie: TalkieConfig = TalkieConfig(),
val models: List<ModelConfig> = emptyList(),
val modelsSettings: ModelsSettings = ModelsSettings(),
val artifacts: List<ArtifactKindConfig> = emptyList(),
@@ -189,7 +189,7 @@ data class ProviderConfig(
)
@Serializable
data class RouterConfig(
data class TalkieConfig(
val embedder: EmbedderConfig = EmbedderConfig(),
val l3: L3Config = L3Config(),
val conversationKeepLast: Int = 6,
@@ -51,36 +51,36 @@ object CorrexConfigWriter {
b.section("tools.file_edit")
b.kv("enabled", cfg.tools.fileEditEnabled)
b.section("router")
b.kv("conversation_keep_last", cfg.router.conversationKeepLast)
b.kv("retrieval_k", cfg.router.retrievalK)
b.kv("token_budget", cfg.router.tokenBudget)
b.section("talkie")
b.kv("conversation_keep_last", cfg.talkie.conversationKeepLast)
b.kv("retrieval_k", cfg.talkie.retrievalK)
b.kv("token_budget", cfg.talkie.tokenBudget)
b.section("embedder")
b.kv("backend", str(cfg.router.embedder.backend))
b.kv("dimension", cfg.router.embedder.dimension)
cfg.router.embedder.url?.let { b.kv("url", str(it)) }
cfg.router.embedder.modelId?.let { b.kv("model_id", str(it)) }
b.kv("backend", str(cfg.talkie.embedder.backend))
b.kv("dimension", cfg.talkie.embedder.dimension)
cfg.talkie.embedder.url?.let { b.kv("url", str(it)) }
cfg.talkie.embedder.modelId?.let { b.kv("model_id", str(it)) }
b.section("l3")
b.kv("backend", str(cfg.router.l3.backend))
cfg.router.l3.persistPath?.let { b.kv("persist_path", str(it)) }
b.kv("python_executable", str(cfg.router.l3.pythonExecutable))
cfg.router.l3.scriptPath?.let { b.kv("script_path", str(it)) }
b.kv("dim", cfg.router.l3.dim)
b.kv("bit_width", cfg.router.l3.bitWidth)
b.kv("backend", str(cfg.talkie.l3.backend))
cfg.talkie.l3.persistPath?.let { b.kv("persist_path", str(it)) }
b.kv("python_executable", str(cfg.talkie.l3.pythonExecutable))
cfg.talkie.l3.scriptPath?.let { b.kv("script_path", str(it)) }
b.kv("dim", cfg.talkie.l3.dim)
b.kv("bit_width", cfg.talkie.l3.bitWidth)
b.section("router.generation")
b.kv("temperature", cfg.router.generation.temperature)
b.kv("top_p", cfg.router.generation.topP)
b.kv("max_tokens", cfg.router.generation.maxTokens)
b.section("talkie.generation")
b.kv("temperature", cfg.talkie.generation.temperature)
b.kv("top_p", cfg.talkie.generation.topP)
b.kv("max_tokens", cfg.talkie.generation.maxTokens)
b.section("router.narration")
b.kv("temperature", cfg.router.narration.temperature)
b.kv("top_p", cfg.router.narration.topP)
b.kv("max_tokens", cfg.router.narration.maxTokens)
b.kv("max_per_run", cfg.router.narration.maxPerRun)
cfg.router.narration.modelId?.let { b.kv("model_id", str(it)) }
b.section("talkie.narration")
b.kv("temperature", cfg.talkie.narration.temperature)
b.kv("top_p", cfg.talkie.narration.topP)
b.kv("max_tokens", cfg.talkie.narration.maxTokens)
b.kv("max_per_run", cfg.talkie.narration.maxPerRun)
cfg.talkie.narration.modelId?.let { b.kv("model_id", str(it)) }
b.section("orchestration")
b.kv("stage_timeout_ms", cfg.orchestration.stageTimeoutMs)
@@ -87,57 +87,57 @@ object EditableConfig {
),
EditableField(
"router.conversation_keep_last", ConfigFieldType.INT,
getString = { it.router.conversationKeepLast.toString() },
getString = { it.talkie.conversationKeepLast.toString() },
withString = { c, v -> rtr(c) { it.copy(conversationKeepLast = int("router.conversation_keep_last", v)) } },
),
EditableField(
"router.retrieval_k", ConfigFieldType.INT,
getString = { it.router.retrievalK.toString() },
getString = { it.talkie.retrievalK.toString() },
withString = { c, v -> rtr(c) { it.copy(retrievalK = int("router.retrieval_k", v)) } },
),
EditableField(
"router.token_budget", ConfigFieldType.INT,
getString = { it.router.tokenBudget.toString() },
getString = { it.talkie.tokenBudget.toString() },
withString = { c, v -> rtr(c) { it.copy(tokenBudget = int("router.token_budget", v)) } },
),
EditableField(
"router.generation.temperature", ConfigFieldType.DOUBLE,
getString = { it.router.generation.temperature.toString() },
getString = { it.talkie.generation.temperature.toString() },
withString = { c, v -> gen(c) { it.copy(temperature = dbl("router.generation.temperature", v)) } },
),
EditableField(
"router.generation.top_p", ConfigFieldType.DOUBLE,
getString = { it.router.generation.topP.toString() },
getString = { it.talkie.generation.topP.toString() },
withString = { c, v -> gen(c) { it.copy(topP = dbl("router.generation.top_p", v)) } },
),
EditableField(
"router.generation.max_tokens", ConfigFieldType.INT,
getString = { it.router.generation.maxTokens.toString() },
getString = { it.talkie.generation.maxTokens.toString() },
withString = { c, v -> gen(c) { it.copy(maxTokens = int("router.generation.max_tokens", v)) } },
),
EditableField(
"router.narration.temperature", ConfigFieldType.DOUBLE,
getString = { it.router.narration.temperature.toString() },
getString = { it.talkie.narration.temperature.toString() },
withString = { c, v -> nar(c) { it.copy(temperature = dbl("router.narration.temperature", v)) } },
),
EditableField(
"router.narration.top_p", ConfigFieldType.DOUBLE,
getString = { it.router.narration.topP.toString() },
getString = { it.talkie.narration.topP.toString() },
withString = { c, v -> nar(c) { it.copy(topP = dbl("router.narration.top_p", v)) } },
),
EditableField(
"router.narration.max_tokens", ConfigFieldType.INT,
getString = { it.router.narration.maxTokens.toString() },
getString = { it.talkie.narration.maxTokens.toString() },
withString = { c, v -> nar(c) { it.copy(maxTokens = int("router.narration.max_tokens", v)) } },
),
EditableField(
"router.narration.max_per_run", ConfigFieldType.INT,
getString = { it.router.narration.maxPerRun.toString() },
getString = { it.talkie.narration.maxPerRun.toString() },
withString = { c, v -> nar(c) { it.copy(maxPerRun = int("router.narration.max_per_run", v)) } },
),
EditableField(
"router.narration.model_id", ConfigFieldType.STRING,
getString = { it.router.narration.modelId.orEmpty() },
getString = { it.talkie.narration.modelId.orEmpty() },
withString = { c, v -> nar(c) { it.copy(modelId = v.trim().ifBlank { null }) } },
),
EditableField(
@@ -215,7 +215,7 @@ private fun srv(c: CorrexConfig, f: (ServerConfig) -> ServerConfig) = c.copy(ser
private fun tui(c: CorrexConfig, f: (TuiConfig) -> TuiConfig) = c.copy(tui = f(c.tui))
private fun cli(c: CorrexConfig, f: (CliConfig) -> CliConfig) = c.copy(cli = f(c.cli))
private fun tls(c: CorrexConfig, f: (ToolsConfig) -> ToolsConfig) = c.copy(tools = f(c.tools))
private fun rtr(c: CorrexConfig, f: (RouterConfig) -> RouterConfig) = c.copy(router = f(c.router))
private fun rtr(c: CorrexConfig, f: (TalkieConfig) -> TalkieConfig) = c.copy(talkie = f(c.talkie))
private fun gen(c: CorrexConfig, f: (GenerationSettings) -> GenerationSettings) =
rtr(c) { it.copy(generation = f(it.generation)) }
private fun nar(c: CorrexConfig, f: (NarrationSettings) -> NarrationSettings) =
@@ -307,16 +307,16 @@ class ConfigLoaderTest {
parseTomlMethod.isAccessible = true
val result = parseTomlMethod.invoke(ConfigLoader, toml) as CorrexConfig
assertEquals("llamacpp", result.router.embedder.backend)
assertEquals(1536, result.router.embedder.dimension)
assertEquals("http://localhost:11000", result.router.embedder.url)
assertEquals("nomic-embed-text", result.router.embedder.modelId)
assertEquals("llamacpp", result.talkie.embedder.backend)
assertEquals(1536, result.talkie.embedder.dimension)
assertEquals("http://localhost:11000", result.talkie.embedder.url)
assertEquals("nomic-embed-text", result.talkie.embedder.modelId)
assertEquals("turbovec", result.router.l3.backend)
assertEquals("/tmp/router/l3.tq", result.router.l3.persistPath)
assertEquals("python3", result.router.l3.pythonExecutable)
assertEquals(1536, result.router.l3.dim)
assertEquals(4, result.router.l3.bitWidth)
assertEquals("turbovec", result.talkie.l3.backend)
assertEquals("/tmp/router/l3.tq", result.talkie.l3.persistPath)
assertEquals("python3", result.talkie.l3.pythonExecutable)
assertEquals(1536, result.talkie.l3.dim)
assertEquals(4, result.talkie.l3.bitWidth)
}
@Test
@@ -331,16 +331,16 @@ class ConfigLoaderTest {
parseTomlMethod.isAccessible = true
val result = parseTomlMethod.invoke(ConfigLoader, toml) as CorrexConfig
assertEquals("noop", result.router.embedder.backend)
assertEquals(1536, result.router.embedder.dimension)
assertEquals(null, result.router.embedder.url)
assertEquals(null, result.router.embedder.modelId)
assertEquals("noop", result.talkie.embedder.backend)
assertEquals(1536, result.talkie.embedder.dimension)
assertEquals(null, result.talkie.embedder.url)
assertEquals(null, result.talkie.embedder.modelId)
assertEquals("in_memory", result.router.l3.backend)
assertEquals(null, result.router.l3.persistPath)
assertEquals("python3", result.router.l3.pythonExecutable)
assertEquals(1536, result.router.l3.dim)
assertEquals(4, result.router.l3.bitWidth)
assertEquals("in_memory", result.talkie.l3.backend)
assertEquals(null, result.talkie.l3.persistPath)
assertEquals("python3", result.talkie.l3.pythonExecutable)
assertEquals(1536, result.talkie.l3.dim)
assertEquals(4, result.talkie.l3.bitWidth)
}
@Test
@@ -477,15 +477,15 @@ class ConfigLoaderTest {
parseTomlMethod.isAccessible = true
val result = parseTomlMethod.invoke(ConfigLoader, toml) as CorrexConfig
assertEquals(8, result.router.conversationKeepLast)
assertEquals(3, result.router.retrievalK)
assertEquals(8192, result.router.tokenBudget)
assertEquals(0.4, result.router.generation.temperature)
assertEquals(0.8, result.router.generation.topP)
assertEquals(600, result.router.generation.maxTokens)
assertEquals(0.55, result.router.narration.temperature)
assertEquals(2048, result.router.narration.maxTokens)
assertEquals(25, result.router.narration.maxPerRun)
assertEquals(8, result.talkie.conversationKeepLast)
assertEquals(3, result.talkie.retrievalK)
assertEquals(8192, result.talkie.tokenBudget)
assertEquals(0.4, result.talkie.generation.temperature)
assertEquals(0.8, result.talkie.generation.topP)
assertEquals(600, result.talkie.generation.maxTokens)
assertEquals(0.55, result.talkie.narration.temperature)
assertEquals(2048, result.talkie.narration.maxTokens)
assertEquals(25, result.talkie.narration.maxPerRun)
}
@Test
@@ -494,10 +494,10 @@ class ConfigLoaderTest {
parseTomlMethod.isAccessible = true
val result = parseTomlMethod.invoke(ConfigLoader, "[server]\nhost = \"x\"") as CorrexConfig
assertEquals(6, result.router.conversationKeepLast)
assertEquals(512, result.router.generation.maxTokens)
assertEquals(4096, result.router.narration.maxTokens)
assertEquals(100, result.router.narration.maxPerRun)
assertEquals(6, result.talkie.conversationKeepLast)
assertEquals(512, result.talkie.generation.maxTokens)
assertEquals(4096, result.talkie.narration.maxTokens)
assertEquals(100, result.talkie.narration.maxPerRun)
}
@Test
@@ -530,7 +530,7 @@ class ConfigLoaderTest {
val result = ConfigLoader.parseTomlForTest(toml)
assertEquals("llama-cpp:phi-3-mini", result.router.narration.modelId)
assertEquals("llama-cpp:phi-3-mini", result.talkie.narration.modelId)
}
@Test
@@ -542,6 +542,6 @@ class ConfigLoaderTest {
val result = ConfigLoader.parseTomlForTest(toml)
assertNull(result.router.narration.modelId)
assertNull(result.talkie.narration.modelId)
}
}
@@ -26,7 +26,7 @@ class CorrexConfigWriterTest {
shellAllowedExecutables = listOf("git", "ls"),
networkAllowedHosts = listOf("example.com"),
),
router = RouterConfig(
talkie = TalkieConfig(
conversationKeepLast = 7,
retrievalK = 4,
tokenBudget = 5000,
@@ -25,7 +25,7 @@ class EditableConfigTest {
CorrexConfig(),
mapOf("router.generation.temperature" to "0.25", "orchestration.stage_timeout_ms" to "90000"),
).getOrThrow()
assertEquals(0.25, out.router.generation.temperature)
assertEquals(0.25, out.talkie.generation.temperature)
assertEquals(90_000L, out.orchestration.stageTimeoutMs)
}