Mercurial
annotate mrjunejune/inference/public_knowledge.py @ 273:e02e2036ef84 default tip
add Layer 2 JRPG component system
Add reusable content and window modals, an isolated component sandbox, shared cyberpunk scroll areas, production-safe cache freshness, and server-rendered JRPG panel state.
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sat, 08 Aug 2026 02:08:08 -0700 |
| parents | 056790c4fb0d |
| children |
| rev | line source |
|---|---|
|
265
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
1 """ |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
2 Stdlib-only deterministic loader and compiler for the assistant knowledge base. |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
3 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
4 Loads prompt files from mrjunejune/assistant/ and compiles them with verified |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
5 public facts into a hashed, deterministic system prompt. Fails closed on any |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
6 malformed input. |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
7 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
8 Public API: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
9 compile_prompt(profile, assistant_dir=None) -> dict |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
10 Returns {"content": str, "version": int, "hash": str}. |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
11 Raises ValueError for unknown profile or any validation failure. |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
12 """ |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
13 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
14 import hashlib |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
15 import json |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
16 import pathlib |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
17 import re |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
18 from typing import Optional |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
19 from urllib.parse import urlsplit |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
20 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
21 # --------------------------------------------------------------------------- |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
22 # Constants |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
23 # --------------------------------------------------------------------------- |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
24 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
25 _KNOWN_PROFILES: frozenset = frozenset({"public_visitor", "invited_friend", "june_admin"}) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
26 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
27 _REQUIRED_TOP_KEYS: frozenset = frozenset({"version", "facts"}) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
28 _REQUIRED_FACT_KEYS: frozenset = frozenset( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
29 {"id", "topic", "text", "sourceLabel", "sourceUrl", "visibility", "status"} |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
30 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
31 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
32 _EXPECTED_VERSION: int = 1 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
33 _MAX_PROMPT_FILE_BYTES: int = 8192 # 8 KB per prompt file |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
34 _MAX_COMPILED_BYTES: int = 16384 # 16 KB total compiled ceiling |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
35 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
36 _MAX_ID_LEN: int = 64 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
37 _MAX_TOPIC_LEN: int = 64 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
38 _MAX_TEXT_LEN: int = 500 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
39 _MAX_SOURCE_LABEL_LEN: int = 128 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
40 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
41 _SLUG_RE = re.compile(r"^[a-z0-9]([a-z0-9-]*[a-z0-9])?$") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
42 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
43 # Contact patterns: email and North-American-style phone numbers |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
44 _CONTACT_PATTERNS: list = [ |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
45 re.compile(r"[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}"), |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
46 re.compile(r"(\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]\d{3}[-.\s]\d{4}"), |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
47 ] |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
48 _SECRET_VALUE_PATTERNS: list = [ |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
49 re.compile( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
50 r"\b(password|passwd|secret|token|api[_\-]?key|private[_\-]?key)" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
51 r"\s*[:=]\s*\S+", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
52 re.IGNORECASE, |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
53 ), |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
54 re.compile(r"-----BEGIN [A-Z ]*PRIVATE KEY-----"), |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
55 ] |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
56 _CONTROL_PATTERN = re.compile(r"[\x00-\x1f\x7f]") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
57 _PROMPT_CONTROL_PATTERN = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
58 _RESERVED_CORPUS_PATTERNS: tuple[str, ...] = ( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
59 "--- knowledge corpus ---", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
60 "system:", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
61 "assistant:", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
62 "user:", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
63 "<system", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
64 "ignore previous instructions", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
65 "ignore prior instructions", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
66 "follow these instructions", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
67 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
68 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
69 # Credential / secret keyword patterns |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
70 _SECRET_PATTERNS: list = [ |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
71 re.compile( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
72 r"\b(password|passwd|secret|token|api[_\-]?key|private[_\-]?key)\b", |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
73 re.IGNORECASE, |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
74 ), |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
75 ] |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
76 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
77 _FACTS_DELIMITER: str = "--- KNOWLEDGE CORPUS ---" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
78 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
79 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
80 # --------------------------------------------------------------------------- |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
81 # Internal helpers |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
82 # --------------------------------------------------------------------------- |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
83 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
84 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
85 def _default_assistant_dir() -> pathlib.Path: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
86 return pathlib.Path(__file__).parent.parent / "assistant" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
87 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
88 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
89 def _validate_source_url(url: str, fact_id: str) -> None: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
90 if not isinstance(url, str) or not url: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
91 raise ValueError(f"Fact '{fact_id}': sourceUrl is empty") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
92 if _CONTROL_PATTERN.search(url) or "\\" in url: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
93 raise ValueError(f"Fact '{fact_id}': sourceUrl contains unsafe characters") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
94 if url.startswith("/"): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
95 if url.startswith("//") or any( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
96 segment in (".", "..") for segment in url.split("/") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
97 ): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
98 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
99 f"Fact '{fact_id}': sourceUrl must be a safe local path" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
100 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
101 return |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
102 parsed = urlsplit(url) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
103 if ( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
104 parsed.scheme != "https" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
105 or not parsed.hostname |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
106 or parsed.username is not None |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
107 or parsed.password is not None |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
108 ): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
109 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
110 f"Fact '{fact_id}': sourceUrl must be HTTPS or a safe local path" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
111 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
112 try: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
113 parsed.port |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
114 except ValueError as exc: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
115 raise ValueError(f"Fact '{fact_id}': sourceUrl has an invalid port") from exc |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
116 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
117 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
118 def _check_no_contact_or_secret(text: str, fact_id: str, field: str) -> None: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
119 for pat in _CONTACT_PATTERNS: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
120 if pat.search(text): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
121 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
122 f"Fact '{fact_id}': {field} contains contact data (email or phone number)" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
123 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
124 for pat in _SECRET_PATTERNS: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
125 if pat.search(text): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
126 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
127 f"Fact '{fact_id}': {field} contains a secret or credential pattern" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
128 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
129 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
130 def _validate_corpus_text(text: str, fact_id: str, field: str) -> None: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
131 if _CONTROL_PATTERN.search(text): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
132 raise ValueError(f"Fact '{fact_id}': {field} contains control characters") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
133 lowered = text.lower() |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
134 for reserved in _RESERVED_CORPUS_PATTERNS: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
135 if reserved in lowered: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
136 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
137 f"Fact '{fact_id}': {field} contains reserved prompt instructions" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
138 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
139 _check_no_contact_or_secret(text, fact_id, field) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
140 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
141 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
142 def _load_and_validate_facts(assistant_dir: pathlib.Path) -> list: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
143 facts_path = assistant_dir / "knowledge" / "public_facts.json" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
144 try: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
145 raw = facts_path.read_text(encoding="utf-8") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
146 except OSError as exc: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
147 raise ValueError(f"Cannot read facts file: {exc}") from exc |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
148 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
149 try: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
150 data = json.loads(raw) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
151 except json.JSONDecodeError as exc: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
152 raise ValueError(f"Facts file is not valid JSON: {exc}") from exc |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
153 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
154 if not isinstance(data, dict): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
155 raise ValueError("Facts file top level must be a JSON object") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
156 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
157 extra_keys = set(data.keys()) - _REQUIRED_TOP_KEYS |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
158 missing_keys = _REQUIRED_TOP_KEYS - set(data.keys()) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
159 if extra_keys or missing_keys: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
160 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
161 f"Facts file top-level keys must be exactly {sorted(_REQUIRED_TOP_KEYS)}; " |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
162 f"extra={sorted(extra_keys)}, missing={sorted(missing_keys)}" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
163 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
164 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
165 if ( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
166 not isinstance(data["version"], int) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
167 or isinstance(data["version"], bool) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
168 or data["version"] != _EXPECTED_VERSION |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
169 ): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
170 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
171 f"Facts file version must be {_EXPECTED_VERSION}; got {data['version']!r}" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
172 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
173 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
174 raw_facts = data["facts"] |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
175 if not isinstance(raw_facts, list) or len(raw_facts) == 0: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
176 raise ValueError("Facts file 'facts' must be a non-empty list") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
177 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
178 seen_ids: set = set() |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
179 validated: list = [] |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
180 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
181 for i, fact in enumerate(raw_facts): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
182 if not isinstance(fact, dict): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
183 raise ValueError(f"Fact at index {i} must be a JSON object") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
184 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
185 extra = set(fact.keys()) - _REQUIRED_FACT_KEYS |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
186 missing = _REQUIRED_FACT_KEYS - set(fact.keys()) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
187 if extra or missing: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
188 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
189 f"Fact at index {i}: keys must be exactly " |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
190 f"{sorted(_REQUIRED_FACT_KEYS)}; " |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
191 f"extra={sorted(extra)}, missing={sorted(missing)}" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
192 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
193 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
194 fid = fact["id"] |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
195 if not isinstance(fid, str) or not fid: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
196 raise ValueError(f"Fact at index {i}: 'id' must be a non-empty string") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
197 if len(fid) > _MAX_ID_LEN: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
198 raise ValueError(f"Fact '{fid}': id exceeds {_MAX_ID_LEN} characters") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
199 if not _SLUG_RE.match(fid): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
200 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
201 f"Fact '{fid}': id must be lowercase alphanumeric with hyphens" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
202 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
203 if fid in seen_ids: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
204 raise ValueError(f"Duplicate fact id: {fid!r}") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
205 seen_ids.add(fid) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
206 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
207 topic = fact["topic"] |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
208 if not isinstance(topic, str) or not topic: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
209 raise ValueError(f"Fact '{fid}': 'topic' must be a non-empty string") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
210 if len(topic) > _MAX_TOPIC_LEN: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
211 raise ValueError(f"Fact '{fid}': topic exceeds {_MAX_TOPIC_LEN} characters") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
212 if not _SLUG_RE.match(topic): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
213 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
214 f"Fact '{fid}': topic must be lowercase alphanumeric with hyphens" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
215 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
216 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
217 text = fact["text"] |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
218 if not isinstance(text, str) or len(text) < 10: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
219 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
220 f"Fact '{fid}': 'text' must be a string of at least 10 characters" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
221 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
222 if len(text) > _MAX_TEXT_LEN: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
223 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
224 f"Fact '{fid}': text exceeds {_MAX_TEXT_LEN} characters" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
225 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
226 _validate_corpus_text(text, fid, "text") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
227 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
228 source_label = fact["sourceLabel"] |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
229 if not isinstance(source_label, str) or not source_label: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
230 raise ValueError(f"Fact '{fid}': 'sourceLabel' must be a non-empty string") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
231 if len(source_label) > _MAX_SOURCE_LABEL_LEN: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
232 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
233 f"Fact '{fid}': sourceLabel exceeds {_MAX_SOURCE_LABEL_LEN} characters" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
234 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
235 _validate_corpus_text(source_label, fid, "sourceLabel") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
236 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
237 _validate_source_url(fact["sourceUrl"], fid) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
238 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
239 if not isinstance(fact["visibility"], str) or fact["visibility"] != "public": |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
240 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
241 f"Fact '{fid}': visibility must be 'public'; got {fact['visibility']!r}" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
242 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
243 if not isinstance(fact["status"], str) or fact["status"] != "verified": |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
244 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
245 f"Fact '{fid}': status must be 'verified'; got {fact['status']!r}" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
246 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
247 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
248 validated.append(fact) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
249 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
250 validated.sort(key=lambda f: f["id"]) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
251 return validated |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
252 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
253 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
254 def _load_prompt_file(path: pathlib.Path) -> str: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
255 try: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
256 raw_bytes = path.read_bytes() |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
257 except OSError as exc: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
258 raise ValueError(f"Cannot read prompt file {path.name}: {exc}") from exc |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
259 if len(raw_bytes) > _MAX_PROMPT_FILE_BYTES: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
260 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
261 f"Prompt file {path.name} exceeds {_MAX_PROMPT_FILE_BYTES} bytes " |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
262 f"(got {len(raw_bytes)})" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
263 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
264 try: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
265 content = raw_bytes.decode("utf-8") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
266 except UnicodeDecodeError as exc: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
267 raise ValueError(f"Prompt file {path.name} is not valid UTF-8") from exc |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
268 if _PROMPT_CONTROL_PATTERN.search(content): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
269 raise ValueError(f"Prompt file {path.name} contains control characters") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
270 for pattern in _CONTACT_PATTERNS + _SECRET_VALUE_PATTERNS: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
271 if pattern.search(content): |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
272 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
273 f"Prompt file {path.name} contains contact data or a secret value" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
274 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
275 return content |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
276 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
277 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
278 def _format_facts(facts: list) -> str: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
279 lines: list = [] |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
280 for fact in facts: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
281 lines.append( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
282 json.dumps( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
283 { |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
284 "fact": fact["text"], |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
285 "id": fact["id"], |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
286 "sourceLabel": fact["sourceLabel"], |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
287 "sourceUrl": fact["sourceUrl"], |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
288 "topic": fact["topic"], |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
289 }, |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
290 ensure_ascii=False, |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
291 separators=(",", ":"), |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
292 sort_keys=True, |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
293 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
294 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
295 return "\n".join(lines) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
296 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
297 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
298 # --------------------------------------------------------------------------- |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
299 # Public API |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
300 # --------------------------------------------------------------------------- |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
301 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
302 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
303 def compile_prompt( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
304 profile: str, |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
305 assistant_dir: Optional[pathlib.Path] = None, |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
306 ) -> dict: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
307 """ |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
308 Compile a deterministic system prompt for *profile*. |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
309 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
310 Parameters |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
311 ---------- |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
312 profile: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
313 One of ``"public_visitor"``, ``"invited_friend"``, or ``"june_admin"``. |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
314 assistant_dir: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
315 Path to the ``mrjunejune/assistant/`` directory. Defaults to the |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
316 sibling of the ``inference/`` package at runtime. |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
317 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
318 Returns |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
319 ------- |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
320 dict with keys: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
321 - ``"content"`` (str): compiled prompt text |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
322 - ``"version"`` (int): schema version (always 1) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
323 - ``"hash"`` (str): lowercase hex SHA-256 of ``content`` encoded UTF-8 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
324 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
325 Raises |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
326 ------ |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
327 ValueError |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
328 On unknown profile, malformed files, validation failures, or size |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
329 limit exceeded. |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
330 """ |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
331 if profile not in _KNOWN_PROFILES: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
332 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
333 f"Unknown profile {profile!r}; " |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
334 f"known profiles: {sorted(_KNOWN_PROFILES)}" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
335 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
336 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
337 base = pathlib.Path(assistant_dir) if assistant_dir is not None else _default_assistant_dir() |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
338 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
339 common = _load_prompt_file(base / "common.md") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
340 profile_section = _load_prompt_file(base / f"{profile}.md") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
341 facts = _load_and_validate_facts(base) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
342 facts_block = _format_facts(facts) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
343 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
344 content = ( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
345 common.rstrip() |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
346 + "\n\n" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
347 + profile_section.rstrip() |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
348 + "\n\n" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
349 + _FACTS_DELIMITER |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
350 + "\n\n" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
351 + facts_block |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
352 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
353 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
354 encoded = content.encode("utf-8") |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
355 if len(encoded) > _MAX_COMPILED_BYTES: |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
356 raise ValueError( |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
357 f"Compiled prompt exceeds {_MAX_COMPILED_BYTES} bytes " |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
358 f"(got {len(encoded)})" |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
359 ) |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
360 |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
361 return { |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
362 "content": content, |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
363 "version": _EXPECTED_VERSION, |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
364 "hash": hashlib.sha256(encoded).hexdigest(), |
|
056790c4fb0d
add role-aware Epi assistant prompts
MrJuneJune <me@mrjunejune.com>
parents:
diff
changeset
|
365 } |