mirror of
				https://github.com/microsoft/autogen.git
				synced 2025-11-04 03:39:52 +00:00 
			
		
		
		
	Feature: Composable Actor Platform for AutoGen (#1655)
* Core CAP components + Autogen adapter + Demo * Cleanup Readme * C# folder * Cleanup readme * summary_method bug fix * CAN -> CAP * pre-commit fixes * pre-commit fixes * modification of sys path should ignore E402 * fix pre-commit check issues * Updated docs * Clean up docs * more refactoring * better packaging refactor * Refactoring for package changes * Run demo app without autogencap installed or in the path * Remove debug related sleep() * removed CAP in some class names * Investigate a logging framework that supports color in windows * added type hints * remove circular dependency * fixed pre-commit issues * pre-commit ruff issues * removed circular definition * pre-commit fixes * Fix pre-commit issues * pre-commit fixes * updated for _prepare_chat signature changes * Better instructions for demo and some minor refactoring * Added details that explain CAP * Reformat Readme * More ReadMe Formatting * Readme edits * Agent -> Actor * Broker can startup on it's own * Remote AutoGen Agents * Updated docs * 1) StandaloneBroker in demo 2) Removed Autogen only demo options * 1) Agent -> Actor refactor 2) init broker as early * rename user_proxy -> user_proxy_conn * Add DirectorySvc * Standalone demo refactor * Get ActorInfo from DirectorySvc when searching for Actor * Broker cleanup * Proper cleanup and remove debug sleep() * Run one directory service only. * fix paths to run demo apps from command line * Handle keyboard interrupt * Wait for Broker and Directory to start up * Move Terminate AGActor * Accept input from the user in UserProxy * Move sleeps close to operations that bind or connect * Comments * Created an encapsulated CAP Pair for AutoGen pair communication * pre-commit checks * fix pre-commit * Pair should not make assumptions about who is first and who is second * Use task passed into InitiateChat * Standalone directory svc * Fix broken LFS files * Long running DirectorySvc * DirectorySvc does not have a status * Exit DirectorySvc Loop * Debugging Remoting * Reduce frequency of status messages * Debugging remote Actor * roll back git-lfs updates * rollback git-lfs changes * Debug network connectivity * pre-commit fixes * Create a group chat interface familiar to AutoGen GroupChat users * pre-commit fixes
This commit is contained in:
		
							parent
							
								
									a120f0ed2b
								
							
						
					
					
						commit
						8f6590e231
					
				
							
								
								
									
										54
									
								
								samples/apps/cap/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								samples/apps/cap/README.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
			
		||||
# Composable Actor Platform (CAP) for AutoGen
 | 
			
		||||
 | 
			
		||||
## I just want to run the demo!
 | 
			
		||||
*Python Instructions (Windows, Linux, MacOS):*
 | 
			
		||||
 | 
			
		||||
0) cd py
 | 
			
		||||
1) pip install -r autogencap/requirements.txt
 | 
			
		||||
2) python ./demo/App.py
 | 
			
		||||
 | 
			
		||||
*Demo Notes:*
 | 
			
		||||
1) Options involving AutoGen require OAI_CONFIG_LIST.
 | 
			
		||||
   AutoGen python requirements: 3.8 <= python <= 3.11
 | 
			
		||||
2) For option 2, type something in and see who receives the message.  Quit to quit.
 | 
			
		||||
3) To view any option that displays a chart (such as option 4), you will need to disable Docker code execution. You can do this by setting the environment variable `AUTOGEN_USE_DOCKER` to `False`.
 | 
			
		||||
 | 
			
		||||
*Demo Reference:*
 | 
			
		||||
```
 | 
			
		||||
    Select the Composable Actor Platform (CAP) demo app to run:
 | 
			
		||||
    (enter anything else to quit)
 | 
			
		||||
    1. Hello World Actor
 | 
			
		||||
    2. Complex Actor Graph
 | 
			
		||||
    3. AutoGen Pair
 | 
			
		||||
    4. AutoGen GroupChat
 | 
			
		||||
    5. AutoGen Agents in different processes
 | 
			
		||||
    Enter your choice (1-5):
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## What is Composable Actor Platform (CAP)?
 | 
			
		||||
AutoGen is about Agents and Agent Orchestration.  CAP extends AutoGen to allows Agents to communicate via a message bus.  CAP, therefore, deals with the space between these components.  CAP is a message based, actor platform that allows actors to be composed into arbitrary graphs.
 | 
			
		||||
 | 
			
		||||
Actors can register themselves with CAP, find other agents, construct arbitrary graphs, send and receive messages independently and many, many, many other things.
 | 
			
		||||
```python
 | 
			
		||||
    # CAP Platform
 | 
			
		||||
    network = LocalActorNetwork()
 | 
			
		||||
    # Register an agent
 | 
			
		||||
    network.register(GreeterAgent())
 | 
			
		||||
    # Tell agents to connect to other agents
 | 
			
		||||
    network.connect()
 | 
			
		||||
    # Get a channel to the agent
 | 
			
		||||
    greeter_link = network.lookup_agent("Greeter")
 | 
			
		||||
    # Send a message to the agent
 | 
			
		||||
    greeter_link.send_txt_msg("Hello World!")
 | 
			
		||||
    # Cleanup
 | 
			
		||||
    greeter_link.close()
 | 
			
		||||
    network.disconnect()
 | 
			
		||||
```
 | 
			
		||||
### Check out other demos in the `py/demo` directory.  We show the following: ###
 | 
			
		||||
1) Hello World shown above
 | 
			
		||||
2) Many CAP Actors interacting with each other
 | 
			
		||||
3) A pair of interacting AutoGen Agents wrapped in CAP Actors
 | 
			
		||||
4) CAP wrapped AutoGen Agents in a group chat
 | 
			
		||||
 | 
			
		||||
### Coming soon. Stay tuned! ###
 | 
			
		||||
1) Two AutoGen Agents running in different processes and communicating through CAP
 | 
			
		||||
							
								
								
									
										21
									
								
								samples/apps/cap/TODO.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								samples/apps/cap/TODO.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
- ~~Pretty print debug_logs~~
 | 
			
		||||
  - ~~colors~~
 | 
			
		||||
  - ~~messages to oai should be condensed~~
 | 
			
		||||
- ~~remove orchestrator in scenario 4 and have the two actors talk to each other~~
 | 
			
		||||
- ~~pass a complex multi-part message~~
 | 
			
		||||
- ~~protobuf for messages~~
 | 
			
		||||
- ~~make changes to autogen to enable scenario 3 to work with CAN~~
 | 
			
		||||
- ~~make groupchat work~~
 | 
			
		||||
- ~~actors instead of agents~~
 | 
			
		||||
- clean up for PR into autogen
 | 
			
		||||
  - ~~Create folder structure under Autogen examples~~
 | 
			
		||||
  - ~~CAN -> CAP (Composable Actor Protocol)~~
 | 
			
		||||
- CAP actor lookup should use zmq
 | 
			
		||||
- Add min C# actors & reorganize
 | 
			
		||||
- Hybrid GroupChat with C# ProductManager
 | 
			
		||||
- C++ Msg Layer
 | 
			
		||||
- Rust Msg Layer
 | 
			
		||||
- Node Msg Layer
 | 
			
		||||
- Java Msg Layer
 | 
			
		||||
- Investigate a standard logging framework that supports color in windows
 | 
			
		||||
  - structlog?
 | 
			
		||||
							
								
								
									
										1
									
								
								samples/apps/cap/c#/Readme.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								samples/apps/cap/c#/Readme.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
Coming soon...
 | 
			
		||||
							
								
								
									
										1
									
								
								samples/apps/cap/c++/Readme.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								samples/apps/cap/c++/Readme.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
Coming soon...
 | 
			
		||||
							
								
								
									
										1
									
								
								samples/apps/cap/node/Readme.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								samples/apps/cap/node/Readme.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
Coming soon...
 | 
			
		||||
							
								
								
									
										78
									
								
								samples/apps/cap/py/autogencap/Actor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								samples/apps/cap/py/autogencap/Actor.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,78 @@
 | 
			
		||||
import zmq
 | 
			
		||||
import threading
 | 
			
		||||
import traceback
 | 
			
		||||
import time
 | 
			
		||||
from .DebugLog import Debug, Info
 | 
			
		||||
from .Config import xpub_url
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Actor:
 | 
			
		||||
    def __init__(self, agent_name: str, description: str):
 | 
			
		||||
        self.actor_name: str = agent_name
 | 
			
		||||
        self.agent_description: str = description
 | 
			
		||||
        self.run = False
 | 
			
		||||
 | 
			
		||||
    def connect_network(self, network):
 | 
			
		||||
        Debug(self.actor_name, f"is connecting to {network}")
 | 
			
		||||
        Debug(self.actor_name, "connected")
 | 
			
		||||
 | 
			
		||||
    def _process_txt_msg(self, msg: str, msg_type: str, topic: str, sender: str) -> bool:
 | 
			
		||||
        Info(self.actor_name, f"InBox: {msg}")
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def _process_bin_msg(self, msg: bytes, msg_type: str, topic: str, sender: str) -> bool:
 | 
			
		||||
        Info(self.actor_name, f"Msg: topic=[{topic}], msg_type=[{msg_type}]")
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def _recv_thread(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}")
 | 
			
		||||
        try:
 | 
			
		||||
            while self.run:
 | 
			
		||||
                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:
 | 
			
		||||
                    continue  # No message received, continue to next iteration
 | 
			
		||||
                except Exception:
 | 
			
		||||
                    continue
 | 
			
		||||
                if msg_type == "text":
 | 
			
		||||
                    msg = msg.decode("utf-8")  # Convert bytes to string
 | 
			
		||||
                    if not self._process_txt_msg(msg, msg_type, topic, sender_topic):
 | 
			
		||||
                        msg = "quit"
 | 
			
		||||
                    if msg.lower() == "quit":
 | 
			
		||||
                        break
 | 
			
		||||
                else:
 | 
			
		||||
                    if not self._process_bin_msg(msg, msg_type, topic, sender_topic):
 | 
			
		||||
                        break
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            Debug(self.actor_name, f"recv thread encountered an error: {e}")
 | 
			
		||||
            traceback.print_exc()
 | 
			
		||||
        finally:
 | 
			
		||||
            self.run = False
 | 
			
		||||
            Debug(self.actor_name, "recv thread ended")
 | 
			
		||||
 | 
			
		||||
    def start(self, context: zmq.Context):
 | 
			
		||||
        self._context = context
 | 
			
		||||
        self.run: bool = True
 | 
			
		||||
        self._thread = threading.Thread(target=self._recv_thread)
 | 
			
		||||
        self._thread.start()
 | 
			
		||||
        time.sleep(0.01)
 | 
			
		||||
 | 
			
		||||
    def disconnect_network(self, network):
 | 
			
		||||
        Debug(self.actor_name, f"is disconnecting from {network}")
 | 
			
		||||
        Debug(self.actor_name, "disconnected")
 | 
			
		||||
        self.stop()
 | 
			
		||||
 | 
			
		||||
    def stop(self):
 | 
			
		||||
        self.run = False
 | 
			
		||||
        self._thread.join()
 | 
			
		||||
        self._socket.setsockopt(zmq.LINGER, 0)
 | 
			
		||||
        self._socket.close()
 | 
			
		||||
							
								
								
									
										57
									
								
								samples/apps/cap/py/autogencap/ActorConnector.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								samples/apps/cap/py/autogencap/ActorConnector.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
# 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 zmq
 | 
			
		||||
import time
 | 
			
		||||
import uuid
 | 
			
		||||
from .DebugLog import Debug, Error
 | 
			
		||||
from .Config import xsub_url, xpub_url
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ActorConnector:
 | 
			
		||||
    def __init__(self, context, topic):
 | 
			
		||||
        self._pub_socket = context.socket(zmq.PUB)
 | 
			
		||||
        self._pub_socket.setsockopt(zmq.LINGER, 0)
 | 
			
		||||
        self._pub_socket.connect(xsub_url)
 | 
			
		||||
 | 
			
		||||
        self._resp_socket = context.socket(zmq.SUB)
 | 
			
		||||
        self._resp_socket.setsockopt(zmq.LINGER, 0)
 | 
			
		||||
        self._resp_socket.setsockopt(zmq.RCVTIMEO, 10000)
 | 
			
		||||
        self._resp_socket.connect(xpub_url)
 | 
			
		||||
        self._resp_topic = str(uuid.uuid4())
 | 
			
		||||
        Debug("AgentConnector", f"subscribe to: {self._resp_topic}")
 | 
			
		||||
        self._resp_socket.setsockopt_string(zmq.SUBSCRIBE, f"{self._resp_topic}")
 | 
			
		||||
        self._topic = topic
 | 
			
		||||
        time.sleep(0.01)  # Let the network do things.
 | 
			
		||||
 | 
			
		||||
    def send_txt_msg(self, msg):
 | 
			
		||||
        self._pub_socket.send_multipart(
 | 
			
		||||
            [self._topic.encode("utf8"), "text".encode("utf8"), self._resp_topic.encode("utf8"), msg.encode("utf8")]
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def send_bin_msg(self, msg_type: str, msg):
 | 
			
		||||
        self._pub_socket.send_multipart(
 | 
			
		||||
            [self._topic.encode("utf8"), msg_type.encode("utf8"), self._resp_topic.encode("utf8"), msg]
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def binary_request(self, msg_type: str, msg, retry=5):
 | 
			
		||||
        time.sleep(0.5)  # Let the network do things.
 | 
			
		||||
        self._pub_socket.send_multipart(
 | 
			
		||||
            [self._topic.encode("utf8"), msg_type.encode("utf8"), self._resp_topic.encode("utf8"), msg]
 | 
			
		||||
        )
 | 
			
		||||
        time.sleep(0.5)  # Let the network do things.
 | 
			
		||||
        for i in range(retry + 1):
 | 
			
		||||
            try:
 | 
			
		||||
                self._resp_socket.setsockopt(zmq.RCVTIMEO, 10000)
 | 
			
		||||
                resp_topic, resp_msg_type, resp_sender_topic, resp = self._resp_socket.recv_multipart()
 | 
			
		||||
                return resp_topic, resp_msg_type, resp_sender_topic, resp
 | 
			
		||||
            except zmq.Again:
 | 
			
		||||
                Debug("ActorConnector", f"binary_request: No response received. retry_count={i}, max_retry={retry}")
 | 
			
		||||
                time.sleep(0.01)  # Wait a bit before retrying
 | 
			
		||||
                continue
 | 
			
		||||
        Error("ActorConnector", "binary_request: No response received. Giving up.")
 | 
			
		||||
        return None, None, None, None
 | 
			
		||||
 | 
			
		||||
    def close(self):
 | 
			
		||||
        self._pub_socket.close()
 | 
			
		||||
        self._resp_socket.close()
 | 
			
		||||
							
								
								
									
										114
									
								
								samples/apps/cap/py/autogencap/Broker.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								samples/apps/cap/py/autogencap/Broker.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,114 @@
 | 
			
		||||
import time
 | 
			
		||||
import zmq
 | 
			
		||||
import threading
 | 
			
		||||
from autogencap.DebugLog import Debug, Info, Warn
 | 
			
		||||
from autogencap.Config import xsub_url, xpub_url
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Broker:
 | 
			
		||||
    def __init__(self, context: zmq.Context = zmq.Context()):
 | 
			
		||||
        self._context: zmq.Context = context
 | 
			
		||||
        self._run: bool = False
 | 
			
		||||
        self._xpub: zmq.Socket = None
 | 
			
		||||
        self._xsub: zmq.Socket = None
 | 
			
		||||
 | 
			
		||||
    def start(self) -> bool:
 | 
			
		||||
        try:
 | 
			
		||||
            # XPUB setup
 | 
			
		||||
            self._xpub = self._context.socket(zmq.XPUB)
 | 
			
		||||
            self._xpub.setsockopt(zmq.LINGER, 0)
 | 
			
		||||
            self._xpub.bind(xpub_url)
 | 
			
		||||
 | 
			
		||||
            # XSUB setup
 | 
			
		||||
            self._xsub = self._context.socket(zmq.XSUB)
 | 
			
		||||
            self._xsub.setsockopt(zmq.LINGER, 0)
 | 
			
		||||
            self._xsub.bind(xsub_url)
 | 
			
		||||
 | 
			
		||||
        except zmq.ZMQError as e:
 | 
			
		||||
            Debug("BROKER", f"Unable to start.  Check details: {e}")
 | 
			
		||||
            # If binding fails, close the sockets and return False
 | 
			
		||||
            if self._xpub:
 | 
			
		||||
                self._xpub.close()
 | 
			
		||||
            if self._xsub:
 | 
			
		||||
                self._xsub.close()
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
        self._run = True
 | 
			
		||||
        self._broker_thread: threading.Thread = threading.Thread(target=self.thread_fn)
 | 
			
		||||
        self._broker_thread.start()
 | 
			
		||||
        time.sleep(0.01)
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def stop(self):
 | 
			
		||||
        # Error("BROKER_ERR", "fix cleanup self._context.term()")
 | 
			
		||||
        Debug("BROKER", "stopped")
 | 
			
		||||
        self._run = False
 | 
			
		||||
        self._broker_thread.join()
 | 
			
		||||
        if self._xpub:
 | 
			
		||||
            self._xpub.close()
 | 
			
		||||
        if self._xsub:
 | 
			
		||||
            self._xsub.close()
 | 
			
		||||
        # self._context.term()
 | 
			
		||||
 | 
			
		||||
    def thread_fn(self):
 | 
			
		||||
        try:
 | 
			
		||||
            # Poll sockets for events
 | 
			
		||||
            self._poller: zmq.Poller = zmq.Poller()
 | 
			
		||||
            self._poller.register(self._xpub, zmq.POLLIN)
 | 
			
		||||
            self._poller.register(self._xsub, zmq.POLLIN)
 | 
			
		||||
 | 
			
		||||
            # Receive msgs, forward and process
 | 
			
		||||
            while self._run:
 | 
			
		||||
                events = dict(self._poller.poll(500))
 | 
			
		||||
                if self._xpub in events:
 | 
			
		||||
                    message = self._xpub.recv_multipart()
 | 
			
		||||
                    Debug("BROKER", f"subscription message: {message[0]}")
 | 
			
		||||
                    self._xsub.send_multipart(message)
 | 
			
		||||
 | 
			
		||||
                if self._xsub in events:
 | 
			
		||||
                    message = self._xsub.recv_multipart()
 | 
			
		||||
                    Debug("BROKER", f"publishing message: {message}")
 | 
			
		||||
                    self._xpub.send_multipart(message)
 | 
			
		||||
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            Debug("BROKER", f"thread encountered an error: {e}")
 | 
			
		||||
        finally:
 | 
			
		||||
            self._run = False
 | 
			
		||||
            Debug("BROKER", "thread ended")
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Run a standalone broker that all other Actors can connect to.
 | 
			
		||||
# This can also run inproc with the other actors.
 | 
			
		||||
def main():
 | 
			
		||||
    broker = Broker()
 | 
			
		||||
    Info("BROKER", "Starting.")
 | 
			
		||||
    if broker.start():
 | 
			
		||||
        Info("BROKER", "Running.")
 | 
			
		||||
    else:
 | 
			
		||||
        Warn("BROKER", "Failed to start.")
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    status_interval = 300  # seconds
 | 
			
		||||
    last_time = time.time()
 | 
			
		||||
 | 
			
		||||
    # Broker is running in a separate thread. Here we are watching the
 | 
			
		||||
    # broker's status and printing status every few seconds.  This is
 | 
			
		||||
    # a good place to print other statistics captured as the broker runs.
 | 
			
		||||
    # -- Exits when the user presses Ctrl+C --
 | 
			
		||||
    while broker._run:
 | 
			
		||||
        # print a message every n seconds
 | 
			
		||||
        current_time = time.time()
 | 
			
		||||
        elapsed_time = current_time - last_time
 | 
			
		||||
        if elapsed_time > status_interval:
 | 
			
		||||
            Info("BROKER", "Running.")
 | 
			
		||||
            last_time = current_time
 | 
			
		||||
        try:
 | 
			
		||||
            time.sleep(0.5)
 | 
			
		||||
        except KeyboardInterrupt:
 | 
			
		||||
            Info("BROKER", "KeyboardInterrupt.  Stopping the broker.")
 | 
			
		||||
            broker.stop()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										5
									
								
								samples/apps/cap/py/autogencap/Config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								samples/apps/cap/py/autogencap/Config.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
# Set the current log level
 | 
			
		||||
LOG_LEVEL = 0
 | 
			
		||||
IGNORED_LOG_CONTEXTS = []
 | 
			
		||||
xpub_url: str = "tcp://127.0.0.1:5555"
 | 
			
		||||
xsub_url: str = "tcp://127.0.0.1:5556"
 | 
			
		||||
							
								
								
									
										2
									
								
								samples/apps/cap/py/autogencap/Constants.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								samples/apps/cap/py/autogencap/Constants.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
Termination_Topic: str = "Termination"
 | 
			
		||||
Directory_Svc_Topic: str = "Directory_Svc"
 | 
			
		||||
							
								
								
									
										73
									
								
								samples/apps/cap/py/autogencap/DebugLog.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								samples/apps/cap/py/autogencap/DebugLog.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,73 @@
 | 
			
		||||
import threading
 | 
			
		||||
import datetime
 | 
			
		||||
from autogencap.Config import LOG_LEVEL, IGNORED_LOG_CONTEXTS
 | 
			
		||||
from termcolor import colored
 | 
			
		||||
 | 
			
		||||
# Define log levels as constants
 | 
			
		||||
DEBUG = 0
 | 
			
		||||
INFO = 1
 | 
			
		||||
WARN = 2
 | 
			
		||||
ERROR = 3
 | 
			
		||||
 | 
			
		||||
# Map log levels to their names
 | 
			
		||||
LEVEL_NAMES = ["DBG", "INF", "WRN", "ERR"]
 | 
			
		||||
LEVEL_COLOR = ["dark_grey", "green", "yellow", "red"]
 | 
			
		||||
 | 
			
		||||
console_lock = threading.Lock()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Log(level, context, msg):
 | 
			
		||||
    # Check if the current level meets the threshold
 | 
			
		||||
    if level >= LOG_LEVEL:  # Use the LOG_LEVEL from the Config module
 | 
			
		||||
        # Check if the context is in the list of ignored contexts
 | 
			
		||||
        if context in IGNORED_LOG_CONTEXTS:
 | 
			
		||||
            return
 | 
			
		||||
        with console_lock:
 | 
			
		||||
            timestamp = colored(datetime.datetime.now().strftime("%m/%d/%y %H:%M:%S"), "dark_grey")
 | 
			
		||||
            # Translate level number to name and color
 | 
			
		||||
            level_name = colored(LEVEL_NAMES[level], LEVEL_COLOR[level])
 | 
			
		||||
            # Center justify the context and color it blue
 | 
			
		||||
            context = colored(context.ljust(14), "blue")
 | 
			
		||||
            # color the msg based on the level
 | 
			
		||||
            msg = colored(msg, LEVEL_COLOR[level])
 | 
			
		||||
            print(f"{threading.get_ident()} {timestamp} {level_name}: [{context}] {msg}")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Debug(context, message):
 | 
			
		||||
    Log(DEBUG, context, message)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Info(context, message):
 | 
			
		||||
    Log(INFO, context, message)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Warn(context, message):
 | 
			
		||||
    Log(WARN, context, message)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def Error(context, message):
 | 
			
		||||
    Log(ERROR, context, message)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def shorten(msg, num_parts=5, max_len=100):
 | 
			
		||||
    # Remove new lines
 | 
			
		||||
    msg = msg.replace("\n", " ")
 | 
			
		||||
 | 
			
		||||
    # If the message is shorter than or equal to max_len characters, return it as is
 | 
			
		||||
    if len(msg) <= max_len:
 | 
			
		||||
        return msg
 | 
			
		||||
 | 
			
		||||
    # Calculate the length of each part
 | 
			
		||||
    part_len = max_len // num_parts
 | 
			
		||||
 | 
			
		||||
    # Create a list to store the parts
 | 
			
		||||
    parts = []
 | 
			
		||||
 | 
			
		||||
    # Get the parts from the message
 | 
			
		||||
    for i in range(num_parts):
 | 
			
		||||
        start = i * part_len
 | 
			
		||||
        end = start + part_len
 | 
			
		||||
        parts.append(msg[start:end])
 | 
			
		||||
 | 
			
		||||
    # Join the parts with '...' and return the result
 | 
			
		||||
    return "...".join(parts)
 | 
			
		||||
							
								
								
									
										210
									
								
								samples/apps/cap/py/autogencap/DirectorySvc.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								samples/apps/cap/py/autogencap/DirectorySvc.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,210 @@
 | 
			
		||||
from autogencap.Constants import Directory_Svc_Topic
 | 
			
		||||
from autogencap.Config import xpub_url, xsub_url
 | 
			
		||||
from autogencap.DebugLog import Debug, Info, Error
 | 
			
		||||
from autogencap.ActorConnector import ActorConnector
 | 
			
		||||
from autogencap.Actor import Actor
 | 
			
		||||
from autogencap.proto.CAP_pb2 import ActorRegistration, ActorInfo, ActorLookup, ActorLookupResponse, Ping, Pong
 | 
			
		||||
import zmq
 | 
			
		||||
import threading
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
# 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):
 | 
			
		||||
        super().__init__(topic, name)
 | 
			
		||||
        self._registered_actors = {}
 | 
			
		||||
        self._network_prefix = ""
 | 
			
		||||
 | 
			
		||||
    def _process_bin_msg(self, msg: bytes, msg_type: str, topic: str, sender: str) -> bool:
 | 
			
		||||
        if msg_type == ActorRegistration.__name__:
 | 
			
		||||
            self._actor_registration_msg_handler(topic, msg_type, msg)
 | 
			
		||||
        elif msg_type == ActorLookup.__name__:
 | 
			
		||||
            self._actor_lookup_msg_handler(topic, msg_type, msg, sender)
 | 
			
		||||
        elif msg_type == Ping.__name__:
 | 
			
		||||
            self._ping_msg_handler(topic, msg_type, msg, sender)
 | 
			
		||||
        else:
 | 
			
		||||
            Error("DirectorySvc", f"Unknown message type: {msg_type}")
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def _ping_msg_handler(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 = ActorConnector(self._context, sender_topic)
 | 
			
		||||
        sender_connection.send_bin_msg(Pong.__name__, serialized_msg)
 | 
			
		||||
 | 
			
		||||
    def _actor_registration_msg_handler(self, topic: str, msg_type: str, msg: bytes):
 | 
			
		||||
        actor_reg = ActorRegistration()
 | 
			
		||||
        actor_reg.ParseFromString(msg)
 | 
			
		||||
        Info("DirectorySvc", f"Actor registration: {actor_reg.actor_info.name}")
 | 
			
		||||
        name = actor_reg.actor_info.name
 | 
			
		||||
        # TODO (Future DirectorySv PR) network_id should be namespace prefixed to support multiple networks
 | 
			
		||||
        actor_reg.actor_info.name + self._network_prefix
 | 
			
		||||
        if name in self._registered_actors:
 | 
			
		||||
            Error("DirectorySvc", f"Actor already registered: {name}")
 | 
			
		||||
            return
 | 
			
		||||
        self._registered_actors[name] = actor_reg.actor_info
 | 
			
		||||
 | 
			
		||||
    def _actor_lookup_msg_handler(self, topic: str, msg_type: str, msg: bytes, sender_topic: str):
 | 
			
		||||
        actor_lookup = ActorLookup()
 | 
			
		||||
        actor_lookup.ParseFromString(msg)
 | 
			
		||||
        Debug("DirectorySvc", f"Actor lookup: {actor_lookup.actor_info.name}")
 | 
			
		||||
        actor: ActorInfo = None
 | 
			
		||||
        if actor_lookup.actor_info.name in self._registered_actors:
 | 
			
		||||
            Info("DirectorySvc", f"Actor found: {actor_lookup.actor_info.name}")
 | 
			
		||||
            actor = self._registered_actors[actor_lookup.actor_info.name]
 | 
			
		||||
        else:
 | 
			
		||||
            Error("DirectorySvc", f"Actor not found: {actor_lookup.actor_info.name}")
 | 
			
		||||
        actor_lookup_resp = ActorLookupResponse()
 | 
			
		||||
        if actor is not None:
 | 
			
		||||
            actor_lookup_resp.actor.info_coll.extend([actor])
 | 
			
		||||
            actor_lookup_resp.found = True
 | 
			
		||||
        else:
 | 
			
		||||
            actor_lookup_resp.found = False
 | 
			
		||||
        sender_connection = ActorConnector(self._context, sender_topic)
 | 
			
		||||
        serialized_msg = actor_lookup_resp.SerializeToString()
 | 
			
		||||
        sender_connection.send_bin_msg(ActorLookupResponse.__name__, serialized_msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DirectorySvc:
 | 
			
		||||
    def __init__(self, context: zmq.Context = zmq.Context()):
 | 
			
		||||
        self._context: zmq.Context = context
 | 
			
		||||
        self._directory_connector: ActorConnector = None
 | 
			
		||||
        self._directory_actor: DirectoryActor = None
 | 
			
		||||
 | 
			
		||||
    def _no_other_directory(self) -> bool:
 | 
			
		||||
        ping = Ping()
 | 
			
		||||
        serialized_msg = ping.SerializeToString()
 | 
			
		||||
        _, _, _, resp = self._directory_connector.binary_request(Ping.__name__, serialized_msg, retry=0)
 | 
			
		||||
        if resp is None:
 | 
			
		||||
            return True
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def start(self):
 | 
			
		||||
        self._directory_connector = ActorConnector(self._context, Directory_Svc_Topic)
 | 
			
		||||
        if self._no_other_directory():
 | 
			
		||||
            self._directory_actor = DirectoryActor(Directory_Svc_Topic, "Directory Service")
 | 
			
		||||
            self._directory_actor.start(self._context)
 | 
			
		||||
            Info("DirectorySvc", "Directory service started.")
 | 
			
		||||
        else:
 | 
			
		||||
            Info("DirectorySvc", "Another directory service is running. This instance will not start.")
 | 
			
		||||
 | 
			
		||||
    def stop(self):
 | 
			
		||||
        if self._directory_actor:
 | 
			
		||||
            self._directory_actor.stop()
 | 
			
		||||
        if self._directory_connector:
 | 
			
		||||
            self._directory_connector.close()
 | 
			
		||||
 | 
			
		||||
    def register_actor(self, actor_info: ActorInfo):
 | 
			
		||||
        # Send a message to the directory service
 | 
			
		||||
        # to register the actor
 | 
			
		||||
        actor_reg = ActorRegistration()
 | 
			
		||||
        actor_reg.actor_info.CopyFrom(actor_info)
 | 
			
		||||
        serialized_msg = actor_reg.SerializeToString()
 | 
			
		||||
        self._directory_connector.send_bin_msg(ActorRegistration.__name__, serialized_msg)
 | 
			
		||||
 | 
			
		||||
    def register_actor_by_name(self, actor_name: str):
 | 
			
		||||
        actor_info = ActorInfo(name=actor_name)
 | 
			
		||||
        self.register_actor(actor_info)
 | 
			
		||||
 | 
			
		||||
    def lookup_actor_by_name(self, actor_name: str) -> ActorInfo:
 | 
			
		||||
        actor_info = ActorInfo(name=actor_name)
 | 
			
		||||
        actor_lookup = ActorLookup(actor_info=actor_info)
 | 
			
		||||
        serialized_msg = actor_lookup.SerializeToString()
 | 
			
		||||
        _, _, _, resp = self._directory_connector.binary_request(ActorLookup.__name__, serialized_msg)
 | 
			
		||||
        actor_lookup_resp = ActorLookupResponse()
 | 
			
		||||
        actor_lookup_resp.ParseFromString(resp)
 | 
			
		||||
        if actor_lookup_resp.found:
 | 
			
		||||
            if len(actor_lookup_resp.actor.info_coll) > 0:
 | 
			
		||||
                return actor_lookup_resp.actor.info_coll[0]
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Standalone min proxy for a standalone directory service
 | 
			
		||||
class MinProxy:
 | 
			
		||||
    def __init__(self, context: zmq.Context):
 | 
			
		||||
        self._context: zmq.Context = context
 | 
			
		||||
        self._xpub: zmq.Socket = None
 | 
			
		||||
        self._xsub: zmq.Socket = None
 | 
			
		||||
 | 
			
		||||
    def start(self):
 | 
			
		||||
        # Start the proxy thread
 | 
			
		||||
        proxy_thread = threading.Thread(target=self.proxy_thread_fn)
 | 
			
		||||
        proxy_thread.start()
 | 
			
		||||
        time.sleep(0.01)
 | 
			
		||||
 | 
			
		||||
    def stop(self):
 | 
			
		||||
        self._xsub.setsockopt(zmq.LINGER, 0)
 | 
			
		||||
        self._xpub.setsockopt(zmq.LINGER, 0)
 | 
			
		||||
        self._xpub.close()
 | 
			
		||||
        self._xsub.close()
 | 
			
		||||
        time.sleep(0.01)
 | 
			
		||||
 | 
			
		||||
    def proxy_thread_fn(self):
 | 
			
		||||
        self._xpub: zmq.Socket = self._context.socket(zmq.XPUB)
 | 
			
		||||
        self._xsub: zmq.Socket = self._context.socket(zmq.XSUB)
 | 
			
		||||
        try:
 | 
			
		||||
            self._xpub.bind(xpub_url)
 | 
			
		||||
            self._xsub.bind(xsub_url)
 | 
			
		||||
            zmq.proxy(self._xpub, self._xsub)
 | 
			
		||||
        except zmq.ContextTerminated:
 | 
			
		||||
            self._xpub.close()
 | 
			
		||||
            self._xsub.close()
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            Error("proxy_thread_fn", f"proxy_thread_fn encountered an error: {e}")
 | 
			
		||||
            self._xpub.setsockopt(zmq.LINGER, 0)
 | 
			
		||||
            self._xsub.setsockopt(zmq.LINGER, 0)
 | 
			
		||||
            self._xpub.close()
 | 
			
		||||
            self._xsub.close()
 | 
			
		||||
        finally:
 | 
			
		||||
            Info("proxy_thread_fn", "proxy_thread_fn terminated.")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Run a standalone directory service
 | 
			
		||||
def main():
 | 
			
		||||
    context: zmq.Context = zmq.Context()
 | 
			
		||||
    # Start simple broker (will exit if real broker is running)
 | 
			
		||||
    proxy: MinProxy = MinProxy(context)
 | 
			
		||||
    proxy.start()
 | 
			
		||||
    # Start the directory service
 | 
			
		||||
    directory_svc = DirectorySvc(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
 | 
			
		||||
    # a good place to print other statistics captured as the broker runs.
 | 
			
		||||
    # -- Exits when the user presses Ctrl+C --
 | 
			
		||||
    status_interval = 300  # seconds
 | 
			
		||||
    last_time = time.time()
 | 
			
		||||
    while True:
 | 
			
		||||
        # print a message every n seconds
 | 
			
		||||
        current_time = time.time()
 | 
			
		||||
        elapsed_time = current_time - last_time
 | 
			
		||||
        if elapsed_time > status_interval:
 | 
			
		||||
            Info("DirectorySvc", "Running.")
 | 
			
		||||
            last_time = current_time
 | 
			
		||||
        try:
 | 
			
		||||
            time.sleep(0.5)
 | 
			
		||||
        except KeyboardInterrupt:
 | 
			
		||||
            Info("DirectorySvc", "KeyboardInterrupt.  Stopping the DirectorySvc.")
 | 
			
		||||
            break
 | 
			
		||||
 | 
			
		||||
    directory_svc.stop()
 | 
			
		||||
    proxy.stop()
 | 
			
		||||
    context.term()
 | 
			
		||||
    Info("main", "Done.")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										71
									
								
								samples/apps/cap/py/autogencap/LocalActorNetwork.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								samples/apps/cap/py/autogencap/LocalActorNetwork.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
			
		||||
import zmq
 | 
			
		||||
from .DebugLog import Debug, Warn
 | 
			
		||||
from .ActorConnector import ActorConnector
 | 
			
		||||
from .Broker import Broker
 | 
			
		||||
from .DirectorySvc import DirectorySvc
 | 
			
		||||
from .Constants import Termination_Topic
 | 
			
		||||
from .Actor import Actor
 | 
			
		||||
from .proto.CAP_pb2 import ActorInfo
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
# TODO: remove time import
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LocalActorNetwork:
 | 
			
		||||
    def __init__(self, name: str = "Local Actor Network", 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
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return f"{self.name}"
 | 
			
		||||
 | 
			
		||||
    def _init_runtime(self):
 | 
			
		||||
        if self._start_broker and self._broker is None:
 | 
			
		||||
            self._broker = Broker(self._context)
 | 
			
		||||
            if not self._broker.start():
 | 
			
		||||
                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()
 | 
			
		||||
 | 
			
		||||
    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.start(self._context)
 | 
			
		||||
        Debug("Local_Actor_Network", f"{actor.actor_name} registered in the network.")
 | 
			
		||||
 | 
			
		||||
    def connect(self):
 | 
			
		||||
        self._init_runtime()
 | 
			
		||||
        for actor in self.local_actors.values():
 | 
			
		||||
            actor.connect_network(self)
 | 
			
		||||
 | 
			
		||||
    def disconnect(self):
 | 
			
		||||
        for actor in self.local_actors.values():
 | 
			
		||||
            actor.disconnect_network(self)
 | 
			
		||||
        if self._directory_svc:
 | 
			
		||||
            self._directory_svc.stop()
 | 
			
		||||
        if self._broker:
 | 
			
		||||
            self._broker.stop()
 | 
			
		||||
 | 
			
		||||
    def actor_connector_by_topic(self, topic: str) -> ActorConnector:
 | 
			
		||||
        return ActorConnector(self._context, topic)
 | 
			
		||||
 | 
			
		||||
    def lookup_actor(self, name: str) -> ActorConnector:
 | 
			
		||||
        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.")
 | 
			
		||||
            return None
 | 
			
		||||
        Debug("Local_Actor_Network", f"[{name}] found in the network.")
 | 
			
		||||
        return self.actor_connector_by_topic(name)
 | 
			
		||||
 | 
			
		||||
    def lookup_termination(self) -> ActorConnector:
 | 
			
		||||
        termination_topic: str = Termination_Topic
 | 
			
		||||
        return self.actor_connector_by_topic(termination_topic)
 | 
			
		||||
							
								
								
									
										0
									
								
								samples/apps/cap/py/autogencap/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								samples/apps/cap/py/autogencap/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										81
									
								
								samples/apps/cap/py/autogencap/ag_adapter/AG2CAP.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								samples/apps/cap/py/autogencap/ag_adapter/AG2CAP.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
			
		||||
import time
 | 
			
		||||
from typing import Callable, Dict, List, Optional, Union
 | 
			
		||||
from autogen import Agent, ConversableAgent
 | 
			
		||||
from .AutoGenConnector import AutoGenConnector
 | 
			
		||||
from ..LocalActorNetwork import LocalActorNetwork
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AG2CAP(ConversableAgent):
 | 
			
		||||
    """
 | 
			
		||||
    A conversable agent proxy that sends messages to CAN when called
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        network: LocalActorNetwork,
 | 
			
		||||
        agent_name: str,
 | 
			
		||||
        agent_description: Optional[str] = None,
 | 
			
		||||
    ):
 | 
			
		||||
        super().__init__(name=agent_name, description=agent_description, llm_config=False)
 | 
			
		||||
        self._agent_connector: AutoGenConnector = None
 | 
			
		||||
        self._network: LocalActorNetwork = network
 | 
			
		||||
        self._recv_called = False
 | 
			
		||||
 | 
			
		||||
    def reset_receive_called(self):
 | 
			
		||||
        self._recv_called = False
 | 
			
		||||
 | 
			
		||||
    def was_receive_called(self):
 | 
			
		||||
        return self._recv_called
 | 
			
		||||
 | 
			
		||||
    def set_name(self, name: str):
 | 
			
		||||
        """
 | 
			
		||||
        Set the name of the agent.
 | 
			
		||||
        Why? because we need it to look like different agents
 | 
			
		||||
        """
 | 
			
		||||
        self._name = name
 | 
			
		||||
 | 
			
		||||
    def _check_connection(self):
 | 
			
		||||
        if self._agent_connector is None:
 | 
			
		||||
            self._agent_connector = AutoGenConnector(self._network.lookup_actor(self.name))
 | 
			
		||||
            self._terminate_connector = AutoGenConnector(self._network.lookup_termination())
 | 
			
		||||
 | 
			
		||||
    def receive(
 | 
			
		||||
        self,
 | 
			
		||||
        message: Union[Dict, str],
 | 
			
		||||
        sender: Agent,
 | 
			
		||||
        request_reply: Optional[bool] = None,
 | 
			
		||||
        silent: Optional[bool] = False,
 | 
			
		||||
    ):
 | 
			
		||||
        """
 | 
			
		||||
        Receive a message from the AutoGen system.
 | 
			
		||||
        """
 | 
			
		||||
        self._recv_called = True
 | 
			
		||||
        self._check_connection()
 | 
			
		||||
        self._agent_connector.send_receive_req(message, sender, request_reply, silent)
 | 
			
		||||
 | 
			
		||||
    def generate_reply(
 | 
			
		||||
        self,
 | 
			
		||||
        messages: Optional[List[Dict]] = None,
 | 
			
		||||
        sender: Optional[Agent] = None,
 | 
			
		||||
        exclude: Optional[List[Callable]] = None,
 | 
			
		||||
    ) -> Union[str, Dict, None]:
 | 
			
		||||
        """
 | 
			
		||||
        Generate a reply message for the AutoGen system.
 | 
			
		||||
        """
 | 
			
		||||
        self._check_connection()
 | 
			
		||||
        return self._agent_connector.send_gen_reply_req()
 | 
			
		||||
 | 
			
		||||
    def _prepare_chat(
 | 
			
		||||
        self,
 | 
			
		||||
        recipient: ConversableAgent,
 | 
			
		||||
        clear_history: bool,
 | 
			
		||||
        prepare_recipient: bool = True,
 | 
			
		||||
        reply_at_receive: bool = True,
 | 
			
		||||
    ) -> None:
 | 
			
		||||
        self._check_connection()
 | 
			
		||||
        self._agent_connector.send_prep_chat(recipient, clear_history, prepare_recipient)
 | 
			
		||||
 | 
			
		||||
    def send_terminate(self, recipient: ConversableAgent) -> None:
 | 
			
		||||
        self._check_connection()
 | 
			
		||||
        self._agent_connector.send_terminate(recipient)
 | 
			
		||||
        self._terminate_connector.send_terminate(self)
 | 
			
		||||
							
								
								
									
										12
									
								
								samples/apps/cap/py/autogencap/ag_adapter/AGActor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								samples/apps/cap/py/autogencap/ag_adapter/AGActor.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
import zmq
 | 
			
		||||
from autogencap.Actor import Actor
 | 
			
		||||
from autogencap.Constants import Termination_Topic
 | 
			
		||||
from autogencap.DebugLog import Debug
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AGActor(Actor):
 | 
			
		||||
    def start(self, context: zmq.Context):
 | 
			
		||||
        super().start(context)
 | 
			
		||||
        str_topic = Termination_Topic
 | 
			
		||||
        Debug(self.actor_name, f"subscribe to: {str_topic}")
 | 
			
		||||
        self._socket.setsockopt_string(zmq.SUBSCRIBE, f"{str_topic}")
 | 
			
		||||
@ -0,0 +1,84 @@
 | 
			
		||||
from typing import Dict, Optional, Union
 | 
			
		||||
from autogen import Agent
 | 
			
		||||
from ..ActorConnector import ActorConnector
 | 
			
		||||
from ..proto.Autogen_pb2 import GenReplyReq, GenReplyResp, PrepChat, ReceiveReq, Terminate
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AutoGenConnector:
 | 
			
		||||
    """
 | 
			
		||||
    A specialized ActorConnector class for sending and receiving Autogen messages
 | 
			
		||||
    to/from the CAP system.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, cap_sender: ActorConnector):
 | 
			
		||||
        self._can_channel: ActorConnector = cap_sender
 | 
			
		||||
 | 
			
		||||
    def close(self):
 | 
			
		||||
        """
 | 
			
		||||
        Close the connector.
 | 
			
		||||
        """
 | 
			
		||||
        self._can_channel.close()
 | 
			
		||||
 | 
			
		||||
    def _send_msg(self, msg):
 | 
			
		||||
        """
 | 
			
		||||
        Send a message to CAP.
 | 
			
		||||
        """
 | 
			
		||||
        serialized_msg = msg.SerializeToString()
 | 
			
		||||
        self._can_channel.send_bin_msg(type(msg).__name__, serialized_msg)
 | 
			
		||||
 | 
			
		||||
    def send_gen_reply_req(self):
 | 
			
		||||
        """
 | 
			
		||||
        Send a GenReplyReq message to CAP and receive the response.
 | 
			
		||||
        """
 | 
			
		||||
        msg = GenReplyReq()
 | 
			
		||||
        serialized_msg = msg.SerializeToString()
 | 
			
		||||
        _, _, _, resp = self._can_channel.binary_request(type(msg).__name__, serialized_msg)
 | 
			
		||||
        gen_reply_resp = GenReplyResp()
 | 
			
		||||
        gen_reply_resp.ParseFromString(resp)
 | 
			
		||||
        return gen_reply_resp.data
 | 
			
		||||
 | 
			
		||||
    def send_receive_req(
 | 
			
		||||
        self,
 | 
			
		||||
        message: Union[Dict, str],
 | 
			
		||||
        sender: Agent,
 | 
			
		||||
        request_reply: Optional[bool] = None,
 | 
			
		||||
        silent: Optional[bool] = False,
 | 
			
		||||
    ):
 | 
			
		||||
        """
 | 
			
		||||
        Send a ReceiveReq message to CAP.
 | 
			
		||||
        """
 | 
			
		||||
        msg = ReceiveReq()
 | 
			
		||||
        if isinstance(message, dict):
 | 
			
		||||
            for key, value in message.items():
 | 
			
		||||
                msg.data_map.data[key] = value
 | 
			
		||||
        elif isinstance(message, str):
 | 
			
		||||
            msg.data = message
 | 
			
		||||
        msg.sender = sender.name
 | 
			
		||||
        if request_reply is not None:
 | 
			
		||||
            msg.request_reply = request_reply
 | 
			
		||||
        if silent is not None:
 | 
			
		||||
            msg.silent = silent
 | 
			
		||||
        self._send_msg(msg)
 | 
			
		||||
 | 
			
		||||
    def send_terminate(self, sender: Agent):
 | 
			
		||||
        """
 | 
			
		||||
        Send a Terminate message to CAP.
 | 
			
		||||
        """
 | 
			
		||||
        msg = Terminate()
 | 
			
		||||
        msg.sender = sender.name
 | 
			
		||||
        self._send_msg(msg)
 | 
			
		||||
 | 
			
		||||
    def send_prep_chat(self, recipient: "Agent", clear_history: bool, prepare_recipient: bool = True) -> None:
 | 
			
		||||
        """
 | 
			
		||||
        Send a PrepChat message to CAP.
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            recipient (Agent): _description_
 | 
			
		||||
            clear_history (bool): _description_
 | 
			
		||||
            prepare_recipient (bool, optional): _description_. Defaults to True.
 | 
			
		||||
        """
 | 
			
		||||
        msg = PrepChat()
 | 
			
		||||
        msg.recipient = recipient.name
 | 
			
		||||
        msg.clear_history = clear_history
 | 
			
		||||
        msg.prepare_recipient = prepare_recipient
 | 
			
		||||
        self._send_msg(msg)
 | 
			
		||||
							
								
								
									
										155
									
								
								samples/apps/cap/py/autogencap/ag_adapter/CAP2AG.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								samples/apps/cap/py/autogencap/ag_adapter/CAP2AG.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,155 @@
 | 
			
		||||
from enum import Enum
 | 
			
		||||
from typing import Optional
 | 
			
		||||
from ..DebugLog import Debug, Error, Info, Warn, shorten
 | 
			
		||||
from ..LocalActorNetwork import LocalActorNetwork
 | 
			
		||||
from ..proto.Autogen_pb2 import GenReplyReq, GenReplyResp, PrepChat, ReceiveReq, Terminate
 | 
			
		||||
from .AGActor import AGActor
 | 
			
		||||
from .AG2CAP import AG2CAP
 | 
			
		||||
from autogen import ConversableAgent
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CAP2AG(AGActor):
 | 
			
		||||
    """
 | 
			
		||||
    A CAN actor that acts as an adapter for the AutoGen system.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    States = Enum("States", ["INIT", "CONVERSING"])
 | 
			
		||||
 | 
			
		||||
    def __init__(self, ag_agent: ConversableAgent, the_other_name: str, init_chat: bool, self_recursive: bool = True):
 | 
			
		||||
        super().__init__(ag_agent.name, ag_agent.description)
 | 
			
		||||
        self._the_ag_agent: ConversableAgent = ag_agent
 | 
			
		||||
        self._ag2can_other_agent: AG2CAP = None
 | 
			
		||||
        self._other_agent_name: str = the_other_name
 | 
			
		||||
        self._init_chat: bool = init_chat
 | 
			
		||||
        self.STATE = self.States.INIT
 | 
			
		||||
        self._can2ag_name: str = self.actor_name + ".can2ag"
 | 
			
		||||
        self._self_recursive: bool = self_recursive
 | 
			
		||||
        self._network: LocalActorNetwork = None
 | 
			
		||||
        self._connectors = {}
 | 
			
		||||
 | 
			
		||||
    def connect_network(self, network: LocalActorNetwork):
 | 
			
		||||
        """
 | 
			
		||||
        Connect to the AutoGen system.
 | 
			
		||||
        """
 | 
			
		||||
        self._network = network
 | 
			
		||||
        self._ag2can_other_agent = AG2CAP(self._network, self._other_agent_name)
 | 
			
		||||
        Debug(self._can2ag_name, "connected to {network}")
 | 
			
		||||
 | 
			
		||||
    def disconnect_network(self, network: LocalActorNetwork):
 | 
			
		||||
        """
 | 
			
		||||
        Disconnect from the AutoGen system.
 | 
			
		||||
        """
 | 
			
		||||
        super().disconnect_network(network)
 | 
			
		||||
        #        self._the_other.close()
 | 
			
		||||
        Debug(self.actor_name, "disconnected")
 | 
			
		||||
 | 
			
		||||
    def _process_txt_msg(self, msg: str, msg_type: str, topic: str, sender: str):
 | 
			
		||||
        """
 | 
			
		||||
        Process a text message received from the AutoGen system.
 | 
			
		||||
        """
 | 
			
		||||
        Info(self._can2ag_name, f"proc_txt_msg: [{topic}], [{msg_type}], {shorten(msg)}")
 | 
			
		||||
        if self.STATE == self.States.INIT:
 | 
			
		||||
            self.STATE = self.States.CONVERSING
 | 
			
		||||
            if self._init_chat:
 | 
			
		||||
                self._the_ag_agent.initiate_chat(self._ag2can_other_agent, message=msg, summary_method=None)
 | 
			
		||||
            else:
 | 
			
		||||
                self._the_ag_agent.receive(msg, self._ag2can_other_agent, True)
 | 
			
		||||
        else:
 | 
			
		||||
            self._the_ag_agent.receive(msg, self._ag2can_other_agent, True)
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def _call_agent_receive(self, receive_params: ReceiveReq):
 | 
			
		||||
        request_reply: Optional[bool] = None
 | 
			
		||||
        silent: Optional[bool] = False
 | 
			
		||||
 | 
			
		||||
        if receive_params.HasField("request_reply"):
 | 
			
		||||
            request_reply = receive_params.request_reply
 | 
			
		||||
        if receive_params.HasField("silent"):
 | 
			
		||||
            silent = receive_params.silent
 | 
			
		||||
 | 
			
		||||
        save_name = self._ag2can_other_agent.name
 | 
			
		||||
        self._ag2can_other_agent.set_name(receive_params.sender)
 | 
			
		||||
        if receive_params.HasField("data_map"):
 | 
			
		||||
            data = dict(receive_params.data_map.data)
 | 
			
		||||
        else:
 | 
			
		||||
            data = receive_params.data
 | 
			
		||||
        self._the_ag_agent.receive(data, self._ag2can_other_agent, request_reply, silent)
 | 
			
		||||
        self._ag2can_other_agent.set_name(save_name)
 | 
			
		||||
 | 
			
		||||
    def receive_msgproc(self, msg: bytes):
 | 
			
		||||
        """
 | 
			
		||||
        Process a ReceiveReq message received from the AutoGen system.
 | 
			
		||||
        """
 | 
			
		||||
        receive_params = ReceiveReq()
 | 
			
		||||
        receive_params.ParseFromString(msg)
 | 
			
		||||
 | 
			
		||||
        self._ag2can_other_agent.reset_receive_called()
 | 
			
		||||
 | 
			
		||||
        if self.STATE == self.States.INIT:
 | 
			
		||||
            self.STATE = self.States.CONVERSING
 | 
			
		||||
 | 
			
		||||
            if self._init_chat:
 | 
			
		||||
                self._the_ag_agent.initiate_chat(
 | 
			
		||||
                    self._ag2can_other_agent, message=receive_params.data, summary_method=None
 | 
			
		||||
                )
 | 
			
		||||
            else:
 | 
			
		||||
                self._call_agent_receive(receive_params)
 | 
			
		||||
        else:
 | 
			
		||||
            self._call_agent_receive(receive_params)
 | 
			
		||||
 | 
			
		||||
        if not self._ag2can_other_agent.was_receive_called() and self._self_recursive:
 | 
			
		||||
            Warn(self._can2ag_name, "TERMINATE")
 | 
			
		||||
            self._ag2can_other_agent.send_terminate(self._the_ag_agent)
 | 
			
		||||
            return False
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def get_actor_connector(self, topic: str):
 | 
			
		||||
        """
 | 
			
		||||
        Get the actor connector for the given topic.
 | 
			
		||||
        """
 | 
			
		||||
        if topic in self._connectors:
 | 
			
		||||
            return self._connectors[topic]
 | 
			
		||||
        else:
 | 
			
		||||
            connector = self._network.actor_connector_by_topic(topic)
 | 
			
		||||
            self._connectors[topic] = connector
 | 
			
		||||
            return connector
 | 
			
		||||
 | 
			
		||||
    def generate_reply_msgproc(self, msg: GenReplyReq, sender_topic: str):
 | 
			
		||||
        """
 | 
			
		||||
        Process a GenReplyReq message received from the AutoGen system and generate a reply.
 | 
			
		||||
        """
 | 
			
		||||
        generate_reply_params = GenReplyReq()
 | 
			
		||||
        generate_reply_params.ParseFromString(msg)
 | 
			
		||||
        reply = self._the_ag_agent.generate_reply(sender=self._ag2can_other_agent)
 | 
			
		||||
        connector = self.get_actor_connector(sender_topic)
 | 
			
		||||
 | 
			
		||||
        reply_msg = GenReplyResp()
 | 
			
		||||
        if reply:
 | 
			
		||||
            reply_msg.data = reply.encode("utf8")
 | 
			
		||||
        serialized_msg = reply_msg.SerializeToString()
 | 
			
		||||
        connector.send_bin_msg(type(reply_msg).__name__, serialized_msg)
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def prepchat_msgproc(self, msg, sender_topic):
 | 
			
		||||
        prep_chat = PrepChat()
 | 
			
		||||
        prep_chat.ParseFromString(msg)
 | 
			
		||||
        self._the_ag_agent._prepare_chat(self._ag2can_other_agent, prep_chat.clear_history, prep_chat.prepare_recipient)
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def _process_bin_msg(self, msg: bytes, msg_type: str, topic: str, sender: str):
 | 
			
		||||
        """
 | 
			
		||||
        Process a binary message received from the AutoGen system.
 | 
			
		||||
        """
 | 
			
		||||
        Info(self._can2ag_name, f"proc_bin_msg: topic=[{topic}], msg_type=[{msg_type}]")
 | 
			
		||||
        if msg_type == ReceiveReq.__name__:
 | 
			
		||||
            return self.receive_msgproc(msg)
 | 
			
		||||
        elif msg_type == GenReplyReq.__name__:
 | 
			
		||||
            return self.generate_reply_msgproc(msg, sender)
 | 
			
		||||
        elif msg_type == PrepChat.__name__:
 | 
			
		||||
            return self.prepchat_msgproc(msg, sender)
 | 
			
		||||
        elif msg_type == Terminate.__name__:
 | 
			
		||||
            Warn(self._can2ag_name, f"TERMINATE received: topic=[{topic}], msg_type=[{msg_type}]")
 | 
			
		||||
            return False
 | 
			
		||||
        else:
 | 
			
		||||
            Error(self._can2ag_name, f"Unhandled message type: topic=[{topic}], msg_type=[{msg_type}]")
 | 
			
		||||
        return True
 | 
			
		||||
							
								
								
									
										39
									
								
								samples/apps/cap/py/autogencap/ag_adapter/CAPGroupChat.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								samples/apps/cap/py/autogencap/ag_adapter/CAPGroupChat.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
from autogen import Agent, AssistantAgent, GroupChat
 | 
			
		||||
from autogencap.ag_adapter.AG2CAP import AG2CAP
 | 
			
		||||
from autogencap.ag_adapter.CAP2AG import CAP2AG
 | 
			
		||||
from autogencap.LocalActorNetwork import LocalActorNetwork
 | 
			
		||||
from typing import List
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CAPGroupChat(GroupChat):
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        agents: List[AssistantAgent],
 | 
			
		||||
        messages: List[str],
 | 
			
		||||
        max_round: int,
 | 
			
		||||
        chat_initiator: str,
 | 
			
		||||
        network: LocalActorNetwork,
 | 
			
		||||
    ):
 | 
			
		||||
        self.chat_initiator: str = chat_initiator
 | 
			
		||||
        self._cap_network: LocalActorNetwork = network
 | 
			
		||||
        self._cap_proxies: List[CAP2AG] = []
 | 
			
		||||
        self._ag_proxies: List[AG2CAP] = []
 | 
			
		||||
        self._ag_agents: List[Agent] = agents
 | 
			
		||||
        self._init_cap_proxies()
 | 
			
		||||
        self._init_ag_proxies()
 | 
			
		||||
        super().__init__(agents=self._ag_proxies, messages=messages, max_round=max_round)
 | 
			
		||||
 | 
			
		||||
    def _init_cap_proxies(self):
 | 
			
		||||
        for agent in self._ag_agents:
 | 
			
		||||
            init_chat = agent.name == self.chat_initiator
 | 
			
		||||
            cap2ag = CAP2AG(ag_agent=agent, the_other_name="chat_manager", init_chat=init_chat, self_recursive=False)
 | 
			
		||||
            self._cap_network.register(cap2ag)
 | 
			
		||||
            self._cap_proxies.append(cap2ag)
 | 
			
		||||
 | 
			
		||||
    def _init_ag_proxies(self):
 | 
			
		||||
        for agent in self._ag_agents:
 | 
			
		||||
            ag2cap = AG2CAP(self._cap_network, agent_name=agent.name, agent_description=agent.description)
 | 
			
		||||
            self._ag_proxies.append(ag2cap)
 | 
			
		||||
 | 
			
		||||
    def is_running(self) -> bool:
 | 
			
		||||
        return all(proxy.run for proxy in self._cap_proxies)
 | 
			
		||||
@ -0,0 +1,38 @@
 | 
			
		||||
from autogen import GroupChatManager
 | 
			
		||||
from autogencap.ActorConnector import ActorConnector
 | 
			
		||||
from autogencap.LocalActorNetwork import LocalActorNetwork
 | 
			
		||||
from autogencap.ag_adapter.CAP2AG import CAP2AG
 | 
			
		||||
from autogencap.ag_adapter.CAPGroupChat import CAPGroupChat
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CAPGroupChatManager:
 | 
			
		||||
    def __init__(self, groupchat: CAPGroupChat, llm_config: dict, network: LocalActorNetwork):
 | 
			
		||||
        self._network: LocalActorNetwork = network
 | 
			
		||||
        self._cap_group_chat: CAPGroupChat = groupchat
 | 
			
		||||
        self._ag_group_chat_manager: GroupChatManager = GroupChatManager(
 | 
			
		||||
            groupchat=self._cap_group_chat, llm_config=llm_config
 | 
			
		||||
        )
 | 
			
		||||
        self._cap_proxy: CAP2AG = CAP2AG(
 | 
			
		||||
            ag_agent=self._ag_group_chat_manager,
 | 
			
		||||
            the_other_name=self._cap_group_chat.chat_initiator,
 | 
			
		||||
            init_chat=False,
 | 
			
		||||
            self_recursive=True,
 | 
			
		||||
        )
 | 
			
		||||
        self._network.register(self._cap_proxy)
 | 
			
		||||
 | 
			
		||||
    def initiate_chat(self, txt_msg: str) -> None:
 | 
			
		||||
        self._network.connect()
 | 
			
		||||
        user_proxy_conn: ActorConnector = self._network.lookup_actor(self._cap_group_chat.chat_initiator)
 | 
			
		||||
        user_proxy_conn.send_txt_msg(txt_msg)
 | 
			
		||||
        self._wait_for_user_exit()
 | 
			
		||||
 | 
			
		||||
    def is_running(self) -> bool:
 | 
			
		||||
        return self._cap_group_chat.is_running()
 | 
			
		||||
 | 
			
		||||
    def _wait_for_user_exit(self) -> None:
 | 
			
		||||
        try:
 | 
			
		||||
            while self.is_running():
 | 
			
		||||
                time.sleep(0.5)
 | 
			
		||||
        except KeyboardInterrupt:
 | 
			
		||||
            print("Interrupted by user, shutting down.")
 | 
			
		||||
							
								
								
									
										34
									
								
								samples/apps/cap/py/autogencap/ag_adapter/CAPPair.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								samples/apps/cap/py/autogencap/ag_adapter/CAPPair.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
from autogencap.ag_adapter.CAP2AG import CAP2AG
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CAPPair:
 | 
			
		||||
    def __init__(self, network, first, second):
 | 
			
		||||
        self._network = network
 | 
			
		||||
        self._first_ag_agent = first
 | 
			
		||||
        self._second_ag_agent = second
 | 
			
		||||
        self._first_adptr = None
 | 
			
		||||
        self._second_adptr = None
 | 
			
		||||
 | 
			
		||||
    def initiate_chat(self, message: str):
 | 
			
		||||
        self._first_adptr = CAP2AG(
 | 
			
		||||
            ag_agent=self._first_ag_agent,
 | 
			
		||||
            the_other_name=self._second_ag_agent.name,
 | 
			
		||||
            init_chat=True,
 | 
			
		||||
            self_recursive=True,
 | 
			
		||||
        )
 | 
			
		||||
        self._second_adptr = CAP2AG(
 | 
			
		||||
            ag_agent=self._second_ag_agent,
 | 
			
		||||
            the_other_name=self._first_ag_agent.name,
 | 
			
		||||
            init_chat=False,
 | 
			
		||||
            self_recursive=True,
 | 
			
		||||
        )
 | 
			
		||||
        self._network.register(self._first_adptr)
 | 
			
		||||
        self._network.register(self._second_adptr)
 | 
			
		||||
        self._network.connect()
 | 
			
		||||
 | 
			
		||||
        # Send a message to the user_proxy
 | 
			
		||||
        agent_connection = self._network.lookup_actor(self._first_ag_agent.name)
 | 
			
		||||
        agent_connection.send_txt_msg(message)
 | 
			
		||||
 | 
			
		||||
    def running(self):
 | 
			
		||||
        return self._first_adptr.run and self._second_adptr.run
 | 
			
		||||
							
								
								
									
										35
									
								
								samples/apps/cap/py/autogencap/proto/Autogen.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								samples/apps/cap/py/autogencap/proto/Autogen.proto
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
// Get protoc here https://github.com/protocolbuffers/protobuf/releases
 | 
			
		||||
// .\protoc --python_out=. --pyi_out=. Autogen.proto
 | 
			
		||||
 | 
			
		||||
message DataMap {
 | 
			
		||||
    map<string, string> data = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ReceiveReq {
 | 
			
		||||
    oneof Type {
 | 
			
		||||
        DataMap data_map = 1;
 | 
			
		||||
        string data = 2;
 | 
			
		||||
    }
 | 
			
		||||
    optional string sender = 3;
 | 
			
		||||
    optional bool request_reply = 4;
 | 
			
		||||
    optional bool silent = 5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Terminate {
 | 
			
		||||
    optional string sender = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message GenReplyReq {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message GenReplyResp {
 | 
			
		||||
    optional string data = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message PrepChat {
 | 
			
		||||
    string recipient = 1;
 | 
			
		||||
    bool clear_history = 2;
 | 
			
		||||
    bool prepare_recipient = 3;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								samples/apps/cap/py/autogencap/proto/Autogen_pb2.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								samples/apps/cap/py/autogencap/proto/Autogen_pb2.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by the protocol buffer compiler.  DO NOT EDIT!
 | 
			
		||||
# source: Autogen.proto
 | 
			
		||||
# Protobuf Python Version: 4.25.2
 | 
			
		||||
"""Generated protocol buffer code."""
 | 
			
		||||
from google.protobuf import descriptor as _descriptor
 | 
			
		||||
from google.protobuf import descriptor_pool as _descriptor_pool
 | 
			
		||||
from google.protobuf import symbol_database as _symbol_database
 | 
			
		||||
from google.protobuf.internal import builder as _builder
 | 
			
		||||
 | 
			
		||||
# @@protoc_insertion_point(imports)
 | 
			
		||||
 | 
			
		||||
_sym_db = _symbol_database.Default()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
 | 
			
		||||
    b'\n\rAutogen.proto"X\n\x07\x44\x61taMap\x12 \n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x12.DataMap.DataEntry\x1a+\n\tDataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01"\xb0\x01\n\nReceiveReq\x12\x1c\n\x08\x64\x61ta_map\x18\x01 \x01(\x0b\x32\x08.DataMapH\x00\x12\x0e\n\x04\x64\x61ta\x18\x02 \x01(\tH\x00\x12\x13\n\x06sender\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x1a\n\rrequest_reply\x18\x04 \x01(\x08H\x02\x88\x01\x01\x12\x13\n\x06silent\x18\x05 \x01(\x08H\x03\x88\x01\x01\x42\x06\n\x04TypeB\t\n\x07_senderB\x10\n\x0e_request_replyB\t\n\x07_silent"+\n\tTerminate\x12\x13\n\x06sender\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\t\n\x07_sender"\r\n\x0bGenReplyReq"*\n\x0cGenReplyResp\x12\x11\n\x04\x64\x61ta\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x07\n\x05_data"O\n\x08PrepChat\x12\x11\n\trecipient\x18\x01 \x01(\t\x12\x15\n\rclear_history\x18\x02 \x01(\x08\x12\x19\n\x11prepare_recipient\x18\x03 \x01(\x08\x62\x06proto3'
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
_globals = globals()
 | 
			
		||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
 | 
			
		||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "Autogen_pb2", _globals)
 | 
			
		||||
if _descriptor._USE_C_DESCRIPTORS is False:
 | 
			
		||||
    DESCRIPTOR._options = None
 | 
			
		||||
    _globals["_DATAMAP_DATAENTRY"]._options = None
 | 
			
		||||
    _globals["_DATAMAP_DATAENTRY"]._serialized_options = b"8\001"
 | 
			
		||||
    _globals["_DATAMAP"]._serialized_start = 17
 | 
			
		||||
    _globals["_DATAMAP"]._serialized_end = 105
 | 
			
		||||
    _globals["_DATAMAP_DATAENTRY"]._serialized_start = 62
 | 
			
		||||
    _globals["_DATAMAP_DATAENTRY"]._serialized_end = 105
 | 
			
		||||
    _globals["_RECEIVEREQ"]._serialized_start = 108
 | 
			
		||||
    _globals["_RECEIVEREQ"]._serialized_end = 284
 | 
			
		||||
    _globals["_TERMINATE"]._serialized_start = 286
 | 
			
		||||
    _globals["_TERMINATE"]._serialized_end = 329
 | 
			
		||||
    _globals["_GENREPLYREQ"]._serialized_start = 331
 | 
			
		||||
    _globals["_GENREPLYREQ"]._serialized_end = 344
 | 
			
		||||
    _globals["_GENREPLYRESP"]._serialized_start = 346
 | 
			
		||||
    _globals["_GENREPLYRESP"]._serialized_end = 388
 | 
			
		||||
    _globals["_PREPCHAT"]._serialized_start = 390
 | 
			
		||||
    _globals["_PREPCHAT"]._serialized_end = 469
 | 
			
		||||
# @@protoc_insertion_point(module_scope)
 | 
			
		||||
							
								
								
									
										69
									
								
								samples/apps/cap/py/autogencap/proto/Autogen_pb2.pyi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								samples/apps/cap/py/autogencap/proto/Autogen_pb2.pyi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,69 @@
 | 
			
		||||
from google.protobuf.internal import containers as _containers
 | 
			
		||||
from google.protobuf import descriptor as _descriptor
 | 
			
		||||
from google.protobuf import message as _message
 | 
			
		||||
from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
 | 
			
		||||
 | 
			
		||||
DESCRIPTOR: _descriptor.FileDescriptor
 | 
			
		||||
 | 
			
		||||
class DataMap(_message.Message):
 | 
			
		||||
    __slots__ = ("data",)
 | 
			
		||||
 | 
			
		||||
    class DataEntry(_message.Message):
 | 
			
		||||
        __slots__ = ("key", "value")
 | 
			
		||||
        KEY_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
        VALUE_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
        key: str
 | 
			
		||||
        value: str
 | 
			
		||||
        def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ...
 | 
			
		||||
    DATA_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    data: _containers.ScalarMap[str, str]
 | 
			
		||||
    def __init__(self, data: _Optional[_Mapping[str, str]] = ...) -> None: ...
 | 
			
		||||
 | 
			
		||||
class ReceiveReq(_message.Message):
 | 
			
		||||
    __slots__ = ("data_map", "data", "sender", "request_reply", "silent")
 | 
			
		||||
    DATA_MAP_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    DATA_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    SENDER_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    REQUEST_REPLY_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    SILENT_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    data_map: DataMap
 | 
			
		||||
    data: str
 | 
			
		||||
    sender: str
 | 
			
		||||
    request_reply: bool
 | 
			
		||||
    silent: bool
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        data_map: _Optional[_Union[DataMap, _Mapping]] = ...,
 | 
			
		||||
        data: _Optional[str] = ...,
 | 
			
		||||
        sender: _Optional[str] = ...,
 | 
			
		||||
        request_reply: bool = ...,
 | 
			
		||||
        silent: bool = ...,
 | 
			
		||||
    ) -> None: ...
 | 
			
		||||
 | 
			
		||||
class Terminate(_message.Message):
 | 
			
		||||
    __slots__ = ("sender",)
 | 
			
		||||
    SENDER_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    sender: str
 | 
			
		||||
    def __init__(self, sender: _Optional[str] = ...) -> None: ...
 | 
			
		||||
 | 
			
		||||
class GenReplyReq(_message.Message):
 | 
			
		||||
    __slots__ = ()
 | 
			
		||||
    def __init__(self) -> None: ...
 | 
			
		||||
 | 
			
		||||
class GenReplyResp(_message.Message):
 | 
			
		||||
    __slots__ = ("data",)
 | 
			
		||||
    DATA_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    data: str
 | 
			
		||||
    def __init__(self, data: _Optional[str] = ...) -> None: ...
 | 
			
		||||
 | 
			
		||||
class PrepChat(_message.Message):
 | 
			
		||||
    __slots__ = ("recipient", "clear_history", "prepare_recipient")
 | 
			
		||||
    RECIPIENT_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    CLEAR_HISTORY_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    PREPARE_RECIPIENT_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    recipient: str
 | 
			
		||||
    clear_history: bool
 | 
			
		||||
    prepare_recipient: bool
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self, recipient: _Optional[str] = ..., clear_history: bool = ..., prepare_recipient: bool = ...
 | 
			
		||||
    ) -> None: ...
 | 
			
		||||
							
								
								
									
										35
									
								
								samples/apps/cap/py/autogencap/proto/CAP.proto
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								samples/apps/cap/py/autogencap/proto/CAP.proto
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
syntax = "proto3";
 | 
			
		||||
 | 
			
		||||
// Get protoc here https://github.com/protocolbuffers/protobuf/releases
 | 
			
		||||
// .\protoc --python_out=. --pyi_out=. CAP.proto
 | 
			
		||||
 | 
			
		||||
message ActorInfo {
 | 
			
		||||
    string name = 1;
 | 
			
		||||
    optional string namespace = 2;
 | 
			
		||||
    optional string description = 3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ActorRegistration {
 | 
			
		||||
    ActorInfo actor_info = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ActorLookup {
 | 
			
		||||
    optional ActorInfo actor_info = 1;
 | 
			
		||||
    // TODO:  May need more structure here for semantic service discovery
 | 
			
		||||
    // optional string service_descriptor = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ActorInfoCollection {
 | 
			
		||||
    repeated ActorInfo info_coll = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message ActorLookupResponse {
 | 
			
		||||
    bool found = 1;
 | 
			
		||||
    optional ActorInfoCollection actor = 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Ping {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
message Pong {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								samples/apps/cap/py/autogencap/proto/CAP_pb2.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								samples/apps/cap/py/autogencap/proto/CAP_pb2.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Generated by the protocol buffer compiler.  DO NOT EDIT!
 | 
			
		||||
# source: CAP.proto
 | 
			
		||||
# Protobuf Python Version: 4.25.2
 | 
			
		||||
"""Generated protocol buffer code."""
 | 
			
		||||
from google.protobuf import descriptor as _descriptor
 | 
			
		||||
from google.protobuf import descriptor_pool as _descriptor_pool
 | 
			
		||||
from google.protobuf import symbol_database as _symbol_database
 | 
			
		||||
from google.protobuf.internal import builder as _builder
 | 
			
		||||
 | 
			
		||||
# @@protoc_insertion_point(imports)
 | 
			
		||||
 | 
			
		||||
_sym_db = _symbol_database.Default()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
 | 
			
		||||
    b'\n\tCAP.proto"i\n\tActorInfo\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x16\n\tnamespace\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0b\x64\x65scription\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x0c\n\n_namespaceB\x0e\n\x0c_description"3\n\x11\x41\x63torRegistration\x12\x1e\n\nactor_info\x18\x01 \x01(\x0b\x32\n.ActorInfo"A\n\x0b\x41\x63torLookup\x12#\n\nactor_info\x18\x01 \x01(\x0b\x32\n.ActorInfoH\x00\x88\x01\x01\x42\r\n\x0b_actor_info"4\n\x13\x41\x63torInfoCollection\x12\x1d\n\tinfo_coll\x18\x01 \x03(\x0b\x32\n.ActorInfo"X\n\x13\x41\x63torLookupResponse\x12\r\n\x05\x66ound\x18\x01 \x01(\x08\x12(\n\x05\x61\x63tor\x18\x02 \x01(\x0b\x32\x14.ActorInfoCollectionH\x00\x88\x01\x01\x42\x08\n\x06_actor"\x06\n\x04Ping"\x06\n\x04Pongb\x06proto3'
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
_globals = globals()
 | 
			
		||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
 | 
			
		||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "CAP_pb2", _globals)
 | 
			
		||||
if _descriptor._USE_C_DESCRIPTORS is False:
 | 
			
		||||
    DESCRIPTOR._options = None
 | 
			
		||||
    _globals["_ACTORINFO"]._serialized_start = 13
 | 
			
		||||
    _globals["_ACTORINFO"]._serialized_end = 118
 | 
			
		||||
    _globals["_ACTORREGISTRATION"]._serialized_start = 120
 | 
			
		||||
    _globals["_ACTORREGISTRATION"]._serialized_end = 171
 | 
			
		||||
    _globals["_ACTORLOOKUP"]._serialized_start = 173
 | 
			
		||||
    _globals["_ACTORLOOKUP"]._serialized_end = 238
 | 
			
		||||
    _globals["_ACTORINFOCOLLECTION"]._serialized_start = 240
 | 
			
		||||
    _globals["_ACTORINFOCOLLECTION"]._serialized_end = 292
 | 
			
		||||
    _globals["_ACTORLOOKUPRESPONSE"]._serialized_start = 294
 | 
			
		||||
    _globals["_ACTORLOOKUPRESPONSE"]._serialized_end = 382
 | 
			
		||||
    _globals["_PING"]._serialized_start = 384
 | 
			
		||||
    _globals["_PING"]._serialized_end = 390
 | 
			
		||||
    _globals["_PONG"]._serialized_start = 392
 | 
			
		||||
    _globals["_PONG"]._serialized_end = 398
 | 
			
		||||
# @@protoc_insertion_point(module_scope)
 | 
			
		||||
							
								
								
									
										58
									
								
								samples/apps/cap/py/autogencap/proto/CAP_pb2.pyi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								samples/apps/cap/py/autogencap/proto/CAP_pb2.pyi
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
			
		||||
from google.protobuf.internal import containers as _containers
 | 
			
		||||
from google.protobuf import descriptor as _descriptor
 | 
			
		||||
from google.protobuf import message as _message
 | 
			
		||||
from typing import (
 | 
			
		||||
    ClassVar as _ClassVar,
 | 
			
		||||
    Iterable as _Iterable,
 | 
			
		||||
    Mapping as _Mapping,
 | 
			
		||||
    Optional as _Optional,
 | 
			
		||||
    Union as _Union,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
DESCRIPTOR: _descriptor.FileDescriptor
 | 
			
		||||
 | 
			
		||||
class ActorInfo(_message.Message):
 | 
			
		||||
    __slots__ = ("name", "namespace", "description")
 | 
			
		||||
    NAME_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    NAMESPACE_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    DESCRIPTION_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    name: str
 | 
			
		||||
    namespace: str
 | 
			
		||||
    description: str
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self, name: _Optional[str] = ..., namespace: _Optional[str] = ..., description: _Optional[str] = ...
 | 
			
		||||
    ) -> None: ...
 | 
			
		||||
 | 
			
		||||
class ActorRegistration(_message.Message):
 | 
			
		||||
    __slots__ = ("actor_info",)
 | 
			
		||||
    ACTOR_INFO_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    actor_info: ActorInfo
 | 
			
		||||
    def __init__(self, actor_info: _Optional[_Union[ActorInfo, _Mapping]] = ...) -> None: ...
 | 
			
		||||
 | 
			
		||||
class ActorLookup(_message.Message):
 | 
			
		||||
    __slots__ = ("actor_info",)
 | 
			
		||||
    ACTOR_INFO_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    actor_info: ActorInfo
 | 
			
		||||
    def __init__(self, actor_info: _Optional[_Union[ActorInfo, _Mapping]] = ...) -> None: ...
 | 
			
		||||
 | 
			
		||||
class ActorInfoCollection(_message.Message):
 | 
			
		||||
    __slots__ = ("info_coll",)
 | 
			
		||||
    INFO_COLL_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    info_coll: _containers.RepeatedCompositeFieldContainer[ActorInfo]
 | 
			
		||||
    def __init__(self, info_coll: _Optional[_Iterable[_Union[ActorInfo, _Mapping]]] = ...) -> None: ...
 | 
			
		||||
 | 
			
		||||
class ActorLookupResponse(_message.Message):
 | 
			
		||||
    __slots__ = ("found", "actor")
 | 
			
		||||
    FOUND_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    ACTOR_FIELD_NUMBER: _ClassVar[int]
 | 
			
		||||
    found: bool
 | 
			
		||||
    actor: ActorInfoCollection
 | 
			
		||||
    def __init__(self, found: bool = ..., actor: _Optional[_Union[ActorInfoCollection, _Mapping]] = ...) -> None: ...
 | 
			
		||||
 | 
			
		||||
class Ping(_message.Message):
 | 
			
		||||
    __slots__ = ()
 | 
			
		||||
    def __init__(self) -> None: ...
 | 
			
		||||
 | 
			
		||||
class Pong(_message.Message):
 | 
			
		||||
    __slots__ = ()
 | 
			
		||||
    def __init__(self) -> None: ...
 | 
			
		||||
							
								
								
									
										0
									
								
								samples/apps/cap/py/autogencap/proto/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								samples/apps/cap/py/autogencap/proto/__init__.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
.\protoc --pyi_out=. --python_out=. CAP.proto Autogen.proto
 | 
			
		||||
							
								
								
									
										4
									
								
								samples/apps/cap/py/autogencap/requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								samples/apps/cap/py/autogencap/requirements.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,4 @@
 | 
			
		||||
pyzmq
 | 
			
		||||
protobuf
 | 
			
		||||
termcolor
 | 
			
		||||
pyautogen
 | 
			
		||||
							
								
								
									
										7
									
								
								samples/apps/cap/py/autogencap/setup.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								samples/apps/cap/py/autogencap/setup.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
from setuptools import setup, find_packages
 | 
			
		||||
 | 
			
		||||
setup(
 | 
			
		||||
    name="autogencap",
 | 
			
		||||
    version="0.1",
 | 
			
		||||
    packages=find_packages(),
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										12
									
								
								samples/apps/cap/py/demo/AGDemo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								samples/apps/cap/py/demo/AGDemo.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
from autogen import AssistantAgent, UserProxyAgent, config_list_from_json
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def ag_demo():
 | 
			
		||||
    config_list = config_list_from_json(env_or_file="OAI_CONFIG_LIST")
 | 
			
		||||
    assistant = AssistantAgent("assistant", llm_config={"config_list": config_list})
 | 
			
		||||
    user_proxy = UserProxyAgent(
 | 
			
		||||
        "user_proxy",
 | 
			
		||||
        code_execution_config={"work_dir": "coding"},
 | 
			
		||||
        is_termination_msg=lambda x: "TERMINATE" in x.get("content"),
 | 
			
		||||
    )
 | 
			
		||||
    user_proxy.initiate_chat(assistant, message="Plot a chart of MSFT daily closing prices for last 1 Month.")
 | 
			
		||||
							
								
								
									
										34
									
								
								samples/apps/cap/py/demo/AGGroupChatDemo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								samples/apps/cap/py/demo/AGGroupChatDemo.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
from autogen import AssistantAgent, GroupChat, GroupChatManager, UserProxyAgent, config_list_from_json
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def ag_groupchat_demo():
 | 
			
		||||
    config_list = config_list_from_json(env_or_file="OAI_CONFIG_LIST")
 | 
			
		||||
    gpt4_config = {
 | 
			
		||||
        "cache_seed": 72,
 | 
			
		||||
        "temperature": 0,
 | 
			
		||||
        "config_list": config_list,
 | 
			
		||||
        "timeout": 120,
 | 
			
		||||
    }
 | 
			
		||||
    user_proxy = UserProxyAgent(
 | 
			
		||||
        name="User_proxy",
 | 
			
		||||
        system_message="A human admin.",
 | 
			
		||||
        code_execution_config={
 | 
			
		||||
            "last_n_messages": 2,
 | 
			
		||||
            "work_dir": "groupchat",
 | 
			
		||||
            "use_docker": False,
 | 
			
		||||
        },
 | 
			
		||||
        human_input_mode="TERMINATE",
 | 
			
		||||
        is_termination_msg=lambda x: "TERMINATE" in x.get("content"),
 | 
			
		||||
    )
 | 
			
		||||
    coder = AssistantAgent(name="Coder", llm_config=gpt4_config)
 | 
			
		||||
    pm = AssistantAgent(
 | 
			
		||||
        name="Product_manager",
 | 
			
		||||
        system_message="Creative in software product ideas.",
 | 
			
		||||
        llm_config=gpt4_config,
 | 
			
		||||
    )
 | 
			
		||||
    groupchat = GroupChat(agents=[user_proxy, coder, pm], messages=[], max_round=12)
 | 
			
		||||
    manager = GroupChatManager(groupchat=groupchat, llm_config=gpt4_config)
 | 
			
		||||
    user_proxy.initiate_chat(
 | 
			
		||||
        manager,
 | 
			
		||||
        message="Find a latest paper about gpt-4 on arxiv and find its potential applications in software.",
 | 
			
		||||
    )
 | 
			
		||||
							
								
								
									
										66
									
								
								samples/apps/cap/py/demo/App.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								samples/apps/cap/py/demo/App.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
"""
 | 
			
		||||
Demo App
 | 
			
		||||
"""
 | 
			
		||||
import argparse
 | 
			
		||||
import _paths
 | 
			
		||||
from autogencap.Config import LOG_LEVEL, IGNORED_LOG_CONTEXTS
 | 
			
		||||
import autogencap.DebugLog as DebugLog
 | 
			
		||||
from SimpleActorDemo import simple_actor_demo
 | 
			
		||||
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
 | 
			
		||||
from RemoteAGDemo import remote_ag_demo
 | 
			
		||||
 | 
			
		||||
####################################################################################################
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def parse_args():
 | 
			
		||||
    # Create a parser for the command line arguments
 | 
			
		||||
    parser = argparse.ArgumentParser(description="Demo App")
 | 
			
		||||
    parser.add_argument("--log_level", type=int, default=1, help="Set the log level (0-3)")
 | 
			
		||||
    # Parse the command line arguments
 | 
			
		||||
    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]}")
 | 
			
		||||
    # IGNORED_LOG_CONTEXTS.extend(["BROKER"])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
####################################################################################################
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    parse_args()
 | 
			
		||||
    while True:
 | 
			
		||||
        print("Select the Composable Actor Platform (CAP) demo app to run:")
 | 
			
		||||
        print("(enter anything else to quit)")
 | 
			
		||||
        print("1. Hello World")
 | 
			
		||||
        print("2. Complex Agent (e.g. Name or Quit)")
 | 
			
		||||
        print("3. AutoGen Pair")
 | 
			
		||||
        print("4. AutoGen GroupChat")
 | 
			
		||||
        print("5. AutoGen Agents in different processes")
 | 
			
		||||
        choice = input("Enter your choice (1-5): ")
 | 
			
		||||
 | 
			
		||||
        if choice == "1":
 | 
			
		||||
            simple_actor_demo()
 | 
			
		||||
        elif choice == "2":
 | 
			
		||||
            complex_actor_demo()
 | 
			
		||||
        # elif choice == "3":
 | 
			
		||||
        #     ag_demo()
 | 
			
		||||
        elif choice == "3":
 | 
			
		||||
            cap_ag_pair_demo()
 | 
			
		||||
        # elif choice == "5":
 | 
			
		||||
        #     ag_groupchat_demo()
 | 
			
		||||
        elif choice == "4":
 | 
			
		||||
            cap_ag_group_demo()
 | 
			
		||||
        elif choice == "5":
 | 
			
		||||
            remote_ag_demo()
 | 
			
		||||
        else:
 | 
			
		||||
            print("Quitting...")
 | 
			
		||||
            break
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										189
									
								
								samples/apps/cap/py/demo/AppAgents.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								samples/apps/cap/py/demo/AppAgents.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,189 @@
 | 
			
		||||
"""
 | 
			
		||||
This file contains the implementation of various agents used in the application.
 | 
			
		||||
Each agent represents a different role and knows how to connect to external systems
 | 
			
		||||
to retrieve information.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from autogencap.DebugLog import Debug, Info, shorten
 | 
			
		||||
from autogencap.LocalActorNetwork import LocalActorNetwork
 | 
			
		||||
from autogencap.ActorConnector import ActorConnector
 | 
			
		||||
from autogencap.Actor import Actor
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GreeterAgent(Actor):
 | 
			
		||||
    """
 | 
			
		||||
    Prints message to screen
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        agent_name="Greeter",
 | 
			
		||||
        description="This is the greeter agent, who knows how to greet people.",
 | 
			
		||||
    ):
 | 
			
		||||
        super().__init__(agent_name, description)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FidelityAgent(Actor):
 | 
			
		||||
    """
 | 
			
		||||
    This class represents the fidelity agent, who knows how to connect to fidelity to get account,
 | 
			
		||||
    portfolio, and order information.
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        agent_name (str, optional): The name of the agent. Defaults to "Fidelity".
 | 
			
		||||
        description (str, optional): A description of the agent. Defaults to "This is the
 | 
			
		||||
        fidelity agent who knows how to connect to fidelity to get account, portfolio, and
 | 
			
		||||
        order information."
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        agent_name="Fidelity",
 | 
			
		||||
        description=(
 | 
			
		||||
            "This is the fidelity agent, who knows"
 | 
			
		||||
            "how to connect to fidelity to get account, portfolio, and order information."
 | 
			
		||||
        ),
 | 
			
		||||
    ):
 | 
			
		||||
        super().__init__(agent_name, description)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FinancialPlannerAgent(Actor):
 | 
			
		||||
    """
 | 
			
		||||
    This class represents the financial planner agent, who knows how to connect to a financial
 | 
			
		||||
    planner and get financial planning information.
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        agent_name (str, optional): The name of the agent. Defaults to "Financial Planner".
 | 
			
		||||
        description (str, optional): A description of the agent. Defaults to "This is the
 | 
			
		||||
        financial planner agent, who knows how to connect to a financial planner and get
 | 
			
		||||
        financial planning information."
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        agent_name="Financial Planner",
 | 
			
		||||
        description=(
 | 
			
		||||
            "This is the financial planner"
 | 
			
		||||
            " agent, who knows how to connect to a financial planner and get financial"
 | 
			
		||||
            " planning information."
 | 
			
		||||
        ),
 | 
			
		||||
    ):
 | 
			
		||||
        super().__init__(agent_name, description)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QuantAgent(Actor):
 | 
			
		||||
    """
 | 
			
		||||
    This class represents the quant agent, who knows how to connect to a quant and get
 | 
			
		||||
    quant information.
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        agent_name (str, optional): The name of the agent. Defaults to "Quant".
 | 
			
		||||
        description (str, optional): A description of the agent. Defaults to "This is the
 | 
			
		||||
        quant agent, who knows how to connect to a quant and get quant information."
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        agent_name="Quant",
 | 
			
		||||
        description="This is the quant agent, who knows " "how to connect to a quant and get quant information.",
 | 
			
		||||
    ):
 | 
			
		||||
        super().__init__(agent_name, description)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RiskManager(Actor):
 | 
			
		||||
    """
 | 
			
		||||
    This class represents a risk manager, who will analyze portfolio risk.
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        description (str, optional): A description of the agent. Defaults to "This is the user
 | 
			
		||||
        interface agent, who knows how to connect to a user interface and get
 | 
			
		||||
        user interface information."
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    cls_agent_name = "Risk Manager"
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        description=(
 | 
			
		||||
            "This is the user interface agent, who knows how to connect"
 | 
			
		||||
            " to a user interface and get user interface information."
 | 
			
		||||
        ),
 | 
			
		||||
    ):
 | 
			
		||||
        super().__init__(RiskManager.cls_agent_name, description)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PersonalAssistant(Actor):
 | 
			
		||||
    """
 | 
			
		||||
    This class represents the personal assistant, who knows how to connect to the other agents and
 | 
			
		||||
    get information from them.
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        agent_name (str, optional): The name of the agent. Defaults to "PersonalAssistant".
 | 
			
		||||
        description (str, optional): A description of the agent. Defaults to "This is the personal assistant,
 | 
			
		||||
        who knows how to connect to the other agents and get information from them."
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    cls_agent_name = "PersonalAssistant"
 | 
			
		||||
 | 
			
		||||
    def __init__(
 | 
			
		||||
        self,
 | 
			
		||||
        agent_name=cls_agent_name,
 | 
			
		||||
        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
 | 
			
		||||
 | 
			
		||||
    def connect_network(self, network: LocalActorNetwork):
 | 
			
		||||
        """
 | 
			
		||||
        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.lookup_actor("Fidelity")
 | 
			
		||||
        self.financial_planner = network.lookup_actor("Financial Planner")
 | 
			
		||||
        self.quant = network.lookup_actor("Quant")
 | 
			
		||||
        self.risk_manager = network.lookup_actor("Risk Manager")
 | 
			
		||||
        Debug(self.actor_name, "connected")
 | 
			
		||||
 | 
			
		||||
    def disconnect_network(self, network: LocalActorNetwork):
 | 
			
		||||
        """
 | 
			
		||||
        Disconnects the personal assistant from the specified local actor network.
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            network (LocalActorNetwork): The local actor network to disconnect from.
 | 
			
		||||
        """
 | 
			
		||||
        super().disconnect_network(network)
 | 
			
		||||
        self.fidelity.close()
 | 
			
		||||
        self.financial_planner.close()
 | 
			
		||||
        self.quant.close()
 | 
			
		||||
        self.risk_manager.close()
 | 
			
		||||
        Debug(self.actor_name, "disconnected")
 | 
			
		||||
 | 
			
		||||
    def _process_txt_msg(self, msg, msg_type, topic, sender):
 | 
			
		||||
        """
 | 
			
		||||
        Processes a text message received by the personal assistant.
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            msg (str): The text message.
 | 
			
		||||
            msg_type (str): The type of the message.
 | 
			
		||||
            topic (str): The topic of the message.
 | 
			
		||||
            sender (str): The sender of the message.
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
            bool: True if the message was processed successfully, False otherwise.
 | 
			
		||||
        """
 | 
			
		||||
        if msg.strip().lower() != "quit" and msg.strip().lower() != "":
 | 
			
		||||
            Info(self.actor_name, f"Helping user: {shorten(msg)}")
 | 
			
		||||
            self.fidelity.send_txt_msg(f"I, {self.actor_name}, need your help to buy/sell assets for " + msg)
 | 
			
		||||
            self.financial_planner.send_txt_msg(
 | 
			
		||||
                f"I, {self.actor_name}, need your help in creating a financial plan for {msg}'s goals."
 | 
			
		||||
            )
 | 
			
		||||
            self.quant.send_txt_msg(
 | 
			
		||||
                f"I, {self.actor_name}, need your help with quantitative analysis of the interest rate for " + msg
 | 
			
		||||
            )
 | 
			
		||||
            self.risk_manager.send_txt_msg(f"I, {self.actor_name}, need your help in analyzing {msg}'s portfolio risk")
 | 
			
		||||
        return True
 | 
			
		||||
							
								
								
									
										40
									
								
								samples/apps/cap/py/demo/CAPAutGenGroupDemo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								samples/apps/cap/py/demo/CAPAutGenGroupDemo.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
from autogen import AssistantAgent, UserProxyAgent, config_list_from_json
 | 
			
		||||
from autogencap.DebugLog import Info
 | 
			
		||||
from autogencap.LocalActorNetwork import LocalActorNetwork
 | 
			
		||||
from autogencap.ag_adapter.CAPGroupChat import CAPGroupChat
 | 
			
		||||
from autogencap.ag_adapter.CAPGroupChatManager import CAPGroupChatManager
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def cap_ag_group_demo():
 | 
			
		||||
    config_list = config_list_from_json(env_or_file="OAI_CONFIG_LIST")
 | 
			
		||||
    gpt4_config = {
 | 
			
		||||
        "cache_seed": 73,
 | 
			
		||||
        "temperature": 0,
 | 
			
		||||
        "config_list": config_list,
 | 
			
		||||
        "timeout": 120,
 | 
			
		||||
    }
 | 
			
		||||
    user_proxy = UserProxyAgent(
 | 
			
		||||
        name="User_proxy",
 | 
			
		||||
        system_message="A human admin.",
 | 
			
		||||
        is_termination_msg=lambda x: "TERMINATE" in x.get("content"),
 | 
			
		||||
        code_execution_config={
 | 
			
		||||
            "last_n_messages": 2,
 | 
			
		||||
            "work_dir": "groupchat",
 | 
			
		||||
            "use_docker": False,
 | 
			
		||||
        },
 | 
			
		||||
        human_input_mode="TERMINATE",
 | 
			
		||||
    )
 | 
			
		||||
    coder = AssistantAgent(name="Coder", llm_config=gpt4_config)
 | 
			
		||||
    pm = AssistantAgent(
 | 
			
		||||
        name="Product_manager",
 | 
			
		||||
        system_message="Creative in software product ideas.",
 | 
			
		||||
        llm_config=gpt4_config,
 | 
			
		||||
    )
 | 
			
		||||
    network = LocalActorNetwork()
 | 
			
		||||
    cap_groupchat = CAPGroupChat(
 | 
			
		||||
        agents=[user_proxy, coder, pm], messages=[], max_round=12, network=network, chat_initiator=user_proxy.name
 | 
			
		||||
    )
 | 
			
		||||
    manager = CAPGroupChatManager(groupchat=cap_groupchat, llm_config=gpt4_config, network=network)
 | 
			
		||||
    manager.initiate_chat("Find a latest paper about gpt-4 on arxiv and find its potential applications in software.")
 | 
			
		||||
    network.disconnect()
 | 
			
		||||
    Info("App", "App Exit")
 | 
			
		||||
							
								
								
									
										31
									
								
								samples/apps/cap/py/demo/CAPAutoGenPairDemo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								samples/apps/cap/py/demo/CAPAutoGenPairDemo.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
			
		||||
import time
 | 
			
		||||
from autogen import AssistantAgent, UserProxyAgent, config_list_from_json
 | 
			
		||||
from autogencap.DebugLog import Info
 | 
			
		||||
from autogencap.ag_adapter.CAPPair import CAPPair
 | 
			
		||||
from autogencap.LocalActorNetwork import LocalActorNetwork
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def cap_ag_pair_demo():
 | 
			
		||||
    config_list = config_list_from_json(env_or_file="OAI_CONFIG_LIST")
 | 
			
		||||
    assistant = AssistantAgent("assistant", llm_config={"config_list": config_list})
 | 
			
		||||
    user_proxy = UserProxyAgent(
 | 
			
		||||
        "user_proxy",
 | 
			
		||||
        code_execution_config={"work_dir": "coding"},
 | 
			
		||||
        is_termination_msg=lambda x: "TERMINATE" in x.get("content"),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # Composable Agent Platform AutoGen Pair adapter
 | 
			
		||||
    network = LocalActorNetwork()
 | 
			
		||||
 | 
			
		||||
    pair = CAPPair(network, user_proxy, assistant)
 | 
			
		||||
    pair.initiate_chat("Plot a chart of MSFT daily closing prices for last 1 Month.")
 | 
			
		||||
 | 
			
		||||
    # Wait for the pair to finish
 | 
			
		||||
    try:
 | 
			
		||||
        while pair.running():
 | 
			
		||||
            time.sleep(0.5)
 | 
			
		||||
    except KeyboardInterrupt:
 | 
			
		||||
        print("Interrupted by user, shutting down.")
 | 
			
		||||
 | 
			
		||||
    network.disconnect()
 | 
			
		||||
    Info("App", "App Exit")
 | 
			
		||||
							
								
								
									
										50
									
								
								samples/apps/cap/py/demo/ComplexActorDemo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								samples/apps/cap/py/demo/ComplexActorDemo.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
			
		||||
import time
 | 
			
		||||
from termcolor import colored
 | 
			
		||||
from autogencap.LocalActorNetwork import LocalActorNetwork
 | 
			
		||||
from AppAgents import FidelityAgent, FinancialPlannerAgent, PersonalAssistant, QuantAgent, RiskManager
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def complex_actor_demo():
 | 
			
		||||
    """
 | 
			
		||||
    This function demonstrates the usage of a complex actor system.
 | 
			
		||||
    It creates a local actor graph, registers various agents,
 | 
			
		||||
    connects them, and interacts with a personal assistant agent.
 | 
			
		||||
    The function continuously prompts the user for input messages,
 | 
			
		||||
    sends them to the personal assistant agent, and terminates
 | 
			
		||||
    when the user enters "quit".
 | 
			
		||||
    """
 | 
			
		||||
    network = LocalActorNetwork()
 | 
			
		||||
    # Register agents
 | 
			
		||||
    network.register(PersonalAssistant())
 | 
			
		||||
    network.register(FidelityAgent())
 | 
			
		||||
    network.register(FinancialPlannerAgent())
 | 
			
		||||
    network.register(RiskManager())
 | 
			
		||||
    network.register(QuantAgent())
 | 
			
		||||
    # Tell agents to connect to other agents
 | 
			
		||||
    network.connect()
 | 
			
		||||
    # Get a channel to the personal assistant agent
 | 
			
		||||
    pa = network.lookup_actor(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
 | 
			
		||||
    can interact with the personal assistant agent by entering
 | 
			
		||||
    their name. The personal assistant agent will then enlist
 | 
			
		||||
    the other four agents to create a financial plan.
 | 
			
		||||
 | 
			
		||||
    Start by entering your name.
 | 
			
		||||
    """
 | 
			
		||||
    print(colored(info_msg, "blue"))
 | 
			
		||||
 | 
			
		||||
    while True:
 | 
			
		||||
        # For aesthetic reasons, better to let network messages complete
 | 
			
		||||
        time.sleep(0.1)
 | 
			
		||||
        # Get a message from the user
 | 
			
		||||
        msg = input(colored("Enter your name (or quit): ", "light_red"))
 | 
			
		||||
        # Send the message to the personal assistant agent
 | 
			
		||||
        pa.send_txt_msg(msg)
 | 
			
		||||
        if msg.lower() == "quit":
 | 
			
		||||
            break
 | 
			
		||||
    # Cleanup
 | 
			
		||||
 | 
			
		||||
    pa.close()
 | 
			
		||||
    network.disconnect()
 | 
			
		||||
							
								
								
									
										18
									
								
								samples/apps/cap/py/demo/RemoteAGDemo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								samples/apps/cap/py/demo/RemoteAGDemo.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
# Start Broker & Assistant
 | 
			
		||||
# Start UserProxy - Let it run
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def remote_ag_demo():
 | 
			
		||||
    print("Remote Agent Demo")
 | 
			
		||||
    instructions = """
 | 
			
		||||
    In this demo, Broker, Assistant, and UserProxy are running in separate processes.
 | 
			
		||||
    demo/standalone/UserProxy.py will initiate a conversation by sending UserProxy a message.
 | 
			
		||||
 | 
			
		||||
    Please do the following:
 | 
			
		||||
    1) Start Broker (python demo/standalone/Broker.py)
 | 
			
		||||
    2) Start Assistant (python demo/standalone/Assistant.py)
 | 
			
		||||
    3) Start UserProxy (python demo/standalone/UserProxy.py)
 | 
			
		||||
    """
 | 
			
		||||
    print(instructions)
 | 
			
		||||
    input("Press Enter to return to demo menu...")
 | 
			
		||||
    pass
 | 
			
		||||
							
								
								
									
										26
									
								
								samples/apps/cap/py/demo/SimpleActorDemo.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								samples/apps/cap/py/demo/SimpleActorDemo.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
import time
 | 
			
		||||
from AppAgents import GreeterAgent
 | 
			
		||||
from autogencap.LocalActorNetwork import LocalActorNetwork
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def simple_actor_demo():
 | 
			
		||||
    """
 | 
			
		||||
    Demonstrates the usage of the CAP platform by registering an actor, connecting to the actor,
 | 
			
		||||
    sending a message, and performing cleanup operations.
 | 
			
		||||
    """
 | 
			
		||||
    # CAP Platform
 | 
			
		||||
 | 
			
		||||
    network = LocalActorNetwork()
 | 
			
		||||
    # Register an actor
 | 
			
		||||
    network.register(GreeterAgent())
 | 
			
		||||
    # Tell actor to connect to other actors
 | 
			
		||||
    network.connect()
 | 
			
		||||
    # Get a channel to the actor
 | 
			
		||||
    greeter_link = network.lookup_actor("Greeter")
 | 
			
		||||
    time.sleep(1)
 | 
			
		||||
    # Send a message to the actor
 | 
			
		||||
    greeter_link.send_txt_msg("Hello World!")
 | 
			
		||||
    time.sleep(1)
 | 
			
		||||
    # Cleanup
 | 
			
		||||
    greeter_link.close()
 | 
			
		||||
    network.disconnect()
 | 
			
		||||
							
								
								
									
										7
									
								
								samples/apps/cap/py/demo/_paths.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								samples/apps/cap/py/demo/_paths.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
# Add autogencap to system path in case autogencap is not pip installed
 | 
			
		||||
# Since this library has not been published to PyPi, it is not easy to install using pip
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
absparent = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
 | 
			
		||||
sys.path.append(absparent)
 | 
			
		||||
							
								
								
									
										40
									
								
								samples/apps/cap/py/demo/standalone/Assistant.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								samples/apps/cap/py/demo/standalone/Assistant.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
import time
 | 
			
		||||
import _paths
 | 
			
		||||
from autogen import AssistantAgent, config_list_from_json
 | 
			
		||||
from autogencap.DebugLog import Info
 | 
			
		||||
from autogencap.LocalActorNetwork import LocalActorNetwork
 | 
			
		||||
from autogencap.ag_adapter.CAP2AG import CAP2AG
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Starts the Broker and the Assistant. The UserProxy is started separately.
 | 
			
		||||
class StandaloneAssistant:
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def run(self):
 | 
			
		||||
        print("Running the StandaloneAssistant")
 | 
			
		||||
        config_list = config_list_from_json(env_or_file="OAI_CONFIG_LIST")
 | 
			
		||||
        assistant = AssistantAgent("assistant", llm_config={"config_list": config_list})
 | 
			
		||||
        # Composable Agent Network adapter
 | 
			
		||||
        network = LocalActorNetwork()
 | 
			
		||||
        assistant_adptr = CAP2AG(ag_agent=assistant, the_other_name="user_proxy", init_chat=False, self_recursive=True)
 | 
			
		||||
        network.register(assistant_adptr)
 | 
			
		||||
        network.connect()
 | 
			
		||||
 | 
			
		||||
        # Hang around for a while
 | 
			
		||||
        try:
 | 
			
		||||
            while assistant_adptr.run:
 | 
			
		||||
                time.sleep(0.5)
 | 
			
		||||
        except KeyboardInterrupt:
 | 
			
		||||
            print("Interrupted by user, shutting down.")
 | 
			
		||||
        network.disconnect()
 | 
			
		||||
        Info("StandaloneAssistant", "App Exit")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    assistant = StandaloneAssistant()
 | 
			
		||||
    assistant.run()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										5
									
								
								samples/apps/cap/py/demo/standalone/Broker.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								samples/apps/cap/py/demo/standalone/Broker.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
import _paths
 | 
			
		||||
from autogencap.Broker import main
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										5
									
								
								samples/apps/cap/py/demo/standalone/DirectorySvc.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								samples/apps/cap/py/demo/standalone/DirectorySvc.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
import _paths
 | 
			
		||||
from autogencap.DirectorySvc import main
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										56
									
								
								samples/apps/cap/py/demo/standalone/UserProxy.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								samples/apps/cap/py/demo/standalone/UserProxy.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
			
		||||
import time
 | 
			
		||||
import _paths
 | 
			
		||||
from autogen import UserProxyAgent, config_list_from_json
 | 
			
		||||
from autogencap.DebugLog import Info
 | 
			
		||||
from autogencap.LocalActorNetwork import LocalActorNetwork
 | 
			
		||||
from autogencap.ag_adapter.CAP2AG import CAP2AG
 | 
			
		||||
from autogencap.Config import IGNORED_LOG_CONTEXTS
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 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
 | 
			
		||||
        network = LocalActorNetwork()
 | 
			
		||||
        user_proxy_adptr = CAP2AG(ag_agent=user_proxy, the_other_name="assistant", init_chat=True, self_recursive=True)
 | 
			
		||||
        network.register(user_proxy_adptr)
 | 
			
		||||
        network.connect()
 | 
			
		||||
 | 
			
		||||
        # Send a message to the user_proxy
 | 
			
		||||
        user_proxy_conn = network.lookup_actor("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.")
 | 
			
		||||
        network.disconnect()
 | 
			
		||||
        Info("StandaloneUserProxy", "App Exit")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    IGNORED_LOG_CONTEXTS.extend(["BROKER", "DirectorySvc"])
 | 
			
		||||
    assistant = StandaloneUserProxy()
 | 
			
		||||
    assistant.run()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    main()
 | 
			
		||||
							
								
								
									
										7
									
								
								samples/apps/cap/py/demo/standalone/_paths.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								samples/apps/cap/py/demo/standalone/_paths.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
# Add autogencap to system path in case autogencap is not pip installed
 | 
			
		||||
# Since this library has not been published to PyPi, it is not easy to install using pip
 | 
			
		||||
import sys
 | 
			
		||||
import os
 | 
			
		||||
 | 
			
		||||
absparent = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
 | 
			
		||||
sys.path.append(absparent)
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user