Context
Agents are stateless, Context is used to track the state of execution throughout each turn.
AgentContext
The default base context class for agents:
from factorial import AgentContext
context = AgentContext(
query="Tell me a joke",
messages=[], # Conversation history
turn=0, # Current turn number
)
Custom Agent Context
Create a custom agent context classes for specialized agents:
from typing import Any
from factorial import AgentContext
class DualAgentContext(AgentContext):
agent_a_messages: list[dict[str, Any]] = []
agent_b_messages: list[dict[str, Any]] = []
Using Custom Agent Context
from factorial import BaseAgent
class ABTestableAgent(BaseAgent[DualAgentContext]): # For the type checker
def __init__(self):
super().__init__(
description="Executes two agents side by side",
instructions="You are a helpful assistant",
tools=tools,
context_class=DualAgentContext, # For task serialization
)
# Create tasks with custom context
context = DualAgentContext(
query="Research AI developments",
)
task = agent.create_task(owner_id="user123", payload=context)
Execution Context
The ExecutionContext is a per-request context that tracks task-level information such as task ID, owner ID, retries, and pickups during agent execution.
Unlike AgentContext, it is not stored with the agent and is automatically managed by the framework.
from factorial import AgentContext, ExecutionContext
class MyAgent(Agent):
def run_turn(self, agent_ctx: AgentContext)
execution_ctx = self.get_execution_context()
# or
execution_ctx = ExecutionContext.current()
print(f"Task ID: {execution_ctx.task_id}")
print(f"Owner ID: {execution_ctx.owner_id}")
print(f"Retries: {execution_ctx.retries}")
print(f"Iterations: {execution_ctx.iterations}")
Using Context in Tools
The agent automatically injects the agent and execution context to tools that require them as arguments.
def stateless_tool(input_args: str) -> str:
...
def stateful_tool(input_args: str, agent_ctx: AgentContext) -> str:
if len(agent_ctx.messages) > 10:
return run_tool_b(input_args)
return run_tool_a(input_args)
def tool_with_fallbacks(input_args: str, agent_ctx: AgentContext, execution_ctx: ExecutionContext) -> str:
if execution_context.retries > 0:
return run_tool_b(input_args)
return run_tool_a(input_args)