Callbacks
Kader provides a callback system that allows you to hook into various stages of agent execution. Callbacks can be used for logging, monitoring, argument transformation, result modification, and more.
Overview
Callbacks are triggered at different points during agent execution:
- Agent Start/End - When an agent begins or finishes execution
- LLM Start/End - Before and after LLM calls
- Tool Start/End - Before and after tool execution
Callback Types
BaseCallback
The base class for all callbacks. It provides default no-op implementations for all callback methods.
from kader.callbacks import BaseCallback, CallbackContext, CallbackEvent
class MyCallback(BaseCallback):
def on_agent_start(self, context: CallbackContext) -> None:
print(f"Agent {context.agent_name} starting!")
def on_agent_end(self, context: CallbackContext) -> None:
print(f"Agent {context.agent_name} finished!")
ToolCallback
Callbacks for tool execution events. Supports filtering by tool names.
from kader.callbacks import ToolCallback, CallbackContext
class MyToolCallback(ToolCallback):
def __init__(self, tool_names: list[str] | None = None):
super().__init__(tool_names=tool_names)
def on_tool_before(
self,
context: CallbackContext,
tool_name: str,
arguments: dict,
) -> dict:
print(f"Calling {tool_name} with {arguments}")
return arguments # Can modify arguments
def on_tool_after(
self,
context: CallbackContext,
tool_name: str,
arguments: dict,
result,
):
print(f"{tool_name} returned: {result}")
return result # Can modify result
LLMCallback
Callbacks for LLM invocation events. Supports filtering by model names.
from kader.callbacks import LLMCallback, CallbackContext
class MyLLMCallback(LLMCallback):
def __init__(self, model_names: list[str] | None = None):
super().__init__(model_names=model_names)
def on_llm_start(
self,
context: CallbackContext,
messages: list,
config,
) -> tuple:
print(f"LLM call starting with {len(messages)} messages")
return messages, config # Can modify messages and config
def on_llm_end(
self,
context: CallbackContext,
messages: list,
response,
):
print(f"LLM response: {response.content}")
return response # Can modify response
Using Callbacks with Agents
Pass callbacks to the agent via the callbacks parameter:
from kader.agent import BaseAgent
from kader.callbacks import ToolCallback, LLMCallback, BaseCallback, CallbackContext
# Create callbacks
class LoggingToolCallback(ToolCallback):
def on_tool_before(self, context, tool_name, arguments):
print(f"[LOG] Calling {tool_name}")
return arguments
def on_tool_after(self, context, tool_name, arguments, result):
print(f"[LOG] {tool_name} -> {result}")
return result
class LoggingLLMCallback(LLMCallback):
def on_llm_start(self, context, messages, config):
print(f"[LOG] LLM call starting")
return messages, config
def on_llm_end(self, context, messages, response):
print(f"[LOG] LLM response: {response.content[:50]}...")
return response
class AgentEventsCallback(BaseCallback):
def on_agent_start(self, context):
print(f"[LOG] Agent starting!")
def on_agent_end(self, context):
print(f"[LOG] Agent finished!")
# Initialize agent with callbacks
agent = BaseAgent(
name="my_agent",
system_prompt="You are a helpful assistant.",
callbacks=[
LoggingToolCallback(),
LoggingLLMCallback(),
AgentEventsCallback(),
],
)
response = agent.invoke("Hello!")
Callback Execution Order
When multiple callbacks are registered, they are invoked in order:
on_agent_start- At the beginning ofinvoke()/ainvoke()on_llm_start- Before each LLM call (inside the agent loop)on_llm_end- After each LLM callon_tool_before- Before each tool executionon_tool_after- After each tool executionon_agent_end- At the end ofinvoke()/ainvoke()
Callback Context
All callbacks receive a CallbackContext object containing:
@dataclass
class CallbackContext:
event: CallbackEvent # The event that triggered the callback
agent_name: str # Name of the agent
extra: dict # Additional context data
Available Events
| Event | Description |
|---|---|
CallbackEvent.AGENT_START |
Agent starts execution |
CallbackEvent.AGENT_END |
Agent finishes execution |
CallbackEvent.LLM_START |
Before LLM invocation |
CallbackEvent.LLM_END |
After LLM invocation |
CallbackEvent.TOOL_BEFORE |
Before tool execution |
CallbackEvent.TOOL_AFTER |
After tool execution |
Built-in Callbacks
Kader provides several ready-to-use callbacks:
LoggingToolCallback
Logs tool execution events to the console.
from kader.callbacks import LoggingToolCallback
agent = BaseAgent(
callbacks=[LoggingToolCallback(tool_names=["read_file", "write_file"])]
)
LoggingLLMCallback
Logs LLM invocation events to the console.
from kader.callbacks import LoggingLLMCallback
agent = BaseAgent(
callbacks=[LoggingLLMCallback(model_names=["mistral-vibe-cli"])]
)
Transforming Arguments and Results
Callbacks can modify arguments before execution and results after:
class TransformCallback(ToolCallback):
def on_tool_before(self, context, tool_name, arguments):
# Add prefix to all arguments
arguments["_callback"] = f"Modified by {context.agent_name}"
return arguments
def on_tool_after(self, context, tool_name, arguments, result):
# Wrap result
result.content = f"[MODIFIED] {result.content}"
return result
Async Support
All callbacks work with both sync and async agent methods:
# Works with invoke()
response = agent.invoke("Hello")
# Works with ainvoke()
import asyncio
response = await agent.ainvoke("Hello")