use serde::{Deserialize, Serialize};
pub const DEFAULT_MAX_OPERATIONS: u64 = 100_000;
pub const DEFAULT_MAX_TOOL_CALLS: usize = 50;
pub const DEFAULT_TIMEOUT_MS: u64 = 30_000;
pub const DEFAULT_MAX_STRING_SIZE: usize = 10_000_000;
pub const DEFAULT_MAX_ARRAY_SIZE: usize = 10_000;
pub const DEFAULT_MAX_MAP_SIZE: usize = 1_000;
pub const QUICK_MAX_OPERATIONS: u64 = 10_000;
pub const QUICK_MAX_TOOL_CALLS: usize = 10;
pub const QUICK_TIMEOUT_MS: u64 = 5_000;
pub const EXTENDED_MAX_OPERATIONS: u64 = 500_000;
pub const EXTENDED_MAX_TOOL_CALLS: usize = 100;
pub const EXTENDED_TIMEOUT_MS: u64 = 120_000;
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct ExecutionLimits {
pub max_operations: u64,
pub max_tool_calls: usize,
pub timeout_ms: u64,
pub max_string_size: usize,
pub max_array_size: usize,
pub max_map_size: usize,
}
impl Default for ExecutionLimits {
fn default() -> Self {
Self {
max_operations: DEFAULT_MAX_OPERATIONS,
max_tool_calls: DEFAULT_MAX_TOOL_CALLS,
timeout_ms: DEFAULT_TIMEOUT_MS,
max_string_size: DEFAULT_MAX_STRING_SIZE,
max_array_size: DEFAULT_MAX_ARRAY_SIZE,
max_map_size: DEFAULT_MAX_MAP_SIZE,
}
}
}
impl ExecutionLimits {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn quick() -> Self {
Self {
max_operations: QUICK_MAX_OPERATIONS,
max_tool_calls: QUICK_MAX_TOOL_CALLS,
timeout_ms: QUICK_TIMEOUT_MS,
..Default::default()
}
}
#[must_use]
pub fn extended() -> Self {
Self {
max_operations: EXTENDED_MAX_OPERATIONS,
max_tool_calls: EXTENDED_MAX_TOOL_CALLS,
timeout_ms: EXTENDED_TIMEOUT_MS,
..Default::default()
}
}
#[must_use]
pub const fn with_max_operations(mut self, max: u64) -> Self {
self.max_operations = max;
self
}
#[must_use]
pub const fn with_max_tool_calls(mut self, max: usize) -> Self {
self.max_tool_calls = max;
self
}
#[must_use]
pub const fn with_timeout_ms(mut self, timeout: u64) -> Self {
self.timeout_ms = timeout;
self
}
#[must_use]
pub const fn with_max_string_size(mut self, size: usize) -> Self {
self.max_string_size = size;
self
}
#[must_use]
pub const fn with_max_array_size(mut self, size: usize) -> Self {
self.max_array_size = size;
self
}
#[must_use]
pub const fn with_max_map_size(mut self, size: usize) -> Self {
self.max_map_size = size;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_limits() {
let limits = ExecutionLimits::default();
assert_eq!(limits.max_operations, DEFAULT_MAX_OPERATIONS);
assert_eq!(limits.max_tool_calls, DEFAULT_MAX_TOOL_CALLS);
assert_eq!(limits.timeout_ms, DEFAULT_TIMEOUT_MS);
}
#[test]
fn test_quick_limits() {
let limits = ExecutionLimits::quick();
assert_eq!(limits.max_operations, QUICK_MAX_OPERATIONS);
assert_eq!(limits.max_tool_calls, QUICK_MAX_TOOL_CALLS);
}
#[test]
fn test_extended_limits() {
let limits = ExecutionLimits::extended();
assert_eq!(limits.max_operations, EXTENDED_MAX_OPERATIONS);
assert_eq!(limits.max_tool_calls, EXTENDED_MAX_TOOL_CALLS);
}
#[test]
fn test_builder_pattern() {
let limits = ExecutionLimits::default()
.with_max_operations(50_000)
.with_max_tool_calls(25)
.with_timeout_ms(10_000);
assert_eq!(limits.max_operations, 50_000);
assert_eq!(limits.max_tool_calls, 25);
assert_eq!(limits.timeout_ms, 10_000);
}
#[test]
fn test_new_equals_default() {
let new_limits = ExecutionLimits::new();
let default_limits = ExecutionLimits::default();
assert_eq!(new_limits.max_operations, default_limits.max_operations);
assert_eq!(new_limits.max_tool_calls, default_limits.max_tool_calls);
assert_eq!(new_limits.timeout_ms, default_limits.timeout_ms);
assert_eq!(new_limits.max_string_size, default_limits.max_string_size);
assert_eq!(new_limits.max_array_size, default_limits.max_array_size);
assert_eq!(new_limits.max_map_size, default_limits.max_map_size);
}
#[test]
fn test_with_max_string_size() {
let limits = ExecutionLimits::default().with_max_string_size(5_000_000);
assert_eq!(limits.max_string_size, 5_000_000);
assert_eq!(limits.max_operations, DEFAULT_MAX_OPERATIONS);
}
#[test]
fn test_with_max_array_size() {
let limits = ExecutionLimits::default().with_max_array_size(5_000);
assert_eq!(limits.max_array_size, 5_000);
assert_eq!(limits.max_operations, DEFAULT_MAX_OPERATIONS);
}
#[test]
fn test_with_max_map_size() {
let limits = ExecutionLimits::default().with_max_map_size(500);
assert_eq!(limits.max_map_size, 500);
assert_eq!(limits.max_operations, DEFAULT_MAX_OPERATIONS);
}
#[test]
fn test_full_builder_chain() {
let limits = ExecutionLimits::new()
.with_max_operations(200_000)
.with_max_tool_calls(75)
.with_timeout_ms(60_000)
.with_max_string_size(20_000_000)
.with_max_array_size(20_000)
.with_max_map_size(2_000);
assert_eq!(limits.max_operations, 200_000);
assert_eq!(limits.max_tool_calls, 75);
assert_eq!(limits.timeout_ms, 60_000);
assert_eq!(limits.max_string_size, 20_000_000);
assert_eq!(limits.max_array_size, 20_000);
assert_eq!(limits.max_map_size, 2_000);
}
}