Entropic 2.9.4
Local-first agentic inference engine
Loading...
Searching...
No Matches
validate.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
10
11static auto s_log = entropic::log::get("config");
12
13namespace entropic::config {
14
22std::string validate_allowed_tools(const std::vector<std::string>& tools)
23{
24 for (const auto& entry : tools) {
25 if (entry.find('.') == std::string::npos) {
26 return "allowed_tools entry '" + entry
27 + "' must use '{server_name}.{tool_name}' format";
28 }
29 }
30 return "";
31}
32
40std::string validate(const ModelConfig& config)
41{
42 std::string err;
43
44 if (config.context_length < 512 || config.context_length > 131072) {
45 err = "context_length must be in [512, 131072], got "
46 + std::to_string(config.context_length);
47 } else if (config.adapter.empty()) {
48 err = "adapter must not be empty";
49 } else if (config.n_batch < 1) {
50 err = "n_batch must be >= 1, got "
51 + std::to_string(config.n_batch);
52 } else if (config.allowed_tools.has_value()) {
54 }
55
56 return err;
57}
58
66std::string validate(const ModelsConfig& config)
67{
68 if (!config.tiers.empty()
69 && config.tiers.count(config.default_tier) == 0) {
70 return "default tier '" + config.default_tier
71 + "' not in tiers";
72 }
73 return "";
74}
75
83std::string validate(const CompactionConfig& config)
84{
85 std::string err;
86
87 if (config.threshold_percent < 0.5f
88 || config.threshold_percent > 0.99f) {
89 err = "compaction.threshold_percent must be in [0.5, 0.99], got "
90 + std::to_string(config.threshold_percent);
91 } else if (config.warning_threshold_percent
92 >= config.threshold_percent) {
93 err = "compaction.warning_threshold_percent ("
94 + std::to_string(config.warning_threshold_percent)
95 + ") must be less than threshold_percent ("
96 + std::to_string(config.threshold_percent) + ")";
97 } else if (config.preserve_recent_turns < 1
98 || config.preserve_recent_turns > 10) {
99 err = "compaction.preserve_recent_turns must be in [1, 10], got "
100 + std::to_string(config.preserve_recent_turns);
101 } else if (config.tool_result_ttl < 1) {
102 // v2.1.3 #6 / TTL clamp removal: tool_result_ttl was previously
103 // documented as "1–20" but never actually validated. The upper
104 // bound was always advisory — consumers can pick whatever
105 // makes sense for their workload (long delegations on large
106 // context windows benefit from large TTLs). Lower bound IS
107 // enforced because TTL=0 would prune every result on the next
108 // iteration, which is nonsensical and almost certainly a
109 // misconfiguration rather than an intent.
110 err = "compaction.tool_result_ttl must be >= 1, got "
111 + std::to_string(config.tool_result_ttl);
112 }
113
114 return err;
115}
116
126 const std::string& fallback,
127 const std::unordered_map<std::string, TierConfig>& tiers)
128{
129 if (tiers.count(fallback) == 0) {
130 return "routing.fallback_tier '" + fallback + "' not in tiers";
131 }
132 return "";
133}
134
144 const std::unordered_map<std::string, std::string>& tier_map,
145 const std::unordered_map<std::string, TierConfig>& tiers)
146{
147 for (const auto& [key, tier] : tier_map) {
148 if (tiers.count(tier) == 0) {
149 return "routing.tier_map['" + key + "'] = '" + tier
150 + "' not in tiers";
151 }
152 }
153 return "";
154}
155
165 const std::unordered_map<std::string, std::vector<std::string>>& rules,
166 const std::unordered_map<std::string, TierConfig>& tiers)
167{
168 for (const auto& [source, targets] : rules) {
169 if (tiers.count(source) == 0) {
170 return "routing.handoff_rules key '" + source
171 + "' not in tiers";
172 }
173 for (const auto& target : targets) {
174 if (tiers.count(target) == 0) {
175 return "routing.handoff_rules['" + source
176 + "'] contains '" + target + "' not in tiers";
177 }
178 }
179 }
180 return "";
181}
182
200 bool has_prompt = routing.classification_prompt.has_value()
201 && !routing.classification_prompt->empty();
202 if (routing.enabled && has_prompt && routing.tier_map.empty()) {
203 return "routing.classification_prompt is set but routing.tier_map is "
204 "empty — the router emits a digit that maps to no tier, so every "
205 "route falls back to the default (configure routing.tier_map)";
206 }
207 return "";
208}
209
219 const RoutingConfig& routing,
220 const ModelsConfig& models)
221{
222 std::string err;
223
224 if (models.tiers.empty()) {
225 /* no tiers — nothing to validate */
226 } else if (routing.enabled && !models.router.has_value()) {
227 err = "routing.enabled is true but models.router is not configured";
228 } else {
229 err = validate_fallback_tier(routing.fallback_tier, models.tiers);
230
231 if (err.empty()) {
232 err = validate_tier_map(routing.tier_map, models.tiers);
233 }
234 if (err.empty()) {
235 err = validate_handoff_rules(routing.handoff_rules, models.tiers);
236 }
237 if (err.empty()) {
239 }
240 }
241
242 return err;
243}
244
254 const std::unordered_map<std::string, TierConfig>& tiers,
255 const std::unordered_map<std::string, std::vector<std::string>>&
256 handoff_rules)
257{
258 std::string warnings;
259 for (const auto& [name, tier] : tiers) {
260 if (tier.auto_chain.has_value() && !tier.auto_chain->empty()
261 && handoff_rules.count(name) == 0) {
262 if (!warnings.empty()) {
263 warnings += "; ";
264 }
265 warnings += "tier '" + name
266 + "' has auto_chain but no handoff_rules entry";
267 }
268 }
269 return warnings;
270}
271
279std::string validate(const PromptCacheConfig& config)
280{
281 if (config.enabled && config.max_bytes == 0) {
282 return "inference.prompt_cache: enabled=true but max_bytes=0";
283 }
284 return "";
285}
286
294static std::string validate_model_tiers(const ModelsConfig& models)
295{
296 std::string err = validate(models);
297
298 if (err.empty()) {
299 for (const auto& [name, tier] : models.tiers) {
300 err = validate(static_cast<const ModelConfig&>(tier));
301 if (!err.empty()) {
302 err = "models." + name + ": " + err;
303 break;
304 }
305 }
306 }
307
308 if (err.empty() && models.router.has_value()) {
309 err = validate(*models.router);
310 if (!err.empty()) {
311 err = "models.router: " + err;
312 }
313 }
314
315 return err;
316}
317
326std::string validate_config(
327 const ParsedConfig& config,
328 std::vector<std::string>& warnings)
329{
330 s_log->info("Config validation start");
331 std::string err = validate_model_tiers(config.models);
332
333 if (err.empty()) {
334 err = validate_routing(config.routing, config.models);
335 }
336 if (err.empty()) {
337 err = validate(config.compaction);
338 }
339 if (err.empty()) {
340 err = validate(config.prompt_cache);
341 }
342 if (err.empty()) {
344 config.models.tiers, config.routing.handoff_rules);
345 if (!w.empty()) {
346 warnings.push_back(w);
347 }
348 }
349
350 if (err.empty()) {
351 s_log->info("Config validation passed ({} warning(s))",
352 warnings.size());
353 } else {
354 s_log->error("Config validation failed: {}", err);
355 }
356 return err;
357}
358
359} // namespace entropic::config
spdlog initialization and logger access.
ENTROPIC_EXPORT std::shared_ptr< spdlog::logger > get(const std::string &name)
Get or create a named logger.
Definition logging.cpp:211
Auto-compaction configuration.
Definition config.h:697
float warning_threshold_percent
Warning trigger (0.3–0.9)
Definition config.h:705
int preserve_recent_turns
Turns to preserve (1–10)
Definition config.h:700
int tool_result_ttl
Tool result TTL in turns (>= 1; v2.1.3 #6: gated on fill, no upper bound)
Definition config.h:704
float threshold_percent
Compaction trigger (0.5–0.99)
Definition config.h:699
Model configuration for a single tier.
Definition config.h:148
int context_length
Context window size (512–131072)
Definition config.h:151
int n_batch
Batch size for prompt processing.
Definition config.h:160
std::optional< std::vector< std::string > > allowed_tools
Tool whitelist (nullopt = all)
Definition config.h:236
std::string adapter
Chat adapter name.
Definition config.h:150
Configuration for all models (tiers + router).
Definition config.h:542
std::optional< ModelConfig > router
Router model (separate from tiers)
Definition config.h:544
std::unordered_map< std::string, TierConfig > tiers
Tier name → config.
Definition config.h:543
std::string default_tier
Default tier name.
Definition config.h:545
Full parsed configuration.
Definition config.h:929
PromptCacheConfig prompt_cache
Prompt KV cache settings.
Definition config.h:937
CompactionConfig compaction
Auto-compaction settings.
Definition config.h:935
RoutingConfig routing
Routing rules.
Definition config.h:931
ModelsConfig models
Tiers + router.
Definition config.h:930
Prompt caching configuration.
Definition config.h:266
size_t max_bytes
Maximum cache RAM (512 MB default)
Definition config.h:267
bool enabled
Master switch (false = no caching)
Definition config.h:268
Configuration for model routing.
Definition config.h:577
std::string fallback_tier
Fallback when routing fails.
Definition config.h:579
std::unordered_map< std::string, std::vector< std::string > > handoff_rules
Tier handoff rules.
Definition config.h:582
bool enabled
Enable routing.
Definition config.h:578
std::optional< std::string > classification_prompt
Custom prompt (nullopt = auto)
Definition config.h:580
std::unordered_map< std::string, std::string > tier_map
Classification → tier mapping.
Definition config.h:581
std::string validate_classification_routable(const RoutingConfig &routing)
A configured classification_prompt is inert without a tier_map.
Definition validate.cpp:199
static std::string validate_model_tiers(const ModelsConfig &models)
Validate model tiers and router.
Definition validate.cpp:294
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.
Definition validate.cpp:164
ENTROPIC_EXPORT std::string validate_routing(const RoutingConfig &routing, const ModelsConfig &models)
Validate RoutingConfig against defined tiers.
Definition validate.cpp:218
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.
Definition validate.cpp:143
ENTROPIC_EXPORT std::string validate_config(const ParsedConfig &config, std::vector< std::string > &warnings)
Validate the full ParsedConfig.
Definition validate.cpp:326
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.
Definition validate.cpp:125
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.
Definition validate.cpp:253
ENTROPIC_EXPORT std::string validate(const ModelConfig &config)
Validate a ModelConfig.
Definition validate.cpp:40
ENTROPIC_EXPORT std::string validate_allowed_tools(const std::vector< std::string > &tools)
Validate allowed_tools entries use "server.tool" format.
Definition validate.cpp:22