feat: add /public/agents endpoint for Agent Console with home_node

This commit is contained in:
Apple
2025-11-28 04:49:58 -08:00
parent 7e55b72027
commit e8bcb0c97e
3 changed files with 154 additions and 0 deletions

View File

@@ -161,6 +161,21 @@ class AgentRead(BaseModel):
capabilities: List[str] = []
class AgentSummary(BaseModel):
"""Agent summary for Agent Console"""
id: str
display_name: str
kind: str = "assistant"
avatar_url: Optional[str] = None
status: str = "offline"
is_public: bool = False
public_slug: Optional[str] = None
public_title: Optional[str] = None
district: Optional[str] = None
home_node: Optional[HomeNodeView] = None
microdao_memberships: List[Dict[str, Any]] = []
class AgentPresence(BaseModel):
"""Agent presence in a room"""
agent_id: str

View File

@@ -307,6 +307,87 @@ async def get_all_agents() -> List[dict]:
return [dict(row) for row in rows]
async def get_agents_with_home_node(
kind: Optional[str] = None,
node_id: Optional[str] = None,
limit: int = 100,
offset: int = 0
) -> Tuple[List[dict], int]:
"""Отримати агентів з інформацією про home_node"""
pool = await get_pool()
params: List[Any] = []
where_clauses = ["1=1"]
if kind:
params.append(kind)
where_clauses.append(f"a.kind = ${len(params)}")
if node_id:
params.append(node_id)
where_clauses.append(f"a.node_id = ${len(params)}")
where_sql = " AND ".join(where_clauses)
query = f"""
SELECT
a.id,
a.display_name,
a.kind,
a.avatar_url,
a.status,
a.is_public,
a.public_slug,
a.public_title,
a.public_district,
a.node_id,
nc.node_name AS home_node_name,
nc.hostname AS home_node_hostname,
nc.roles AS home_node_roles,
nc.environment AS home_node_environment,
COUNT(*) OVER() AS total_count
FROM agents a
LEFT JOIN node_cache nc ON a.node_id = nc.node_id
WHERE {where_sql}
ORDER BY a.display_name
LIMIT ${len(params) + 1} OFFSET ${len(params) + 2}
"""
params.append(limit)
params.append(offset)
rows = await pool.fetch(query, *params)
if not rows:
return [], 0
total = rows[0]["total_count"]
items = []
for row in rows:
data = dict(row)
data.pop("total_count", None)
# Build home_node object
if data.get("node_id"):
data["home_node"] = {
"id": data.get("node_id"),
"name": data.get("home_node_name"),
"hostname": data.get("home_node_hostname"),
"roles": list(data.get("home_node_roles") or []),
"environment": data.get("home_node_environment")
}
else:
data["home_node"] = None
# Clean up intermediate fields
for key in ["home_node_name", "home_node_hostname", "home_node_roles", "home_node_environment"]:
data.pop(key, None)
items.append(data)
return items, total
async def get_agents_by_room(room_id: str) -> List[dict]:
"""Отримати агентів у конкретній кімнаті"""
pool = await get_pool()

View File

@@ -21,6 +21,7 @@ from models_city import (
CityMapResponse,
AgentRead,
AgentPresence,
AgentSummary,
HomeNodeView,
PublicCitizenSummary,
PublicCitizenProfile,
@@ -57,6 +58,63 @@ class MicrodaoMembershipPayload(BaseModel):
is_core: bool = False
# =============================================================================
# Agents API (for Agent Console)
# =============================================================================
@public_router.get("/agents")
async def list_agents(
kind: Optional[str] = Query(None, description="Filter by agent kind"),
node_id: Optional[str] = Query(None, description="Filter by node_id"),
limit: int = Query(100, le=200),
offset: int = Query(0, ge=0)
):
"""Список всіх агентів для Agent Console"""
try:
agents, total = await repo_city.get_agents_with_home_node(
kind=kind,
node_id=node_id,
limit=limit,
offset=offset
)
items: List[AgentSummary] = []
for agent in agents:
# Build home_node if available
home_node_data = agent.get("home_node")
home_node = None
if home_node_data:
home_node = HomeNodeView(
id=home_node_data.get("id"),
name=home_node_data.get("name"),
hostname=home_node_data.get("hostname"),
roles=home_node_data.get("roles", []),
environment=home_node_data.get("environment")
)
# Get microdao memberships
memberships = await repo_city.get_agent_microdao_memberships(agent["id"])
items.append(AgentSummary(
id=agent["id"],
display_name=agent["display_name"],
kind=agent.get("kind", "assistant"),
avatar_url=agent.get("avatar_url"),
status=agent.get("status", "offline"),
is_public=agent.get("is_public", False),
public_slug=agent.get("public_slug"),
public_title=agent.get("public_title"),
district=agent.get("public_district"),
home_node=home_node,
microdao_memberships=memberships
))
return {"items": items, "total": total}
except Exception as e:
logger.error(f"Failed to list agents: {e}")
raise HTTPException(status_code=500, detail="Failed to list agents")
# =============================================================================
# Public Citizens API
# =============================================================================