mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: name changes executed (#607)
* name changes executed * updated adr to accepted * renamed openai base config * renamed openai config to mixin * added renames in user docs * reverted mcperror * fix tests * remove sse from tests
This commit is contained in:
committed by
GitHub
Unverified
parent
6310ca5be0
commit
40ab6e9d67
@@ -7,14 +7,14 @@ from datetime import datetime
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, TypedDict, cast
|
||||
|
||||
from agent_framework import (
|
||||
AgentBase,
|
||||
AgentRunResponse,
|
||||
AgentRunResponseUpdate,
|
||||
AgentThread,
|
||||
BaseAgent,
|
||||
ChatMessage,
|
||||
ChatRole,
|
||||
FunctionCallContent,
|
||||
FunctionResultContent,
|
||||
Role,
|
||||
TextContent,
|
||||
UsageDetails,
|
||||
)
|
||||
@@ -34,8 +34,8 @@ if TYPE_CHECKING:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WorkflowAgent(AgentBase):
|
||||
"""An `AIAgent` subclass that wraps a workflow and exposes it as an agent."""
|
||||
class WorkflowAgent(BaseAgent):
|
||||
"""An `Agent` subclass that wraps a workflow and exposes it as an agent."""
|
||||
|
||||
# Class variable for the request info function name
|
||||
REQUEST_INFO_FUNCTION_NAME: ClassVar[str] = "request_info"
|
||||
@@ -65,11 +65,11 @@ class WorkflowAgent(AgentBase):
|
||||
id: Unique identifier for the agent. If None, will be generated.
|
||||
name: Optional name for the agent.
|
||||
description: Optional description of the agent.
|
||||
**kwargs: Additional keyword arguments passed to AgentBase.
|
||||
**kwargs: Additional keyword arguments passed to BaseAgent.
|
||||
"""
|
||||
if id is None:
|
||||
id = f"WorkflowAgent_{uuid.uuid4().hex[:8]}"
|
||||
# Initialize with standard AgentBase parameters first
|
||||
# Initialize with standard BaseAgent parameters first
|
||||
kwargs["workflow"] = workflow
|
||||
|
||||
# Validate the workflow's start executor can handle agent-facing message inputs
|
||||
@@ -107,7 +107,7 @@ class WorkflowAgent(AgentBase):
|
||||
thread = thread or self.get_new_thread()
|
||||
response_id = str(uuid.uuid4())
|
||||
|
||||
async for update in self._run_streaming_impl(input_messages, response_id):
|
||||
async for update in self._run_stream_impl(input_messages, response_id):
|
||||
response_updates.append(update)
|
||||
|
||||
# Convert updates to final response.
|
||||
@@ -119,7 +119,7 @@ class WorkflowAgent(AgentBase):
|
||||
|
||||
return response
|
||||
|
||||
async def run_streaming(
|
||||
async def run_stream(
|
||||
self,
|
||||
messages: str | ChatMessage | list[str] | list[ChatMessage] | None = None,
|
||||
*,
|
||||
@@ -141,7 +141,7 @@ class WorkflowAgent(AgentBase):
|
||||
response_updates: list[AgentRunResponseUpdate] = []
|
||||
response_id = str(uuid.uuid4())
|
||||
|
||||
async for update in self._run_streaming_impl(input_messages, response_id):
|
||||
async for update in self._run_stream_impl(input_messages, response_id):
|
||||
response_updates.append(update)
|
||||
yield update
|
||||
|
||||
@@ -152,7 +152,7 @@ class WorkflowAgent(AgentBase):
|
||||
await self._notify_thread_of_new_messages(thread, input_messages)
|
||||
await self._notify_thread_of_new_messages(thread, response.messages)
|
||||
|
||||
async def _run_streaming_impl(
|
||||
async def _run_stream_impl(
|
||||
self,
|
||||
input_messages: list[ChatMessage],
|
||||
response_id: str,
|
||||
@@ -188,7 +188,7 @@ class WorkflowAgent(AgentBase):
|
||||
else:
|
||||
# Execute workflow with streaming (initial run or no function responses)
|
||||
# Pass the new input messages directly to the workflow
|
||||
event_stream = self.workflow.run_streaming(input_messages)
|
||||
event_stream = self.workflow.run_stream(input_messages)
|
||||
|
||||
# Process events from the stream
|
||||
async for event in event_stream:
|
||||
@@ -206,7 +206,7 @@ class WorkflowAgent(AgentBase):
|
||||
return []
|
||||
|
||||
if isinstance(messages, str):
|
||||
return [ChatMessage(role=ChatRole.USER, contents=[TextContent(text=messages)])]
|
||||
return [ChatMessage(role=Role.USER, contents=[TextContent(text=messages)])]
|
||||
|
||||
if isinstance(messages, ChatMessage):
|
||||
return [messages]
|
||||
@@ -214,7 +214,7 @@ class WorkflowAgent(AgentBase):
|
||||
normalized = []
|
||||
for msg in messages:
|
||||
if isinstance(msg, str):
|
||||
normalized.append(ChatMessage(role=ChatRole.USER, contents=[TextContent(text=msg)]))
|
||||
normalized.append(ChatMessage(role=Role.USER, contents=[TextContent(text=msg)]))
|
||||
elif isinstance(msg, ChatMessage):
|
||||
normalized.append(msg)
|
||||
return normalized
|
||||
@@ -250,7 +250,7 @@ class WorkflowAgent(AgentBase):
|
||||
)
|
||||
return AgentRunResponseUpdate(
|
||||
contents=[function_call],
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
author_name=self.name,
|
||||
response_id=response_id,
|
||||
message_id=str(uuid.uuid4()),
|
||||
|
||||
@@ -12,7 +12,7 @@ from typing import TYPE_CHECKING, Any, Generic, TypeVar, Union, get_args, get_or
|
||||
if TYPE_CHECKING:
|
||||
from ._workflow import Workflow
|
||||
|
||||
from agent_framework import AgentRunResponse, AgentRunResponseUpdate, AgentThread, AIAgent, ChatMessage
|
||||
from agent_framework import AgentProtocol, AgentRunResponse, AgentRunResponseUpdate, AgentThread, ChatMessage
|
||||
from agent_framework._pydantic import AFBaseModel
|
||||
from pydantic import Field
|
||||
|
||||
@@ -789,7 +789,7 @@ class AgentExecutor(Executor):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
agent: AIAgent,
|
||||
agent: AgentProtocol,
|
||||
*,
|
||||
agent_thread: AgentThread | None = None,
|
||||
streaming: bool = False,
|
||||
@@ -818,7 +818,7 @@ class AgentExecutor(Executor):
|
||||
if request.should_respond:
|
||||
if self._streaming:
|
||||
updates: list[AgentRunResponseUpdate] = []
|
||||
async for update in self._agent.run_streaming(
|
||||
async for update in self._agent.run_stream(
|
||||
self._cache,
|
||||
thread=self._agent_thread,
|
||||
):
|
||||
@@ -894,7 +894,7 @@ class WorkflowExecutor(Executor):
|
||||
|
||||
try:
|
||||
# Run the sub-workflow and collect all events
|
||||
events = [event async for event in self.workflow.run_streaming(input_data)]
|
||||
events = [event async for event in self.workflow.run_stream(input_data)]
|
||||
|
||||
# Count requests and initialize response tracking
|
||||
request_count = 0
|
||||
|
||||
@@ -14,16 +14,16 @@ from typing import Annotated, Any, Literal, Protocol, TypeVar, Union, cast
|
||||
from uuid import uuid4
|
||||
|
||||
from agent_framework import (
|
||||
AgentProtocol,
|
||||
AgentRunResponse,
|
||||
AgentRunResponseUpdate,
|
||||
AIAgent,
|
||||
ChatClient,
|
||||
ChatClientProtocol,
|
||||
ChatMessage,
|
||||
ChatRole,
|
||||
FunctionCallContent,
|
||||
FunctionResultContent,
|
||||
Role,
|
||||
)
|
||||
from agent_framework._agents import AgentBase
|
||||
from agent_framework._agents import BaseAgent
|
||||
from agent_framework._pydantic import AFBaseModel
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
@@ -83,7 +83,7 @@ class MagenticAgentDeltaEvent:
|
||||
function_call_arguments: Any | None = None
|
||||
function_result_id: str | None = None
|
||||
function_result: Any | None = None
|
||||
role: ChatRole | None = None
|
||||
role: Role | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -289,7 +289,7 @@ class MagenticStartMessage:
|
||||
Returns:
|
||||
A MagenticStartMessage with the string converted to a ChatMessage.
|
||||
"""
|
||||
return cls(task=ChatMessage(role=ChatRole.USER, text=task_text))
|
||||
return cls(task=ChatMessage(role=Role.USER, text=task_text))
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -401,7 +401,7 @@ def _team_block(participants: dict[str, str]) -> str:
|
||||
|
||||
def _first_assistant(messages: list[ChatMessage]) -> ChatMessage | None:
|
||||
for msg in reversed(messages):
|
||||
if msg.role == ChatRole.ASSISTANT:
|
||||
if msg.role == Role.ASSISTANT:
|
||||
return msg
|
||||
return None
|
||||
|
||||
@@ -409,7 +409,7 @@ def _first_assistant(messages: list[ChatMessage]) -> ChatMessage | None:
|
||||
def _extract_json(text: str) -> dict[str, Any]:
|
||||
"""Potentially temp helper method.
|
||||
|
||||
Note: this method is required right now because the ChatClient, when calling
|
||||
Note: this method is required right now because the ChatClientProtocol, when calling
|
||||
response.text, returns duplicate JSON payloads - need to figure out why.
|
||||
|
||||
The `text` method is concatenating multiple text contents from diff msgs into a single string.
|
||||
@@ -497,7 +497,7 @@ class MagenticManagerBase(AFBaseModel, ABC):
|
||||
|
||||
|
||||
class StandardMagenticManager(MagenticManagerBase):
|
||||
"""Standard Magentic manager that performs real LLM calls via a ChatClientAgent.
|
||||
"""Standard Magentic manager that performs real LLM calls via a ChatAgent.
|
||||
|
||||
The manager constructs prompts that mirror the original Magentic One orchestration:
|
||||
- Facts gathering
|
||||
@@ -509,7 +509,7 @@ class StandardMagenticManager(MagenticManagerBase):
|
||||
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
|
||||
chat_client: ChatClient
|
||||
chat_client: ChatClientProtocol
|
||||
task_ledger: MagenticTaskLedger | None = None
|
||||
instructions: str | None = None
|
||||
|
||||
@@ -526,7 +526,7 @@ class StandardMagenticManager(MagenticManagerBase):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
chat_client: ChatClient,
|
||||
chat_client: ChatClientProtocol,
|
||||
task_ledger: MagenticTaskLedger | None = None,
|
||||
*,
|
||||
instructions: str | None = None,
|
||||
@@ -597,7 +597,7 @@ class StandardMagenticManager(MagenticManagerBase):
|
||||
*,
|
||||
response_format: type[BaseModel] | None = None,
|
||||
) -> ChatMessage:
|
||||
"""Call the underlying ChatClient directly and return the last assistant message.
|
||||
"""Call the underlying ChatClientProtocol directly and return the last assistant message.
|
||||
|
||||
If manager instructions are provided, they are injected as a SYSTEM message
|
||||
at the start of the request to guide the model consistently without needing
|
||||
@@ -606,7 +606,7 @@ class StandardMagenticManager(MagenticManagerBase):
|
||||
# Prepend system instructions if present
|
||||
request_messages: list[ChatMessage] = []
|
||||
if self.instructions:
|
||||
request_messages.append(ChatMessage(role=ChatRole.SYSTEM, text=self.instructions))
|
||||
request_messages.append(ChatMessage(role=Role.SYSTEM, text=self.instructions))
|
||||
request_messages.extend(messages)
|
||||
|
||||
# Invoke the chat client non-streaming API
|
||||
@@ -619,13 +619,13 @@ class StandardMagenticManager(MagenticManagerBase):
|
||||
if out_messages:
|
||||
last = out_messages[-1]
|
||||
return ChatMessage(
|
||||
role=last.role or ChatRole.ASSISTANT,
|
||||
role=last.role or Role.ASSISTANT,
|
||||
text=last.text or "",
|
||||
author_name=last.author_name or MAGENTIC_MANAGER_NAME,
|
||||
)
|
||||
|
||||
# Fallback if no messages
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text="No output produced.", author_name=MAGENTIC_MANAGER_NAME)
|
||||
return ChatMessage(role=Role.ASSISTANT, text="No output produced.", author_name=MAGENTIC_MANAGER_NAME)
|
||||
|
||||
async def plan(self, magentic_context: MagenticContext) -> ChatMessage:
|
||||
"""Create facts and plan using the model, then render a combined task ledger as a single assistant message."""
|
||||
@@ -634,14 +634,14 @@ class StandardMagenticManager(MagenticManagerBase):
|
||||
|
||||
# Gather facts
|
||||
facts_user = ChatMessage(
|
||||
role=ChatRole.USER,
|
||||
role=Role.USER,
|
||||
text=self.task_ledger_facts_prompt.format(task=task_text),
|
||||
)
|
||||
facts_msg = await self._complete([*magentic_context.chat_history, facts_user])
|
||||
|
||||
# Create plan
|
||||
plan_user = ChatMessage(
|
||||
role=ChatRole.USER,
|
||||
role=Role.USER,
|
||||
text=self.task_ledger_plan_prompt.format(team=team_text),
|
||||
)
|
||||
plan_msg = await self._complete([*magentic_context.chat_history, facts_user, facts_msg, plan_user])
|
||||
@@ -659,7 +659,7 @@ class StandardMagenticManager(MagenticManagerBase):
|
||||
facts=facts_msg.text,
|
||||
plan=plan_msg.text,
|
||||
)
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text=combined, author_name=MAGENTIC_MANAGER_NAME)
|
||||
return ChatMessage(role=Role.ASSISTANT, text=combined, author_name=MAGENTIC_MANAGER_NAME)
|
||||
|
||||
async def replan(self, magentic_context: MagenticContext) -> ChatMessage:
|
||||
"""Update facts and plan when stalling or looping has been detected."""
|
||||
@@ -671,14 +671,14 @@ class StandardMagenticManager(MagenticManagerBase):
|
||||
|
||||
# Update facts
|
||||
facts_update_user = ChatMessage(
|
||||
role=ChatRole.USER,
|
||||
role=Role.USER,
|
||||
text=self.task_ledger_facts_update_prompt.format(task=task_text, old_facts=self.task_ledger.facts.text),
|
||||
)
|
||||
updated_facts = await self._complete([*magentic_context.chat_history, facts_update_user])
|
||||
|
||||
# Update plan
|
||||
plan_update_user = ChatMessage(
|
||||
role=ChatRole.USER,
|
||||
role=Role.USER,
|
||||
text=self.task_ledger_plan_update_prompt.format(team=team_text),
|
||||
)
|
||||
updated_plan = await self._complete([
|
||||
@@ -701,7 +701,7 @@ class StandardMagenticManager(MagenticManagerBase):
|
||||
facts=updated_facts.text,
|
||||
plan=updated_plan.text,
|
||||
)
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text=combined, author_name=MAGENTIC_MANAGER_NAME)
|
||||
return ChatMessage(role=Role.ASSISTANT, text=combined, author_name=MAGENTIC_MANAGER_NAME)
|
||||
|
||||
async def create_progress_ledger(self, magentic_context: MagenticContext) -> MagenticProgressLedger:
|
||||
"""Use the model to produce a JSON progress ledger based on the conversation so far.
|
||||
@@ -721,7 +721,7 @@ class StandardMagenticManager(MagenticManagerBase):
|
||||
team=team_text,
|
||||
names=names_csv,
|
||||
)
|
||||
user_message = ChatMessage(role=ChatRole.USER, text=prompt)
|
||||
user_message = ChatMessage(role=Role.USER, text=prompt)
|
||||
|
||||
# Include full context to help the model decide current stage, with small retry loop
|
||||
attempts = 0
|
||||
@@ -751,11 +751,11 @@ class StandardMagenticManager(MagenticManagerBase):
|
||||
async def prepare_final_answer(self, magentic_context: MagenticContext) -> ChatMessage:
|
||||
"""Ask the model to produce the final answer addressed to the user."""
|
||||
prompt = self.final_answer_prompt.format(task=magentic_context.task.text)
|
||||
user_message = ChatMessage(role=ChatRole.USER, text=prompt)
|
||||
user_message = ChatMessage(role=Role.USER, text=prompt)
|
||||
response = await self._complete([*magentic_context.chat_history, user_message])
|
||||
# Ensure role is assistant
|
||||
return ChatMessage(
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
text=response.text,
|
||||
author_name=response.author_name or MAGENTIC_MANAGER_NAME,
|
||||
)
|
||||
@@ -896,9 +896,9 @@ class MagenticOrchestratorExecutor(Executor):
|
||||
logger.debug("Magentic Orchestrator: Received response from agent")
|
||||
|
||||
# Add transfer message if needed
|
||||
if message.body.role != ChatRole.USER:
|
||||
if message.body.role != Role.USER:
|
||||
transfer_msg = ChatMessage(
|
||||
role=ChatRole.USER,
|
||||
role=Role.USER,
|
||||
text=f"Transferred to {getattr(message.body, 'author_name', 'agent')}",
|
||||
)
|
||||
self._context.chat_history.append(transfer_msg)
|
||||
@@ -945,7 +945,7 @@ class MagenticOrchestratorExecutor(Executor):
|
||||
plan=human.edited_plan_text,
|
||||
)
|
||||
self._task_ledger = ChatMessage(
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
text=combined,
|
||||
author_name=MAGENTIC_MANAGER_NAME,
|
||||
)
|
||||
@@ -953,7 +953,7 @@ class MagenticOrchestratorExecutor(Executor):
|
||||
elif human.comments:
|
||||
# Record the human feedback for grounding
|
||||
self._context.chat_history.append(
|
||||
ChatMessage(role=ChatRole.USER, text=f"Human plan feedback: {human.comments}")
|
||||
ChatMessage(role=Role.USER, text=f"Human plan feedback: {human.comments}")
|
||||
)
|
||||
# Ask the manager to replan based on comments; proceed immediately
|
||||
self._task_ledger = await self._manager.replan(self._context.model_copy(deep=True))
|
||||
@@ -981,7 +981,7 @@ class MagenticOrchestratorExecutor(Executor):
|
||||
self._require_plan_signoff = False
|
||||
# Add a clear note to the conversation so users know review is closed
|
||||
notice = ChatMessage(
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
text=(
|
||||
"Plan review closed after max rounds. Proceeding with the current plan and will no longer "
|
||||
"prompt for plan approval."
|
||||
@@ -1015,14 +1015,14 @@ class MagenticOrchestratorExecutor(Executor):
|
||||
facts=(mgr_ledger2.facts.text if mgr_ledger2 else ""),
|
||||
plan=human.edited_plan_text,
|
||||
)
|
||||
self._task_ledger = ChatMessage(role=ChatRole.ASSISTANT, text=combined, author_name=MAGENTIC_MANAGER_NAME)
|
||||
self._task_ledger = ChatMessage(role=Role.ASSISTANT, text=combined, author_name=MAGENTIC_MANAGER_NAME)
|
||||
await self._send_plan_review_request(context)
|
||||
return
|
||||
|
||||
# Else pass comments into the chat history and replan with the manager
|
||||
if human.comments:
|
||||
self._context.chat_history.append(
|
||||
ChatMessage(role=ChatRole.USER, text=f"Human plan feedback: {human.comments}")
|
||||
ChatMessage(role=Role.USER, text=f"Human plan feedback: {human.comments}")
|
||||
)
|
||||
|
||||
# Ask the manager to replan; this only adjusts the plan stage, not a full reset
|
||||
@@ -1127,7 +1127,7 @@ class MagenticOrchestratorExecutor(Executor):
|
||||
|
||||
# Add instruction to conversation (assistant guidance)
|
||||
instruction_msg = ChatMessage(
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
text=str(instruction),
|
||||
author_name=MAGENTIC_MANAGER_NAME,
|
||||
)
|
||||
@@ -1215,7 +1215,7 @@ class MagenticOrchestratorExecutor(Executor):
|
||||
partial_result = _first_assistant(ctx.chat_history)
|
||||
if partial_result is None:
|
||||
partial_result = ChatMessage(
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
text=f"Stopped due to {limit_type} limit. No partial result available.",
|
||||
author_name=MAGENTIC_MANAGER_NAME,
|
||||
)
|
||||
@@ -1262,7 +1262,7 @@ class MagenticAgentExecutor(Executor):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
agent: AIAgent | Executor,
|
||||
agent: AgentProtocol | Executor,
|
||||
agent_id: str,
|
||||
agent_response_callback: Callable[[str, ChatMessage], Awaitable[None]] | None = None,
|
||||
streaming_agent_response_callback: Callable[[str, AgentRunResponseUpdate, bool], Awaitable[None]] | None = None,
|
||||
@@ -1288,9 +1288,9 @@ class MagenticAgentExecutor(Executor):
|
||||
return
|
||||
|
||||
# Add transfer message if needed
|
||||
if message.body.role != ChatRole.USER:
|
||||
if message.body.role != Role.USER:
|
||||
transfer_msg = ChatMessage(
|
||||
role=ChatRole.USER,
|
||||
role=Role.USER,
|
||||
text=f"Transferred to {getattr(message.body, 'author_name', 'agent')}",
|
||||
)
|
||||
self._chat_history.append(transfer_msg)
|
||||
@@ -1298,18 +1298,18 @@ class MagenticAgentExecutor(Executor):
|
||||
# Add message to agent's history
|
||||
self._chat_history.append(message.body)
|
||||
|
||||
def _get_persona_adoption_role(self) -> ChatRole:
|
||||
def _get_persona_adoption_role(self) -> Role:
|
||||
"""Determine the best role for persona adoption messages.
|
||||
|
||||
Uses SYSTEM role if the agent supports it, otherwise falls back to USER.
|
||||
"""
|
||||
# Only AgentBase-derived agents are assumed to support SYSTEM messages reliably.
|
||||
from agent_framework import AgentBase as _AF_AgentBase # local import to avoid cycles
|
||||
# Only BaseAgent-derived agents are assumed to support SYSTEM messages reliably.
|
||||
from agent_framework import BaseAgent as _AF_AgentBase # local import to avoid cycles
|
||||
|
||||
if isinstance(self._agent, _AF_AgentBase) and hasattr(self._agent, "chat_client"):
|
||||
return ChatRole.SYSTEM
|
||||
return Role.SYSTEM
|
||||
# For other agent types or when we can't determine support, use USER
|
||||
return ChatRole.USER
|
||||
return Role.USER
|
||||
|
||||
@handler
|
||||
async def handle_request_message(
|
||||
@@ -1331,14 +1331,14 @@ class MagenticAgentExecutor(Executor):
|
||||
|
||||
# Add the orchestrator's instruction as a USER message so the agent treats it as the prompt
|
||||
if message.instruction:
|
||||
self._chat_history.append(ChatMessage(role=ChatRole.USER, text=message.instruction))
|
||||
self._chat_history.append(ChatMessage(role=Role.USER, text=message.instruction))
|
||||
try:
|
||||
# If the participant is not an invokable AgentBase, return a no-op response.
|
||||
from agent_framework import AgentBase as _AF_AgentBase # local import to avoid cycles
|
||||
# If the participant is not an invokable BaseAgent, return a no-op response.
|
||||
from agent_framework import BaseAgent as _AF_AgentBase # local import to avoid cycles
|
||||
|
||||
if not isinstance(self._agent, _AF_AgentBase):
|
||||
response = ChatMessage(
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
text=f"{self._agent_id} is a workflow executor and cannot be invoked directly.",
|
||||
author_name=self._agent_id,
|
||||
)
|
||||
@@ -1354,7 +1354,7 @@ class MagenticAgentExecutor(Executor):
|
||||
logger.warning("Agent %s invoke failed: %s", self._agent_id, e)
|
||||
# Fallback response
|
||||
response = ChatMessage(
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
text=f"Agent {self._agent_id}: Error processing request - {str(e)[:100]}",
|
||||
)
|
||||
self._chat_history.append(response)
|
||||
@@ -1370,9 +1370,9 @@ class MagenticAgentExecutor(Executor):
|
||||
logger.debug(f"Agent {self._agent_id}: Running with {len(self._chat_history)} messages")
|
||||
|
||||
updates: list[AgentRunResponseUpdate] = []
|
||||
# The wrapped participant is guaranteed to be an AgentBase when this is called.
|
||||
agent = cast("AIAgent", self._agent)
|
||||
async for update in agent.run_streaming(messages=self._chat_history): # type: ignore[attr-defined]
|
||||
# The wrapped participant is guaranteed to be an BaseAgent when this is called.
|
||||
agent = cast("AgentProtocol", self._agent)
|
||||
async for update in agent.run_stream(messages=self._chat_history): # type: ignore[attr-defined]
|
||||
updates.append(update)
|
||||
if self._streaming_agent_response_callback is not None:
|
||||
with contextlib.suppress(Exception):
|
||||
@@ -1394,7 +1394,7 @@ class MagenticAgentExecutor(Executor):
|
||||
if messages and len(messages) > 0:
|
||||
last: ChatMessage = messages[-1]
|
||||
author = last.author_name or self._agent_id
|
||||
role: ChatRole = last.role if last.role else ChatRole.ASSISTANT
|
||||
role: Role = last.role if last.role else Role.ASSISTANT
|
||||
text = last.text or str(last)
|
||||
msg = ChatMessage(role=role, text=text, author_name=author)
|
||||
if self._agent_response_callback is not None:
|
||||
@@ -1403,7 +1403,7 @@ class MagenticAgentExecutor(Executor):
|
||||
return msg
|
||||
|
||||
msg = ChatMessage(
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
text=f"Agent {self._agent_id}: No output produced",
|
||||
author_name=self._agent_id,
|
||||
)
|
||||
@@ -1422,7 +1422,7 @@ class MagenticBuilder:
|
||||
"""High-level builder for creating Magentic One workflows."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._participants: dict[str, AIAgent | Executor] = {}
|
||||
self._participants: dict[str, AgentProtocol | Executor] = {}
|
||||
self._manager: MagenticManagerBase | None = None
|
||||
self._exception_callback: Callable[[Exception], None] | None = None
|
||||
self._result_callback: Callable[[ChatMessage], Awaitable[None]] | None = None
|
||||
@@ -1435,7 +1435,7 @@ class MagenticBuilder:
|
||||
self._unified_callback: CallbackSink | None = None
|
||||
self._callback_mode: MagenticCallbackMode | None = None
|
||||
|
||||
def participants(self, **participants: AIAgent | Executor) -> Self:
|
||||
def participants(self, **participants: AgentProtocol | Executor) -> Self:
|
||||
"""Add participants (agents) to the workflow."""
|
||||
self._participants.update(participants)
|
||||
return self
|
||||
@@ -1450,7 +1450,7 @@ class MagenticBuilder:
|
||||
manager: MagenticManagerBase | None = None,
|
||||
*,
|
||||
# Constructor args for StandardMagenticManager when manager is not provided
|
||||
chat_client: ChatClient | None = None,
|
||||
chat_client: ChatClientProtocol | None = None,
|
||||
task_ledger: MagenticTaskLedger | None = None,
|
||||
instructions: str | None = None,
|
||||
# Prompt overrides
|
||||
@@ -1540,7 +1540,7 @@ class MagenticBuilder:
|
||||
# Create participant descriptions
|
||||
participant_descriptions: dict[str, str] = {}
|
||||
for name, participant in self._participants.items():
|
||||
if isinstance(participant, AgentBase):
|
||||
if isinstance(participant, BaseAgent):
|
||||
description = getattr(participant, "description", None) or f"Agent {name}"
|
||||
else:
|
||||
description = f"Executor {name}"
|
||||
@@ -1745,7 +1745,7 @@ class MagenticWorkflow:
|
||||
WorkflowEvent: The events generated during the workflow execution.
|
||||
"""
|
||||
start_message = MagenticStartMessage.from_string(task_text)
|
||||
async for event in self._workflow.run_streaming(start_message):
|
||||
async for event in self._workflow.run_stream(start_message):
|
||||
yield event
|
||||
|
||||
async def run_streaming_with_message(self, task_message: ChatMessage) -> AsyncIterable[WorkflowEvent]:
|
||||
@@ -1758,10 +1758,10 @@ class MagenticWorkflow:
|
||||
WorkflowEvent: The events generated during the workflow execution.
|
||||
"""
|
||||
start_message = MagenticStartMessage(task=task_message)
|
||||
async for event in self._workflow.run_streaming(start_message):
|
||||
async for event in self._workflow.run_stream(start_message):
|
||||
yield event
|
||||
|
||||
async def run_streaming(self, message: Any | None = None) -> AsyncIterable[WorkflowEvent]:
|
||||
async def run_stream(self, message: Any | None = None) -> AsyncIterable[WorkflowEvent]:
|
||||
"""Run the workflow with either a message object or the preset task string.
|
||||
|
||||
Args:
|
||||
@@ -1780,7 +1780,7 @@ class MagenticWorkflow:
|
||||
elif isinstance(message, ChatMessage):
|
||||
message = MagenticStartMessage(task=message)
|
||||
|
||||
async for event in self._workflow.run_streaming(message):
|
||||
async for event in self._workflow.run_stream(message):
|
||||
yield event
|
||||
|
||||
async def run_with_string(self, task_text: str) -> WorkflowRunResult:
|
||||
@@ -1822,7 +1822,7 @@ class MagenticWorkflow:
|
||||
WorkflowRunResult: All events generated during the workflow execution.
|
||||
"""
|
||||
events: list[WorkflowEvent] = []
|
||||
async for event in self.run_streaming(message):
|
||||
async for event in self.run_stream(message):
|
||||
events.append(event)
|
||||
return WorkflowRunResult(events)
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ class Workflow(AFBaseModel):
|
||||
workflow_tracer.add_workflow_error_event(e)
|
||||
raise
|
||||
|
||||
async def run_streaming(self, message: Any) -> AsyncIterable[WorkflowEvent]:
|
||||
async def run_stream(self, message: Any) -> AsyncIterable[WorkflowEvent]:
|
||||
"""Run the workflow with a starting message and stream events.
|
||||
|
||||
Args:
|
||||
@@ -252,7 +252,7 @@ class Workflow(AFBaseModel):
|
||||
async for event in self._run_workflow_with_tracing(initial_executor_fn=initial_execution, reset_context=True):
|
||||
yield event
|
||||
|
||||
async def run_streaming_from_checkpoint(
|
||||
async def run_stream_from_checkpoint(
|
||||
self,
|
||||
checkpoint_id: str,
|
||||
checkpoint_storage: CheckpointStorage | None = None,
|
||||
@@ -368,7 +368,7 @@ class Workflow(AFBaseModel):
|
||||
Returns:
|
||||
A WorkflowRunResult instance containing a list of events generated during the workflow execution.
|
||||
"""
|
||||
events = [event async for event in self.run_streaming(message)]
|
||||
events = [event async for event in self.run_stream(message)]
|
||||
return WorkflowRunResult(events)
|
||||
|
||||
async def run_from_checkpoint(
|
||||
@@ -394,7 +394,7 @@ class Workflow(AFBaseModel):
|
||||
RuntimeError: If checkpoint restoration fails.
|
||||
"""
|
||||
events = [
|
||||
event async for event in self.run_streaming_from_checkpoint(checkpoint_id, checkpoint_storage, responses)
|
||||
event async for event in self.run_stream_from_checkpoint(checkpoint_id, checkpoint_storage, responses)
|
||||
]
|
||||
return WorkflowRunResult(events)
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ from agent_framework import (
|
||||
ChatMessage,
|
||||
ChatResponse,
|
||||
ChatResponseUpdate,
|
||||
ChatRole,
|
||||
Role,
|
||||
TextContent,
|
||||
)
|
||||
from agent_framework._agents import AgentBase
|
||||
from agent_framework._clients import ChatClient as AFChatClient
|
||||
from agent_framework._agents import BaseAgent
|
||||
from agent_framework._clients import ChatClientProtocol as AFChatClient
|
||||
|
||||
from agent_framework_workflow import (
|
||||
Executor,
|
||||
@@ -42,7 +42,7 @@ def test_magentic_start_message_from_string():
|
||||
msg = MagenticStartMessage.from_string("Do the thing")
|
||||
assert isinstance(msg, MagenticStartMessage)
|
||||
assert isinstance(msg.task, ChatMessage)
|
||||
assert msg.task.role == ChatRole.USER
|
||||
assert msg.task.role == Role.USER
|
||||
assert msg.task.text == "Do the thing"
|
||||
|
||||
|
||||
@@ -67,11 +67,11 @@ def test_plan_review_request_defaults_and_reply_variants():
|
||||
|
||||
def test_magentic_context_reset_behavior():
|
||||
ctx = MagenticContext(
|
||||
task=ChatMessage(role=ChatRole.USER, text="task"),
|
||||
task=ChatMessage(role=Role.USER, text="task"),
|
||||
participant_descriptions={"Alice": "Researcher"},
|
||||
)
|
||||
# seed context state
|
||||
ctx.chat_history.append(ChatMessage(role=ChatRole.ASSISTANT, text="draft"))
|
||||
ctx.chat_history.append(ChatMessage(role=Role.ASSISTANT, text="draft"))
|
||||
ctx.stall_count = 2
|
||||
prev_reset = ctx.reset_count
|
||||
|
||||
@@ -97,18 +97,18 @@ class FakeManager(MagenticManagerBase):
|
||||
instruction_text: str = "Proceed with step 1"
|
||||
|
||||
async def plan(self, magentic_context: MagenticContext) -> ChatMessage:
|
||||
facts = ChatMessage(role=ChatRole.ASSISTANT, text="GIVEN OR VERIFIED FACTS\n- A\n")
|
||||
plan = ChatMessage(role=ChatRole.ASSISTANT, text="- Do X\n- Do Y\n")
|
||||
facts = ChatMessage(role=Role.ASSISTANT, text="GIVEN OR VERIFIED FACTS\n- A\n")
|
||||
plan = ChatMessage(role=Role.ASSISTANT, text="- Do X\n- Do Y\n")
|
||||
self.task_ledger = _SimpleLedger(facts=facts, plan=plan)
|
||||
combined = f"Task: {magentic_context.task.text}\n\nFacts:\n{facts.text}\n\nPlan:\n{plan.text}"
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text=combined, author_name="magentic_manager")
|
||||
return ChatMessage(role=Role.ASSISTANT, text=combined, author_name="magentic_manager")
|
||||
|
||||
async def replan(self, magentic_context: MagenticContext) -> ChatMessage:
|
||||
facts = ChatMessage(role=ChatRole.ASSISTANT, text="GIVEN OR VERIFIED FACTS\n- A2\n")
|
||||
plan = ChatMessage(role=ChatRole.ASSISTANT, text="- Do Z\n")
|
||||
facts = ChatMessage(role=Role.ASSISTANT, text="GIVEN OR VERIFIED FACTS\n- A2\n")
|
||||
plan = ChatMessage(role=Role.ASSISTANT, text="- Do Z\n")
|
||||
self.task_ledger = _SimpleLedger(facts=facts, plan=plan)
|
||||
combined = f"Task: {magentic_context.task.text}\n\nFacts:\n{facts.text}\n\nPlan:\n{plan.text}"
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text=combined, author_name="magentic_manager")
|
||||
return ChatMessage(role=Role.ASSISTANT, text=combined, author_name="magentic_manager")
|
||||
|
||||
async def create_progress_ledger(self, magentic_context: MagenticContext) -> MagenticProgressLedger:
|
||||
is_satisfied = self.satisfied_after_signoff and len(magentic_context.chat_history) > 0
|
||||
@@ -121,18 +121,18 @@ class FakeManager(MagenticManagerBase):
|
||||
)
|
||||
|
||||
async def prepare_final_answer(self, magentic_context: MagenticContext) -> ChatMessage:
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text="FINAL", author_name="magentic_manager")
|
||||
return ChatMessage(role=Role.ASSISTANT, text="FINAL", author_name="magentic_manager")
|
||||
|
||||
|
||||
async def test_standard_manager_plan_and_replan_combined_ledger():
|
||||
manager = FakeManager(max_round_count=10, max_stall_count=3, max_reset_count=2)
|
||||
ctx = MagenticContext(
|
||||
task=ChatMessage(role=ChatRole.USER, text="demo task"),
|
||||
task=ChatMessage(role=Role.USER, text="demo task"),
|
||||
participant_descriptions={"agentA": "Agent A"},
|
||||
)
|
||||
|
||||
first = await manager.plan(ctx.model_copy(deep=True))
|
||||
assert first.role == ChatRole.ASSISTANT and "Facts:" in first.text and "Plan:" in first.text
|
||||
assert first.role == Role.ASSISTANT and "Facts:" in first.text and "Plan:" in first.text
|
||||
assert manager.task_ledger is not None
|
||||
|
||||
replanned = await manager.replan(ctx.model_copy(deep=True))
|
||||
@@ -142,7 +142,7 @@ async def test_standard_manager_plan_and_replan_combined_ledger():
|
||||
async def test_standard_manager_progress_ledger_and_fallback():
|
||||
manager = FakeManager(max_round_count=10)
|
||||
ctx = MagenticContext(
|
||||
task=ChatMessage(role=ChatRole.USER, text="demo"),
|
||||
task=ChatMessage(role=Role.USER, text="demo"),
|
||||
participant_descriptions={"agentA": "Agent A"},
|
||||
)
|
||||
|
||||
@@ -166,7 +166,7 @@ async def test_magentic_workflow_plan_review_approval_to_completion():
|
||||
)
|
||||
|
||||
req_event: RequestInfoEvent | None = None
|
||||
async for ev in wf.run_streaming("do work"):
|
||||
async for ev in wf.run_stream("do work"):
|
||||
if isinstance(ev, RequestInfoEvent) and ev.request_type is MagenticPlanReviewRequest:
|
||||
req_event = ev
|
||||
assert req_event is not None
|
||||
@@ -205,7 +205,7 @@ async def test_magentic_plan_review_approve_with_comments_replans_and_proceeds()
|
||||
|
||||
# Wait for the initial plan review request
|
||||
req_event: RequestInfoEvent | None = None
|
||||
async for ev in wf.run_streaming("do work"):
|
||||
async for ev in wf.run_stream("do work"):
|
||||
if isinstance(ev, RequestInfoEvent) and ev.request_type is MagenticPlanReviewRequest:
|
||||
req_event = ev
|
||||
assert req_event is not None
|
||||
@@ -242,7 +242,7 @@ async def test_magentic_orchestrator_round_limit_produces_partial_result():
|
||||
from agent_framework_workflow import WorkflowEvent # type: ignore
|
||||
|
||||
events: list[WorkflowEvent] = []
|
||||
async for ev in wf.run_streaming("round limit test"):
|
||||
async for ev in wf.run_stream("round limit test"):
|
||||
events.append(ev)
|
||||
if len(events) > 50:
|
||||
break
|
||||
@@ -251,7 +251,7 @@ async def test_magentic_orchestrator_round_limit_produces_partial_result():
|
||||
assert completed is not None
|
||||
data = getattr(completed, "data", None)
|
||||
assert isinstance(data, ChatMessage)
|
||||
assert data.role == ChatRole.ASSISTANT
|
||||
assert data.role == Role.ASSISTANT
|
||||
|
||||
|
||||
class _DummyExec(Executor):
|
||||
@@ -268,7 +268,7 @@ from agent_framework_workflow import StandardMagenticManager # noqa: E402
|
||||
|
||||
class _StubChatClient(AFChatClient):
|
||||
async def get_response(self, messages, **kwargs): # type: ignore[override]
|
||||
return ChatResponse(messages=[ChatMessage(role=ChatRole.ASSISTANT, text="ok")])
|
||||
return ChatResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="ok")])
|
||||
|
||||
def get_streaming_response(self, messages, **kwargs) -> AsyncIterable[ChatResponseUpdate]: # type: ignore[override]
|
||||
async def _gen():
|
||||
@@ -284,14 +284,14 @@ async def test_standard_manager_plan_and_replan_via_complete_monkeypatch():
|
||||
async def fake_complete_plan(messages: list[ChatMessage], **kwargs: Any) -> ChatMessage:
|
||||
# Return a different response depending on call order length
|
||||
if any("FACTS" in (m.text or "") for m in messages):
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text="- step A\n- step B")
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text="GIVEN OR VERIFIED FACTS\n- fact1")
|
||||
return ChatMessage(role=Role.ASSISTANT, text="- step A\n- step B")
|
||||
return ChatMessage(role=Role.ASSISTANT, text="GIVEN OR VERIFIED FACTS\n- fact1")
|
||||
|
||||
# First, patch to produce facts then plan
|
||||
mgr._complete = fake_complete_plan # type: ignore[attr-defined]
|
||||
|
||||
ctx = MagenticContext(
|
||||
task=ChatMessage(role=ChatRole.USER, text="T"),
|
||||
task=ChatMessage(role=Role.USER, text="T"),
|
||||
participant_descriptions={"A": "desc"},
|
||||
)
|
||||
combined = await mgr.plan(ctx.model_copy(deep=True))
|
||||
@@ -303,8 +303,8 @@ async def test_standard_manager_plan_and_replan_via_complete_monkeypatch():
|
||||
# Now replan with new outputs
|
||||
async def fake_complete_replan(messages: list[ChatMessage], **kwargs: Any) -> ChatMessage:
|
||||
if any("Please briefly explain" in (m.text or "") for m in messages):
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text="- new step")
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text="GIVEN OR VERIFIED FACTS\n- updated")
|
||||
return ChatMessage(role=Role.ASSISTANT, text="- new step")
|
||||
return ChatMessage(role=Role.ASSISTANT, text="GIVEN OR VERIFIED FACTS\n- updated")
|
||||
|
||||
mgr._complete = fake_complete_replan # type: ignore[attr-defined]
|
||||
combined2 = await mgr.replan(ctx.model_copy(deep=True))
|
||||
@@ -314,7 +314,7 @@ async def test_standard_manager_plan_and_replan_via_complete_monkeypatch():
|
||||
async def test_standard_manager_progress_ledger_success_and_error():
|
||||
mgr = StandardMagenticManager(chat_client=_StubChatClient())
|
||||
ctx = MagenticContext(
|
||||
task=ChatMessage(role=ChatRole.USER, text="task"),
|
||||
task=ChatMessage(role=Role.USER, text="task"),
|
||||
participant_descriptions={"alice": "desc"},
|
||||
)
|
||||
|
||||
@@ -327,7 +327,7 @@ async def test_standard_manager_progress_ledger_success_and_error():
|
||||
'"next_speaker": {"reason": "r", "answer": "alice"}, '
|
||||
'"instruction_or_question": {"reason": "r", "answer": "do"}}'
|
||||
)
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text=json_text)
|
||||
return ChatMessage(role=Role.ASSISTANT, text=json_text)
|
||||
|
||||
mgr._complete = fake_complete_ok # type: ignore[attr-defined]
|
||||
ledger = await mgr.create_progress_ledger(ctx.model_copy(deep=True))
|
||||
@@ -335,7 +335,7 @@ async def test_standard_manager_progress_ledger_success_and_error():
|
||||
|
||||
# Error path: invalid JSON now raises to avoid emitting planner-oriented instructions to agents
|
||||
async def fake_complete_bad(messages: list[ChatMessage], **kwargs: Any) -> ChatMessage:
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text="not-json")
|
||||
return ChatMessage(role=Role.ASSISTANT, text="not-json")
|
||||
|
||||
mgr._complete = fake_complete_bad # type: ignore[attr-defined]
|
||||
with pytest.raises(RuntimeError):
|
||||
@@ -348,10 +348,10 @@ class InvokeOnceManager(MagenticManagerBase):
|
||||
self._invoked = False
|
||||
|
||||
async def plan(self, magentic_context: MagenticContext) -> ChatMessage:
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text="ledger")
|
||||
return ChatMessage(role=Role.ASSISTANT, text="ledger")
|
||||
|
||||
async def replan(self, magentic_context: MagenticContext) -> ChatMessage:
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text="re-ledger")
|
||||
return ChatMessage(role=Role.ASSISTANT, text="re-ledger")
|
||||
|
||||
async def create_progress_ledger(self, magentic_context: MagenticContext) -> MagenticProgressLedger:
|
||||
if not self._invoked:
|
||||
@@ -374,43 +374,41 @@ class InvokeOnceManager(MagenticManagerBase):
|
||||
)
|
||||
|
||||
async def prepare_final_answer(self, magentic_context: MagenticContext) -> ChatMessage:
|
||||
return ChatMessage(role=ChatRole.ASSISTANT, text="final")
|
||||
return ChatMessage(role=Role.ASSISTANT, text="final")
|
||||
|
||||
|
||||
class StubThreadAgent(AgentBase):
|
||||
async def run_streaming(self, messages=None, *, thread=None, **kwargs): # type: ignore[override]
|
||||
class StubThreadAgent(BaseAgent):
|
||||
async def run_stream(self, messages=None, *, thread=None, **kwargs): # type: ignore[override]
|
||||
yield AgentRunResponseUpdate(
|
||||
contents=[TextContent(text="thread-ok")],
|
||||
author_name="agentA",
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
)
|
||||
|
||||
async def run(self, messages=None, *, thread=None, **kwargs): # type: ignore[override]
|
||||
return AgentRunResponse(messages=[ChatMessage(role=ChatRole.ASSISTANT, text="thread-ok", author_name="agentA")])
|
||||
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="thread-ok", author_name="agentA")])
|
||||
|
||||
|
||||
class StubAssistantsClient:
|
||||
pass # class name used for branch detection
|
||||
|
||||
|
||||
class StubAssistantsAgent(AgentBase):
|
||||
class StubAssistantsAgent(BaseAgent):
|
||||
chat_client: object | None = None # allow assignment via Pydantic field
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.chat_client = StubAssistantsClient() # type name contains 'AssistantsClient'
|
||||
|
||||
async def run_streaming(self, messages=None, *, thread=None, **kwargs): # type: ignore[override]
|
||||
async def run_stream(self, messages=None, *, thread=None, **kwargs): # type: ignore[override]
|
||||
yield AgentRunResponseUpdate(
|
||||
contents=[TextContent(text="assistants-ok")],
|
||||
author_name="agentA",
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
)
|
||||
|
||||
async def run(self, messages=None, *, thread=None, **kwargs): # type: ignore[override]
|
||||
return AgentRunResponse(
|
||||
messages=[ChatMessage(role=ChatRole.ASSISTANT, text="assistants-ok", author_name="agentA")]
|
||||
)
|
||||
return AgentRunResponse(messages=[ChatMessage(role=Role.ASSISTANT, text="assistants-ok", author_name="agentA")])
|
||||
|
||||
|
||||
async def _collect_agent_responses_setup(participant_obj: object):
|
||||
@@ -432,7 +430,7 @@ async def _collect_agent_responses_setup(participant_obj: object):
|
||||
|
||||
# Run a bounded stream to allow one invoke and then completion
|
||||
events: list[WorkflowEvent] = []
|
||||
async for ev in wf.run_streaming("task"): # plan review disabled
|
||||
async for ev in wf.run_stream("task"): # plan review disabled
|
||||
events.append(ev)
|
||||
if len(events) > 50:
|
||||
break
|
||||
|
||||
@@ -343,7 +343,7 @@ async def test_end_to_end_workflow_tracing(tracing_enabled: Any, span_exporter:
|
||||
|
||||
# Run workflow (this should create run spans)
|
||||
events = []
|
||||
async for event in workflow.run_streaming("test input"):
|
||||
async for event in workflow.run_stream("test input"):
|
||||
events.append(event)
|
||||
|
||||
# Verify workflow executed correctly
|
||||
@@ -444,7 +444,7 @@ async def test_workflow_error_handling_in_tracing(tracing_enabled: Any, span_exp
|
||||
|
||||
# Run workflow and expect error
|
||||
with pytest.raises(ValueError, match="Test error"):
|
||||
async for _ in workflow.run_streaming("test input"):
|
||||
async for _ in workflow.run_stream("test input"):
|
||||
pass
|
||||
|
||||
spans = span_exporter.get_finished_spans()
|
||||
|
||||
@@ -95,7 +95,7 @@ async def test_workflow_run_streaming():
|
||||
)
|
||||
|
||||
result: int | None = None
|
||||
async for event in workflow.run_streaming(NumberMessage(data=0)):
|
||||
async for event in workflow.run_stream(NumberMessage(data=0)):
|
||||
assert isinstance(event, WorkflowEvent)
|
||||
if isinstance(event, WorkflowCompletedEvent):
|
||||
result = event.data
|
||||
@@ -118,7 +118,7 @@ async def test_workflow_run_stream_not_completed():
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
async for _ in workflow.run_streaming(NumberMessage(data=0)):
|
||||
async for _ in workflow.run_stream(NumberMessage(data=0)):
|
||||
pass
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ async def test_workflow_send_responses_streaming():
|
||||
)
|
||||
|
||||
request_info_event: RequestInfoEvent | None = None
|
||||
async for event in workflow.run_streaming(NumberMessage(data=0)):
|
||||
async for event in workflow.run_stream(NumberMessage(data=0)):
|
||||
if isinstance(event, RequestInfoEvent):
|
||||
request_info_event = event
|
||||
|
||||
@@ -326,7 +326,7 @@ async def test_workflow_checkpointing_not_enabled_for_external_restore(simple_ex
|
||||
|
||||
# Attempt to restore from checkpoint without providing external storage should fail
|
||||
try:
|
||||
[event async for event in workflow.run_streaming_from_checkpoint("fake-checkpoint-id")]
|
||||
[event async for event in workflow.run_stream_from_checkpoint("fake-checkpoint-id")]
|
||||
raise AssertionError("Expected ValueError to be raised")
|
||||
except ValueError as e:
|
||||
assert "Cannot restore from checkpoint" in str(e)
|
||||
@@ -344,7 +344,7 @@ async def test_workflow_run_stream_from_checkpoint_no_checkpointing_enabled(simp
|
||||
|
||||
# Attempt to run from checkpoint should fail
|
||||
try:
|
||||
async for _ in workflow.run_streaming_from_checkpoint("fake_checkpoint_id"):
|
||||
async for _ in workflow.run_stream_from_checkpoint("fake_checkpoint_id"):
|
||||
pass
|
||||
raise AssertionError("Expected ValueError to be raised")
|
||||
except ValueError as e:
|
||||
@@ -368,7 +368,7 @@ async def test_workflow_run_stream_from_checkpoint_invalid_checkpoint(simple_exe
|
||||
|
||||
# Attempt to run from non-existent checkpoint should fail
|
||||
try:
|
||||
async for _ in workflow.run_streaming_from_checkpoint("nonexistent_checkpoint_id"):
|
||||
async for _ in workflow.run_stream_from_checkpoint("nonexistent_checkpoint_id"):
|
||||
pass
|
||||
raise AssertionError("Expected RuntimeError to be raised")
|
||||
except RuntimeError as e:
|
||||
@@ -401,7 +401,7 @@ async def test_workflow_run_stream_from_checkpoint_with_external_storage(simple_
|
||||
# Resume from checkpoint using external storage parameter
|
||||
try:
|
||||
events: list[WorkflowEvent] = []
|
||||
async for event in workflow_without_checkpointing.run_streaming_from_checkpoint(
|
||||
async for event in workflow_without_checkpointing.run_stream_from_checkpoint(
|
||||
checkpoint_id, checkpoint_storage=storage
|
||||
):
|
||||
events.append(event)
|
||||
@@ -446,7 +446,7 @@ async def test_workflow_run_from_checkpoint_non_streaming(simple_executor: Execu
|
||||
|
||||
|
||||
async def test_workflow_run_stream_from_checkpoint_with_responses(simple_executor: Executor):
|
||||
"""Test that run_streaming_from_checkpoint accepts responses parameter."""
|
||||
"""Test that run_stream_from_checkpoint accepts responses parameter."""
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
storage = FileCheckpointStorage(temp_dir)
|
||||
|
||||
@@ -477,7 +477,7 @@ async def test_workflow_run_stream_from_checkpoint_with_responses(simple_executo
|
||||
|
||||
try:
|
||||
events: list[WorkflowEvent] = []
|
||||
async for event in workflow.run_streaming_from_checkpoint(checkpoint_id, responses=responses):
|
||||
async for event in workflow.run_stream_from_checkpoint(checkpoint_id, responses=responses):
|
||||
events.append(event)
|
||||
if len(events) >= 2: # Limit to avoid infinite loops
|
||||
break
|
||||
|
||||
@@ -8,8 +8,8 @@ from agent_framework import (
|
||||
AgentRunResponse,
|
||||
AgentRunResponseUpdate,
|
||||
ChatMessage,
|
||||
ChatRole,
|
||||
FunctionResultContent,
|
||||
Role,
|
||||
TextContent,
|
||||
UsageContent,
|
||||
UsageDetails,
|
||||
@@ -43,11 +43,11 @@ class SimpleExecutor(Executor):
|
||||
response_text = f"{self.response_text}: {input_text}"
|
||||
|
||||
# Create response message for both streaming and non-streaming cases
|
||||
response_message = ChatMessage(role=ChatRole.ASSISTANT, contents=[TextContent(text=response_text)])
|
||||
response_message = ChatMessage(role=Role.ASSISTANT, contents=[TextContent(text=response_text)])
|
||||
|
||||
# Emit update event.
|
||||
streaming_update = AgentRunResponseUpdate(
|
||||
contents=[TextContent(text=response_text)], role=ChatRole.ASSISTANT, message_id=str(uuid.uuid4())
|
||||
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))
|
||||
|
||||
@@ -68,7 +68,7 @@ class RequestingExecutor(Executor):
|
||||
# Handle the response and emit completion response
|
||||
update = AgentRunResponseUpdate(
|
||||
contents=[TextContent(text="Request completed successfully")],
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
message_id=str(uuid.uuid4()),
|
||||
)
|
||||
await ctx.add_event(AgentRunUpdateEvent(executor_id=self.id, data=update))
|
||||
@@ -132,7 +132,7 @@ class TestWorkflowAgent:
|
||||
|
||||
# Execute workflow streaming to capture streaming events
|
||||
updates = []
|
||||
async for update in agent.run_streaming("Test input"):
|
||||
async for update in agent.run_stream("Test input"):
|
||||
updates.append(update)
|
||||
|
||||
# Should have received at least one streaming update
|
||||
@@ -165,7 +165,7 @@ class TestWorkflowAgent:
|
||||
|
||||
# Execute workflow streaming to get request info event
|
||||
updates = []
|
||||
async for update in agent.run_streaming("Start request"):
|
||||
async for update in agent.run_stream("Start request"):
|
||||
updates.append(update)
|
||||
# Should have received a function call for the request info
|
||||
assert len(updates) > 0
|
||||
@@ -192,7 +192,7 @@ class TestWorkflowAgent:
|
||||
|
||||
# Now provide a function result response to test continuation
|
||||
response_message = ChatMessage(
|
||||
role=ChatRole.USER,
|
||||
role=Role.USER,
|
||||
contents=[FunctionResultContent(call_id=function_call.call_id, result="User provided answer")],
|
||||
)
|
||||
|
||||
@@ -252,7 +252,7 @@ class TestWorkflowAgentMergeUpdates:
|
||||
# Response B, Message 2 (latest in resp B)
|
||||
AgentRunResponseUpdate(
|
||||
contents=[TextContent(text="RespB-Msg2")],
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
response_id="resp-b",
|
||||
message_id="msg-2",
|
||||
created_at="2024-01-01T12:02:00Z",
|
||||
@@ -260,7 +260,7 @@ class TestWorkflowAgentMergeUpdates:
|
||||
# Response A, Message 1 (earliest overall)
|
||||
AgentRunResponseUpdate(
|
||||
contents=[TextContent(text="RespA-Msg1")],
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
response_id="resp-a",
|
||||
message_id="msg-1",
|
||||
created_at="2024-01-01T12:00:00Z",
|
||||
@@ -268,7 +268,7 @@ class TestWorkflowAgentMergeUpdates:
|
||||
# Response B, Message 1 (earlier in resp B)
|
||||
AgentRunResponseUpdate(
|
||||
contents=[TextContent(text="RespB-Msg1")],
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
response_id="resp-b",
|
||||
message_id="msg-1",
|
||||
created_at="2024-01-01T12:01:00Z",
|
||||
@@ -276,7 +276,7 @@ class TestWorkflowAgentMergeUpdates:
|
||||
# Response A, Message 2 (later in resp A)
|
||||
AgentRunResponseUpdate(
|
||||
contents=[TextContent(text="RespA-Msg2")],
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
response_id="resp-a",
|
||||
message_id="msg-2",
|
||||
created_at="2024-01-01T12:00:30Z",
|
||||
@@ -284,7 +284,7 @@ class TestWorkflowAgentMergeUpdates:
|
||||
# Global dangling update (no response_id) - should go at end
|
||||
AgentRunResponseUpdate(
|
||||
contents=[TextContent(text="Global-Dangling")],
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
response_id=None,
|
||||
message_id="msg-global",
|
||||
created_at="2024-01-01T11:59:00Z", # Earliest timestamp but should be last
|
||||
@@ -360,7 +360,7 @@ class TestWorkflowAgentMergeUpdates:
|
||||
details=UsageDetails(input_token_count=10, output_token_count=5, total_token_count=15)
|
||||
),
|
||||
],
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
response_id="resp-1",
|
||||
message_id="msg-1",
|
||||
created_at="2024-01-01T12:00:00Z",
|
||||
@@ -373,7 +373,7 @@ class TestWorkflowAgentMergeUpdates:
|
||||
details=UsageDetails(input_token_count=20, output_token_count=8, total_token_count=28)
|
||||
),
|
||||
],
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
response_id="resp-2",
|
||||
message_id="msg-2",
|
||||
created_at="2024-01-01T12:01:00Z", # Later timestamp
|
||||
@@ -384,7 +384,7 @@ class TestWorkflowAgentMergeUpdates:
|
||||
TextContent(text="Third"),
|
||||
UsageContent(details=UsageDetails(input_token_count=5, output_token_count=3, total_token_count=8)),
|
||||
],
|
||||
role=ChatRole.ASSISTANT,
|
||||
role=Role.ASSISTANT,
|
||||
response_id="resp-1", # Same response_id as first
|
||||
message_id="msg-3",
|
||||
created_at="2024-01-01T11:59:00Z", # Earlier timestamp
|
||||
|
||||
Reference in New Issue
Block a user