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>
55 lines
1.6 KiB
Python
55 lines
1.6 KiB
Python
"""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
|