feat: Presence Layer API implementation

Matrix Gateway:
- GET /internal/matrix/presence/{matrix_user_id} - get single user presence
- GET /internal/matrix/presence/bulk - get multiple users presence

City Service:
- GET /api/v1/agents/{agent_id}/presence - get agent presence via gateway
- get_matrix_presence_for_user() helper function

Task doc: TASK_PHASE_PRESENCE_LAYER_v1.md
This commit is contained in:
Apple
2025-11-30 10:42:29 -08:00
parent e912019d16
commit 3bfbd359fd
3 changed files with 412 additions and 0 deletions

View File

@@ -1736,6 +1736,61 @@ async def get_agents_presence():
raise HTTPException(status_code=500, detail="Failed to get agents presence")
@api_router.get("/agents/{agent_id}/presence")
async def get_single_agent_presence(agent_id: str):
"""
Отримати presence статус одного агента.
Використовує Matrix Gateway для отримання реального статусу.
"""
try:
# Get agent from DB
agent = await repo_city.get_agent_by_id(agent_id)
if not agent:
raise HTTPException(status_code=404, detail=f"Agent not found: {agent_id}")
# Get Matrix user ID for agent (or generate it)
# Pattern: @agent_{slug}:daarion.space
agent_slug = agent.get("public_slug") or agent_id.replace("ag_", "").replace("-", "_")
matrix_user_id = f"@agent_{agent_slug}:daarion.space"
# Get presence from Matrix Gateway
presence_data = await get_matrix_presence_for_user(matrix_user_id)
return {
"agent_id": agent_id,
"display_name": agent.get("display_name"),
"matrix_user_id": matrix_user_id,
"presence": presence_data.get("presence", "offline"),
"last_active_ago_ms": presence_data.get("last_active_ago_ms"),
"status_msg": presence_data.get("status_msg")
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to get agent presence for {agent_id}: {e}")
raise HTTPException(status_code=500, detail="Failed to get agent presence")
async def get_matrix_presence_for_user(matrix_user_id: str) -> dict:
"""
Get Matrix presence for a single user via Matrix Gateway.
"""
try:
gateway_url = os.getenv("MATRIX_GATEWAY_URL", "http://daarion-matrix-gateway:7025")
async with httpx.AsyncClient(timeout=5.0) as client:
# URL encode the matrix user ID
encoded_mxid = matrix_user_id.replace("@", "%40").replace(":", "%3A")
response = await client.get(f"{gateway_url}/internal/matrix/presence/{encoded_mxid}")
if response.status_code == 200:
return response.json()
else:
logger.warning(f"Matrix gateway presence returned {response.status_code}")
return {"presence": "offline"}
except Exception as e:
logger.warning(f"Failed to get Matrix presence for {matrix_user_id}: {e}")
return {"presence": "offline"}
async def get_matrix_presence_status():
"""
Get Matrix presence from matrix-presence-aggregator.