diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/agents/__init__.py b/python/packages/autogen-agentchat/src/autogen_agentchat/agents/__init__.py new file mode 100644 index 000000000000..f47329ac2541 --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/agents/__init__.py @@ -0,0 +1,10 @@ +from ._base_chat_agent import BaseChatAgent, ChatMessage +from .coding._code_executor_agent import CodeExecutorAgent +from .coding._coding_assistant_agent import CodingAssistantAgent + +__all__ = [ + "BaseChatAgent", + "ChatMessage", + "CodeExecutorAgent", + "CodingAssistantAgent", +] diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/agents/_base_chat_agent.py b/python/packages/autogen-agentchat/src/autogen_agentchat/agents/_base_chat_agent.py new file mode 100644 index 000000000000..8199ebabbc93 --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/agents/_base_chat_agent.py @@ -0,0 +1,43 @@ +from abc import ABC, abstractmethod +from typing import Sequence + +from autogen_core.base import CancellationToken +from autogen_core.components.models import AssistantMessage, UserMessage +from pydantic import BaseModel + + +class ChatMessage(BaseModel): + """A chat message from a user or agent.""" + + content: UserMessage | AssistantMessage + """The content of the message.""" + + request_pause: bool + """A flag indicating whether the current conversation session should be + paused after processing this message.""" + + +class BaseChatAgent(ABC): + """Base class for a chat agent that can participant in a team.""" + + def __init__(self, name: str, description: str) -> None: + self._name = name + self._description = description + + @property + def name(self) -> str: + """The name of the agent. This is used by team to uniquely identify + the agent. It should be unique within the team.""" + return self._name + + @property + def description(self) -> str: + """The description of the agent. This is used by team to + make decisions about which agents to use. The description should + describe the agent's capabilities and how to interact with it.""" + return self._description + + @abstractmethod + async def on_messages(self, messages: Sequence[ChatMessage], cancellation_token: CancellationToken) -> ChatMessage: + """Handle incoming messages and return a response message.""" + ... diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/agents/coding/__init__.py b/python/packages/autogen-agentchat/src/autogen_agentchat/agents/coding/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/agents/coding/_code_executor_agent.py b/python/packages/autogen-agentchat/src/autogen_agentchat/agents/coding/_code_executor_agent.py new file mode 100644 index 000000000000..0b3e47297515 --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/agents/coding/_code_executor_agent.py @@ -0,0 +1,34 @@ +from typing import List, Sequence + +from autogen_core.base import CancellationToken +from autogen_core.components.code_executor import CodeBlock, CodeExecutor, extract_markdown_code_blocks +from autogen_core.components.models import UserMessage + +from .._base_chat_agent import BaseChatAgent, ChatMessage + + +class CodeExecutorAgent(BaseChatAgent): + """An agent that executes code snippets and report the results.""" + + DESCRIPTION = "A computer terminal that performs no other action than running Python scripts (provided to it quoted in ```python code blocks), or sh shell scripts (provided to it quoted in ```sh code blocks)." + + def __init__(self, name: str, code_executor: CodeExecutor): + """Initialize the agent with a code executor.""" + super().__init__(name=name, description=self.DESCRIPTION) + self._code_executor = code_executor + + async def on_messages(self, messages: Sequence[ChatMessage], cancellation_token: CancellationToken) -> ChatMessage: + # Extract code blocks from the messages. + code_blocks: List[CodeBlock] = [] + for msg in messages: + if isinstance(msg.content, UserMessage) and isinstance(msg.content.content, str): + code_blocks.extend(extract_markdown_code_blocks(msg.content.content)) + if code_blocks: + # Execute the code blocks. + result = await self._code_executor.execute_code_blocks(code_blocks, cancellation_token=cancellation_token) + return ChatMessage(content=UserMessage(content=result.output, source=self.name), request_pause=False) + else: + return ChatMessage( + content=UserMessage(content="No code blocks found in the thread.", source=self.name), + request_pause=False, + ) diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/agents/coding/_coding_assistant_agent.py b/python/packages/autogen-agentchat/src/autogen_agentchat/agents/coding/_coding_assistant_agent.py new file mode 100644 index 000000000000..02e503cfa63d --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/agents/coding/_coding_assistant_agent.py @@ -0,0 +1,48 @@ +from typing import List, Sequence + +from autogen_core.base import CancellationToken +from autogen_core.components.models import AssistantMessage, ChatCompletionClient, SystemMessage, UserMessage + +from .._base_chat_agent import BaseChatAgent, ChatMessage + + +class CodingAssistantAgent(BaseChatAgent): + """An agent that provides coding assistance using an LLM model client.""" + + DESCRIPTION = "A helpful and general-purpose AI assistant that has strong language skills, Python skills, and Linux command line skills." + + SYSTEM_MESSAGE = """You are a helpful AI assistant. +Solve tasks using your coding and language skills. +In the following cases, suggest python code (in a python coding block) or shell script (in a sh coding block) for the user to execute. + 1. When you need to collect info, use the code to output the info you need, for example, browse or search the web, download/read a file, print the content of a webpage or a file, get the current date/time, check the operating system. After sufficient info is printed and the task is ready to be solved based on your language skill, you can solve the task by yourself. + 2. When you need to perform some task with code, use the code to perform the task and output the result. Finish the task smartly. +Solve the task step by step if you need to. If a plan is not provided, explain your plan first. Be clear which step uses code, and which step uses your language skill. +When using code, you must indicate the script type in the code block. The user cannot provide any other feedback or perform any other action beyond executing the code you suggest. The user can't modify your code. So do not suggest incomplete code which requires users to modify. Don't use a code block if it's not intended to be executed by the user. +If you want the user to save the code in a file before executing it, put # filename: inside the code block as the first line. Don't include multiple code blocks in one response. Do not ask users to copy and paste the result. Instead, use 'print' function for the output when relevant. Check the execution result returned by the user. +If the result indicates there is an error, fix the error and output the code again. Suggest the full code instead of partial code or code changes. If the error can't be fixed or if the task is not solved even after the code is executed successfully, analyze the problem, revisit your assumption, collect additional info you need, and think of a different approach to try. +When you find an answer, verify the answer carefully. Include verifiable evidence in your response if possible. +Reply "TERMINATE" in the end when everything is done.""" + + def __init__(self, name: str, model_client: ChatCompletionClient): + super().__init__(name=name, description=self.DESCRIPTION) + self._model_client = model_client + self._system_messages = [SystemMessage(content=self.SYSTEM_MESSAGE)] + self._message_thread: List[UserMessage | AssistantMessage] = [] + + async def on_messages(self, messages: Sequence[ChatMessage], cancellation_token: CancellationToken) -> ChatMessage: + # Add messages to the thread. + for msg in messages: + self._message_thread.append(msg.content) + + # Generate an inference result based on the thread. + llm_messages = self._system_messages + self._message_thread + result = await self._model_client.create(llm_messages, cancellation_token=cancellation_token) + assert isinstance(result.content, str) + + # Add the response to the thread. + self._message_thread.append(AssistantMessage(content=result.content, source=self.name)) + + # Detect pause request. + request_pause = "terminate" in result.content.strip().lower() + + return ChatMessage(content=UserMessage(content=result.content, source=self.name), request_pause=request_pause) diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/__init__.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/__init__.py new file mode 100644 index 000000000000..1a56f4ae7e26 --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/__init__.py @@ -0,0 +1,3 @@ +from .group_chat._round_robin_group_chat import RoundRobinGroupChat + +__all__ = ["RoundRobinGroupChat"] diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_chat_agent_container.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_chat_agent_container.py new file mode 100644 index 000000000000..870d4fef6e15 --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_chat_agent_container.py @@ -0,0 +1,39 @@ +from typing import List + +from autogen_core.base import MessageContext +from autogen_core.components import DefaultTopicId, RoutedAgent, event + +from ..agents import BaseChatAgent, ChatMessage +from ._messages import ContentPublishEvent, ContentRequestEvent + + +class BaseChatAgentContainer(RoutedAgent): + """A core agent class that delegates message handling to an + :class:`autogen_agentchat.agents.BaseChatAgent` so that it can be used in a team. + + Args: + parent_topic_type (str): The topic type of the parent orchestrator. + agent (BaseChatAgent): The agent to delegate message handling to. + """ + + def __init__(self, parent_topic_type: str, agent: BaseChatAgent) -> None: + super().__init__(description=agent.description) + self._parent_topic_type = parent_topic_type + self._agent = agent + self._message_buffer: List[ChatMessage] = [] + + @event + async def handle_content_publish(self, message: ContentPublishEvent, ctx: MessageContext) -> None: + """Handle a content publish event by appending the content to the buffer.""" + self._message_buffer.append(ChatMessage(content=message.content, request_pause=message.request_pause)) + + @event + async def handle_content_request(self, message: ContentRequestEvent, ctx: MessageContext) -> None: + """Handle a content request event by passing the messages in the buffer + to the delegate agent and publish the response.""" + response = await self._agent.on_messages(self._message_buffer, ctx.cancellation_token) + self._message_buffer.clear() + await self.publish_message( + ContentPublishEvent(content=response.content, request_pause=response.request_pause), + topic_id=DefaultTopicId(type=self._parent_topic_type), + ) diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_team.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_team.py new file mode 100644 index 000000000000..8653372d1875 --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_team.py @@ -0,0 +1,13 @@ +from dataclasses import dataclass +from typing import Protocol + + +@dataclass +class TeamRunResult: + result: str + + +class BaseTeam(Protocol): + async def run(self, task: str) -> TeamRunResult: + """Run the team and return the result.""" + ... diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_messages.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_messages.py new file mode 100644 index 000000000000..57dcdbd75c9a --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_messages.py @@ -0,0 +1,25 @@ +from autogen_core.components.models import AssistantMessage, UserMessage +from pydantic import BaseModel + + +class ContentPublishEvent(BaseModel): + """An event message for sharing some data. Agents receive this message should + update their internal state (e.g., append to message history) with the + content of the message. + """ + + content: UserMessage | AssistantMessage + """The content of the message.""" + + request_pause: bool + """A flag indicating whether the current conversation session should be + paused after processing this message.""" + + +class ContentRequestEvent(BaseModel): + """An event message for requesting to publish a content message. + Upon receiving this message, the agent should publish a ContentPublishEvent + message. + """ + + ... diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/__init__.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_group_chat_manager.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_group_chat_manager.py new file mode 100644 index 000000000000..6b15124f2c5c --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_group_chat_manager.py @@ -0,0 +1,106 @@ +import sys +from typing import List + +from autogen_core.base import MessageContext, TopicId +from autogen_core.components import RoutedAgent, event +from autogen_core.components.models import AssistantMessage, UserMessage + +from .._messages import ContentPublishEvent, ContentRequestEvent + + +class BaseGroupChatManager(RoutedAgent): + """Base class for a group chat manager that manages a group chat with multiple participants. + + It is the responsibility of the caller to ensure: + - All participants must subscribe to the group chat topic and each of their own topics. + - The group chat manager must subscribe to the parent topic and the group chat topic. + + Args: + parent_topic_type (str): The topic type of the parent orchestrator. + group_topic_type (str): The topic type of the group chat. + participant_topic_types (List[str]): The topic types of the participants. + participant_descriptions (List[str]): The descriptions of the participants + + Raises: + ValueError: If the number of participant topic types, agent types, and descriptions are not the same. + """ + + def __init__( + self, + parent_topic_type: str, + group_topic_type: str, + participant_topic_types: List[str], + participant_descriptions: List[str], + ): + super().__init__(description="Group chat manager") + self._parent_topic_type = parent_topic_type + self._group_topic_type = group_topic_type + if len(participant_topic_types) != len(participant_descriptions): + raise ValueError("The number of participant topic types, agent types, and descriptions must be the same.") + if len(set(participant_topic_types)) != len(participant_topic_types): + raise ValueError("The participant topic types must be unique.") + if group_topic_type in participant_topic_types: + raise ValueError("The group topic type must not be in the participant topic types.") + if parent_topic_type in participant_topic_types: + raise ValueError("The parent topic type must not be in the participant topic types.") + if group_topic_type == parent_topic_type: + raise ValueError("The group topic type must not be the same as the parent topic type.") + self._participant_topic_types = participant_topic_types + self._participant_descriptions = participant_descriptions + self._message_thread: List[UserMessage | AssistantMessage] = [] + + @event + async def handle_content_publish(self, message: ContentPublishEvent, ctx: MessageContext) -> None: + """Handle a content publish event. + + If the event is from the parent topic, add the message to the thread. + + If the event is from the group chat topic, add the message to the thread and select a speaker to continue the conversation. + If the event from the group chat session requests a pause, publish the last message to the parent topic.""" + assert ctx.topic_id is not None + group_chat_topic_id = TopicId(type=self._group_topic_type, source=ctx.topic_id.source) + + # TODO: use something else other than print. + assert isinstance(message.content, UserMessage) or isinstance(message.content, AssistantMessage) + sys.stdout.write(f"{'-'*80}\n{message.content.source}:\n{message.content.content}\n") + + # Process event from parent. + if ctx.topic_id.type == self._parent_topic_type: + self._message_thread.append(message.content) + await self.publish_message(message, topic_id=group_chat_topic_id) + return + + # Process event from the group chat this agent manages. + assert ctx.topic_id.type == self._group_topic_type + self._message_thread.append(message.content) + + if message.request_pause: + parent_topic_id = TopicId(type=self._parent_topic_type, source=ctx.topic_id.source) + await self.publish_message( + ContentPublishEvent(content=message.content, request_pause=True), topic_id=parent_topic_id + ) + return + + # Select a speaker to continue the conversation. + speaker_topic_type = await self.select_speaker(self._message_thread) + + participant_topic_id = TopicId(type=speaker_topic_type, source=ctx.topic_id.source) + group_chat_topic_id = TopicId(type=self._group_topic_type, source=ctx.topic_id.source) + await self.publish_message(ContentRequestEvent(), topic_id=participant_topic_id) + + @event + async def handle_content_request(self, message: ContentRequestEvent, ctx: MessageContext) -> None: + """Handle a content request by selecting a speaker to start the conversation.""" + assert ctx.topic_id is not None + if ctx.topic_id.type == self._group_topic_type: + raise RuntimeError("Content request event from the group chat topic is not allowed.") + + speaker_topic_type = await self.select_speaker(self._message_thread) + + participant_topic_id = TopicId(type=speaker_topic_type, source=ctx.topic_id.source) + await self.publish_message(ContentRequestEvent(), topic_id=participant_topic_id) + + async def select_speaker(self, thread: List[UserMessage | AssistantMessage]) -> str: + """Select a speaker from the participants and return the + topic type of the selected speaker.""" + raise NotImplementedError("Method not implemented") diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_round_robin_group_chat.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_round_robin_group_chat.py new file mode 100644 index 000000000000..5e80746ddb98 --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_round_robin_group_chat.py @@ -0,0 +1,127 @@ +import asyncio +import uuid +from typing import Callable, List + +from autogen_core.application import SingleThreadedAgentRuntime +from autogen_core.base import AgentId, AgentInstantiationContext, AgentRuntime, AgentType, MessageContext, TopicId +from autogen_core.components import ClosureAgent, TypeSubscription +from autogen_core.components.models import UserMessage + +from ...agents import BaseChatAgent +from .._base_chat_agent_container import BaseChatAgentContainer +from .._base_team import BaseTeam, TeamRunResult +from .._messages import ContentPublishEvent, ContentRequestEvent +from ._round_robin_group_chat_manager import RoundRobinGroupChatManager + + +class RoundRobinGroupChat(BaseTeam): + def __init__(self, participants: List[BaseChatAgent]): + if len(participants) == 0: + raise ValueError("At least one participant is required.") + if len(participants) != len(set(participant.name for participant in participants)): + raise ValueError("The participant names must be unique.") + self._participants = participants + self._team_id = str(uuid.uuid4()) + + def _create_factory(self, parent_topic_type: str, agent: BaseChatAgent) -> Callable[[], BaseChatAgentContainer]: + def _factory() -> BaseChatAgentContainer: + id = AgentInstantiationContext.current_agent_id() + assert id == AgentId(type=agent.name, key=self._team_id) + container = BaseChatAgentContainer(parent_topic_type, agent) + assert container.id == id + return container + + return _factory + + async def run(self, task: str) -> TeamRunResult: + """Run the team and return the result.""" + # Create the runtime. + runtime = SingleThreadedAgentRuntime() + + # Constants for the group chat manager. + group_chat_manager_agent_type = AgentType("group_chat_manager") + group_chat_manager_topic_type = group_chat_manager_agent_type.type + group_topic_type = "round_robin_group_topic" + team_topic_type = "team_topic" + + # Register participants. + participant_topic_types: List[str] = [] + participant_descriptions: List[str] = [] + for participant in self._participants: + # Use the participant name as the agent type and topic type. + agent_type = participant.name + topic_type = participant.name + # Register the participant factory. + await BaseChatAgentContainer.register( + runtime, type=agent_type, factory=self._create_factory(group_topic_type, participant) + ) + # Add subscriptions for the participant. + await runtime.add_subscription(TypeSubscription(topic_type=topic_type, agent_type=agent_type)) + await runtime.add_subscription(TypeSubscription(topic_type=group_topic_type, agent_type=agent_type)) + # Add the participant to the lists. + participant_descriptions.append(participant.description) + participant_topic_types.append(topic_type) + + # Register the group chat manager. + await RoundRobinGroupChatManager.register( + runtime, + type=group_chat_manager_agent_type.type, + factory=lambda: RoundRobinGroupChatManager( + parent_topic_type=team_topic_type, + group_topic_type=group_topic_type, + participant_topic_types=participant_topic_types, + participant_descriptions=participant_descriptions, + ), + ) + # Add subscriptions for the group chat manager. + await runtime.add_subscription( + TypeSubscription(topic_type=group_chat_manager_topic_type, agent_type=group_chat_manager_agent_type.type) + ) + await runtime.add_subscription( + TypeSubscription(topic_type=group_topic_type, agent_type=group_chat_manager_agent_type.type) + ) + await runtime.add_subscription( + TypeSubscription(topic_type=team_topic_type, agent_type=group_chat_manager_agent_type.type) + ) + + # Create a closure agent to recieve the final result. + team_messages = asyncio.Queue[ContentPublishEvent]() + + async def output_result( + _runtime: AgentRuntime, id: AgentId, message: ContentPublishEvent, ctx: MessageContext + ) -> None: + await team_messages.put(message) + + await ClosureAgent.register( + runtime, + type="output_result", + closure=output_result, + subscriptions=lambda: [TypeSubscription(topic_type=team_topic_type, agent_type="output_result")], + ) + + # Start the runtime. + runtime.start() + + # Run the team by publishing the task to the team topic and then requesting the result. + team_topic_id = TopicId(type=team_topic_type, source=self._team_id) + group_chat_manager_topic_id = TopicId(type=group_chat_manager_topic_type, source=self._team_id) + await runtime.publish_message( + ContentPublishEvent(content=UserMessage(content=task, source="user"), request_pause=False), + topic_id=team_topic_id, + ) + await runtime.publish_message(ContentRequestEvent(), topic_id=group_chat_manager_topic_id) + + # Wait for the runtime to stop. + await runtime.stop_when_idle() + + # Get the last message from the team. + last_message = None + while not team_messages.empty(): + last_message = await team_messages.get() + + assert ( + last_message is not None + and isinstance(last_message.content, UserMessage) + and isinstance(last_message.content.content, str) + ) + return TeamRunResult(last_message.content.content) diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_round_robin_group_chat_manager.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_round_robin_group_chat_manager.py new file mode 100644 index 000000000000..129d79dd1a91 --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_round_robin_group_chat_manager.py @@ -0,0 +1,30 @@ +from typing import List + +from autogen_core.components.models import AssistantMessage, UserMessage + +from ._base_group_chat_manager import BaseGroupChatManager + + +class RoundRobinGroupChatManager(BaseGroupChatManager): + """A group chat manager that selects the next speaker in a round-robin fashion.""" + + def __init__( + self, + parent_topic_type: str, + group_topic_type: str, + participant_topic_types: List[str], + participant_descriptions: List[str], + ): + super().__init__( + parent_topic_type, + group_topic_type, + participant_topic_types, + participant_descriptions, + ) + self._next_speaker_index = 0 + + async def select_speaker(self, thread: List[UserMessage | AssistantMessage]) -> str: + """Select a speaker from the participants in a round-robin fashion.""" + current_speaker_index = self._next_speaker_index + self._next_speaker_index = (current_speaker_index + 1) % len(self._participant_topic_types) + return self._participant_topic_types[current_speaker_index] diff --git a/python/packages/autogen-agentchat/tests/test_example.py b/python/packages/autogen-agentchat/tests/test_example.py deleted file mode 100644 index 60f1465c8ffb..000000000000 --- a/python/packages/autogen-agentchat/tests/test_example.py +++ /dev/null @@ -1,2 +0,0 @@ -async def test_example() -> None: - assert True diff --git a/python/packages/autogen-agentchat/tests/test_group_chat.py b/python/packages/autogen-agentchat/tests/test_group_chat.py new file mode 100644 index 000000000000..0771207f6b0e --- /dev/null +++ b/python/packages/autogen-agentchat/tests/test_group_chat.py @@ -0,0 +1,76 @@ +import asyncio +import tempfile +from typing import Any, AsyncGenerator, List + +import pytest +from autogen_agentchat.agents import CodeExecutorAgent, CodingAssistantAgent +from autogen_agentchat.teams import RoundRobinGroupChat +from autogen_core.components.code_executor import LocalCommandLineCodeExecutor +from autogen_core.components.models import OpenAIChatCompletionClient +from openai.resources.chat.completions import AsyncCompletions +from openai.types.chat.chat_completion import ChatCompletion, Choice +from openai.types.chat.chat_completion_chunk import ChatCompletionChunk +from openai.types.chat.chat_completion_message import ChatCompletionMessage +from openai.types.completion_usage import CompletionUsage + + +class _MockChatCompletion: + def __init__(self, model: str = "gpt-4o") -> None: + self._saved_chat_completions: List[ChatCompletion] = [ + ChatCompletion( + id="id1", + choices=[ + Choice( + finish_reason="stop", + index=0, + message=ChatCompletionMessage( + content="""Here is the program\n ```python\nprint("Hello, world!")\n```""", + role="assistant", + ), + ) + ], + created=0, + model=model, + object="chat.completion", + usage=CompletionUsage(prompt_tokens=0, completion_tokens=0, total_tokens=0), + ), + ChatCompletion( + id="id2", + choices=[ + Choice( + finish_reason="stop", + index=0, + message=ChatCompletionMessage(content="TERMINATE", role="assistant"), + ) + ], + created=0, + model=model, + object="chat.completion", + usage=CompletionUsage(prompt_tokens=0, completion_tokens=0, total_tokens=0), + ), + ] + self._curr_index = 0 + + async def mock_create( + self, *args: Any, **kwargs: Any + ) -> ChatCompletion | AsyncGenerator[ChatCompletionChunk, None]: + await asyncio.sleep(0.1) + completion = self._saved_chat_completions[self._curr_index] + self._curr_index += 1 + return completion + + +@pytest.mark.asyncio +async def test_round_robin_group_chat(monkeypatch: pytest.MonkeyPatch) -> None: + mock = _MockChatCompletion(model="gpt-4o-2024-05-13") + monkeypatch.setattr(AsyncCompletions, "create", mock.mock_create) + with tempfile.TemporaryDirectory() as temp_dir: + code_executor_agent = CodeExecutorAgent( + "code_executor", code_executor=LocalCommandLineCodeExecutor(work_dir=temp_dir) + ) + coding_assistant_agent = CodingAssistantAgent( + "coding_assistant", model_client=OpenAIChatCompletionClient(model="gpt-4o-2024-05-13", api_key="") + ) + team = RoundRobinGroupChat(participants=[coding_assistant_agent, code_executor_agent]) + result = await team.run("Write a program that prints 'Hello, world!'") + assert result.result == "TERMINATE" diff --git a/python/packages/autogen-core/docs/src/agentchat-user-guide/guides/.gitignore b/python/packages/autogen-core/docs/src/agentchat-user-guide/guides/.gitignore new file mode 100644 index 000000000000..f2e35496e47c --- /dev/null +++ b/python/packages/autogen-core/docs/src/agentchat-user-guide/guides/.gitignore @@ -0,0 +1 @@ +coding \ No newline at end of file diff --git a/python/packages/autogen-core/docs/src/agentchat-user-guide/guides/quickstart.ipynb b/python/packages/autogen-core/docs/src/agentchat-user-guide/guides/quickstart.ipynb index 405c498b166f..08135a8fd4a7 100644 --- a/python/packages/autogen-core/docs/src/agentchat-user-guide/guides/quickstart.ipynb +++ b/python/packages/autogen-core/docs/src/agentchat-user-guide/guides/quickstart.ipynb @@ -14,6 +14,341 @@ "🚧 Under construction 🚧\n", ":::" ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--------------------------------------------------------------------------------\n", + "user:\n", + "Create a plot of NVDIA and TSLA stock returns YTD from 2024-01-01 and save it to 'nvidia_tesla_2024_ytd.png'.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "coding_assistant:\n", + "To create a plot of NVIDIA and TSLA stock returns from January 1, 2024, year-to-date, we will perform the following steps:\n", + "\n", + "1. **Install Required Libraries:**\n", + " We'll need `pandas`, `matplotlib`, and `yfinance` to fetch and plot the stock data. Make sure these libraries are installed.\n", + "\n", + "2. **Fetch the Stock Data:**\n", + " Use the `yfinance` library to download the stock data for NVIDIA (ticker: NVDA) and Tesla (ticker: TSLA) from January 1, 2024.\n", + "\n", + "3. **Calculate Stock Returns:**\n", + " Calculate the percentage returns of both stocks over the date range.\n", + "\n", + "4. **Plot the Data:**\n", + " Plot NVIDIA and Tesla returns using `matplotlib` and save the plot as 'nvidia_tesla_2024_ytd.png'.\n", + "\n", + "Here's the complete code to perform these steps:\n", + "\n", + "```python\n", + "# filename: plot_nvidia_tesla_2024_ytd.py\n", + "\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import yfinance as yf\n", + "\n", + "# Step 1: Fetch the Stock Data\n", + "start_date = \"2024-01-01\"\n", + "end_date = pd.Timestamp.now().strftime('%Y-%m-%d')\n", + "\n", + "nvda = yf.download('NVDA', start=start_date, end=end_date)\n", + "tsla = yf.download('TSLA', start=start_date, end=end_date)\n", + "\n", + "# Step 2: Calculate the returns\n", + "nvda['Returns'] = nvda['Adj Close'].pct_change()\n", + "tsla['Returns'] = tsla['Adj Close'].pct_change()\n", + "\n", + "# Step 3: Drop the first NaN values from the dataset\n", + "nvda = nvda.dropna(subset=['Returns'])\n", + "tsla = tsla.dropna(subset=['Returns'])\n", + "\n", + "# Step 4: Plot the Data\n", + "plt.figure(figsize=(10, 6))\n", + "plt.plot(nvda['Returns'].index, (nvda['Returns'] + 1).cumprod() - 1, label='NVIDIA (NVDA)')\n", + "plt.plot(tsla['Returns'].index, (tsla['Returns'] + 1).cumprod() - 1, label='Tesla (TSLA)')\n", + "\n", + "# Adding titles and labels\n", + "plt.title('NVIDIA and Tesla Stock Returns YTD (2024)')\n", + "plt.xlabel('Date')\n", + "plt.ylabel('Cumulative Return')\n", + "plt.legend()\n", + "\n", + "# Save the plot\n", + "plt.savefig('nvidia_tesla_2024_ytd.png')\n", + "\n", + "# Display a confirmation message\n", + "print(\"The plot has been saved as 'nvidia_tesla_2024_ytd.png'.\")\n", + "```\n", + "\n", + "Please save the code above in a file named `plot_nvidia_tesla_2024_ytd.py` and execute it. This will generate the plot of NVIDIA and Tesla stock returns for the year 2024 up to today's date and save it as `'nvidia_tesla_2024_ytd.png'`.\n", + "\n", + "After running the code, check that the file `nvidia_tesla_2024_ytd.png` has been created in the directory. If there are any errors or issues, let me know so I can help you resolve them.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "code_executor:\n", + "Traceback (most recent call last):\n", + " File \"/workspace/plot_nvidia_tesla_2024_ytd.py\", line 3, in \n", + " import pandas as pd\n", + "ModuleNotFoundError: No module named 'pandas'\n", + "\n", + "\n", + "--------------------------------------------------------------------------------\n", + "coding_assistant:\n", + "It seems that the `pandas` library is not installed in your environment. Let's update the script to include the installation of the required libraries within the code itself.\n", + "\n", + "Here's the updated script that installs the necessary libraries before executing the main tasks:\n", + "\n", + "```python\n", + "# filename: plot_nvidia_tesla_2024_ytd.py\n", + "\n", + "import subprocess\n", + "import sys\n", + "\n", + "# Function to install required libraries\n", + "def install(package):\n", + " subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", package])\n", + "\n", + "# Install the required libraries\n", + "try:\n", + " import pandas as pd\n", + "except ImportError:\n", + " install(\"pandas\")\n", + " import pandas as pd\n", + " \n", + "try:\n", + " import matplotlib.pyplot as plt\n", + "except ImportError:\n", + " install(\"matplotlib\")\n", + " import matplotlib.pyplot as plt\n", + "\n", + "try:\n", + " import yfinance as yf\n", + "except ImportError:\n", + " install(\"yfinance\")\n", + " import yfinance as yf\n", + "\n", + "# Step 1: Fetch the Stock Data\n", + "start_date = \"2024-01-01\"\n", + "end_date = pd.Timestamp.now().strftime('%Y-%m-%d')\n", + "\n", + "nvda = yf.download('NVDA', start=start_date, end=end_date)\n", + "tsla = yf.download('TSLA', start=start_date, end=end_date)\n", + "\n", + "# Step 2: Calculate the returns\n", + "nvda['Returns'] = nvda['Adj Close'].pct_change()\n", + "tsla['Returns'] = tsla['Adj Close'].pct_change()\n", + "\n", + "# Step 3: Drop the first NaN values from the dataset\n", + "nvda = nvda.dropna(subset=['Returns'])\n", + "tsla = tsla.dropna(subset=['Returns'])\n", + "\n", + "# Step 4: Plot the Data\n", + "plt.figure(figsize=(10, 6))\n", + "plt.plot(nvda['Returns'].index, (nvda['Returns'] + 1).cumprod() - 1, label='NVIDIA (NVDA)')\n", + "plt.plot(tsla['Returns'].index, (tsla['Returns'] + 1).cumprod() - 1, label='Tesla (TSLA)')\n", + "\n", + "# Adding titles and labels\n", + "plt.title('NVIDIA and Tesla Stock Returns YTD (2024)')\n", + "plt.xlabel('Date')\n", + "plt.ylabel('Cumulative Return')\n", + "plt.legend()\n", + "\n", + "# Save the plot\n", + "plt.savefig('nvidia_tesla_2024_ytd.png')\n", + "\n", + "# Display a confirmation message\n", + "print(\"The plot has been saved as 'nvidia_tesla_2024_ytd.png'.\")\n", + "```\n", + "\n", + "Please save the code above in a file named `plot_nvidia_tesla_2024_ytd.py` and execute it again. This script will handle the installation of any missing libraries automatically before proceeding with the data fetching, processing, and plotting tasks.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "code_executor:\n", + "Collecting pandas\n", + " Downloading pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (89 kB)\n", + "Collecting numpy>=1.26.0 (from pandas)\n", + " Downloading numpy-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (60 kB)\n", + "Collecting python-dateutil>=2.8.2 (from pandas)\n", + " Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl.metadata (8.4 kB)\n", + "Collecting pytz>=2020.1 (from pandas)\n", + " Downloading pytz-2024.2-py2.py3-none-any.whl.metadata (22 kB)\n", + "Collecting tzdata>=2022.7 (from pandas)\n", + " Downloading tzdata-2024.2-py2.py3-none-any.whl.metadata (1.4 kB)\n", + "Collecting six>=1.5 (from python-dateutil>=2.8.2->pandas)\n", + " Downloading six-1.16.0-py2.py3-none-any.whl.metadata (1.8 kB)\n", + "Downloading pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.7 MB)\n", + " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.7/12.7 MB 9.6 MB/s eta 0:00:00\n", + "Downloading numpy-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (16.0 MB)\n", + " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 16.0/16.0 MB 8.6 MB/s eta 0:00:00\n", + "Downloading python_dateutil-2.9.0.post0-py2.py3-none-any.whl (229 kB)\n", + "Downloading pytz-2024.2-py2.py3-none-any.whl (508 kB)\n", + "Downloading tzdata-2024.2-py2.py3-none-any.whl (346 kB)\n", + "Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)\n", + "Installing collected packages: pytz, tzdata, six, numpy, python-dateutil, pandas\n", + "Successfully installed numpy-2.1.1 pandas-2.2.3 python-dateutil-2.9.0.post0 pytz-2024.2 six-1.16.0 tzdata-2024.2\n", + "WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable.It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.\n", + "Collecting matplotlib\n", + " Downloading matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (11 kB)\n", + "Collecting contourpy>=1.0.1 (from matplotlib)\n", + " Downloading contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (5.4 kB)\n", + "Collecting cycler>=0.10 (from matplotlib)\n", + " Downloading cycler-0.12.1-py3-none-any.whl.metadata (3.8 kB)\n", + "Collecting fonttools>=4.22.0 (from matplotlib)\n", + " Downloading fonttools-4.54.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (163 kB)\n", + "Collecting kiwisolver>=1.3.1 (from matplotlib)\n", + " Downloading kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.3 kB)\n", + "Requirement already satisfied: numpy>=1.23 in /usr/local/lib/python3.12/site-packages (from matplotlib) (2.1.1)\n", + "Collecting packaging>=20.0 (from matplotlib)\n", + " Downloading packaging-24.1-py3-none-any.whl.metadata (3.2 kB)\n", + "Collecting pillow>=8 (from matplotlib)\n", + " Downloading pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl.metadata (9.2 kB)\n", + "Collecting pyparsing>=2.3.1 (from matplotlib)\n", + " Downloading pyparsing-3.1.4-py3-none-any.whl.metadata (5.1 kB)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.12/site-packages (from matplotlib) (2.9.0.post0)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.12/site-packages (from python-dateutil>=2.7->matplotlib) (1.16.0)\n", + "Downloading matplotlib-3.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (8.3 MB)\n", + " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.3/8.3 MB 10.1 MB/s eta 0:00:00\n", + "Downloading contourpy-1.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (320 kB)\n", + "Downloading cycler-0.12.1-py3-none-any.whl (8.3 kB)\n", + "Downloading fonttools-4.54.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.9 MB)\n", + " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.9/4.9 MB 9.5 MB/s eta 0:00:00\n", + "Downloading kiwisolver-1.4.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.5 MB)\n", + " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.5/1.5 MB 10.8 MB/s eta 0:00:00\n", + "Downloading packaging-24.1-py3-none-any.whl (53 kB)\n", + "Downloading pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl (4.5 MB)\n", + " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.5/4.5 MB 8.9 MB/s eta 0:00:00\n", + "Downloading pyparsing-3.1.4-py3-none-any.whl (104 kB)\n", + "Installing collected packages: pyparsing, pillow, packaging, kiwisolver, fonttools, cycler, contourpy, matplotlib\n", + "Successfully installed contourpy-1.3.0 cycler-0.12.1 fonttools-4.54.1 kiwisolver-1.4.7 matplotlib-3.9.2 packaging-24.1 pillow-10.4.0 pyparsing-3.1.4\n", + "WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable.It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.\n", + "Collecting yfinance\n", + " Downloading yfinance-0.2.43-py2.py3-none-any.whl.metadata (11 kB)\n", + "Requirement already satisfied: pandas>=1.3.0 in /usr/local/lib/python3.12/site-packages (from yfinance) (2.2.3)\n", + "Requirement already satisfied: numpy>=1.16.5 in /usr/local/lib/python3.12/site-packages (from yfinance) (2.1.1)\n", + "Collecting requests>=2.31 (from yfinance)\n", + " Downloading requests-2.32.3-py3-none-any.whl.metadata (4.6 kB)\n", + "Collecting multitasking>=0.0.7 (from yfinance)\n", + " Downloading multitasking-0.0.11-py3-none-any.whl.metadata (5.5 kB)\n", + "Collecting lxml>=4.9.1 (from yfinance)\n", + " Downloading lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl.metadata (3.8 kB)\n", + "Collecting platformdirs>=2.0.0 (from yfinance)\n", + " Downloading platformdirs-4.3.6-py3-none-any.whl.metadata (11 kB)\n", + "Requirement already satisfied: pytz>=2022.5 in /usr/local/lib/python3.12/site-packages (from yfinance) (2024.2)\n", + "Collecting frozendict>=2.3.4 (from yfinance)\n", + " Downloading frozendict-2.4.4-py312-none-any.whl.metadata (23 kB)\n", + "Collecting peewee>=3.16.2 (from yfinance)\n", + " Downloading peewee-3.17.6.tar.gz (3.0 MB)\n", + " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.0/3.0 MB 18.8 MB/s eta 0:00:00\n", + " Installing build dependencies: started\n", + " Installing build dependencies: finished with status 'done'\n", + " Getting requirements to build wheel: started\n", + " Getting requirements to build wheel: finished with status 'done'\n", + " Preparing metadata (pyproject.toml): started\n", + " Preparing metadata (pyproject.toml): finished with status 'done'\n", + "Collecting beautifulsoup4>=4.11.1 (from yfinance)\n", + " Downloading beautifulsoup4-4.12.3-py3-none-any.whl.metadata (3.8 kB)\n", + "Collecting html5lib>=1.1 (from yfinance)\n", + " Downloading html5lib-1.1-py2.py3-none-any.whl.metadata (16 kB)\n", + "Collecting soupsieve>1.2 (from beautifulsoup4>=4.11.1->yfinance)\n", + " Downloading soupsieve-2.6-py3-none-any.whl.metadata (4.6 kB)\n", + "Requirement already satisfied: six>=1.9 in /usr/local/lib/python3.12/site-packages (from html5lib>=1.1->yfinance) (1.16.0)\n", + "Collecting webencodings (from html5lib>=1.1->yfinance)\n", + " Downloading webencodings-0.5.1-py2.py3-none-any.whl.metadata (2.1 kB)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.12/site-packages (from pandas>=1.3.0->yfinance) (2.9.0.post0)\n", + "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.12/site-packages (from pandas>=1.3.0->yfinance) (2024.2)\n", + "Collecting charset-normalizer<4,>=2 (from requests>=2.31->yfinance)\n", + " Downloading charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (33 kB)\n", + "Collecting idna<4,>=2.5 (from requests>=2.31->yfinance)\n", + " Downloading idna-3.10-py3-none-any.whl.metadata (10 kB)\n", + "Collecting urllib3<3,>=1.21.1 (from requests>=2.31->yfinance)\n", + " Downloading urllib3-2.2.3-py3-none-any.whl.metadata (6.5 kB)\n", + "Collecting certifi>=2017.4.17 (from requests>=2.31->yfinance)\n", + " Downloading certifi-2024.8.30-py3-none-any.whl.metadata (2.2 kB)\n", + "Downloading yfinance-0.2.43-py2.py3-none-any.whl (84 kB)\n", + "Downloading beautifulsoup4-4.12.3-py3-none-any.whl (147 kB)\n", + "Downloading frozendict-2.4.4-py312-none-any.whl (16 kB)\n", + "Downloading html5lib-1.1-py2.py3-none-any.whl (112 kB)\n", + "Downloading lxml-5.3.0-cp312-cp312-manylinux_2_28_x86_64.whl (4.9 MB)\n", + " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.9/4.9 MB 11.5 MB/s eta 0:00:00\n", + "Downloading multitasking-0.0.11-py3-none-any.whl (8.5 kB)\n", + "Downloading platformdirs-4.3.6-py3-none-any.whl (18 kB)\n", + "Downloading requests-2.32.3-py3-none-any.whl (64 kB)\n", + "Downloading certifi-2024.8.30-py3-none-any.whl (167 kB)\n", + "Downloading charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (141 kB)\n", + "Downloading idna-3.10-py3-none-any.whl (70 kB)\n", + "Downloading soupsieve-2.6-py3-none-any.whl (36 kB)\n", + "Downloading urllib3-2.2.3-py3-none-any.whl (126 kB)\n", + "Downloading webencodings-0.5.1-py2.py3-none-any.whl (11 kB)\n", + "Building wheels for collected packages: peewee\n", + " Building wheel for peewee (pyproject.toml): started\n", + " Building wheel for peewee (pyproject.toml): finished with status 'done'\n", + " Created wheel for peewee: filename=peewee-3.17.6-py3-none-any.whl size=138891 sha256=2ebfaa05ebbf22e164164fd4c2b09d7c7c279dd785fbd5ac8419c7f62c32f90f\n", + " Stored in directory: /root/.cache/pip/wheels/a6/5e/0f/8319805c4115320e0d3e8fb5799b114a2e4c4a3d6c7e523b06\n", + "Successfully built peewee\n", + "Installing collected packages: webencodings, peewee, multitasking, urllib3, soupsieve, platformdirs, lxml, idna, html5lib, frozendict, charset-normalizer, certifi, requests, beautifulsoup4, yfinance\n", + "Successfully installed beautifulsoup4-4.12.3 certifi-2024.8.30 charset-normalizer-3.3.2 frozendict-2.4.4 html5lib-1.1 idna-3.10 lxml-5.3.0 multitasking-0.0.11 peewee-3.17.6 platformdirs-4.3.6 requests-2.32.3 soupsieve-2.6 urllib3-2.2.3 webencodings-0.5.1 yfinance-0.2.43\n", + "WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable.It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning.\n", + "[*********************100%***********************] 1 of 1 completed\n", + "[*********************100%***********************] 1 of 1 completed\n", + "The plot has been saved as 'nvidia_tesla_2024_ytd.png'.\n", + "\n", + "\n", + "--------------------------------------------------------------------------------\n", + "coding_assistant:\n", + "The plot has been successfully saved as `nvidia_tesla_2024_ytd.png`. You should now see the file in your directory. This file contains the year-to-date cumulative return plot of NVIDIA and Tesla stocks for the year 2024.\n", + "\n", + "If you need any further assistance, feel free to ask. TERMINATE\n", + "\n", + "TeamRunResult(result='The plot has been successfully saved as `nvidia_tesla_2024_ytd.png`. You should now see the file in your directory. This file contains the year-to-date cumulative return plot of NVIDIA and Tesla stocks for the year 2024.\\n\\nIf you need any further assistance, feel free to ask. TERMINATE')\n" + ] + } + ], + "source": [ + "from autogen_agentchat.agents import CodeExecutorAgent, CodingAssistantAgent\n", + "from autogen_agentchat.teams import RoundRobinGroupChat\n", + "from autogen_core.components.code_executor import DockerCommandLineCodeExecutor\n", + "from autogen_core.components.models import OpenAIChatCompletionClient\n", + "\n", + "async with DockerCommandLineCodeExecutor(work_dir=\"coding\") as code_executor: # type: ignore[syntax]\n", + " code_executor_agent = CodeExecutorAgent(\"code_executor\", code_executor=code_executor)\n", + " coding_assistant_agent = CodingAssistantAgent(\n", + " \"coding_assistant\", model_client=OpenAIChatCompletionClient(model=\"gpt-4o\")\n", + " )\n", + " group_chat = RoundRobinGroupChat([coding_assistant_agent, code_executor_agent])\n", + " result = await group_chat.run(\n", + " task=\"Create a plot of NVDIA and TSLA stock returns YTD from 2024-01-01 and save it to 'nvidia_tesla_2024_ytd.png'.\"\n", + " )\n", + " print(result)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA+gAAAJYCAYAAADxHswlAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAADoUklEQVR4nOzdd3yT9fYH8M+TpE333osuoOxS9t5LBJGtssU97k+vAxUUnKjXwfW62KIoCgiigAgoe++9uifde6XJ8/sjow1d6UzafN6vV1+2yZMn36cNtSfnfM8RRFEUQURERERERERGJTH2AoiIiIiIiIiIAToRERERERGRSWCATkRERERERGQCGKATERERERERmQAG6EREREREREQmgAE6ERERERERkQlggE5ERERERERkAhigExEREREREZkABuhEREREREREJoABOhEREREREZEJYIBOREREREREZAIYoBMRERERERGZAAboRERERERERCaAAToRERERERGRCWCATkRERERERGQCGKATERERERERmQAG6EREREREREQmgAE6ERERERERkQlggE5ERERERERkAhigExEREREREZkABuhEREREREREJoABOhEREREREZEJYIBOREREREREZAIYoBMRERERERGZAAboRERERERERCaAAToRERERERGRCWCATkRERERERGQCGKATERERERERmQAG6EREREREREQmgAE6ERERERERkQlggE5ERERERERkAhigExEREREREZkABuhEREREREREJoABOhEREREREZEJYIBOREREREREZAIYoBMRERERERGZAAboRERERERERCaAAToRERERERGRCWCATkRERERERGQCGKATERERERERmQAG6EREREREREQmgAE6ERERERERkQlggE5ERERERERkAhigExEREREREZkABuhEREREREREJoABOhEREREREZEJYIBOREREREREZAIYoBMRERERERGZAAboRERERERERCaAAToREZmcoUOHYujQocZehs7SpUshCIKxl9Fk1q9fD0EQcObMGWMvhZrJ008/jVGjRhl7GXWmUCjg7++Pr776ythLISJqEgzQiYjqQBvIWFlZITExsdL9Q4cORefOnQEA586dgyAIWLx4cbXnu337NgRBwIsvvgigPBBMT0/XHTNv3jwIgqD7sLOzQ3Bw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LAwbN25ETk5OlVtJXn75Zaxbtw6ff/653naYisLDw3H48GGoVCq9KomTJ0/CxsYG7dq10zv+yy+/xNKlS/F///d/ePXVVyudLzExESqVCs8//zyef/75SvcHBQXhX//6l15n9+joaADqihEiotaEJe5ERA0UEhKCWbNm4dtvv9V1J76XtbU1HnzwQezatQtff/01bG1t8cADDzT4uZcvX46//voLM2bMqFQqXpE2e/7KK69g6tSpeh/Tp0/HkCFDai1zl0qllbLfmzdv1u3lrquePXvC3d0d33zzjd64r/Xr11cZgNWFh4cHhg4dim+//bbKTF9aWpru84yMDL377OzsEBoaWmUJr5Y2+1rx+5GTk4N169YZtL79+/dXebt277i2dF3bOfve74e3tzfCw8Px3Xff6d135coV/PXXX7jvvvsAABKJBJMmTcLvv/+OM2fOVHq+qqoZlixZouu8b+jYuKqEhIRgypQpWL9+PVJSUiCVSjFlyhRs3bq1yjcMKv5MbG1tAVS+bu15T5w4ofea+eOPPxql8/+97n1tSCQSXZa/ptdHczP09wAA9OvXD6Io4uzZs5Xu+/jjj/Gf//wHr7/+Ov71r39Ve46pU6fi7t27+PXXX3W3paenY/PmzZgwYYLe/vSff/4Zzz//PB555BF8+umnVZ6vc+fO2LZtW6WPTp06ISAgANu2bcOjjz6q95izZ89CEAT069evxuslImppmEEnImoEb7zxBr7//nvcvHkTnTp1qvKYWbNmYcOGDdizZw8eeeQRXRBiiLKyMvzwww8A1GWfsbGx2LFjBy5duoRhw4bpjYaqysaNGxEeHg5/f/8q7584cSKee+45nDt3DhEREVUec//99+Ptt9/G/Pnz0b9/f1y+fBkbN26sd9bSwsIC7777Lp544gkMHz4cM2bMQHR0NNatW9comdAvv/wSAwcORJcuXfDYY48hODgYd+/exfHjx5GQkKCb396xY0cMHToUPXr0gIuLC86cOYMtW7bg2Wefrfbco0eP1mVWn3jiCeTn52PVqlXw8PCosWGg1gMPPICgoCBMmDABISEhKCgowL59+/D777+jV69emDBhAgD1GzsdO3bEzz//jHbt2sHFxQWdO3dG586d8fHHH2PcuHHo168fHn30URQVFeGLL76Ao6Oj3qz0999/H3/99ReGDBmCxx9/HB06dEBycjI2b96MI0eOwMnJqdL6Pv74Y+Tk5OCZZ56Bvb09Zs2aVbdvvsbLL7+MX375BZ9//jmWL1+O5cuX459//kGfPn3w2GOPoWPHjsjMzMS5c+ewb98+3UzrkJAQODk54ZtvvoG9vT1sbW3Rp08fBAUFYeHChdiyZQvGjh2L6dOnIzIyEj/88ANCQkLqtcaaLFy4EJmZmRg+fDj8/PwQGxuLL774AuHh4UbJ3Db09wAADBw4EK6urti3b59e5cq2bdvwyiuvoG3btujQoYPuebRGjRqla3I3depU9O3bF/Pnz8e1a9fg5uaGr776CkqlEsuWLdM95tSpU5gzZw5cXV0xYsSISm8C9u/fH8HBwXBzc8OkSZMqrVWbMa/qvr1792LAgAFwdXWt9ZqJiFoUY7WPJyJqiSqOo7qXdnRTdWOBysrKRG9vbxGAuGvXriqPqW7MGgDdh42NjRgYGChOmTJF3LJlS6XRXKKoP57o7NmzIgBxyZIl1V5XTExMrSOaiouLxX//+9+it7e3aG1tLQ4YMEA8fvx4teOtNm/erPf46OjoKkdnffXVV2JQUJAol8vFnj17iocOHap0ztpUN6IqMjJSnDNnjujl5SVaWFiIvr6+4v333y9u2bJFd8y7774r9u7dW3RychKtra3FsLAw8b333hNLS0t1x1Q1Zm3Hjh1i165dRSsrKzEwMFD88MMPxbVr14oAxOjo6BrX+9NPP4kzZ84UQ0JCRGtra9HKykrs2LGj+MYbb4i5ubl6xx47dkzs0aOHaGlpWeka9+3bJw4YMEC0trYWHRwcxAkTJojXrl2r9HyxsbHinDlzRHd3d1Eul4vBwcHiM888oxtvV9XrWqlUig899JAok8nE7du3V3st1f28tYYOHSo6ODiI2dnZoiiK4t27d8VnnnlG9Pf3Fy0sLEQvLy9xxIgR4sqVK/Ue99tvv4kdO3YUZTJZpdfNJ598Ivr6+opyuVwcMGCAeObMGYNfh6JY/ciye3/OW7ZsEUePHi16eHiIlpaWYkBAgPjEE0+IycnJ1X4/7lXT74yKDBmzVtffA9V5/vnnxdDQUL3btNde3cc///yjd3xmZqb46KOPiq6urqKNjY04ZMiQSteovfbqPqoao1dRdWPWsrOzRUtLS3H16tUGXzMRUUshiGIzdOshIiIiIpMQFRWFsLAw7N69GyNGjDD2curs888/x0cffYTIyMhqmwASEbVUDNCJiIiIzMxTTz2FO3fu1HvGu7EoFAqEhIRg0aJFePrpp429HCKiRscAnYiIiIiIiMgEsIs7ERERERERkQlggE5ERERERERkAhigExEREREREZkABuhEREREREREJkBm7AVQ81KpVEhKSoK9vT0EQTD2coiIiIiIyEhEUUReXh58fHwgkTB3awoYoJuZpKQk+Pv7G3sZRERERERkIuLj4+Hn52fsZRAYoJsde3t7AOp/hA4ODkZeDRERERERGUtubi78/f11MQIZHwN0M6Mta3dwcGCATkRERERE3PpqQrjRgIiIiIiIiMgEMEAnIiIiIiIiMgEM0ImIiIiIiIhMAPegU5WUSiUUCoWxl0GtiIWFBaRSqbGXQURERERkshigkx5RFJGSkoLs7GxjL4VaIScnJ3h5ebERCRERERFRFRigkx5tcO7h4QEbGxsGUtQoRFFEYWEhUlNTAQDe3t5GXhERERERkelhgE46SqVSF5y7uroaeznUylhbWwMAUlNT4eHhwXJ3IiIiIqJ7sEkc6Wj3nNvY2Bh5JdRaaV9b7G9ARERERFQZA3SqhGXt1FT42iIiIiIiqh4DdCIiIiIiIiITwACdyEQtWbIEjz/+uLGXYbC+ffti69atxl4GEREREVGLxQCdWrx58+ZBEAQsX75c7/bt27frSqq3bt0KqVSKxMTEKs/Rtm1bvPjiiwCAoUOH4v/+7/909w0dOhSCIEAQBMjlcvj6+mLChAn49ddfK51HEARs37690u1PPPEEpFIpNm/ebNA1paSkYMWKFXjjjTea9DoNvS6tsLAwyOVypKSkVLpv8eLFWLRoEVQqlUHXSERERERE+higU6tgZWWFDz/8EFlZWVXeP3HiRLi6uuK7776rdN+hQ4dw584dPProo9We/7HHHkNycjIiIyOxdetWdOzYETNnzjQow11YWIhNmzbhlVdewdq1aw26ntWrV6N///5o06aN3u2NfZ11ua4jR46gqKgIU6dOrfL848aNQ15eHnbv3m3QNRIRERERkT4G6NQqjBw5El5eXvjggw+qvN/CwgKzZ8/G+vXrK923du1a9OnTB506dar2/DY2NvDy8oKfnx/69u2LDz/8EN9++y1WrVqFffv21bi2zZs3o2PHjli0aBEOHTqE+Pj4Wq9n06ZNmDBhQqXbG/s663Jda9aswcMPP4zZs2dX+UaDVCrFfffdh02bNtV6fUREREREVBkDdKqRKIooLC1r9g9RFOu0TqlUivfffx9ffPEFEhISqjzm0Ucfxe3bt3Ho0CHdbfn5+diyZUuN2fPqzJ07F87OzjWWhAPqwHbWrFlwdHTEuHHjqgyeK8rMzMS1a9fQs2fPSvc1x3VWdV15eXnYvHkzZs2ahVGjRiEnJweHDx+u9NjevXtXeTsREREREdVOZuwFkGkrUijR8c09zf68194eAxvLur08H3zwQYSHh+Ott97CmjVrKt3fsWNH9O3bF2vXrsXgwYMBAL/88gtEUcTMmTPrvEaJRIJ27dohJiam2mNu376NEydO6ILdWbNm4cUXX8TixYurHTkWFxcHURTh4+NT5f1NfZ1VXdemTZvQtm1bXfZ95syZWLNmDQYNGqT3WB8fH8THx0OlUkEi4ft/RERERER1wb+gqVX58MMP8d133+H69etV3r9gwQJs2bIFeXl5ANRl39OmTYO9vX29nk8UxRpne69duxZjxoyBm5sbAOC+++5DTk4O/v7772ofU1RUBEC937w6TX2d917X2rVrMWvWLN3Xs2bNwubNm3Xn17K2toZKpUJJSYlBz0NEREREROWYQacaWVtIce3tMUZ53voYPHgwxowZg9deew3z5s2rdP/MmTPxwgsv4JdffsHgwYNx9OjRavdz10apVOL27dvo1atXtfd/9913SElJgUwm07t97dq1GDFiRJWP0wbzWVlZcHd3r/KYprzOe6/r2rVrOHHiBE6dOoVXX31V77hNmzbhscce092WmZkJW1tbWFtbG/RcRETmolihxOSvjsHfxRrfzq68hYmIiAhggE61EAShzqXmxrZ8+XKEh4ejffv2le6zt7fHtGnTsHbtWkRGRqJdu3aVyrQN9d133yErKwtTpkyp8v5du3YhLy8P58+fh1Ra/obDlStXMH/+fGRnZ8PJyanS40JCQuDg4IBr166hXbt21T5/U13nvde1Zs0aDB48GF9++aXecevWrcOaNWv0AvQrV66ge/fuBj0PEZE5uZqUg2vJubiWnIu4jEIEuNoYe0lERGSCWlbkRWSALl264JFHHsF///vfKu9/9NFHMWjQIFy/fl0vI1yTwsJCpKSkoKysDAkJCdi2bRs+++wzPPXUUxg2bFiVj1mzZg3Gjx+P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YSxdupSxY8cSHR3NxIkTC/Q5zuCJbbl7924A/ve//zFx4kRq167NhAkT6N69O9u3by/Ri5ae2H7/9sknn9C7d2+qV69eoM9wFk9sS5vNxh9//MGAAQMoV64cdrudiIgI5syZQ4UKFQr0OY7mie145ZVXMmbMGF577TUeeughEhMTefLJJwGIjo4u0Oc4iru1X0EUJT4pPvWgCwD33XcfmzZt4ttvvy3yMTZt2sR1113HuHHj6NWrFwAZGRncfPPNPPfcczRs2DDP93399deULVs2+7Z48eIix+AOPL0tDx06RJ8+fRg8eDAjR44s8jkUhie32X/+8x/Wrl3L3Llz8fHxYdiwYViWVeTzKC5PbMvJkyeTkJDA2LFjixyzo3hi+wGMGTOG7t2707JlS0aNGsWECROYPHkyKSkpRT6P4vLEtszMzATgv//9L4MGDaJdu3ZMmTIFm83G999/X+TzKApPbL9zHTx4kN9//50777yzyPE7iie2pWVZ3HfffURERLB48WJWrlzJgAEDuOaaa0o8scziie3YrFkzPv/8cyZMmEBwcDCVK1emTp06REZG5upVLwme2H7iIi4eYi9u4L777rOqV69u7d69O9f2+fPnW4B18uTJXNtr1qxpTZw4Mde2zZs3WxEREdZTTz2Va/vJkyctwPLx8cm+2Wy27G3z58+34uPjrR07dmTfkpKSrF27duU5F+ayyy6zHnzwwfPOwV3moHt6Wx46dMhq0KCBddttt+War+VMnt5m5zpw4IAFWEuXLi18QziAp7blddddZ9nt9lzHzjrusGHDHNM4BeCp7ZeXTZs2WYC1bdu2wjeEA3hqWy5YsMACrMWLF+fap2PHjufF4Uye2n7nev75563w8HCX1+Tw1Lb8448/LLvdbsXFxeXap379+tb48eOL0SJF46nteK6YmBgrISHBOn36tGW3263vvvuu6A1SSO7YfufKbw56YeITx1GC7sUyMzOt++67z6pataq1ffv2817PKgwxffr07G3btm07rzDEpk2brIiICOs///nPecfIyMiwNm7cmOs2evRoq1GjRtbGjRvzrTKcVfjj9ddfz94WFxfntkXiSkNbHjx40GrQoIE1dOhQKz09vUjtUBiloc3+bd++fRZgLVy4sCBN4DCe3pb79u3Lddzff//dAqzp06dbBw4cKHK7FJSnt19evvrqK8tut1uxsbEFagNH8fS2zHp+bpG41NRUKyIiwvrggw8K3yCF5Ontd+6+derUcepKIBfj6W35888/W3a73UpISMj13oYNG1ovvvhi4RqjGDy9HfPyySefWMHBweclnc7gzu13rosVibtYfOJYStC92OjRo63Q0FBr0aJFuZZEOfeq2qhRo6yaNWtaCxYssP7555/zlpHauHGjFR4ebt166625jnH06NF8P7eglSVffvllq3z58tbMmTOtDRs2WNddd915S5Ds27fPWrt2rfXcc89ZZcuWtdauXWutXbv2vD9ozubpbXnw4EGrfv36Vo8ePayDBw/m+nxn8fQ2W758uTV58mRr7dq11t69e6358+dbXbt2terVq2clJycXvWGKwNPb8t/y+6LgLJ7efkuXLrXeeOMNa926ddauXbusr776ygoPDy/R0QdZPL0tLcuyHnroIatatWrW77//bm3bts268847rYiIiBK52FEa2s+yTO8vYG3durXwjeAgnt6Wx44dsypWrGgNHDjQWrdunRUVFWU99thjlp+fn7Vu3bqiN0wheXo7WpZlTZ482Vq9erUVFRVlvf3221ZQUJD15ptvFq1BCsnd2+/EiRPW2rVrrVmzZlmA9e2331pr167N9f3vYvGJ4ylB92JAnrcpU6Zk73PmzBnr3nvvtSpUqGAFBwdb119/fa5f2nHjxuV5jFq1auX7uQX9TyMzM9N65plnrMjISCsgIMDq0aOHFRUVlWuf22+/Pc/PL+keTE9vyylTpuR7Ds7i6W22YcMG64orrrDCwsKsgIAAq3bt2taoUaOsgwcPFqU5isXT2/LfSjpB9/T2W716tdWpUycrNDTUCgwMtJo0aWK99NJLJX6hyLI8vy0ty/SYP/roo1ZERIRVrlw5q2fPntamTZsK2xRFUhraz7Is66abbnL5OsmloS1XrVpl9erVywoLC7PKlStnde7c2Zo9e3Zhm6JYSkM73nbbbVZYWJjl7+9vtWzZ0vriiy8K2wxF5u7tl9/3v3HjxhU4PnE8m2W5sJqRiIiIiIiIiACq4i4iIiIiIiLiFpSgi4iIiIiIiLgBJegiIiIiIiIibkAJuoiIiIiIiIgbUIIuIiIiIiIi4gaUoIuIiIiIiIi4ASXoIiIiIiIiIm5ACbqIiIiIiIiIG1CCLiIi4qGGDx+OzWbDZrPh5+dHZGQkV111FZ9++imZmZkFPs5nn31G+fLlnReoiIiIFIgSdBEREQ/Wp08foqOj2bt3L7/99htXXHEFDz30EP379yc9Pd3V4YmIiEghKEEXERHxYAEBAVSuXJlq1arRtm1bnnrqKWbOnMlvv/3GZ599BsDEiRNp0aIFZcqUoUaNGtx7772cPn0agEWLFjFixAji4uKye+P/97//AZCSksJjjz1GtWrVKFOmDJ06dWLRokWuOVEREREvoARdRESklLnyyitp1aoVM2bMAMBut/PWW2+xefNmPv/8cxYsWMDjjz8OQNeuXZk0aRIhISFER0cTHR3NY489BsD999/PsmXL+Pbbb9mwYQODBw+mT58+7Nixw2XnJiIiUprZLMuyXB2EiIiIFN7w4cM5deoUP/3003mvDR06lA0bNrBly5bzXps+fTqjRo3i+PHjgJmD/vDDD3Pq1Knsffbv30/dunXZv38/VatWzd7es2dPOnbsyEsvveTw8xEREfF2vq4OQERERBzPsixsNhsAf/zxB+PHj2fbtm3Ex8eTnp5OcnIySUlJBAcH5/n+jRs3kpGRQcOGDXNtT0lJoWLFik6PX0RExBspQRcRESmFtm7dSp06ddi7dy/9+/dn9OjRvPjii4SFhfH3339z5513kpqamm+Cfvr0aXx8fFi9ejU+Pj65XitbtmxJnIKIiIjXUYIuIiJSyixYsICNGzfyyCOPsHr1ajIzM5kwYQJ2uyk989133+Xa39/fn4yMjFzb2rRpQ0ZGBkePHuXSSy8tsdhFRES8mRJ0ERERD5aSkkJMTAwZGRkcOXKEOXPmMH78ePr378+wYcPYtGkTaWlpTJ48mWuuuYYlS5bw/vvv5zpG7dq1OX36NPPnz6dVq1YEBwfTsGFDbrnlFoYNG8aECRNo06YNx44dY/78+bRs2ZKrr77aRWcsIiJSeqmKu4iIiAebM2cOVapUoXbt2vTp04eFCxfy1ltvMXPmTHx8fGjVqhUTJ07klVdeoXnz5nz99deMHz8+1zG6du3KqFGjGDJkCOHh4bz66qsATJkyhWHDhvHoo4/SqFEjBgwYwKpVq6hZs6YrTlVERKTUUxV3ERERERERETegHnQRERERERERN6AEXURERERERMQNKEEXERERERERcQNK0EVERERERETcgBJ0ERERERERETegBF1ERERERETEDShBFxEREREREXEDStBFRERERERE3IASdBERERERERE3oARdRERERERExA0oQRcRERERERFxA0rQRURERERERNyAEnQRERERERERN6AEXURERERERMQNKEEXERERERERcQNK0EVERERERETcgBJ0ERERERERETegBF1ERERERETEDShBFxEREREREXEDStBFRERERERE3IASdBERERERERE3oARdRERERERExA0oQRcRERERERFxA0rQRURERERERNyAEnQRERERERERN/D/vF9FpL49AeIAAAAASUVORK5CYII=", + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "\n", + "Image(filename=\"coding/nvidia_tesla_2024_ytd.png\") # type: ignore" + ] } ], "metadata": { diff --git a/python/packages/autogen-core/src/autogen_core/application/_single_threaded_agent_runtime.py b/python/packages/autogen-core/src/autogen_core/application/_single_threaded_agent_runtime.py index c21678ec9909..38066f1f526e 100644 --- a/python/packages/autogen-core/src/autogen_core/application/_single_threaded_agent_runtime.py +++ b/python/packages/autogen-core/src/autogen_core/application/_single_threaded_agent_runtime.py @@ -372,13 +372,13 @@ async def _process_publish(self, message_envelope: PublishMessageEnvelope) -> No async def _on_message(agent: Agent, message_context: MessageContext) -> Any: with self._tracer_helper.trace_block("process", agent.id, parent=None): - return await agent.on_message( - message_envelope.message, - ctx=message_context, - ) + with MessageHandlerContext.populate_context(agent.id): + return await agent.on_message( + message_envelope.message, + ctx=message_context, + ) - with MessageHandlerContext.populate_context(agent.id): - future = _on_message(agent, message_context) + future = _on_message(agent, message_context) responses.append(future) try: diff --git a/python/packages/autogen-core/src/autogen_core/components/model_context/__init__.py b/python/packages/autogen-core/src/autogen_core/components/model_context/__init__.py index 55ea2cac1469..8431a2e80dfc 100644 --- a/python/packages/autogen-core/src/autogen_core/components/model_context/__init__.py +++ b/python/packages/autogen-core/src/autogen_core/components/model_context/__init__.py @@ -2,4 +2,8 @@ from ._chat_completion_context import ChatCompletionContext from ._head_and_tail_chat_completion_context import HeadAndTailChatCompletionContext -__all__ = ["ChatCompletionContext", "BufferedChatCompletionContext", "HeadAndTailChatCompletionContext"] +__all__ = [ + "ChatCompletionContext", + "BufferedChatCompletionContext", + "HeadAndTailChatCompletionContext", +] diff --git a/python/packages/autogen-core/tests/test_runtime.py b/python/packages/autogen-core/tests/test_runtime.py index 398735f9cfcd..762a05a4edc8 100644 --- a/python/packages/autogen-core/tests/test_runtime.py +++ b/python/packages/autogen-core/tests/test_runtime.py @@ -41,7 +41,9 @@ def agent_factory() -> NoopAgent: assert agent.id == id return agent - await runtime.register_factory(type=AgentType("name1"), agent_factory=agent_factory, expected_class=NoopAgent) + await NoopAgent.register(runtime, "name1", agent_factory) + + # await runtime.register_factory(type=AgentType("name1"), agent_factory=agent_factory, expected_class=NoopAgent) with pytest.raises(ValueError): await runtime.register_factory(type=AgentType("name1"), agent_factory=agent_factory, expected_class=NoopAgent)