make logging independent module

This commit is contained in:
Victor Dibia 2024-10-03 10:03:17 -07:00
parent b0b0825c1d
commit 13c135100f
5 changed files with 72 additions and 82 deletions

View File

@ -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

View File

@ -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:

View File

@ -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):

View File

@ -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)

View File

@ -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()
super().close()