Files
Agentic-OS/backend/app/api/balance.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

55 lines
1.9 KiB
Python

"""API balance / consumption endpoints."""
from __future__ import annotations
from fastapi import APIRouter, Depends
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.deps import require_readonly, require_support
from app.database import get_db
from app.models.balance import BalanceSnapshot
from app.models.user import User
from app.schemas import BalanceOut
from app.services import balance as balance_service
router = APIRouter(prefix="/api/balance", tags=["balance"])
async def _latest_snapshot(db: AsyncSession, provider: str) -> BalanceSnapshot | None:
"""Prefer the newest successful snapshot; fall back to latest error row."""
res = await db.execute(
select(BalanceSnapshot)
.where(BalanceSnapshot.provider == provider)
.where(BalanceSnapshot.error.is_(None))
.where(BalanceSnapshot.remaining.is_not(None))
.order_by(BalanceSnapshot.created_at.desc())
.limit(1)
)
snap = res.scalar_one_or_none()
if snap:
return snap
res = await db.execute(
select(BalanceSnapshot)
.where(BalanceSnapshot.provider == provider)
.order_by(BalanceSnapshot.created_at.desc())
.limit(1)
)
return res.scalar_one_or_none()
@router.get("", response_model=list[BalanceOut])
async def latest_balances(db: AsyncSession = Depends(get_db), _: User = Depends(require_readonly)):
"""Latest snapshot per provider."""
out: list[BalanceSnapshot] = []
for provider in ("openrouter", "deepseek"):
snap = await _latest_snapshot(db, provider)
if snap:
out.append(snap)
return out
@router.post("/refresh", response_model=list[BalanceOut])
async def refresh_balances(db: AsyncSession = Depends(get_db), _: User = Depends(require_support)):
await balance_service.poll_once()
return await latest_balances(db) # type: ignore[arg-type]