132 lines
3.9 KiB
Python
132 lines
3.9 KiB
Python
"""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}
|