Files
microdao-daarion/services/city-service/routes_agents.py

119 lines
4.7 KiB
Python

from fastapi import APIRouter, HTTPException, Request, Depends
from typing import List
import logging
import repo_city
from schemas_agents import AgentPromptList, AgentPromptUpsertRequest, AgentPrompt
router = APIRouter(prefix="/agents", tags=["agents"])
logger = logging.getLogger(__name__)
@router.get("/{agent_id}/prompts", response_model=AgentPromptList)
async def get_agent_prompts(agent_id: str):
"""
Отримати системні промти агента.
"""
try:
# Check agent exists
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 prompts dict from repo
prompts_dict = await repo_city.get_agent_prompts(agent_id)
# Convert to list of AgentPrompt models
prompts_list = []
valid_kinds = ["core", "safety", "governance", "tools"]
for kind in valid_kinds:
p_data = prompts_dict.get(kind)
if p_data:
prompts_list.append(AgentPrompt(
kind=kind,
content=p_data["content"],
version=p_data["version"],
updated_at=p_data["created_at"], # repo returns created_at as isoformat string or datetime? Repo returns isoformat string in dict
note=p_data.get("note")
))
else:
# Should we return empty prompt structure or just skip?
# The frontend expects 4 kinds. If we skip, frontend might need adjustment.
# But AgentPrompt requires content.
# Let's return empty content if missing, or just skip and let frontend handle default.
# Frontend AgentSystemPromptsCard handles missing prompts gracefully?
# Yes: const currentPrompt = systemPrompts?.[activeTab];
pass
# However, the response model is AgentPromptList which has prompts: List[AgentPrompt].
# If we return a list, the frontend needs to map it back to dict by kind.
# The user requested GET returns AgentPromptList.
# Wait, the frontend `useAgentPrompts` implementation in the prompt suggests:
# return { prompts: data?.prompts ?? [] }
# And the component maps it:
# for (const p of prompts) { map[p.kind] = p.content; }
return AgentPromptList(agent_id=agent_id, prompts=prompts_list)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to get agent prompts: {e}")
raise HTTPException(status_code=500, detail="Failed to get agent prompts")
@router.put("/{agent_id}/prompts", response_model=AgentPromptList)
async def upsert_agent_prompts_endpoint(agent_id: str, payload: AgentPromptUpsertRequest, request: Request):
"""
Оновити системні промти агента (bulk).
"""
try:
# Check agent exists
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}")
# TODO: Get user from auth
created_by = "ARCHITECT"
# Upsert
# Convert Pydantic models to dicts for repo
prompts_to_update = []
for p in payload.prompts:
prompts_to_update.append({
"kind": p.kind,
"content": p.content,
"note": p.note
})
if not prompts_to_update:
# Nothing to update, just return current state
pass
else:
await repo_city.upsert_agent_prompts(agent_id, prompts_to_update, created_by)
# Return updated state
# Re-use get logic
prompts_dict = await repo_city.get_agent_prompts(agent_id)
prompts_list = []
valid_kinds = ["core", "safety", "governance", "tools"]
for kind in valid_kinds:
p_data = prompts_dict.get(kind)
if p_data:
prompts_list.append(AgentPrompt(
kind=kind,
content=p_data["content"],
version=p_data["version"],
updated_at=p_data["created_at"],
note=p_data.get("note")
))
return AgentPromptList(agent_id=agent_id, prompts=prompts_list)
except HTTPException:
raise
except Exception as e:
logger.error(f"Failed to upsert agent prompts: {e}")
raise HTTPException(status_code=500, detail="Failed to upsert agent prompts")