Skip to content

Commit 42f4745

Browse files
committed
verified version that works with run_integration_test.py; added gemma models fallback; added integration test script
1 parent 014dfa7 commit 42f4745

2 files changed

Lines changed: 160 additions & 2 deletions

File tree

src/agent.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import os
1111
from google import genai
1212
from google.genai import types
13+
from a2a.types import Part, DataPart
1314

1415
SYSTEM_PROMPT = '''
1516
you are an expert evaluation agent specialized in evaluating code and programming languages translation and
@@ -120,6 +121,8 @@ async def run_eval(self, request: EvalRequest, updater: TaskUpdater) -> None:
120121
models_to_try = [
121122
"gemini-2.5-flash",
122123
"gemini-2.0-flash",
124+
"gemma-3-27b-it",
125+
"gemma-3-12b-it",
123126
"gemini-flash-latest",
124127
"gemini-pro-latest",
125128
"gemini-2.5-pro"
@@ -143,12 +146,18 @@ async def run_eval(self, request: EvalRequest, updater: TaskUpdater) -> None:
143146
if not eval_result:
144147
raise ValueError("Model failed to return structured output")
145148

149+
# import json removed since it's global
150+
# from a2a.types import Part, DataPart moved to global (or just imported here)
151+
152+
await updater.add_artifact(
153+
parts=[Part(root=DataPart(data=eval_result.model_dump()))],
154+
name="Evaluation Result"
155+
)
156+
146157
await updater.update_status(
147158
"completed",
148159
new_agent_text_message(f"Evaluation complete. Winner: {eval_result.winner}, Scores: {eval_result.scores}")
149160
)
150-
# You might want to store the full eval_result or just the scores in the task result
151-
await updater.update_result(eval_result.model_dump())
152161
return # Assessment successful, exit function
153162

154163
except Exception as e:

tests/run_integration_test.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import asyncio
2+
import os
3+
import signal
4+
import subprocess
5+
import sys
6+
import time
7+
import httpx
8+
import json
9+
10+
# Configuration
11+
GREEN_AGENT_DIR = os.path.abspath("code_translator_green_agent")
12+
PURPLE_AGENT_DIR = os.path.abspath("code_translator_purple_agent")
13+
14+
GREEN_PORT = 9009
15+
PURPLE_PORT = 9010
16+
17+
GREEN_URL = f"http://127.0.0.1:{GREEN_PORT}"
18+
PURPLE_URL = f"http://127.0.0.1:{PURPLE_PORT}"
19+
20+
def start_process(command, cwd, name, log_file):
21+
print(f"Starting {name}...")
22+
# Open log file for writing
23+
f = open(log_file, "w")
24+
process = subprocess.Popen(
25+
command,
26+
cwd=cwd,
27+
stdout=f,
28+
stderr=subprocess.STDOUT,
29+
preexec_fn=os.setsid # Creates a new session to easily kill process group
30+
)
31+
return process, f
32+
33+
async def wait_for_agent(url, name, timeout=30):
34+
print(f"Waiting for {name} to be ready at {url}...")
35+
start_time = time.time()
36+
async with httpx.AsyncClient() as client:
37+
while time.time() - start_time < timeout:
38+
try:
39+
response = await client.get(f"{url}/.well-known/agent-card.json")
40+
if response.status_code == 200:
41+
print(f"{name} is ready!")
42+
return True
43+
except httpx.ConnectError:
44+
pass
45+
except Exception as e:
46+
print(f"Error checking {name}: {e}")
47+
48+
await asyncio.sleep(1)
49+
50+
print(f"{name} failed to start within {timeout} seconds.")
51+
return False
52+
53+
async def run_test():
54+
# 1. Start Agents
55+
green_proc, green_log = start_process(
56+
[sys.executable, "src/server.py", "--port", str(GREEN_PORT)],
57+
GREEN_AGENT_DIR,
58+
"Green Agent",
59+
"green_agent.log"
60+
)
61+
62+
purple_proc, purple_log = start_process(
63+
[sys.executable, "src/server.py", "--port", str(PURPLE_PORT)],
64+
PURPLE_AGENT_DIR,
65+
"Purple Agent",
66+
"purple_agent.log"
67+
)
68+
69+
try:
70+
# 2. Wait for health
71+
green_ready = await wait_for_agent(GREEN_URL, "Green Agent")
72+
purple_ready = await wait_for_agent(PURPLE_URL, "Purple Agent")
73+
74+
if not (green_ready and purple_ready):
75+
print("One or more agents failed to start. Aborting.")
76+
return
77+
78+
# 3. Send Test Request
79+
print("\n--- Sending Evaluation Request ---")
80+
81+
# This payload matches what the Green Agent expects locally
82+
payload = {
83+
"participants": {
84+
"translator": PURPLE_URL
85+
},
86+
"config": {
87+
"code_to_translate": "def factorial(n):\n if n == 0:\n return 1\n else:\n return n * factorial(n-1)",
88+
"source_language": "python",
89+
"target_language": "javascript"
90+
}
91+
}
92+
93+
from a2a.client import A2ACardResolver, ClientConfig, ClientFactory
94+
from a2a.types import Message, Part, TextPart, Role
95+
from uuid import uuid4
96+
97+
async with httpx.AsyncClient(timeout=60.0) as httpx_client:
98+
print(f"Resolving agent card from {GREEN_URL}...")
99+
resolver = A2ACardResolver(httpx_client=httpx_client, base_url=GREEN_URL)
100+
agent_card = await resolver.get_agent_card()
101+
102+
config = ClientConfig(httpx_client=httpx_client, streaming=True)
103+
factory = ClientFactory(config)
104+
client = factory.create(agent_card)
105+
106+
msg = Message(
107+
kind="message",
108+
role=Role.user,
109+
parts=[Part(TextPart(text=json.dumps(payload)))],
110+
message_id=uuid4().hex,
111+
)
112+
113+
print(f"Messaging Green Agent at {GREEN_URL}...")
114+
async for event in client.send_message(msg):
115+
if isinstance(event, Message):
116+
# Final response
117+
print(f"[RESPONSE]: {event.parts[0].root.text if event.parts and event.parts[0].root.kind == 'text' else event.parts}")
118+
else:
119+
# Task update tuple (task, task_update)
120+
task, update = event
121+
# We might get task updates or artifacts
122+
status = task.status.state
123+
status_text = ""
124+
if hasattr(task.status, 'message') and task.status.message and task.status.message.parts:
125+
# Check if part is TextPart (it might be wrapped in Part -> root -> text)
126+
part = task.status.message.parts[0]
127+
if hasattr(part, 'root') and hasattr(part.root, 'text'):
128+
status_text = part.root.text
129+
elif hasattr(part, 'text') and hasattr(part.text, 'text'):
130+
status_text = part.text.text
131+
132+
print(f"[UPDATE] Status: {status} | {status_text}")
133+
if update:
134+
# Ensure we print artifact if available
135+
pass
136+
137+
except Exception as e:
138+
print(f"An error occurred during testing: {e}")
139+
140+
finally:
141+
print("\n--- Shutting down agents ---")
142+
os.killpg(os.getpgid(green_proc.pid), signal.SIGTERM)
143+
os.killpg(os.getpgid(purple_proc.pid), signal.SIGTERM)
144+
green_log.close()
145+
purple_log.close()
146+
print("Done.")
147+
148+
if __name__ == "__main__":
149+
asyncio.run(run_test())

0 commit comments

Comments
 (0)