feat(agent-zero): uvicorn A2A server calling LiteLLM directly
CI / validate (pull_request) Failing after 1s
CI / validate (pull_request) Failing after 1s
This commit is contained in:
@@ -1,24 +1,24 @@
|
|||||||
"""A2A Agent for kagentz — processes messages via Agent Zero core directly."""
|
"""A2A agent for kagentz — uvicorn-based, calls LiteLLM for responses."""
|
||||||
import sys, os, asyncio, json, uuid, time
|
import os, json, uuid, threading, asyncio
|
||||||
|
|
||||||
sys.path.insert(0, "/a0")
|
|
||||||
os.environ["A2A_TOKEN"] = "8zNgdOEXzYxjQvTl"
|
|
||||||
|
|
||||||
import uvicorn
|
import uvicorn
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request
|
||||||
from agent import AgentContext, UserMessage, AgentContextType
|
from fastapi.responses import JSONResponse
|
||||||
|
import httpx
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
AGENT_TOKEN = os.environ["A2A_TOKEN"]
|
task_results = {}
|
||||||
|
LITELLM_URL = "https://litellm.sysloggh.net/v1"
|
||||||
|
LITELLM_KEY = "sk-U_ydi3B-wfGU-_xESkoU1Q"
|
||||||
|
LITELLM_MODEL = "syslog-auto"
|
||||||
|
|
||||||
@app.get("/.well-known/agent.json")
|
@app.get("/.well-known/agent.json")
|
||||||
async def agent_card():
|
async def agent_card():
|
||||||
return {
|
return {
|
||||||
"name": "kagentz",
|
"name": "kagentz",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Agent Zero instance managed via Zulip",
|
"description": "Agent Zero on CT 105 via Zulip + LiteLLM",
|
||||||
"capabilities": {"a2a": {"version": "1.0", "authentication": ["bearer"]}},
|
"capabilities": {"a2a": {"version": "1.0"}},
|
||||||
"skills": [{"id": "chat", "name": "Chat", "description": "General conversation via Zulip"}],
|
"skills": [{"id": "chat", "name": "Chat"}],
|
||||||
}
|
}
|
||||||
|
|
||||||
@app.post("/a2a")
|
@app.post("/a2a")
|
||||||
@@ -31,17 +31,13 @@ async def a2a_endpoint(request: Request):
|
|||||||
msg = params.get("message", {})
|
msg = params.get("message", {})
|
||||||
parts = msg.get("parts", [])
|
parts = msg.get("parts", [])
|
||||||
text = " ".join(p.get("text", "") for p in parts if isinstance(p, dict))
|
text = " ".join(p.get("text", "") for p in parts if isinstance(p, dict))
|
||||||
|
|
||||||
task_id = f"az-{uuid.uuid4().hex[:12]}"
|
task_id = f"az-{uuid.uuid4().hex[:12]}"
|
||||||
asyncio.create_task(process_via_agent_zero(task_id, text))
|
asyncio.create_task(call_litellm(task_id, text))
|
||||||
|
|
||||||
return {"jsonrpc": "2.0", "result": {"id": task_id, "status": {"state": "working"}}}
|
return {"jsonrpc": "2.0", "result": {"id": task_id, "status": {"state": "working"}}}
|
||||||
|
|
||||||
elif method == "tasks/get":
|
elif method == "tasks/get":
|
||||||
params = body.get("params", {})
|
task_id = body.get("params", {}).get("id", "")
|
||||||
task_id = params.get("id", "")
|
|
||||||
status, result = task_results.get(task_id, ("pending", None))
|
status, result = task_results.get(task_id, ("pending", None))
|
||||||
|
|
||||||
resp = {"jsonrpc": "2.0", "result": {"id": task_id, "status": {"state": status}}}
|
resp = {"jsonrpc": "2.0", "result": {"id": task_id, "status": {"state": status}}}
|
||||||
if status == "completed" and result:
|
if status == "completed" and result:
|
||||||
resp["result"]["history"] = [
|
resp["result"]["history"] = [
|
||||||
@@ -49,44 +45,31 @@ async def a2a_endpoint(request: Request):
|
|||||||
{"role": "assistant", "parts": [{"text": result.get("output", "")}]},
|
{"role": "assistant", "parts": [{"text": result.get("output", "")}]},
|
||||||
]
|
]
|
||||||
elif status == "failed":
|
elif status == "failed":
|
||||||
resp["result"]["status"]["message"] = {"text": str(result or "Unknown error")}
|
resp["result"]["status"]["message"] = {"text": str(result)}
|
||||||
|
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
return {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}}
|
return {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}}
|
||||||
|
|
||||||
task_results = {}
|
async def call_litellm(task_id, message):
|
||||||
|
|
||||||
async def process_via_agent_zero(task_id: str, message: str):
|
|
||||||
"""Process a message through Agent Zero's core."""
|
|
||||||
try:
|
try:
|
||||||
# Create a new context and send the message
|
async with httpx.AsyncClient(timeout=120.0) as client:
|
||||||
ctx = AgentContext.get(uuid.uuid4().hex)
|
resp = await client.post(
|
||||||
|
f"{LITELLM_URL}/chat/completions",
|
||||||
# Run in executor to avoid blocking the event loop
|
headers={"Authorization": f"Bearer {LITELLM_KEY}", "Content-Type": "application/json"},
|
||||||
loop = asyncio.get_event_loop()
|
json={
|
||||||
|
"model": LITELLM_MODEL,
|
||||||
def _run():
|
"messages": [
|
||||||
try:
|
{"role": "system", "content": "You are kagentz, an Agent Zero instance on CT 105. You communicate via Zulip. Keep responses concise."},
|
||||||
# Send user message and get response
|
{"role": "user", "content": message},
|
||||||
msg = UserMessage(text=message, context=ctx)
|
],
|
||||||
result = ctx.agent.handle_message(msg)
|
"max_tokens": 2000,
|
||||||
|
},
|
||||||
# Extract text response
|
)
|
||||||
if hasattr(result, 'content'):
|
if resp.is_success:
|
||||||
output = result.content
|
output = resp.json()["choices"][0]["message"]["content"]
|
||||||
elif isinstance(result, str):
|
task_results[task_id] = ("completed", {"input": message, "output": output})
|
||||||
output = result
|
else:
|
||||||
else:
|
task_results[task_id] = ("failed", f"HTTP {resp.status_code}")
|
||||||
output = str(result)
|
|
||||||
|
|
||||||
return output
|
|
||||||
except Exception as e:
|
|
||||||
return f"Error: {e}"
|
|
||||||
|
|
||||||
output = await loop.run_in_executor(None, _run)
|
|
||||||
task_results[task_id] = ("completed", {"input": message, "output": output})
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
task_results[task_id] = ("failed", str(e))
|
task_results[task_id] = ("failed", str(e))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user