Mercurial
annotate mrjunejune/inference/public_knowledge.py @ 279:b3b547563ec7
Add Google connector service and agent wiki
Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 22:22:36 -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 } |