forked from Rockachopa/Timmy-time-dashboard
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:
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user