Spaces:
Sleeping
Sleeping
Claude Code Claude Opus 4.6 commited on
Commit ·
0fd72f9
1
Parent(s): baf67a7
Claude Code: Complete A2A routing - add target_agent validation with 400 error
Browse files- Modify POST /api/say to accept optional target_agent string
- Return 400 error if target_agent not found in registry
- Default to broadcast when target_agent is null/missing
- Log routing decision (Broadcast vs Direct) to console
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
app.py
CHANGED
|
@@ -282,64 +282,67 @@ async def api_say(request_data: dict):
|
|
| 282 |
Payload:
|
| 283 |
{
|
| 284 |
"message": "Hello, Agent!",
|
| 285 |
-
"target_agent": "AgentName", // Optional -
|
| 286 |
"sender": "sender_name" // Optional - for logging
|
| 287 |
}
|
| 288 |
"""
|
| 289 |
global _registered_agents, _agent_name_routing
|
| 290 |
|
| 291 |
message = request_data.get("message", "")
|
| 292 |
-
target_agent = request_data.get("target_agent"
|
| 293 |
sender = request_data.get("sender", "unknown")
|
| 294 |
|
| 295 |
if not message:
|
| 296 |
raise HTTPException(status_code=400, detail="message field is required")
|
| 297 |
|
| 298 |
-
|
| 299 |
-
if not target_agent:
|
| 300 |
-
logger.warning(f"[A2A] No target_agent specified by '{sender}', defaulting to broadcast (all). "
|
| 301 |
-
f"This may cause unnecessary network traffic.")
|
| 302 |
-
target_agent = "all"
|
| 303 |
-
|
| 304 |
-
results = {"delivered": [], "failed": [], "target_type": target_agent}
|
| 305 |
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
logger.info(f"[A2A]
|
|
|
|
| 309 |
for agent_id, agent_info in _registered_agents.items():
|
| 310 |
agent_name = agent_info["agentName"]
|
| 311 |
results["delivered"].append({
|
| 312 |
"agentId": agent_id,
|
| 313 |
"agentName": agent_name
|
| 314 |
})
|
| 315 |
-
# In a real implementation, you'd push to each agent here
|
| 316 |
results["broadcast_count"] = len(results["delivered"])
|
|
|
|
|
|
|
|
|
|
|
|
|
| 317 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
else:
|
| 319 |
-
#
|
| 320 |
-
|
| 321 |
-
|
| 322 |
-
|
| 323 |
-
|
| 324 |
-
|
| 325 |
-
"agentId": target_id,
|
| 326 |
-
"agentName": target_agent
|
| 327 |
-
})
|
| 328 |
-
logger.info(f"[A2A] Message from '{sender}' delivered to '{target_agent}'")
|
| 329 |
-
else:
|
| 330 |
-
results["failed"].append({
|
| 331 |
-
"agentName": target_agent,
|
| 332 |
-
"error": "Agent registered in routing but not in registry"
|
| 333 |
-
})
|
| 334 |
-
else:
|
| 335 |
-
results["failed"].append({
|
| 336 |
-
"agentName": target_agent,
|
| 337 |
-
"error": "Agent not found in routing table"
|
| 338 |
-
})
|
| 339 |
-
logger.warning(f"[A2A] Target agent '{target_agent}' not found in routing table")
|
| 340 |
|
| 341 |
return {
|
| 342 |
-
"success":
|
| 343 |
"results": results
|
| 344 |
}
|
| 345 |
|
|
|
|
| 282 |
Payload:
|
| 283 |
{
|
| 284 |
"message": "Hello, Agent!",
|
| 285 |
+
"target_agent": "AgentName", // Optional - if null/missing, broadcast to all
|
| 286 |
"sender": "sender_name" // Optional - for logging
|
| 287 |
}
|
| 288 |
"""
|
| 289 |
global _registered_agents, _agent_name_routing
|
| 290 |
|
| 291 |
message = request_data.get("message", "")
|
| 292 |
+
target_agent = request_data.get("target_agent")
|
| 293 |
sender = request_data.get("sender", "unknown")
|
| 294 |
|
| 295 |
if not message:
|
| 296 |
raise HTTPException(status_code=400, detail="message field is required")
|
| 297 |
|
| 298 |
+
results = {"delivered": [], "failed": [], "routing_type": ""}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
|
| 300 |
+
# Handle missing or null target_agent - default to broadcast
|
| 301 |
+
if not target_agent:
|
| 302 |
+
logger.info(f"[A2A] Routing: BROADCAST (no target specified, sending to all agents)")
|
| 303 |
+
results["routing_type"] = "Broadcast"
|
| 304 |
for agent_id, agent_info in _registered_agents.items():
|
| 305 |
agent_name = agent_info["agentName"]
|
| 306 |
results["delivered"].append({
|
| 307 |
"agentId": agent_id,
|
| 308 |
"agentName": agent_name
|
| 309 |
})
|
|
|
|
| 310 |
results["broadcast_count"] = len(results["delivered"])
|
| 311 |
+
return {
|
| 312 |
+
"success": True,
|
| 313 |
+
"results": results
|
| 314 |
+
}
|
| 315 |
|
| 316 |
+
# Direct routing to specific agent
|
| 317 |
+
logger.info(f"[A2A] Routing: DIRECT to '{target_agent}'")
|
| 318 |
+
results["routing_type"] = "Direct"
|
| 319 |
+
|
| 320 |
+
# Look up agent in routing table - return 400 if not found
|
| 321 |
+
if target_agent not in _agent_name_routing:
|
| 322 |
+
logger.warning(f"[A2A] Agent '{target_agent}' not found in registry")
|
| 323 |
+
raise HTTPException(
|
| 324 |
+
status_code=400,
|
| 325 |
+
detail=f"Agent '{target_agent}' not found in registry. Available agents: {list(_agent_name_routing.keys())}"
|
| 326 |
+
)
|
| 327 |
+
|
| 328 |
+
target_id = _agent_name_routing[target_agent]
|
| 329 |
+
agent_info = _registered_agents.get(target_id)
|
| 330 |
+
if agent_info:
|
| 331 |
+
results["delivered"].append({
|
| 332 |
+
"agentId": target_id,
|
| 333 |
+
"agentName": target_agent
|
| 334 |
+
})
|
| 335 |
+
logger.info(f"[A2A] Message from '{sender}' delivered to '{target_agent}'")
|
| 336 |
else:
|
| 337 |
+
# This should never happen if routing table is consistent
|
| 338 |
+
logger.error(f"[A2A] Inconsistent state: '{target_agent}' in routing but not in registry")
|
| 339 |
+
raise HTTPException(
|
| 340 |
+
status_code=500,
|
| 341 |
+
detail=f"Internal error: Agent '{target_agent}' found in routing table but not in registry"
|
| 342 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 343 |
|
| 344 |
return {
|
| 345 |
+
"success": True,
|
| 346 |
"results": results
|
| 347 |
}
|
| 348 |
|