Pablan, as it stands
Self-hosted knowledge management for SMEs: a split-screen Markdown editor whose sections an LLM refines while you write, and RAG question answering over the documents that result. FastAPI + Postgres/pgvector on the back, SvelteKit on the front, everything OpenAI-compatible and self-hostable. Squashed into a single commit; the development history stays local. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CA43ZJda8Rbp2hKXNy8f6b
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
"""The effective system prompts, as the process sees them.
|
||||
|
||||
Prompts default to code (`app/prompts/defaults.py`); an admin may override any
|
||||
of them in `prompt_settings`, applied without a restart. This mirrors the LLM
|
||||
settings override pattern, with two simplifications: the reset target is the
|
||||
code default (prompts have no `.env` layer), and there is no bootstrap — a
|
||||
missing row simply means "use the default".
|
||||
|
||||
`get_prompt` is called while rendering a prompt, so it reads a module-level
|
||||
cache rather than awaiting a query. The cache is filled at startup and refreshed
|
||||
on every admin write. Single-process by design (`--workers 1`); a multi-worker
|
||||
deployment would need a notification channel.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models import PromptSetting
|
||||
from app.prompts.defaults import DEFAULTS
|
||||
|
||||
logger = logging.getLogger("pablan.prompts")
|
||||
|
||||
# Only holds the keys an admin has actually overridden.
|
||||
_config: dict[str, str] = {}
|
||||
|
||||
|
||||
async def load_config(db: AsyncSession) -> None:
|
||||
"""Re-read every override row into the cache. Call at startup and after any
|
||||
admin write."""
|
||||
rows = (await db.execute(select(PromptSetting))).scalars().all()
|
||||
_config.clear()
|
||||
_config.update({row.key: row.content for row in rows if row.key in DEFAULTS})
|
||||
logger.info(
|
||||
"prompt settings loaded",
|
||||
extra={"event": "prompt_settings_loaded", "overridden": sorted(_config)},
|
||||
)
|
||||
|
||||
|
||||
def get_prompt(key: str) -> str:
|
||||
"""The effective prompt: an admin override if present, else the code default.
|
||||
|
||||
`key` must be a known prompt (a `KeyError` here is a programming error, not
|
||||
user input)."""
|
||||
return _config.get(key) or DEFAULTS[key]
|
||||
|
||||
|
||||
def is_overridden(key: str) -> bool:
|
||||
return key in _config
|
||||
|
||||
|
||||
def clear() -> None:
|
||||
"""Drop the cache — used by tests between cases."""
|
||||
_config.clear()
|
||||
Reference in New Issue
Block a user