Files
Agentic-OS/backend/app/models/task.py
nearxos 6185b9b85a 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>
2026-06-14 22:11:07 +03:00

86 lines
3.8 KiB
Python

"""Troubleshooting tasks, their event stream, and approval requests."""
from __future__ import annotations
from datetime import datetime
from sqlalchemy import DateTime, Enum, ForeignKey, Index, Integer, String, Text, func
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.database import Base
from app.models.enums import ApprovalStatus, TaskStatus
class Task(Base):
__tablename__ = "tasks"
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(255))
issue: Mapped[str] = mapped_column(Text) # description of the problem
details: Mapped[dict | None] = mapped_column(JSONB, nullable=True) # extra structured context
status: Mapped[TaskStatus] = mapped_column(Enum(TaskStatus), default=TaskStatus.queued, index=True)
device_id: Mapped[int | None] = mapped_column(
ForeignKey("devices.id", ondelete="SET NULL"), nullable=True
)
vessel_id: Mapped[int | None] = mapped_column(
ForeignKey("vessels.id", ondelete="SET NULL"), nullable=True, index=True
)
created_by_id: Mapped[int | None] = mapped_column(
ForeignKey("users.id", ondelete="SET NULL"), nullable=True
)
# Final structured report (issue, steps, root cause, resolution)
report: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
error: Mapped[str | None] = mapped_column(Text, nullable=True)
# Links to persisted artifacts
memory_id: Mapped[str | None] = mapped_column(String(128), nullable=True)
obsidian_path: Mapped[str | None] = mapped_column(String(512), nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
)
events: Mapped[list["TaskEvent"]] = relationship(
back_populates="task", cascade="all, delete-orphan", order_by="TaskEvent.id"
)
approvals: Mapped[list["ApprovalRequest"]] = relationship(
back_populates="task", cascade="all, delete-orphan"
)
class TaskEvent(Base):
__tablename__ = "task_events"
id: Mapped[int] = mapped_column(primary_key=True)
task_id: Mapped[int] = mapped_column(ForeignKey("tasks.id", ondelete="CASCADE"), index=True)
# node / kind: triage, connect, diagnose, reason, propose_fix, report, tool_call, log, error
kind: Mapped[str] = mapped_column(String(64))
message: Mapped[str | None] = mapped_column(Text, nullable=True)
payload: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
task: Mapped[Task] = relationship(back_populates="events")
class ApprovalRequest(Base):
__tablename__ = "approval_requests"
__table_args__ = (
Index("ix_approval_requests_task_status", "task_id", "status"),
)
id: Mapped[int] = mapped_column(primary_key=True)
task_id: Mapped[int] = mapped_column(ForeignKey("tasks.id", ondelete="CASCADE"), index=True)
tool_name: Mapped[str] = mapped_column(String(255))
tool_args: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
risk: Mapped[str | None] = mapped_column(Text, nullable=True)
status: Mapped[ApprovalStatus] = mapped_column(Enum(ApprovalStatus), default=ApprovalStatus.pending)
decided_by_id: Mapped[int | None] = mapped_column(
ForeignKey("users.id", ondelete="SET NULL"), nullable=True
)
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
decided_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
task: Mapped[Task] = relationship(back_populates="approvals")