From 1c5baf020fa62af5cccff27e77730c2af6e46d35 Mon Sep 17 00:00:00 2001 From: Rajan Date: Tue, 22 Oct 2024 04:52:06 -0400 Subject: [PATCH] [CAP] Abstraction of actor_connector to go along with runtime factory and runtime abstraction (#3296) * Added Runtime Factory to support multiple implementations * Rename to ComponentEnsemble to ZMQRuntime * rename zmq_runtime * rename zmq_runtime * pre-commit fixes * pre-commit fix * pre-commit fixes and default runtime * pre-commit fixes * Rename constants * Rename Constants * Create interfaces for connectors * pre-commit fixes * pre-commit fixes * pre-commit fixes * lower case file names * rename files to lower _case * rename files to _lowercase * removed _ * Refactored to make Actor zmq agnostic * fix for refactor * fix refactor, circular dependency * pre-commit fixes * document classes * pre-commit ruff * fix ruff issues * ruff fixes * ruff fixes * actor connector documentation * better docs --------- Co-authored-by: Li Jiang Co-authored-by: Chi Wang Co-authored-by: Ryan Sweet Co-authored-by: Eric Zhu --- samples/apps/cap/py/autogencap/Config.py | 1 + .../cap/py/autogencap/{Actor.py => actor.py} | 71 +++++++-------- .../apps/cap/py/autogencap/actor_connector.py | 83 ++++++++++++++++++ .../apps/cap/py/autogencap/actor_runtime.py | 86 +++++++++++++++++-- .../cap/py/autogencap/ag_adapter/AGActor.py | 13 --- .../cap/py/autogencap/ag_adapter/ag_actor.py | 11 +++ .../ag_adapter/{AG2CAP.py => ag_to_cap.py} | 2 +- .../cap/py/autogencap/ag_adapter/agent.py | 4 +- ...toGenConnector.py => autogen_connector.py} | 6 +- .../{CAPGroupChat.py => cap_group_chat.py} | 4 +- ...atManager.py => cap_group_chat_manager.py} | 16 ++-- .../ag_adapter/{CAPPair.py => cap_pair.py} | 2 +- .../ag_adapter/{CAP2AG.py => cap_to_ag.py} | 14 ++- .../py/autogencap/{Broker.py => broker.py} | 4 +- .../autogencap/{DebugLog.py => debug_log.py} | 9 +- .../apps/cap/py/autogencap/runtime_factory.py | 2 +- samples/apps/cap/py/autogencap/utility.py | 2 +- ...torConnector.py => zmq_actor_connector.py} | 14 ++- .../{DirectorySvc.py => zmq_directory_svc.py} | 45 +++++----- .../cap/py/autogencap/zmq_msg_receiver.py | 51 +++++++++++ samples/apps/cap/py/autogencap/zmq_runtime.py | 59 +++++++------ .../cap/py/demo/{AGDemo.py => ag_demo.py} | 0 ...GroupChatDemo.py => ag_group_chat_demo.py} | 0 samples/apps/cap/py/demo/{App.py => app.py} | 22 ++--- .../py/demo/{AppAgents.py => app_agents.py} | 27 +++--- ...GroupDemo.py => cap_autogen_group_demo.py} | 8 +- ...enPairDemo.py => cap_autogen_pair_demo.py} | 8 +- ...plexActorDemo.py => complex_actor_demo.py} | 20 ++--- samples/apps/cap/py/demo/list_agents.py | 4 +- ...RemoteAGDemo.py => remote_autogen_demo.py} | 0 ...impleActorDemo.py => simple_actor_demo.py} | 2 +- samples/apps/cap/py/demo/single_threaded.py | 4 +- .../apps/cap/py/demo/standalone/UserProxy.py | 58 ------------- .../apps/cap/py/demo/standalone/assistant.py | 4 +- .../demo/standalone/{Broker.py => broker.py} | 2 +- .../cap/py/demo/standalone/directory_svc.py | 2 +- .../apps/cap/py/demo/standalone/user_proxy.py | 2 +- samples/apps/cap/py/demo/zmq_tests.py | 2 +- 38 files changed, 401 insertions(+), 263 deletions(-) rename samples/apps/cap/py/autogencap/{Actor.py => actor.py} (58%) create mode 100644 samples/apps/cap/py/autogencap/actor_connector.py delete mode 100644 samples/apps/cap/py/autogencap/ag_adapter/AGActor.py create mode 100644 samples/apps/cap/py/autogencap/ag_adapter/ag_actor.py rename samples/apps/cap/py/autogencap/ag_adapter/{AG2CAP.py => ag_to_cap.py} (98%) rename samples/apps/cap/py/autogencap/ag_adapter/{AutoGenConnector.py => autogen_connector.py} (94%) rename samples/apps/cap/py/autogencap/ag_adapter/{CAPGroupChat.py => cap_group_chat.py} (93%) rename samples/apps/cap/py/autogencap/ag_adapter/{CAPGroupChatManager.py => cap_group_chat_manager.py} (75%) rename samples/apps/cap/py/autogencap/ag_adapter/{CAPPair.py => cap_pair.py} (95%) rename samples/apps/cap/py/autogencap/ag_adapter/{CAP2AG.py => cap_to_ag.py} (94%) rename samples/apps/cap/py/autogencap/{Broker.py => broker.py} (97%) rename samples/apps/cap/py/autogencap/{DebugLog.py => debug_log.py} (90%) rename samples/apps/cap/py/autogencap/{ActorConnector.py => zmq_actor_connector.py} (94%) rename samples/apps/cap/py/autogencap/{DirectorySvc.py => zmq_directory_svc.py} (85%) create mode 100644 samples/apps/cap/py/autogencap/zmq_msg_receiver.py rename samples/apps/cap/py/demo/{AGDemo.py => ag_demo.py} (100%) rename samples/apps/cap/py/demo/{AGGroupChatDemo.py => ag_group_chat_demo.py} (100%) rename samples/apps/cap/py/demo/{App.py => app.py} (79%) rename samples/apps/cap/py/demo/{AppAgents.py => app_agents.py} (89%) rename samples/apps/cap/py/demo/{CAPAutGenGroupDemo.py => cap_autogen_group_demo.py} (86%) rename samples/apps/cap/py/demo/{CAPAutoGenPairDemo.py => cap_autogen_pair_demo.py} (85%) rename samples/apps/cap/py/demo/{ComplexActorDemo.py => complex_actor_demo.py} (75%) rename samples/apps/cap/py/demo/{RemoteAGDemo.py => remote_autogen_demo.py} (100%) rename samples/apps/cap/py/demo/{SimpleActorDemo.py => simple_actor_demo.py} (93%) delete mode 100644 samples/apps/cap/py/demo/standalone/UserProxy.py rename samples/apps/cap/py/demo/standalone/{Broker.py => broker.py} (60%) diff --git a/samples/apps/cap/py/autogencap/Config.py b/samples/apps/cap/py/autogencap/Config.py index 5584a8d29cb..0e49d98b49d 100644 --- a/samples/apps/cap/py/autogencap/Config.py +++ b/samples/apps/cap/py/autogencap/Config.py @@ -5,3 +5,4 @@ xsub_url: str = "tcp://127.0.0.1:5556" router_url: str = "tcp://127.0.0.1:5557" dealer_url: str = "tcp://127.0.0.1:5558" +USE_COLOR_LOGGING = True diff --git a/samples/apps/cap/py/autogencap/Actor.py b/samples/apps/cap/py/autogencap/actor.py similarity index 58% rename from samples/apps/cap/py/autogencap/Actor.py rename to samples/apps/cap/py/autogencap/actor.py index 778fd7634c2..9b954f8461b 100644 --- a/samples/apps/cap/py/autogencap/Actor.py +++ b/samples/apps/cap/py/autogencap/actor.py @@ -1,57 +1,38 @@ import threading import traceback -import zmq +from .actor_runtime import IMessageReceiver, IMsgActor, IRuntime +from .debug_log import Debug, Info -from .Config import xpub_url -from .DebugLog import Debug, Error, Info - -class Actor: +class Actor(IMsgActor): def __init__(self, agent_name: str, description: str, start_thread: bool = True): + """Initialize the Actor with a name, description, and threading option.""" self.actor_name: str = agent_name self.agent_description: str = description self.run = False self._start_event = threading.Event() self._start_thread = start_thread + self._msg_receiver: IMessageReceiver = None + self._runtime: IRuntime = None - def on_connect(self, network): - Debug(self.actor_name, f"is connecting to {network}") + def on_connect(self): + """Connect the actor to the runtime.""" + Debug(self.actor_name, f"is connecting to {self._runtime}") Debug(self.actor_name, "connected") def on_txt_msg(self, msg: str, msg_type: str, receiver: str, sender: str) -> bool: + """Handle incoming text messages.""" Info(self.actor_name, f"InBox: {msg}") return True def on_bin_msg(self, msg: bytes, msg_type: str, receiver: str, sender: str) -> bool: + """Handle incoming binary messages.""" Info(self.actor_name, f"Msg: receiver=[{receiver}], msg_type=[{msg_type}]") return True - def _msg_loop_init(self): - Debug(self.actor_name, "recv thread started") - self._socket: zmq.Socket = self._context.socket(zmq.SUB) - self._socket.setsockopt(zmq.RCVTIMEO, 500) - self._socket.connect(xpub_url) - str_topic = f"{self.actor_name}" - Debug(self.actor_name, f"subscribe to: {str_topic}") - self._socket.setsockopt_string(zmq.SUBSCRIBE, f"{str_topic}") - self._start_event.set() - - def get_message(self): - try: - topic, msg_type, sender_topic, msg = self._socket.recv_multipart() - topic = topic.decode("utf-8") # Convert bytes to string - msg_type = msg_type.decode("utf-8") # Convert bytes to string - sender_topic = sender_topic.decode("utf-8") # Convert bytes to string - except zmq.Again: - return None # No message received, continue to next iteration - except Exception as e: - Error(self.actor_name, f"recv thread encountered an error: {e}") - traceback.print_exc() - return None - return topic, msg_type, sender_topic, msg - def dispatch_message(self, message): + """Dispatch the received message based on its type.""" if message is None: return topic, msg_type, sender_topic, msg = message @@ -65,40 +46,50 @@ def dispatch_message(self, message): if not self.on_bin_msg(msg, msg_type, topic, sender_topic): self.run = False + def get_message(self): + """Retrieve a message from the runtime implementation.""" + return self._msg_receiver.get_message() + def _msg_loop(self): + """Main message loop for receiving and dispatching messages.""" try: - self._msg_loop_init() + self._msg_receiver = self._runtime.get_new_msg_receiver() + self._msg_receiver.init(self.actor_name) + self._start_event.set() while self.run: - message = self.get_message() + message = self._msg_receiver.get_message() self.dispatch_message(message) except Exception as e: Debug(self.actor_name, f"recv thread encountered an error: {e}") traceback.print_exc() finally: - self.run = False # In case there was an exception at startup signal # the main thread. self._start_event.set() + self.run = False Debug(self.actor_name, "recv thread ended") - def on_start(self, context: zmq.Context): - self._context = context - self.run: bool = True + def on_start(self, runtime: IRuntime): + """Start the actor and its message receiving thread if applicable.""" + self._runtime = runtime # Save the runtime + self.run = True if self._start_thread: self._thread = threading.Thread(target=self._msg_loop) self._thread.start() self._start_event.wait() else: - self._msg_loop_init() + self._msg_receiver = self._runtime.get_new_msg_receiver() + self._msg_receiver.init(self.actor_name) def disconnect_network(self, network): + """Disconnect the actor from the network.""" Debug(self.actor_name, f"is disconnecting from {network}") Debug(self.actor_name, "disconnected") self.stop() def stop(self): + """Stop the actor and its message receiver.""" self.run = False if self._start_thread: self._thread.join() - self._socket.setsockopt(zmq.LINGER, 0) - self._socket.close() + self._msg_receiver.stop() diff --git a/samples/apps/cap/py/autogencap/actor_connector.py b/samples/apps/cap/py/autogencap/actor_connector.py new file mode 100644 index 00000000000..700d8ba655c --- /dev/null +++ b/samples/apps/cap/py/autogencap/actor_connector.py @@ -0,0 +1,83 @@ +from abc import ABC, abstractmethod +from typing import Any, Optional, Tuple + + +class IActorConnector(ABC): + """ + Abstract base class for actor connectors. Each runtime will have a different implementation. + Obtain an instance of the correct connector from the runtime by calling the runtime's find_by_xyz + method. + """ + + @abstractmethod + def send_txt_msg(self, msg: str) -> None: + """ + Send a text message to the actor. + + Args: + msg (str): The text message to send. + """ + pass + + @abstractmethod + def send_bin_msg(self, msg_type: str, msg: bytes) -> None: + """ + Send a binary message to the actor. + + Args: + msg_type (str): The type of the binary message. + msg (bytes): The binary message to send. + """ + pass + + @abstractmethod + def send_proto_msg(self, msg: Any) -> None: + """ + Send a protocol buffer message to the actor. + + Args: + msg (Any): The protocol buffer message to send. + """ + pass + + @abstractmethod + def send_recv_proto_msg( + self, msg: Any, num_attempts: int = 5 + ) -> Tuple[Optional[str], Optional[str], Optional[bytes]]: + """ + Send a protocol buffer message and receive a response from the actor. + + Args: + msg (Any): The protocol buffer message to send. + num_attempts (int, optional): Number of attempts to send and receive. Defaults to 5. + + Returns: + Tuple[Optional[str], Optional[str], Optional[bytes]]: A tuple containing the topic, + message type, and response message, or None if no response is received. + """ + pass + + @abstractmethod + def send_recv_msg( + self, msg_type: str, msg: bytes, num_attempts: int = 5 + ) -> Tuple[Optional[str], Optional[str], Optional[bytes]]: + """ + Send a binary message and receive a response from the actor. + + Args: + msg_type (str): The type of the binary message. + msg (bytes): The binary message to send. + num_attempts (int, optional): Number of attempts to send and receive. Defaults to 5. + + Returns: + Tuple[Optional[str], Optional[str], Optional[bytes]]: A tuple containing the topic, + message type, and response message, or None if no response is received. + """ + pass + + @abstractmethod + def close(self) -> None: + """ + Close the actor connector and release any resources. + """ + pass diff --git a/samples/apps/cap/py/autogencap/actor_runtime.py b/samples/apps/cap/py/autogencap/actor_runtime.py index 027b2090587..bd1e31a339a 100644 --- a/samples/apps/cap/py/autogencap/actor_runtime.py +++ b/samples/apps/cap/py/autogencap/actor_runtime.py @@ -1,36 +1,108 @@ from abc import ABC, abstractmethod from typing import List -from .Actor import Actor -from .ActorConnector import ActorConnector +from .actor_connector import IActorConnector from .proto.CAP_pb2 import ActorInfo +class IMsgActor(ABC): + """Abstract base class for message based actors.""" + + @abstractmethod + def on_connect(self, runtime: "IRuntime"): + """Called when the actor connects to the runtime.""" + pass + + @abstractmethod + def on_txt_msg(self, msg: str, msg_type: str, receiver: str, sender: str) -> bool: + """Handle incoming text messages.""" + pass + + @abstractmethod + def on_bin_msg(self, msg: bytes, msg_type: str, receiver: str, sender: str) -> bool: + """Handle incoming binary messages.""" + pass + + @abstractmethod + def on_start(self): + """Called when the actor starts.""" + pass + + @abstractmethod + def stop(self): + """Stop the actor.""" + pass + + @abstractmethod + def dispatch_message(self, message): + """Dispatch the received message based on its type.""" + pass + + +class IMessageReceiver(ABC): + """Abstract base class for message receivers. Implementations are runtime specific.""" + + @abstractmethod + def init(self, actor_name: str): + """Initialize the message receiver.""" + pass + + @abstractmethod + def add_listener(self, topic: str): + """Add a topic to the message receiver.""" + pass + + @abstractmethod + def get_message(self): + """Retrieve a message from the runtime implementation.""" + pass + + @abstractmethod + def stop(self): + """Stop the message receiver.""" + pass + + +# Abstract base class for the runtime environment class IRuntime(ABC): + """Abstract base class for the actor runtime environment.""" + + @abstractmethod + def register(self, actor: IMsgActor): + """Register an actor with the runtime.""" + pass + @abstractmethod - def register(self, actor: Actor): + def get_new_msg_receiver(self) -> IMessageReceiver: + """Create and return a new message receiver.""" pass @abstractmethod def connect(self): + """Connect the runtime to the messaging system.""" pass @abstractmethod def disconnect(self): + """Disconnect the runtime from the messaging system.""" pass @abstractmethod - def find_by_topic(self, topic: str) -> ActorConnector: + def find_by_topic(self, topic: str) -> IActorConnector: + """Find an actor connector by topic.""" pass @abstractmethod - def find_by_name(self, name: str) -> ActorConnector: + def find_by_name(self, name: str) -> IActorConnector: + """Find an actor connector by name.""" pass @abstractmethod - def find_termination(self) -> ActorConnector: + def find_termination(self) -> IActorConnector: + """Find the termination actor connector.""" pass @abstractmethod - def find_by_name_regex(self, name_regex) -> List[ActorInfo]: + def find_by_name_regex(self, name_regex) -> List["ActorInfo"]: + """Find actors by name using a regular expression.""" pass diff --git a/samples/apps/cap/py/autogencap/ag_adapter/AGActor.py b/samples/apps/cap/py/autogencap/ag_adapter/AGActor.py deleted file mode 100644 index 6bd804e33e9..00000000000 --- a/samples/apps/cap/py/autogencap/ag_adapter/AGActor.py +++ /dev/null @@ -1,13 +0,0 @@ -import zmq - -from autogencap.Actor import Actor -from autogencap.constants import Termination_Topic -from autogencap.DebugLog import Debug - - -class AGActor(Actor): - def on_start(self, context: zmq.Context): - super().on_start(context) - str_topic = Termination_Topic - Debug(self.actor_name, f"subscribe to: {str_topic}") - self._socket.setsockopt_string(zmq.SUBSCRIBE, f"{str_topic}") diff --git a/samples/apps/cap/py/autogencap/ag_adapter/ag_actor.py b/samples/apps/cap/py/autogencap/ag_adapter/ag_actor.py new file mode 100644 index 00000000000..410a042b8ae --- /dev/null +++ b/samples/apps/cap/py/autogencap/ag_adapter/ag_actor.py @@ -0,0 +1,11 @@ +from autogencap.actor import Actor +from autogencap.constants import Termination_Topic +from autogencap.debug_log import Debug + + +class AGActor(Actor): + def on_start(self, runtime): + super().on_start(runtime) + str_topic = Termination_Topic + self._msg_receiver.add_listener(str_topic) + Debug(self.actor_name, f"subscribe to: {str_topic}") diff --git a/samples/apps/cap/py/autogencap/ag_adapter/AG2CAP.py b/samples/apps/cap/py/autogencap/ag_adapter/ag_to_cap.py similarity index 98% rename from samples/apps/cap/py/autogencap/ag_adapter/AG2CAP.py rename to samples/apps/cap/py/autogencap/ag_adapter/ag_to_cap.py index 4b5f79aefd8..38abf0a8a09 100644 --- a/samples/apps/cap/py/autogencap/ag_adapter/AG2CAP.py +++ b/samples/apps/cap/py/autogencap/ag_adapter/ag_to_cap.py @@ -4,7 +4,7 @@ from autogen import Agent, ConversableAgent from ..actor_runtime import IRuntime -from .AutoGenConnector import AutoGenConnector +from .autogen_connector import AutoGenConnector class AG2CAP(ConversableAgent): diff --git a/samples/apps/cap/py/autogencap/ag_adapter/agent.py b/samples/apps/cap/py/autogencap/ag_adapter/agent.py index 219bb7297c1..aa47554bd0c 100644 --- a/samples/apps/cap/py/autogencap/ag_adapter/agent.py +++ b/samples/apps/cap/py/autogencap/ag_adapter/agent.py @@ -2,8 +2,8 @@ from autogen import ConversableAgent -from ..DebugLog import Info, Warn -from .CAP2AG import CAP2AG +from ..debug_log import Info, Warn +from .cap_to_ag import CAP2AG class Agent: diff --git a/samples/apps/cap/py/autogencap/ag_adapter/AutoGenConnector.py b/samples/apps/cap/py/autogencap/ag_adapter/autogen_connector.py similarity index 94% rename from samples/apps/cap/py/autogencap/ag_adapter/AutoGenConnector.py rename to samples/apps/cap/py/autogencap/ag_adapter/autogen_connector.py index 47b70ea7a13..d2baa9020e1 100644 --- a/samples/apps/cap/py/autogencap/ag_adapter/AutoGenConnector.py +++ b/samples/apps/cap/py/autogencap/ag_adapter/autogen_connector.py @@ -3,7 +3,7 @@ from autogen import Agent -from ..ActorConnector import ActorConnector +from ..actor_connector import IActorConnector from ..proto.Autogen_pb2 import GenReplyReq, GenReplyResp, PrepChat, ReceiveReq, Terminate @@ -13,8 +13,8 @@ class AutoGenConnector: to/from the CAP system. """ - def __init__(self, cap_sender: ActorConnector): - self._can_channel: ActorConnector = cap_sender + def __init__(self, cap_sender: IActorConnector): + self._can_channel: IActorConnector = cap_sender def close(self): """ diff --git a/samples/apps/cap/py/autogencap/ag_adapter/CAPGroupChat.py b/samples/apps/cap/py/autogencap/ag_adapter/cap_group_chat.py similarity index 93% rename from samples/apps/cap/py/autogencap/ag_adapter/CAPGroupChat.py rename to samples/apps/cap/py/autogencap/ag_adapter/cap_group_chat.py index caf2a11a66f..889f90f8fff 100644 --- a/samples/apps/cap/py/autogencap/ag_adapter/CAPGroupChat.py +++ b/samples/apps/cap/py/autogencap/ag_adapter/cap_group_chat.py @@ -1,8 +1,8 @@ from typing import List from autogen import Agent, AssistantAgent, GroupChat -from autogencap.ag_adapter.AG2CAP import AG2CAP -from autogencap.ag_adapter.CAP2AG import CAP2AG +from autogencap.ag_adapter.ag_to_cap import AG2CAP +from autogencap.ag_adapter.cap_to_ag import CAP2AG from ..actor_runtime import IRuntime diff --git a/samples/apps/cap/py/autogencap/ag_adapter/CAPGroupChatManager.py b/samples/apps/cap/py/autogencap/ag_adapter/cap_group_chat_manager.py similarity index 75% rename from samples/apps/cap/py/autogencap/ag_adapter/CAPGroupChatManager.py rename to samples/apps/cap/py/autogencap/ag_adapter/cap_group_chat_manager.py index e71e6aecddf..3934715028b 100644 --- a/samples/apps/cap/py/autogencap/ag_adapter/CAPGroupChatManager.py +++ b/samples/apps/cap/py/autogencap/ag_adapter/cap_group_chat_manager.py @@ -1,16 +1,16 @@ import time from autogen import GroupChatManager -from autogencap.ActorConnector import ActorConnector -from autogencap.ag_adapter.CAP2AG import CAP2AG -from autogencap.ag_adapter.CAPGroupChat import CAPGroupChat +from autogencap.actor_connector import IActorConnector +from autogencap.ag_adapter.cap_group_chat import CAPGroupChat +from autogencap.ag_adapter.cap_to_ag import CAP2AG from ..actor_runtime import IRuntime class CAPGroupChatManager: - def __init__(self, groupchat: CAPGroupChat, llm_config: dict, network: IRuntime): - self._ensemble: IRuntime = network + def __init__(self, groupchat: CAPGroupChat, llm_config: dict, runtime: IRuntime): + self._runtime: IRuntime = runtime self._cap_group_chat: CAPGroupChat = groupchat self._ag_group_chat_manager: GroupChatManager = GroupChatManager( groupchat=self._cap_group_chat, llm_config=llm_config @@ -21,11 +21,11 @@ def __init__(self, groupchat: CAPGroupChat, llm_config: dict, network: IRuntime) init_chat=False, self_recursive=True, ) - self._ensemble.register(self._cap_proxy) + self._runtime.register(self._cap_proxy) def initiate_chat(self, txt_msg: str) -> None: - self._ensemble.connect() - user_proxy_conn: ActorConnector = self._ensemble.find_by_name(self._cap_group_chat.chat_initiator) + self._runtime.connect() + user_proxy_conn: IActorConnector = self._runtime.find_by_name(self._cap_group_chat.chat_initiator) user_proxy_conn.send_txt_msg(txt_msg) self._wait_for_user_exit() diff --git a/samples/apps/cap/py/autogencap/ag_adapter/CAPPair.py b/samples/apps/cap/py/autogencap/ag_adapter/cap_pair.py similarity index 95% rename from samples/apps/cap/py/autogencap/ag_adapter/CAPPair.py rename to samples/apps/cap/py/autogencap/ag_adapter/cap_pair.py index 4a87a742b5d..85dda2bca83 100644 --- a/samples/apps/cap/py/autogencap/ag_adapter/CAPPair.py +++ b/samples/apps/cap/py/autogencap/ag_adapter/cap_pair.py @@ -1,4 +1,4 @@ -from autogencap.ag_adapter.CAP2AG import CAP2AG +from autogencap.ag_adapter.cap_to_ag import CAP2AG class CAPPair: diff --git a/samples/apps/cap/py/autogencap/ag_adapter/CAP2AG.py b/samples/apps/cap/py/autogencap/ag_adapter/cap_to_ag.py similarity index 94% rename from samples/apps/cap/py/autogencap/ag_adapter/CAP2AG.py rename to samples/apps/cap/py/autogencap/ag_adapter/cap_to_ag.py index 0dd3b7be5ce..30f5b52354f 100644 --- a/samples/apps/cap/py/autogencap/ag_adapter/CAP2AG.py +++ b/samples/apps/cap/py/autogencap/ag_adapter/cap_to_ag.py @@ -5,10 +5,10 @@ from autogen import ConversableAgent from ..actor_runtime import IRuntime -from ..DebugLog import Debug, Error, Info, Warn, shorten +from ..debug_log import Debug, Error, Info, Warn, shorten from ..proto.Autogen_pb2 import GenReplyReq, GenReplyResp, PrepChat, ReceiveReq, Terminate -from .AG2CAP import AG2CAP -from .AGActor import AGActor +from .ag_actor import AGActor +from .ag_to_cap import AG2CAP class CAP2AG(AGActor): @@ -27,15 +27,13 @@ def __init__(self, ag_agent: ConversableAgent, the_other_name: str, init_chat: b self.STATE = self.States.INIT self._can2ag_name: str = self.actor_name + ".can2ag" self._self_recursive: bool = self_recursive - self._ensemble: IRuntime = None self._connectors = {} - def on_connect(self, ensemble: IRuntime): + def on_connect(self): """ Connect to the AutoGen system. """ - self._ensemble = ensemble - self._ag2can_other_agent = AG2CAP(self._ensemble, self._other_agent_name) + self._ag2can_other_agent = AG2CAP(self._runtime, self._other_agent_name) Debug(self._can2ag_name, "connected to {ensemble}") def disconnect_network(self, ensemble: IRuntime): @@ -117,7 +115,7 @@ def get_actor_connector(self, topic: str): if topic in self._connectors: return self._connectors[topic] else: - connector = self._ensemble.find_by_topic(topic) + connector = self._runtime.find_by_topic(topic) self._connectors[topic] = connector return connector diff --git a/samples/apps/cap/py/autogencap/Broker.py b/samples/apps/cap/py/autogencap/broker.py similarity index 97% rename from samples/apps/cap/py/autogencap/Broker.py rename to samples/apps/cap/py/autogencap/broker.py index 2fd430d1bc7..39da094203c 100644 --- a/samples/apps/cap/py/autogencap/Broker.py +++ b/samples/apps/cap/py/autogencap/broker.py @@ -3,8 +3,8 @@ import zmq -from autogencap.Config import router_url, xpub_url, xsub_url -from autogencap.DebugLog import Debug, Info, Warn +from autogencap.config import router_url, xpub_url, xsub_url +from autogencap.debug_log import Debug, Info, Warn class Broker: diff --git a/samples/apps/cap/py/autogencap/DebugLog.py b/samples/apps/cap/py/autogencap/debug_log.py similarity index 90% rename from samples/apps/cap/py/autogencap/DebugLog.py rename to samples/apps/cap/py/autogencap/debug_log.py index f8a3f209ee3..1e2a6bf2a00 100644 --- a/samples/apps/cap/py/autogencap/DebugLog.py +++ b/samples/apps/cap/py/autogencap/debug_log.py @@ -3,7 +3,7 @@ from termcolor import colored -import autogencap.Config as Config +import autogencap.config as config # Define log levels as constants DEBUG = 0 @@ -22,9 +22,9 @@ def __init__(self): def Log(self, level, context, msg): # Check if the current level meets the threshold - if level >= Config.LOG_LEVEL: # Use the LOG_LEVEL from the Config module + if level >= config.LOG_LEVEL: # Use the LOG_LEVEL from the Config module # Check if the context is in the list of ignored contexts - if context in Config.IGNORED_LOG_CONTEXTS: + if context in config.IGNORED_LOG_CONTEXTS: return with self._lock: self.WriteLog(level, context, msg) @@ -34,7 +34,7 @@ def WriteLog(self, level, context, msg): class ConsoleLogger(BaseLogger): - def __init__(self, use_color=True): + def __init__(self, use_color=config.USE_COLOR_LOGGING): super().__init__() self._use_color = use_color @@ -56,6 +56,7 @@ def WriteLog(self, level, context, msg): print(f"{thread_id} {timestamp} {level_name}: [{context}] {msg}") +# Modify this line to disable color logging by default LOGGER = ConsoleLogger() diff --git a/samples/apps/cap/py/autogencap/runtime_factory.py b/samples/apps/cap/py/autogencap/runtime_factory.py index 77fb091a248..c585653e132 100644 --- a/samples/apps/cap/py/autogencap/runtime_factory.py +++ b/samples/apps/cap/py/autogencap/runtime_factory.py @@ -1,6 +1,6 @@ from autogencap.actor_runtime import IRuntime from autogencap.constants import ZMQ_Runtime -from autogencap.DebugLog import Error +from autogencap.debug_log import Error from autogencap.zmq_runtime import ZMQRuntime diff --git a/samples/apps/cap/py/autogencap/utility.py b/samples/apps/cap/py/autogencap/utility.py index 2083e565ffe..317e835e9ea 100644 --- a/samples/apps/cap/py/autogencap/utility.py +++ b/samples/apps/cap/py/autogencap/utility.py @@ -1,4 +1,4 @@ -from autogencap.DebugLog import Error +from autogencap.debug_log import Error from autogencap.proto.CAP_pb2 import Error as ErrorMsg from autogencap.proto.CAP_pb2 import ErrorCode diff --git a/samples/apps/cap/py/autogencap/ActorConnector.py b/samples/apps/cap/py/autogencap/zmq_actor_connector.py similarity index 94% rename from samples/apps/cap/py/autogencap/ActorConnector.py rename to samples/apps/cap/py/autogencap/zmq_actor_connector.py index 1595f641fc8..6b5b30f4446 100644 --- a/samples/apps/cap/py/autogencap/ActorConnector.py +++ b/samples/apps/cap/py/autogencap/zmq_actor_connector.py @@ -1,6 +1,3 @@ -# Agent_Sender takes a zmq context, Topic and creates a -# socket that can publish to that topic. It exposes this functionality -# using send_msg method import time import uuid from typing import Any, Dict @@ -8,11 +5,12 @@ import zmq from zmq.utils.monitor import recv_monitor_message -from .Config import router_url, xpub_url, xsub_url -from .DebugLog import Debug, Error, Info +from .actor_connector import IActorConnector +from .config import router_url, xpub_url, xsub_url +from .debug_log import Debug, Error, Info -class ActorSender: +class ZMQActorSender: def __init__(self, context, topic): self._context = context self._topic = topic @@ -73,12 +71,12 @@ def close(self): self._pub_socket.close() -class ActorConnector: +class ZMQActorConnector(IActorConnector): def __init__(self, context, topic): self._context = context self._topic = topic self._connect_sub_socket() - self._sender = ActorSender(context, topic) + self._sender = ZMQActorSender(context, topic) time.sleep(0.1) # Wait for the socket to connect def _connect_sub_socket(self): diff --git a/samples/apps/cap/py/autogencap/DirectorySvc.py b/samples/apps/cap/py/autogencap/zmq_directory_svc.py similarity index 85% rename from samples/apps/cap/py/autogencap/DirectorySvc.py rename to samples/apps/cap/py/autogencap/zmq_directory_svc.py index 6057558c0b2..eb0f2ee3792 100644 --- a/samples/apps/cap/py/autogencap/DirectorySvc.py +++ b/samples/apps/cap/py/autogencap/zmq_directory_svc.py @@ -4,12 +4,10 @@ import zmq -from autogencap.Actor import Actor -from autogencap.ActorConnector import ActorConnector, ActorSender -from autogencap.Broker import Broker -from autogencap.Config import router_url, xpub_url, xsub_url +from autogencap.actor import Actor +from autogencap.broker import Broker from autogencap.constants import Directory_Svc_Topic -from autogencap.DebugLog import Debug, Error, Info +from autogencap.debug_log import Debug, Error, Info from autogencap.proto.CAP_pb2 import ( ActorInfo, ActorInfoCollection, @@ -24,16 +22,18 @@ Error as ErrorMsg, ) from autogencap.utility import report_error_msg +from autogencap.zmq_actor_connector import ZMQActorConnector, ZMQActorSender # TODO (Future DirectorySv PR) use actor description, network_id, other properties to make directory # service more generic and powerful -class DirectoryActor(Actor): - def __init__(self, topic: str, name: str): +class ZMQDirectoryActor(Actor): + def __init__(self, topic: str, name: str, context: zmq.Context): super().__init__(topic, name) self._registered_actors = {} self._network_prefix = "" + self._context = context def on_bin_msg(self, msg: bytes, msg_type: str, topic: str, sender: str) -> bool: if msg_type == ActorRegistration.__name__: @@ -50,7 +50,7 @@ def _on_ping_msg(self, topic: str, msg_type: str, msg: bytes, sender_topic: str) Info("DirectorySvc", f"Ping received: {sender_topic}") pong = Pong() serialized_msg = pong.SerializeToString() - sender_connection = ActorSender(self._context, sender_topic) + sender_connection = ZMQActorSender(self._context, sender_topic) sender_connection.send_bin_msg(Pong.__name__, serialized_msg) def _on_actor_registration_msg(self, topic: str, msg_type: str, msg: bytes, sender_topic: str): @@ -67,7 +67,7 @@ def _on_actor_registration_msg(self, topic: str, msg_type: str, msg: bytes, send else: self._registered_actors[name] = actor_reg.actor_info - sender_connection = ActorSender(self._context, sender_topic) + sender_connection = ZMQActorSender(self._context, sender_topic) serialized_msg = err.SerializeToString() sender_connection.send_bin_msg(ErrorMsg.__name__, serialized_msg) @@ -96,16 +96,16 @@ def _on_actor_lookup_msg(self, topic: str, msg_type: str, msg: bytes, sender_top else: Error("DirectorySvc", f"Actor not found: {actor_lookup.actor_info.name}") - sender_connection = ActorSender(self._context, sender_topic) + sender_connection = ZMQActorSender(self._context, sender_topic) serialized_msg = actor_lookup_resp.SerializeToString() sender_connection.send_bin_msg(ActorLookupResponse.__name__, serialized_msg) -class DirectorySvc: +class ZMQDirectorySvc: def __init__(self, context: zmq.Context = zmq.Context()): self._context: zmq.Context = context - self._directory_connector: ActorConnector = None - self._directory_actor: DirectoryActor = None + self._directory_connector: ZMQActorConnector = None + self._directory_actor: ZMQDirectoryActor = None def _no_other_directory(self) -> bool: Debug("DirectorySvc", "Pinging existing DirectorySvc") @@ -116,12 +116,14 @@ def _no_other_directory(self) -> bool: return True return False - def start(self): + def start(self, runtime): Debug("DirectorySvc", "Starting.") - self._directory_connector = ActorConnector(self._context, Directory_Svc_Topic) + self._directory_connector = ZMQActorConnector(self._context, Directory_Svc_Topic) if self._no_other_directory(): - self._directory_actor = DirectoryActor(Directory_Svc_Topic, "Directory Service") - self._directory_actor.on_start(self._context) + self._directory_actor = ZMQDirectoryActor( + Directory_Svc_Topic, "Directory Service", self._context + ) # Update this line + self._directory_actor.on_start(runtime) Info("DirectorySvc", "Directory service started.") else: Info("DirectorySvc", "Another directory service is running. This instance will not start.") @@ -176,15 +178,8 @@ def main(): proxy: Broker = Broker(context) proxy.start() # Start the directory service - directory_svc = DirectorySvc(context) + directory_svc = ZMQDirectorySvc(context) directory_svc.start() - # # How do you register an actor? - # directory_svc.register_actor_by_name("my_actor") - # - # # How do you look up an actor? - # actor: ActorInfo = directory_svc.lookup_actor_by_name("my_actor") - # if actor is not None: - # Info("main", f"Found actor: {actor.name}") # DirectorySvc is running in a separate thread. Here we are watching the # status and printing status every few seconds. This is diff --git a/samples/apps/cap/py/autogencap/zmq_msg_receiver.py b/samples/apps/cap/py/autogencap/zmq_msg_receiver.py new file mode 100644 index 00000000000..b6a2a27fa64 --- /dev/null +++ b/samples/apps/cap/py/autogencap/zmq_msg_receiver.py @@ -0,0 +1,51 @@ +# ZMQ implementation of the message receiver +import threading + +import zmq + +from autogencap.actor_runtime import IMessageReceiver +from autogencap.config import xpub_url +from autogencap.debug_log import Debug, Error + + +class ZMQMsgReceiver(IMessageReceiver): + def __init__(self, context: zmq.Context): + self._socket = None + self._context = context + self._start_event = threading.Event() + self.run = False + + def init(self, actor_name: str): + """Initialize the ZMQ message receiver.""" + self.actor_name = actor_name + self._socket = self._context.socket(zmq.SUB) + self._socket.setsockopt(zmq.RCVTIMEO, 500) + self._socket.connect(xpub_url) + str_topic = f"{self.actor_name}" + self.add_listener(str_topic) + self._start_event.set() + + def add_listener(self, topic: str): + """Add a topic to the message receiver.""" + Debug(self.actor_name, f"subscribe to: {topic}") + self._socket.setsockopt_string(zmq.SUBSCRIBE, f"{topic}") + + def get_message(self): + """Retrieve a message from the ZMQ socket.""" + try: + topic, msg_type, sender_topic, msg = self._socket.recv_multipart() + topic = topic.decode("utf-8") # Convert bytes to string + msg_type = msg_type.decode("utf-8") # Convert bytes to string + sender_topic = sender_topic.decode("utf-8") # Convert bytes to string + except zmq.Again: + return None # No message received, continue to next iteration + except Exception as e: + Error(self.actor_name, f"recv thread encountered an error: {e}") + return None + return topic, msg_type, sender_topic, msg + + def stop(self): + """Stop the ZMQ message receiver.""" + self.run = False + self._socket.setsockopt(zmq.LINGER, 0) + self._socket.close() diff --git a/samples/apps/cap/py/autogencap/zmq_runtime.py b/samples/apps/cap/py/autogencap/zmq_runtime.py index a8074fb48d3..6693db7d41a 100644 --- a/samples/apps/cap/py/autogencap/zmq_runtime.py +++ b/samples/apps/cap/py/autogencap/zmq_runtime.py @@ -3,27 +3,31 @@ import zmq -from .Actor import Actor -from .actor_runtime import IRuntime -from .ActorConnector import ActorConnector -from .Broker import Broker +from .actor import Actor +from .actor_connector import IActorConnector +from .actor_runtime import IMessageReceiver, IRuntime +from .broker import Broker from .constants import Termination_Topic -from .DebugLog import Debug, Warn -from .DirectorySvc import DirectorySvc +from .debug_log import Debug, Warn from .proto.CAP_pb2 import ActorInfo, ActorInfoCollection +from .zmq_actor_connector import ZMQActorConnector class ZMQRuntime(IRuntime): - def __init__(self, name: str = "Local Actor Network", start_broker: bool = True): + def __init__(self, start_broker: bool = True): self.local_actors = {} - self.name: str = name self._context: zmq.Context = zmq.Context() self._start_broker: bool = start_broker self._broker: Broker = None - self._directory_svc: DirectorySvc = None + self._directory_svc = None + self._log_name = self.__class__.__name__ def __str__(self): - return f"{self.name}" + return f" \ +{self._log_name}\n \ +is_broker: {self._broker is not None}\n \ +is_directory_svc: {self._directory_svc is not None}\n \ +local_actors: {self.local_actors}\n" def _init_runtime(self): if self._start_broker and self._broker is None: @@ -32,23 +36,28 @@ def _init_runtime(self): self._start_broker = False # Don't try to start the broker again self._broker = None if self._directory_svc is None: - self._directory_svc = DirectorySvc(self._context) - self._directory_svc.start() + from .zmq_directory_svc import ZMQDirectorySvc + + self._directory_svc = ZMQDirectorySvc(self._context) + self._directory_svc.start(self) time.sleep(0.25) # Process queued thread events in Broker and Directory def register(self, actor: Actor): self._init_runtime() - # Get actor's name and description and add to a dictionary so - # that we can look up the actor by name self._directory_svc.register_actor_by_name(actor.actor_name) self.local_actors[actor.actor_name] = actor - actor.on_start(self._context) - Debug("Local_Actor_Network", f"{actor.actor_name} registered in the network.") + actor.on_start(self) # Pass self (the runtime) to on_start + Debug(self._log_name, f"{actor.actor_name} registered in the network.") + + def get_new_msg_receiver(self) -> IMessageReceiver: + from .zmq_msg_receiver import ZMQMsgReceiver + + return ZMQMsgReceiver(self._context) def connect(self): self._init_runtime() for actor in self.local_actors.values(): - actor.on_connect(self) + actor.on_connect() def disconnect(self): for actor in self.local_actors.values(): @@ -58,27 +67,27 @@ def disconnect(self): if self._broker: self._broker.stop() - def find_by_topic(self, topic: str) -> ActorConnector: - return ActorConnector(self._context, topic) + def find_by_topic(self, topic: str) -> IActorConnector: + return ZMQActorConnector(self._context, topic) - def find_by_name(self, name: str) -> ActorConnector: + def find_by_name(self, name: str) -> IActorConnector: actor_info: ActorInfo = self._directory_svc.lookup_actor_by_name(name) if actor_info is None: - Warn("Local_Actor_Network", f"{name}, not found in the network.") + Warn(self._log_name, f"{name}, not found in the network.") return None - Debug("Local_Actor_Network", f"[{name}] found in the network.") + Debug(self._log_name, f"[{name}] found in the network.") return self.find_by_topic(name) - def find_termination(self) -> ActorConnector: + def find_termination(self) -> IActorConnector: termination_topic: str = Termination_Topic return self.find_by_topic(termination_topic) def find_by_name_regex(self, name_regex) -> List[ActorInfo]: actor_info: ActorInfoCollection = self._directory_svc.lookup_actor_info_by_name(name_regex) if actor_info is None: - Warn("Local_Actor_Network", f"{name_regex}, not found in the network.") + Warn(self._log_name, f"{name_regex}, not found in the network.") return None - Debug("Local_Actor_Network", f"[{name_regex}] found in the network.") + Debug(self._log_name, f"[{name_regex}] found in the network.") actor_list = [] for actor in actor_info.info_coll: actor_list.append(actor) diff --git a/samples/apps/cap/py/demo/AGDemo.py b/samples/apps/cap/py/demo/ag_demo.py similarity index 100% rename from samples/apps/cap/py/demo/AGDemo.py rename to samples/apps/cap/py/demo/ag_demo.py diff --git a/samples/apps/cap/py/demo/AGGroupChatDemo.py b/samples/apps/cap/py/demo/ag_group_chat_demo.py similarity index 100% rename from samples/apps/cap/py/demo/AGGroupChatDemo.py rename to samples/apps/cap/py/demo/ag_group_chat_demo.py diff --git a/samples/apps/cap/py/demo/App.py b/samples/apps/cap/py/demo/app.py similarity index 79% rename from samples/apps/cap/py/demo/App.py rename to samples/apps/cap/py/demo/app.py index 19987ab75ca..7f44730ee50 100644 --- a/samples/apps/cap/py/demo/App.py +++ b/samples/apps/cap/py/demo/app.py @@ -5,16 +5,16 @@ import argparse import _paths -import autogencap.Config as Config -import autogencap.DebugLog as DebugLog -from AGDemo import ag_demo -from AGGroupChatDemo import ag_groupchat_demo -from CAPAutGenGroupDemo import cap_ag_group_demo -from CAPAutoGenPairDemo import cap_ag_pair_demo -from ComplexActorDemo import complex_actor_demo +import autogencap.config as config +import autogencap.debug_log as debug_log +from ag_demo import ag_demo +from ag_group_chat_demo import ag_groupchat_demo +from cap_autogen_group_demo import cap_ag_group_demo +from cap_autogen_pair_demo import cap_ag_pair_demo +from complex_actor_demo import complex_actor_demo from list_agents import list_agents -from RemoteAGDemo import remote_ag_demo -from SimpleActorDemo import simple_actor_demo +from remote_autogen_demo import remote_ag_demo +from simple_actor_demo import simple_actor_demo from single_threaded import single_threaded_demo #################################################################################################### @@ -28,8 +28,8 @@ def parse_args(): args = parser.parse_args() # Set the log level # Print log level string based on names in debug_log.py - print(f"Log level: {DebugLog.LEVEL_NAMES[args.log_level]}") - Config.LOG_LEVEL = args.log_level + print(f"Log level: {debug_log.LEVEL_NAMES[args.log_level]}") + config.LOG_LEVEL = args.log_level # Config.IGNORED_LOG_CONTEXTS.extend(["BROKER"]) diff --git a/samples/apps/cap/py/demo/AppAgents.py b/samples/apps/cap/py/demo/app_agents.py similarity index 89% rename from samples/apps/cap/py/demo/AppAgents.py rename to samples/apps/cap/py/demo/app_agents.py index f13e4b471fd..f8095ba1867 100644 --- a/samples/apps/cap/py/demo/AppAgents.py +++ b/samples/apps/cap/py/demo/app_agents.py @@ -4,11 +4,10 @@ to retrieve information. """ -from autogencap.Actor import Actor +from autogencap.actor import Actor +from autogencap.actor_connector import IActorConnector from autogencap.actor_runtime import IRuntime -from autogencap.ActorConnector import ActorConnector -from autogencap.DebugLog import Debug, Info, shorten -from autogencap.runtime_factory import RuntimeFactory +from autogencap.debug_log import Debug, Info, shorten class GreeterAgent(Actor): @@ -132,23 +131,23 @@ def __init__( description="This is the personal assistant, who knows how to connect to the other agents and get information from them.", ): super().__init__(agent_name, description) - self.fidelity: ActorConnector = None - self.financial_planner: ActorConnector = None - self.quant: ActorConnector = None - self.risk_manager: ActorConnector = None + self.fidelity: IActorConnector = None + self.financial_planner: IActorConnector = None + self.quant: IActorConnector = None + self.risk_manager: IActorConnector = None - def on_connect(self, network: IRuntime): + def on_connect(self): """ Connects the personal assistant to the specified local actor network. Args: network (LocalActorNetwork): The local actor network to connect to. """ - Debug(self.actor_name, f"is connecting to {network}") - self.fidelity = network.find_by_name("Fidelity") - self.financial_planner = network.find_by_name("Financial Planner") - self.quant = network.find_by_name("Quant") - self.risk_manager = network.find_by_name("Risk Manager") + Debug(self.actor_name, f"is connecting to {self._runtime}") + self.fidelity = self._runtime.find_by_name("Fidelity") + self.financial_planner = self._runtime.find_by_name("Financial Planner") + self.quant = self._runtime.find_by_name("Quant") + self.risk_manager = self._runtime.find_by_name("Risk Manager") Debug(self.actor_name, "connected") def disconnect_network(self, network: IRuntime): diff --git a/samples/apps/cap/py/demo/CAPAutGenGroupDemo.py b/samples/apps/cap/py/demo/cap_autogen_group_demo.py similarity index 86% rename from samples/apps/cap/py/demo/CAPAutGenGroupDemo.py rename to samples/apps/cap/py/demo/cap_autogen_group_demo.py index 93a28c753ca..600763aab8f 100644 --- a/samples/apps/cap/py/demo/CAPAutGenGroupDemo.py +++ b/samples/apps/cap/py/demo/cap_autogen_group_demo.py @@ -1,6 +1,6 @@ -from autogencap.ag_adapter.CAPGroupChat import CAPGroupChat -from autogencap.ag_adapter.CAPGroupChatManager import CAPGroupChatManager -from autogencap.DebugLog import Info +from autogencap.ag_adapter.cap_group_chat import CAPGroupChat +from autogencap.ag_adapter.cap_group_chat_manager import CAPGroupChatManager +from autogencap.debug_log import Info from autogencap.runtime_factory import RuntimeFactory from autogen import AssistantAgent, UserProxyAgent, config_list_from_json @@ -35,7 +35,7 @@ def cap_ag_group_demo(): cap_groupchat = CAPGroupChat( agents=[user_proxy, coder, pm], messages=[], max_round=12, ensemble=ensemble, chat_initiator=user_proxy.name ) - manager = CAPGroupChatManager(groupchat=cap_groupchat, llm_config=gpt4_config, network=ensemble) + manager = CAPGroupChatManager(groupchat=cap_groupchat, llm_config=gpt4_config, runtime=ensemble) manager.initiate_chat("Find a latest paper about gpt-4 on arxiv and find its potential applications in software.") ensemble.disconnect() Info("App", "App Exit") diff --git a/samples/apps/cap/py/demo/CAPAutoGenPairDemo.py b/samples/apps/cap/py/demo/cap_autogen_pair_demo.py similarity index 85% rename from samples/apps/cap/py/demo/CAPAutoGenPairDemo.py rename to samples/apps/cap/py/demo/cap_autogen_pair_demo.py index 77323ddf870..eac1f0e4020 100644 --- a/samples/apps/cap/py/demo/CAPAutoGenPairDemo.py +++ b/samples/apps/cap/py/demo/cap_autogen_pair_demo.py @@ -1,15 +1,15 @@ import time -import autogencap.DebugLog as DebugLog -from autogencap.ag_adapter.CAPPair import CAPPair -from autogencap.DebugLog import ConsoleLogger, Info +import autogencap.debug_log as debug_log +from autogencap.ag_adapter.cap_pair import CAPPair +from autogencap.debug_log import ConsoleLogger, Info from autogencap.runtime_factory import RuntimeFactory from autogen import AssistantAgent, UserProxyAgent, config_list_from_json def cap_ag_pair_demo(): - DebugLog.LOGGER = ConsoleLogger(use_color=False) + debug_log.LOGGER = ConsoleLogger(use_color=False) config_list = config_list_from_json(env_or_file="OAI_CONFIG_LIST") assistant = AssistantAgent("assistant", llm_config={"config_list": config_list}) diff --git a/samples/apps/cap/py/demo/ComplexActorDemo.py b/samples/apps/cap/py/demo/complex_actor_demo.py similarity index 75% rename from samples/apps/cap/py/demo/ComplexActorDemo.py rename to samples/apps/cap/py/demo/complex_actor_demo.py index b82d457cc67..ec34b309b38 100644 --- a/samples/apps/cap/py/demo/ComplexActorDemo.py +++ b/samples/apps/cap/py/demo/complex_actor_demo.py @@ -1,6 +1,6 @@ import time -from AppAgents import FidelityAgent, FinancialPlannerAgent, PersonalAssistant, QuantAgent, RiskManager +from app_agents import FidelityAgent, FinancialPlannerAgent, PersonalAssistant, QuantAgent, RiskManager from autogencap.runtime_factory import RuntimeFactory from termcolor import colored @@ -14,17 +14,17 @@ def complex_actor_demo(): sends them to the personal assistant agent, and terminates when the user enters "quit". """ - ensemble = RuntimeFactory.get_runtime("ZMQ") + runtime = RuntimeFactory.get_runtime("ZMQ") # Register agents - ensemble.register(PersonalAssistant()) - ensemble.register(FidelityAgent()) - ensemble.register(FinancialPlannerAgent()) - ensemble.register(RiskManager()) - ensemble.register(QuantAgent()) + runtime.register(PersonalAssistant()) + runtime.register(FidelityAgent()) + runtime.register(FinancialPlannerAgent()) + runtime.register(RiskManager()) + runtime.register(QuantAgent()) # Tell agents to connect to other agents - ensemble.connect() + runtime.connect() # Get a channel to the personal assistant agent - pa = ensemble.find_by_name(PersonalAssistant.cls_agent_name) + pa = runtime.find_by_name(PersonalAssistant.cls_agent_name) info_msg = """ This is an imaginary personal assistant agent scenario. Five actors are connected in a self-determined graph. The user @@ -48,4 +48,4 @@ def complex_actor_demo(): # Cleanup pa.close() - ensemble.disconnect() + runtime.disconnect() diff --git a/samples/apps/cap/py/demo/list_agents.py b/samples/apps/cap/py/demo/list_agents.py index ca02006df2b..4785ef34231 100644 --- a/samples/apps/cap/py/demo/list_agents.py +++ b/samples/apps/cap/py/demo/list_agents.py @@ -1,8 +1,8 @@ import time from typing import List -from AppAgents import FidelityAgent, GreeterAgent -from autogencap.DebugLog import Info +from app_agents import FidelityAgent, GreeterAgent +from autogencap.debug_log import Info from autogencap.proto.CAP_pb2 import ActorInfo from autogencap.runtime_factory import RuntimeFactory diff --git a/samples/apps/cap/py/demo/RemoteAGDemo.py b/samples/apps/cap/py/demo/remote_autogen_demo.py similarity index 100% rename from samples/apps/cap/py/demo/RemoteAGDemo.py rename to samples/apps/cap/py/demo/remote_autogen_demo.py diff --git a/samples/apps/cap/py/demo/SimpleActorDemo.py b/samples/apps/cap/py/demo/simple_actor_demo.py similarity index 93% rename from samples/apps/cap/py/demo/SimpleActorDemo.py rename to samples/apps/cap/py/demo/simple_actor_demo.py index afc39829726..cb6b9a59768 100644 --- a/samples/apps/cap/py/demo/SimpleActorDemo.py +++ b/samples/apps/cap/py/demo/simple_actor_demo.py @@ -1,4 +1,4 @@ -from AppAgents import GreeterAgent +from app_agents import GreeterAgent from autogencap.runtime_factory import RuntimeFactory diff --git a/samples/apps/cap/py/demo/single_threaded.py b/samples/apps/cap/py/demo/single_threaded.py index f4c1fdfb633..b087eba5e6b 100644 --- a/samples/apps/cap/py/demo/single_threaded.py +++ b/samples/apps/cap/py/demo/single_threaded.py @@ -1,6 +1,6 @@ import _paths -from AppAgents import GreeterAgent -from autogencap.DebugLog import Error +from app_agents import GreeterAgent +from autogencap.debug_log import Error from autogencap.proto.CAP_pb2 import Ping from autogencap.runtime_factory import RuntimeFactory diff --git a/samples/apps/cap/py/demo/standalone/UserProxy.py b/samples/apps/cap/py/demo/standalone/UserProxy.py deleted file mode 100644 index c2eb4bf4238..00000000000 --- a/samples/apps/cap/py/demo/standalone/UserProxy.py +++ /dev/null @@ -1,58 +0,0 @@ -import time - -import _paths -from autogencap.ag_adapter.CAP2AG import CAP2AG -from autogencap.Config import IGNORED_LOG_CONTEXTS -from autogencap.DebugLog import Info -from autogencap.runtime_factory import RuntimeFactory - -from autogen import UserProxyAgent, config_list_from_json - - -# Starts the Broker and the Assistant. The UserProxy is started separately. -class StandaloneUserProxy: - def __init__(self): - pass - - def run(self): - print("Running the StandaloneUserProxy") - - user_proxy = UserProxyAgent( - "user_proxy", - code_execution_config={"work_dir": "coding"}, - is_termination_msg=lambda x: "TERMINATE" in x.get("content"), - ) - # Composable Agent Network adapter - ensemble = RuntimeFactory.get_runtime("ZMQ") - user_proxy_adptr = CAP2AG(ag_agent=user_proxy, the_other_name="assistant", init_chat=True, self_recursive=True) - ensemble.register(user_proxy_adptr) - ensemble.connect() - - # Send a message to the user_proxy - user_proxy_conn = ensemble.find_by_name("user_proxy") - example = "Plot a chart of MSFT daily closing prices for last 1 Month." - print(f"Example: {example}") - try: - user_input = input("Please enter your command: ") - if user_input == "": - user_input = example - print(f"Sending: {user_input}") - user_proxy_conn.send_txt_msg(user_input) - - # Hang around for a while - while user_proxy_adptr.run: - time.sleep(0.5) - except KeyboardInterrupt: - print("Interrupted by user, shutting down.") - ensemble.disconnect() - Info("StandaloneUserProxy", "App Exit") - - -def main(): - IGNORED_LOG_CONTEXTS.extend(["BROKER", "DirectorySvc"]) - assistant = StandaloneUserProxy() - assistant.run() - - -if __name__ == "__main__": - main() diff --git a/samples/apps/cap/py/demo/standalone/assistant.py b/samples/apps/cap/py/demo/standalone/assistant.py index 162071e6089..bb2ce19fea0 100644 --- a/samples/apps/cap/py/demo/standalone/assistant.py +++ b/samples/apps/cap/py/demo/standalone/assistant.py @@ -1,8 +1,8 @@ import time import _paths -from autogencap.ag_adapter.CAP2AG import CAP2AG -from autogencap.DebugLog import Info +from autogencap.ag_adapter.cap_to_ag import CAP2AG +from autogencap.debug_log import Info from autogencap.runtime_factory import RuntimeFactory from autogen import AssistantAgent, config_list_from_json diff --git a/samples/apps/cap/py/demo/standalone/Broker.py b/samples/apps/cap/py/demo/standalone/broker.py similarity index 60% rename from samples/apps/cap/py/demo/standalone/Broker.py rename to samples/apps/cap/py/demo/standalone/broker.py index f61064eb8e5..a7062554e7a 100644 --- a/samples/apps/cap/py/demo/standalone/Broker.py +++ b/samples/apps/cap/py/demo/standalone/broker.py @@ -1,5 +1,5 @@ import _paths -from autogencap.Broker import main +from autogencap.broker import main if __name__ == "__main__": main() diff --git a/samples/apps/cap/py/demo/standalone/directory_svc.py b/samples/apps/cap/py/demo/standalone/directory_svc.py index 3320b96e573..974c697de99 100644 --- a/samples/apps/cap/py/demo/standalone/directory_svc.py +++ b/samples/apps/cap/py/demo/standalone/directory_svc.py @@ -1,5 +1,5 @@ import _paths -from autogencap.DirectorySvc import main +from autogencap.zmq_directory_svc import main if __name__ == "__main__": main() diff --git a/samples/apps/cap/py/demo/standalone/user_proxy.py b/samples/apps/cap/py/demo/standalone/user_proxy.py index d1183a7b7a6..8acf3970458 100644 --- a/samples/apps/cap/py/demo/standalone/user_proxy.py +++ b/samples/apps/cap/py/demo/standalone/user_proxy.py @@ -2,7 +2,7 @@ import _paths from autogencap.ag_adapter.agent import Agent -from autogencap.Config import IGNORED_LOG_CONTEXTS +from autogencap.config import IGNORED_LOG_CONTEXTS from autogencap.runtime_factory import RuntimeFactory from autogen import UserProxyAgent diff --git a/samples/apps/cap/py/demo/zmq_tests.py b/samples/apps/cap/py/demo/zmq_tests.py index 8550ce6c2c8..cef0780a890 100644 --- a/samples/apps/cap/py/demo/zmq_tests.py +++ b/samples/apps/cap/py/demo/zmq_tests.py @@ -4,7 +4,7 @@ import _paths import zmq -from autogencap.Config import dealer_url, router_url, xpub_url, xsub_url +from autogencap.config import dealer_url, router_url, xpub_url, xsub_url from zmq.utils.monitor import recv_monitor_message