mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
renamed all (#3207)
This commit is contained in:
committed by
GitHub
Unverified
parent
1ae0b09e42
commit
d8cf8361bd
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user