"""Refinement prompt for the writing editor — natural language only. The model refines exactly ONE section of a document the user is writing. The rest of the document travels as prefix/suffix context so the section stays coherent with its surroundings, but the model regenerates ONLY the section — a large document is never re-emitted whole (FIM-style). The base texts (persona, rules, framings) are admin-editable: they come from `app/prompts/overrides.py::get_prompt`, which returns a DB override when one exists and the code default (`app/prompts/defaults.py`) otherwise. """ from app.llm.client import ChatMessage from app.prompts.overrides import get_prompt def render_refine_prompt( section: str, *, prefix: str, suffix: str, persona: str | None, hint: str | None, context: str | None = None, knowledge: list[str] | None = None, ) -> list[ChatMessage]: # A template may carry its own persona; otherwise the admin-editable default. system_parts = [persona.strip() if persona else get_prompt("refine_persona")] if hint: system_parts.append(f"What this section should convey: {hint}") if context: # Background from the chat this capture came from, so the refinement # is on-topic — but only as orientation, never a source of new facts. system_parts.append( f"Background (the conversation this document came from, for " f"orientation only — do not invent facts from it): {context}" ) system_parts.append(get_prompt("refine_rules")) # The document being edited leads the user turn (prefix/suffix/section); # the retrieved knowledge trails it, because it changes on every call and # keeping it last leaves the stable prompt prefix reusable between calls. user_parts: list[str] = [] if prefix.strip(): user_parts.append( f"Text before the section (context only, do not repeat it):\n{prefix}" ) if suffix.strip(): user_parts.append( f"Text after the section (context only, do not repeat it):\n{suffix}" ) user_parts.append(f"Refine only this section:\n{section}") if knowledge: # What the company has already documented elsewhere. It is grounding, # not source material: it keeps terminology and facts consistent and # lets the section point at related documents, but it must not be # copied in or become a way to add facts the section's notes do not # support. joined = "\n\n".join(knowledge) user_parts.append(f"{get_prompt('grounding_framing')}\n{joined}") return [ {"role": "system", "content": "\n\n".join(system_parts)}, {"role": "user", "content": "\n\n".join(user_parts)}, ] def render_topic_summary_prompt(transcript: str) -> list[ChatMessage]: """Condense a conversation into a short search topic (a few words).""" return [ {"role": "system", "content": get_prompt("topic_summary")}, {"role": "user", "content": f"Conversation:\n{transcript}"}, ] def render_title_prompt(content_md: str) -> list[ChatMessage]: """Suggest a concise document title from its written content.""" return [ {"role": "system", "content": get_prompt("title")}, {"role": "user", "content": f"Document:\n{content_md}"}, ]