Files
hive/core/framework/server/routes_prompts.py
T
Vincent Jiang 6e97191f21 feat: UI/UX improvements across BYOK, org chart, profiles, and prompt library
- BYOK: unified styling (remove purple, consistent grey headers), model selector opens settings modal directly, backend validates API keys before activation
- Org chart: queen profiles are now editable (name, title, about, skills, achievement) with changes persisted to YAML
- Avatars: upload profile pictures for queens and user with client-side compression, displayed across org chart, sidebar, chat, and header
- Colony deletion: await backend delete and re-fetch to prevent ghost colonies
- Prompt library: add pagination (24/page), custom prompt upload/delete with backend persistence
- Settings modal: performance cleanup (remove backdrop-blur, reduce transitions)
- Fix ensure_default_queens() overwriting user edits on every API call

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 14:21:18 -07:00

89 lines
2.8 KiB
Python

"""Custom user prompts — CRUD for user-uploaded prompts.
- GET /api/prompts — list all custom prompts
- POST /api/prompts — add a new custom prompt
- DELETE /api/prompts/{id} — delete a custom prompt
"""
import json
import logging
import time
from pathlib import Path
from aiohttp import web
from framework.config import HIVE_HOME
logger = logging.getLogger(__name__)
CUSTOM_PROMPTS_FILE = HIVE_HOME / "custom_prompts.json"
def _load_custom_prompts() -> list[dict]:
if not CUSTOM_PROMPTS_FILE.exists():
return []
try:
data = json.loads(CUSTOM_PROMPTS_FILE.read_text(encoding="utf-8"))
return data if isinstance(data, list) else []
except Exception:
return []
def _save_custom_prompts(prompts: list[dict]) -> None:
CUSTOM_PROMPTS_FILE.parent.mkdir(parents=True, exist_ok=True)
CUSTOM_PROMPTS_FILE.write_text(
json.dumps(prompts, indent=2, ensure_ascii=False) + "\n",
encoding="utf-8",
)
async def handle_list_prompts(request: web.Request) -> web.Response:
"""GET /api/prompts — list all custom prompts."""
return web.json_response({"prompts": _load_custom_prompts()})
async def handle_create_prompt(request: web.Request) -> web.Response:
"""POST /api/prompts — add a new custom prompt."""
try:
body = await request.json()
except Exception:
return web.json_response({"error": "Invalid JSON body"}, status=400)
title = (body.get("title") or "").strip()
category = (body.get("category") or "").strip()
content = (body.get("content") or "").strip()
if not title or not content:
return web.json_response({"error": "Title and content are required"}, status=400)
prompts = _load_custom_prompts()
new_prompt = {
"id": f"custom_{int(time.time() * 1000)}",
"title": title,
"category": category or "custom",
"content": content,
"custom": True,
}
prompts.append(new_prompt)
_save_custom_prompts(prompts)
logger.info("Custom prompt added: %s", title)
return web.json_response(new_prompt, status=201)
async def handle_delete_prompt(request: web.Request) -> web.Response:
"""DELETE /api/prompts/{prompt_id} — delete a custom prompt."""
prompt_id = request.match_info["prompt_id"]
prompts = _load_custom_prompts()
before = len(prompts)
prompts = [p for p in prompts if p.get("id") != prompt_id]
if len(prompts) == before:
return web.json_response({"error": "Prompt not found"}, status=404)
_save_custom_prompts(prompts)
return web.json_response({"deleted": prompt_id})
def register_routes(app: web.Application) -> None:
app.router.add_get("/api/prompts", handle_list_prompts)
app.router.add_post("/api/prompts", handle_create_prompt)
app.router.add_delete("/api/prompts/{prompt_id}", handle_delete_prompt)