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
+25 -25
View File
@@ -33,8 +33,8 @@ from ._serialization import SerializationMixin
from ._threads import AgentThread, ChatMessageStoreProtocol
from ._tools import FUNCTION_INVOKING_CHAT_CLIENT_MARKER, AIFunction, ToolProtocol
from ._types import (
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
ChatMessage,
ChatResponse,
ChatResponseUpdate,
@@ -177,16 +177,16 @@ class AgentProtocol(Protocol):
async def run(self, messages=None, *, thread=None, **kwargs):
# Your custom implementation
from agent_framework import AgentRunResponse
from agent_framework import AgentResponse
return AgentRunResponse(messages=[], response_id="custom-response")
return AgentResponse(messages=[], response_id="custom-response")
def run_stream(self, messages=None, *, thread=None, **kwargs):
# Your custom streaming implementation
async def _stream():
from agent_framework import AgentRunResponseUpdate
from agent_framework import AgentResponseUpdate
yield AgentRunResponseUpdate()
yield AgentResponseUpdate()
return _stream()
@@ -210,15 +210,15 @@ class AgentProtocol(Protocol):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
"""Get a response from the agent.
This method returns the final result of the agent's execution
as a single AgentRunResponse object. The caller is blocked until
as a single AgentResponse object. The caller is blocked until
the final result is available.
Note: For streaming responses, use the run_stream method, which returns
intermediate steps and the final result as a stream of AgentRunResponseUpdate
intermediate steps and the final result as a stream of AgentResponseUpdate
objects. Streaming only the final result is not feasible because the timing of
the final result's availability is unknown, and blocking the caller until then
is undesirable in streaming scenarios.
@@ -241,13 +241,13 @@ class AgentProtocol(Protocol):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
"""Run the agent as a stream.
This method will return the intermediate steps and final results of the
agent's execution as a stream of AgentRunResponseUpdate objects to the caller.
agent's execution as a stream of AgentResponseUpdate objects to the caller.
Note: An AgentRunResponseUpdate object contains a chunk of a message.
Note: An AgentResponseUpdate object contains a chunk of a message.
Args:
messages: The message(s) to send to the agent.
@@ -283,19 +283,19 @@ class BaseAgent(SerializationMixin):
Examples:
.. code-block:: python
from agent_framework import BaseAgent, AgentThread, AgentRunResponse
from agent_framework import BaseAgent, AgentThread, AgentResponse
# Create a concrete subclass that implements the protocol
class SimpleAgent(BaseAgent):
async def run(self, messages=None, *, thread=None, **kwargs):
# Custom implementation
return AgentRunResponse(messages=[], response_id="simple-response")
return AgentResponse(messages=[], response_id="simple-response")
def run_stream(self, messages=None, *, thread=None, **kwargs):
async def _stream():
# Custom streaming implementation
yield AgentRunResponseUpdate()
yield AgentResponseUpdate()
return _stream()
@@ -412,8 +412,8 @@ class BaseAgent(SerializationMixin):
description: str | None = None,
arg_name: str = "task",
arg_description: str | None = None,
stream_callback: Callable[[AgentRunResponseUpdate], None]
| Callable[[AgentRunResponseUpdate], Awaitable[None]]
stream_callback: Callable[[AgentResponseUpdate], None]
| Callable[[AgentResponseUpdate], Awaitable[None]]
| None = None,
) -> AIFunction[BaseModel, str]:
"""Create an AIFunction tool that wraps this agent.
@@ -478,7 +478,7 @@ class BaseAgent(SerializationMixin):
return (await self.run(input_text, **forwarded_kwargs)).text
# Use streaming mode - accumulate updates and create final response
response_updates: list[AgentRunResponseUpdate] = []
response_updates: list[AgentResponseUpdate] = []
async for update in self.run_stream(input_text, **forwarded_kwargs):
response_updates.append(update)
if is_async_callback:
@@ -487,7 +487,7 @@ class BaseAgent(SerializationMixin):
stream_callback(update)
# Create final text from accumulated updates
return AgentRunResponse.from_agent_run_response_updates(response_updates).text
return AgentResponse.from_agent_run_response_updates(response_updates).text
agent_tool: AIFunction[BaseModel, str] = AIFunction(
name=tool_name,
@@ -766,7 +766,7 @@ class ChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
| None = None,
options: TOptions_co | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
"""Run the agent with the given messages and options.
Note:
@@ -789,7 +789,7 @@ class ChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
Will only be passed to functions that are called.
Returns:
An AgentRunResponse containing the agent's response.
An AgentResponse containing the agent's response.
"""
# Build options dict from provided options
opts = dict(options) if options else {}
@@ -872,7 +872,7 @@ class ChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
response.messages,
**{k: v for k, v in kwargs.items() if k != "thread"},
)
return AgentRunResponse(
return AgentResponse(
messages=response.messages,
response_id=response.response_id,
created_at=response.created_at,
@@ -894,7 +894,7 @@ class ChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
| None = None,
options: TOptions_co | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
"""Stream the agent with the given messages and options.
Note:
@@ -917,7 +917,7 @@ class ChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
Will only be passed to functions that are called.
Yields:
AgentRunResponseUpdate objects containing chunks of the agent's response.
AgentResponseUpdate objects containing chunks of the agent's response.
"""
# Build options dict from provided options
opts = dict(options) if options else {}
@@ -989,7 +989,7 @@ class ChatAgent(BaseAgent, Generic[TOptions_co]): # type: ignore[misc]
if update.author_name is None:
update.author_name = agent_name
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=update.contents,
role=update.role,
author_name=update.author_name,
@@ -8,7 +8,7 @@ from functools import update_wrapper
from typing import TYPE_CHECKING, Any, ClassVar, Generic, TypeAlias, TypedDict, TypeVar
from ._serialization import SerializationMixin
from ._types import AgentRunResponse, AgentRunResponseUpdate, ChatMessage, prepare_messages
from ._types import AgentResponse, AgentResponseUpdate, ChatMessage, prepare_messages
from .exceptions import MiddlewareException
if TYPE_CHECKING:
@@ -67,8 +67,8 @@ class AgentRunContext(SerializationMixin):
metadata: Metadata dictionary for sharing data between agent middleware.
result: Agent execution result. Can be observed after calling ``next()``
to see the actual execution result or can be set to override the execution result.
For non-streaming: should be AgentRunResponse.
For streaming: should be AsyncIterable[AgentRunResponseUpdate].
For non-streaming: should be AgentResponse.
For streaming: should be AsyncIterable[AgentResponseUpdate].
terminate: A flag indicating whether to terminate execution after current middleware.
When set to True, execution will stop as soon as control returns to framework.
kwargs: Additional keyword arguments passed to the agent run method.
@@ -105,7 +105,7 @@ class AgentRunContext(SerializationMixin):
thread: "AgentThread | None" = None,
is_streaming: bool = False,
metadata: dict[str, Any] | None = None,
result: AgentRunResponse | AsyncIterable[AgentRunResponseUpdate] | None = None,
result: AgentResponse | AsyncIterable[AgentResponseUpdate] | None = None,
terminate: bool = False,
kwargs: dict[str, Any] | None = None,
) -> None:
@@ -321,8 +321,8 @@ class AgentMiddleware(ABC):
Use context.is_streaming to determine if this is a streaming call.
Middleware can set context.result to override execution, or observe
the actual execution result after calling next().
For non-streaming: AgentRunResponse
For streaming: AsyncIterable[AgentRunResponseUpdate]
For non-streaming: AgentResponse
For streaming: AsyncIterable[AgentResponseUpdate]
next: Function to call the next middleware or final agent execution.
Does not return anything - all data flows through the context.
@@ -773,8 +773,8 @@ class AgentMiddlewarePipeline(BaseMiddlewarePipeline):
agent: "AgentProtocol",
messages: list[ChatMessage],
context: AgentRunContext,
final_handler: Callable[[AgentRunContext], Awaitable[AgentRunResponse]],
) -> AgentRunResponse | None:
final_handler: Callable[[AgentRunContext], Awaitable[AgentResponse]],
) -> AgentResponse | None:
"""Execute the agent middleware pipeline for non-streaming.
Args:
@@ -795,15 +795,15 @@ class AgentMiddlewarePipeline(BaseMiddlewarePipeline):
return await final_handler(context)
# Store the final result
result_container: dict[str, AgentRunResponse | None] = {"result": None}
result_container: dict[str, AgentResponse | None] = {"result": None}
# Custom final handler that handles termination and result override
async def agent_final_handler(c: AgentRunContext) -> AgentRunResponse:
async def agent_final_handler(c: AgentRunContext) -> AgentResponse:
# If terminate was set, return the result (which might be None)
if c.terminate:
if c.result is not None and isinstance(c.result, AgentRunResponse):
if c.result is not None and isinstance(c.result, AgentResponse):
return c.result
return AgentRunResponse()
return AgentResponse()
# Execute actual handler and populate context for observability
return await final_handler(c)
@@ -811,13 +811,13 @@ class AgentMiddlewarePipeline(BaseMiddlewarePipeline):
await first_handler(context)
# Return the result from result container or overridden result
if context.result is not None and isinstance(context.result, AgentRunResponse):
if context.result is not None and isinstance(context.result, AgentResponse):
return context.result
# If no result was set (next() not called), return empty AgentRunResponse
# If no result was set (next() not called), return empty AgentResponse
response = result_container.get("result")
if response is None:
return AgentRunResponse()
return AgentResponse()
return response
async def execute_stream(
@@ -825,8 +825,8 @@ class AgentMiddlewarePipeline(BaseMiddlewarePipeline):
agent: "AgentProtocol",
messages: list[ChatMessage],
context: AgentRunContext,
final_handler: Callable[[AgentRunContext], AsyncIterable[AgentRunResponseUpdate]],
) -> AsyncIterable[AgentRunResponseUpdate]:
final_handler: Callable[[AgentRunContext], AsyncIterable[AgentResponseUpdate]],
) -> AsyncIterable[AgentResponseUpdate]:
"""Execute the agent middleware pipeline for streaming.
Args:
@@ -849,7 +849,7 @@ class AgentMiddlewarePipeline(BaseMiddlewarePipeline):
return
# Store the final result
result_container: dict[str, AsyncIterable[AgentRunResponseUpdate] | None] = {"result_stream": None}
result_container: dict[str, AsyncIterable[AgentResponseUpdate] | None] = {"result_stream": None}
first_handler = self._create_streaming_handler_chain(final_handler, result_container, "result_stream")
await first_handler(context)
@@ -1210,7 +1210,7 @@ def use_agent_middleware(agent_class: type[TAgent]) -> type[TAgent]:
thread: Any = None,
middleware: Sequence[Middleware] | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
"""Middleware-enabled run method."""
# Build fresh middleware pipelines from current middleware collection and run-level middleware
agent_middleware = getattr(self, "middleware", None)
@@ -1237,7 +1237,7 @@ def use_agent_middleware(agent_class: type[TAgent]) -> type[TAgent]:
kwargs=kwargs,
)
async def _execute_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def _execute_handler(ctx: AgentRunContext) -> AgentResponse:
return await original_run(self, ctx.messages, thread=thread, **ctx.kwargs) # type: ignore
result = await agent_pipeline.execute(
@@ -1247,7 +1247,7 @@ def use_agent_middleware(agent_class: type[TAgent]) -> type[TAgent]:
_execute_handler,
)
return result if result else AgentRunResponse()
return result if result else AgentResponse()
# No middleware, execute directly
return await original_run(self, normalized_messages, thread=thread, **kwargs) # type: ignore[return-value]
@@ -1259,7 +1259,7 @@ def use_agent_middleware(agent_class: type[TAgent]) -> type[TAgent]:
thread: Any = None,
middleware: Sequence[Middleware] | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
"""Middleware-enabled run_stream method."""
# Build fresh middleware pipelines from current middleware collection and run-level middleware
agent_middleware = getattr(self, "middleware", None)
@@ -1285,11 +1285,11 @@ def use_agent_middleware(agent_class: type[TAgent]) -> type[TAgent]:
kwargs=kwargs,
)
async def _execute_stream_handler(ctx: AgentRunContext) -> AsyncIterable[AgentRunResponseUpdate]:
async def _execute_stream_handler(ctx: AgentRunContext) -> AsyncIterable[AgentResponseUpdate]:
async for update in original_run_stream(self, ctx.messages, thread=thread, **ctx.kwargs): # type: ignore[misc]
yield update
async def _stream_generator() -> AsyncIterable[AgentRunResponseUpdate]:
async def _stream_generator() -> AsyncIterable[AgentResponseUpdate]:
async for update in agent_pipeline.execute_stream(
self, # type: ignore[arg-type]
normalized_messages,
+31 -31
View File
@@ -29,8 +29,8 @@ else:
__all__ = [
"AgentRunResponse",
"AgentRunResponseUpdate",
"AgentResponse",
"AgentResponseUpdate",
"AnnotatedRegions",
"Annotations",
"BaseAnnotation",
@@ -188,7 +188,7 @@ _T = TypeVar("_T")
TEmbedding = TypeVar("TEmbedding")
TChatResponse = TypeVar("TChatResponse", bound="ChatResponse")
TToolMode = TypeVar("TToolMode", bound="ToolMode")
TAgentRunResponse = TypeVar("TAgentRunResponse", bound="AgentRunResponse")
TAgentRunResponse = TypeVar("TAgentRunResponse", bound="AgentResponse")
CreatedAtT = str # Use a datetimeoffset type? Or a more specific type like datetime.datetime?
@@ -2541,7 +2541,7 @@ def prepend_instructions_to_messages(
def _process_update(
response: "ChatResponse | AgentRunResponse", update: "ChatResponseUpdate | AgentRunResponseUpdate"
response: "ChatResponse | AgentResponse", update: "ChatResponseUpdate | AgentResponseUpdate"
) -> None:
"""Processes a single update and modifies the response in place."""
is_new_message = False
@@ -2645,7 +2645,7 @@ def _coalesce_text_content(
contents.extend(coalesced_contents)
def _finalize_response(response: "ChatResponse | AgentRunResponse") -> None:
def _finalize_response(response: "ChatResponse | AgentResponse") -> None:
"""Finalizes the response by performing any necessary post-processing."""
for msg in response.messages:
_coalesce_text_content(msg.contents, TextContent)
@@ -3067,10 +3067,10 @@ class ChatResponseUpdate(SerializationMixin):
return self.text
# region AgentRunResponse
# region AgentResponse
class AgentRunResponse(SerializationMixin):
class AgentResponse(SerializationMixin):
"""Represents the response to an Agent run request.
Provides one or more response messages and metadata about the response.
@@ -3080,11 +3080,11 @@ class AgentRunResponse(SerializationMixin):
Examples:
.. code-block:: python
from agent_framework import AgentRunResponse, ChatMessage
from agent_framework import AgentResponse, ChatMessage
# Create agent response
msg = ChatMessage(role="assistant", text="Task completed successfully.")
response = AgentRunResponse(messages=[msg], response_id="run_123")
response = AgentResponse(messages=[msg], response_id="run_123")
print(response.text) # "Task completed successfully."
# Access user input requests
@@ -3092,20 +3092,20 @@ class AgentRunResponse(SerializationMixin):
print(len(user_requests)) # 0
# Combine streaming updates
updates = [...] # List of AgentRunResponseUpdate objects
response = AgentRunResponse.from_agent_run_response_updates(updates)
updates = [...] # List of AgentResponseUpdate objects
response = AgentResponse.from_agent_run_response_updates(updates)
# Serialization - to_dict and from_dict
response_dict = response.to_dict()
# {'type': 'agent_run_response', 'messages': [...], 'response_id': 'run_123',
# {'type': 'agent_response', 'messages': [...], 'response_id': 'run_123',
# 'additional_properties': {}}
restored_response = AgentRunResponse.from_dict(response_dict)
restored_response = AgentResponse.from_dict(response_dict)
print(restored_response.response_id) # "run_123"
# Serialization - to_json and from_json
response_json = response.to_json()
# '{"type": "agent_run_response", "messages": [...], "response_id": "run_123", ...}'
restored_from_json = AgentRunResponse.from_json(response_json)
# '{"type": "agent_response", "messages": [...], "response_id": "run_123", ...}'
restored_from_json = AgentResponse.from_json(response_json)
print(restored_from_json.text) # "Task completed successfully."
"""
@@ -3127,7 +3127,7 @@ class AgentRunResponse(SerializationMixin):
additional_properties: dict[str, Any] | None = None,
**kwargs: Any,
) -> None:
"""Initialize an AgentRunResponse.
"""Initialize an AgentResponse.
Keyword Args:
messages: The list of chat messages in the response.
@@ -3185,14 +3185,14 @@ class AgentRunResponse(SerializationMixin):
@classmethod
def from_agent_run_response_updates(
cls: type[TAgentRunResponse],
updates: Sequence["AgentRunResponseUpdate"],
updates: Sequence["AgentResponseUpdate"],
*,
output_format_type: type[BaseModel] | None = None,
) -> TAgentRunResponse:
"""Joins multiple updates into a single AgentRunResponse.
"""Joins multiple updates into a single AgentResponse.
Args:
updates: A sequence of AgentRunResponseUpdate objects to combine.
updates: A sequence of AgentResponseUpdate objects to combine.
Keyword Args:
output_format_type: Optional Pydantic model type to parse the response text into structured data.
@@ -3208,14 +3208,14 @@ class AgentRunResponse(SerializationMixin):
@classmethod
async def from_agent_response_generator(
cls: type[TAgentRunResponse],
updates: AsyncIterable["AgentRunResponseUpdate"],
updates: AsyncIterable["AgentResponseUpdate"],
*,
output_format_type: type[BaseModel] | None = None,
) -> TAgentRunResponse:
"""Joins multiple updates into a single AgentRunResponse.
"""Joins multiple updates into a single AgentResponse.
Args:
updates: An async iterable of AgentRunResponseUpdate objects to combine.
updates: An async iterable of AgentResponseUpdate objects to combine.
Keyword Args:
output_format_type: Optional Pydantic model type to parse the response text into structured data
@@ -3240,19 +3240,19 @@ class AgentRunResponse(SerializationMixin):
logger.debug("Failed to parse value from agent run response text: %s", ex)
# region AgentRunResponseUpdate
# region AgentResponseUpdate
class AgentRunResponseUpdate(SerializationMixin):
class AgentResponseUpdate(SerializationMixin):
"""Represents a single streaming response chunk from an Agent.
Examples:
.. code-block:: python
from agent_framework import AgentRunResponseUpdate, TextContent
from agent_framework import AgentResponseUpdate, TextContent
# Create an agent run update
update = AgentRunResponseUpdate(
update = AgentResponseUpdate(
contents=[TextContent(text="Processing...")],
role="assistant",
response_id="run_123",
@@ -3264,15 +3264,15 @@ class AgentRunResponseUpdate(SerializationMixin):
# Serialization - to_dict and from_dict
update_dict = update.to_dict()
# {'type': 'agent_run_response_update', 'contents': [{'type': 'text', 'text': 'Processing...'}],
# {'type': 'agent_response_update', 'contents': [{'type': 'text', 'text': 'Processing...'}],
# 'role': {'type': 'role', 'value': 'assistant'}, 'response_id': 'run_123'}
restored_update = AgentRunResponseUpdate.from_dict(update_dict)
restored_update = AgentResponseUpdate.from_dict(update_dict)
print(restored_update.response_id) # "run_123"
# Serialization - to_json and from_json
update_json = update.to_json()
# '{"type": "agent_run_response_update", "contents": [{"type": "text", "text": "Processing..."}], ...}'
restored_from_json = AgentRunResponseUpdate.from_json(update_json)
# '{"type": "agent_response_update", "contents": [{"type": "text", "text": "Processing..."}], ...}'
restored_from_json = AgentResponseUpdate.from_json(update_json)
print(restored_from_json.text) # "Processing..."
"""
@@ -3292,7 +3292,7 @@ class AgentRunResponseUpdate(SerializationMixin):
raw_representation: Any | None = None,
**kwargs: Any,
) -> None:
"""Initialize an AgentRunResponseUpdate.
"""Initialize an AgentResponseUpdate.
Keyword Args:
contents: Optional list of BaseContent items or dicts to include in the update.
@@ -9,8 +9,8 @@ from datetime import datetime, timezone
from typing import TYPE_CHECKING, Any, ClassVar, TypedDict, cast
from agent_framework import (
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
BaseAgent,
BaseContent,
@@ -126,7 +126,7 @@ class WorkflowAgent(BaseAgent):
checkpoint_id: str | None = None,
checkpoint_storage: CheckpointStorage | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
"""Get a response from the workflow agent (non-streaming).
This method collects all streaming updates and merges them into a single response.
@@ -146,10 +146,10 @@ class WorkflowAgent(BaseAgent):
and ai_function tools.
Returns:
The final workflow response as an AgentRunResponse.
The final workflow response as an AgentResponse.
"""
# Collect all streaming updates
response_updates: list[AgentRunResponseUpdate] = []
response_updates: list[AgentResponseUpdate] = []
input_messages = normalize_messages_input(messages)
thread = thread or self.get_new_thread()
response_id = str(uuid.uuid4())
@@ -175,7 +175,7 @@ class WorkflowAgent(BaseAgent):
checkpoint_id: str | None = None,
checkpoint_storage: CheckpointStorage | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
"""Stream response updates from the workflow agent.
Args:
@@ -193,11 +193,11 @@ class WorkflowAgent(BaseAgent):
and ai_function tools.
Yields:
AgentRunResponseUpdate objects representing the workflow execution progress.
AgentResponseUpdate objects representing the workflow execution progress.
"""
input_messages = normalize_messages_input(messages)
thread = thread or self.get_new_thread()
response_updates: list[AgentRunResponseUpdate] = []
response_updates: list[AgentResponseUpdate] = []
response_id = str(uuid.uuid4())
async for update in self._run_stream_impl(
@@ -220,7 +220,7 @@ class WorkflowAgent(BaseAgent):
checkpoint_id: str | None = None,
checkpoint_storage: CheckpointStorage | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
"""Internal implementation of streaming execution.
Args:
@@ -233,7 +233,7 @@ class WorkflowAgent(BaseAgent):
workflow and ai_function tools.
Yields:
AgentRunResponseUpdate objects representing the workflow execution progress.
AgentResponseUpdate objects representing the workflow execution progress.
"""
# Determine the event stream based on whether we have function responses
if bool(self.pending_requests):
@@ -289,8 +289,8 @@ class WorkflowAgent(BaseAgent):
self,
response_id: str,
event: WorkflowEvent,
) -> AgentRunResponseUpdate | None:
"""Convert a workflow event to an AgentRunResponseUpdate.
) -> AgentResponseUpdate | None:
"""Convert a workflow event to an AgentResponseUpdate.
AgentRunUpdateEvent, RequestInfoEvent, and WorkflowOutputEvent are processed.
Other workflow events are ignored as they are workflow-internal.
@@ -319,17 +319,17 @@ class WorkflowAgent(BaseAgent):
# Convert workflow output to an agent response update.
# Handle different data types appropriately.
# Skip AgentRunResponse from AgentExecutor with output_response=True
# Skip AgentResponse from AgentExecutor with output_response=True
# since streaming events already surfaced the content.
if isinstance(data, AgentRunResponse):
if isinstance(data, AgentResponse):
executor = self.workflow.executors.get(source_executor_id)
if isinstance(executor, AgentExecutor) and executor.output_response:
return None
if isinstance(data, AgentRunResponseUpdate):
if isinstance(data, AgentResponseUpdate):
return data
if isinstance(data, ChatMessage):
return AgentRunResponseUpdate(
return AgentResponseUpdate(
contents=list(data.contents),
role=data.role,
author_name=data.author_name or source_executor_id,
@@ -341,7 +341,7 @@ class WorkflowAgent(BaseAgent):
contents = self._extract_contents(data)
if not contents:
return None
return AgentRunResponseUpdate(
return AgentResponseUpdate(
contents=contents,
role=Role.ASSISTANT,
author_name=source_executor_id,
@@ -367,7 +367,7 @@ class WorkflowAgent(BaseAgent):
function_call=function_call,
additional_properties={"request_id": request_id},
)
return AgentRunResponseUpdate(
return AgentResponseUpdate(
contents=[function_call, approval_request],
role=Role.ASSISTANT,
author_name=self.name,
@@ -441,30 +441,30 @@ class WorkflowAgent(BaseAgent):
class _ResponseState(TypedDict):
"""State for grouping response updates by message_id."""
by_msg: dict[str, list[AgentRunResponseUpdate]]
dangling: list[AgentRunResponseUpdate]
by_msg: dict[str, list[AgentResponseUpdate]]
dangling: list[AgentResponseUpdate]
@staticmethod
def merge_updates(updates: list[AgentRunResponseUpdate], response_id: str) -> AgentRunResponse:
"""Merge streaming updates into a single AgentRunResponse.
def merge_updates(updates: list[AgentResponseUpdate], response_id: str) -> AgentResponse:
"""Merge streaming updates into a single AgentResponse.
Behavior:
- Group updates by response_id; within each response_id, group by message_id and keep a dangling bucket for
updates without message_id.
- Convert each group (per message and dangling) into an intermediate AgentRunResponse via
AgentRunResponse.from_agent_run_response_updates, then sort by created_at and merge.
- Convert each group (per message and dangling) into an intermediate AgentResponse via
AgentResponse.from_agent_run_response_updates, then sort by created_at and merge.
- Append messages from updates without any response_id at the end (global dangling), while aggregating metadata.
Args:
updates: The list of AgentRunResponseUpdate objects to merge.
response_id: The response identifier to set on the returned AgentRunResponse.
updates: The list of AgentResponseUpdate objects to merge.
response_id: The response identifier to set on the returned AgentResponse.
Returns:
An AgentRunResponse with messages in processing order and aggregated metadata.
An AgentResponse with messages in processing order and aggregated metadata.
"""
# PHASE 1: GROUP UPDATES BY RESPONSE_ID AND MESSAGE_ID
states: dict[str, WorkflowAgent._ResponseState] = {}
global_dangling: list[AgentRunResponseUpdate] = []
global_dangling: list[AgentResponseUpdate] = []
for u in updates:
if u.response_id:
@@ -497,7 +497,7 @@ class WorkflowAgent(BaseAgent):
return a
return a + b
def _merge_responses(current: AgentRunResponse | None, incoming: AgentRunResponse) -> AgentRunResponse:
def _merge_responses(current: AgentResponse | None, incoming: AgentResponse) -> AgentResponse:
if current is None:
return incoming
raw_list: list[object] = []
@@ -512,7 +512,7 @@ class WorkflowAgent(BaseAgent):
_add_raw(current.raw_representation)
if incoming.raw_representation is not None:
_add_raw(incoming.raw_representation)
return AgentRunResponse(
return AgentResponse(
messages=(current.messages or []) + (incoming.messages or []),
response_id=current.response_id or incoming.response_id,
created_at=incoming.created_at or current.created_at,
@@ -533,16 +533,16 @@ class WorkflowAgent(BaseAgent):
by_msg = state["by_msg"]
dangling = state["dangling"]
per_message_responses: list[AgentRunResponse] = []
per_message_responses: list[AgentResponse] = []
for _, msg_updates in by_msg.items():
if msg_updates:
per_message_responses.append(AgentRunResponse.from_agent_run_response_updates(msg_updates))
per_message_responses.append(AgentResponse.from_agent_run_response_updates(msg_updates))
if dangling:
per_message_responses.append(AgentRunResponse.from_agent_run_response_updates(dangling))
per_message_responses.append(AgentResponse.from_agent_run_response_updates(dangling))
per_message_responses.sort(key=lambda r: _parse_dt(r.created_at))
aggregated: AgentRunResponse | None = None
aggregated: AgentResponse | None = None
for resp in per_message_responses:
if resp.response_id and grouped_response_id and resp.response_id != grouped_response_id:
resp.response_id = grouped_response_id
@@ -570,7 +570,7 @@ class WorkflowAgent(BaseAgent):
# PHASE 3: HANDLE GLOBAL DANGLING UPDATES (NO RESPONSE_ID)
if global_dangling:
flattened = AgentRunResponse.from_agent_run_response_updates(global_dangling)
flattened = AgentResponse.from_agent_run_response_updates(global_dangling)
final_messages.extend(flattened.messages)
if flattened.usage_details:
merged_usage = _sum_usage(merged_usage, flattened.usage_details)
@@ -591,7 +591,7 @@ class WorkflowAgent(BaseAgent):
raw_representations.append(cast_flat)
# PHASE 4: CONSTRUCT FINAL RESPONSE WITH INPUT RESPONSE_ID
return AgentRunResponse(
return AgentResponse(
messages=final_messages,
response_id=response_id,
created_at=latest_created_at,
@@ -9,7 +9,7 @@ from agent_framework import FunctionApprovalRequestContent, FunctionApprovalResp
from .._agents import AgentProtocol, ChatAgent
from .._threads import AgentThread
from .._types import AgentRunResponse, AgentRunResponseUpdate, ChatMessage
from .._types import AgentResponse, AgentResponseUpdate, ChatMessage
from ._agent_utils import resolve_agent_id
from ._checkpoint_encoding import decode_checkpoint_value, encode_checkpoint_value
from ._const import WORKFLOW_RUN_KWARGS_KEY
@@ -51,14 +51,14 @@ class AgentExecutorResponse:
Attributes:
executor_id: The ID of the executor that generated the response.
agent_run_response: The underlying agent run response (unaltered from client).
agent_response: The underlying agent run response (unaltered from client).
full_conversation: The full conversation context (prior inputs + all assistant/tool outputs) that
should be used when chaining to another AgentExecutor. This prevents downstream agents losing
user prompts while keeping the emitted AgentRunEvent text faithful to the raw agent output.
"""
executor_id: str
agent_run_response: AgentRunResponse
agent_response: AgentResponse
full_conversation: list[ChatMessage] | None = None
@@ -85,7 +85,7 @@ class AgentExecutor(Executor):
Args:
agent: The agent to be wrapped by this executor.
agent_thread: The thread to use for running the agent. If None, a new thread will be created.
output_response: Whether to yield an AgentRunResponse as a workflow output when the agent completes.
output_response: Whether to yield an AgentResponse as a workflow output when the agent completes.
id: A unique identifier for the executor. If None, the agent's name will be used if available.
"""
# Prefer provided id; else use agent.name if present; else generate deterministic prefix
@@ -106,14 +106,14 @@ class AgentExecutor(Executor):
@property
def output_response(self) -> bool:
"""Whether this executor yields AgentRunResponse as workflow output when complete."""
"""Whether this executor yields AgentResponse as workflow output when complete."""
return self._output_response
@property
def workflow_output_types(self) -> list[type[Any]]:
# Override to declare AgentRunResponse as a possible output type only if enabled.
# Override to declare AgentResponse as a possible output type only if enabled.
if self._output_response:
return [AgentRunResponse]
return [AgentResponse]
return []
@property
@@ -123,7 +123,7 @@ class AgentExecutor(Executor):
@handler
async def run(
self, request: AgentExecutorRequest, ctx: WorkflowContext[AgentExecutorResponse, AgentRunResponse]
self, request: AgentExecutorRequest, ctx: WorkflowContext[AgentExecutorResponse, AgentResponse]
) -> None:
"""Handle an AgentExecutorRequest (canonical input).
@@ -136,22 +136,22 @@ class AgentExecutor(Executor):
@handler
async def from_response(
self, prior: AgentExecutorResponse, ctx: WorkflowContext[AgentExecutorResponse, AgentRunResponse]
self, prior: AgentExecutorResponse, ctx: WorkflowContext[AgentExecutorResponse, AgentResponse]
) -> None:
"""Enable seamless chaining: accept a prior AgentExecutorResponse as input.
Strategy: treat the prior response's messages as the conversation state and
immediately run the agent to produce a new response.
"""
# Replace cache with full conversation if available, else fall back to agent_run_response messages.
# Replace cache with full conversation if available, else fall back to agent_response messages.
if prior.full_conversation is not None:
self._cache = list(prior.full_conversation)
else:
self._cache = list(prior.agent_run_response.messages)
self._cache = list(prior.agent_response.messages)
await self._run_agent_and_emit(ctx)
@handler
async def from_str(self, text: str, ctx: WorkflowContext[AgentExecutorResponse, AgentRunResponse]) -> None:
async def from_str(self, text: str, ctx: WorkflowContext[AgentExecutorResponse, AgentResponse]) -> None:
"""Accept a raw user prompt string and run the agent (one-shot)."""
self._cache = normalize_messages_input(text)
await self._run_agent_and_emit(ctx)
@@ -160,7 +160,7 @@ class AgentExecutor(Executor):
async def from_message(
self,
message: ChatMessage,
ctx: WorkflowContext[AgentExecutorResponse, AgentRunResponse],
ctx: WorkflowContext[AgentExecutorResponse, AgentResponse],
) -> None:
"""Accept a single ChatMessage as input."""
self._cache = normalize_messages_input(message)
@@ -170,7 +170,7 @@ class AgentExecutor(Executor):
async def from_messages(
self,
messages: list[str | ChatMessage],
ctx: WorkflowContext[AgentExecutorResponse, AgentRunResponse],
ctx: WorkflowContext[AgentExecutorResponse, AgentResponse],
) -> None:
"""Accept a list of chat inputs (strings or ChatMessage) as conversation context."""
self._cache = normalize_messages_input(messages)
@@ -181,7 +181,7 @@ class AgentExecutor(Executor):
self,
original_request: FunctionApprovalRequestContent,
response: FunctionApprovalResponseContent,
ctx: WorkflowContext[AgentExecutorResponse, AgentRunResponse],
ctx: WorkflowContext[AgentExecutorResponse, AgentResponse],
) -> None:
"""Handle user input responses for function approvals during agent execution.
@@ -292,7 +292,7 @@ class AgentExecutor(Executor):
logger.debug("AgentExecutor %s: Resetting cache", self.id)
self._cache.clear()
async def _run_agent_and_emit(self, ctx: WorkflowContext[AgentExecutorResponse, AgentRunResponse]) -> None:
async def _run_agent_and_emit(self, ctx: WorkflowContext[AgentExecutorResponse, AgentResponse]) -> None:
"""Execute the underlying agent, emit events, and enqueue response.
Checks ctx.is_streaming() to determine whether to emit incremental AgentRunUpdateEvent
@@ -306,7 +306,7 @@ class AgentExecutor(Executor):
response = await self._run_agent(cast(WorkflowContext, ctx))
# Always extend full conversation with cached messages plus agent outputs
# (agent_run_response.messages) after each run. This is to avoid losing context
# (agent_response.messages) after each run. This is to avoid losing context
# when agent did not complete and the cache is cleared when responses come back.
# Do not mutate response.messages so AgentRunEvent remains faithful to the raw output.
self._full_conversation.extend(list(self._cache) + (list(response.messages) if response else []))
@@ -323,14 +323,14 @@ class AgentExecutor(Executor):
await ctx.send_message(agent_response)
self._cache.clear()
async def _run_agent(self, ctx: WorkflowContext) -> AgentRunResponse | None:
async def _run_agent(self, ctx: WorkflowContext) -> AgentResponse | None:
"""Execute the underlying agent in non-streaming mode.
Args:
ctx: The workflow context for emitting events.
Returns:
The complete AgentRunResponse, or None if waiting for user input.
The complete AgentResponse, or None if waiting for user input.
"""
run_kwargs: dict[str, Any] = await ctx.get_shared_state(WORKFLOW_RUN_KWARGS_KEY)
@@ -350,18 +350,18 @@ class AgentExecutor(Executor):
return response
async def _run_agent_streaming(self, ctx: WorkflowContext) -> AgentRunResponse | None:
async def _run_agent_streaming(self, ctx: WorkflowContext) -> AgentResponse | None:
"""Execute the underlying agent in streaming mode and collect the full response.
Args:
ctx: The workflow context for emitting events.
Returns:
The complete AgentRunResponse, or None if waiting for user input.
The complete AgentResponse, or None if waiting for user input.
"""
run_kwargs: dict[str, Any] = await ctx.get_shared_state(WORKFLOW_RUN_KWARGS_KEY)
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
user_input_requests: list[FunctionApprovalRequestContent] = []
async for update in self._agent.run_stream(
self._cache,
@@ -374,15 +374,15 @@ class AgentExecutor(Executor):
if update.user_input_requests:
user_input_requests.extend(update.user_input_requests)
# Build the final AgentRunResponse from the collected updates
# Build the final AgentResponse from the collected updates
if isinstance(self._agent, ChatAgent):
response_format = self._agent.default_options.get("response_format")
response = AgentRunResponse.from_agent_run_response_updates(
response = AgentResponse.from_agent_run_response_updates(
updates,
output_format_type=response_format,
)
else:
response = AgentRunResponse.from_agent_run_response_updates(updates)
response = AgentResponse.from_agent_run_response_updates(updates)
# Handle any user input requests after the streaming completes
if user_input_requests:
@@ -346,7 +346,7 @@ class BaseGroupChatOrchestrator(Executor, ABC):
List of ChatMessages extracted from the response
"""
if isinstance(response, AgentExecutorResponse):
return response.agent_run_response.messages
return response.agent_response.messages
if isinstance(response, GroupChatResponseMessage):
return [response.message]
raise TypeError(f"Unsupported response type: {type(response)}")
@@ -79,7 +79,7 @@ class _AggregateAgentConversations(Executor):
[ single_user_prompt?, agent1_final_assistant, agent2_final_assistant, ... ]
- Extracts a single user prompt (first user message seen across results).
- For each result, selects the final assistant message (prefers agent_run_response.messages).
- For each result, selects the final assistant message (prefers agent_response.messages).
- Avoids duplicating the same user message per agent.
"""
@@ -107,7 +107,7 @@ class _AggregateAgentConversations(Executor):
assistant_replies: list[ChatMessage] = []
for r in results:
resp_messages = list(getattr(r.agent_run_response, "messages", []) or [])
resp_messages = list(getattr(r.agent_response, "messages", []) or [])
conv = r.full_conversation if r.full_conversation is not None else resp_messages
logger.debug(
@@ -213,7 +213,7 @@ class ConcurrentBuilder:
# Custom aggregator via callback (sync or async). The callback receives
# list[AgentExecutorResponse] and its return value becomes the workflow's output.
def summarize(results: list[AgentExecutorResponse]) -> str:
return " | ".join(r.agent_run_response.messages[-1].text for r in results)
return " | ".join(r.agent_response.messages[-1].text for r in results)
workflow = ConcurrentBuilder().participants([agent1, agent2, agent3]).with_aggregator(summarize).build()
@@ -223,7 +223,7 @@ class ConcurrentBuilder:
class MyAggregator(Executor):
@handler
async def aggregate(self, results: list[AgentExecutorResponse], ctx: WorkflowContext[Never, str]) -> None:
await ctx.yield_output(" | ".join(r.agent_run_response.messages[-1].text for r in results))
await ctx.yield_output(" | ".join(r.agent_response.messages[-1].text for r in results))
workflow = (
@@ -416,7 +416,7 @@ class ConcurrentBuilder:
class CustomAggregator(Executor):
@handler
async def aggregate(self, results: list[AgentExecutorResponse], ctx: WorkflowContext) -> None:
await ctx.yield_output(" | ".join(r.agent_run_response.messages[-1].text for r in results))
await ctx.yield_output(" | ".join(r.agent_response.messages[-1].text for r in results))
wf = ConcurrentBuilder().participants([a1, a2, a3]).with_aggregator(CustomAggregator()).build()
@@ -424,7 +424,7 @@ class ConcurrentBuilder:
# Callback-based aggregator (string result)
async def summarize(results: list[AgentExecutorResponse]) -> str:
return " | ".join(r.agent_run_response.messages[-1].text for r in results)
return " | ".join(r.agent_response.messages[-1].text for r in results)
wf = ConcurrentBuilder().participants([a1, a2, a3]).with_aggregator(summarize).build()
@@ -432,7 +432,7 @@ class ConcurrentBuilder:
# Callback-based aggregator (yield result)
async def summarize(results: list[AgentExecutorResponse], ctx: WorkflowContext[Never, str]) -> None:
await ctx.yield_output(" | ".join(r.agent_run_response.messages[-1].text for r in results))
await ctx.yield_output(" | ".join(r.agent_response.messages[-1].text for r in results))
wf = ConcurrentBuilder().participants([a1, a2, a3]).with_aggregator(summarize).build()
@@ -8,7 +8,7 @@ from dataclasses import dataclass
from enum import Enum
from typing import Any, TypeAlias
from agent_framework import AgentRunResponse, AgentRunResponseUpdate
from agent_framework import AgentResponse, AgentResponseUpdate
from ._checkpoint_encoding import decode_checkpoint_value, encode_checkpoint_value
from ._typing_utils import deserialize_type, serialize_type
@@ -367,9 +367,9 @@ class ExecutorFailedEvent(ExecutorEvent):
class AgentRunUpdateEvent(ExecutorEvent):
"""Event triggered when an agent is streaming messages."""
data: AgentRunResponseUpdate
data: AgentResponseUpdate
def __init__(self, executor_id: str, data: AgentRunResponseUpdate):
def __init__(self, executor_id: str, data: AgentResponseUpdate):
"""Initialize the agent streaming event."""
super().__init__(executor_id, data)
@@ -381,9 +381,9 @@ class AgentRunUpdateEvent(ExecutorEvent):
class AgentRunEvent(ExecutorEvent):
"""Event triggered when an agent run is completed."""
data: AgentRunResponse
data: AgentResponse
def __init__(self, executor_id: str, data: AgentRunResponse):
def __init__(self, executor_id: str, data: AgentResponse):
"""Initialize the agent run event."""
super().__init__(executor_id, data)
@@ -42,7 +42,7 @@ from .._agents import AgentProtocol, ChatAgent
from .._middleware import FunctionInvocationContext, FunctionMiddleware
from .._threads import AgentThread
from .._tools import AIFunction, ai_function
from .._types import AgentRunResponse, ChatMessage, Role
from .._types import AgentResponse, ChatMessage, Role
from ._agent_executor import AgentExecutor, AgentExecutorRequest, AgentExecutorResponse
from ._agent_utils import resolve_agent_id
from ._base_group_chat_orchestrator import TerminationCondition
@@ -155,7 +155,7 @@ class HandoffAgentUserRequest:
agent_response: The response generated by the agent at the most recent turn
"""
agent_response: AgentRunResponse
agent_response: AgentResponse
@staticmethod
def create_response(response: str | list[str] | ChatMessage | list[ChatMessage]) -> list[ChatMessage]:
@@ -361,7 +361,7 @@ class HandoffAgentExecutor(AgentExecutor):
return _handoff_tool
@override
async def _run_agent_and_emit(self, ctx: WorkflowContext[AgentExecutorResponse, AgentRunResponse]) -> None:
async def _run_agent_and_emit(self, ctx: WorkflowContext[AgentExecutorResponse, AgentResponse]) -> None:
"""Override to support handoff."""
# When the full conversation is empty, it means this is the first run.
# Broadcast the initial cache to all other agents. Subsequent runs won't
@@ -436,7 +436,7 @@ class HandoffAgentExecutor(AgentExecutor):
self,
original_request: HandoffAgentUserRequest,
response: list[ChatMessage],
ctx: WorkflowContext[AgentExecutorResponse, AgentRunResponse],
ctx: WorkflowContext[AgentExecutorResponse, AgentResponse],
) -> None:
"""Handle user response for a request that is issued after agent runs.
@@ -477,7 +477,7 @@ class HandoffAgentExecutor(AgentExecutor):
# Since all agents are connected via fan-out, we can directly send the message
await ctx.send_message(agent_executor_request)
def _is_handoff_requested(self, response: AgentRunResponse) -> str | None:
def _is_handoff_requested(self, response: AgentResponse) -> str | None:
"""Determine if the agent response includes a handoff request.
If a handoff tool is invoked, the middleware will short-circuit execution
@@ -16,7 +16,7 @@ from typing_extensions import Never
from agent_framework import (
AgentProtocol,
AgentRunResponse,
AgentResponse,
ChatMessage,
Role,
)
@@ -594,7 +594,7 @@ class StandardMagenticManager(MagenticManagerBase):
The agent's run method is called which applies the agent's configured options
(temperature, seed, instructions, etc.).
"""
response: AgentRunResponse = await self._agent.run(messages)
response: AgentResponse = await self._agent.run(messages)
if not response.messages:
raise RuntimeError("Agent returned no messages in response.")
if len(response.messages) > 1:
@@ -223,7 +223,7 @@ class WorkflowBuilder:
Args:
candidate: The executor or agent to wrap.
agent_thread: The thread to use for running the agent. If None, a new thread will be created.
output_response: Whether to yield an AgentRunResponse as a workflow output when the agent completes.
output_response: Whether to yield an AgentResponse as a workflow output when the agent completes.
executor_id: A unique identifier for the executor. If None, the agent's name will be used if available.
"""
try: # Local import to avoid hard dependency at import time
@@ -352,7 +352,7 @@ class WorkflowBuilder:
the agent's internal name. But it must be unique within the workflow.
agent_thread: The thread to use for running the agent. If None, a new thread will be created when
the agent is instantiated.
output_response: Whether to yield an AgentRunResponse as a workflow output when the agent completes.
output_response: Whether to yield an AgentResponse as a workflow output when the agent completes.
Example:
.. code-block:: python
@@ -411,7 +411,7 @@ class WorkflowBuilder:
Args:
agent: The agent to add to the workflow.
agent_thread: The thread to use for running the agent. If None, a new thread will be created.
output_response: Whether to yield an AgentRunResponse as a workflow output when the agent completes.
output_response: Whether to yield an AgentResponse as a workflow output when the agent completes.
id: A unique identifier for the executor. If None, the agent's name will be used if available.
Returns:
@@ -35,8 +35,8 @@ if TYPE_CHECKING: # pragma: no cover
from ._threads import AgentThread
from ._tools import AIFunction
from ._types import (
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
ChatMessage,
ChatResponse,
ChatResponseUpdate,
@@ -1315,10 +1315,10 @@ def use_instrumentation(
def _trace_agent_run(
run_func: Callable[..., Awaitable["AgentRunResponse"]],
run_func: Callable[..., Awaitable["AgentResponse"]],
provider_name: str,
capture_usage: bool = True,
) -> Callable[..., Awaitable["AgentRunResponse"]]:
) -> Callable[..., Awaitable["AgentResponse"]]:
"""Decorator to trace chat completion activities.
Args:
@@ -1334,7 +1334,7 @@ def _trace_agent_run(
*,
thread: "AgentThread | None" = None,
**kwargs: Any,
) -> "AgentRunResponse":
) -> "AgentResponse":
global OBSERVABILITY_SETTINGS
if not OBSERVABILITY_SETTINGS.ENABLED:
@@ -1384,10 +1384,10 @@ def _trace_agent_run(
def _trace_agent_run_stream(
run_streaming_func: Callable[..., AsyncIterable["AgentRunResponseUpdate"]],
run_streaming_func: Callable[..., AsyncIterable["AgentResponseUpdate"]],
provider_name: str,
capture_usage: bool,
) -> Callable[..., AsyncIterable["AgentRunResponseUpdate"]]:
) -> Callable[..., AsyncIterable["AgentResponseUpdate"]]:
"""Decorator to trace streaming agent run activities.
Args:
@@ -1403,7 +1403,7 @@ def _trace_agent_run_stream(
*,
thread: "AgentThread | None" = None,
**kwargs: Any,
) -> AsyncIterable["AgentRunResponseUpdate"]:
) -> AsyncIterable["AgentResponseUpdate"]:
global OBSERVABILITY_SETTINGS
if not OBSERVABILITY_SETTINGS.ENABLED:
@@ -1412,9 +1412,9 @@ def _trace_agent_run_stream(
yield streaming_agent_response
return
from ._types import AgentRunResponse, merge_chat_options
from ._types import AgentResponse, merge_chat_options
all_updates: list["AgentRunResponseUpdate"] = []
all_updates: list["AgentResponseUpdate"] = []
default_options = getattr(self, "default_options", {})
options = merge_chat_options(default_options, kwargs.get("options", {}))
@@ -1444,7 +1444,7 @@ def _trace_agent_run_stream(
capture_exception(span=span, exception=exception, timestamp=time_ns())
raise
else:
response = AgentRunResponse.from_agent_run_response_updates(all_updates)
response = AgentResponse.from_agent_run_response_updates(all_updates)
attributes = _get_response_attributes(attributes, response, capture_usage=capture_usage)
_capture_response(span=span, attributes=attributes)
if OBSERVABILITY_SETTINGS.SENSITIVE_DATA_ENABLED and response.messages:
@@ -1784,7 +1784,7 @@ def _to_otel_part(content: "Contents") -> dict[str, Any] | None:
def _get_response_attributes(
attributes: dict[str, Any],
response: "ChatResponse | AgentRunResponse",
response: "ChatResponse | AgentResponse",
duration: float | None = None,
*,
capture_usage: bool = True,
@@ -9,8 +9,8 @@ from azure.identity import AzureCliCredential
from pydantic import Field
from agent_framework import (
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
ChatAgent,
ChatClientProtocol,
@@ -403,7 +403,7 @@ async def test_azure_assistants_agent_basic_run():
response = await agent.run("Hello! Please respond with 'Hello World' exactly.")
# Validate response
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.text is not None
assert len(response.text) > 0
assert "Hello World" in response.text
@@ -420,7 +420,7 @@ async def test_azure_assistants_agent_basic_run_streaming():
full_message: str = ""
async for chunk in agent.run_stream("Please respond with exactly: 'This is a streaming response test.'"):
assert chunk is not None
assert isinstance(chunk, AgentRunResponseUpdate)
assert isinstance(chunk, AgentResponseUpdate)
if chunk.text:
full_message += chunk.text
@@ -444,14 +444,14 @@ async def test_azure_assistants_agent_thread_persistence():
first_response = await agent.run(
"Remember this number: 42. What number did I just tell you to remember?", thread=thread
)
assert isinstance(first_response, AgentRunResponse)
assert isinstance(first_response, AgentResponse)
assert "42" in first_response.text
# Second message - test conversation memory
second_response = await agent.run(
"What number did I tell you to remember in my previous message?", thread=thread
)
assert isinstance(second_response, AgentRunResponse)
assert isinstance(second_response, AgentResponse)
assert "42" in second_response.text
# Verify thread has been populated with conversation ID
@@ -475,7 +475,7 @@ async def test_azure_assistants_agent_existing_thread_id():
response1 = await agent.run("What's the weather in Paris?", thread=thread)
# Validate first response
assert isinstance(response1, AgentRunResponse)
assert isinstance(response1, AgentResponse)
assert response1.text is not None
assert any(word in response1.text.lower() for word in ["weather", "paris"])
@@ -497,7 +497,7 @@ async def test_azure_assistants_agent_existing_thread_id():
response2 = await agent.run("What was the last city I asked about?", thread=thread)
# Validate that the agent remembers the previous conversation
assert isinstance(response2, AgentRunResponse)
assert isinstance(response2, AgentResponse)
assert response2.text is not None
# Should reference Paris from the previous conversation
assert "paris" in response2.text.lower()
@@ -517,7 +517,7 @@ async def test_azure_assistants_agent_code_interpreter():
response = await agent.run("Write Python code to calculate the factorial of 5 and show the result.")
# Validate response
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.text is not None
# Factorial of 5 is 120
assert "120" in response.text or "factorial" in response.text.lower()
@@ -536,7 +536,7 @@ async def test_azure_assistants_client_agent_level_tool_persistence():
# First run - agent-level tool should be available
first_response = await agent.run("What's the weather like in Chicago?")
assert isinstance(first_response, AgentRunResponse)
assert isinstance(first_response, AgentResponse)
assert first_response.text is not None
# Should use the agent-level weather tool
assert any(term in first_response.text.lower() for term in ["chicago", "sunny", "72"])
@@ -544,7 +544,7 @@ async def test_azure_assistants_client_agent_level_tool_persistence():
# Second run - agent-level tool should still be available (persistence test)
second_response = await agent.run("What's the weather in Miami?")
assert isinstance(second_response, AgentRunResponse)
assert isinstance(second_response, AgentResponse)
assert second_response.text is not None
# Should use the agent-level weather tool again
assert any(term in second_response.text.lower() for term in ["miami", "sunny", "72"])
@@ -17,8 +17,8 @@ from openai.types.chat.chat_completion_chunk import ChoiceDelta as ChunkChoiceDe
from openai.types.chat.chat_completion_message import ChatCompletionMessage
from agent_framework import (
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
BaseChatClient,
ChatAgent,
ChatClientProtocol,
@@ -731,7 +731,7 @@ async def test_azure_openai_chat_client_agent_basic_run():
# Test basic run
response = await agent.run("Please respond with exactly: 'This is a response test.'")
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.text is not None
assert len(response.text) > 0
assert "response test" in response.text.lower()
@@ -747,7 +747,7 @@ async def test_azure_openai_chat_client_agent_basic_run_streaming():
# Test streaming run
full_text = ""
async for chunk in agent.run_stream("Please respond with exactly: 'This is a streaming response test.'"):
assert isinstance(chunk, AgentRunResponseUpdate)
assert isinstance(chunk, AgentResponseUpdate)
if chunk.text:
full_text += chunk.text
@@ -769,13 +769,13 @@ async def test_azure_openai_chat_client_agent_thread_persistence():
# First interaction
response1 = await agent.run("My name is Alice. Remember this.", thread=thread)
assert isinstance(response1, AgentRunResponse)
assert isinstance(response1, AgentResponse)
assert response1.text is not None
# Second interaction - test memory
response2 = await agent.run("What is my name?", thread=thread)
assert isinstance(response2, AgentRunResponse)
assert isinstance(response2, AgentResponse)
assert response2.text is not None
assert "alice" in response2.text.lower()
@@ -795,7 +795,7 @@ async def test_azure_openai_chat_client_agent_existing_thread():
thread = first_agent.get_new_thread()
first_response = await first_agent.run("My name is Alice. Remember this.", thread=thread)
assert isinstance(first_response, AgentRunResponse)
assert isinstance(first_response, AgentResponse)
assert first_response.text is not None
# Preserve the thread for reuse
@@ -810,7 +810,7 @@ async def test_azure_openai_chat_client_agent_existing_thread():
# Reuse the preserved thread
second_response = await second_agent.run("What is my name?", thread=preserved_thread)
assert isinstance(second_response, AgentRunResponse)
assert isinstance(second_response, AgentResponse)
assert second_response.text is not None
assert "alice" in second_response.text.lower()
@@ -828,7 +828,7 @@ async def test_azure_chat_client_agent_level_tool_persistence():
# First run - agent-level tool should be available
first_response = await agent.run("What's the weather like in Chicago?")
assert isinstance(first_response, AgentRunResponse)
assert isinstance(first_response, AgentResponse)
assert first_response.text is not None
# Should use the agent-level weather tool
assert any(term in first_response.text.lower() for term in ["chicago", "sunny", "72"])
@@ -836,7 +836,7 @@ async def test_azure_chat_client_agent_level_tool_persistence():
# Second run - agent-level tool should still be available (persistence test)
second_response = await agent.run("What's the weather in Miami?")
assert isinstance(second_response, AgentRunResponse)
assert isinstance(second_response, AgentResponse)
assert second_response.text is not None
# Should use the agent-level weather tool again
assert any(term in second_response.text.lower() for term in ["miami", "sunny", "72"])
@@ -10,7 +10,7 @@ from pydantic import BaseModel
from pytest import param
from agent_framework import (
AgentRunResponse,
AgentResponse,
ChatAgent,
ChatClientProtocol,
ChatMessage,
@@ -432,7 +432,7 @@ async def test_integration_client_agent_existing_thread():
thread = first_agent.get_new_thread()
first_response = await first_agent.run("My hobby is photography. Remember this.", thread=thread, store=True)
assert isinstance(first_response, AgentRunResponse)
assert isinstance(first_response, AgentResponse)
assert first_response.text is not None
# Preserve the thread for reuse
@@ -447,6 +447,6 @@ async def test_integration_client_agent_existing_thread():
# Reuse the preserved thread
second_response = await second_agent.run("What is my hobby?", thread=preserved_thread)
assert isinstance(second_response, AgentRunResponse)
assert isinstance(second_response, AgentResponse)
assert second_response.text is not None
assert "photography" in second_response.text.lower()
+6 -6
View File
@@ -13,8 +13,8 @@ from pytest import fixture
from agent_framework import (
AgentProtocol,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
BaseChatClient,
ChatMessage,
@@ -231,9 +231,9 @@ class MockAgent(AgentProtocol):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
logger.debug(f"Running mock agent, with: {messages=}, {thread=}, {kwargs=}")
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, contents=[TextContent("Response")])])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, contents=[TextContent("Response")])])
async def run_stream(
self,
@@ -241,9 +241,9 @@ class MockAgent(AgentProtocol):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
logger.debug(f"Running mock agent stream, with: {messages=}, {thread=}, {kwargs=}")
yield AgentRunResponseUpdate(contents=[TextContent("Response")])
yield AgentResponseUpdate(contents=[TextContent("Response")])
def get_new_thread(self) -> AgentThread:
return MockAgentThread()
@@ -10,8 +10,8 @@ from pytest import raises
from agent_framework import (
AgentProtocol,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
ChatAgent,
ChatClientProtocol,
@@ -45,7 +45,7 @@ async def test_agent_run(agent: AgentProtocol) -> None:
async def test_agent_run_streaming(agent: AgentProtocol) -> None:
async def collect_updates(updates: AsyncIterable[AgentRunResponseUpdate]) -> list[AgentRunResponseUpdate]:
async def collect_updates(updates: AsyncIterable[AgentResponseUpdate]) -> list[AgentResponseUpdate]:
return [u async for u in updates]
updates = await collect_updates(agent.run_stream(messages="test"))
@@ -87,7 +87,7 @@ async def test_chat_client_agent_run(chat_client: ChatClientProtocol) -> None:
async def test_chat_client_agent_run_streaming(chat_client: ChatClientProtocol) -> None:
agent = ChatAgent(chat_client=chat_client)
result = await AgentRunResponse.from_agent_response_generator(agent.run_stream("Hello"))
result = await AgentResponse.from_agent_response_generator(agent.run_stream("Hello"))
assert result.text == "test streaming response another update"
@@ -329,7 +329,7 @@ async def test_chat_agent_run_stream_context_providers(chat_client: ChatClientPr
agent = ChatAgent(chat_client=chat_client, context_provider=mock_provider)
# Collect all stream updates
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream("Hello"):
updates.append(update)
@@ -440,9 +440,9 @@ async def test_chat_agent_as_tool_with_stream_callback(chat_client: ChatClientPr
agent = ChatAgent(chat_client=chat_client, name="StreamingAgent")
# Collect streaming updates
collected_updates: list[AgentRunResponseUpdate] = []
collected_updates: list[AgentResponseUpdate] = []
def stream_callback(update: AgentRunResponseUpdate) -> None:
def stream_callback(update: AgentResponseUpdate) -> None:
collected_updates.append(update)
tool = agent.as_tool(stream_callback=stream_callback)
@@ -474,9 +474,9 @@ async def test_chat_agent_as_tool_with_async_stream_callback(chat_client: ChatCl
agent = ChatAgent(chat_client=chat_client, name="AsyncStreamingAgent")
# Collect streaming updates using an async callback
collected_updates: list[AgentRunResponseUpdate] = []
collected_updates: list[AgentResponseUpdate] = []
async def async_stream_callback(update: AgentRunResponseUpdate) -> None:
async def async_stream_callback(update: AgentResponseUpdate) -> None:
collected_updates.append(update)
tool = agent.as_tool(stream_callback=async_stream_callback)
@@ -8,8 +8,8 @@ import pytest
from pydantic import BaseModel
from agent_framework import (
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
ChatAgent,
HostedCodeInterpreterTool,
@@ -46,7 +46,7 @@ async def test_openai_responses_client_agent_basic_run_streaming():
# Test streaming run
full_text = ""
async for chunk in agent.run_stream("Please respond with exactly: 'This is a streaming response test.'"):
assert isinstance(chunk, AgentRunResponseUpdate)
assert isinstance(chunk, AgentResponseUpdate)
if chunk.text:
full_text += chunk.text
@@ -68,13 +68,13 @@ async def test_openai_responses_client_agent_thread_persistence():
# First interaction
first_response = await agent.run("My favorite programming language is Python. Remember this.", thread=thread)
assert isinstance(first_response, AgentRunResponse)
assert isinstance(first_response, AgentResponse)
assert first_response.text is not None
# Second interaction - test memory
second_response = await agent.run("What is my favorite programming language?", thread=thread)
assert isinstance(second_response, AgentRunResponse)
assert isinstance(second_response, AgentResponse)
assert second_response.text is not None
@@ -100,7 +100,7 @@ async def test_openai_responses_client_agent_thread_storage_with_store_true():
)
# Validate response
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.text is not None
assert len(response.text) > 0
@@ -125,7 +125,7 @@ async def test_openai_responses_client_agent_existing_thread():
thread = first_agent.get_new_thread()
first_response = await first_agent.run("My hobby is photography. Remember this.", thread=thread)
assert isinstance(first_response, AgentRunResponse)
assert isinstance(first_response, AgentResponse)
assert first_response.text is not None
# Preserve the thread for reuse
@@ -140,7 +140,7 @@ async def test_openai_responses_client_agent_existing_thread():
# Reuse the preserved thread
second_response = await second_agent.run("What is my hobby?", thread=preserved_thread)
assert isinstance(second_response, AgentRunResponse)
assert isinstance(second_response, AgentResponse)
assert second_response.text is not None
assert "photography" in second_response.text.lower()
@@ -157,7 +157,7 @@ async def test_openai_responses_client_agent_hosted_code_interpreter_tool():
# Test code interpreter functionality
response = await agent.run("Calculate the sum of numbers from 1 to 10 using Python code.")
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.text is not None
assert len(response.text) > 0
# Should contain calculation result (sum of 1-10 = 55) or code execution content
@@ -179,7 +179,7 @@ async def test_openai_responses_client_agent_image_generation_tool():
# Test image generation functionality
response = await agent.run("Generate an image of a cute red panda sitting on a tree branch in a forest.")
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.messages
# Verify we got image content - look for ImageGenerationToolResultContent
@@ -209,7 +209,7 @@ async def test_openai_responses_client_agent_level_tool_persistence():
# First run - agent-level tool should be available
first_response = await agent.run("What's the weather like in Chicago?")
assert isinstance(first_response, AgentRunResponse)
assert isinstance(first_response, AgentResponse)
assert first_response.text is not None
# Should use the agent-level weather tool
assert any(term in first_response.text.lower() for term in ["chicago", "sunny", "72"])
@@ -217,7 +217,7 @@ async def test_openai_responses_client_agent_level_tool_persistence():
# Second run - agent-level tool should still be available (persistence test)
second_response = await agent.run("What's the weather in Miami?")
assert isinstance(second_response, AgentRunResponse)
assert isinstance(second_response, AgentResponse)
assert second_response.text is not None
# Should use the agent-level weather tool again
assert any(term in second_response.text.lower() for term in ["miami", "sunny", "72"])
@@ -249,7 +249,7 @@ async def test_openai_responses_client_run_level_tool_isolation():
tools=[get_weather_with_counter], # Run-level tool
)
assert isinstance(first_response, AgentRunResponse)
assert isinstance(first_response, AgentResponse)
assert first_response.text is not None
# Should use the run-level weather tool (call count should be 1)
assert call_count == 1
@@ -258,7 +258,7 @@ async def test_openai_responses_client_run_level_tool_isolation():
# Second run - run-level tool should NOT persist (key isolation test)
second_response = await agent.run("What's the weather like in Miami?")
assert isinstance(second_response, AgentRunResponse)
assert isinstance(second_response, AgentResponse)
assert second_response.text is not None
# Should NOT use the weather tool since it was only run-level in previous call
# Call count should still be 1 (no additional calls)
@@ -286,7 +286,7 @@ async def test_openai_responses_client_agent_chat_options_agent_level() -> None:
"Provide a brief, helpful response.",
)
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.text is not None
assert len(response.text) > 0
@@ -312,7 +312,7 @@ async def test_openai_responses_client_agent_hosted_mcp_tool() -> None:
options={"max_tokens": 5000},
)
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.text
# Should contain Azure-related content since it's asking about Azure CLI
assert any(term in response.text.lower() for term in ["azure", "storage", "account", "cli"])
@@ -338,7 +338,7 @@ async def test_openai_responses_client_agent_local_mcp_tool() -> None:
options={"max_tokens": 200},
)
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.text is not None
assert len(response.text) > 0
# Should contain Azure-related content since it's asking about Azure CLI
@@ -375,7 +375,7 @@ async def test_openai_responses_client_agent_with_response_format_pydantic() ->
)
# Validate response
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.value is not None
assert isinstance(response.value, ReleaseBrief)
@@ -422,7 +422,7 @@ async def test_openai_responses_client_agent_with_runtime_json_schema() -> None:
)
# Validate response
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.text is not None
# Parse JSON and validate structure
@@ -9,8 +9,8 @@ from pydantic import BaseModel, Field
from agent_framework import (
AgentProtocol,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
ChatMessage,
ChatResponse,
ChatResponseUpdate,
@@ -172,9 +172,9 @@ class TestAgentMiddlewarePipeline:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
expected_response = AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
expected_response = AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
return expected_response
result = await pipeline.execute(mock_agent, messages, context, final_handler)
@@ -200,9 +200,9 @@ class TestAgentMiddlewarePipeline:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
expected_response = AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
expected_response = AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
execution_order.append("handler")
return expected_response
@@ -216,11 +216,11 @@ class TestAgentMiddlewarePipeline:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentRunResponseUpdate]:
yield AgentRunResponseUpdate(contents=[TextContent(text="chunk1")])
yield AgentRunResponseUpdate(contents=[TextContent(text="chunk2")])
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentResponseUpdate]:
yield AgentResponseUpdate(contents=[TextContent(text="chunk1")])
yield AgentResponseUpdate(contents=[TextContent(text="chunk2")])
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in pipeline.execute_stream(mock_agent, messages, context, final_handler):
updates.append(update)
@@ -248,13 +248,13 @@ class TestAgentMiddlewarePipeline:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentRunResponseUpdate]:
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentResponseUpdate]:
execution_order.append("handler_start")
yield AgentRunResponseUpdate(contents=[TextContent(text="chunk1")])
yield AgentRunResponseUpdate(contents=[TextContent(text="chunk2")])
yield AgentResponseUpdate(contents=[TextContent(text="chunk1")])
yield AgentResponseUpdate(contents=[TextContent(text="chunk2")])
execution_order.append("handler_end")
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in pipeline.execute_stream(mock_agent, messages, context, final_handler):
updates.append(update)
@@ -271,10 +271,10 @@ class TestAgentMiddlewarePipeline:
context = AgentRunContext(agent=mock_agent, messages=messages)
execution_order: list[str] = []
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
# Handler should not be executed when terminated before next()
execution_order.append("handler")
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
response = await pipeline.execute(mock_agent, messages, context, final_handler)
assert response is not None
@@ -291,9 +291,9 @@ class TestAgentMiddlewarePipeline:
context = AgentRunContext(agent=mock_agent, messages=messages)
execution_order: list[str] = []
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
execution_order.append("handler")
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
response = await pipeline.execute(mock_agent, messages, context, final_handler)
assert response is not None
@@ -310,14 +310,14 @@ class TestAgentMiddlewarePipeline:
context = AgentRunContext(agent=mock_agent, messages=messages)
execution_order: list[str] = []
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentRunResponseUpdate]:
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentResponseUpdate]:
# Handler should not be executed when terminated before next()
execution_order.append("handler_start")
yield AgentRunResponseUpdate(contents=[TextContent(text="chunk1")])
yield AgentRunResponseUpdate(contents=[TextContent(text="chunk2")])
yield AgentResponseUpdate(contents=[TextContent(text="chunk1")])
yield AgentResponseUpdate(contents=[TextContent(text="chunk2")])
execution_order.append("handler_end")
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in pipeline.execute_stream(mock_agent, messages, context, final_handler):
updates.append(update)
@@ -334,13 +334,13 @@ class TestAgentMiddlewarePipeline:
context = AgentRunContext(agent=mock_agent, messages=messages)
execution_order: list[str] = []
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentRunResponseUpdate]:
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentResponseUpdate]:
execution_order.append("handler_start")
yield AgentRunResponseUpdate(contents=[TextContent(text="chunk1")])
yield AgentRunResponseUpdate(contents=[TextContent(text="chunk2")])
yield AgentResponseUpdate(contents=[TextContent(text="chunk1")])
yield AgentResponseUpdate(contents=[TextContent(text="chunk2")])
execution_order.append("handler_end")
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in pipeline.execute_stream(mock_agent, messages, context, final_handler):
updates.append(update)
@@ -370,9 +370,9 @@ class TestAgentMiddlewarePipeline:
thread = AgentThread()
context = AgentRunContext(agent=mock_agent, messages=messages, thread=thread)
expected_response = AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
expected_response = AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
return expected_response
result = await pipeline.execute(mock_agent, messages, context, final_handler)
@@ -396,9 +396,9 @@ class TestAgentMiddlewarePipeline:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages, thread=None)
expected_response = AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
expected_response = AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
return expected_response
result = await pipeline.execute(mock_agent, messages, context, final_handler)
@@ -767,9 +767,9 @@ class TestClassBasedMiddleware:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
metadata_updates.append("handler")
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
result = await pipeline.execute(mock_agent, messages, context, final_handler)
@@ -830,9 +830,9 @@ class TestFunctionBasedMiddleware:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
execution_order.append("handler")
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
result = await pipeline.execute(mock_agent, messages, context, final_handler)
@@ -893,9 +893,9 @@ class TestMixedMiddleware:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
execution_order.append("handler")
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
result = await pipeline.execute(mock_agent, messages, context, final_handler)
@@ -1004,9 +1004,9 @@ class TestMultipleMiddlewareOrdering:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
execution_order.append("handler")
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
result = await pipeline.execute(mock_agent, messages, context, final_handler)
@@ -1142,10 +1142,10 @@ class TestContextContentValidation:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
# Verify metadata was set by middleware
assert ctx.metadata.get("validated") is True
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
result = await pipeline.execute(mock_agent, messages, context, final_handler)
assert result is not None
@@ -1253,20 +1253,20 @@ class TestStreamingScenarios:
# Test non-streaming
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
streaming_flags.append(ctx.is_streaming)
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response")])
await pipeline.execute(mock_agent, messages, context, final_handler)
# Test streaming
context_stream = AgentRunContext(agent=mock_agent, messages=messages)
async def final_stream_handler(ctx: AgentRunContext) -> AsyncIterable[AgentRunResponseUpdate]:
async def final_stream_handler(ctx: AgentRunContext) -> AsyncIterable[AgentResponseUpdate]:
streaming_flags.append(ctx.is_streaming)
yield AgentRunResponseUpdate(contents=[TextContent(text="chunk")])
yield AgentResponseUpdate(contents=[TextContent(text="chunk")])
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in pipeline.execute_stream(mock_agent, messages, context_stream, final_stream_handler):
updates.append(update)
@@ -1290,11 +1290,11 @@ class TestStreamingScenarios:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_stream_handler(ctx: AgentRunContext) -> AsyncIterable[AgentRunResponseUpdate]:
async def final_stream_handler(ctx: AgentRunContext) -> AsyncIterable[AgentResponseUpdate]:
chunks_processed.append("stream_start")
yield AgentRunResponseUpdate(contents=[TextContent(text="chunk1")])
yield AgentResponseUpdate(contents=[TextContent(text="chunk1")])
chunks_processed.append("chunk1_yielded")
yield AgentRunResponseUpdate(contents=[TextContent(text="chunk2")])
yield AgentResponseUpdate(contents=[TextContent(text="chunk2")])
chunks_processed.append("chunk2_yielded")
chunks_processed.append("stream_end")
@@ -1452,16 +1452,16 @@ class TestMiddlewareExecutionControl:
handler_called = False
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
nonlocal handler_called
handler_called = True
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="should not execute")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="should not execute")])
result = await pipeline.execute(mock_agent, messages, context, final_handler)
# Verify no execution happened - should return empty AgentRunResponse
# Verify no execution happened - should return empty AgentResponse
assert result is not None
assert isinstance(result, AgentRunResponse)
assert isinstance(result, AgentResponse)
assert result.messages == [] # Empty response
assert not handler_called
assert context.result is None
@@ -1483,13 +1483,13 @@ class TestMiddlewareExecutionControl:
handler_called = False
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentRunResponseUpdate]:
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentResponseUpdate]:
nonlocal handler_called
handler_called = True
yield AgentRunResponseUpdate(contents=[TextContent(text="should not execute")])
yield AgentResponseUpdate(contents=[TextContent(text="should not execute")])
# When middleware doesn't call next(), streaming should yield no updates
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in pipeline.execute_stream(mock_agent, messages, context, final_handler):
updates.append(update)
@@ -1556,17 +1556,17 @@ class TestMiddlewareExecutionControl:
handler_called = False
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
nonlocal handler_called
handler_called = True
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="should not execute")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="should not execute")])
result = await pipeline.execute(mock_agent, messages, context, final_handler)
# Verify only first middleware was called and empty response returned
assert execution_order == ["first"]
assert result is not None
assert isinstance(result, AgentRunResponse)
assert isinstance(result, AgentResponse)
assert result.messages == [] # Empty response
assert not handler_called
@@ -9,8 +9,8 @@ from pydantic import BaseModel, Field
from agent_framework import (
AgentProtocol,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
ChatAgent,
ChatMessage,
Role,
@@ -40,7 +40,7 @@ class TestResultOverrideMiddleware:
async def test_agent_middleware_response_override_non_streaming(self, mock_agent: AgentProtocol) -> None:
"""Test that agent middleware can override response for non-streaming execution."""
override_response = AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="overridden response")])
override_response = AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="overridden response")])
class ResponseOverrideMiddleware(AgentMiddleware):
async def process(
@@ -57,10 +57,10 @@ class TestResultOverrideMiddleware:
handler_called = False
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
nonlocal handler_called
handler_called = True
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="original response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="original response")])
result = await pipeline.execute(mock_agent, messages, context, final_handler)
@@ -74,9 +74,9 @@ class TestResultOverrideMiddleware:
async def test_agent_middleware_response_override_streaming(self, mock_agent: AgentProtocol) -> None:
"""Test that agent middleware can override response for streaming execution."""
async def override_stream() -> AsyncIterable[AgentRunResponseUpdate]:
yield AgentRunResponseUpdate(contents=[TextContent(text="overridden")])
yield AgentRunResponseUpdate(contents=[TextContent(text=" stream")])
async def override_stream() -> AsyncIterable[AgentResponseUpdate]:
yield AgentResponseUpdate(contents=[TextContent(text="overridden")])
yield AgentResponseUpdate(contents=[TextContent(text=" stream")])
class StreamResponseOverrideMiddleware(AgentMiddleware):
async def process(
@@ -91,10 +91,10 @@ class TestResultOverrideMiddleware:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentRunResponseUpdate]:
yield AgentRunResponseUpdate(contents=[TextContent(text="original")])
async def final_handler(ctx: AgentRunContext) -> AsyncIterable[AgentResponseUpdate]:
yield AgentResponseUpdate(contents=[TextContent(text="original")])
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in pipeline.execute_stream(mock_agent, messages, context, final_handler):
updates.append(update)
@@ -148,7 +148,7 @@ class TestResultOverrideMiddleware:
await next(context)
# Then conditionally override based on content
if any("special" in msg.text for msg in context.messages if msg.text):
context.result = AgentRunResponse(
context.result = AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, text="Special response from middleware!")]
)
@@ -174,10 +174,10 @@ class TestResultOverrideMiddleware:
"""Test streaming result override functionality with ChatAgent integration."""
mock_chat_client = MockChatClient()
async def custom_stream() -> AsyncIterable[AgentRunResponseUpdate]:
yield AgentRunResponseUpdate(contents=[TextContent(text="Custom")])
yield AgentRunResponseUpdate(contents=[TextContent(text=" streaming")])
yield AgentRunResponseUpdate(contents=[TextContent(text=" response!")])
async def custom_stream() -> AsyncIterable[AgentResponseUpdate]:
yield AgentResponseUpdate(contents=[TextContent(text="Custom")])
yield AgentResponseUpdate(contents=[TextContent(text=" streaming")])
yield AgentResponseUpdate(contents=[TextContent(text=" response!")])
class ChatAgentStreamOverrideMiddleware(AgentMiddleware):
async def process(
@@ -195,7 +195,7 @@ class TestResultOverrideMiddleware:
# Test streaming override case
override_messages = [ChatMessage(role=Role.USER, text="Give me a custom stream")]
override_updates: list[AgentRunResponseUpdate] = []
override_updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream(override_messages):
override_updates.append(update)
@@ -206,7 +206,7 @@ class TestResultOverrideMiddleware:
# Test normal streaming case
normal_messages = [ChatMessage(role=Role.USER, text="Normal streaming request")]
normal_updates: list[AgentRunResponseUpdate] = []
normal_updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream(normal_messages):
normal_updates.append(update)
@@ -231,19 +231,19 @@ class TestResultOverrideMiddleware:
handler_called = False
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
nonlocal handler_called
handler_called = True
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="executed response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="executed response")])
# Test case where next() is NOT called
no_execute_messages = [ChatMessage(role=Role.USER, text="Don't run this")]
no_execute_context = AgentRunContext(agent=mock_agent, messages=no_execute_messages)
no_execute_result = await pipeline.execute(mock_agent, no_execute_messages, no_execute_context, final_handler)
# When middleware doesn't call next(), result should be empty AgentRunResponse
# When middleware doesn't call next(), result should be empty AgentResponse
assert no_execute_result is not None
assert isinstance(no_execute_result, AgentRunResponse)
assert isinstance(no_execute_result, AgentResponse)
assert no_execute_result.messages == [] # Empty response
assert not handler_called
assert no_execute_context.result is None
@@ -313,7 +313,7 @@ class TestResultObservability:
async def test_agent_middleware_response_observability(self, mock_agent: AgentProtocol) -> None:
"""Test that middleware can observe response after execution."""
observed_responses: list[AgentRunResponse] = []
observed_responses: list[AgentResponse] = []
class ObservabilityMiddleware(AgentMiddleware):
async def process(
@@ -327,7 +327,7 @@ class TestResultObservability:
# Context should now contain the response for observability
assert context.result is not None
assert isinstance(context.result, AgentRunResponse)
assert isinstance(context.result, AgentResponse)
observed_responses.append(context.result)
middleware = ObservabilityMiddleware()
@@ -335,8 +335,8 @@ class TestResultObservability:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="executed response")])
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="executed response")])
result = await pipeline.execute(mock_agent, messages, context, final_handler)
@@ -392,11 +392,11 @@ class TestResultObservability:
# Now observe and conditionally override
assert context.result is not None
assert isinstance(context.result, AgentRunResponse)
assert isinstance(context.result, AgentResponse)
if "modify" in context.result.messages[0].text:
# Override after observing
context.result = AgentRunResponse(
context.result = AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, text="modified after execution")]
)
@@ -405,8 +405,8 @@ class TestResultObservability:
messages = [ChatMessage(role=Role.USER, text="test")]
context = AgentRunContext(agent=mock_agent, messages=messages)
async def final_handler(ctx: AgentRunContext) -> AgentRunResponse:
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response to modify")])
async def final_handler(ctx: AgentRunContext) -> AgentResponse:
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="response to modify")])
result = await pipeline.execute(mock_agent, messages, context, final_handler)
@@ -6,7 +6,7 @@ from typing import Any
import pytest
from agent_framework import (
AgentRunResponseUpdate,
AgentResponseUpdate,
ChatAgent,
ChatContext,
ChatMessage,
@@ -372,7 +372,7 @@ class TestChatAgentStreamingMiddleware:
# Execute streaming
messages = [ChatMessage(role=Role.USER, text="test message")]
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream(messages):
updates.append(update)
@@ -878,7 +878,7 @@ class TestMiddlewareDynamicRebuild:
agent = ChatAgent(chat_client=chat_client, middleware=[middleware1])
# First streaming execution
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream("Test stream message 1"):
updates.append(update)
@@ -1085,7 +1085,7 @@ class TestRunLevelMiddleware:
run_middleware = StreamingTrackingMiddleware("run_stream")
# Execute streaming with run middleware
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream("Test streaming", middleware=[run_middleware]):
updates.append(update)
@@ -1711,7 +1711,7 @@ class TestChatAgentChatMiddleware:
# Execute streaming
messages = [ChatMessage(role=Role.USER, text="test message")]
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream(messages):
updates.append(update)
@@ -13,7 +13,7 @@ from opentelemetry.trace import StatusCode
from agent_framework import (
AGENT_FRAMEWORK_USER_AGENT,
AgentProtocol,
AgentRunResponse,
AgentResponse,
AgentThread,
BaseChatClient,
ChatMessage,
@@ -407,7 +407,7 @@ def mock_chat_agent():
self.default_options: dict[str, Any] = {"model_id": "TestModel"}
async def run(self, messages=None, *, thread=None, **kwargs):
return AgentRunResponse(
return AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, text="Agent response")],
usage_details=UsageDetails(input_token_count=15, output_token_count=25),
response_id="test_response_id",
@@ -415,10 +415,10 @@ def mock_chat_agent():
)
async def run_stream(self, messages=None, *, thread=None, **kwargs):
from agent_framework import AgentRunResponseUpdate
from agent_framework import AgentResponseUpdate
yield AgentRunResponseUpdate(text="Hello", role=Role.ASSISTANT)
yield AgentRunResponseUpdate(text=" from agent", role=Role.ASSISTANT)
yield AgentResponseUpdate(text="Hello", role=Role.ASSISTANT)
yield AgentResponseUpdate(text=" from agent", role=Role.ASSISTANT)
return MockChatClientAgent
+43 -43
View File
@@ -10,8 +10,8 @@ from pydantic import BaseModel
from pytest import fixture, mark, raises
from agent_framework import (
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
BaseContent,
ChatMessage,
ChatOptions,
@@ -1026,90 +1026,90 @@ def text_content() -> TextContent:
@fixture
def agent_run_response(chat_message: ChatMessage) -> AgentRunResponse:
return AgentRunResponse(messages=chat_message)
def agent_response(chat_message: ChatMessage) -> AgentResponse:
return AgentResponse(messages=chat_message)
@fixture
def agent_run_response_update(text_content: TextContent) -> AgentRunResponseUpdate:
return AgentRunResponseUpdate(role=Role.ASSISTANT, contents=[text_content])
def agent_response_update(text_content: TextContent) -> AgentResponseUpdate:
return AgentResponseUpdate(role=Role.ASSISTANT, contents=[text_content])
# region AgentRunResponse
# region AgentResponse
def test_agent_run_response_init_single_message(chat_message: ChatMessage) -> None:
response = AgentRunResponse(messages=chat_message)
response = AgentResponse(messages=chat_message)
assert response.messages == [chat_message]
def test_agent_run_response_init_list_messages(chat_message: ChatMessage) -> None:
response = AgentRunResponse(messages=[chat_message, chat_message])
response = AgentResponse(messages=[chat_message, chat_message])
assert len(response.messages) == 2
assert response.messages[0] == chat_message
def test_agent_run_response_init_none_messages() -> None:
response = AgentRunResponse()
response = AgentResponse()
assert response.messages == []
def test_agent_run_response_text_property(chat_message: ChatMessage) -> None:
response = AgentRunResponse(messages=[chat_message, chat_message])
response = AgentResponse(messages=[chat_message, chat_message])
assert response.text == "HelloHello"
def test_agent_run_response_text_property_empty() -> None:
response = AgentRunResponse()
response = AgentResponse()
assert response.text == ""
def test_agent_run_response_from_updates(agent_run_response_update: AgentRunResponseUpdate) -> None:
updates = [agent_run_response_update, agent_run_response_update]
response = AgentRunResponse.from_agent_run_response_updates(updates)
def test_agent_run_response_from_updates(agent_response_update: AgentResponseUpdate) -> None:
updates = [agent_response_update, agent_response_update]
response = AgentResponse.from_agent_run_response_updates(updates)
assert len(response.messages) > 0
assert response.text == "Test contentTest content"
def test_agent_run_response_str_method(chat_message: ChatMessage) -> None:
response = AgentRunResponse(messages=chat_message)
response = AgentResponse(messages=chat_message)
assert str(response) == "Hello"
# region AgentRunResponseUpdate
# region AgentResponseUpdate
def test_agent_run_response_update_init_content_list(text_content: TextContent) -> None:
update = AgentRunResponseUpdate(contents=[text_content, text_content])
update = AgentResponseUpdate(contents=[text_content, text_content])
assert len(update.contents) == 2
assert update.contents[0] == text_content
def test_agent_run_response_update_init_none_content() -> None:
update = AgentRunResponseUpdate()
update = AgentResponseUpdate()
assert update.contents == []
def test_agent_run_response_update_text_property(text_content: TextContent) -> None:
update = AgentRunResponseUpdate(contents=[text_content, text_content])
update = AgentResponseUpdate(contents=[text_content, text_content])
assert update.text == "Test contentTest content"
def test_agent_run_response_update_text_property_empty() -> None:
update = AgentRunResponseUpdate()
update = AgentResponseUpdate()
assert update.text == ""
def test_agent_run_response_update_str_method(text_content: TextContent) -> None:
update = AgentRunResponseUpdate(contents=[text_content])
update = AgentResponseUpdate(contents=[text_content])
assert str(update) == "Test content"
def test_agent_run_response_update_created_at() -> None:
"""Test that AgentRunResponseUpdate properly handles created_at timestamps."""
"""Test that AgentResponseUpdate properly handles created_at timestamps."""
# Test with a properly formatted UTC timestamp
utc_timestamp = "2024-12-01T00:31:30.000000Z"
update = AgentRunResponseUpdate(
update = AgentResponseUpdate(
contents=[TextContent(text="test")],
role=Role.ASSISTANT,
created_at=utc_timestamp,
@@ -1120,7 +1120,7 @@ def test_agent_run_response_update_created_at() -> None:
# Verify that we can generate a proper UTC timestamp
now_utc = datetime.now(tz=timezone.utc)
formatted_utc = now_utc.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
update_with_now = AgentRunResponseUpdate(
update_with_now = AgentResponseUpdate(
contents=[TextContent(text="test")],
role=Role.ASSISTANT,
created_at=formatted_utc,
@@ -1130,10 +1130,10 @@ def test_agent_run_response_update_created_at() -> None:
def test_agent_run_response_created_at() -> None:
"""Test that AgentRunResponse properly handles created_at timestamps."""
"""Test that AgentResponse properly handles created_at timestamps."""
# Test with a properly formatted UTC timestamp
utc_timestamp = "2024-12-01T00:31:30.000000Z"
response = AgentRunResponse(
response = AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, text="Hello")],
created_at=utc_timestamp,
)
@@ -1143,7 +1143,7 @@ def test_agent_run_response_created_at() -> None:
# Verify that we can generate a proper UTC timestamp
now_utc = datetime.now(tz=timezone.utc)
formatted_utc = now_utc.strftime("%Y-%m-%dT%H:%M:%S.%fZ")
response_with_now = AgentRunResponse(
response_with_now = AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, text="Hello")],
created_at=formatted_utc,
)
@@ -1285,20 +1285,20 @@ def test_chat_tool_mode_eq_with_string():
assert {"mode": "auto"} == {"mode": "auto"}
# region AgentRunResponse
# region AgentResponse
@fixture
def agent_run_response_async() -> AgentRunResponse:
return AgentRunResponse(messages=[ChatMessage(role="user", text="Hello")])
def agent_run_response_async() -> AgentResponse:
return AgentResponse(messages=[ChatMessage(role="user", text="Hello")])
async def test_agent_run_response_from_async_generator():
async def gen():
yield AgentRunResponseUpdate(contents=[TextContent("A")])
yield AgentRunResponseUpdate(contents=[TextContent("B")])
yield AgentResponseUpdate(contents=[TextContent("A")])
yield AgentResponseUpdate(contents=[TextContent("B")])
r = await AgentRunResponse.from_agent_response_generator(gen())
r = await AgentResponse.from_agent_response_generator(gen())
assert r.text == "AB"
@@ -1668,7 +1668,7 @@ def test_chat_response_update_all_content_types():
def test_agent_run_response_complex_serialization():
"""Test AgentRunResponse from_dict and to_dict with messages and usage_details."""
"""Test AgentResponse from_dict and to_dict with messages and usage_details."""
response_data = {
"messages": [
@@ -1683,7 +1683,7 @@ def test_agent_run_response_complex_serialization():
},
}
response = AgentRunResponse.from_dict(response_data)
response = AgentResponse.from_dict(response_data)
assert len(response.messages) == 2
assert isinstance(response.messages[0], ChatMessage)
assert isinstance(response.usage_details, UsageDetails)
@@ -1696,7 +1696,7 @@ def test_agent_run_response_complex_serialization():
def test_agent_run_response_update_all_content_types():
"""Test AgentRunResponseUpdate from_dict with all content types and role handling."""
"""Test AgentResponseUpdate from_dict with all content types and role handling."""
update_data = {
"contents": [
@@ -1725,7 +1725,7 @@ def test_agent_run_response_update_all_content_types():
"role": {"value": "assistant"}, # Test role as dict
}
update = AgentRunResponseUpdate.from_dict(update_data)
update = AgentResponseUpdate.from_dict(update_data)
assert len(update.contents) == 12 # unknown_type is logged and ignored
assert isinstance(update.role, Role)
assert update.role.value == "assistant"
@@ -1738,7 +1738,7 @@ def test_agent_run_response_update_all_content_types():
# Test role as string conversion
update_data_str_role = update_data.copy()
update_data_str_role["role"] = "user"
update_str = AgentRunResponseUpdate.from_dict(update_data_str_role)
update_str = AgentResponseUpdate.from_dict(update_data_str_role)
assert isinstance(update_str.role, Role)
assert update_str.role.value == "user"
@@ -1922,7 +1922,7 @@ def test_agent_run_response_update_all_content_types():
id="chat_response_update",
),
pytest.param(
AgentRunResponse,
AgentResponse,
{
"messages": [
{
@@ -1942,10 +1942,10 @@ def test_agent_run_response_update_all_content_types():
"total_token_count": 8,
},
},
id="agent_run_response",
id="agent_response",
),
pytest.param(
AgentRunResponseUpdate,
AgentResponseUpdate,
{
"contents": [
{"type": "text", "text": "Streaming"},
@@ -1956,7 +1956,7 @@ def test_agent_run_response_update_all_content_types():
"response_id": "run-123",
"author_name": "Agent",
},
id="agent_run_response_update",
id="agent_response_update",
),
],
)
@@ -11,8 +11,8 @@ from openai.types.beta.threads.runs import RunStep
from pydantic import Field
from agent_framework import (
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
ChatAgent,
ChatClientProtocol,
@@ -1118,7 +1118,7 @@ async def test_openai_assistants_agent_basic_run():
response = await agent.run("Hello! Please respond with 'Hello World' exactly.")
# Validate response
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.text is not None
assert len(response.text) > 0
assert "Hello World" in response.text
@@ -1135,7 +1135,7 @@ async def test_openai_assistants_agent_basic_run_streaming():
full_message: str = ""
async for chunk in agent.run_stream("Please respond with exactly: 'This is a streaming response test.'"):
assert chunk is not None
assert isinstance(chunk, AgentRunResponseUpdate)
assert isinstance(chunk, AgentResponseUpdate)
if chunk.text:
full_message += chunk.text
@@ -1159,14 +1159,14 @@ async def test_openai_assistants_agent_thread_persistence():
first_response = await agent.run(
"Remember this number: 42. What number did I just tell you to remember?", thread=thread
)
assert isinstance(first_response, AgentRunResponse)
assert isinstance(first_response, AgentResponse)
assert "42" in first_response.text
# Second message - test conversation memory
second_response = await agent.run(
"What number did I tell you to remember in my previous message?", thread=thread
)
assert isinstance(second_response, AgentRunResponse)
assert isinstance(second_response, AgentResponse)
assert "42" in second_response.text
# Verify thread has been populated with conversation ID
@@ -1190,7 +1190,7 @@ async def test_openai_assistants_agent_existing_thread_id():
response1 = await agent.run("What's the weather in Paris?", thread=thread)
# Validate first response
assert isinstance(response1, AgentRunResponse)
assert isinstance(response1, AgentResponse)
assert response1.text is not None
assert any(word in response1.text.lower() for word in ["weather", "paris"])
@@ -1212,7 +1212,7 @@ async def test_openai_assistants_agent_existing_thread_id():
response2 = await agent.run("What was the last city I asked about?", thread=thread)
# Validate that the agent remembers the previous conversation
assert isinstance(response2, AgentRunResponse)
assert isinstance(response2, AgentResponse)
assert response2.text is not None
# Should reference Paris from the previous conversation
assert "paris" in response2.text.lower()
@@ -1232,7 +1232,7 @@ async def test_openai_assistants_agent_code_interpreter():
response = await agent.run("Write Python code to calculate the factorial of 5 and show the result.")
# Validate response
assert isinstance(response, AgentRunResponse)
assert isinstance(response, AgentResponse)
assert response.text is not None
# Factorial of 5 is 120
assert "120" in response.text or "factorial" in response.text.lower()
@@ -1251,7 +1251,7 @@ async def test_agent_level_tool_persistence():
# First run - agent-level tool should be available
first_response = await agent.run("What's the weather like in Chicago?")
assert isinstance(first_response, AgentRunResponse)
assert isinstance(first_response, AgentResponse)
assert first_response.text is not None
# Should use the agent-level weather tool
assert any(term in first_response.text.lower() for term in ["chicago", "sunny", "72"])
@@ -1259,7 +1259,7 @@ async def test_agent_level_tool_persistence():
# Second run - agent-level tool should still be available (persistence test)
second_response = await agent.run("What's the weather in Miami?")
assert isinstance(second_response, AgentRunResponse)
assert isinstance(second_response, AgentResponse)
assert second_response.text is not None
# Should use the agent-level weather tool again
assert any(term in second_response.text.lower() for term in ["miami", "sunny", "72"])
@@ -5,8 +5,8 @@ from typing import Any
from agent_framework import (
AgentExecutor,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
BaseAgent,
ChatMessage,
@@ -35,9 +35,9 @@ class _CountingAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
self.call_count += 1
return AgentRunResponse(
return AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, text=f"Response #{self.call_count}: {self.name}")]
)
@@ -47,9 +47,9 @@ class _CountingAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
self.call_count += 1
yield AgentRunResponseUpdate(contents=[TextContent(text=f"Response #{self.call_count}: {self.name}")])
yield AgentResponseUpdate(contents=[TextContent(text=f"Response #{self.call_count}: {self.name}")])
async def test_agent_executor_checkpoint_stores_and_restores_state() -> None:
@@ -10,8 +10,8 @@ from typing_extensions import Never
from agent_framework import (
AgentExecutor,
AgentExecutorResponse,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentRunUpdateEvent,
AgentThread,
BaseAgent,
@@ -46,9 +46,9 @@ class _ToolCallingAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
"""Non-streaming run - not used in this test."""
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="done")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="done")])
async def run_stream(
self,
@@ -56,16 +56,16 @@ class _ToolCallingAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
"""Simulate streaming with tool calls and results."""
# First update: some text
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=[TextContent(text="Let me search for that...")],
role=Role.ASSISTANT,
)
# Second update: tool call (no text!)
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=[
FunctionCallContent(
call_id="call_123",
@@ -77,7 +77,7 @@ class _ToolCallingAgent(BaseAgent):
)
# Third update: tool result (no text!)
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=[
FunctionResultContent(
call_id="call_123",
@@ -88,7 +88,7 @@ class _ToolCallingAgent(BaseAgent):
)
# Fourth update: final text response
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=[TextContent(text="The weather is sunny, 72°F.")],
role=Role.ASSISTANT,
)
@@ -223,7 +223,7 @@ class MockChatClient:
@executor(id="test_executor")
async def test_executor(agent_executor_response: AgentExecutorResponse, ctx: WorkflowContext[Never, str]) -> None:
await ctx.yield_output(agent_executor_response.agent_run_response.text)
await ctx.yield_output(agent_executor_response.agent_response.text)
async def test_agent_executor_tool_call_with_approval() -> None:
@@ -2,26 +2,26 @@
"""Tests for AgentRunEvent and AgentRunUpdateEvent type annotations."""
from agent_framework import AgentRunResponse, AgentRunResponseUpdate, ChatMessage, Role
from agent_framework import AgentResponse, AgentResponseUpdate, ChatMessage, Role
from agent_framework._workflows._events import AgentRunEvent, AgentRunUpdateEvent
def test_agent_run_event_data_type() -> None:
"""Verify AgentRunEvent.data is typed as AgentRunResponse | None."""
response = AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="Hello")])
"""Verify AgentRunEvent.data is typed as AgentResponse | None."""
response = AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="Hello")])
event = AgentRunEvent(executor_id="test", data=response)
# This assignment should pass type checking without a cast
data: AgentRunResponse | None = event.data
data: AgentResponse | None = event.data
assert data is not None
assert data.text == "Hello"
def test_agent_run_update_event_data_type() -> None:
"""Verify AgentRunUpdateEvent.data is typed as AgentRunResponseUpdate | None."""
update = AgentRunResponseUpdate()
"""Verify AgentRunUpdateEvent.data is typed as AgentResponseUpdate | None."""
update = AgentResponseUpdate()
event = AgentRunUpdateEvent(executor_id="test", data=update)
# This assignment should pass type checking without a cast
data: AgentRunResponseUpdate | None = event.data
data: AgentResponseUpdate | None = event.data
assert data is not None
@@ -3,7 +3,7 @@
from collections.abc import AsyncIterable
from typing import Any
from agent_framework import AgentRunResponse, AgentRunResponseUpdate, AgentThread, ChatMessage
from agent_framework import AgentResponse, AgentResponseUpdate, AgentThread, ChatMessage
from agent_framework._workflows._agent_utils import resolve_agent_id
@@ -38,7 +38,7 @@ class MockAgent:
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse: ...
) -> AgentResponse: ...
def run_stream(
self,
@@ -46,7 +46,7 @@ class MockAgent:
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]: ...
) -> AsyncIterable[AgentResponseUpdate]: ...
def get_new_thread(self, **kwargs: Any) -> AgentThread:
"""Creates a new conversation thread for the agent."""
@@ -8,7 +8,7 @@ from typing_extensions import Never
from agent_framework import (
AgentExecutorRequest,
AgentExecutorResponse,
AgentRunResponse,
AgentResponse,
ChatMessage,
ConcurrentBuilder,
Executor,
@@ -36,7 +36,7 @@ class _FakeAgentExec(Executor):
@handler
async def run(self, request: AgentExecutorRequest, ctx: WorkflowContext[AgentExecutorResponse]) -> None:
response = AgentRunResponse(messages=ChatMessage(Role.ASSISTANT, text=self._reply_text))
response = AgentResponse(messages=ChatMessage(Role.ASSISTANT, text=self._reply_text))
full_conversation = list(request.messages) + list(response.messages)
await ctx.send_message(AgentExecutorResponse(self.id, response, full_conversation=full_conversation))
@@ -142,7 +142,7 @@ async def test_concurrent_custom_aggregator_callback_is_used() -> None:
async def summarize(results: list[AgentExecutorResponse]) -> str:
texts: list[str] = []
for r in results:
msgs: list[ChatMessage] = r.agent_run_response.messages
msgs: list[ChatMessage] = r.agent_response.messages
texts.append(msgs[-1].text if msgs else "")
return " | ".join(sorted(texts))
@@ -173,7 +173,7 @@ async def test_concurrent_custom_aggregator_sync_callback_is_used() -> None:
def summarize_sync(results: list[AgentExecutorResponse], _ctx: WorkflowContext[Any]) -> str: # type: ignore[unused-argument]
texts: list[str] = []
for r in results:
msgs: list[ChatMessage] = r.agent_run_response.messages
msgs: list[ChatMessage] = r.agent_response.messages
texts.append(msgs[-1].text if msgs else "")
return " | ".join(sorted(texts))
@@ -217,7 +217,7 @@ async def test_concurrent_with_aggregator_executor_instance() -> None:
async def aggregate(self, results: list[AgentExecutorResponse], ctx: WorkflowContext[Never, str]) -> None:
texts: list[str] = []
for r in results:
msgs: list[ChatMessage] = r.agent_run_response.messages
msgs: list[ChatMessage] = r.agent_response.messages
texts.append(msgs[-1].text if msgs else "")
await ctx.yield_output(" & ".join(sorted(texts)))
@@ -251,7 +251,7 @@ async def test_concurrent_with_aggregator_executor_factory() -> None:
async def aggregate(self, results: list[AgentExecutorResponse], ctx: WorkflowContext[Never, str]) -> None:
texts: list[str] = []
for r in results:
msgs: list[ChatMessage] = r.agent_run_response.messages
msgs: list[ChatMessage] = r.agent_response.messages
texts.append(msgs[-1].text if msgs else "")
await ctx.yield_output(" | ".join(sorted(texts)))
@@ -292,7 +292,7 @@ async def test_concurrent_with_aggregator_executor_factory_with_default_id() ->
async def aggregate(self, results: list[AgentExecutorResponse], ctx: WorkflowContext[Never, str]) -> None:
texts: list[str] = []
for r in results:
msgs: list[ChatMessage] = r.agent_run_response.messages
msgs: list[ChatMessage] = r.agent_response.messages
texts.append(msgs[-1].text if msgs else "")
await ctx.yield_output(" | ".join(sorted(texts)))
@@ -9,8 +9,8 @@ from typing_extensions import Never
from agent_framework import (
AgentExecutor,
AgentExecutorResponse,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
BaseAgent,
ChatMessage,
@@ -39,8 +39,8 @@ class _SimpleAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text=self._reply_text)])
) -> AgentResponse:
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text=self._reply_text)])
async def run_stream( # type: ignore[override]
self,
@@ -48,9 +48,9 @@ class _SimpleAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
# This agent does not support streaming; yield a single complete response
yield AgentRunResponseUpdate(contents=[TextContent(text=self._reply_text)])
yield AgentResponseUpdate(contents=[TextContent(text=self._reply_text)])
class _CaptureFullConversation(Executor):
@@ -108,7 +108,7 @@ class _CaptureAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
# Normalize and record messages for verification when running non-streaming
norm: list[ChatMessage] = []
if messages:
@@ -118,7 +118,7 @@ class _CaptureAgent(BaseAgent):
elif isinstance(m, str):
norm.append(ChatMessage(role=Role.USER, text=m))
self._last_messages = norm
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text=self._reply_text)])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text=self._reply_text)])
async def run_stream( # type: ignore[override]
self,
@@ -126,7 +126,7 @@ class _CaptureAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
# Normalize and record messages for verification when running streaming
norm: list[ChatMessage] = []
if messages:
@@ -136,7 +136,7 @@ class _CaptureAgent(BaseAgent):
elif isinstance(m, str):
norm.append(ChatMessage(role=Role.USER, text=m))
self._last_messages = norm
yield AgentRunResponseUpdate(contents=[TextContent(text=self._reply_text)])
yield AgentResponseUpdate(contents=[TextContent(text=self._reply_text)])
async def test_sequential_adapter_uses_full_conversation() -> None:
@@ -8,8 +8,8 @@ import pytest
from agent_framework import (
AgentExecutorResponse,
AgentRequestInfoResponse,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
BaseAgent,
BaseGroupChatOrchestrator,
@@ -44,9 +44,9 @@ class StubAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
response = ChatMessage(role=Role.ASSISTANT, text=self._reply_text, author_name=self.name)
return AgentRunResponse(messages=[response])
return AgentResponse(messages=[response])
def run_stream( # type: ignore[override]
self,
@@ -54,9 +54,9 @@ class StubAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
async def _stream() -> AsyncIterable[AgentRunResponseUpdate]:
yield AgentRunResponseUpdate(
) -> AsyncIterable[AgentResponseUpdate]:
async def _stream() -> AsyncIterable[AgentResponseUpdate]:
yield AgentResponseUpdate(
contents=[TextContent(text=self._reply_text)], role=Role.ASSISTANT, author_name=self.name
)
@@ -88,12 +88,12 @@ class StubManagerAgent(ChatAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
if self._call_count == 0:
self._call_count += 1
# First call: select the agent (using AgentOrchestrationOutput format)
payload = {"terminate": False, "reason": "Selecting agent", "next_speaker": "agent", "final_message": None}
return AgentRunResponse(
return AgentResponse(
messages=[
ChatMessage(
role=Role.ASSISTANT,
@@ -114,7 +114,7 @@ class StubManagerAgent(ChatAgent):
"next_speaker": None,
"final_message": "agent manager final",
}
return AgentRunResponse(
return AgentResponse(
messages=[
ChatMessage(
role=Role.ASSISTANT,
@@ -134,12 +134,12 @@ class StubManagerAgent(ChatAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
if self._call_count == 0:
self._call_count += 1
async def _stream_initial() -> AsyncIterable[AgentRunResponseUpdate]:
yield AgentRunResponseUpdate(
async def _stream_initial() -> AsyncIterable[AgentResponseUpdate]:
yield AgentResponseUpdate(
contents=[
TextContent(
text=(
@@ -154,8 +154,8 @@ class StubManagerAgent(ChatAgent):
return _stream_initial()
async def _stream_final() -> AsyncIterable[AgentRunResponseUpdate]:
yield AgentRunResponseUpdate(
async def _stream_final() -> AsyncIterable[AgentResponseUpdate]:
yield AgentResponseUpdate(
contents=[
TextContent(
text=(
@@ -341,14 +341,14 @@ class TestGroupChatBuilder:
def __init__(self) -> None:
super().__init__(name="", description="test")
async def run(self, messages: Any = None, *, thread: Any = None, **kwargs: Any) -> AgentRunResponse:
return AgentRunResponse(messages=[])
async def run(self, messages: Any = None, *, thread: Any = None, **kwargs: Any) -> AgentResponse:
return AgentResponse(messages=[])
def run_stream(
self, messages: Any = None, *, thread: Any = None, **kwargs: Any
) -> AsyncIterable[AgentRunResponseUpdate]:
async def _stream() -> AsyncIterable[AgentRunResponseUpdate]:
yield AgentRunResponseUpdate(contents=[])
) -> AsyncIterable[AgentResponseUpdate]:
async def _stream() -> AsyncIterable[AgentResponseUpdate]:
yield AgentResponseUpdate(contents=[])
return _stream()
@@ -9,8 +9,8 @@ import pytest
from agent_framework import (
AgentProtocol,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentRunUpdateEvent,
AgentThread,
BaseAgent,
@@ -158,9 +158,9 @@ class StubAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
response = ChatMessage(role=Role.ASSISTANT, text=self._reply_text, author_name=self.name)
return AgentRunResponse(messages=[response])
return AgentResponse(messages=[response])
def run_stream( # type: ignore[override]
self,
@@ -168,9 +168,9 @@ class StubAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
async def _stream() -> AsyncIterable[AgentRunResponseUpdate]:
yield AgentRunResponseUpdate(
) -> AsyncIterable[AgentResponseUpdate]:
async def _stream() -> AsyncIterable[AgentResponseUpdate]:
yield AgentResponseUpdate(
contents=[TextContent(text=self._reply_text)], role=Role.ASSISTANT, author_name=self.name
)
@@ -424,8 +424,8 @@ class StubManagerAgent(BaseAgent):
*,
thread: Any = None,
**kwargs: Any,
) -> AgentRunResponse:
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="ok")])
) -> AgentResponse:
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="ok")])
def run_stream(
self,
@@ -433,9 +433,9 @@ class StubManagerAgent(BaseAgent):
*,
thread: Any = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
async def _gen() -> AsyncIterable[AgentRunResponseUpdate]:
yield AgentRunResponseUpdate(message_deltas=[ChatMessage(role=Role.ASSISTANT, text="ok")])
) -> AsyncIterable[AgentResponseUpdate]:
async def _gen() -> AsyncIterable[AgentResponseUpdate]:
yield AgentResponseUpdate(message_deltas=[ChatMessage(role=Role.ASSISTANT, text="ok")])
return _gen()
@@ -538,14 +538,14 @@ class StubThreadAgent(BaseAgent):
super().__init__(name=name or "agentA")
async def run_stream(self, messages=None, *, thread=None, **kwargs): # type: ignore[override]
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=[TextContent(text="thread-ok")],
author_name=self.name,
role=Role.ASSISTANT,
)
async def run(self, messages=None, *, thread=None, **kwargs): # type: ignore[override]
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="thread-ok", author_name=self.name)])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="thread-ok", author_name=self.name)])
class StubAssistantsClient:
@@ -560,16 +560,14 @@ class StubAssistantsAgent(BaseAgent):
self.chat_client = StubAssistantsClient() # type name contains 'AssistantsClient'
async def run_stream(self, messages=None, *, thread=None, **kwargs): # type: ignore[override]
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=[TextContent(text="assistants-ok")],
author_name=self.name,
role=Role.ASSISTANT,
)
async def run(self, messages=None, *, thread=None, **kwargs): # type: ignore[override]
return AgentRunResponse(
messages=[ChatMessage(role=Role.ASSISTANT, text="assistants-ok", author_name=self.name)]
)
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="assistants-ok", author_name=self.name)])
async def _collect_agent_responses_setup(participant: AgentProtocol) -> list[ChatMessage]:
@@ -10,8 +10,8 @@ import pytest
from agent_framework import (
AgentProtocol,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
ChatMessage,
Role,
@@ -114,10 +114,10 @@ class TestAgentRequestInfoExecutor:
"""Test that request_info handler calls ctx.request_info."""
executor = AgentRequestInfoExecutor(id="test_executor")
agent_run_response = AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="Agent response")])
agent_response = AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="Agent response")])
agent_response = AgentExecutorResponse(
executor_id="test_agent",
agent_run_response=agent_run_response,
agent_response=agent_response,
)
ctx = MagicMock(spec=WorkflowContext)
@@ -132,10 +132,10 @@ class TestAgentRequestInfoExecutor:
"""Test response handler when user provides additional messages."""
executor = AgentRequestInfoExecutor(id="test_executor")
agent_run_response = AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="Original")])
agent_response = AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="Original")])
original_request = AgentExecutorResponse(
executor_id="test_agent",
agent_run_response=agent_run_response,
agent_response=agent_response,
)
response = AgentRequestInfoResponse.from_strings(["Additional input"])
@@ -158,10 +158,10 @@ class TestAgentRequestInfoExecutor:
"""Test response handler when user approves (no additional messages)."""
executor = AgentRequestInfoExecutor(id="test_executor")
agent_run_response = AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="Original")])
agent_response = AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="Original")])
original_request = AgentExecutorResponse(
executor_id="test_agent",
agent_run_response=agent_run_response,
agent_response=agent_response,
)
response = AgentRequestInfoResponse.approve()
@@ -205,9 +205,9 @@ class _TestAgent:
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
"""Dummy run method."""
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="Test response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="Test response")])
def run_stream(
self,
@@ -215,11 +215,11 @@ class _TestAgent:
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
"""Dummy run_stream method."""
async def generator():
yield AgentRunResponseUpdate(messages=[ChatMessage(role=Role.ASSISTANT, text="Test response stream")])
yield AgentResponseUpdate(messages=[ChatMessage(role=Role.ASSISTANT, text="Test response stream")])
return generator()
@@ -7,7 +7,7 @@ import pytest
from agent_framework import (
AgentExecutorResponse,
AgentRunResponse,
AgentResponse,
Executor,
WorkflowContext,
WorkflowEvent,
@@ -158,7 +158,7 @@ async def test_runner_emits_runner_completion_for_agent_response_without_targets
await ctx.send_message(
Message(
data=AgentExecutorResponse("agent", AgentRunResponse()),
data=AgentExecutorResponse("agent", AgentResponse()),
source_id="agent",
)
)
@@ -7,8 +7,8 @@ import pytest
from agent_framework import (
AgentExecutorResponse,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
BaseAgent,
ChatMessage,
@@ -35,8 +35,8 @@ class _EchoAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text=f"{self.name} reply")])
) -> AgentResponse:
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text=f"{self.name} reply")])
async def run_stream( # type: ignore[override]
self,
@@ -44,9 +44,9 @@ class _EchoAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
# Minimal async generator with one assistant update
yield AgentRunResponseUpdate(contents=[TextContent(text=f"{self.name} reply")])
yield AgentResponseUpdate(contents=[TextContent(text=f"{self.name} reply")])
class _SummarizerExec(Executor):
@@ -11,9 +11,9 @@ import pytest
from agent_framework import (
AgentExecutor,
AgentResponse,
AgentResponseUpdate,
AgentRunEvent,
AgentRunResponse,
AgentRunResponseUpdate,
AgentRunUpdateEvent,
AgentThread,
BaseAgent,
@@ -831,9 +831,9 @@ class _StreamingTestAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
"""Non-streaming run - returns complete response."""
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text=self._reply_text)])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text=self._reply_text)])
async def run_stream(
self,
@@ -841,11 +841,11 @@ class _StreamingTestAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
"""Streaming run - yields incremental updates."""
# Simulate streaming by yielding character by character
for char in self._reply_text:
yield AgentRunResponseUpdate(contents=[TextContent(text=char)])
yield AgentResponseUpdate(contents=[TextContent(text=char)])
async def test_agent_streaming_vs_non_streaming() -> None:
@@ -8,8 +8,8 @@ import pytest
from agent_framework import (
AgentProtocol,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentRunUpdateEvent,
AgentThread,
ChatMessage,
@@ -52,7 +52,7 @@ class SimpleExecutor(Executor):
response_message = ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text=response_text)])
# Emit update event.
streaming_update = AgentRunResponseUpdate(
streaming_update = AgentResponseUpdate(
contents=[TextContent(text=response_text)], role=Role.ASSISTANT, message_id=str(uuid.uuid4())
)
await ctx.add_event(AgentRunUpdateEvent(executor_id=self.id, data=streaming_update))
@@ -74,7 +74,7 @@ class RequestingExecutor(Executor):
self, original_request: str, response: str, ctx: WorkflowContext[ChatMessage]
) -> None:
# Handle the response and emit completion response
update = AgentRunResponseUpdate(
update = AgentResponseUpdate(
contents=[TextContent(text="Request completed successfully")],
role=Role.ASSISTANT,
message_id=str(uuid.uuid4()),
@@ -100,7 +100,7 @@ class ConversationHistoryCapturingExecutor(Executor):
response_message = ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text=response_text)])
streaming_update = AgentRunResponseUpdate(
streaming_update = AgentResponseUpdate(
contents=[TextContent(text=response_text)], role=Role.ASSISTANT, message_id=str(uuid.uuid4())
)
await ctx.add_event(AgentRunUpdateEvent(executor_id=self.id, data=streaming_update))
@@ -124,7 +124,7 @@ class TestWorkflowAgent:
result = await agent.run("Hello World")
# Verify we got responses from both executors
assert isinstance(result, AgentRunResponse)
assert isinstance(result, AgentResponse)
assert len(result.messages) >= 2, f"Expected at least 2 messages, got {len(result.messages)}"
# Find messages from each executor
@@ -162,7 +162,7 @@ class TestWorkflowAgent:
agent = WorkflowAgent(workflow=workflow, name="Streaming Test Agent")
# Execute workflow streaming to capture streaming events
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream("Test input"):
updates.append(update)
@@ -191,13 +191,13 @@ class TestWorkflowAgent:
agent = WorkflowAgent(workflow=workflow, name="Request Test Agent")
# Execute workflow streaming to get request info event
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream("Start request"):
updates.append(update)
# Should have received an approval request for the request info
assert len(updates) > 0
approval_update: AgentRunResponseUpdate | None = None
approval_update: AgentResponseUpdate | None = None
for update in updates:
if any(isinstance(content, FunctionApprovalRequestContent) for content in update.contents):
approval_update = update
@@ -248,7 +248,7 @@ class TestWorkflowAgent:
continuation_result = await agent.run(response_message)
# Should complete successfully
assert isinstance(continuation_result, AgentRunResponse)
assert isinstance(continuation_result, AgentResponse)
# Verify cleanup - pending requests should be cleared after function response handling
assert len(agent.pending_requests) == 0
@@ -293,7 +293,7 @@ class TestWorkflowAgent:
"""Test that ctx.yield_output() in a workflow executor surfaces as agent output when using .as_agent().
This validates the fix for issue #2813: WorkflowOutputEvent should be converted to
AgentRunResponseUpdate when the workflow is wrapped via .as_agent().
AgentResponseUpdate when the workflow is wrapped via .as_agent().
"""
@executor
@@ -314,12 +314,12 @@ class TestWorkflowAgent:
agent = workflow.as_agent("test-agent")
agent_result = await agent.run("hello")
assert isinstance(agent_result, AgentRunResponse)
assert isinstance(agent_result, AgentResponse)
assert len(agent_result.messages) == 1
assert agent_result.messages[0].text == "processed: hello"
async def test_workflow_as_agent_yield_output_surfaces_in_run_stream(self) -> None:
"""Test that ctx.yield_output() surfaces as AgentRunResponseUpdate when streaming."""
"""Test that ctx.yield_output() surfaces as AgentResponseUpdate when streaming."""
@executor
async def yielding_executor(messages: list[ChatMessage], ctx: WorkflowContext) -> None:
@@ -329,7 +329,7 @@ class TestWorkflowAgent:
workflow = WorkflowBuilder().set_start_executor(yielding_executor).build()
agent = workflow.as_agent("test-agent")
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream("hello"):
updates.append(update)
@@ -353,7 +353,7 @@ class TestWorkflowAgent:
result = await agent.run("test")
assert isinstance(result, AgentRunResponse)
assert isinstance(result, AgentResponse)
assert len(result.messages) == 3
# Verify each content type is preserved
@@ -410,7 +410,7 @@ class TestWorkflowAgent:
workflow = WorkflowBuilder().set_start_executor(raw_yielding_executor).build()
agent = workflow.as_agent("raw-test-agent")
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream("test"):
updates.append(update)
@@ -448,7 +448,7 @@ class TestWorkflowAgent:
agent = workflow.as_agent("list-msg-agent")
# Verify streaming returns the update with all 4 contents before coalescing
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream("test"):
updates.append(update)
@@ -460,7 +460,7 @@ class TestWorkflowAgent:
# Verify run() coalesces text contents (expected behavior)
result = await agent.run("test")
assert isinstance(result, AgentRunResponse)
assert isinstance(result, AgentResponse)
assert len(result.messages) == 1
# TextContent items are coalesced into one
assert len(result.messages[0].contents) == 1
@@ -587,17 +587,17 @@ class TestWorkflowAgent:
def get_new_thread(self) -> AgentThread:
return AgentThread()
async def run(self, messages: Any, *, thread: AgentThread | None = None, **kwargs: Any) -> AgentRunResponse:
return AgentRunResponse(
async def run(self, messages: Any, *, thread: AgentThread | None = None, **kwargs: Any) -> AgentResponse:
return AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, text=self._response_text)],
text=self._response_text,
)
async def run_stream(
self, messages: Any, *, thread: AgentThread | None = None, **kwargs: Any
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
for word in self._response_text.split():
yield AgentRunResponseUpdate(
yield AgentResponseUpdate(
contents=[TextContent(text=word + " ")],
role=Role.ASSISTANT,
author_name=self._name,
@@ -661,16 +661,16 @@ class TestWorkflowAgent:
def get_new_thread(self) -> AgentThread:
return AgentThread()
async def run(self, messages: Any, *, thread: AgentThread | None = None, **kwargs: Any) -> AgentRunResponse:
return AgentRunResponse(
async def run(self, messages: Any, *, thread: AgentThread | None = None, **kwargs: Any) -> AgentResponse:
return AgentResponse(
messages=[ChatMessage(role=Role.ASSISTANT, text=self._response_text)],
text=self._response_text,
)
async def run_stream(
self, messages: Any, *, thread: AgentThread | None = None, **kwargs: Any
) -> AsyncIterable[AgentRunResponseUpdate]:
yield AgentRunResponseUpdate(
) -> AsyncIterable[AgentResponseUpdate]:
yield AgentResponseUpdate(
contents=[TextContent(text=self._response_text)],
role=Role.ASSISTANT,
author_name=self._name,
@@ -717,7 +717,7 @@ class TestWorkflowAgentAuthorName:
agent = WorkflowAgent(workflow=workflow, name="Test Agent")
# Collect streaming updates
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream("Hello"):
updates.append(update)
@@ -736,7 +736,7 @@ class TestWorkflowAgentAuthorName:
@handler
async def handle_message(self, message: list[ChatMessage], ctx: WorkflowContext[list[ChatMessage]]) -> None:
# Emit update with explicit author_name
update = AgentRunResponseUpdate(
update = AgentResponseUpdate(
contents=[TextContent(text="Response with author")],
role=Role.ASSISTANT,
author_name="custom_author_name", # Explicitly set
@@ -749,7 +749,7 @@ class TestWorkflowAgentAuthorName:
agent = WorkflowAgent(workflow=workflow, name="Test Agent")
# Collect streaming updates
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream("Hello"):
updates.append(update)
@@ -767,7 +767,7 @@ class TestWorkflowAgentAuthorName:
agent = WorkflowAgent(workflow=workflow, name="Multi-Executor Agent")
# Collect streaming updates
updates: list[AgentRunResponseUpdate] = []
updates: list[AgentResponseUpdate] = []
async for update in agent.run_stream("Hello"):
updates.append(update)
@@ -788,7 +788,7 @@ class TestWorkflowAgentMergeUpdates:
# Create updates with different response_ids and message_ids in non-chronological order
updates = [
# Response B, Message 2 (latest in resp B)
AgentRunResponseUpdate(
AgentResponseUpdate(
contents=[TextContent(text="RespB-Msg2")],
role=Role.ASSISTANT,
response_id="resp-b",
@@ -796,7 +796,7 @@ class TestWorkflowAgentMergeUpdates:
created_at="2024-01-01T12:02:00Z",
),
# Response A, Message 1 (earliest overall)
AgentRunResponseUpdate(
AgentResponseUpdate(
contents=[TextContent(text="RespA-Msg1")],
role=Role.ASSISTANT,
response_id="resp-a",
@@ -804,7 +804,7 @@ class TestWorkflowAgentMergeUpdates:
created_at="2024-01-01T12:00:00Z",
),
# Response B, Message 1 (earlier in resp B)
AgentRunResponseUpdate(
AgentResponseUpdate(
contents=[TextContent(text="RespB-Msg1")],
role=Role.ASSISTANT,
response_id="resp-b",
@@ -812,7 +812,7 @@ class TestWorkflowAgentMergeUpdates:
created_at="2024-01-01T12:01:00Z",
),
# Response A, Message 2 (later in resp A)
AgentRunResponseUpdate(
AgentResponseUpdate(
contents=[TextContent(text="RespA-Msg2")],
role=Role.ASSISTANT,
response_id="resp-a",
@@ -820,7 +820,7 @@ class TestWorkflowAgentMergeUpdates:
created_at="2024-01-01T12:00:30Z",
),
# Global dangling update (no response_id) - should go at end
AgentRunResponseUpdate(
AgentResponseUpdate(
contents=[TextContent(text="Global-Dangling")],
role=Role.ASSISTANT,
response_id=None,
@@ -891,7 +891,7 @@ class TestWorkflowAgentMergeUpdates:
"""Test that merge_updates correctly aggregates usage details, timestamps, and additional properties."""
# Create updates with various metadata including usage details
updates = [
AgentRunResponseUpdate(
AgentResponseUpdate(
contents=[
TextContent(text="First"),
UsageContent(
@@ -904,7 +904,7 @@ class TestWorkflowAgentMergeUpdates:
created_at="2024-01-01T12:00:00Z",
additional_properties={"source": "executor1", "priority": "high"},
),
AgentRunResponseUpdate(
AgentResponseUpdate(
contents=[
TextContent(text="Second"),
UsageContent(
@@ -917,7 +917,7 @@ class TestWorkflowAgentMergeUpdates:
created_at="2024-01-01T12:01:00Z", # Later timestamp
additional_properties={"source": "executor2", "category": "analysis"},
),
AgentRunResponseUpdate(
AgentResponseUpdate(
contents=[
TextContent(text="Third"),
UsageContent(details=UsageDetails(input_token_count=5, output_token_count=3, total_token_count=8)),
@@ -7,8 +7,8 @@ import pytest
from agent_framework import (
AgentExecutor,
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
BaseAgent,
ChatMessage,
@@ -29,11 +29,11 @@ class DummyAgent(BaseAgent):
norm.append(m)
elif isinstance(m, str):
norm.append(ChatMessage(role=Role.USER, text=m))
return AgentRunResponse(messages=norm)
return AgentResponse(messages=norm)
async def run_stream(self, messages=None, *, thread: AgentThread | None = None, **kwargs): # type: ignore[override]
# Minimal async generator
yield AgentRunResponseUpdate()
yield AgentResponseUpdate()
def test_builder_accepts_agents_directly():
@@ -6,8 +6,8 @@ from typing import Annotated, Any
import pytest
from agent_framework import (
AgentRunResponse,
AgentRunResponseUpdate,
AgentResponse,
AgentResponseUpdate,
AgentThread,
BaseAgent,
ChatMessage,
@@ -55,9 +55,9 @@ class _KwargsCapturingAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AgentRunResponse:
) -> AgentResponse:
self.captured_kwargs.append(dict(kwargs))
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text=f"{self.name} response")])
return AgentResponse(messages=[ChatMessage(role=Role.ASSISTANT, text=f"{self.name} response")])
async def run_stream(
self,
@@ -65,9 +65,9 @@ class _KwargsCapturingAgent(BaseAgent):
*,
thread: AgentThread | None = None,
**kwargs: Any,
) -> AsyncIterable[AgentRunResponseUpdate]:
) -> AsyncIterable[AgentResponseUpdate]:
self.captured_kwargs.append(dict(kwargs))
yield AgentRunResponseUpdate(contents=[TextContent(text=f"{self.name} response")])
yield AgentResponseUpdate(contents=[TextContent(text=f"{self.name} response")])
# region Sequential Builder Tests