Files
ProfessorNovaandClaude Opus 5 784b76baf7 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
2026-09-04 09:21:37 +02:00

56 lines
1.9 KiB
Python

"""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()