@@ -365,12 +365,105 @@ async with Agent(
365365
366366** Note** : Currently input schemas can only be used by subagents, not by regular agents.
367367
368- ## Loop Stop Conditions
368+ ## Hooks
369+
370+ Hooks are user-defined callback functions that can be registered to execute at specific points
371+ during the agent's operation. Hooks allow developers to add custom behavior, logging and monitoring
372+ or implement custom stopping conditions for the agent loop without modifying the core agent logic.
373+
374+ There are several types of hooks available.
375+ They differ by the point in the execution flow where they are invoked:
376+
377+ - before_model: before each model call
378+ - after_model: after each model call
379+ - before_agent: once per agent invocation, before any model calls
380+ - after_agent: once per agent invocation, after all model calls
381+
382+ Example hook that logs token usage after each model call:
383+
384+ ``` py
385+ from splunklib.ai import Agent, OpenAIModel
386+ from splunklib.ai.hooks import after_model
387+ from splunklib.client import connect
388+
389+ import logging
390+
391+ logger = logging.getLogger(__name__ )
392+
393+ model = OpenAIModel(... )
394+ service = connect(... )
395+
396+ @after_model
397+ def log_token_usage (state : AgentState) -> None :
398+ logger.debug(f " Model used { state.token_count} tokens up to this point " )
399+
400+
401+ async with Agent(
402+ model = model,
403+ service = service,
404+ system_prompt = " ..." ,
405+ hooks = [log_token_usage],
406+ ) as agent: ...
407+ ```
408+
409+ The same hook can be defined as a class. It needs to provide the type and name attributes, and implement the ` __call__ ` method:
410+
411+ ``` py
412+ from typing import final, override
413+ from splunklib.ai.hooks import AgentHook, AgentState
414+ import logging
415+
416+ logger = logging.getLogger(__name__ )
417+
418+ @final
419+ class LoggingHook (AgentHook ):
420+ type = " before_model"
421+ name = " test_hook"
422+
423+ @override
424+ def __call__ (self , state : AgentState) -> None :
425+ logger.debug(f " Model used { state.token_count} tokens up to this point " )
426+
427+ async with Agent(
428+ model = model,
429+ service = service,
430+ system_prompt = " ..." ,
431+ hooks = [LoggingHook()],
432+ ) as agent: ...
433+ ```
434+
435+ The hooks can stop the Agentic Loop under custom conditions by raising exceptions.
436+ The logic of the hook can be more advanced and include multiple conditions, for example, based on both token usage and execution time:
437+
438+ ``` py
439+ from splunklib.ai import Agent, OpenAIModel
440+ from splunklib.ai.hooks import before_model, AgentHook
441+ from time import monotonic
442+
443+ def timeout_or_token_limit (seconds_limit : float , token_limit : float ) -> AgentHook:
444+ now = monotonic()
445+ timeout = now + seconds_limit
446+
447+ @before_model
448+ def _limit_hook (state : AgentState) -> None :
449+ if state.token_count > token_limit or monotonic() >= timeout:
450+ raise Exception (" Stopping Agentic Loop" )
451+
452+ return _limit_hook
453+
454+
455+ async with Agent(
456+ ... ,
457+ hooks = [timeout_or_token_limit(seconds_limit = 10.0 , token_limit = 10000 )],
458+ ) as agent: ...
459+ ```
460+
461+ ### Predefined hooks for loop stopping conditions
369462
370463To prevent excessive token usage or runaway execution, an Agent can be constrained
371- using loop stop conditions .
464+ using predefined hooks .
372465
373- Stop conditions allow you to automatically terminate the agent loop when one or more
466+ Those hooks allow you to automatically terminate the agent loop when one or more
374467limits are reached, such as:
375468
376469- Maximum number of generated tokens
@@ -379,7 +472,7 @@ limits are reached, such as:
379472
380473``` py
381474from splunklib.ai import Agent, OpenAIModel
382- from splunklib.ai.stop_conditions import StopConditions
475+ from splunklib.ai.hooks import token_limit, step_limit, timeout_limit
383476from splunklib.client import connect
384477
385478model = OpenAIModel(... )
@@ -389,11 +482,11 @@ async with Agent(
389482 model = model,
390483 service = service,
391484 system_prompt = " ..." ,
392- loop_stop_conditions = StopConditions(
393- token_limit = 10000 ,
394- steps_limit = 25 ,
395- timeout_seconds = 10.5 ,
396- ) ,
485+ hooks = [
486+ token_limit( 10000 ) ,
487+ step_limit( 25 ) ,
488+ timeout_limit( 10.5 ) ,
489+ ] ,
397490 ) as agent: ...
398491```
399492
0 commit comments