Ship War Room UX, CEO inbox, mobile chat, and Agents NAS workspace.
Make A2A togglable, keep reply context while reading, route agent data to //10.4.7.11/share/Agents, and polish themes plus export-intel sync cancel.
This commit is contained in:
@@ -21,9 +21,9 @@ AGENT_STATUSES = [
|
||||
|
||||
@router.get("")
|
||||
async def agents_page(request: Request):
|
||||
active_tab = request.query_params.get("tab", "souls")
|
||||
active_tab = request.query_params.get("tab", "warroom")
|
||||
if active_tab not in {"souls", "mesh", "terminals", "approvals", "warroom"}:
|
||||
active_tab = "souls"
|
||||
active_tab = "warroom"
|
||||
events: list = []
|
||||
try:
|
||||
events = fetch_all(
|
||||
|
||||
@@ -551,6 +551,7 @@ def api_execute_approved_request(request_id: int, body: ExecuteBody) -> dict[str
|
||||
class WarroomMessageBody(BaseModel):
|
||||
content: str = Field("", max_length=8000)
|
||||
attachments: list[dict] = Field(default_factory=list)
|
||||
reply_to_id: Optional[int] = None
|
||||
|
||||
|
||||
@router.get("/warroom/rooms")
|
||||
@@ -575,9 +576,12 @@ async def warroom_list_messages(room_id: int, limit: int = 100, after_id: int |
|
||||
from app.services import agent_chat
|
||||
|
||||
agent_chat.ensure_warroom()
|
||||
room = agent_chat.get_room(room_id)
|
||||
if not room:
|
||||
raise HTTPException(404, "Room niet gevonden")
|
||||
items = agent_chat.list_messages(room_id, limit=min(limit, 300), after_id=after_id)
|
||||
deleted_ids = agent_chat.list_deleted_ids(room_id) if after_id else []
|
||||
return {"ok": True, "items": items, "deleted_ids": deleted_ids}
|
||||
return {"ok": True, "room": room, "items": items, "deleted_ids": deleted_ids}
|
||||
|
||||
|
||||
@router.post("/warroom/rooms/{room_id}/messages")
|
||||
@@ -592,6 +596,7 @@ async def warroom_post_message(request: Request, room_id: int, body: WarroomMess
|
||||
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,
|
||||
reply_to_id=body.reply_to_id,
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(400, str(exc)) from exc
|
||||
@@ -615,6 +620,7 @@ async def warroom_post_message_stream(request: Request, room_id: int, body: Warr
|
||||
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,
|
||||
reply_to_id=body.reply_to_id,
|
||||
):
|
||||
yield f"data: {json.dumps(ev, default=str)}\n\n"
|
||||
except ValueError as exc:
|
||||
@@ -715,6 +721,46 @@ async def warroom_continue(request: Request, room_id: int, turns: int = 2):
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@router.get("/warroom/ceo-inbox")
|
||||
async def warroom_ceo_inbox(unread: bool = False, limit: int = 50) -> dict[str, Any]:
|
||||
"""Direct messages from agents to CEO (@aissa)."""
|
||||
from app.services import agent_chat
|
||||
|
||||
items = agent_chat.list_ceo_inbox(unread_only=unread, limit=min(limit, 100))
|
||||
return {
|
||||
"ok": True,
|
||||
"items": items,
|
||||
"unread": agent_chat.ceo_inbox_unread_count(),
|
||||
}
|
||||
|
||||
|
||||
class CeoInboxReadBody(BaseModel):
|
||||
ids: Optional[list[int]] = None
|
||||
all: bool = False
|
||||
|
||||
|
||||
@router.post("/warroom/ceo-inbox/read")
|
||||
async def warroom_ceo_inbox_read(body: CeoInboxReadBody) -> dict[str, Any]:
|
||||
from app.services import agent_chat
|
||||
|
||||
n = agent_chat.mark_ceo_inbox_read(body.ids, all_unread=bool(body.all))
|
||||
return {"ok": True, "marked": n, "unread": agent_chat.ceo_inbox_unread_count()}
|
||||
|
||||
|
||||
@router.delete("/warroom/rooms/{room_id}/messages")
|
||||
async def warroom_clear_messages(room_id: int) -> dict[str, Any]:
|
||||
"""Soft-delete all messages in a War Room / DM."""
|
||||
from app.services import agent_chat
|
||||
|
||||
room = agent_chat.get_room(room_id)
|
||||
if not room:
|
||||
raise HTTPException(404, "Room niet gevonden")
|
||||
n = agent_chat.clear_messages(room_id)
|
||||
return {"ok": True, "cleared": n}
|
||||
|
||||
|
||||
@router.delete("/warroom/rooms/{room_id}/messages/{message_id}")
|
||||
async def warroom_delete_message(room_id: int, message_id: int) -> dict[str, Any]:
|
||||
"""Soft-delete a War Room message."""
|
||||
|
||||
@@ -305,6 +305,11 @@ async def api_sync_places(request: Request):
|
||||
return r.json()
|
||||
|
||||
|
||||
|
||||
@router.post("/api/export-intel/sync/cancel")
|
||||
async def api_sync_cancel():
|
||||
return await _proxy("POST", "/sync/cancel")
|
||||
|
||||
@router.get("/api/export-intel/sync/status")
|
||||
async def api_sync_status():
|
||||
return await _proxy("GET", "/sync/status")
|
||||
|
||||
Reference in New Issue
Block a user