1
0

feat: add task queue with human-in-the-loop approval + work orders + UI bug fixes

Task Queue system:
- New /tasks page with three-column layout (Pending/Active/Completed)
- Full CRUD API at /api/tasks with approve/veto/modify/pause/cancel/retry
- SQLite persistence in task_queue table
- WebSocket live updates via ws_manager
- Create task modal with agent assignment and priority
- Auto-approve rules for low-risk tasks
- HTMX polling for real-time column updates
- HOME TASK buttons now link to task queue with agent pre-selected
- MARKET HIRE buttons link to task queue with agent pre-selected

Work Order system:
- External submission API for agents/users (POST /work-orders/submit)
- Risk scoring and configurable auto-execution thresholds
- Dashboard at /work-orders/queue with approve/reject/execute flow
- Integration with swarm task system for execution

UI & Dashboard bug fixes:
- EVENTS: add startup event so page is never empty
- LEDGER: fix empty filter params in URL
- MISSION CONTROL: LLM backend and model now read from /health
- MISSION CONTROL: agent count fallback to /swarm/agents
- SWARM: HTMX fallback loads initial data if WebSocket is slow
- MEMORY: add edit/delete buttons for personal facts
- UPGRADES: add empty state guidance with links
- BRIEFING: add regenerate button and POST /briefing/regenerate endpoint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Alexander Payne
2026-02-26 10:27:08 -05:00
parent 4e78f7102e
commit 5f9bbb8435
31 changed files with 3159 additions and 47 deletions

View File

@@ -3,8 +3,8 @@
from pathlib import Path
from typing import Optional
from fastapi import APIRouter, Form, Request
from fastapi.responses import HTMLResponse
from fastapi import APIRouter, Form, HTTPException, Request
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.templating import Jinja2Templates
from memory.vector_store import (
@@ -12,7 +12,10 @@ from memory.vector_store import (
search_memories,
get_memory_stats,
recall_personal_facts,
recall_personal_facts_with_ids,
store_personal_fact,
update_personal_fact,
delete_memory,
)
router = APIRouter(prefix="/memory", tags=["memory"])
@@ -37,7 +40,7 @@ async def memory_page(
)
stats = get_memory_stats()
facts = recall_personal_facts()[:10]
facts = recall_personal_facts_with_ids()[:10]
return templates.TemplateResponse(
request,
@@ -86,13 +89,32 @@ async def add_fact(
):
"""Add a personal fact to memory."""
store_personal_fact(fact, agent_id=agent_id)
# Return updated facts list
facts = recall_personal_facts()[:10]
facts = recall_personal_facts_with_ids()[:10]
return templates.TemplateResponse(
request,
"partials/memory_facts.html",
{
"facts": facts,
},
{"facts": facts},
)
@router.put("/fact/{fact_id}", response_class=JSONResponse)
async def edit_fact(fact_id: str, request: Request):
"""Update a personal fact."""
body = await request.json()
new_content = body.get("content", "").strip()
if not new_content:
raise HTTPException(400, "Content cannot be empty")
ok = update_personal_fact(fact_id, new_content)
if not ok:
raise HTTPException(404, "Fact not found")
return {"success": True, "id": fact_id, "content": new_content}
@router.delete("/fact/{fact_id}", response_class=JSONResponse)
async def delete_fact(fact_id: str):
"""Delete a personal fact."""
ok = delete_memory(fact_id)
if not ok:
raise HTTPException(404, "Fact not found")
return {"success": True, "id": fact_id}