Merge pull request 'feat: JSON status endpoints for briefing, memory, swarm (#49, #50)' (#101) from fix/api-consistency into main

This commit is contained in:
2026-03-14 19:24:15 -04:00
2 changed files with 158 additions and 0 deletions

View File

@@ -1,10 +1,12 @@
"""System-level dashboard routes (ledger, upgrades, etc.)."""
import logging
from pathlib import Path
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse, JSONResponse
from config import settings
from dashboard.templating import templates
logger = logging.getLogger(__name__)
@@ -147,3 +149,82 @@ async def api_notifications():
except Exception as exc:
logger.debug("System events fetch error: %s", exc)
return JSONResponse([])
@router.get("/api/briefing/status", response_class=JSONResponse)
async def api_briefing_status():
"""Return briefing status including pending approvals and last generated time."""
from timmy import approvals
from timmy.briefing import engine as briefing_engine
pending = approvals.list_pending()
pending_count = len(pending)
last_generated = None
try:
cached = briefing_engine.get_cached()
if cached:
last_generated = cached.generated_at.isoformat()
except Exception:
pass
return JSONResponse(
{
"status": "ok",
"pending_approvals": pending_count,
"last_generated": last_generated,
}
)
@router.get("/api/memory/status", response_class=JSONResponse)
async def api_memory_status():
"""Return memory database status including file info and indexed files count."""
from timmy.memory.vector_store import get_memory_stats
db_path = Path(settings.repo_root) / "data" / "memory.db"
db_exists = db_path.exists()
db_size = db_path.stat().st_size if db_exists else 0
try:
stats = get_memory_stats()
indexed_files = stats.get("total_entries", 0)
except Exception:
indexed_files = 0
return JSONResponse(
{
"status": "ok",
"db_exists": db_exists,
"db_size_bytes": db_size,
"indexed_files": indexed_files,
}
)
@router.get("/api/swarm/status", response_class=JSONResponse)
async def api_swarm_status():
"""Return swarm worker status and pending tasks count."""
from dashboard.routes.tasks import _get_db
pending_tasks = 0
try:
db = _get_db()
try:
row = db.execute(
"SELECT COUNT(*) as cnt FROM tasks WHERE status IN ('pending_approval','approved')"
).fetchone()
pending_tasks = row["cnt"] if row else 0
finally:
db.close()
except Exception:
pass
return JSONResponse(
{
"status": "ok",
"active_workers": 0,
"pending_tasks": pending_tasks,
"message": "Swarm monitoring endpoint",
}
)

View File

@@ -0,0 +1,77 @@
"""Tests for the API status endpoints.
Verifies /api/briefing/status, /api/memory/status, and /api/swarm/status
return valid JSON with expected keys.
"""
def test_api_briefing_status_returns_ok(client):
"""GET /api/briefing/status returns 200 with expected JSON structure."""
response = client.get("/api/briefing/status")
assert response.status_code == 200
data = response.json()
assert data["status"] == "ok"
assert "pending_approvals" in data
assert isinstance(data["pending_approvals"], int)
assert "last_generated" in data
# last_generated can be None or a string
assert data["last_generated"] is None or isinstance(data["last_generated"], str)
def test_api_memory_status_returns_ok(client):
"""GET /api/memory/status returns 200 with expected JSON structure."""
response = client.get("/api/memory/status")
assert response.status_code == 200
data = response.json()
assert data["status"] == "ok"
assert "db_exists" in data
assert isinstance(data["db_exists"], bool)
assert "db_size_bytes" in data
assert isinstance(data["db_size_bytes"], int)
assert data["db_size_bytes"] >= 0
assert "indexed_files" in data
assert isinstance(data["indexed_files"], int)
assert data["indexed_files"] >= 0
def test_api_swarm_status_returns_ok(client):
"""GET /api/swarm/status returns 200 with expected JSON structure."""
response = client.get("/api/swarm/status")
assert response.status_code == 200
data = response.json()
assert data["status"] == "ok"
assert "active_workers" in data
assert isinstance(data["active_workers"], int)
assert "pending_tasks" in data
assert isinstance(data["pending_tasks"], int)
assert data["pending_tasks"] >= 0
assert "message" in data
assert isinstance(data["message"], str)
assert data["message"] == "Swarm monitoring endpoint"
def test_api_swarm_status_reflects_pending_tasks(client):
"""GET /api/swarm/status reflects pending tasks from task queue."""
# First create a task
client.post("/api/tasks", json={"title": "Swarm status test task"})
# Now check swarm status
response = client.get("/api/swarm/status")
assert response.status_code == 200
data = response.json()
assert data["pending_tasks"] >= 1
def test_api_briefing_status_pending_approvals_count(client):
"""GET /api/briefing/status returns correct pending approvals count."""
response = client.get("/api/briefing/status")
assert response.status_code == 200
data = response.json()
assert "pending_approvals" in data
assert isinstance(data["pending_approvals"], int)
assert data["pending_approvals"] >= 0