feat(config): expose router generation + narration knobs in config file

The router/narration model behaviour was hardcoded (Main built RouterConfig()
with defaults). Surface it under the [router] section so it's tunable without a
rebuild:

  [router]            conversation_keep_last, retrieval_k, token_budget
  [router.generation] temperature, top_p, max_tokens          (chat/steering)
  [router.narration]  temperature, top_p, max_tokens, max_per_run

ConfigLoader parses the new sections (adds asDouble); Main maps the config-layer
RouterConfig onto the domain RouterConfig and threads narration.max_per_run into
ServerModule. All values default to the previous constants, so behaviour is
unchanged when the sections are absent. Documents the block in sample-config.toml
and adds parser tests for present/absent cases.
This commit is contained in:
2026-06-03 23:09:48 +04:00
parent e95d2633f8
commit 371e0df340
5 changed files with 141 additions and 1 deletions
@@ -14,10 +14,12 @@ import com.correx.core.config.CorrexConfig
import com.correx.core.config.ProviderConfig
import com.correx.core.context.builder.DefaultContextPackBuilder
import com.correx.core.context.compression.DefaultContextCompressor
import com.correx.core.context.model.TokenBudget
import com.correx.core.events.EventDispatcher
import com.correx.core.events.stores.EventStore
import com.correx.core.inference.CapabilityScore
import com.correx.core.inference.DefaultInferenceRouter
import com.correx.core.inference.GenerationConfig
import com.correx.core.inference.InferenceProjector
import com.correx.core.inference.InferenceRepository
import com.correx.core.inference.InferenceRouter
@@ -246,10 +248,26 @@ fun main() {
// persisted vectors survive restart but the metadata map does not (no-op for
// non-rehydratable backends like in_memory).
runBlocking { L3MetadataRehydrator(eventStore).rehydrate(l3MemoryStore) }
// Map the config-file [router] block onto the domain RouterConfig the facade uses.
val domainRouterConfig = RouterConfig(
conversationKeepLast = routerConfig.conversationKeepLast,
retrievalK = routerConfig.retrievalK,
tokenBudget = TokenBudget(limit = routerConfig.tokenBudget),
generationConfig = GenerationConfig(
temperature = routerConfig.generation.temperature,
topP = routerConfig.generation.topP,
maxTokens = routerConfig.generation.maxTokens,
),
narrationGenerationConfig = GenerationConfig(
temperature = routerConfig.narration.temperature,
topP = routerConfig.narration.topP,
maxTokens = routerConfig.narration.maxTokens,
),
)
val routerFacade = InfrastructureModule.createRouterFacade(
eventStore = eventStore,
inferenceRouter = inferenceRouter,
config = RouterConfig(),
config = domainRouterConfig,
tokenizer = firstProvider.tokenizer,
embedder = embedder,
l3MemoryStore = l3MemoryStore,
@@ -289,6 +307,7 @@ fun main() {
modelSwapper = modelSwapper,
resourceProbe = resourceProbe,
workspaceResolver = workspaceResolver,
narrationMaxPerRun = routerConfig.narration.maxPerRun,
)
module.start()
log.info("==============================")