|
1 | | -ORGANIZER_SYSTEM = """You are an information-extraction engine for a personal knowledge base. |
| 1 | +ORGANIZER_SYSTEM = """You are Gray Box's Organizer. |
2 | 2 |
|
3 | | -You read one raw note at a time and extract structured facts from it. |
| 3 | +Your job is to convert one raw note into structured knowledge. |
4 | 4 |
|
5 | | -You never invent information that is not stated or clearly implied in the note. |
| 5 | +Extract SALIENT entities with HIGH recall while remaining completely faithful to the note. |
| 6 | +Never invent facts. |
| 7 | +Never return all-empty arrays for a non-empty note; if the note is vague, fall back to extracting a "topic" entity capturing the note's subject. |
| 8 | +When uncertain about an entity's type, prefer "topic" rather than omitting it. |
6 | 9 |
|
7 | | -You respond with STRICT JSON only: |
8 | | -no markdown fences, no commentary, no trailing text before or after the JSON object. |
| 10 | +Return STRICT JSON only. |
| 11 | +Do not output markdown. |
| 12 | +Do not output explanations. |
| 13 | +Do not output anything except one JSON object. |
9 | 14 | """ |
10 | 15 |
|
11 | 16 | ORGANIZER_PROMPT_TMPL = """Extract structured knowledge from the note below. |
12 | 17 |
|
13 | | -Your job is to keep the knowledge base synchronized with reality. |
| 18 | +YOUR JOB: Convert ONE raw note into structured knowledge. You MUST always |
| 19 | +return at least one item for any non-empty note. If the note is short, |
| 20 | +vague, or contains no clearly-named subject, extract a "topic" entity |
| 21 | +whose name is the note's central subject and whose summary is the note |
| 22 | +itself (lightly cleaned). Never return all-empty arrays for a non-empty note. |
| 23 | +
|
| 24 | +PRECISION vs RECALL: |
| 25 | +- Extract every SALIENT item the note is actually about (HIGH recall). |
| 26 | +- Do NOT extract peripheral mentions: words that merely appear in the |
| 27 | + note but are not the subject of any factual statement. |
| 28 | +- A noun is salient only if the note says something ABOUT it |
| 29 | + (a fact, a status, an action, a relationship, an opinion). |
| 30 | +- Verbs, adjectives, dates, and time expressions are NOT entities by themselves. |
| 31 | +- "Clearly implied" means a reasonable reader would name the same thing; |
| 32 | + it does NOT mean "this word could plausibly be an entity." |
| 33 | +
|
| 34 | +WHEN UNCERTAIN about an entity's type, prefer "topic" over omitting it. |
| 35 | +A vague note about "the meeting" with no other detail should still yield |
| 36 | +a topic entity named after the meeting subject. |
| 37 | +
|
| 38 | +FEW-SHOT EXAMPLES: |
| 39 | +
|
| 40 | +Note: "Standup tomorrow at 9am in room 4." |
| 41 | +Output: |
| 42 | +{{ |
| 43 | + "entities": [], |
| 44 | + "relations": [], |
| 45 | + "tasks": [], |
| 46 | + "actions": [], |
| 47 | + "decisions": [], |
| 48 | + "meetings": [], |
| 49 | + "events": [ |
| 50 | + {{"title": "Standup", "date": "", "description": "Standup scheduled for tomorrow at 9am in room 4.", "location": "room 4"}} |
| 51 | + ] |
| 52 | +}} |
| 53 | +
|
| 54 | +Note: "Read an article about Rust ownership; might be relevant to Project Atlas." |
| 55 | +Output: |
| 56 | +{{ |
| 57 | + "entities": [ |
| 58 | + {{"type": "technology", "name": "Rust", "aliases": [], "summary": "Programming language; user read an article about its ownership model.", "status": "", "owner": "", "due": "", "date": "", "attendees": [], "tags": ["ownership"]}}, |
| 59 | + {{"type": "project", "name": "Project Atlas", "aliases": [], "summary": "Project that may benefit from Rust ownership patterns.", "status": "", "owner": "", "due": "", "date": "", "attendees": [], "tags": []}} |
| 60 | + ], |
| 61 | + "relations": [ |
| 62 | + {{"a": "Rust", "b": "Project Atlas", "note": "Rust ownership model may be relevant to Project Atlas."}} |
| 63 | + ], |
| 64 | + "tasks": [], |
| 65 | + "actions": [], |
| 66 | + "decisions": [], |
| 67 | + "meetings": [], |
| 68 | + "events": [] |
| 69 | +}} |
| 70 | +
|
| 71 | +Note: "Felt tired today." <- minimal/vague note |
| 72 | +Output: |
| 73 | +{{ |
| 74 | + "entities": [ |
| 75 | + {{"type": "topic", "name": "Personal Log", "aliases": [], "summary": "User felt tired today.", "status": "", "owner": "", "due": "", "date": "", "attendees": [], "tags": ["journal"]}} |
| 76 | + ], |
| 77 | + "relations": [], "tasks": [], "actions": [], "decisions": [], "meetings": [], "events": [] |
| 78 | +}} |
| 79 | +
|
| 80 | +ANTI-EXAMPLES (do NOT do this): |
| 81 | +- Note "Discussed pricing with John." -> Do NOT extract "pricing" as an entity. DO extract John (person) and optionally a topic "Pricing discussion". |
| 82 | +- Note "Sent the email." -> Extract at most a topic "Email - sent" IF the note has no other subject. Do NOT extract "email" as a technology entity in this case. |
14 | 83 |
|
15 | 84 | A note may do one or more of the following: |
16 | 85 | - introduce new entities |
17 | 86 | - update the current state of existing entities |
18 | 87 | - create relationships between entities |
19 | 88 | - create or update tasks |
| 89 | +- create or update actions |
20 | 90 | - create or update decisions |
21 | 91 | - create or update meetings |
| 92 | +- create or update events |
22 | 93 |
|
23 | 94 | The knowledge base has two layers: |
24 | 95 |
|
25 | 96 | 1. Current state |
26 | | - - summary |
27 | | - - status |
28 | | - - owner |
29 | | - - due |
30 | | - - date |
31 | | - - attendees |
32 | | - - aliases |
33 | | - - tags |
| 97 | + - summary, status, owner, due, date, attendees, aliases, tags |
34 | 98 |
|
35 | 99 | 2. History |
36 | 100 | - every extracted item should also be appended as a historical note |
37 | 101 |
|
38 | 102 | When a note changes the current state of an entity, return the NEW current state |
39 | 103 | rather than the old one. |
40 | 104 |
|
41 | | -Examples: |
42 | | -- "Project Atlas has been archived." |
43 | | - -> status = "done" or "archived" only if clearly supported by the note |
44 | | -- "DB cutover task has been reviewed and deployed." |
45 | | - -> status = "done" |
46 | | -- "Architecture meeting moved to Friday." |
47 | | - -> date = "YYYY-MM-DD" if the date can be resolved from the note |
48 | | -- "John is now Engineering Manager." |
49 | | - -> summary reflects the new role |
50 | | -
|
51 | 105 | Use hyphenated status values when relevant: |
52 | 106 | open, in-progress, blocked, done, cancelled |
53 | 107 |
|
54 | 108 | Existing pages already in the knowledge base that MAY relate to this note |
55 | 109 | (any type - project, person, meeting, technology, company, topic, action, |
56 | | -task, or decision). This is provided so you can RECONCILE state changes |
| 110 | +task, event, or decision). This is provided so you can RECONCILE state changes |
57 | 111 | against what already exists, instead of creating a disconnected duplicate: |
58 | 112 |
|
59 | 113 | {existing_context} |
60 | 114 |
|
61 | | -UNIVERSAL RECONCILIATION RULE (applies to every category below, not just one): |
62 | | -- Before extracting ANY entity, task, decision, or meeting, check whether it |
63 | | - refers to the SAME underlying thing as one of the existing pages listed |
64 | | - above - even if the note's wording, category, or phrasing differs from |
65 | | - how that page was originally tracked. The same underlying work or topic |
66 | | - can legitimately be tracked as a "task" in one note and described in |
67 | | - "project"/"topic"/other entity language in another - these are not |
68 | | - different things just because the note's phrasing differs. |
69 | | -- If a match exists, reuse that EXISTING page's exact title (and reference |
70 | | - its type) in your output instead of inventing a new title. Do not |
71 | | - create a near-duplicate with slightly different wording. |
| 115 | +UNIVERSAL RECONCILIATION RULE: |
| 116 | +- Before extracting ANY entity, task, action, event, decision, or meeting, |
| 117 | + check whether it refers to the SAME underlying thing as one of the existing |
| 118 | + pages listed above. |
| 119 | +- If a HIGH-CONFIDENCE match exists (same proper noun, same date+subject, or |
| 120 | + one is an exact alias of the other), reuse that EXISTING page's exact title |
| 121 | + and reference its type in your output instead of inventing a new title. |
| 122 | +- If a match is only "thematically related" or a loose conceptual fit, DO NOT |
| 123 | + force a match — extract the new item as-is with its own unique title. |
72 | 124 | - If the note describes a status change (reviewed, completed, deployed, |
73 | 125 | blocked, cancelled, decided, rescheduled, etc.) for something that |
74 | | - matches an existing page - REGARDLESS OF WHICH CATEGORY THAT EXISTING |
75 | | - PAGE IS IN - emit an update for that exact category AND title. If the |
76 | | - same real-world item is tracked as both an existing task and referenced |
77 | | - as a project/entity, update BOTH using their existing exact titles so |
78 | | - neither one goes stale. |
79 | | -- This rule applies symmetrically across entities, tasks, decisions, and |
80 | | - meetings: a note phrased as a decision can update an existing task; a |
81 | | - note phrased as a project update can update an existing task; a note |
82 | | - phrased as a task update can update an existing decision or meeting |
83 | | - outcome; etc. Match on underlying meaning, not on which list something |
84 | | - was originally extracted into. |
| 126 | + HIGH-CONFIDENCE matches an existing page, emit an update for that exact |
| 127 | + category AND title. If the same real-world item is tracked as both an |
| 128 | + existing task and referenced as a project/entity, update BOTH using their |
| 129 | + existing exact titles so neither one goes stale. |
85 | 130 | - Never invent a new title for something that already exists above. |
86 | 131 |
|
87 | 132 | Return a JSON object strictly with the following structure: |
88 | 133 | {{ |
89 | 134 | "entities": [ |
90 | 135 | {{ |
91 | | - "type": "project|person|meeting|technology|company|topic|action", |
| 136 | + "type": "project|person|meeting|technology|company|topic|action|event", |
92 | 137 | "name": "canonical name", |
93 | 138 | "aliases": ["other names used"], |
94 | 139 | "summary": "one short sentence describing the entity in its current state", |
|
115 | 160 | "status": "open|in-progress|blocked|done|cancelled" |
116 | 161 | }} |
117 | 162 | ], |
| 163 | + "actions": [ |
| 164 | + {{ |
| 165 | + "title": "short imperative action title", |
| 166 | + "owner": "person or empty string", |
| 167 | + "due": "date or empty string", |
| 168 | + "status": "open|in-progress|blocked|done|cancelled" |
| 169 | + }} |
| 170 | + ], |
118 | 171 | "decisions": [ |
119 | 172 | {{ |
120 | 173 | "title": "short decision title", |
|
129 | 182 | "attendees": ["person names present in the note"], |
130 | 183 | "agenda": "one to two sentence summary of what the meeting covered" |
131 | 184 | }} |
| 185 | + ], |
| 186 | + "events": [ |
| 187 | + {{ |
| 188 | + "title": "short event title", |
| 189 | + "date": "YYYY-MM-DD or empty string", |
| 190 | + "description": "short summary of the event", |
| 191 | + "location": "event location or empty string" |
| 192 | + }} |
132 | 193 | ] |
133 | 194 | }} |
134 | 195 |
|
135 | 196 | Rules: |
136 | | -- Only include entities/tasks/decisions/meetings actually present or clearly implied in the note. |
| 197 | +- Only include SALIENT items actually present or clearly implied in the note. |
| 198 | +- If an item is an action or an event, put it in the `actions` or `events` array. Do NOT duplicate them inside the `entities` array. |
137 | 199 | - Keep summaries and descriptions concise (1-2 sentences). |
138 | 200 | - If a category is empty, return an empty list for it. |
139 | 201 | - Do not wrap the JSON in markdown code fences. |
|
144 | 206 | NOTE: |
145 | 207 | --- |
146 | 208 | {note} |
147 | | ---- |
148 | 209 | """ |
149 | 210 |
|
150 | 211 | RETRIEVAL_SYSTEM = """You are Gray Box's knowledge retrieval assistant. |
|
347 | 408 | appeared under. Never move a fact to a different tag, never merge two |
348 | 409 | tags' content under one tag, and never drop a Source Tag line while |
349 | 410 | keeping content from that block. |
350 | | -- If a block's content is fully removed because it is pure repetition of |
351 | | - another block, you may drop the block entirely (tag and all) — do not |
352 | | - leave a Source Tag with no content, and do not leave content with no |
353 | | - Source Tag. |
354 | | -
|
| 411 | +- Only drop a block if it is BYTE-FOR-BYTE identical to another block. |
| 412 | + "Similar Topic" is not repetition - two pages about the same project |
| 413 | + may carry different notes/information. When in doubt, keep the block. |
355 | 414 | Return only the compressed context.""" |
356 | 415 |
|
357 | 416 | HISTORY_COMPRESSION_PROMPT = """You are a highly efficient text summarizer. Summarize the following conversation history. |
|
0 commit comments