Python: [BREAKING] Renamed AgentRunContext to AgentContext (#3714)

* Renamed AgentRunContext to AgentContext

* Update python/packages/core/AGENTS.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Dmytro Struk
2026-02-05 22:47:51 -08:00
committed by GitHub
Unverified
parent c609b14f63
commit 09f59b21ad
18 changed files with 219 additions and 319 deletions
+2 -2
View File
@@ -34,7 +34,7 @@ sequenceDiagram
Note over Agent,AML: Agent Middleware Layer
Agent->>AML: run() with middleware param
AML->>AML: categorize_middleware() → split by type
AML->>AMP: execute(AgentRunContext)
AML->>AMP: execute(AgentContext)
loop Agent Middleware Chain
AMP->>AMP: middleware[i].process(context, next)
@@ -127,7 +127,7 @@ sequenceDiagram
**Entry Point:** `Agent.run(messages, thread, options, middleware)`
**Context Object:** `AgentRunContext`
**Context Object:** `AgentContext`
| Field | Type | Description |
|-------|------|-------------|
@@ -13,7 +13,7 @@ This folder contains examples demonstrating various middleware patterns with the
| [`exception_handling_with_middleware.py`](exception_handling_with_middleware.py) | Demonstrates how to use middleware for centralized exception handling in function calls. Shows how to catch exceptions from functions, provide graceful error responses, and override function results when errors occur to provide user-friendly messages. |
| [`override_result_with_middleware.py`](override_result_with_middleware.py) | Shows how to use middleware to intercept and modify function results after execution, supporting both regular and streaming agent responses. Demonstrates result filtering, formatting, enhancement, and custom streaming response generation. |
| [`shared_state_middleware.py`](shared_state_middleware.py) | Demonstrates how to implement function-based middleware within a class to share state between multiple middleware functions. Shows how middleware can work together by sharing state, including call counting and result enhancement. |
| [`thread_behavior_middleware.py`](thread_behavior_middleware.py) | Demonstrates how middleware can access and track thread state across multiple agent runs. Shows how `AgentRunContext.thread` behaves differently before and after the `next()` call, how conversation history accumulates in threads, and timing of thread message updates. Essential for understanding conversation flow in middleware. |
| [`thread_behavior_middleware.py`](thread_behavior_middleware.py) | Demonstrates how middleware can access and track thread state across multiple agent runs. Shows how `AgentContext.thread` behaves differently before and after the `next()` call, how conversation history accumulates in threads, and timing of thread message updates. Essential for understanding conversation flow in middleware. |
| [`agent_and_run_level_middleware.py`](agent_and_run_level_middleware.py) | Explains the difference between agent-level middleware (applied to ALL runs of the agent) and run-level middleware (applied to specific runs only). Shows security validation, performance monitoring, and context-specific middleware patterns. |
| [`chat_middleware.py`](chat_middleware.py) | Demonstrates how to use chat middleware to observe and override inputs sent to AI models. Shows how to intercept chat requests, log and modify input messages, and override entire responses before they reach the underlying AI service. |
@@ -7,9 +7,9 @@ from random import randint
from typing import Annotated
from agent_framework import (
AgentContext,
AgentMiddleware,
AgentResponse,
AgentRunContext,
FunctionInvocationContext,
tool,
)
@@ -49,7 +49,7 @@ def get_weather(
class SecurityAgentMiddleware(AgentMiddleware):
"""Agent-level security middleware that validates all requests."""
async def process(self, context: AgentRunContext, next: Callable[[AgentRunContext], Awaitable[None]]) -> None:
async def process(self, context: AgentContext, next: Callable[[AgentContext], Awaitable[None]]) -> None:
print("[SecurityMiddleware] Checking security for all requests...")
# Check for security violations in the last user message
@@ -66,8 +66,8 @@ class SecurityAgentMiddleware(AgentMiddleware):
async def performance_monitor_middleware(
context: AgentRunContext,
next: Callable[[AgentRunContext], Awaitable[None]],
context: AgentContext,
next: Callable[[AgentContext], Awaitable[None]],
) -> None:
"""Agent-level performance monitoring for all runs."""
print("[PerformanceMonitor] Starting performance monitoring...")
@@ -85,7 +85,7 @@ async def performance_monitor_middleware(
class HighPriorityMiddleware(AgentMiddleware):
"""Run-level middleware for high priority requests."""
async def process(self, context: AgentRunContext, next: Callable[[AgentRunContext], Awaitable[None]]) -> None:
async def process(self, context: AgentContext, next: Callable[[AgentContext], Awaitable[None]]) -> None:
print("[HighPriority] Processing high priority request with expedited handling...")
# Read metadata set by agent-level middleware
@@ -101,8 +101,8 @@ class HighPriorityMiddleware(AgentMiddleware):
async def debugging_middleware(
context: AgentRunContext,
next: Callable[[AgentRunContext], Awaitable[None]],
context: AgentContext,
next: Callable[[AgentContext], Awaitable[None]],
) -> None:
"""Run-level debugging middleware for troubleshooting specific runs."""
print("[Debug] Debug mode enabled for this run")
@@ -126,7 +126,7 @@ class CachingMiddleware(AgentMiddleware):
def __init__(self) -> None:
self.cache: dict[str, AgentResponse] = {}
async def process(self, context: AgentRunContext, next: Callable[[AgentRunContext], Awaitable[None]]) -> None:
async def process(self, context: AgentContext, next: Callable[[AgentContext], Awaitable[None]]) -> None:
# Create a simple cache key from the last message
last_message = context.messages[-1] if context.messages else None
cache_key: str = last_message.text if last_message and last_message.text else "no_message"
@@ -7,9 +7,9 @@ from random import randint
from typing import Annotated
from agent_framework import (
AgentContext,
AgentMiddleware,
AgentResponse,
AgentRunContext,
ChatMessage,
FunctionInvocationContext,
FunctionMiddleware,
@@ -49,8 +49,8 @@ class SecurityAgentMiddleware(AgentMiddleware):
async def process(
self,
context: AgentRunContext,
next: Callable[[AgentRunContext], Awaitable[None]],
context: AgentContext,
next: Callable[[AgentContext], Awaitable[None]],
) -> None:
# Check for potential security violations in the query
# Look at the last user message
@@ -61,9 +61,7 @@ class SecurityAgentMiddleware(AgentMiddleware):
print("[SecurityAgentMiddleware] Security Warning: Detected sensitive information, blocking request.")
# Override the result with warning message
context.result = AgentResponse(
messages=[
ChatMessage("assistant", ["Detected sensitive information, the request is blocked."])
]
messages=[ChatMessage("assistant", ["Detected sensitive information, the request is blocked."])]
)
# Simply don't call next() to prevent execution
return
@@ -20,7 +20,7 @@ to explicitly mark middleware functions without requiring type annotations.
The framework supports the following middleware detection scenarios:
1. Both decorator and parameter type specified:
- Validates that they match (e.g., @agent_middleware with AgentRunContext)
- Validates that they match (e.g., @agent_middleware with AgentContext)
- Throws exception if they don't match for safety
2. Only decorator specified:
@@ -28,7 +28,7 @@ The framework supports the following middleware detection scenarios:
- No type annotations needed - framework handles context types automatically
3. Only parameter type specified:
- Uses type annotations (AgentRunContext, FunctionInvocationContext) for detection
- Uses type annotations (AgentContext, FunctionInvocationContext) for detection
4. Neither decorator nor parameter type specified:
- Throws exception requiring either decorator or type annotation
@@ -7,7 +7,7 @@ from random import randint
from typing import Annotated
from agent_framework import (
AgentRunContext,
AgentContext,
FunctionInvocationContext,
tool,
)
@@ -42,8 +42,8 @@ def get_weather(
async def security_agent_middleware(
context: AgentRunContext,
next: Callable[[AgentRunContext], Awaitable[None]],
context: AgentContext,
next: Callable[[AgentContext], Awaitable[None]],
) -> None:
"""Agent middleware that checks for security violations."""
# Check for potential security violations in the query
@@ -6,9 +6,9 @@ from random import randint
from typing import Annotated
from agent_framework import (
AgentContext,
AgentMiddleware,
AgentResponse,
AgentRunContext,
ChatMessage,
tool,
)
@@ -47,8 +47,8 @@ class PreTerminationMiddleware(AgentMiddleware):
async def process(
self,
context: AgentRunContext,
next: Callable[[AgentRunContext], Awaitable[None]],
context: AgentContext,
next: Callable[[AgentContext], Awaitable[None]],
) -> None:
# Check if the user message contains any blocked words
last_message = context.messages[-1] if context.messages else None
@@ -87,8 +87,8 @@ class PostTerminationMiddleware(AgentMiddleware):
async def process(
self,
context: AgentRunContext,
next: Callable[[AgentRunContext], Awaitable[None]],
context: AgentContext,
next: Callable[[AgentContext], Awaitable[None]],
) -> None:
print(f"[PostTerminationMiddleware] Processing request (response count: {self.response_count})")
@@ -7,9 +7,9 @@ from random import randint
from typing import Annotated
from agent_framework import (
AgentContext,
AgentResponse,
AgentResponseUpdate,
AgentRunContext,
ChatContext,
ChatMessage,
ChatResponse,
@@ -104,9 +104,7 @@ async def validate_weather_middleware(context: ChatContext, next: Callable[[Chat
context.result.messages.append(ChatMessage(role=Role.ASSISTANT, text=validation_note))
async def agent_cleanup_middleware(
context: AgentRunContext, next: Callable[[AgentRunContext], Awaitable[None]]
) -> None:
async def agent_cleanup_middleware(context: AgentContext, next: Callable[[AgentContext], Awaitable[None]]) -> None:
"""Agent middleware that validates chat middleware effects and cleans the result."""
await next(context)
@@ -5,7 +5,7 @@ from collections.abc import Awaitable, Callable
from typing import Annotated
from agent_framework import (
AgentRunContext,
AgentContext,
ChatMessageStore,
tool,
)
@@ -19,7 +19,7 @@ Thread Behavior MiddlewareTypes Example
This sample demonstrates how middleware can access and track thread state across multiple agent runs.
The example shows:
- How AgentRunContext.thread property behaves across multiple runs
- How AgentContext.thread property behaves across multiple runs
- How middleware can access conversation history through the thread
- The timing of when thread messages are populated (before vs after next() call)
- How to track thread state changes across runs
@@ -45,8 +45,8 @@ def get_weather(
async def thread_tracking_middleware(
context: AgentRunContext,
next: Callable[[AgentRunContext], Awaitable[None]],
context: AgentContext,
next: Callable[[AgentContext], Awaitable[None]],
) -> None:
"""MiddlewareTypes that tracks and logs thread behavior across runs."""
thread_messages = []