Context Variables - AG2

Context Variables

Try it on the AG2 Playground

See context-driven routing live at playground.ag2.ai — no setup required.

Context Variables provide shared memory for your agents, allowing them to maintain state across a conversation and make decisions based on that shared information. If tools are the specialized capabilities agents can use, context variables are their collective knowledge base.

Introduction to Context Variables

Context Variables are a structured way to store and share information between agents in a group chat. They act as a persistent memory that:

The Hospital ER Analogy

Let's return to our hospital emergency room analogy to understand context variables.

Imagine a patient chart that follows them throughout their entire hospital visit. When a patient arrives at the ER:

In this analogy:

The ContextVariables Class

Context variables in AG2 are implemented through the ContextVariables class, which provides a dictionary-like interface to store and retrieve values:

from autogen.agentchat.group import ContextVariables

# Create context variables
context = ContextVariables(data={
    "user_name": "Alex",
    "issue_count": 0,
    "previous_issues": []
})

Core Functionality

Creating and Initializing Context Variables

You can create context variables when setting up your group chat pattern:

from autogen.agentchat.group import ContextVariables
from autogen.agentchat.group.patterns import AutoPattern

# Initialize context variables with initial data
context = ContextVariables(data={
    "user_name": "Alex",
    "issue_count": 0,
    "previous_issues": []
})

# Create pattern with the context variables
pattern = AutoPattern(
    initial_agent=triage_agent,
    agents=[triage_agent, tech_agent, general_agent],
    user_agent=user,
    context_variables=context,  # Pass context variables to the pattern
    group_manager_args={"llm_config": llm_config}
)

Reading and Writing Context Values

The ContextVariables class provides several methods for reading and writing values:

# Reading values
user_name = context.get("user_name")  # Returns "Alex"
non_existent = context.get("non_existent", "default")  # Returns "default"

# Writing values
context.set("issue_count", 1)  # Sets issue_count to 1
context.update({"last_login": "2023-05-01", "premium": True})  # Update multiple values

Dictionary-like Interface

The ContextVariables class implements a dictionary-like interface, allowing you to use a familiar syntax:

# Dictionary-like operations
user_name = context["user_name"]  # Get a value
context["issue_count"] = 2  # Set a value
del context["temporary_value"]  # Delete a value
if "premium" in context:  # Check if a key exists
    print("Premium user")

# Iterate over keys and values
for key, value in context:
    print(f"{key}: {value}")

Persistence Across Agent Transitions

One of the most powerful features of context variables is their persistence across agent transitions. When control passes from one agent to another, the context variables go with it, maintaining the shared state.

In the below example, the route_to_tech_support function updates the context variables with the current issue and passes control to the tech support agent who can then access the updated context variables to make informed decisions.

def route_to_tech_support(issue: str, context_variables: ContextVariables) -> ReplyResult:
    """Route an issue to technical support."""
    # Update the context with the current issue
    context_variables["current_issue"] = issue
    context_variables["issue_count"] += 1
    context_variables["previous_issues"].append(issue)

# Return control to the tech agent with the updated context
    return ReplyResult(
        message="Routing to technical support...",
        target=AgentTarget(tech_agent),
        context_variables=context_variables  # Update the shared context
    )

How Agents Access Context Variables

Context Variables are NOT Automatically Visible to LLMs

Context variables are not automatically included in the prompts sent to LLMs. Unlike conversation history, which is always visible, context variables remain in AG2's memory layer and must be explicitly accessed through specific mechanisms provided by the framework.

Why This Design?

AG2 keeps context variables separate from LLM prompts for several important reasons:

Three Access Methods

There are three primary ways agents can access context variables:

1. Through Tools with Context Parameters

The most common method is through tools that have a context_variables parameter. AG2's dependency injection automatically provides the current context:

def check_user_history(
    query: str,
    context_variables: ContextVariables  # AG2 injects this automatically
) -> str:
    """Check user's previous issues and provide personalized help."""
    user_name = context_variables.get("user_name", "User")
    issue_count = context_variables.get("issue_count", 0)

if issue_count > 3:
        return f"I see you've had {issue_count} issues today, {user_name}. Let me escalate this to a senior technician."
    else:
        return f"Let me help you with this issue, {user_name}."

2. Using System Message Templates

For critical context that agents should always be aware of, use the UpdateSystemMessage feature to dynamically update the system prompt:

from autogen import UpdateSystemMessage

agent = ConversableAgent(
    name="support_agent",
    system_message="You are a helpful support agent.",
    update_agent_state_before_reply=[
        UpdateSystemMessage(
            "You are helping {user_name} (Premium: {is_premium}). "
            "They have reported {issue_count} issues in this session. "
            "Current issue type: {issue_type}"
        )
    ]
)

This approach ensures that key context variables are always visible in the agent's system message, updated before each response.

3. Creating Context Summary Tools

For complex contexts, create dedicated tools that summarize the current state:

def get_session_summary(context_variables: ContextVariables) -> str:
    """Get a summary of the current support session."""
    summary = f"""
    Session Summary:
    - User: {context_variables.get('user_name', 'Unknown')}
    - Session Duration: {calculate_duration(context_variables.get('session_start'))}
    - Issues Reported: {context_variables.get('issue_count', 0)}
    - Current Status: {context_variables.get('status', 'Active')}
    - Last Action: {context_variables.get('last_action', 'None')}
    """
    return summary

Best Practices

Context Variables in Handoffs

Agent handoffs provide a sophisticated mechanism for using context variables to control conversation flow. Unlike tools and system messages where agents actively access context, handoffs use context to automatically determine routing between agents.

Context-Based Handoffs (OnContextCondition)

The most efficient way to route agents based on context is through OnContextCondition. These conditions evaluate context variables directly without using the LLM:

from autogen.agentchat.group import OnContextCondition, ExpressionContextCondition, ContextExpression
from autogen.agentchat.group import StringContextCondition, AgentTarget

# Simple context check - triggers when 'logged_in' is truthy
agent.handoffs.add_context_condition(
    OnContextCondition(
        target=AgentTarget(order_mgmt_agent),
        condition=StringContextCondition(variable_name="logged_in")
    )
)

# Complex expression - evaluates boolean expressions on context
agent.handoffs.add_context_condition(
    OnContextCondition(
        target=AgentTarget(advanced_support),
        condition=ExpressionContextCondition(
            ContextExpression("${issue_count} >= 3 and ${is_premium} == True")
        )
    )
)

These conditions are evaluated automatically before each agent response, without any LLM involvement.

LLM-Based Handoffs with Context (OnCondition)

For more nuanced decisions that require understanding message content, use OnCondition with context-aware prompts:

from autogen.agentchat.group import OnCondition, ContextStrLLMCondition, ContextStr
from autogen.agentchat.group import StringAvailableCondition

# The ContextStr template substitutes context variables into the prompt
agent.handoffs.add_llm_condition(
    OnCondition(
        target=AgentTarget(tech_support),
        condition=ContextStrLLMCondition(
            ContextStr("Transfer to tech support if the user mentions technical issues. "
                      "Current user: {user_name}, Issue count: {issue_count}")
        )
    )
)

AG2 dynamically substitutes context variables into these prompts before each agent response, so the LLM sees actual values (e.g., "Current user: John, Issue count: 3") without the context being part of the conversation history.

Conditional Availability

Both types of handoffs can be conditionally available based on context:

# This handoff is only available when not logged in
OnCondition(
    target=AgentTarget(auth_agent),
    condition=StringLLMCondition("Transfer to authentication if user needs to log in"),
    available=StringAvailableCondition(context_variable="requires_login")
)

How It All Works Together

The context-aware handoff mechanism provides a powerful way to create dynamic agent workflows:

This design allows you to build sophisticated routing logic that adapts to your application's state while keeping LLM prompts focused and token-efficient.

Extending the Triage Example

Let's enhance our triage system with context variables to maintain session state and provide personalized support:

import os
import pprint
from typing import Annotated
from datetime import datetime
from autogen import ConversableAgent, LLMConfig, UpdateSystemMessage
from autogen.agentchat import run_group_chat_iter
from autogen.agentchat.group.patterns import AutoPattern
from autogen.agentchat.group import ReplyResult, AgentNameTarget, ContextVariables
from autogen.events.agent_events import GroupChatRunChatEvent, InputRequestEvent, ToolResponseEvent
from dotenv import load_dotenv
load_dotenv()

# Initialize context variables
support_context = ContextVariables(data={
    "session_start": datetime.now().isoformat(),
    "query_history": [],
    "solutions_provided": [],
    "query_count": 0,
    "solution_count": 0
})

# Define tools that use context variables
def classify_and_log_query(
    query: Annotated[str, "The user query to classify"],
    context_variables: ContextVariables
) -> ReplyResult:
    """Classify a user query as technical or general and log it in the context."""

# Printing the context variables
    print(f"{context_variables.to_dict()=}")

# Record this query in history
    query_history = context_variables.get("query_history", [])
    query_record = {
        "timestamp": datetime.now().isoformat(),
        "query": query
    }
    query_history.append(query_record)
    context_variables["query_history"] = query_history
    context_variables["last_query"] = query
    context_variables["query_count"] = len(query_history)

# Basic classification logic
    technical_keywords = ["error", "bug", "broken", "crash", "not working", "shutting down"]
    is_technical = any(keyword in query.lower() for keyword in technical_keywords)

# Update context with classification
    if is_technical:
        target_agent = AgentNameTarget("tech_agent")
        context_variables["query_type"] = "technical"
        message = "This appears to be a technical issue. Routing to technical support..."
    else:
        target_agent = AgentNameTarget("general_agent")
        context_variables["query_type"] = "general"
        message = "This appears to be a general question. Routing to general support..."

# Printing the context variables
    print(f"{context_variables.to_dict()=}")

return ReplyResult(
        message=message,
        target=target_agent,
        context_variables=context_variables
    )

def provide_technical_solution(
    solution: Annotated[str, "Technical solution to provide"],
    context_variables: ContextVariables
) -> ReplyResult:
    """Provide a technical solution and record it in the context."""

# Printing the context variables
    print(f"{context_variables.to_dict()=}")

# Record the solution
    last_query = context_variables.get("last_query", "your issue")
    solutions_provided = context_variables.get("solutions_provided", [])

solution_record = {
        "timestamp": datetime.now().isoformat(),
        "query": last_query,
        "solution": solution
    }
    solutions_provided.append(solution_record)

# Update context
    context_variables["solutions_provided"] = solutions_provided
    context_variables["last_solution"] = solution
    context_variables["solution_count"] = len(solutions_provided)

# Printing the context variables
    print(f"{context_variables.to_dict()=}")

return ReplyResult(
        message=solution,
        context_variables=context_variables
    )

def get_user_context(context_variables: ContextVariables) -> str:
    """Get information about the current user and session."""
    user_name = context_variables.get("user_name", "User")
    query_count = context_variables.get("query_count", 0)
    session_start = context_variables.get("session_start", "Unknown")

return f"""Current session information:
    - Session started: {session_start}
    - Total queries: {query_count}
    - Last query: {context_variables.get("last_query", "None")}
    - Query type: {context_variables.get("query_type", "Unknown")}"""

# Create the agents
llm_config = LLMConfig({"api_type": "openai", "model": "gpt-5-nano","api_key":os.getenv("OPENAI_API_KEY")})

triage_agent = ConversableAgent(
    name="triage_agent",
    system_message="""You are a triage agent. For each user query,
    identify whether it is a technical issue or a general question.
    Use the classify_and_log_query tool to categorize and log queries.""",
    functions=[classify_and_log_query],
    llm_config=llm_config
)

tech_agent = ConversableAgent(
    name="tech_agent",
    system_message="""You solve technical problems like software bugs
    and hardware issues. After analyzing the problem, use the provide_technical_solution
    tool to format your response consistently and log it for future reference.""",
    functions=[provide_technical_solution],
    # Using UpdateSystemMessage to make context visible
    update_agent_state_before_reply=[
        UpdateSystemMessage(
            "You are assisting with query #{query_count}. "
            "The current issue is: {last_query} (Type: {query_type})" 
        )
    ],
    llm_config=llm_config
)

general_agent = ConversableAgent(
    name="general_agent",
    system_message="""You handle general, non-technical support questions.
    Use the get_user_context tool to understand the current session before responding.""",
    # Providing a tool to access context
    functions=[get_user_context],
    llm_config=llm_config
)

# User agent
user = ConversableAgent(name="user", human_input_mode="ALWAYS")

# Set up the conversation pattern with context variables
pattern = AutoPattern(
    initial_agent=triage_agent,
    agents=[triage_agent, tech_agent, general_agent],
    user_agent=user,
    context_variables=support_context,  # Pass our initialized context
    group_manager_args={"llm_config": llm_config}
)

# Run the chat events
for event in run_group_chat_iter(
    pattern=pattern,
    messages="My laptop keeps shutting down randomly. Can you help?",
    max_rounds=20,
):
    if isinstance(event, InputRequestEvent):
        user_input = input("  Input requested: ")
        event.content.respond(user_input)
        continue

if isinstance(event, GroupChatRunChatEvent):
        print(f"\n=== {event.content.speaker}'s turn ===")
        pprint.pprint(event.content)
        print("-" * 80)

if isinstance(event, ToolResponseEvent):
        print(f"\n=== {event.content} tool response ===")
        print("-" * 80)

if hasattr(event, "content") and hasattr(event.content, "content"):
        content = str(event.content.content)
        pprint.pprint(content)
        print("-" * 80)
    pass

Key Takeaways

Understanding Context Variables in AG2

Next Steps

Now that you understand Context Variables, the next section will explore Handoffs and Transitions - the mechanisms that control how agents pass control to each other in a group chat.

In the Handoffs and Transitions section, you'll learn:

The concepts you've learned about tools and context variables will be essential as we explore how to control the flow of conversation in complex multi-agent systems.