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:
64
backend/app/services/task_runtime.py
Normal file
64
backend/app/services/task_runtime.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""Per-task runtime flags (Redis) — e.g. user-requested LLM tier escalation and cancellation."""
|
||||
from __future__ import annotations
|
||||
|
||||
from app.services.events import get_redis
|
||||
|
||||
TIER_ORDER = ["local", "economy", "premium"]
|
||||
TIER_RANK = {t: i for i, t in enumerate(TIER_ORDER)}
|
||||
|
||||
CANCELLABLE_STATUSES = frozenset({"queued", "running", "waiting_approval"})
|
||||
|
||||
|
||||
class TaskCancelledError(Exception):
|
||||
"""Raised when the user stops a running or queued task."""
|
||||
|
||||
|
||||
def _min_tier_key(task_id: int) -> str:
|
||||
return f"agentic:task:{task_id}:min_tier"
|
||||
|
||||
|
||||
def _cancel_key(task_id: int) -> str:
|
||||
return f"agentic:task:{task_id}:cancel"
|
||||
|
||||
|
||||
async def request_task_cancel(task_id: int) -> None:
|
||||
await get_redis().set(_cancel_key(task_id), "1", ex=86400)
|
||||
|
||||
|
||||
async def is_task_cancel_requested(task_id: int) -> bool:
|
||||
return bool(await get_redis().get(_cancel_key(task_id)))
|
||||
|
||||
|
||||
async def clear_task_cancel(task_id: int) -> None:
|
||||
await get_redis().delete(_cancel_key(task_id))
|
||||
|
||||
|
||||
async def ensure_not_cancelled(task_id: int) -> None:
|
||||
if await is_task_cancel_requested(task_id):
|
||||
raise TaskCancelledError("Task cancelled by user")
|
||||
|
||||
|
||||
async def set_task_min_tier(task_id: int, tier: str) -> None:
|
||||
if tier not in TIER_RANK:
|
||||
raise ValueError(f"Invalid tier: {tier}")
|
||||
await get_redis().set(_min_tier_key(task_id), tier, ex=86400)
|
||||
|
||||
|
||||
async def get_task_min_tier(task_id: int) -> str | None:
|
||||
tier = await get_redis().get(_min_tier_key(task_id))
|
||||
return tier if tier in TIER_RANK else None
|
||||
|
||||
|
||||
async def clear_task_min_tier(task_id: int) -> None:
|
||||
await get_redis().delete(_min_tier_key(task_id))
|
||||
|
||||
|
||||
def apply_min_tier_floor(tiers: list[str], min_tier: str) -> list[str]:
|
||||
"""Drop tiers below min_tier (e.g. skip local when user requests economy)."""
|
||||
if min_tier not in TIER_RANK:
|
||||
return tiers
|
||||
floor = TIER_RANK[min_tier]
|
||||
filtered = [t for t in tiers if TIER_RANK[t] >= floor]
|
||||
if filtered:
|
||||
return filtered
|
||||
return [min_tier]
|
||||
Reference in New Issue
Block a user