12#include "../inference/session_pool_util.h"
15#include "../inference/expert_offload.h"
19namespace entropic::config {
30 for (
const auto& entry : tools) {
31 if (entry.find(
'.') == std::string::npos) {
32 return "allowed_tools entry '" + entry
33 +
"' must use '{server_name}.{tool_name}' format";
51 if (
config.context_length < 512 ||
config.context_length > 131072) {
52 err =
"context_length must be in [512, 131072], got "
53 + std::to_string(
config.context_length);
54 }
else if (
config.adapter.empty()) {
55 err =
"adapter must not be empty";
56 }
else if (
config.n_batch < 1) {
57 err =
"n_batch must be >= 1, got "
58 + std::to_string(
config.n_batch);
59 }
else if (
config.allowed_tools.has_value()) {
93 return "default tier '" +
config.default_tier
110 if (
config.threshold_percent < 0.5f
111 ||
config.threshold_percent > 0.99f) {
112 err =
"compaction.threshold_percent must be in [0.5, 0.99], got "
113 + std::to_string(
config.threshold_percent);
114 }
else if (
config.warning_threshold_percent
115 >=
config.threshold_percent) {
116 err =
"compaction.warning_threshold_percent ("
117 + std::to_string(
config.warning_threshold_percent)
118 +
") must be less than threshold_percent ("
119 + std::to_string(
config.threshold_percent) +
")";
120 }
else if (
config.preserve_recent_turns < 1
121 ||
config.preserve_recent_turns > 10) {
122 err =
"compaction.preserve_recent_turns must be in [1, 10], got "
123 + std::to_string(
config.preserve_recent_turns);
124 }
else if (
config.tool_result_ttl < 1) {
133 err =
"compaction.tool_result_ttl must be >= 1, got "
134 + std::to_string(
config.tool_result_ttl);
150 const std::unordered_map<std::string, TierConfig>& tiers)
153 return "routing.fallback_tier '" +
fallback +
"' not in tiers";
167 const std::unordered_map<std::string, std::string>& tier_map,
168 const std::unordered_map<std::string, TierConfig>& tiers)
170 for (
const auto& [key,
tier] : tier_map) {
171 if (tiers.count(
tier) == 0) {
172 return "routing.tier_map['" + key +
"'] = '" +
tier
188 const std::unordered_map<std::string, std::vector<std::string>>&
rules,
189 const std::unordered_map<std::string, TierConfig>& tiers)
192 if (tiers.count(source) == 0) {
193 return "routing.handoff_rules key '" + source
196 for (
const auto& target :
targets) {
197 if (tiers.count(target) == 0) {
198 return "routing.handoff_rules['" + source
199 +
"'] contains '" + target +
"' not in tiers";
226 return "routing.classification_prompt is set but routing.tier_map is "
227 "empty — the router emits a digit that maps to no tier, so every "
228 "route falls back to the default (configure routing.tier_map)";
247 if (models.
tiers.empty()) {
250 err =
"routing.enabled is true but models.router is not configured";
277 const std::unordered_map<std::string, TierConfig>& tiers,
278 const std::unordered_map<std::string, std::vector<std::string>>&
282 for (
const auto& [name,
tier] : tiers) {
283 if (
tier.auto_chain.has_value() && !
tier.auto_chain->empty()
284 && handoff_rules.count(name) == 0) {
289 +
"' has auto_chain but no handoff_rules entry";
305 return "inference.prompt_cache: enabled=true but max_bytes=0";
322 for (
const auto& [name,
tier] : models.
tiers) {
325 err =
"models." + name +
": " +
err;
331 if (
err.empty() && models.
router.has_value()) {
334 err =
"models.router: " +
err;
351 if (!std::filesystem::is_directory(
dir,
ec)) {
return false; }
353 for (
const auto& entry : std::filesystem::directory_iterator(
dir,
ec)) {
354 if (entry.path().extension() ==
".gbnf") {
372 const std::filesystem::path&
data_dir)
374 std::vector<std::filesystem::path>
dirs;
375 if (!
config.config_dir.empty()) {
376 dirs.push_back(
config.config_dir /
"grammars");
396 const std::string&
stem,
397 const std::vector<std::filesystem::path>&
search_dirs)
402 if (std::filesystem::exists(
dir / (
stem +
".gbnf"),
ec)) {
418 const std::vector<std::filesystem::path>&
search_dirs)
421 return "no grammar search path is configured "
422 "(set config_dir, or install the bundled data directory)";
426 if (!list.empty()) { list +=
", "; }
427 list +=
dir.string();
445 const std::vector<std::filesystem::path>&
search_dirs)
448 for (
const auto& [name,
tier] :
config.models.tiers) {
449 if (!
tier.grammar.has_value()) {
continue; }
452 const auto stem =
tier.grammar->stem().string();
462 if (!list.empty()) { list +=
", "; }
465 return "grammar not resolvable yet for " + list
467 +
". Register each key with entropic_grammar_register_file() or "
468 "entropic_grammar_register() before the first run on that tier, "
469 "or place <stem>.gbnf in a grammar search path. A run on such a "
470 "tier before then fails with ENTROPIC_ERROR_GRAMMAR_NOT_FOUND "
471 "rather than decoding unconstrained (gh#154).";
486 s_log->info(
"Config validation start");
507 s_log->info(
"Config validation passed ({} warning(s))",
510 s_log->error(
"Config validation failed: {}",
err);
std::string err
size_exceeded, when set
const ReadWindow & w
Requested window.
spdlog initialization and logger access.
ENTROPIC_EXPORT std::shared_ptr< spdlog::logger > get(const std::string &name)
Get or create a named logger.
@ optional
optional: every escape asks the host's path approver
@ tier
The TIER's identity frontmatter grammar: stem (gh#154).
std::string session_pool_conflict_reason(const ModelConfig &cfg)
Why this tier's session-pool request cannot be honoured.
std::string expert_offload_conflict_reason(const ModelConfig &cfg)
Configuration-time refusal for a combination that cannot mean what it says.
std::string config
–config FILE
Auto-compaction configuration.
Model configuration for a single tier.
Configuration for all models (tiers + router).
std::optional< ModelConfig > router
Router model (separate from tiers)
std::unordered_map< std::string, TierConfig > tiers
Tier name → config.
Full parsed configuration.
Prompt caching configuration.
Configuration for model routing.
std::string fallback_tier
Fallback when routing fails.
std::unordered_map< std::string, std::vector< std::string > > handoff_rules
Tier handoff rules.
bool enabled
Enable routing.
std::optional< std::string > classification_prompt
Custom prompt (nullopt = auto)
std::unordered_map< std::string, std::string > tier_map
Classification → tier mapping.
static bool grammar_stem_resolves(const std::string &stem, const std::vector< std::filesystem::path > &search_dirs)
Whether <stem>.gbnf exists in any search directory.
static std::string describe_search_dirs(const std::vector< std::filesystem::path > &search_dirs)
Render the search-path list for an error message.
std::string validate_classification_routable(const RoutingConfig &routing)
A configured classification_prompt is inert without a tier_map.
static std::string validate_model_tiers(const ModelsConfig &models)
Validate model tiers and router.
static bool holds_grammars(const std::filesystem::path &dir)
Whether a directory holds at least one .gbnf file.
Config validation functions.
ENTROPIC_EXPORT std::string validate_handoff_rules(const std::unordered_map< std::string, std::vector< std::string > > &rules, const std::unordered_map< std::string, TierConfig > &tiers)
Check all handoff_rules keys and values exist in tiers.
ENTROPIC_EXPORT std::string validate_routing(const RoutingConfig &routing, const ModelsConfig &models)
Validate RoutingConfig against defined tiers.
ENTROPIC_EXPORT std::string validate_tier_map(const std::unordered_map< std::string, std::string > &tier_map, const std::unordered_map< std::string, TierConfig > &tiers)
Check all tier_map values exist in tiers.
ENTROPIC_EXPORT std::string validate_config(const ParsedConfig &config, std::vector< std::string > &warnings)
Validate the full ParsedConfig.
ENTROPIC_EXPORT std::string warn_unresolved_tier_grammars(const ParsedConfig &config, const std::vector< std::filesystem::path > &search_dirs)
Warn about a tier whose grammar: stem resolves to no .gbnf (gh#154).
ENTROPIC_EXPORT std::string validate_fallback_tier(const std::string &fallback, const std::unordered_map< std::string, TierConfig > &tiers)
Check fallback_tier exists in tiers.
ENTROPIC_EXPORT std::string warn_auto_chain_without_targets(const std::unordered_map< std::string, TierConfig > &tiers, const std::unordered_map< std::string, std::vector< std::string > > &handoff_rules)
Warn if tier has auto_chain but no handoff_rules entry.
ENTROPIC_EXPORT std::string validate(const ModelConfig &config)
Validate a ModelConfig.
ENTROPIC_EXPORT std::string validate_allowed_tools(const std::vector< std::string > &tools)
Validate allowed_tools entries use "server.tool" format.
ENTROPIC_EXPORT std::vector< std::filesystem::path > grammar_search_paths(const ParsedConfig &config, const std::filesystem::path &data_dir)
The directories a bare grammar stem is looked up in (gh#154).