@@ -602,10 +602,10 @@ Each middleware can inspect input, call `handler(request)`, and modify the retur
602602
603603Available decorators:
604604
605- - ` agent_middleware `
606- - ` model_middleware `
607- - ` tool_middleware `
608- - ` subagent_middleware `
605+ - ` agent_middleware ` - runs once per ` invoke ` call.
606+ - ` model_middleware ` - runs on every model call.
607+ - ` tool_middleware ` - runs on every tool call.
608+ - ` subagent_middleware ` - runs on every subagent call.
609609
610610Class-based middleware:
611611
@@ -848,65 +848,76 @@ The hooks can stop the Agentic Loop under custom conditions by raising exception
848848The logic of the hook can be more advanced and include multiple conditions, for example, based on both token usage and execution time:
849849
850850``` py
851- from splunklib.ai import Agent, OpenAIModel
852851from splunklib.ai.hooks import before_model
853852from splunklib.ai.middleware import AgentMiddleware, ModelRequest
854- from time import monotonic
855-
856- def timeout_or_token_limit (seconds_limit : float , token_limit : float ) -> AgentMiddleware:
857- now = monotonic()
858- timeout = now + seconds_limit
859853
854+ def token_and_step_limit (token_limit : float , step_limit : int ) -> AgentMiddleware:
860855 @before_model
861- def _limit_hook (req : ModelRequest) -> None :
862- if req.state.token_count > token_limit or monotonic() >= timeout :
856+ def _hook (req : ModelRequest) -> None :
857+ if req.state.token_count > token_limit or req.state.total_steps >= step_limit :
863858 raise Exception (" Stopping Agentic Loop" )
864859
865- return _limit_hook
860+ return _hook
866861
867862
868863async with Agent(
869864 ... ,
870- middleware = [timeout_or_token_limit( seconds_limit = 10.0 , token_limit = 10000 )],
865+ middleware = [token_and_step_limit( token_limit = 10_000 , step_limit = 5 )],
871866) as agent: ...
872867```
873868
874- ### Predefined hooks for loop stopping conditions
869+ ### Default limit middlewares
875870
876- To prevent excessive token usage or runaway execution, an Agent can be constrained
877- using predefined hooks.
871+ Every ` Agent ` automatically applies sane default limits to prevent runaway execution
872+ or excessive token usage. Default limit middlewares are appended after any user-supplied
873+ middleware, so they always act on the final state of the request. If you override one of
874+ the defaults by passing your own instance, you are responsible for its position in the
875+ chain - place it last if you want the same behavior.
878876
879- Those hooks allow you to automatically terminate the agent loop when one or more
880- limits are reached, such as:
877+ | Middleware | Default | Measured |
878+ | ---| ---| ---|
879+ | ` TokenLimitMiddleware ` | 200 000 tokens | token count of messages passed to the model |
880+ | ` StepLimitMiddleware ` | 100 steps | steps taken |
881+ | ` TimeoutLimitMiddleware ` | 600 seconds (10 minutes) | per ` invoke ` call |
881882
882- - Maximum number of generated tokens
883- - Maximum number of reasoning / execution steps
884- - Maximum wall-clock execution time
883+ ` TokenLimitMiddleware ` and ` StepLimitMiddleware ` check the values from the messages passed to the
884+ model on each call. ` TimeoutLimitMiddleware ` resets its deadline on each ` invoke ` , so every call
885+ gets a fresh time budget.
885886
886- ``` py
887- from splunklib.ai import Agent, OpenAIModel
888- from splunklib.ai.hooks import token_limit, step_limit, timeout_limit
889- from splunklib.client import connect
887+ When a limit is exceeded, the agent raises the corresponding exception:
888+ ` TokenLimitExceededException ` , ` StepsLimitExceededException ` , or ` TimeoutExceededException ` .
890889
891- model = OpenAIModel(... )
892- service = connect(... )
890+ #### Overriding defaults
891+
892+ To override a specific limit, pass your own instance of the corresponding middleware
893+ class. The default for that limit is suppressed automatically - the other defaults
894+ remain active:
895+
896+ ``` py
897+ from splunklib.ai.hooks import TokenLimitMiddleware, StepLimitMiddleware, TimeoutLimitMiddleware
893898
894899async with Agent(
895- model = model,
896- service = service,
897- system_prompt = " ..." ,
898- hooks = [
899- token_limit(10000 ),
900- step_limit(25 ),
901- timeout_limit(10.5 ),
902- ],
903- ) as agent: ...
900+ ... ,
901+ middleware = [
902+ TokenLimitMiddleware(50_000 ), # overrides default 200 000; other defaults still apply
903+ ],
904+ ) as agent: ...
904905```
905906
906- When a limit is exceeded, the agent raises the exception corresponding to the violated
907- condition (` TokenLimitExceededException ` , ` StepsLimitExceededException ` or ` TimeoutExceededException ` ).
907+ To override all defaults, pass all three:
908+
909+ ``` py
910+ async with Agent(
911+ ... ,
912+ middleware = [
913+ TokenLimitMiddleware(50_000 ),
914+ StepLimitMiddleware(10 ),
915+ TimeoutLimitMiddleware(30.0 ),
916+ ],
917+ ) as agent: ...
918+ ```
908919
909- These limits apply over the entire lifetime of an ` Agent ` .
920+ There is no explicit opt-out - the intent is that agents should always have some guardrails .
910921
911922## Logger
912923
@@ -915,7 +926,6 @@ tracing and debugging throughout the agent’s lifecycle.
915926
916927``` py
917928from splunklib.ai import Agent, OpenAIModel
918- from splunklib.ai.hooks import token_limit, step_limit, timeout_limit
919929from splunklib.client import connect
920930import logging
921931
0 commit comments