Switch Agent0 from MCP to REST API (/api/api_message)
MCP endpoint returns 403 (wrong token) and the mcp library's TaskGroup error is opaque. The REST API (X-API-KEY header, /api/api_message) is already validated in connectivity tests and returns proper responses. mcp_key field is reused as the X-API-KEY value. context_id replaces chat_id for conversation continuity. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -268,60 +268,50 @@ async def handle_agent0_mcp(
|
||||
valid_poses: list[str],
|
||||
) -> ChatResponse:
|
||||
"""
|
||||
Send a message to a live Agent Zero instance via its MCP streamable-http
|
||||
server and return the response as a ChatResponse.
|
||||
Send a message to a live Agent Zero instance via its REST API
|
||||
(POST /api/api_message, X-API-KEY header).
|
||||
|
||||
MCP URL format: {endpoint}/mcp/t-{mcp_key}/http
|
||||
Tool called: send_message (built into every Agent Zero instance)
|
||||
|
||||
Conversation continuity is maintained via Agent Zero's chat_id, which maps
|
||||
to a gnommoweb conversation_id in _a0_sessions (in-memory).
|
||||
Conversation continuity is maintained via Agent Zero's context_id, which
|
||||
maps to a gnommoweb conversation_id in _a0_sessions (in-memory).
|
||||
"""
|
||||
from mcp.client.streamable_http import streamablehttp_client
|
||||
from mcp import ClientSession
|
||||
|
||||
endpoint = (model.endpoint or "").strip().rstrip("/")
|
||||
mcp_key = model.mcp_key or ""
|
||||
mcp_url = f"{endpoint}/mcp/t-{mcp_key}/http"
|
||||
api_key = model.mcp_key or "" # stored in mcp_key field; used as X-API-KEY
|
||||
api_url = f"{endpoint}/api/api_message"
|
||||
|
||||
# Retrieve existing Agent0 chat_id for this conversation (if any)
|
||||
a0_chat_id = _a0_sessions.get(req.conversation_id) if req.conversation_id else None
|
||||
# Retrieve existing Agent0 context_id for this conversation (if any)
|
||||
a0_context_id = _a0_sessions.get(req.conversation_id) if req.conversation_id else None
|
||||
|
||||
log.info(
|
||||
f"[{agent.name}] → Agent0 MCP url={mcp_url} "
|
||||
f"conv={req.conversation_id} a0_chat={a0_chat_id or 'new'} "
|
||||
f"[{agent.name}] → Agent0 REST url={api_url} "
|
||||
f"conv={req.conversation_id} a0_ctx={a0_context_id or 'new'} "
|
||||
f"msg='{req.message[:60]}'"
|
||||
)
|
||||
|
||||
try:
|
||||
async with streamablehttp_client(mcp_url) as (read, write, _):
|
||||
async with ClientSession(read, write) as session:
|
||||
await session.initialize()
|
||||
payload: dict = {
|
||||
"message": req.message,
|
||||
"lifetime_hours": 24,
|
||||
}
|
||||
if a0_context_id:
|
||||
payload["context_id"] = a0_context_id
|
||||
|
||||
tool_args: dict = {
|
||||
"message": req.message,
|
||||
"persistent_chat": True,
|
||||
}
|
||||
if a0_chat_id:
|
||||
tool_args["chat_id"] = a0_chat_id
|
||||
async with httpx.AsyncClient(timeout=120.0) as client:
|
||||
r = await client.post(
|
||||
api_url,
|
||||
headers={"X-API-KEY": api_key, "Content-Type": "application/json"},
|
||||
json=payload,
|
||||
)
|
||||
r.raise_for_status()
|
||||
|
||||
result = await session.call_tool("send_message", tool_args)
|
||||
data = r.json()
|
||||
log.info(f"[{agent.name}] ← Agent0 REST: {str(data)[:300]}")
|
||||
|
||||
# The tool returns a JSON-serialised ToolResponse / ToolError
|
||||
raw = result.content[0].text if result.content else "{}"
|
||||
log.info(f"[{agent.name}] ← Agent0 MCP raw: {raw[:300]}")
|
||||
response_text = data.get("response", "")
|
||||
new_context_id = data.get("context_id", "")
|
||||
|
||||
parsed = json.loads(raw)
|
||||
|
||||
if parsed.get("status") == "error":
|
||||
raise RuntimeError(parsed.get("error", "Unknown Agent0 error"))
|
||||
|
||||
response_text = parsed.get("response", "")
|
||||
new_chat_id = parsed.get("chat_id", "")
|
||||
|
||||
# Persist the Agent0 chat_id so the next turn continues the same context
|
||||
if new_chat_id and req.conversation_id is not None:
|
||||
_a0_sessions[req.conversation_id] = new_chat_id
|
||||
# Persist context_id for conversation continuity
|
||||
if new_context_id and req.conversation_id is not None:
|
||||
_a0_sessions[req.conversation_id] = new_context_id
|
||||
|
||||
pose = pick_pose(response_text, valid_poses)
|
||||
|
||||
@@ -334,7 +324,7 @@ async def handle_agent0_mcp(
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
log.error(f"[{agent.name}] Agent0 MCP error: {e}")
|
||||
log.error(f"[{agent.name}] Agent0 REST error: {e}")
|
||||
fallback_pose = next(
|
||||
(p for p in ("sorry", "annoyed", "neutral") if p in valid_poses),
|
||||
valid_poses[0],
|
||||
|
||||
Reference in New Issue
Block a user