feat(config): relocate orchestration loop/threshold/budget constants to [orchestration] config

The kernel's ReAct-loop tuning constants (max tool rounds, read/rejection-loop
nudge thresholds, feedback issue cap, repo-map top-k/files-per-dir, docs catalog
cap, clarification-round cap, review-block confidence/retry cap, default
refinement, recovery/intent route budgets) were hardcoded in SessionOrchestrator/
DefaultSessionOrchestrator. Relocated to a new OrchestrationTuning value threaded
through the orchestrator constructor, mapped from CorrexConfig.orchestration in
Main.kt, parsed in ConfigLoader, written by CorrexConfigWriter. Defaults equal the
former constants so an absent [orchestration] section reproduces prior behavior.

Startup-load (not hot-reload); pure output-truncation caps left as constants.

Vikunja #46 (task 76).
This commit is contained in:
2026-07-12 17:45:54 +04:00
parent 8d7c827ebb
commit b2c7bbe401
7 changed files with 139 additions and 33 deletions
@@ -630,6 +630,19 @@ object ConfigLoader {
compressionLevel = asInt(orchestrationSection["compression_level"], 4),
tokenPrunerUrl =
asString(orchestrationSection["token_pruner_url"], "http://127.0.0.1:8199"),
maxToolRounds = asInt(orchestrationSection["max_tool_rounds"], 30),
readLoopNudgeThreshold = asInt(orchestrationSection["read_loop_nudge_threshold"], 3),
rejectionLoopNudgeThreshold = asInt(orchestrationSection["rejection_loop_nudge_threshold"], 3),
maxFeedbackIssues = asInt(orchestrationSection["max_feedback_issues"], 3),
repoMapInjectTopK = asInt(orchestrationSection["repo_map_inject_top_k"], 30),
repoMapFilesPerDir = asInt(orchestrationSection["repo_map_files_per_dir"], 8),
docsCatalogMax = asInt(orchestrationSection["docs_catalog_max"], 20),
maxClarificationRounds = asInt(orchestrationSection["max_clarification_rounds"], 3),
reviewBlockMinConfidence = asDouble(orchestrationSection["review_block_min_confidence"], 0.7),
reviewBlockRetryCap = asInt(orchestrationSection["review_block_retry_cap"], 20),
defaultMaxRefinement = asInt(orchestrationSection["default_max_refinement"], 3),
recoveryRouteBudget = asInt(orchestrationSection["recovery_route_budget"], 2),
intentRouteBudget = asInt(orchestrationSection["intent_route_budget"], 2),
)
val modelsSettings = ModelsSettings(
@@ -69,6 +69,25 @@ data class OrchestrationKnobs(
*/
val compressionLevel: Int = 4,
val tokenPrunerUrl: String = "http://127.0.0.1:8199",
/**
* Orchestration loop/threshold/budget tuning, read once at server startup. Defaults equal the
* kernel's former hardcoded constants — an absent section reproduces prior behavior. Reach for
* these when a local model misbehaves (thrashes a read loop, re-asks clarifications, gets trapped
* by a stubborn reviewer). Mirrors kernel OrchestrationTuning.
*/
val maxToolRounds: Int = 30,
val readLoopNudgeThreshold: Int = 3,
val rejectionLoopNudgeThreshold: Int = 3,
val maxFeedbackIssues: Int = 3,
val repoMapInjectTopK: Int = 30,
val repoMapFilesPerDir: Int = 8,
val docsCatalogMax: Int = 20,
val maxClarificationRounds: Int = 3,
val reviewBlockMinConfidence: Double = 0.7,
val reviewBlockRetryCap: Int = 20,
val defaultMaxRefinement: Int = 3,
val recoveryRouteBudget: Int = 2,
val intentRouteBudget: Int = 2,
)
@Serializable
@@ -86,6 +86,21 @@ object CorrexConfigWriter {
b.kv("stage_timeout_ms", cfg.orchestration.stageTimeoutMs)
b.kv("journal_compaction_token_threshold", cfg.orchestration.journalCompactionTokenThreshold)
b.kv("resume_abandoned_max_age_minutes", cfg.orchestration.resumeAbandonedMaxAgeMinutes)
b.kv("compression_level", cfg.orchestration.compressionLevel)
b.kv("token_pruner_url", cfg.orchestration.tokenPrunerUrl)
b.kv("max_tool_rounds", cfg.orchestration.maxToolRounds)
b.kv("read_loop_nudge_threshold", cfg.orchestration.readLoopNudgeThreshold)
b.kv("rejection_loop_nudge_threshold", cfg.orchestration.rejectionLoopNudgeThreshold)
b.kv("max_feedback_issues", cfg.orchestration.maxFeedbackIssues)
b.kv("repo_map_inject_top_k", cfg.orchestration.repoMapInjectTopK)
b.kv("repo_map_files_per_dir", cfg.orchestration.repoMapFilesPerDir)
b.kv("docs_catalog_max", cfg.orchestration.docsCatalogMax)
b.kv("max_clarification_rounds", cfg.orchestration.maxClarificationRounds)
b.kv("review_block_min_confidence", cfg.orchestration.reviewBlockMinConfidence)
b.kv("review_block_retry_cap", cfg.orchestration.reviewBlockRetryCap)
b.kv("default_max_refinement", cfg.orchestration.defaultMaxRefinement)
b.kv("recovery_route_budget", cfg.orchestration.recoveryRouteBudget)
b.kv("intent_route_budget", cfg.orchestration.intentRouteBudget)
b.section("personalization")
b.kv("enabled", cfg.personalization.enabled)