TaskPulse/backend/app/services/agent.py
Steven b04c0ce321 feat: agent avatars, task tags, search, edit/delete agents, cron readability, timezone fix
- Agent avatars: first-letter + deterministic color avatar in all views
- Agent management: edit (name/description) and delete with confirmation
- Execution API: validates agent existence, returns 410 if deleted
- Task tags: JSON array field, editable with tag pills UI
- Task search: by name (?q=) and by tags (?tags=) and by status
- Task edit: simplified to name/tags/description only (not agent params)
- Cron display: human-readable Chinese (e.g. '每5分钟', '每天 09:00')
- Timezone fix: UTC→local via dayjs.utc().local() across all pages
- Content area: full width (removed max-width:1200px constraints)
- Login page: standalone layout without sidebar
2026-06-15 23:33:28 +08:00

63 lines
2.0 KiB
Python

"""Agent business logic."""
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.models import Agent, ScheduledTask
class AgentService:
def __init__(self, db: AsyncSession):
self.db = db
async def create(self, name: str, description: str = "") -> Agent:
agent = Agent(name=name, description=description)
self.db.add(agent)
await self.db.flush()
await self.db.refresh(agent)
return agent
async def get(self, agent_id: int) -> Agent | None:
return await self.db.get(Agent, agent_id)
async def get_by_api_key(self, api_key: str) -> Agent | None:
stmt = select(Agent).where(Agent.api_key == api_key)
result = await self.db.execute(stmt)
return result.scalar_one_or_none()
async def list_all(self) -> list[Agent]:
stmt = select(Agent).order_by(Agent.id)
result = await self.db.execute(stmt)
return list(result.scalars().all())
async def update(self, agent_id: int, **kwargs) -> Agent | None:
agent = await self.get(agent_id)
if agent is None:
return None
for k, v in kwargs.items():
if v is not None and hasattr(agent, k):
setattr(agent, k, v)
await self.db.flush()
return agent
async def heartbeat(self, agent_id: int) -> Agent | None:
from datetime import datetime
agent = await self.get(agent_id)
if agent:
agent.last_heartbeat_at = datetime.utcnow()
await self.db.flush()
return agent
async def get_task_count(self, agent_id: int) -> int:
stmt = select(func.count(ScheduledTask.id)).where(ScheduledTask.agent_id == agent_id)
result = await self.db.execute(stmt)
return result.scalar() or 0
async def delete(self, agent_id: int) -> bool:
agent = await self.get(agent_id)
if agent is None:
return False
await self.db.delete(agent)
await self.db.flush()
return True