Python: [BREAKING] Renamed AgentProtocol to SupportsAgentRun (#3717)

* Renamed AgentProtocol to AgentLike

* Resolved comments

* Renamed AgentLike to SupportsAgentRun

* Resolved comments
This commit is contained in:
Dmytro Struk
2026-02-06 09:53:21 -08:00
committed by GitHub
Unverified
parent ac17adb595
commit 15256bb616
55 changed files with 354 additions and 354 deletions
+3 -3
View File
@@ -12,7 +12,6 @@ from pydantic import BaseModel
from pytest import fixture
from agent_framework import (
AgentProtocol,
AgentResponse,
AgentResponseUpdate,
AgentThread,
@@ -24,6 +23,7 @@ from agent_framework import (
Content,
FunctionInvocationLayer,
ResponseStream,
SupportsAgentRun,
ToolProtocol,
tool,
)
@@ -273,7 +273,7 @@ class MockAgentThread(AgentThread):
# Mock Agent implementation for testing
class MockAgent(AgentProtocol):
class MockAgent(SupportsAgentRun):
@property
def id(self) -> str:
return str(uuid4())
@@ -329,5 +329,5 @@ def agent_thread() -> AgentThread:
@fixture
def agent() -> AgentProtocol:
def agent() -> SupportsAgentRun:
return MockAgent()
@@ -10,7 +10,6 @@ import pytest
from pytest import raises
from agent_framework import (
AgentProtocol,
AgentResponse,
AgentResponseUpdate,
AgentThread,
@@ -24,6 +23,7 @@ from agent_framework import (
Context,
ContextProvider,
HostedCodeInterpreterTool,
SupportsAgentRun,
ToolProtocol,
tool,
)
@@ -36,17 +36,17 @@ def test_agent_thread_type(agent_thread: AgentThread) -> None:
assert isinstance(agent_thread, AgentThread)
def test_agent_type(agent: AgentProtocol) -> None:
assert isinstance(agent, AgentProtocol)
def test_agent_type(agent: SupportsAgentRun) -> None:
assert isinstance(agent, SupportsAgentRun)
async def test_agent_run(agent: AgentProtocol) -> None:
async def test_agent_run(agent: SupportsAgentRun) -> None:
response = await agent.run("test")
assert response.messages[0].role == "assistant"
assert response.messages[0].text == "Response"
async def test_agent_run_streaming(agent: AgentProtocol) -> None:
async def test_agent_run_streaming(agent: SupportsAgentRun) -> None:
async def collect_updates(updates: AsyncIterable[AgentResponseUpdate]) -> list[AgentResponseUpdate]:
return [u async for u in updates]
@@ -57,7 +57,7 @@ async def test_agent_run_streaming(agent: AgentProtocol) -> None:
def test_chat_client_agent_type(chat_client: ChatClientProtocol) -> None:
chat_client_agent = ChatAgent(chat_client=chat_client)
assert isinstance(chat_client_agent, AgentProtocol)
assert isinstance(chat_client_agent, SupportsAgentRun)
async def test_chat_client_agent_init(chat_client: ChatClientProtocol) -> None:
@@ -804,7 +804,7 @@ def test_sanitize_agent_name_replaces_invalid_chars():
# endregion
# region Test AgentProtocol.get_new_thread and deserialize_thread
# region Test SupportsAgentRun.get_new_thread and deserialize_thread
@pytest.mark.asyncio
@@ -8,7 +8,6 @@ import pytest
from pydantic import BaseModel, Field
from agent_framework import (
AgentProtocol,
AgentResponse,
AgentResponseUpdate,
ChatMessage,
@@ -16,6 +15,7 @@ from agent_framework import (
ChatResponseUpdate,
Content,
ResponseStream,
SupportsAgentRun,
)
from agent_framework._middleware import (
AgentContext,
@@ -35,7 +35,7 @@ from agent_framework._tools import FunctionTool
class TestAgentContext:
"""Test cases for AgentContext."""
def test_init_with_defaults(self, mock_agent: AgentProtocol) -> None:
def test_init_with_defaults(self, mock_agent: SupportsAgentRun) -> None:
"""Test AgentContext initialization with default values."""
messages = [ChatMessage(role="user", text="test")]
context = AgentContext(agent=mock_agent, messages=messages)
@@ -45,7 +45,7 @@ class TestAgentContext:
assert context.stream is False
assert context.metadata == {}
def test_init_with_custom_values(self, mock_agent: AgentProtocol) -> None:
def test_init_with_custom_values(self, mock_agent: SupportsAgentRun) -> None:
"""Test AgentContext initialization with custom values."""
messages = [ChatMessage(role="user", text="test")]
metadata = {"key": "value"}
@@ -56,7 +56,7 @@ class TestAgentContext:
assert context.stream is True
assert context.metadata == metadata
def test_init_with_thread(self, mock_agent: AgentProtocol) -> None:
def test_init_with_thread(self, mock_agent: SupportsAgentRun) -> None:
"""Test AgentContext initialization with thread parameter."""
from agent_framework import AgentThread
@@ -163,7 +163,7 @@ class TestAgentMiddlewarePipeline:
pipeline = AgentMiddlewarePipeline(test_middleware)
assert pipeline.has_middlewares
async def test_execute_no_middleware(self, mock_agent: AgentProtocol) -> None:
async def test_execute_no_middleware(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline execution with no middleware."""
pipeline = AgentMiddlewarePipeline()
messages = [ChatMessage(role="user", text="test")]
@@ -177,7 +177,7 @@ class TestAgentMiddlewarePipeline:
result = await pipeline.execute(context, final_handler)
assert result == expected_response
async def test_execute_with_middleware(self, mock_agent: AgentProtocol) -> None:
async def test_execute_with_middleware(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline execution with middleware."""
execution_order: list[str] = []
@@ -205,7 +205,7 @@ class TestAgentMiddlewarePipeline:
assert result == expected_response
assert execution_order == ["test_before", "handler", "test_after"]
async def test_execute_stream_no_middleware(self, mock_agent: AgentProtocol) -> None:
async def test_execute_stream_no_middleware(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline streaming execution with no middleware."""
pipeline = AgentMiddlewarePipeline()
messages = [ChatMessage(role="user", text="test")]
@@ -228,7 +228,7 @@ class TestAgentMiddlewarePipeline:
assert updates[0].text == "chunk1"
assert updates[1].text == "chunk2"
async def test_execute_stream_with_middleware(self, mock_agent: AgentProtocol) -> None:
async def test_execute_stream_with_middleware(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline streaming execution with middleware."""
execution_order: list[str] = []
@@ -265,7 +265,7 @@ class TestAgentMiddlewarePipeline:
assert updates[1].text == "chunk2"
assert execution_order == ["test_before", "test_after", "handler_start", "handler_end"]
async def test_execute_with_pre_next_termination(self, mock_agent: AgentProtocol) -> None:
async def test_execute_with_pre_next_termination(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline execution with termination before next()."""
middleware = self.PreNextTerminateMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
@@ -283,7 +283,7 @@ class TestAgentMiddlewarePipeline:
# Handler should not be called when terminated before next()
assert execution_order == []
async def test_execute_with_post_next_termination(self, mock_agent: AgentProtocol) -> None:
async def test_execute_with_post_next_termination(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline execution with termination after next()."""
middleware = self.PostNextTerminateMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
@@ -301,7 +301,7 @@ class TestAgentMiddlewarePipeline:
assert response.messages[0].text == "response"
assert execution_order == ["handler"]
async def test_execute_stream_with_pre_next_termination(self, mock_agent: AgentProtocol) -> None:
async def test_execute_stream_with_pre_next_termination(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline streaming execution with termination before next()."""
middleware = self.PreNextTerminateMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
@@ -329,7 +329,7 @@ class TestAgentMiddlewarePipeline:
assert execution_order == []
assert not updates
async def test_execute_stream_with_post_next_termination(self, mock_agent: AgentProtocol) -> None:
async def test_execute_stream_with_post_next_termination(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline streaming execution with termination after next()."""
middleware = self.PostNextTerminateMiddleware()
pipeline = AgentMiddlewarePipeline(middleware)
@@ -356,7 +356,7 @@ class TestAgentMiddlewarePipeline:
assert updates[1].text == "chunk2"
assert execution_order == ["handler_start", "handler_end"]
async def test_execute_with_thread_in_context(self, mock_agent: AgentProtocol) -> None:
async def test_execute_with_thread_in_context(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline execution properly passes thread to middleware."""
from agent_framework import AgentThread
@@ -383,7 +383,7 @@ class TestAgentMiddlewarePipeline:
assert result == expected_response
assert captured_thread is thread
async def test_execute_with_no_thread_in_context(self, mock_agent: AgentProtocol) -> None:
async def test_execute_with_no_thread_in_context(self, mock_agent: SupportsAgentRun) -> None:
"""Test pipeline execution when no thread is provided."""
captured_thread = "not_none" # Use string to distinguish from None
@@ -761,7 +761,7 @@ class TestChatMiddlewarePipeline:
class TestClassBasedMiddleware:
"""Test cases for class-based middleware implementations."""
async def test_agent_middleware_execution(self, mock_agent: AgentProtocol) -> None:
async def test_agent_middleware_execution(self, mock_agent: SupportsAgentRun) -> None:
"""Test class-based agent middleware execution."""
metadata_updates: list[str] = []
@@ -825,7 +825,7 @@ class TestClassBasedMiddleware:
class TestFunctionBasedMiddleware:
"""Test cases for function-based middleware implementations."""
async def test_agent_function_middleware(self, mock_agent: AgentProtocol) -> None:
async def test_agent_function_middleware(self, mock_agent: SupportsAgentRun) -> None:
"""Test function-based agent middleware."""
execution_order: list[str] = []
@@ -879,7 +879,7 @@ class TestFunctionBasedMiddleware:
class TestMixedMiddleware:
"""Test cases for mixed class and function-based middleware."""
async def test_mixed_agent_middleware(self, mock_agent: AgentProtocol) -> None:
async def test_mixed_agent_middleware(self, mock_agent: SupportsAgentRun) -> None:
"""Test mixed class and function-based agent middleware."""
execution_order: list[str] = []
@@ -976,7 +976,7 @@ class TestMixedMiddleware:
class TestMultipleMiddlewareOrdering:
"""Test cases for multiple middleware execution order."""
async def test_agent_middleware_execution_order(self, mock_agent: AgentProtocol) -> None:
async def test_agent_middleware_execution_order(self, mock_agent: SupportsAgentRun) -> None:
"""Test that multiple agent middleware execute in registration order."""
execution_order: list[str] = []
@@ -1110,7 +1110,7 @@ class TestMultipleMiddlewareOrdering:
class TestContextContentValidation:
"""Test cases for validating middleware context content."""
async def test_agent_context_validation(self, mock_agent: AgentProtocol) -> None:
async def test_agent_context_validation(self, mock_agent: SupportsAgentRun) -> None:
"""Test that agent context contains expected data."""
class ContextValidationMiddleware(AgentMiddleware):
@@ -1231,7 +1231,7 @@ class TestContextContentValidation:
class TestStreamingScenarios:
"""Test cases for streaming and non-streaming scenarios."""
async def test_streaming_flag_validation(self, mock_agent: AgentProtocol) -> None:
async def test_streaming_flag_validation(self, mock_agent: SupportsAgentRun) -> None:
"""Test that stream flag is correctly set for streaming calls."""
streaming_flags: list[bool] = []
@@ -1271,7 +1271,7 @@ class TestStreamingScenarios:
# Verify flags: [non-streaming middleware, non-streaming handler, streaming middleware, streaming handler]
assert streaming_flags == [False, False, True, True]
async def test_streaming_middleware_behavior(self, mock_agent: AgentProtocol) -> None:
async def test_streaming_middleware_behavior(self, mock_agent: SupportsAgentRun) -> None:
"""Test middleware behavior with streaming responses."""
chunks_processed: list[str] = []
@@ -1437,7 +1437,7 @@ class MockFunctionArgs(BaseModel):
class TestMiddlewareExecutionControl:
"""Test cases for middleware execution control (when next() is called vs not called)."""
async def test_agent_middleware_no_next_no_execution(self, mock_agent: AgentProtocol) -> None:
async def test_agent_middleware_no_next_no_execution(self, mock_agent: SupportsAgentRun) -> None:
"""Test that when agent middleware doesn't call next(), no execution happens."""
class NoNextMiddleware(AgentMiddleware):
@@ -1464,7 +1464,7 @@ class TestMiddlewareExecutionControl:
assert not handler_called
assert context.result is None
async def test_agent_middleware_no_next_no_streaming_execution(self, mock_agent: AgentProtocol) -> None:
async def test_agent_middleware_no_next_no_streaming_execution(self, mock_agent: SupportsAgentRun) -> None:
"""Test that when agent middleware doesn't call next(), no streaming execution happens."""
class NoNextStreamingMiddleware(AgentMiddleware):
@@ -1529,7 +1529,7 @@ class TestMiddlewareExecutionControl:
assert not handler_called
assert context.result is None
async def test_multiple_middlewares_early_stop(self, mock_agent: AgentProtocol) -> None:
async def test_multiple_middlewares_early_stop(self, mock_agent: SupportsAgentRun) -> None:
"""Test that when first middleware doesn't call next(), subsequent middleware are not called."""
execution_order: list[str] = []
@@ -1664,9 +1664,9 @@ class TestMiddlewareExecutionControl:
@pytest.fixture
def mock_agent() -> AgentProtocol:
def mock_agent() -> SupportsAgentRun:
"""Mock agent for testing."""
agent = MagicMock(spec=AgentProtocol)
agent = MagicMock(spec=SupportsAgentRun)
agent.name = "test_agent"
return agent
@@ -8,13 +8,13 @@ import pytest
from pydantic import BaseModel, Field
from agent_framework import (
AgentProtocol,
AgentResponse,
AgentResponseUpdate,
ChatAgent,
ChatMessage,
Content,
ResponseStream,
SupportsAgentRun,
)
from agent_framework._middleware import (
AgentContext,
@@ -38,7 +38,7 @@ class FunctionTestArgs(BaseModel):
class TestResultOverrideMiddleware:
"""Test cases for middleware result override functionality."""
async def test_agent_middleware_response_override_non_streaming(self, mock_agent: AgentProtocol) -> None:
async def test_agent_middleware_response_override_non_streaming(self, mock_agent: SupportsAgentRun) -> None:
"""Test that agent middleware can override response for non-streaming execution."""
override_response = AgentResponse(messages=[ChatMessage(role="assistant", text="overridden response")])
@@ -69,7 +69,7 @@ class TestResultOverrideMiddleware:
# Verify original handler was called since middleware called next()
assert handler_called
async def test_agent_middleware_response_override_streaming(self, mock_agent: AgentProtocol) -> None:
async def test_agent_middleware_response_override_streaming(self, mock_agent: SupportsAgentRun) -> None:
"""Test that agent middleware can override response for streaming execution."""
async def override_stream() -> AsyncIterable[AgentResponseUpdate]:
@@ -211,7 +211,7 @@ class TestResultOverrideMiddleware:
assert normal_updates[0].text == "test streaming response "
assert normal_updates[1].text == "another update"
async def test_agent_middleware_conditional_no_next(self, mock_agent: AgentProtocol) -> None:
async def test_agent_middleware_conditional_no_next(self, mock_agent: SupportsAgentRun) -> None:
"""Test that when agent middleware conditionally doesn't call next(), no execution happens."""
class ConditionalNoNextMiddleware(AgentMiddleware):
@@ -303,7 +303,7 @@ class TestResultOverrideMiddleware:
class TestResultObservability:
"""Test cases for middleware result observability functionality."""
async def test_agent_middleware_response_observability(self, mock_agent: AgentProtocol) -> None:
async def test_agent_middleware_response_observability(self, mock_agent: SupportsAgentRun) -> None:
"""Test that middleware can observe response after execution."""
observed_responses: list[AgentResponse] = []
@@ -370,7 +370,7 @@ class TestResultObservability:
assert observed_results[0] == "executed function result"
assert result == observed_results[0]
async def test_agent_middleware_post_execution_override(self, mock_agent: AgentProtocol) -> None:
async def test_agent_middleware_post_execution_override(self, mock_agent: SupportsAgentRun) -> None:
"""Test that middleware can override response after observing execution."""
class PostExecutionOverrideMiddleware(AgentMiddleware):
@@ -436,9 +436,9 @@ class TestResultObservability:
@pytest.fixture
def mock_agent() -> AgentProtocol:
def mock_agent() -> SupportsAgentRun:
"""Mock agent for testing."""
agent = MagicMock(spec=AgentProtocol)
agent = MagicMock(spec=SupportsAgentRun)
agent.name = "test_agent"
return agent
@@ -1853,13 +1853,13 @@ class TestChatAgentChatMiddleware:
# class TestMiddlewareWithProtocolOnlyAgent:
# """Test use_agent_middleware with agents implementing only AgentProtocol."""
# """Test use_agent_middleware with agents implementing only SupportsAgentRun."""
# async def test_middleware_with_protocol_only_agent(self) -> None:
# """Verify middleware works without BaseAgent inheritance for both run."""
# from collections.abc import AsyncIterable
# from agent_framework import AgentProtocol, AgentResponse, AgentResponseUpdate
# from agent_framework import SupportsAgentRun, AgentResponse, AgentResponseUpdate
# execution_order: list[str] = []
@@ -1873,7 +1873,7 @@ class TestChatAgentChatMiddleware:
# @use_agent_middleware
# class ProtocolOnlyAgent:
# """Minimal agent implementing only AgentProtocol, not inheriting from BaseAgent."""
# """Minimal agent implementing only SupportsAgentRun, not inheriting from BaseAgent."""
# def __init__(self):
# self.id = "protocol-only-agent"
@@ -1896,7 +1896,7 @@ class TestChatAgentChatMiddleware:
# return None
# agent = ProtocolOnlyAgent()
# assert isinstance(agent, AgentProtocol)
# assert isinstance(agent, SupportsAgentRun)
# # Test run (non-streaming)
# response = await agent.run("test message")
@@ -12,7 +12,6 @@ from opentelemetry.trace import StatusCode
from agent_framework import (
AGENT_FRAMEWORK_USER_AGENT,
AgentProtocol,
AgentResponse,
BaseChatClient,
ChatMessage,
@@ -20,6 +19,7 @@ from agent_framework import (
ChatResponseUpdate,
Content,
ResponseStream,
SupportsAgentRun,
UsageDetails,
prepend_agent_framework_to_user_agent,
tool,
@@ -473,7 +473,7 @@ def mock_chat_agent():
@pytest.mark.parametrize("enable_sensitive_data", [True, False], indirect=True)
async def test_agent_instrumentation_enabled(
mock_chat_agent: AgentProtocol, span_exporter: InMemorySpanExporter, enable_sensitive_data
mock_chat_agent: SupportsAgentRun, span_exporter: InMemorySpanExporter, enable_sensitive_data
):
"""Test that when agent diagnostics are enabled, telemetry is applied."""
@@ -499,7 +499,7 @@ async def test_agent_instrumentation_enabled(
@pytest.mark.parametrize("enable_sensitive_data", [True, False], indirect=True)
async def test_agent_streaming_response_with_diagnostics_enabled(
mock_chat_agent: AgentProtocol, span_exporter: InMemorySpanExporter, enable_sensitive_data
mock_chat_agent: SupportsAgentRun, span_exporter: InMemorySpanExporter, enable_sensitive_data
):
"""Test agent streaming telemetry through the agent telemetry mixin."""
agent = mock_chat_agent()
@@ -9,7 +9,6 @@ from typing_extensions import Never
from agent_framework import (
AgentExecutorRequest,
AgentProtocol,
AgentResponse,
AgentResponseUpdate,
AgentThread,
@@ -18,6 +17,7 @@ from agent_framework import (
Content,
Executor,
ResponseStream,
SupportsAgentRun,
UsageDetails,
WorkflowAgent,
WorkflowBuilder,
@@ -615,7 +615,7 @@ class TestWorkflowAgent:
async def test_agent_executor_output_response_false_filters_streaming_events(self):
"""Test that AgentExecutor with output_response=False does not surface streaming events."""
class MockAgent(AgentProtocol):
class MockAgent(SupportsAgentRun):
"""Mock agent for testing."""
def __init__(self, name: str, response_text: str) -> None:
@@ -705,7 +705,7 @@ class TestWorkflowAgent:
async def test_agent_executor_output_response_no_duplicate_from_workflow_output_event(self):
"""Test that AgentExecutor with output_response=True does not duplicate content."""
class MockAgent(AgentProtocol):
class MockAgent(SupportsAgentRun):
"""Mock agent for testing."""
def __init__(self, name: str, response_text: str) -> None:
@@ -422,7 +422,7 @@ def test_mixing_eager_and_lazy_initialization_error():
ValueError,
match=(
r"Both source and target must be either registered factory names \(str\) "
r"or Executor/AgentProtocol instances\."
r"or Executor/SupportsAgentRun instances\."
),
):
builder.add_edge(eager_executor, "Lazy")