use serde::Serialize;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
pub struct RuntimeLimits {
pub max_vm_frames: usize,
pub max_template_include_depth: usize,
pub max_template_parse_cache_entries: usize,
pub max_file_text_cache_entries: usize,
pub max_json_parse_cache_entries: usize,
pub max_std_cache_entries: usize,
pub max_regex_cache_entries: usize,
pub max_schema_pattern_cache_entries: usize,
pub max_schema_guard_cache_entries: usize,
pub max_shape_spec_cache_entries: usize,
pub default_event_log_queue_depth: usize,
pub max_agent_sessions: usize,
pub max_project_fingerprint_depth: usize,
pub max_shape_validation_depth: usize,
pub max_project_enrich_yaml_depth: usize,
pub max_template_ast_depth: usize,
pub max_constant_folded_collection_items: usize,
pub max_constant_folded_string_bytes: usize,
pub max_nested_execution_depth: usize,
pub max_schema_nudge_depth: usize,
pub max_schema_nudge_lines: usize,
pub max_schema_nudge_keys: usize,
}
impl RuntimeLimits {
pub const DEFAULT: Self = Self {
max_vm_frames: 512,
max_template_include_depth: 32,
max_template_parse_cache_entries: 128,
max_file_text_cache_entries: 256,
max_json_parse_cache_entries: 128,
max_std_cache_entries: 256,
max_regex_cache_entries: 128,
max_schema_pattern_cache_entries: 256,
max_schema_guard_cache_entries: 256,
max_shape_spec_cache_entries: 256,
default_event_log_queue_depth: 128,
max_agent_sessions: 128,
max_project_fingerprint_depth: 4,
max_shape_validation_depth: 64,
max_project_enrich_yaml_depth: 128,
max_template_ast_depth: 128,
max_constant_folded_collection_items: 4_096,
max_constant_folded_string_bytes: 64 * 1024,
max_nested_execution_depth: 8,
max_schema_nudge_depth: 3,
max_schema_nudge_lines: 8,
max_schema_nudge_keys: 16,
};
pub fn value(&self, name: &str) -> Option<usize> {
Some(match name {
"max_vm_frames" => self.max_vm_frames,
"max_template_include_depth" => self.max_template_include_depth,
"max_template_parse_cache_entries" => self.max_template_parse_cache_entries,
"max_file_text_cache_entries" => self.max_file_text_cache_entries,
"max_json_parse_cache_entries" => self.max_json_parse_cache_entries,
"max_std_cache_entries" => self.max_std_cache_entries,
"max_regex_cache_entries" => self.max_regex_cache_entries,
"max_schema_pattern_cache_entries" => self.max_schema_pattern_cache_entries,
"max_schema_guard_cache_entries" => self.max_schema_guard_cache_entries,
"max_shape_spec_cache_entries" => self.max_shape_spec_cache_entries,
"default_event_log_queue_depth" => self.default_event_log_queue_depth,
"max_agent_sessions" => self.max_agent_sessions,
"max_project_fingerprint_depth" => self.max_project_fingerprint_depth,
"max_shape_validation_depth" => self.max_shape_validation_depth,
"max_project_enrich_yaml_depth" => self.max_project_enrich_yaml_depth,
"max_template_ast_depth" => self.max_template_ast_depth,
"max_constant_folded_collection_items" => self.max_constant_folded_collection_items,
"max_constant_folded_string_bytes" => self.max_constant_folded_string_bytes,
"max_nested_execution_depth" => self.max_nested_execution_depth,
"max_schema_nudge_depth" => self.max_schema_nudge_depth,
"max_schema_nudge_lines" => self.max_schema_nudge_lines,
"max_schema_nudge_keys" => self.max_schema_nudge_keys,
_ => return None,
})
}
pub fn report(&self) -> RuntimeLimitsReport {
RuntimeLimitsReport {
entries: RUNTIME_LIMIT_DESCRIPTIONS
.iter()
.map(|description| RuntimeLimitEntry {
name: description.name,
value: self
.value(description.name)
.expect("runtime limit description must name a RuntimeLimits field"),
user_visible: description.user_visible,
host_configurable: description.host_configurable,
protects: description.protects,
})
.collect(),
}
}
}
impl Default for RuntimeLimits {
fn default() -> Self {
Self::DEFAULT
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct RuntimeLimitsReport {
pub entries: Vec<RuntimeLimitEntry>,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct RuntimeLimitEntry {
pub name: &'static str,
pub value: usize,
pub user_visible: bool,
pub host_configurable: bool,
pub protects: &'static str,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RuntimeLimitDescription {
pub name: &'static str,
pub user_visible: bool,
pub host_configurable: bool,
pub protects: &'static str,
}
pub const RUNTIME_LIMIT_DESCRIPTIONS: &[RuntimeLimitDescription] = &[
RuntimeLimitDescription {
name: "max_vm_frames",
user_visible: true,
host_configurable: false,
protects: "prevents unbounded Harn function recursion from exhausting the VM stack",
},
RuntimeLimitDescription {
name: "max_template_include_depth",
user_visible: true,
host_configurable: false,
protects: "bounds recursive prompt-template includes after cycle detection",
},
RuntimeLimitDescription {
name: "max_template_parse_cache_entries",
user_visible: false,
host_configurable: false,
protects: "bounds per-thread memory held by parsed prompt-template assets",
},
RuntimeLimitDescription {
name: "max_file_text_cache_entries",
user_visible: false,
host_configurable: false,
protects: "bounds per-thread memory held by cached UTF-8 file reads",
},
RuntimeLimitDescription {
name: "max_json_parse_cache_entries",
user_visible: false,
host_configurable: false,
protects: "bounds per-thread memory held by memoized JSON parse inputs and values",
},
RuntimeLimitDescription {
name: "max_std_cache_entries",
user_visible: true,
host_configurable: false,
protects: "bounds retained entries in std/cache memory, filesystem, and sqlite backends",
},
RuntimeLimitDescription {
name: "max_regex_cache_entries",
user_visible: false,
host_configurable: false,
protects: "bounds per-thread memory held by compiled stdlib regex patterns",
},
RuntimeLimitDescription {
name: "max_schema_pattern_cache_entries",
user_visible: false,
host_configurable: false,
protects: "bounds process-wide memory held by compiled JSON-schema pattern regexes",
},
RuntimeLimitDescription {
name: "max_schema_guard_cache_entries",
user_visible: false,
host_configurable: false,
protects: "bounds per-thread memory held by canonical runtime parameter schemas",
},
RuntimeLimitDescription {
name: "max_shape_spec_cache_entries",
user_visible: false,
host_configurable: false,
protects: "bounds per-thread memory held by parsed runtime shape specs",
},
RuntimeLimitDescription {
name: "default_event_log_queue_depth",
user_visible: true,
host_configurable: true,
protects: "bounds queued subscriber notifications for memory, file, and sqlite event logs",
},
RuntimeLimitDescription {
name: "max_agent_sessions",
user_visible: true,
host_configurable: false,
protects: "bounds concurrent first-class agent sessions stored on one VM thread",
},
RuntimeLimitDescription {
name: "max_project_fingerprint_depth",
user_visible: false,
host_configurable: false,
protects: "bounds project fingerprint discovery in large or adversarial directory trees",
},
RuntimeLimitDescription {
name: "max_shape_validation_depth",
user_visible: true,
host_configurable: false,
protects: "bounds runtime shape validation for nested dicts and structs",
},
RuntimeLimitDescription {
name: "max_project_enrich_yaml_depth",
user_visible: false,
host_configurable: false,
protects: "bounds project enrichment traversal of nested hook YAML",
},
RuntimeLimitDescription {
name: "max_template_ast_depth",
user_visible: true,
host_configurable: false,
protects: "bounds nested prompt-template control structures and expressions",
},
RuntimeLimitDescription {
name: "max_constant_folded_collection_items",
user_visible: false,
host_configurable: false,
protects: "prevents compile-time constant folding from materializing huge collections",
},
RuntimeLimitDescription {
name: "max_constant_folded_string_bytes",
user_visible: false,
host_configurable: false,
protects: "prevents compile-time constant folding from materializing huge strings",
},
RuntimeLimitDescription {
name: "max_nested_execution_depth",
user_visible: true,
host_configurable: false,
protects: "bounds nested agent loops, sub-agents, workers, and workflow stages",
},
RuntimeLimitDescription {
name: "max_schema_nudge_depth",
user_visible: false,
host_configurable: false,
protects: "keeps schema-retry correction prompts compact for deeply nested schemas",
},
RuntimeLimitDescription {
name: "max_schema_nudge_lines",
user_visible: false,
host_configurable: false,
protects: "keeps schema-retry correction prompts from growing with wide schemas",
},
RuntimeLimitDescription {
name: "max_schema_nudge_keys",
user_visible: false,
host_configurable: false,
protects: "keeps schema-retry object-key previews compact for wide objects",
},
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_runtime_limits_match_legacy_values() {
let limits = RuntimeLimits::default();
assert_eq!(limits.max_vm_frames, 512);
assert_eq!(limits.max_template_include_depth, 32);
assert_eq!(limits.max_template_parse_cache_entries, 128);
assert_eq!(limits.max_file_text_cache_entries, 256);
assert_eq!(limits.max_json_parse_cache_entries, 128);
assert_eq!(limits.max_std_cache_entries, 256);
assert_eq!(limits.max_regex_cache_entries, 128);
assert_eq!(limits.max_schema_pattern_cache_entries, 256);
assert_eq!(limits.max_schema_guard_cache_entries, 256);
assert_eq!(limits.max_shape_spec_cache_entries, 256);
assert_eq!(limits.default_event_log_queue_depth, 128);
assert_eq!(limits.max_agent_sessions, 128);
assert_eq!(limits.max_project_fingerprint_depth, 4);
assert_eq!(limits.max_shape_validation_depth, 64);
assert_eq!(limits.max_project_enrich_yaml_depth, 128);
assert_eq!(limits.max_template_ast_depth, 128);
assert_eq!(limits.max_constant_folded_collection_items, 4_096);
assert_eq!(limits.max_constant_folded_string_bytes, 64 * 1024);
assert_eq!(limits.max_nested_execution_depth, 8);
assert_eq!(limits.max_schema_nudge_depth, 3);
assert_eq!(limits.max_schema_nudge_lines, 8);
assert_eq!(limits.max_schema_nudge_keys, 16);
}
#[test]
fn runtime_limit_report_documents_every_field() {
let report = RuntimeLimits::default().report();
let names = report
.entries
.iter()
.map(|entry| entry.name)
.collect::<Vec<_>>();
assert_eq!(
names,
vec![
"max_vm_frames",
"max_template_include_depth",
"max_template_parse_cache_entries",
"max_file_text_cache_entries",
"max_json_parse_cache_entries",
"max_std_cache_entries",
"max_regex_cache_entries",
"max_schema_pattern_cache_entries",
"max_schema_guard_cache_entries",
"max_shape_spec_cache_entries",
"default_event_log_queue_depth",
"max_agent_sessions",
"max_project_fingerprint_depth",
"max_shape_validation_depth",
"max_project_enrich_yaml_depth",
"max_template_ast_depth",
"max_constant_folded_collection_items",
"max_constant_folded_string_bytes",
"max_nested_execution_depth",
"max_schema_nudge_depth",
"max_schema_nudge_lines",
"max_schema_nudge_keys",
]
);
assert!(report.entries.iter().all(|entry| entry.value > 0));
assert!(report
.entries
.iter()
.all(|entry| !entry.protects.is_empty()));
}
}