"""Triggers REST API — CRUD endpoints for the Aware page frontend.""" import uuid from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel from sqlalchemy import select from app.api.auth import get_current_user from app.database import async_session from app.models.trigger import AgentTrigger router = APIRouter(prefix="/api/agents", tags=["triggers"]) class TriggerResponse(BaseModel): id: str name: str type: str config: dict reason: str focus_ref: str | None = None is_enabled: bool fire_count: int max_fires: int | None = None cooldown_seconds: int last_fired_at: str | None = None created_at: str | None = None expires_at: str | None = None class TriggerUpdate(BaseModel): config: dict | None = None reason: str | None = None is_enabled: bool | None = None max_fires: int | None = None cooldown_seconds: int | None = None expires_at: str | None = None @router.get("/{agent_id}/triggers", response_model=list[TriggerResponse]) async def list_agent_triggers(agent_id: uuid.UUID, user=Depends(get_current_user)): """List all triggers for an agent.""" async with async_session() as db: result = await db.execute( select(AgentTrigger) .where(AgentTrigger.agent_id == agent_id) .order_by(AgentTrigger.created_at.desc()) ) triggers = result.scalars().all() return [ TriggerResponse( id=str(t.id), name=t.name, type=t.type, config=t.config or {}, reason=t.reason or "", focus_ref=t.focus_ref, is_enabled=t.is_enabled, fire_count=t.fire_count, max_fires=t.max_fires, cooldown_seconds=t.cooldown_seconds, last_fired_at=t.last_fired_at.isoformat() if t.last_fired_at else None, created_at=t.created_at.isoformat() if t.created_at else None, expires_at=t.expires_at.isoformat() if t.expires_at else None, ) for t in triggers ] @router.patch("/{agent_id}/triggers/{trigger_id}") async def update_trigger( agent_id: uuid.UUID, trigger_id: uuid.UUID, body: TriggerUpdate, user=Depends(get_current_user), ): """Update a trigger (from frontend management UI).""" async with async_session() as db: result = await db.execute( select(AgentTrigger).where( AgentTrigger.id == trigger_id, AgentTrigger.agent_id == agent_id, ) ) trigger = result.scalar_one_or_none() if not trigger: raise HTTPException(404, "Trigger not found") if body.config is not None: trigger.config = body.config if body.reason is not None: trigger.reason = body.reason if body.is_enabled is not None: trigger.is_enabled = body.is_enabled if body.max_fires is not None: trigger.max_fires = body.max_fires if body.cooldown_seconds is not None: trigger.cooldown_seconds = body.cooldown_seconds if body.expires_at is not None: from datetime import datetime trigger.expires_at = datetime.fromisoformat(body.expires_at) await db.commit() return {"ok": True} @router.delete("/{agent_id}/triggers/{trigger_id}") async def delete_trigger( agent_id: uuid.UUID, trigger_id: uuid.UUID, user=Depends(get_current_user), ): """Delete a trigger entirely.""" async with async_session() as db: result = await db.execute( select(AgentTrigger).where( AgentTrigger.id == trigger_id, AgentTrigger.agent_id == agent_id, ) ) trigger = result.scalar_one_or_none() if not trigger: raise HTTPException(404, "Trigger not found") await db.delete(trigger) await db.commit() return {"ok": True}