"""Structured LLM prompts for document enrichment. Provides the system prompt that instructs the LLM to return structured JSON with entities, categories, tags, and action items. """ ENRICHMENT_SYSTEM_PROMPT = """\ You are a knowledge management assistant. Analyze the following text extracted \ from a document and return structured metadata as JSON. Return a JSON object with exactly these fields: - "title": A concise, descriptive title for this note (max 80 chars) - "category": One of "meeting", "project", "decision", "inbox" - "tags": List of relevant topic tags (lowercase, no # prefix) - "entities": List of detected entities, each with: - "type": One of "person", "project", "date", "action_item" - "value": The extracted text value - "confidence": Float between 0.0 and 1.0 indicating detection confidence - "position": Approximate character offset where entity appears (integer or null) - "action_items": List of action items, each with: - "description": What needs to be done - "assignee": Person responsible (string or null) - "deadline": Date in ISO 8601 format, e.g. "2024-03-22" (string or null) - "summary": A 1-2 sentence summary of the document (string or null) Rules: - Be precise with entity detection. Only mark entities you are confident about. - For people, use their full name as the value. - For projects, use the project name as commonly referenced. - For dates, use ISO 8601 format (YYYY-MM-DD) as the value. - Assign confidence scores honestly: 0.9+ for clearly stated entities, 0.7-0.9 for \ likely entities, below 0.7 for uncertain ones. - Category "meeting" for meeting notes, agendas, minutes. - Category "project" for project-specific documentation. - Category "decision" for recorded decisions, ADRs. - Category "inbox" for anything that doesn't clearly fit the above. Context: This is a personal knowledge base for a project manager working across \ multiple business projects.{context_section} """ STRICT_RETRY_PROMPT = """\ Your previous response was not valid JSON. Please respond with ONLY a valid JSON \ object matching the schema described in the system prompt. No markdown, no code fences, \ no explanation — just the raw JSON object. """ def build_system_prompt( known_projects: list[str] | None = None, known_people: list[str] | None = None, ) -> str: """Build the system prompt with optional context about known entities. Args: known_projects: List of known project names for context. known_people: List of known people names for context. Returns: Complete system prompt string. """ context_parts: list[str] = [] if known_projects: projects_str = ", ".join(known_projects) context_parts.append(f"Known projects: {projects_str}.") if known_people: people_str = ", ".join(known_people) context_parts.append(f"Known people: {people_str}.") if context_parts: context_section = "\n" + " ".join(context_parts) else: context_section = "" return ENRICHMENT_SYSTEM_PROMPT.format(context_section=context_section) def build_user_prompt(extracted_text: str) -> str: """Build the user message containing the extracted document text. Args: extracted_text: The raw text extracted from the document. Returns: User prompt string. """ return f"Analyze this document and return the structured JSON:\n\n{extracted_text}"