feat: externalize LLM providers and tool enable flags via config

Adds ProviderConfig + providers list and per-tool enabled flags to
CorrexConfig, and rewires apps/server/Main to build the provider list
from config instead of the hardcoded buildLlamaProvider() factory. Env
vars (CORREX_MODEL_ID, CORREX_MODEL_PATH, CORREX_LLAMA_URL) remain a
fallback only when no providers are declared in config.

Completes slice A of the config layer alongside commit 0834c70 which
already shipped the TOML parser upgrade and sample config — those
parser changes referenced these types but were committed prematurely
in isolation; this commit makes HEAD buildable.
This commit is contained in:
2026-05-30 01:15:55 +04:00
parent 0834c705fd
commit 84a7568e15
2 changed files with 89 additions and 14 deletions
@@ -6,13 +6,17 @@ import com.correx.apps.server.registry.ProviderRegistry
import com.correx.core.approvals.domain.DefaultApprovalEngine
import com.correx.core.artifactstore.ArtifactStore
import com.correx.core.config.ConfigLoader
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.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.InferenceProjector
import com.correx.core.inference.InferenceRepository
import com.correx.core.inference.ModelCapability
import com.correx.core.kernel.orchestration.DefaultOrchestrationReducer
import com.correx.core.kernel.orchestration.DefaultSessionOrchestrator
import com.correx.core.kernel.orchestration.OrchestrationConfig
@@ -37,6 +41,7 @@ import com.correx.infrastructure.inference.DefaultProviderRegistry
import com.correx.infrastructure.inference.FirstAvailableRoutingStrategy
import com.correx.infrastructure.inference.llama.cpp.LlamaCppInferenceProvider
import com.correx.infrastructure.tools.FileEditConfig
import com.correx.infrastructure.tools.FileReadConfig
import com.correx.infrastructure.tools.FileWriteConfig
import com.correx.infrastructure.tools.ShellConfig
import com.correx.infrastructure.tools.ToolConfig
@@ -56,17 +61,19 @@ fun main() {
logStoresInfo(eventStore, artifactStore)
val llamaProvider = buildLlamaProvider()
val infraRegistry = InfrastructureModule.createProviderRegistry(listOf(llamaProvider))
val modelId = System.getenv("CORREX_MODEL_ID") ?: "default"
val modelPath = System.getenv("CORREX_MODEL_PATH") ?: "(not set)"
val llamaUrl = System.getenv("CORREX_LLAMA_URL") ?: "http://127.0.0.1:10000"
val correxConfig = ConfigLoader.load()
val providers = buildProviders(correxConfig)
require(providers.isNotEmpty()) { "At least one provider must be configured" }
val infraRegistry = InfrastructureModule.createProviderRegistry(providers)
val llamaProvider = providers.first()
val modelId = llamaProvider.id.value
val modelPath = "(from config)"
val llamaUrl = "(from config)"
logModelInfo(modelId, modelPath, llamaUrl, infraRegistry)
val repositories = buildRepositories(eventStore)
val approvalEngine = DefaultApprovalEngine()
val correxConfig = ConfigLoader.load()
val toolsConfig = correxConfig.tools
val sandboxRoot = System.getenv("CORREX_SANDBOX_ROOT")
?.let { Path.of(it) }
@@ -83,6 +90,7 @@ fun main() {
sandboxRoot,
workingDir,
shellAllowedExecutables,
toolsConfig,
),
)
val toolExecutor = InfrastructureModule.createToolExecutor(
@@ -180,11 +188,58 @@ private fun logStoresInfo(
log.info(" artifact store: {}", artifactStore::class.simpleName)
}
private fun buildLlamaProvider(): LlamaCppInferenceProvider = InfrastructureModule.createLlamaCppProvider(
modelId = System.getenv("CORREX_MODEL_ID") ?: "default",
modelPath = System.getenv("CORREX_MODEL_PATH") ?: "",
baseUrl = System.getenv("CORREX_LLAMA_URL") ?: "http://127.0.0.1:10000",
)
private fun buildProviders(config: CorrexConfig): List<LlamaCppInferenceProvider> {
return if (config.providers.isNotEmpty()) {
log.info("Loading {} provider(s) from config", config.providers.size)
config.providers.mapNotNull { providerConfig ->
when (providerConfig.type.lowercase()) {
"llamacpp" -> buildProviderFromConfig(providerConfig)
else -> {
log.error("Unknown provider type: {}", providerConfig.type)
null
}
}
}
} else {
log.info("No providers in config; using env var fallback")
listOf(
InfrastructureModule.createLlamaCppProvider(
modelId = System.getenv("CORREX_MODEL_ID") ?: "default",
modelPath = System.getenv("CORREX_MODEL_PATH") ?: "",
baseUrl = System.getenv("CORREX_LLAMA_URL") ?: "http://127.0.0.1:10000",
),
)
}
}
private fun buildProviderFromConfig(config: ProviderConfig): LlamaCppInferenceProvider {
val capabilities = parseCapabilitiesFromConfig(config.capabilities)
return InfrastructureModule.createLlamaCppProvider(
modelId = config.modelId,
modelPath = config.modelPath,
baseUrl = config.url,
capabilities = capabilities,
)
}
private fun parseCapabilitiesFromConfig(capsMap: Map<String, Double>): Set<CapabilityScore> {
val result = mutableSetOf<CapabilityScore>()
capsMap.forEach { (capName, score) ->
val capability = when (capName.lowercase()) {
"general" -> ModelCapability.General
"coding" -> ModelCapability.Coding
"reasoning" -> ModelCapability.Reasoning
"summarization" -> ModelCapability.Summarization
"toolcalling" -> ModelCapability.ToolCalling
else -> {
log.warn("Unknown capability name: {}", capName)
return@forEach
}
}
result.add(CapabilityScore(capability, score))
}
return result
}
private fun buildRepositories(
eventStore: EventStore,
@@ -206,22 +261,27 @@ private fun buildToolConfig(
sandboxRoot: Path,
workingDir: Path,
shellAllowedExecutables: Set<String>,
toolsConfig: com.correx.core.config.ToolsConfig,
): ToolConfig = ToolConfig(
shell = ShellConfig(
enabled = true,
enabled = toolsConfig.shellEnabled,
allowedExecutables = shellAllowedExecutables,
workingDir = workingDir,
),
fileRead = FileReadConfig(
enabled = toolsConfig.fileReadEnabled,
allowedPaths = setOf(sandboxRoot, workingDir),
),
fileWrite = FileWriteConfig(
allowedPaths = setOf(sandboxRoot, workingDir),
enabled = true,
enabled = toolsConfig.fileWriteEnabled,
artifactStore = artifactStore,
materializingWriter = DefaultMaterializingArtifactWriter(),
sandboxRoot = sandboxRoot,
workingDir = workingDir,
),
fileEdit = FileEditConfig(
enabled = true,
enabled = toolsConfig.fileEditEnabled,
allowedPaths = setOf(sandboxRoot, workingDir),
workingDir = workingDir,
),