From b0b0825c1d65b19ff9625c99fb1fcf7ab6d826da Mon Sep 17 00:00:00 2001 From: Victor Dibia Date: Wed, 2 Oct 2024 17:25:14 -0700 Subject: [PATCH 1/3] add logging to agentchat --- .../src/autogen_agentchat/teams/_base_team.py | 9 ++ .../src/autogen_agentchat/teams/_utils.py | 89 +++++++++++++++++++ .../group_chat/_base_chat_agent_container.py | 13 +-- .../group_chat/_base_group_chat_manager.py | 13 +-- .../teams/group_chat/_events.py | 6 +- .../group_chat/_round_robin_group_chat.py | 35 +++++--- .../_round_robin_group_chat_manager.py | 4 +- 7 files changed, 144 insertions(+), 25 deletions(-) create mode 100644 python/packages/autogen-agentchat/src/autogen_agentchat/teams/_utils.py 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 index 4ef19eb3d..5dc544987 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_team.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_team.py @@ -1,7 +1,16 @@ from dataclasses import dataclass +import logging from typing import List, Protocol from autogen_agentchat.agents._base_chat_agent import ChatMessage +from autogen_core.application.logging import EVENT_LOGGER_NAME + +from ._utils import AgentChatLogHandler + +logger = logging.getLogger(EVENT_LOGGER_NAME + ".agentchatchat") +logger.setLevel(logging.INFO) +log_handler = AgentChatLogHandler(filename="log.jsonl") +logger.handlers = [log_handler] @dataclass diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_utils.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_utils.py new file mode 100644 index 000000000..b9ccd97e9 --- /dev/null +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_utils.py @@ -0,0 +1,89 @@ +from datetime import datetime +import json +import logging +import sys +from typing import Optional, Union, List, Dict, Any, Sequence +from dataclasses import asdict, is_dataclass + +from .group_chat._events import ContentPublishEvent +from ..agents import ChatMessage, TextMessage, MultiModalMessage, ToolCallMessage, ToolCallResultMessage, StopMessage +from autogen_core.components import FunctionCall, Image +from autogen_core.components.models import FunctionExecutionResult + +ContentType = Union[str, List[Union[str, Image]], + List[FunctionCall], List[FunctionExecutionResult]] + + +class AgentChatLogHandler(logging.Handler): + def __init__(self, filename: Optional[str] = None) -> None: + super().__init__() + self.filename = filename + self.file_handler: Optional[logging.FileHandler] = None + if filename: + self.file_handler = logging.FileHandler(filename) + + def emit(self, record: logging.LogRecord) -> None: + try: + ts = datetime.fromtimestamp(record.created).isoformat() + if isinstance(record.msg, ContentPublishEvent): + console_message = ( + f"\n{'-'*75} \n" + f"\033[91m[{ts}], {record.msg.agent_message.source}:\033[0m\n" + f"\n{self.serialize_content(record.msg.agent_message.content)}" + ) + # print , flush true + sys.stdout.write(console_message) + + log_entry = json.dumps( + { + "timestamp": ts, + "source": record.msg.agent_message.source, + "message": self.serialize_content(record.msg.agent_message.content), + "type": "OrchestrationEvent", + }, + default=self.json_serializer, + ) + + if self.file_handler: + file_record = logging.LogRecord( + name=record.name, + level=record.levelno, + pathname=record.pathname, + lineno=record.lineno, + msg=log_entry, + args=(), + exc_info=record.exc_info, + ) + self.file_handler.emit(file_record) + else: + sys.stderr.write(log_entry) + except Exception: + self.handleError(record) + + def serialize_content( + self, content: Union[ContentType, Sequence[ChatMessage], ChatMessage] + ) -> Union[List[Any], Dict[str, Any], str]: + if isinstance(content, (str, list)): + return content + elif isinstance(content, (TextMessage, MultiModalMessage, ToolCallMessage, ToolCallResultMessage, StopMessage)): + return asdict(content) + elif isinstance(content, Image): + return {"type": "image", "data": content.data_uri} + elif isinstance(content, FunctionCall): + return {"type": "function_call", "name": content.name, "arguments": content.arguments} + elif isinstance(content, FunctionExecutionResult): + return {"type": "function_execution_result", "content": content.content} + return str(content) + + @staticmethod + def json_serializer(obj: Any) -> Any: + if is_dataclass(obj) and not isinstance(obj, type): + return asdict(obj) + elif isinstance(obj, type): + return str(obj) + return str(obj) + + def close(self) -> None: + if self.file_handler: + self.file_handler.close() + super().close() diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py index c9cdcd5f6..f17039fda 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py @@ -1,11 +1,13 @@ +import logging import asyncio -import sys from typing import List + from autogen_core.base import AgentId, AgentType, MessageContext from autogen_core.components import DefaultTopicId, event from autogen_core.components.models import FunctionExecutionResult from autogen_core.components.tool_agent import ToolException +from autogen_core.application.logging import EVENT_LOGGER_NAME from ...agents import BaseChatAgent, MultiModalMessage, StopMessage, TextMessage, ToolCallMessage, ToolCallResultMessage from ._events import ContentPublishEvent, ContentRequestEvent @@ -29,6 +31,7 @@ class BaseChatAgentContainer(SequentialRoutedAgent): self._agent = agent self._message_buffer: List[TextMessage | MultiModalMessage | StopMessage] = [] self._tool_agent_id = AgentId(type=tool_agent_type, key=self.id.key) + self._logger = self.logger = logging.getLogger(EVENT_LOGGER_NAME + f".agentchatchat") @event async def handle_content_publish(self, message: ContentPublishEvent, ctx: MessageContext) -> None: @@ -48,9 +51,8 @@ class BaseChatAgentContainer(SequentialRoutedAgent): # Handle tool calls. while isinstance(response, ToolCallMessage): - # TODO: use logging instead of print - sys.stdout.write(f"{'-'*80}\n{self._agent.name}:\n{response.content}\n") - # Execute functions called by the model by sending messages to tool agent. + self._logger.info(ContentPublishEvent(agent_message=response)) + results: List[FunctionExecutionResult | BaseException] = await asyncio.gather( *[ self.send_message( @@ -73,8 +75,7 @@ class BaseChatAgentContainer(SequentialRoutedAgent): # Create a new tool call result message. feedback = ToolCallResultMessage(content=function_results, source=self._tool_agent_id.type) # TODO: use logging instead of print - sys.stdout.write(f"{'-'*80}\n{self._tool_agent_id.type}:\n{feedback.content}\n") - # Forward the feedback to the agent. + self._logger.info(ContentPublishEvent(agent_message=feedback, source=self._tool_agent_id.type)) response = await self._agent.on_messages([feedback], ctx.cancellation_token) # Publish the response. 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 index 147d0813b..a92ce2391 100644 --- 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 @@ -1,12 +1,13 @@ -import sys +import logging from typing import List from autogen_core.base import MessageContext, TopicId from autogen_core.components import event -from ...agents import MultiModalMessage, StopMessage, TextMessage +from ...agents import StopMessage, TextMessage, ChatMessage from ._events import ContentPublishEvent, ContentRequestEvent from ._sequential_routed_agent import SequentialRoutedAgent +from autogen_core.application.logging import EVENT_LOGGER_NAME class BaseGroupChatManager(SequentialRoutedAgent): @@ -48,7 +49,8 @@ class BaseGroupChatManager(SequentialRoutedAgent): 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[TextMessage | MultiModalMessage | StopMessage] = [] + self._message_thread: List[ChatMessage] = [] + self._logger = self.logger = logging.getLogger(EVENT_LOGGER_NAME + ".agentchatchat") @event async def handle_content_publish(self, message: ContentPublishEvent, ctx: MessageContext) -> None: @@ -62,7 +64,8 @@ class BaseGroupChatManager(SequentialRoutedAgent): group_chat_topic_id = TopicId(type=self._group_topic_type, source=ctx.topic_id.source) # TODO: use something else other than print. - sys.stdout.write(f"{'-'*80}\n{message.agent_message.source}:\n{message.agent_message.content}\n") + + self._logger.info(ContentPublishEvent(agent_message=message.agent_message)) # Process event from parent. if ctx.topic_id.type == self._parent_topic_type: @@ -105,7 +108,7 @@ class BaseGroupChatManager(SequentialRoutedAgent): 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[TextMessage | MultiModalMessage | StopMessage]) -> str: + async def select_speaker(self, thread: List[ChatMessage]) -> 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/_events.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_events.py index 70ab47e4b..2f20d72fc 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_events.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_events.py @@ -1,6 +1,7 @@ +from typing import Optional from pydantic import BaseModel -from ...agents import MultiModalMessage, StopMessage, TextMessage +from ...agents import ChatMessage class ContentPublishEvent(BaseModel): @@ -9,8 +10,9 @@ class ContentPublishEvent(BaseModel): content of the event. """ - agent_message: TextMessage | MultiModalMessage | StopMessage + agent_message: ChatMessage """The message published by the agent.""" + source: Optional[str] = None class ContentRequestEvent(BaseModel): 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 index d2f21d8ef..a35b8d18b 100644 --- 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 @@ -8,6 +8,7 @@ from autogen_core.components import ClosureAgent, TypeSubscription from autogen_core.components.tool_agent import ToolAgent from autogen_core.components.tools import Tool + from ...agents import BaseChatAgent, TextMessage from .._base_team import BaseTeam, TeamRunResult from ._base_chat_agent_container import BaseChatAgentContainer @@ -54,7 +55,12 @@ class RoundRobinGroupChat(BaseTeam): """ - def __init__(self, participants: List[BaseChatAgent], *, tools: List[Tool] | None = None): + def __init__( + self, + participants: List[BaseChatAgent], + *, + tools: List[Tool] | None = None + ): if len(participants) == 0: raise ValueError("At least one participant is required.") if len(participants) != len(set(participant.name for participant in participants)): @@ -69,7 +75,8 @@ class RoundRobinGroupChat(BaseTeam): def _factory() -> BaseChatAgentContainer: id = AgentInstantiationContext.current_agent_id() assert id == AgentId(type=agent.name, key=self._team_id) - container = BaseChatAgentContainer(parent_topic_type, agent, tool_agent_type) + container = BaseChatAgentContainer( + parent_topic_type, agent, tool_agent_type) assert container.id == id return container @@ -88,7 +95,8 @@ class RoundRobinGroupChat(BaseTeam): # Register the tool agent. tool_agent_type = await ToolAgent.register( - runtime, "tool_agent", lambda: ToolAgent("Tool agent for round-robin group chat", self._tools) + runtime, "tool_agent", lambda: ToolAgent( + "Tool agent for round-robin group chat", self._tools) ) # No subscriptions are needed for the tool agent, which will be called via direct messages. @@ -101,7 +109,8 @@ class RoundRobinGroupChat(BaseTeam): topic_type = participant.name # Register the participant factory. await BaseChatAgentContainer.register( - runtime, type=agent_type, factory=self._create_factory(group_topic_type, participant, tool_agent_type) + runtime, type=agent_type, factory=self._create_factory( + group_topic_type, participant, tool_agent_type) ) # Add subscriptions for the participant. await runtime.add_subscription(TypeSubscription(topic_type=topic_type, agent_type=agent_type)) @@ -123,13 +132,16 @@ class RoundRobinGroupChat(BaseTeam): ) # 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) + 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) + 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) + TypeSubscription(topic_type=team_topic_type, + agent_type=group_chat_manager_agent_type.type) ) group_chat_messages: List[ChatMessage] = [] @@ -144,7 +156,8 @@ class RoundRobinGroupChat(BaseTeam): type="collect_group_chat_messages", closure=collect_group_chat_messages, subscriptions=lambda: [ - TypeSubscription(topic_type=group_topic_type, agent_type="collect_group_chat_messages") + TypeSubscription(topic_type=group_topic_type, + agent_type="collect_group_chat_messages") ], ) @@ -153,9 +166,11 @@ class RoundRobinGroupChat(BaseTeam): # 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) + group_chat_manager_topic_id = TopicId( + type=group_chat_manager_topic_type, source=self._team_id) await runtime.publish_message( - ContentPublishEvent(agent_message=TextMessage(content=task, source="user")), + ContentPublishEvent(agent_message=TextMessage( + content=task, source="user")), topic_id=team_topic_id, ) await runtime.publish_message(ContentRequestEvent(), topic_id=group_chat_manager_topic_id) 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 index a0c5a97e9..713859340 100644 --- 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 @@ -1,6 +1,6 @@ from typing import List -from ...agents import MultiModalMessage, StopMessage, TextMessage +from ...agents import ChatMessage from ._base_group_chat_manager import BaseGroupChatManager @@ -22,7 +22,7 @@ class RoundRobinGroupChatManager(BaseGroupChatManager): ) self._next_speaker_index = 0 - async def select_speaker(self, thread: List[TextMessage | MultiModalMessage | StopMessage]) -> str: + async def select_speaker(self, thread: List[ChatMessage]) -> 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) From 13c135100f6eca36940c730d70b92b110992e6a7 Mon Sep 17 00:00:00 2001 From: Victor Dibia Date: Thu, 3 Oct 2024 10:03:17 -0700 Subject: [PATCH 2/3] make logging independent module --- .../src/autogen_agentchat/teams/_base_team.py | 8 +- .../group_chat/_base_chat_agent_container.py | 4 +- .../group_chat/_base_group_chat_manager.py | 2 +- .../group_chat/_round_robin_group_chat.py | 34 ++---- .../teams/{_utils.py => logging.py} | 106 +++++++++--------- 5 files changed, 72 insertions(+), 82 deletions(-) rename python/packages/autogen-agentchat/src/autogen_agentchat/teams/{_utils.py => logging.py} (68%) 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 index 5dc544987..1719d901d 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_team.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_team.py @@ -5,12 +5,12 @@ from typing import List, Protocol from autogen_agentchat.agents._base_chat_agent import ChatMessage from autogen_core.application.logging import EVENT_LOGGER_NAME -from ._utils import AgentChatLogHandler +from .logging import ConsoleLogHandler, EVENT_LOGGER_NAME -logger = logging.getLogger(EVENT_LOGGER_NAME + ".agentchatchat") +logger = logging.getLogger(EVENT_LOGGER_NAME) logger.setLevel(logging.INFO) -log_handler = AgentChatLogHandler(filename="log.jsonl") -logger.handlers = [log_handler] +console_handler = ConsoleLogHandler() +logger.addHandler(console_handler) @dataclass diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py index f17039fda..b38665b3b 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py @@ -7,11 +7,11 @@ from autogen_core.base import AgentId, AgentType, MessageContext from autogen_core.components import DefaultTopicId, event from autogen_core.components.models import FunctionExecutionResult from autogen_core.components.tool_agent import ToolException -from autogen_core.application.logging import EVENT_LOGGER_NAME from ...agents import BaseChatAgent, MultiModalMessage, StopMessage, TextMessage, ToolCallMessage, ToolCallResultMessage from ._events import ContentPublishEvent, ContentRequestEvent from ._sequential_routed_agent import SequentialRoutedAgent +from ..logging import EVENT_LOGGER_NAME class BaseChatAgentContainer(SequentialRoutedAgent): @@ -31,7 +31,7 @@ class BaseChatAgentContainer(SequentialRoutedAgent): self._agent = agent self._message_buffer: List[TextMessage | MultiModalMessage | StopMessage] = [] self._tool_agent_id = AgentId(type=tool_agent_type, key=self.id.key) - self._logger = self.logger = logging.getLogger(EVENT_LOGGER_NAME + f".agentchatchat") + self._logger = self.logger = logging.getLogger(EVENT_LOGGER_NAME) @event async def handle_content_publish(self, message: ContentPublishEvent, ctx: MessageContext) -> None: 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 index a92ce2391..4743e5288 100644 --- 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 @@ -7,7 +7,7 @@ from autogen_core.components import event from ...agents import StopMessage, TextMessage, ChatMessage from ._events import ContentPublishEvent, ContentRequestEvent from ._sequential_routed_agent import SequentialRoutedAgent -from autogen_core.application.logging import EVENT_LOGGER_NAME +from ..logging import EVENT_LOGGER_NAME class BaseGroupChatManager(SequentialRoutedAgent): 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 index a35b8d18b..5aaf02264 100644 --- 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 @@ -55,12 +55,7 @@ class RoundRobinGroupChat(BaseTeam): """ - def __init__( - self, - participants: List[BaseChatAgent], - *, - tools: List[Tool] | None = None - ): + def __init__(self, participants: List[BaseChatAgent], *, tools: List[Tool] | None = None): if len(participants) == 0: raise ValueError("At least one participant is required.") if len(participants) != len(set(participant.name for participant in participants)): @@ -75,8 +70,7 @@ class RoundRobinGroupChat(BaseTeam): def _factory() -> BaseChatAgentContainer: id = AgentInstantiationContext.current_agent_id() assert id == AgentId(type=agent.name, key=self._team_id) - container = BaseChatAgentContainer( - parent_topic_type, agent, tool_agent_type) + container = BaseChatAgentContainer(parent_topic_type, agent, tool_agent_type) assert container.id == id return container @@ -95,8 +89,7 @@ class RoundRobinGroupChat(BaseTeam): # Register the tool agent. tool_agent_type = await ToolAgent.register( - runtime, "tool_agent", lambda: ToolAgent( - "Tool agent for round-robin group chat", self._tools) + runtime, "tool_agent", lambda: ToolAgent("Tool agent for round-robin group chat", self._tools) ) # No subscriptions are needed for the tool agent, which will be called via direct messages. @@ -109,8 +102,7 @@ class RoundRobinGroupChat(BaseTeam): topic_type = participant.name # Register the participant factory. await BaseChatAgentContainer.register( - runtime, type=agent_type, factory=self._create_factory( - group_topic_type, participant, tool_agent_type) + runtime, type=agent_type, factory=self._create_factory(group_topic_type, participant, tool_agent_type) ) # Add subscriptions for the participant. await runtime.add_subscription(TypeSubscription(topic_type=topic_type, agent_type=agent_type)) @@ -132,16 +124,13 @@ class RoundRobinGroupChat(BaseTeam): ) # 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) + 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) + 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) + TypeSubscription(topic_type=team_topic_type, agent_type=group_chat_manager_agent_type.type) ) group_chat_messages: List[ChatMessage] = [] @@ -156,8 +145,7 @@ class RoundRobinGroupChat(BaseTeam): type="collect_group_chat_messages", closure=collect_group_chat_messages, subscriptions=lambda: [ - TypeSubscription(topic_type=group_topic_type, - agent_type="collect_group_chat_messages") + TypeSubscription(topic_type=group_topic_type, agent_type="collect_group_chat_messages") ], ) @@ -166,11 +154,9 @@ class RoundRobinGroupChat(BaseTeam): # 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) + group_chat_manager_topic_id = TopicId(type=group_chat_manager_topic_type, source=self._team_id) await runtime.publish_message( - ContentPublishEvent(agent_message=TextMessage( - content=task, source="user")), + ContentPublishEvent(agent_message=TextMessage(content=task, source="user")), topic_id=team_topic_id, ) await runtime.publish_message(ContentRequestEvent(), topic_id=group_chat_manager_topic_id) diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_utils.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/logging.py similarity index 68% rename from python/packages/autogen-agentchat/src/autogen_agentchat/teams/_utils.py rename to python/packages/autogen-agentchat/src/autogen_agentchat/teams/logging.py index b9ccd97e9..3d3a8ee86 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_utils.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/logging.py @@ -2,7 +2,7 @@ from datetime import datetime import json import logging import sys -from typing import Optional, Union, List, Dict, Any, Sequence +from typing import Union, List, Dict, Any, Sequence from dataclasses import asdict, is_dataclass from .group_chat._events import ContentPublishEvent @@ -10,56 +10,11 @@ from ..agents import ChatMessage, TextMessage, MultiModalMessage, ToolCallMessag from autogen_core.components import FunctionCall, Image from autogen_core.components.models import FunctionExecutionResult -ContentType = Union[str, List[Union[str, Image]], - List[FunctionCall], List[FunctionExecutionResult]] +EVENT_LOGGER_NAME = "autogen_agentchat.events" +ContentType = Union[str, List[Union[str, Image]], List[FunctionCall], List[FunctionExecutionResult]] -class AgentChatLogHandler(logging.Handler): - def __init__(self, filename: Optional[str] = None) -> None: - super().__init__() - self.filename = filename - self.file_handler: Optional[logging.FileHandler] = None - if filename: - self.file_handler = logging.FileHandler(filename) - - def emit(self, record: logging.LogRecord) -> None: - try: - ts = datetime.fromtimestamp(record.created).isoformat() - if isinstance(record.msg, ContentPublishEvent): - console_message = ( - f"\n{'-'*75} \n" - f"\033[91m[{ts}], {record.msg.agent_message.source}:\033[0m\n" - f"\n{self.serialize_content(record.msg.agent_message.content)}" - ) - # print , flush true - sys.stdout.write(console_message) - - log_entry = json.dumps( - { - "timestamp": ts, - "source": record.msg.agent_message.source, - "message": self.serialize_content(record.msg.agent_message.content), - "type": "OrchestrationEvent", - }, - default=self.json_serializer, - ) - - if self.file_handler: - file_record = logging.LogRecord( - name=record.name, - level=record.levelno, - pathname=record.pathname, - lineno=record.lineno, - msg=log_entry, - args=(), - exc_info=record.exc_info, - ) - self.file_handler.emit(file_record) - else: - sys.stderr.write(log_entry) - except Exception: - self.handleError(record) - +class BaseLogHandler(logging.Handler): def serialize_content( self, content: Union[ContentType, Sequence[ChatMessage], ChatMessage] ) -> Union[List[Any], Dict[str, Any], str]: @@ -83,7 +38,56 @@ class AgentChatLogHandler(logging.Handler): return str(obj) return str(obj) + +class ConsoleLogHandler(BaseLogHandler): + def emit(self, record: logging.LogRecord) -> None: + try: + ts = datetime.fromtimestamp(record.created).isoformat() + if isinstance(record.msg, ContentPublishEvent): + console_message = ( + f"\n{'-'*75} \n" + f"\033[91m[{ts}], {record.msg.agent_message.source}:\033[0m\n" + f"\n{self.serialize_content(record.msg.agent_message.content)}" + ) + sys.stdout.write(console_message) + sys.stdout.flush() + except Exception: + self.handleError(record) + + +class FileLogHandler(BaseLogHandler): + def __init__(self, filename: str) -> None: + super().__init__() + self.filename = filename + self.file_handler = logging.FileHandler(filename) + + def emit(self, record: logging.LogRecord) -> None: + try: + ts = datetime.fromtimestamp(record.created).isoformat() + if isinstance(record.msg, ContentPublishEvent): + log_entry = json.dumps( + { + "timestamp": ts, + "source": record.msg.agent_message.source, + "message": self.serialize_content(record.msg.agent_message.content), + "type": "OrchestrationEvent", + }, + default=self.json_serializer, + ) + + file_record = logging.LogRecord( + name=record.name, + level=record.levelno, + pathname=record.pathname, + lineno=record.lineno, + msg=log_entry, + args=(), + exc_info=record.exc_info, + ) + self.file_handler.emit(file_record) + except Exception: + self.handleError(record) + def close(self) -> None: - if self.file_handler: - self.file_handler.close() + self.file_handler.close() super().close() From d4078a722a0c4d3333c21f764edbd9eedcbd4be0 Mon Sep 17 00:00:00 2001 From: Victor Dibia Date: Thu, 3 Oct 2024 10:08:22 -0700 Subject: [PATCH 3/3] move logging module to root of agent_chat --- .../src/autogen_agentchat/{teams => }/logging.py | 4 ++-- .../src/autogen_agentchat/teams/_base_team.py | 2 +- .../teams/group_chat/_base_chat_agent_container.py | 2 +- .../teams/group_chat/_base_group_chat_manager.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename python/packages/autogen-agentchat/src/autogen_agentchat/{teams => }/logging.py (95%) diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/logging.py b/python/packages/autogen-agentchat/src/autogen_agentchat/logging.py similarity index 95% rename from python/packages/autogen-agentchat/src/autogen_agentchat/teams/logging.py rename to python/packages/autogen-agentchat/src/autogen_agentchat/logging.py index 3d3a8ee86..ce7b0a19c 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/logging.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/logging.py @@ -5,8 +5,8 @@ import sys from typing import Union, List, Dict, Any, Sequence from dataclasses import asdict, is_dataclass -from .group_chat._events import ContentPublishEvent -from ..agents import ChatMessage, TextMessage, MultiModalMessage, ToolCallMessage, ToolCallResultMessage, StopMessage +from .teams.group_chat._events import ContentPublishEvent +from .agents import ChatMessage, TextMessage, MultiModalMessage, ToolCallMessage, ToolCallResultMessage, StopMessage from autogen_core.components import FunctionCall, Image from autogen_core.components.models import FunctionExecutionResult 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 index 1719d901d..5a76d7f9b 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_team.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/_base_team.py @@ -5,7 +5,7 @@ from typing import List, Protocol from autogen_agentchat.agents._base_chat_agent import ChatMessage from autogen_core.application.logging import EVENT_LOGGER_NAME -from .logging import ConsoleLogHandler, EVENT_LOGGER_NAME +from ..logging import ConsoleLogHandler, EVENT_LOGGER_NAME logger = logging.getLogger(EVENT_LOGGER_NAME) logger.setLevel(logging.INFO) diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py index b38665b3b..ef3af5d7e 100644 --- a/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py +++ b/python/packages/autogen-agentchat/src/autogen_agentchat/teams/group_chat/_base_chat_agent_container.py @@ -11,7 +11,7 @@ from autogen_core.components.tool_agent import ToolException from ...agents import BaseChatAgent, MultiModalMessage, StopMessage, TextMessage, ToolCallMessage, ToolCallResultMessage from ._events import ContentPublishEvent, ContentRequestEvent from ._sequential_routed_agent import SequentialRoutedAgent -from ..logging import EVENT_LOGGER_NAME +from ...logging import EVENT_LOGGER_NAME class BaseChatAgentContainer(SequentialRoutedAgent): 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 index 4743e5288..0a5e5061f 100644 --- 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 @@ -7,7 +7,7 @@ from autogen_core.components import event from ...agents import StopMessage, TextMessage, ChatMessage from ._events import ContentPublishEvent, ContentRequestEvent from ._sequential_routed_agent import SequentialRoutedAgent -from ..logging import EVENT_LOGGER_NAME +from ...logging import EVENT_LOGGER_NAME class BaseGroupChatManager(SequentialRoutedAgent):