Initial commit: Agentic OS troubleshooting platform
Self-hosted, Docker-based agentic troubleshooting platform: FastAPI backend + LangGraph agent, Next.js UI, tiered LLM routing (local Ollama -> Gemini -> DeepSeek -> OpenRouter), MCP server manager, encrypted device credentials, RBAC, audit log, project-memory + Obsidian integrations, and editable troubleshooting decision rules tuned for the GeneseasX vessel stack. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
85
backend/app/services/task_present.py
Normal file
85
backend/app/services/task_present.py
Normal file
@@ -0,0 +1,85 @@
|
||||
"""Serialize tasks with vessel names for API responses."""
|
||||
from __future__ import annotations
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.inventory import Vessel
|
||||
from app.models.task import Task
|
||||
from app.schemas import TaskDetail, TaskOut, TaskOverviewOut
|
||||
|
||||
|
||||
async def vessel_name_map(db: AsyncSession, vessel_ids: set[int]) -> dict[int, str]:
|
||||
if not vessel_ids:
|
||||
return {}
|
||||
res = await db.execute(select(Vessel).where(Vessel.id.in_(vessel_ids)))
|
||||
return {v.id: v.name for v in res.scalars().all()}
|
||||
|
||||
|
||||
def task_to_out(task: Task, *, vessel_name: str | None = None) -> TaskOut:
|
||||
base = TaskOut.model_validate(task)
|
||||
name = vessel_name
|
||||
if name is None and task.report:
|
||||
name = task.report.get("vessel_name")
|
||||
return base.model_copy(update={"vessel_name": name})
|
||||
|
||||
|
||||
def task_to_detail(task: Task, *, vessel_name: str | None = None) -> TaskDetail:
|
||||
base = TaskDetail.model_validate(task)
|
||||
name = vessel_name
|
||||
if name is None and task.report:
|
||||
name = task.report.get("vessel_name")
|
||||
return base.model_copy(update={"vessel_name": name})
|
||||
|
||||
|
||||
def _report_summary(report: dict | None) -> tuple[str | None, str | None]:
|
||||
if not report:
|
||||
return None, None
|
||||
summary = report.get("executive_summary") or report.get("summary")
|
||||
findings = report.get("findings") or []
|
||||
key_finding = None
|
||||
if isinstance(findings, list) and findings:
|
||||
first = findings[0]
|
||||
if isinstance(first, dict):
|
||||
key_finding = first.get("summary") or first.get("description")
|
||||
else:
|
||||
key_finding = str(first)
|
||||
if not key_finding:
|
||||
key_finding = report.get("root_cause") or report.get("resolution")
|
||||
return summary, key_finding
|
||||
|
||||
|
||||
def task_to_overview(task: Task, *, vessel_name: str | None = None) -> TaskOverviewOut:
|
||||
report = task.report or {}
|
||||
name = vessel_name or report.get("vessel_name")
|
||||
summary, key_finding = _report_summary(report)
|
||||
return TaskOverviewOut(
|
||||
id=task.id,
|
||||
title=task.title,
|
||||
issue=task.issue,
|
||||
status=task.status,
|
||||
vessel_id=task.vessel_id,
|
||||
vessel_name=name,
|
||||
summary=summary,
|
||||
key_finding=key_finding,
|
||||
devices_checked=list(report.get("devices_checked") or []),
|
||||
resolved=report.get("resolved"),
|
||||
memory_id=task.memory_id or report.get("memory_id"),
|
||||
obsidian_path=task.obsidian_path or report.get("obsidian_path"),
|
||||
obsidian_push_error=report.get("obsidian_push_error"),
|
||||
run_cost_usd=report.get("run_cost_usd"),
|
||||
created_at=task.created_at,
|
||||
updated_at=task.updated_at,
|
||||
)
|
||||
|
||||
|
||||
async def tasks_to_out_list(db: AsyncSession, tasks: list[Task]) -> list[TaskOut]:
|
||||
ids = {t.vessel_id for t in tasks if t.vessel_id}
|
||||
vmap = await vessel_name_map(db, ids)
|
||||
return [task_to_out(t, vessel_name=vmap.get(t.vessel_id) if t.vessel_id else None) for t in tasks]
|
||||
|
||||
|
||||
async def tasks_to_overview_list(db: AsyncSession, tasks: list[Task]) -> list[TaskOverviewOut]:
|
||||
ids = {t.vessel_id for t in tasks if t.vessel_id}
|
||||
vmap = await vessel_name_map(db, ids)
|
||||
return [task_to_overview(t, vessel_name=vmap.get(t.vessel_id) if t.vessel_id else None) for t in tasks]
|
||||
Reference in New Issue
Block a user