@@ -13,6 +13,62 @@ use crate::autonomy::AutonomySupervisorConfig;
1313use crate :: performance:: PerformanceConfig ;
1414use crate :: state_manager:: StateManagerConfig ;
1515
16+ /// Rate limiting configuration for API calls
17+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
18+ pub struct RateLimitConfig {
19+ /// Whether rate limiting is enabled
20+ pub enabled : bool ,
21+ /// Maximum requests per second for reasoning engine
22+ pub reasoning_rps : f64 ,
23+ /// Maximum requests per second for action engine
24+ pub action_rps : f64 ,
25+ /// Maximum requests per second for reflection engine
26+ pub reflection_rps : f64 ,
27+ }
28+
29+ impl Default for RateLimitConfig {
30+ fn default ( ) -> Self {
31+ Self {
32+ enabled : true ,
33+ reasoning_rps : 5.0 , // 5 requests per second
34+ action_rps : 10.0 , // 10 requests per second
35+ reflection_rps : 3.0 , // 3 requests per second
36+ }
37+ }
38+ }
39+
40+ impl RateLimitConfig {
41+ /// Create from environment variables
42+ pub fn from_environment ( ) -> Self {
43+ let enabled = std:: env:: var ( "FLUENT_RATE_LIMIT_ENABLED" )
44+ . ok ( )
45+ . and_then ( |v| v. parse ( ) . ok ( ) )
46+ . unwrap_or ( true ) ;
47+
48+ let reasoning_rps = std:: env:: var ( "FLUENT_REASONING_RPS" )
49+ . ok ( )
50+ . and_then ( |v| v. parse ( ) . ok ( ) )
51+ . unwrap_or ( 5.0 ) ;
52+
53+ let action_rps = std:: env:: var ( "FLUENT_ACTION_RPS" )
54+ . ok ( )
55+ . and_then ( |v| v. parse ( ) . ok ( ) )
56+ . unwrap_or ( 10.0 ) ;
57+
58+ let reflection_rps = std:: env:: var ( "FLUENT_REFLECTION_RPS" )
59+ . ok ( )
60+ . and_then ( |v| v. parse ( ) . ok ( ) )
61+ . unwrap_or ( 3.0 ) ;
62+
63+ Self {
64+ enabled,
65+ reasoning_rps,
66+ action_rps,
67+ reflection_rps,
68+ }
69+ }
70+ }
71+
1672/// Configuration for the agentic framework that integrates with fluent_cli's existing patterns
1773#[ derive( Debug , Clone , Serialize , Deserialize ) ]
1874pub struct AgentConfig {
@@ -33,6 +89,7 @@ pub struct AgentEngineConfig {
3389 pub supervisor : Option < AutonomySupervisorConfig > ,
3490 pub performance : Option < PerformanceConfig > ,
3591 pub state_management : Option < StateManagerConfig > ,
92+ pub rate_limit : Option < RateLimitConfig > ,
3693}
3794
3895/// Tool configuration for the agent
@@ -42,10 +99,16 @@ pub struct ToolConfig {
4299 pub shell_commands : bool ,
43100 pub rust_compiler : bool ,
44101 pub git_operations : bool ,
102+ #[ serde( default = "default_web_browsing" ) ]
103+ pub web_browsing : bool ,
45104 pub allowed_paths : Option < Vec < String > > ,
46105 pub allowed_commands : Option < Vec < String > > ,
47106}
48107
108+ fn default_web_browsing ( ) -> bool {
109+ true
110+ }
111+
49112/// Runtime configuration with loaded engines and credentials
50113#[ derive( Clone ) ]
51114pub struct AgentRuntimeConfig {
@@ -57,6 +120,10 @@ pub struct AgentRuntimeConfig {
57120 pub supervisor : Option < AutonomySupervisorConfig > ,
58121 pub performance : PerformanceConfig ,
59122 pub state_overrides : Option < StateManagerConfig > ,
123+ pub rate_limit : RateLimitConfig ,
124+ pub reasoning_rate_limiter : Option < Arc < fluent_engines:: RateLimiter > > ,
125+ pub action_rate_limiter : Option < Arc < fluent_engines:: RateLimiter > > ,
126+ pub reflection_rate_limiter : Option < Arc < fluent_engines:: RateLimiter > > ,
60127}
61128
62129impl AgentRuntimeConfig {
@@ -68,6 +135,96 @@ impl AgentRuntimeConfig {
68135 // In a real implementation, we'd need to restructure to avoid this type mismatch
69136 None
70137 }
138+
139+ /// Acquire a rate limit token for reasoning operations
140+ ///
141+ /// If rate limiting is disabled, returns immediately.
142+ /// Otherwise, waits until a token is available.
143+ pub async fn acquire_reasoning_rate_limit ( & self ) {
144+ if let Some ( ref limiter) = self . reasoning_rate_limiter {
145+ limiter. acquire ( ) . await ;
146+ }
147+ }
148+
149+ /// Acquire a rate limit token for action operations
150+ pub async fn acquire_action_rate_limit ( & self ) {
151+ if let Some ( ref limiter) = self . action_rate_limiter {
152+ limiter. acquire ( ) . await ;
153+ }
154+ }
155+
156+ /// Acquire a rate limit token for reflection operations
157+ pub async fn acquire_reflection_rate_limit ( & self ) {
158+ if let Some ( ref limiter) = self . reflection_rate_limiter {
159+ limiter. acquire ( ) . await ;
160+ }
161+ }
162+
163+ /// Try to acquire a rate limit token without blocking
164+ ///
165+ /// Returns true if token was acquired, false if rate limited.
166+ pub async fn try_acquire_reasoning_rate_limit ( & self ) -> bool {
167+ if let Some ( ref limiter) = self . reasoning_rate_limiter {
168+ limiter. try_acquire ( ) . await
169+ } else {
170+ true // No limiter = always allowed
171+ }
172+ }
173+
174+ /// Try to acquire an action rate limit token without blocking
175+ pub async fn try_acquire_action_rate_limit ( & self ) -> bool {
176+ if let Some ( ref limiter) = self . action_rate_limiter {
177+ limiter. try_acquire ( ) . await
178+ } else {
179+ true
180+ }
181+ }
182+
183+ /// Try to acquire a reflection rate limit token without blocking
184+ pub async fn try_acquire_reflection_rate_limit ( & self ) -> bool {
185+ if let Some ( ref limiter) = self . reflection_rate_limiter {
186+ limiter. try_acquire ( ) . await
187+ } else {
188+ true
189+ }
190+ }
191+
192+ /// Get the current rate limit configuration
193+ pub fn rate_limit_config ( & self ) -> & RateLimitConfig {
194+ & self . rate_limit
195+ }
196+
197+ /// Check if rate limiting is enabled
198+ pub fn is_rate_limiting_enabled ( & self ) -> bool {
199+ self . rate_limit . enabled
200+ }
201+
202+ /// Get available reasoning tokens (for monitoring)
203+ pub async fn reasoning_tokens_available ( & self ) -> f64 {
204+ if let Some ( ref limiter) = self . reasoning_rate_limiter {
205+ limiter. available_tokens ( ) . await
206+ } else {
207+ f64:: INFINITY
208+ }
209+ }
210+
211+ /// Get available action tokens (for monitoring)
212+ pub async fn action_tokens_available ( & self ) -> f64 {
213+ if let Some ( ref limiter) = self . action_rate_limiter {
214+ limiter. available_tokens ( ) . await
215+ } else {
216+ f64:: INFINITY
217+ }
218+ }
219+
220+ /// Get available reflection tokens (for monitoring)
221+ pub async fn reflection_tokens_available ( & self ) -> f64 {
222+ if let Some ( ref limiter) = self . reflection_rate_limiter {
223+ limiter. available_tokens ( ) . await
224+ } else {
225+ f64:: INFINITY
226+ }
227+ }
71228}
72229
73230impl AgentEngineConfig {
@@ -147,6 +304,20 @@ impl AgentEngineConfig {
147304 . await ?
148305 } ;
149306
307+ // Initialize rate limiters based on config
308+ let rate_limit_config = self . rate_limit . clone ( ) . unwrap_or_else ( RateLimitConfig :: from_environment) ;
309+
310+ let ( reasoning_rate_limiter, action_rate_limiter, reflection_rate_limiter) =
311+ if rate_limit_config. enabled {
312+ (
313+ Some ( Arc :: new ( fluent_engines:: RateLimiter :: new ( rate_limit_config. reasoning_rps ) ) ) ,
314+ Some ( Arc :: new ( fluent_engines:: RateLimiter :: new ( rate_limit_config. action_rps ) ) ) ,
315+ Some ( Arc :: new ( fluent_engines:: RateLimiter :: new ( rate_limit_config. reflection_rps ) ) ) ,
316+ )
317+ } else {
318+ ( None , None , None )
319+ } ;
320+
150321 Ok ( AgentRuntimeConfig {
151322 reasoning_engine : Arc :: new ( reasoning_engine) ,
152323 action_engine : Arc :: new ( action_engine) ,
@@ -156,6 +327,10 @@ impl AgentEngineConfig {
156327 supervisor : self . supervisor . clone ( ) ,
157328 performance : self . performance . clone ( ) . unwrap_or_default ( ) ,
158329 state_overrides : self . state_management . clone ( ) ,
330+ rate_limit : rate_limit_config,
331+ reasoning_rate_limiter,
332+ action_rate_limiter,
333+ reflection_rate_limiter,
159334 } )
160335 }
161336
@@ -362,6 +537,7 @@ impl AgentEngineConfig {
362537 shell_commands : false , // Disabled by default for security
363538 rust_compiler : true ,
364539 git_operations : false , // Disabled by default for security
540+ web_browsing : true ,
365541 allowed_paths : Some ( vec ! [
366542 "./" . to_string( ) ,
367543 "./src" . to_string( ) ,
@@ -381,6 +557,7 @@ impl AgentEngineConfig {
381557 supervisor : None ,
382558 performance : None ,
383559 state_management : None ,
560+ rate_limit : Some ( RateLimitConfig :: default ( ) ) ,
384561 }
385562 }
386563
@@ -403,6 +580,7 @@ impl Default for ToolConfig {
403580 shell_commands : false ,
404581 rust_compiler : true ,
405582 git_operations : false ,
583+ web_browsing : true ,
406584 allowed_paths : Some ( vec ! [
407585 "./" . to_string( ) ,
408586 "./src" . to_string( ) ,
@@ -581,4 +759,36 @@ mod tests {
581759 let engines = vec ! [ "sonnet3.5" . to_string( ) ] ;
582760 assert ! ( credentials:: validate_credentials( & credentials, & engines) . is_err( ) ) ;
583761 }
762+
763+ #[ test]
764+ fn test_rate_limit_config_default ( ) {
765+ let config = RateLimitConfig :: default ( ) ;
766+ assert ! ( config. enabled) ;
767+ assert_eq ! ( config. reasoning_rps, 5.0 ) ;
768+ assert_eq ! ( config. action_rps, 10.0 ) ;
769+ assert_eq ! ( config. reflection_rps, 3.0 ) ;
770+ }
771+
772+ #[ test]
773+ fn test_rate_limit_config_from_env ( ) {
774+ // Test that environment variables are read correctly
775+ std:: env:: set_var ( "FLUENT_RATE_LIMIT_ENABLED" , "false" ) ;
776+ std:: env:: set_var ( "FLUENT_REASONING_RPS" , "2.5" ) ;
777+
778+ let config = RateLimitConfig :: from_environment ( ) ;
779+ assert ! ( !config. enabled) ;
780+ assert_eq ! ( config. reasoning_rps, 2.5 ) ;
781+
782+ // Clean up
783+ std:: env:: remove_var ( "FLUENT_RATE_LIMIT_ENABLED" ) ;
784+ std:: env:: remove_var ( "FLUENT_REASONING_RPS" ) ;
785+ }
786+
787+ #[ test]
788+ fn test_default_config_includes_rate_limit ( ) {
789+ let config = AgentEngineConfig :: default_config ( ) ;
790+ assert ! ( config. rate_limit. is_some( ) ) ;
791+ let rate_limit = config. rate_limit . unwrap ( ) ;
792+ assert ! ( rate_limit. enabled) ;
793+ }
584794}
0 commit comments