SysOps: approved_backup — 2026-08-16 11:01 UTC

This commit is contained in:
sysops
2026-08-16 11:01:58 +00:00
parent 22a17ed048
commit 1dd607b060
46 changed files with 3734 additions and 147 deletions
+119 -1
View File
@@ -5,7 +5,7 @@ import asyncio
import json
from typing import Any, Optional
from fastapi import APIRouter, HTTPException
from fastapi import File, UploadFile, APIRouter, HTTPException, Request
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
@@ -545,3 +545,121 @@ def api_execute_approved_request(request_id: int, body: ExecuteBody) -> dict[str
except Exception as exc:
raise HTTPException(status_code=500, detail=str(exc)) from exc
return {"ok": True, "request": req}
# --- War Room chat ---
class WarroomMessageBody(BaseModel):
content: str = Field("", max_length=8000)
attachments: list[dict] = Field(default_factory=list)
@router.get("/warroom/rooms")
async def warroom_list_rooms() -> dict[str, Any]:
from app.services import agent_chat
agent_chat.ensure_warroom()
return {"items": agent_chat.list_rooms()}
@router.post("/warroom/rooms/dm/{agent_key}")
async def warroom_open_dm(agent_key: str) -> dict[str, Any]:
from app.services import agent_chat
try:
room = agent_chat.get_or_create_dm(agent_key)
except ValueError as exc:
raise HTTPException(404, str(exc)) from exc
return {"room": room}
@router.get("/warroom/rooms/{room_id}/messages")
async def warroom_list_messages(room_id: int, limit: int = 100, after_id: int | None = None) -> dict[str, Any]:
from app.services import agent_chat
room = agent_chat.get_room(room_id)
if not room:
raise HTTPException(404, "Room niet gevonden")
return {"room": room, "items": agent_chat.list_messages(room_id, limit=min(limit, 200), after_id=after_id)}
@router.post("/warroom/rooms/{room_id}/messages")
async def warroom_post_message(request: Request, room_id: int, body: WarroomMessageBody) -> dict[str, Any]:
from app.services import agent_chat
user = getattr(request.state, "user", None) or {}
try:
result = await agent_chat.post_user_message(
room_id,
body.content,
username=(user.get("username") if isinstance(user, dict) else None),
role=(user.get("role") if isinstance(user, dict) else None),
sender_avatar_url=(user.get("avatar_url") if isinstance(user, dict) else None),
attachments=body.attachments,
)
except ValueError as exc:
raise HTTPException(400, str(exc)) from exc
return result
@router.post("/warroom/rooms/{room_id}/messages/stream")
async def warroom_post_message_stream(request: Request, room_id: int, body: WarroomMessageBody):
"""SSE stream: user → typing tokens → agent message(s) → done."""
import json
from app.services import agent_chat
user = getattr(request.state, "user", None) or {}
async def gen():
try:
async for ev in agent_chat.post_user_message_stream(
room_id,
body.content,
username=(user.get("username") if isinstance(user, dict) else None),
role=(user.get("role") if isinstance(user, dict) else None),
sender_avatar_url=(user.get("avatar_url") if isinstance(user, dict) else None),
attachments=body.attachments,
):
yield f"data: {json.dumps(ev, default=str)}\n\n"
except ValueError as exc:
yield f"data: {json.dumps({'event': 'error', 'detail': str(exc)})}\n\n"
except Exception as exc:
yield f"data: {json.dumps({'event': 'error', 'detail': str(exc)})}\n\n"
return StreamingResponse(
gen(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"X-Accel-Buffering": "no",
},
)
@router.post("/warroom/upload")
async def warroom_upload(file: UploadFile = File(...)) -> dict[str, Any]:
"""Upload a file to share in War Room (images/docs)."""
from pathlib import Path as P
import uuid
import re
raw_name = (file.filename or "upload.bin").strip()
safe = re.sub(r"[^a-zA-Z0-9._-]+", "_", raw_name)[:120] or "upload.bin"
ext = P(safe).suffix.lower()
allowed = {
".png", ".jpg", ".jpeg", ".gif", ".webp", ".pdf", ".txt", ".csv",
".xlsx", ".xls", ".doc", ".docx", ".zip", ".json", ".md",
}
if ext not in allowed:
raise HTTPException(400, f"Bestandstype niet toegestaan: {ext or '(geen)'}")
data = await file.read()
if len(data) > 12 * 1024 * 1024:
raise HTTPException(400, "Max 12MB per bestand")
dest_dir = P(__file__).resolve().parent.parent.parent / "static" / "uploads" / "warroom"
dest_dir.mkdir(parents=True, exist_ok=True)
fname = f"{uuid.uuid4().hex[:12]}_{safe}"
(dest_dir / fname).write_bytes(data)
url = f"/static/uploads/warroom/{fname}"
return {
"ok": True,
"url": url,
"name": raw_name[:180],
"mime": file.content_type or "application/octet-stream",
"size": len(data),
}