renamed all (#3207)

This commit is contained in:
Eduard van Valkenburg
2026-01-14 06:54:07 +01:00
committed by GitHub
Unverified
parent 1ae0b09e42
commit d8cf8361bd
125 changed files with 1024 additions and 1027 deletions
@@ -145,7 +145,7 @@ class MessageMapper:
"""Convert a single Agent Framework event to OpenAI events.
Args:
raw_event: Agent Framework event (AgentRunResponseUpdate, WorkflowEvent, etc.)
raw_event: Agent Framework event (AgentResponseUpdate, WorkflowEvent, etc.)
request: Original request for context
Returns:
@@ -178,26 +178,26 @@ class MessageMapper:
# Import Agent Framework types for proper isinstance checks
try:
from agent_framework import AgentRunResponse, AgentRunResponseUpdate, WorkflowEvent
from agent_framework import AgentResponse, AgentResponseUpdate, WorkflowEvent
from agent_framework._workflows._events import AgentRunUpdateEvent
# Handle AgentRunUpdateEvent - workflow event wrapping AgentRunResponseUpdate
# Handle AgentRunUpdateEvent - workflow event wrapping AgentResponseUpdate
# This must be checked BEFORE generic WorkflowEvent check
if isinstance(raw_event, AgentRunUpdateEvent):
# Extract the AgentRunResponseUpdate from the event's data attribute
if raw_event.data and isinstance(raw_event.data, AgentRunResponseUpdate):
# Extract the AgentResponseUpdate from the event's data attribute
if raw_event.data and isinstance(raw_event.data, AgentResponseUpdate):
# Preserve executor_id in context for proper output routing
context["current_executor_id"] = raw_event.executor_id
return await self._convert_agent_update(raw_event.data, context)
# If no data, treat as generic workflow event
return await self._convert_workflow_event(raw_event, context)
# Handle complete agent response (AgentRunResponse) - for non-streaming agent execution
if isinstance(raw_event, AgentRunResponse):
# Handle complete agent response (AgentResponse) - for non-streaming agent execution
if isinstance(raw_event, AgentResponse):
return await self._convert_agent_response(raw_event, context)
# Handle agent updates (AgentRunResponseUpdate) - for direct agent execution
if isinstance(raw_event, AgentRunResponseUpdate):
# Handle agent updates (AgentResponseUpdate) - for direct agent execution
if isinstance(raw_event, AgentResponseUpdate):
return await self._convert_agent_update(raw_event, context)
# Handle workflow events (any class that inherits from WorkflowEvent)
@@ -686,13 +686,13 @@ class MessageMapper:
return events
async def _convert_agent_response(self, response: Any, context: dict[str, Any]) -> Sequence[Any]:
"""Convert complete AgentRunResponse to OpenAI events.
"""Convert complete AgentResponse to OpenAI events.
This handles non-streaming agent execution where agent.run() returns
a complete AgentRunResponse instead of streaming AgentRunResponseUpdate objects.
a complete AgentResponse instead of streaming AgentResponseUpdate objects.
Args:
response: Agent run response (AgentRunResponse)
response: Agent run response (AgentResponse)
context: Conversion context
Returns:
@@ -1047,7 +1047,7 @@ class MessageMapper:
# Create ExecutorActionItem with completed status
# ExecutorCompletedEvent uses 'data' field, not 'result'
# Serialize the result data to ensure it's JSON-serializable
# (AgentExecutorResponse contains AgentRunResponse/ChatMessage which are SerializationMixin)
# (AgentExecutorResponse contains AgentResponse/ChatMessage which are SerializationMixin)
raw_result = getattr(event, "data", None)
serialized_result = self._serialize_value(raw_result) if raw_result is not None else None
executor_item = ExecutorActionItem(
@@ -208,7 +208,7 @@ export interface UsageDetails {
}
// Agent run response update (streaming)
export interface AgentRunResponseUpdate {
export interface AgentResponseUpdate {
contents: Contents[];
role?: Role;
author_name?: string;
@@ -222,7 +222,7 @@ export interface AgentRunResponseUpdate {
}
// Agent run response (final)
export interface AgentRunResponse {
export interface AgentResponse {
messages: ChatMessage[];
response_id?: string;
created_at?: CreatedAtT;
@@ -302,11 +302,11 @@ export interface ExecutorEvent extends WorkflowEvent {
}
export interface AgentRunUpdateEvent extends ExecutorEvent {
data?: AgentRunResponseUpdate;
data?: AgentResponseUpdate;
}
export interface AgentRunEvent extends ExecutorEvent {
data?: AgentRunResponse;
data?: AgentResponse;
}
// Span event structure (from OpenTelemetry)
@@ -7,7 +7,7 @@ import tempfile
from pathlib import Path
import pytest
from agent_framework import AgentRunResponse, ChatMessage, Role, TextContent
from agent_framework import AgentResponse, ChatMessage, Role, TextContent
from agent_framework_devui import register_cleanup
from agent_framework_devui._discovery import EntityDiscovery
@@ -35,7 +35,7 @@ class MockAgent:
async def run_stream(self, messages=None, *, thread=None, **kwargs):
"""Mock streaming run method."""
yield AgentRunResponse(
yield AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text="Test response")])],
)
@@ -259,7 +259,7 @@ async def test_cleanup_with_file_based_discovery():
# Write agent module with cleanup registration
agent_file = agent_dir / "__init__.py"
agent_file.write_text("""
from agent_framework import AgentRunResponse, ChatMessage, Role, TextContent
from agent_framework import AgentResponse, ChatMessage, Role, TextContent
from agent_framework_devui import register_cleanup
class MockCredential:
@@ -278,7 +278,7 @@ class TestAgent:
description = "Test agent with cleanup"
async def run_stream(self, messages=None, *, thread=None, **kwargs):
yield AgentRunResponse(
yield AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, content=[TextContent(text="Test")])],
inner_messages=[],
)
@@ -84,7 +84,7 @@ async def test_discovery_accepts_agents_with_only_run():
init_file = agent_dir / "__init__.py"
init_file.write_text("""
from agent_framework import AgentRunResponse, AgentThread, ChatMessage, Role, TextContent
from agent_framework import AgentResponse, AgentThread, ChatMessage, Role, TextContent
class NonStreamingAgent:
id = "non_streaming"
@@ -92,7 +92,7 @@ class NonStreamingAgent:
description = "Agent without run_stream"
async def run(self, messages=None, *, thread=None, **kwargs):
return AgentRunResponse(
return AgentResponse(
messages=[ChatMessage(
role=Role.ASSISTANT,
contents=[TextContent(text="response")]
@@ -203,13 +203,13 @@ workflow = builder.build()
agent_dir = temp_path / "my_agent"
agent_dir.mkdir()
(agent_dir / "agent.py").write_text("""
from agent_framework import AgentRunResponse, AgentThread, ChatMessage, Role, TextContent
from agent_framework import AgentResponse, AgentThread, ChatMessage, Role, TextContent
class TestAgent:
name = "Test Agent"
async def run(self, messages=None, *, thread=None, **kwargs):
return AgentRunResponse(
return AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text="test")])],
response_id="test"
)
@@ -287,7 +287,7 @@ async def test_full_pipeline_agent_events_are_json_serializable(executor_with_re
2. Each event is converted by the mapper
3. Server calls model_dump_json() on each event for SSE
If any event contains non-serializable objects (like AgentRunResponse),
If any event contains non-serializable objects (like AgentResponse),
this test will fail - catching the bug before it hits production.
"""
executor, entity_id, mock_client = executor_with_real_agent
@@ -327,7 +327,7 @@ async def test_full_pipeline_workflow_events_are_json_serializable():
This is particularly important for workflows with AgentExecutor because:
- AgentExecutor produces ExecutorCompletedEvent with AgentExecutorResponse
- AgentExecutorResponse contains AgentRunResponse and ChatMessage objects
- AgentExecutorResponse contains AgentResponse and ChatMessage objects
- These are SerializationMixin objects, not Pydantic, which caused the original bug
This test ensures the ENTIRE streaming pipeline works end-to-end.
@@ -566,7 +566,7 @@ def test_extract_workflow_hil_responses_handles_stringified_json():
async def test_executor_handles_non_streaming_agent():
"""Test executor can handle agents with only run() method (no run_stream)."""
from agent_framework import AgentRunResponse, AgentThread, ChatMessage, Role, TextContent
from agent_framework import AgentResponse, AgentThread, ChatMessage, Role, TextContent
class NonStreamingAgent:
"""Agent with only run() method - does NOT satisfy full AgentProtocol."""
@@ -576,7 +576,7 @@ async def test_executor_handles_non_streaming_agent():
description = "Test agent without run_stream()"
async def run(self, messages=None, *, thread=None, **kwargs):
return AgentRunResponse(
return AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text=f"Processed: {messages}")])],
response_id="test_123",
)
+18 -18
View File
@@ -18,8 +18,8 @@ from collections.abc import AsyncIterable, MutableSequence
from typing import Any, Generic
from agent_framework import (
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
BaseAgent,
BaseChatClient,
@@ -172,9 +172,9 @@ class MockAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
self.call_count += 1
return AgentRunResponse(
return AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text=self.response_text)])]
)
@@ -184,10 +184,10 @@ class MockAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
self.call_count += 1
for chunk in self.streaming_chunks:
yield AgentRunResponseUpdate(contents=[TextContent(text=chunk)], role=Role.ASSISTANT)
yield AgentResponseUpdate(contents=[TextContent(text=chunk)], role=Role.ASSISTANT)
class MockToolCallingAgent(BaseAgent):
@@ -203,9 +203,9 @@ class MockToolCallingAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
self.call_count += 1
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="done")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="done")])
async def run_stream(
self,
@@ -213,15 +213,15 @@ class MockToolCallingAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
self.call_count += 1
# First: text
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=[TextContent(text="Let me search for that...")],
role=Role.ASSISTANT,
)
# Second: tool call
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=[
FunctionCallContent(
call_id="call_123",
@@ -232,7 +232,7 @@ class MockToolCallingAgent(BaseAgent):
role=Role.ASSISTANT,
)
# Third: tool result
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=[
FunctionResultContent(
call_id="call_123",
@@ -242,7 +242,7 @@ class MockToolCallingAgent(BaseAgent):
role=Role.TOOL,
)
# Fourth: final text
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=[TextContent(text="The weather is sunny, 72°F.")],
role=Role.ASSISTANT,
)
@@ -295,9 +295,9 @@ def create_mock_tool_agent(id: str = "tool_agent", name: str = "ToolAgent") -> M
return MockToolCallingAgent(id=id, name=name)
def create_agent_run_response(text: str = "Test response") -> AgentRunResponse:
"""Create an AgentRunResponse with the given text."""
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text=text)])])
def create_agent_run_response(text: str = "Test response") -> AgentResponse:
"""Create an AgentResponse with the given text."""
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text=text)])])
def create_agent_executor_response(
@@ -308,7 +308,7 @@ def create_agent_executor_response(
agent_response = create_agent_run_response(response_text)
return AgentExecutorResponse(
executor_id=executor_id,
agent_run_response=agent_response,
agent_response=agent_response,
full_conversation=[
ChatMessage(role=Role.USER, contents=[TextContent(text="User input")]),
ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text=response_text)]),
@@ -324,7 +324,7 @@ def create_executor_completed_event(
This creates the exact data structure that caused the serialization bug:
ExecutorCompletedEvent.data contains AgentExecutorResponse which contains
AgentRunResponse and ChatMessage objects (SerializationMixin, not Pydantic).
AgentResponse and ChatMessage objects (SerializationMixin, not Pydantic).
"""
data = create_agent_executor_response(executor_id) if with_agent_response else {"simple": "dict"}
return ExecutorCompletedEvent(executor_id=executor_id, data=data)
+16 -18
View File
@@ -13,7 +13,7 @@ import pytest
# Import Agent Framework types
from agent_framework._types import (
AgentRunResponseUpdate,
AgentResponseUpdate,
ErrorContent,
FunctionCallContent,
FunctionResultContent,
@@ -83,11 +83,9 @@ def create_test_content(content_type: str, **kwargs: Any) -> Any:
raise ValueError(f"Unknown content type: {content_type}")
def create_test_agent_update(contents: list[Any]) -> AgentRunResponseUpdate:
"""Create test AgentRunResponseUpdate."""
return AgentRunResponseUpdate(
contents=contents, role=Role.ASSISTANT, message_id="test_msg", response_id="test_resp"
)
def create_test_agent_update(contents: list[Any]) -> AgentResponseUpdate:
"""Create test AgentResponseUpdate."""
return AgentResponseUpdate(contents=contents, role=Role.ASSISTANT, message_id="test_msg", response_id="test_resp")
# =============================================================================
@@ -105,7 +103,7 @@ async def test_critical_isinstance_bug_detection(mapper: MessageMapper, test_req
assert not hasattr(update, "response") # Fake attribute should not exist
# Test isinstance works with real types
assert isinstance(update, AgentRunResponseUpdate)
assert isinstance(update, AgentResponseUpdate)
# Test mapper conversion - should NOT produce "Unknown event"
events = await mapper.convert_event(update, test_request)
@@ -264,7 +262,7 @@ async def test_agent_lifecycle_events(mapper: MessageMapper, test_request: Agent
async def test_agent_run_response_mapping(mapper: MessageMapper, test_request: AgentFrameworkRequest) -> None:
"""Test that mapper handles complete AgentRunResponse (non-streaming)."""
"""Test that mapper handles complete AgentResponse (non-streaming)."""
response = create_agent_run_response("Complete response from run()")
events = await mapper.convert_event(response, test_request)
@@ -325,14 +323,14 @@ async def test_executor_completed_event_with_agent_response(
This is a REGRESSION TEST for the serialization bug where
ExecutorCompletedEvent.data contained AgentExecutorResponse with nested
AgentRunResponse and ChatMessage objects (SerializationMixin) that
AgentResponse and ChatMessage objects (SerializationMixin) that
Pydantic couldn't serialize.
"""
# Create event with realistic nested data - the exact structure that caused the bug
event = create_executor_completed_event(executor_id="exec_agent", with_agent_response=True)
# Verify the data has the problematic structure
assert hasattr(event.data, "agent_run_response")
assert hasattr(event.data, "agent_response")
assert hasattr(event.data, "full_conversation")
# First invoke the executor
@@ -380,7 +378,7 @@ async def test_executor_completed_event_serialization_to_json(
done_event = events[0]
# This is the critical test - model_dump_json() should NOT raise
# "Unable to serialize unknown type: <class 'agent_framework._types.AgentRunResponse'>"
# "Unable to serialize unknown type: <class 'agent_framework._types.AgentResponse'>"
try:
json_str = done_event.model_dump_json()
assert json_str is not None
@@ -453,11 +451,11 @@ async def test_magentic_agent_run_update_event_with_agent_delta_metadata(
This tests the ACTUAL event format Magentic emits - not a fake MagenticAgentDeltaEvent class.
Magentic uses AgentRunUpdateEvent with additional_properties containing magentic_event_type.
"""
from agent_framework._types import AgentRunResponseUpdate, Role, TextContent
from agent_framework._types import AgentResponseUpdate, Role, TextContent
from agent_framework._workflows._events import AgentRunUpdateEvent
# Create the REAL event format that Magentic emits
update = AgentRunResponseUpdate(
update = AgentResponseUpdate(
contents=[TextContent(text="Hello from agent")],
role=Role.ASSISTANT,
author_name="Writer",
@@ -484,11 +482,11 @@ async def test_magentic_orchestrator_message_event(mapper: MessageMapper, test_r
Magentic emits orchestrator planning/instruction messages using AgentRunUpdateEvent
with additional_properties containing magentic_event_type='orchestrator_message'.
"""
from agent_framework._types import AgentRunResponseUpdate, Role, TextContent
from agent_framework._types import AgentResponseUpdate, Role, TextContent
from agent_framework._workflows._events import AgentRunUpdateEvent
# Create orchestrator message event (REAL format from Magentic)
update = AgentRunResponseUpdate(
update = AgentResponseUpdate(
contents=[TextContent(text="Planning: First, the writer will create content...")],
role=Role.ASSISTANT,
author_name="Orchestrator",
@@ -520,19 +518,19 @@ async def test_magentic_events_use_same_event_class_as_other_workflows(
additional_properties. Any mapper code checking for 'MagenticAgentDeltaEvent'
class names is dead code.
"""
from agent_framework._types import AgentRunResponseUpdate, Role, TextContent
from agent_framework._types import AgentResponseUpdate, Role, TextContent
from agent_framework._workflows._events import AgentRunUpdateEvent
# Create events the way different workflows do it
# 1. Regular workflow (no additional_properties)
regular_update = AgentRunResponseUpdate(
regular_update = AgentResponseUpdate(
contents=[TextContent(text="Regular workflow response")],
role=Role.ASSISTANT,
)
regular_event = AgentRunUpdateEvent(executor_id="regular_executor", data=regular_update)
# 2. Magentic workflow (with additional_properties)
magentic_update = AgentRunResponseUpdate(
magentic_update = AgentResponseUpdate(
contents=[TextContent(text="Magentic workflow response")],
role=Role.ASSISTANT,
additional_properties={"magentic_event_type": "agent_delta"},