"""This is an example demonstrates event-driven orchestration using a group chat manager agnent. WARNING: do not run this example in your local machine as it involves executing arbitrary code. Use a secure environment like a docker container or GitHub Codespaces to run this example. """ import argparse import asyncio import base64 import logging import os import sys import aiofiles import aiohttp import openai from agnext.application import SingleThreadedAgentRuntime from agnext.components.models import SystemMessage from agnext.components.tools import FunctionTool from agnext.core import AgentInstantiationContext, AgentRuntime from markdownify import markdownify # type: ignore from tqdm import tqdm from typing_extensions import Annotated sys.path.append(os.path.abspath(os.path.dirname(__file__))) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) from agnext.core import AgentId from common.agents import ChatCompletionAgent from common.memory import HeadAndTailChatMemory from common.patterns._group_chat_manager import GroupChatManager from common.utils import get_chat_completion_client_from_envs from utils import TextualChatApp, TextualUserAgent async def write_file(filename: str, content: str) -> str: async with aiofiles.open(filename, "w") as file: await file.write(content) return f"Content written to {filename}." async def execute_command(command: str) -> Annotated[str, "The standard output and error of the executed command."]: process = await asyncio.subprocess.create_subprocess_shell( command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) stdout, stderr = await process.communicate() return f"stdout: {stdout.decode()}\nstderr: {stderr.decode()}" async def read_file(filename: str) -> Annotated[str, "The content of the file."]: async with aiofiles.open(filename, "r") as file: return await file.read() async def remove_file(filename: str) -> str: process = await asyncio.subprocess.create_subprocess_exec("rm", filename) await process.wait() if process.returncode != 0: raise ValueError(f"Error occurred while removing file: {filename}") return f"File removed: {filename}." async def list_files(directory: str) -> Annotated[str, "The list of files in the directory."]: # Ask for confirmation first. # await confirm(f"Are you sure you want to list files in {directory}?") process = await asyncio.subprocess.create_subprocess_exec( "ls", directory, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) stdout, stderr = await process.communicate() if stderr: raise ValueError(f"Error occurred while listing files: {stderr.decode()}") return stdout.decode() async def browse_web(url: str) -> Annotated[str, "The content of the web page in Markdown format."]: async with aiohttp.ClientSession() as session: async with session.get(url) as response: html = await response.text() markdown = markdownify(html) # type: ignore if isinstance(markdown, str): return markdown return f"Unable to parse content from {url}." async def create_image( description: Annotated[str, "Describe the image to create"], filename: Annotated[str, "The path to save the created image"], ) -> str: # Use Dalle to generate an image from the description. with tqdm(desc="Generating image...", leave=False) as pbar: client = openai.AsyncClient() response = await client.images.generate(model="dall-e-2", prompt=description, response_format="b64_json") pbar.close() assert len(response.data) > 0 and response.data[0].b64_json is not None # Save the image to a file. async with aiofiles.open(filename, "wb") as file: image_data = base64.b64decode(response.data[0].b64_json) await file.write(image_data) return f"Image created and saved to {filename}." async def software_consultancy(runtime: AgentRuntime, app: TextualChatApp) -> None: # type: ignore await runtime.register( "Customer", lambda: TextualUserAgent( description="A customer looking for help.", app=app, ), ) await runtime.register( "Developer", lambda: ChatCompletionAgent( description="A Python software developer.", system_messages=[ SystemMessage( "Your are a Python developer. \n" "You can read, write, and execute code. \n" "You can browse files and directories. \n" "You can also browse the web for documentation. \n" "You are entering a work session with the customer, product manager, UX designer, and illustrator. \n" "When you are given a task, you should immediately start working on it. \n" "Be concise and deliver now." ) ], model_client=get_chat_completion_client_from_envs(model="gpt-4-turbo"), memory=HeadAndTailChatMemory(head_size=1, tail_size=10), tools=[ FunctionTool( write_file, name="write_file", description="Write code to a file.", ), FunctionTool( read_file, name="read_file", description="Read code from a file.", ), FunctionTool( execute_command, name="execute_command", description="Execute a unix shell command.", ), FunctionTool(list_files, name="list_files", description="List files in a directory."), FunctionTool(browse_web, name="browse_web", description="Browse a web page."), ], tool_approver=AgentId("Customer", AgentInstantiationContext.current_agent_id().key), ), ) await runtime.register( "ProductManager", lambda: ChatCompletionAgent( description="A product manager. " "Responsible for interfacing with the customer, planning and managing the project. ", system_messages=[ SystemMessage( "You are a product manager. \n" "You can browse files and directories. \n" "You are entering a work session with the customer, developer, UX designer, and illustrator. \n" "Keep the project on track. Don't hire any more people. \n" "When a milestone is reached, stop and ask for customer feedback. Make sure the customer is satisfied. \n" "Be VERY concise." ) ], model_client=get_chat_completion_client_from_envs(model="gpt-4-turbo"), memory=HeadAndTailChatMemory(head_size=1, tail_size=10), tools=[ FunctionTool( read_file, name="read_file", description="Read from a file.", ), FunctionTool(list_files, name="list_files", description="List files in a directory."), FunctionTool(browse_web, name="browse_web", description="Browse a web page."), ], tool_approver=AgentId("Customer", AgentInstantiationContext.current_agent_id().key), ), ) await runtime.register( "UserExperienceDesigner", lambda: ChatCompletionAgent( description="A user experience designer for creating user interfaces.", system_messages=[ SystemMessage( "You are a user experience designer. \n" "You can create user interfaces from descriptions. \n" "You can browse files and directories. \n" "You are entering a work session with the customer, developer, product manager, and illustrator. \n" "When you are given a task, you should immediately start working on it. \n" "Be concise and deliver now." ) ], model_client=get_chat_completion_client_from_envs(model="gpt-4-turbo"), memory=HeadAndTailChatMemory(head_size=1, tail_size=10), tools=[ FunctionTool( write_file, name="write_file", description="Write code to a file.", ), FunctionTool( read_file, name="read_file", description="Read code from a file.", ), FunctionTool(list_files, name="list_files", description="List files in a directory."), ], tool_approver=AgentId("Customer", AgentInstantiationContext.current_agent_id().key), ), ) await runtime.register( "Illustrator", lambda: ChatCompletionAgent( description="An illustrator for creating images.", system_messages=[ SystemMessage( "You are an illustrator. " "You can create images from descriptions. " "You are entering a work session with the customer, developer, product manager, and UX designer. \n" "When you are given a task, you should immediately start working on it. \n" "Be concise and deliver now." ) ], model_client=get_chat_completion_client_from_envs(model="gpt-4-turbo"), memory=HeadAndTailChatMemory(head_size=1, tail_size=10), tools=[ FunctionTool( create_image, name="create_image", description="Create an image from a description.", ), ], tool_approver=AgentId("Customer", AgentInstantiationContext.current_agent_id().key), ), ) await runtime.register( "GroupChatManager", lambda: GroupChatManager( description="A group chat manager.", memory=HeadAndTailChatMemory(head_size=1, tail_size=10), model_client=get_chat_completion_client_from_envs(model="gpt-4-turbo"), participants=[ AgentId("Developer", AgentInstantiationContext.current_agent_id().key), AgentId("ProductManager", AgentInstantiationContext.current_agent_id().key), AgentId("UserExperienceDesigner", AgentInstantiationContext.current_agent_id().key), AgentId("Illustrator", AgentInstantiationContext.current_agent_id().key), AgentId("Customer", AgentInstantiationContext.current_agent_id().key), ], ), ) art = r""" +----------------------------------------------------------+ | ____ __ _ | | / ___| ___ / _| |___ ____ _ _ __ ___ | | \___ \ / _ \| |_| __\ \ /\ / / _` | '__/ _ \ | | ___) | (_) | _| |_ \ V V / (_| | | | __/ | | |____/ \___/|_| \__| \_/\_/ \__,_|_| \___| | | | | ____ _ _ | | / ___|___ _ __ ___ _ _| | |_ __ _ _ __ ___ _ _ | | | | / _ \| '_ \/ __| | | | | __/ _` | '_ \ / __| | | | | | | |__| (_) | | | \__ \ |_| | | || (_| | | | | (__| |_| | | | \____\___/|_| |_|___/\__,_|_|\__\__,_|_| |_|\___|\__, | | | |___/ | | | | Work with a software development consultancy to create | | your own Python application. You are working with a team | | of the following agents: | | 1. 🤖 Developer: A Python software developer. | | 2. 🤖 ProductManager: A product manager. | | 3. 🤖 UserExperienceDesigner: A user experience designer. | | 4. 🤖 Illustrator: An illustrator. | +----------------------------------------------------------+ """ app.welcoming_notice = art async def main() -> None: runtime = SingleThreadedAgentRuntime() app = TextualChatApp(runtime, user_name="You") await software_consultancy(runtime, app) # Start the runtime. runtime.start() # Start the app. await app.run_async() if __name__ == "__main__": parser = argparse.ArgumentParser(description="Software consultancy demo.") parser.add_argument("--verbose", action="store_true", help="Enable verbose logging.") args = parser.parse_args() if args.verbose: logging.basicConfig(level=logging.WARNING) logging.getLogger("agnext").setLevel(logging.DEBUG) handler = logging.FileHandler("software_consultancy.log") logging.getLogger("agnext").addHandler(handler) asyncio.run(main())