diff --git a/samples/python/agents/ag2/README.md b/samples/python/agents/ag2/README.md index f32578983..3a7e3da91 100644 --- a/samples/python/agents/ag2/README.md +++ b/samples/python/agents/ag2/README.md @@ -38,54 +38,35 @@ sequenceDiagram ## The demo -Here we have a simple demo that shows how to use the A2A protocol to communicate with an AG2 agent. We have -- one A2A-served remote agent `a2a_python_reviewer.py` -- two different A2A clients, which communicate with the remote agent using the A2A protocol: - CLI code generator `cli_codegen_a2a_client.py` and FastAPI code generator `fastapi_codegen_a2a_client.py` +This demo shows how to use the A2A protocol to communicate with an AG2 agent using a simple server/client architecture. -## Prerequisites - -- Python 3.12 or higher -- UV package manager -- OpenAI API Key (for default configuration) - -## Setup & Running - -1. Navigate to the samples directory: - - ```bash - cd samples/python/agents/ag2 - ``` +4. Run the remote agent: -2. Create an environment file with your API key (uses `openai gpt-4o`): +```bash +uv run a2a_python_reviewer.py +``` - ```bash - echo "OPENAI_API_KEY=your_api_key_here" > .env - ``` +5. In a new terminal, start an A2A client to interact with the remote `ReviewerAgent`. Choose one of the following: -3. Install the dependencies: - ```bash - uv sync - ``` +- CLI client (generates CLI scripts): -4. Run the remote agent: - ```bash - uv run a2a_python_reviewer.py - ``` +```bash +uv run cli_codegen_a2a_client.py +``` -5. In a new terminal, start an A2AClient interface to interact with the remote (ag2) agent. You can use one of the following clients: +- FastAPI client (generates FastAPI apps): - - **Method A: Run the CLI client** +```bash +uv run fastapi_codegen_a2a_client.py +``` - ```bash - uv run cli_codegen_a2a_client.py - ``` +- Optional: WebSocket demo UI (visual demo only): - - **Method B: Run the FastAPI client** +```bash +uv run websocket.py +``` - ```bash - uv run fastapi_codegen_a2a_client.py - ``` +Then open [http://127.0.0.1:9000](http://127.0.0.1:9000) in your browser for the pixel-art themed interactive demo. ## Learn More diff --git a/samples/python/agents/ag2/a2a_python_reviewer.py b/samples/python/agents/ag2/a2a_python_reviewer.py index 8053d3670..4ed276d10 100644 --- a/samples/python/agents/ag2/a2a_python_reviewer.py +++ b/samples/python/agents/ag2/a2a_python_reviewer.py @@ -3,6 +3,14 @@ from typing import Annotated +# Load .env file if python-dotenv is available +try: + from dotenv import load_dotenv + + load_dotenv() +except ImportError: + pass + from autogen import ConversableAgent, LLMConfig from autogen.a2a import A2aAgentServer from mypy import api @@ -11,48 +19,60 @@ # create regular AG2 agent config = LLMConfig( { - 'model': 'gpt-4o-mini', - 'api_key': os.getenv('OPENAI_API_KEY'), + "model": "gpt-4o-mini", + "api_key": os.getenv("OPENAI_API_KEY"), } ) reviewer_agent = ConversableAgent( - name='ReviewerAgent', - description='An agent that reviews the code for the user', + name="ReviewerAgent", + description="An agent that reviews the code for the user", system_message=( - 'You are an expert in code review pretty strict and focused on typing. ' - 'Please, use mypy tool to validate the code.' - 'If mypy has no issues with the code, return "No issues found."' + "You are an expert in code review: strict and focused on typing. " + "Please use the mypy tool to validate the code. " + "If mypy has no issues with the code, return exactly: No issues found." ), llm_config=config, - human_input_mode='NEVER', + human_input_mode="NEVER", ) # Add mypy tool to validate the code @reviewer_agent.register_for_llm( - name='mypy-checker', - description='Check the code with mypy tool', + name="mypy-checker", + description="Check the code with mypy tool", ) def review_code_with_mypy( code: Annotated[ str, - 'Raw code content to review. Code should be formatted as single file.', + "Raw code content to review. Code should be formatted as single file.", ], ) -> str: - with tempfile.NamedTemporaryFile('w', suffix='.py') as tmp: + # Windows-safe: create a temp file, close it, run mypy, then remove the file. + with tempfile.NamedTemporaryFile("w", suffix=".py", delete=False) as tmp: tmp.write(code) - stdout, stderr, exit_status = api.run([tmp.name]) - if exit_status != 0: - return stderr - return stdout or 'No issues found.' + tmp_path = tmp.name + try: + stdout, stderr, exit_status = api.run([tmp_path, "--ignore-missing-imports"]) + finally: + try: + os.unlink(tmp_path) + except OSError: + pass + + # When mypy exits with 0, return the exact agreed success token. + if exit_status == 0: + return "No issues found." + + # Otherwise return any output we got (stdout preferred, then stderr). + return (stdout or stderr) or "mypy reported issues." # wrap agent to A2A server server = A2aAgentServer(reviewer_agent).build() -if __name__ == '__main__': +if __name__ == "__main__": # run server as regular ASGI application import uvicorn - uvicorn.run(server, host='0.0.0.0', port=8000) + uvicorn.run(server, host="0.0.0.0", port=8000) diff --git a/samples/python/agents/ag2/demo/README.md b/samples/python/agents/ag2/demo/README.md new file mode 100644 index 000000000..f232f2d1f --- /dev/null +++ b/samples/python/agents/ag2/demo/README.md @@ -0,0 +1,42 @@ +# AG2 Demo UI + +This folder contains the browser-based WebSocket demo interface for the AG2 A2A sample. + +## Files + +- **`ui.html`** - Main HTML/CSS/JavaScript for the pixel-art themed demo UI +- **`assets/`** - Visual assets for the interface + +## Assets + +- `banner.png` - Top title banner (AG2 × A2A) +- `background-clouds.png` - Sky background +- `code-box.png` - Stone frame for code/log panels +- `grass-bottom.png` - Grass strip at the bottom + +## How it works + +1. The parent folder's `websocket.py` serves this UI at `http://127.0.0.1:9000/` +2. The browser connects via WebSocket to interact with the AG2 agents +3. The UI displays: + - **Prompt box** - Enter code generation requests + - **Live Backend Logs** - Real-time status updates and agent conversations + - **Generated Code** - Final code output after review iterations + +## Running the demo + +From the parent directory: + +```bash +uv run websocket.py +``` + +Then open `http://127.0.0.1:9000/` in your browser. + +## Design notes + +The UI uses a retro pixel-art aesthetic inspired by classic RPG games: +- 16-bit style graphics +- Stone-framed panels for content +- Pixel-rendered fonts +- Sky background with grass footer diff --git a/samples/python/agents/ag2/demo/assets/background-clouds.png b/samples/python/agents/ag2/demo/assets/background-clouds.png new file mode 100644 index 000000000..65ef131f3 Binary files /dev/null and b/samples/python/agents/ag2/demo/assets/background-clouds.png differ diff --git a/samples/python/agents/ag2/demo/assets/banner.png b/samples/python/agents/ag2/demo/assets/banner.png new file mode 100644 index 000000000..d56fb902a Binary files /dev/null and b/samples/python/agents/ag2/demo/assets/banner.png differ diff --git a/samples/python/agents/ag2/demo/assets/code-box.png b/samples/python/agents/ag2/demo/assets/code-box.png new file mode 100644 index 000000000..e2567cc0e Binary files /dev/null and b/samples/python/agents/ag2/demo/assets/code-box.png differ diff --git a/samples/python/agents/ag2/demo/assets/grass-bottom.png b/samples/python/agents/ag2/demo/assets/grass-bottom.png new file mode 100644 index 000000000..ea507e70c Binary files /dev/null and b/samples/python/agents/ag2/demo/assets/grass-bottom.png differ diff --git a/samples/python/agents/ag2/demo/ui.html b/samples/python/agents/ag2/demo/ui.html new file mode 100644 index 000000000..6e4bb3961 --- /dev/null +++ b/samples/python/agents/ag2/demo/ui.html @@ -0,0 +1,453 @@ + + +
+ + +
+
+ +(waiting)+