refactor(config): move embedder/l3 to top-level [embedder]/[l3] sections

They are shared infra (the orchestrator uses them for workflow repo-knowledge,
not just the router chat layer), so [router.embedder]/[router.l3] was misleading.
Loader/writer use the new names; legacy [router.*] still read as a fallback.
Also notes the STEERING LLM-reformulation cost as a ponytail follow-up.
This commit is contained in:
2026-07-03 13:16:20 +04:00
parent 6437d29914
commit 77c28ba313
4 changed files with 18 additions and 7 deletions
@@ -419,8 +419,11 @@ object ConfigLoader {
val toolsFileWriteSection = sections["tools.file_write"] ?: emptyMap()
val toolsFileEditSection = sections["tools.file_edit"] ?: emptyMap()
val routerSection = sections["router"] ?: emptyMap()
val routerEmbedderSection = sections["router.embedder"] ?: emptyMap()
val routerL3Section = sections["router.l3"] ?: 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 modelsSection = sections["models"] ?: emptyMap()
@@ -56,13 +56,13 @@ object CorrexConfigWriter {
b.kv("retrieval_k", cfg.router.retrievalK)
b.kv("token_budget", cfg.router.tokenBudget)
b.section("router.embedder")
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.section("router.l3")
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))
@@ -186,6 +186,11 @@ class DefaultRouterFacade(
emitIdeasCaptured(sessionId, ideas.ideas)
}
// ponytail: STEERING launders the user's text through the router LLM (the `content` above)
// before injecting it as a note. For a clear instruction that's an extra inference that can
// distort intent; the reformulation only earns its cost when the input is terse/context-
// dependent. Upgrade path: inject the raw (validated) input directly and skip the rewrite
// unless a heuristic flags the message as too short/ambiguous to stand alone.
val steeringEmitted = mode == ChatMode.STEERING && rawContent.isNotBlank()
if (steeringEmitted) {
val validationError = validateSteering?.invoke(content)
+6 -3
View File
@@ -107,15 +107,18 @@ top_p = 0.9
max_tokens = 1024
max_per_run = 100
[router.embedder]
# Embedder + L3 vector memory. Shared infra: the orchestrator uses these for workflow
# repo-knowledge retrieval, not just the router chat layer — hence top-level, not [router.*].
# (Legacy [router.embedder] / [router.l3] are still read as a fallback.)
[embedder]
backend = "noop" # or "llamacpp"
dimension = 1536
# url = "http://127.0.0.1:11000"
# model_id = "nomic-embed-text"
[router.l3]
[l3]
backend = "in_memory" # or "turbovec"
# persist_path = "~/.config/correx/router/l3/index.tq"
# persist_path = "~/.config/correx/l3/index.tq"
# python_executable = "python3"
# script_path = "~/.config/correx/python/turbovec_sidecar.py"
# dim = 1536