feat(dashboard): live-editable bot prompt via popup (view/edit/save)
Adds a persisted, runtime-editable system prompt. The brain reads the persona on every turn (prompt_store.get_persona), so a dashboard edit applies to the next reply with no restart; blank clears the override back to the built-in PERSONA. New endpoints GET/POST /api/prompt, and a reusable modal popup (뒤로가기 + 수정/저장) that later white/blacklist features will share. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
54
wsai/prompt_store.py
Normal file
54
wsai/prompt_store.py
Normal file
@@ -0,0 +1,54 @@
|
||||
"""Persisted, live-editable bot persona (the brain's system prompt).
|
||||
|
||||
The dashboard lets the user view and edit the bot's system prompt at runtime.
|
||||
The brain reads the current persona on every turn, so an edit takes effect on
|
||||
the next reply with no restart. The text is persisted to disk so it survives a
|
||||
restart; when no override file exists the caller's default
|
||||
(``ClaudeBrain.PERSONA``) is used.
|
||||
|
||||
Path: ``$WSAI_PROMPT_PATH`` or ``~/.config/wsai/persona.txt`` (disk, never a
|
||||
RAM-backed tmpfs).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
_LOCK = threading.Lock()
|
||||
|
||||
|
||||
def _path() -> Path:
|
||||
override = os.environ.get("WSAI_PROMPT_PATH")
|
||||
return Path(override) if override else (Path.home() / ".config" / "wsai" / "persona.txt")
|
||||
|
||||
|
||||
def get_persona(default: str) -> str:
|
||||
"""Return the saved persona override, or ``default`` if none is set."""
|
||||
try:
|
||||
with _LOCK:
|
||||
text = _path().read_text(encoding="utf-8")
|
||||
except OSError:
|
||||
return default
|
||||
return text if text.strip() else default
|
||||
|
||||
|
||||
def set_persona(text: str) -> None:
|
||||
"""Persist a new persona. Blank text clears the override (reverts to default)."""
|
||||
p = _path()
|
||||
with _LOCK:
|
||||
p.parent.mkdir(parents=True, exist_ok=True)
|
||||
if text and text.strip():
|
||||
p.write_text(text, encoding="utf-8")
|
||||
else:
|
||||
p.unlink(missing_ok=True)
|
||||
|
||||
|
||||
def is_overridden() -> bool:
|
||||
"""True when a non-empty override file is in effect."""
|
||||
try:
|
||||
with _LOCK:
|
||||
return bool(_path().read_text(encoding="utf-8").strip())
|
||||
except OSError:
|
||||
return False
|
||||
Reference in New Issue
Block a user