ei-tui 0.1.25 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +42 -0
  2. package/package.json +2 -1
  3. package/src/README.md +4 -11
  4. package/src/cli/README.md +87 -7
  5. package/src/cli/commands/facts.ts +2 -2
  6. package/src/cli/commands/people.ts +2 -2
  7. package/src/cli/commands/quotes.ts +2 -2
  8. package/src/cli/commands/topics.ts +2 -2
  9. package/src/cli/mcp.ts +94 -0
  10. package/src/cli/retrieval.ts +67 -31
  11. package/src/cli.ts +64 -23
  12. package/src/core/AGENTS.md +1 -1
  13. package/src/core/constants/built-in-facts.ts +49 -0
  14. package/src/core/constants/index.ts +1 -0
  15. package/src/core/context-utils.ts +0 -1
  16. package/src/core/embedding-service.ts +8 -0
  17. package/src/core/handlers/dedup.ts +11 -23
  18. package/src/core/handlers/heartbeat.ts +2 -3
  19. package/src/core/handlers/human-extraction.ts +96 -30
  20. package/src/core/handlers/human-matching.ts +328 -248
  21. package/src/core/handlers/index.ts +8 -6
  22. package/src/core/handlers/persona-generation.ts +8 -8
  23. package/src/core/handlers/rewrite.ts +4 -51
  24. package/src/core/handlers/utils.ts +23 -1
  25. package/src/core/heartbeat-manager.ts +2 -4
  26. package/src/core/human-data-manager.ts +38 -36
  27. package/src/core/message-manager.ts +10 -10
  28. package/src/core/orchestrators/ceremony.ts +49 -44
  29. package/src/core/orchestrators/dedup-phase.ts +2 -4
  30. package/src/core/orchestrators/human-extraction.ts +351 -207
  31. package/src/core/orchestrators/index.ts +6 -4
  32. package/src/core/orchestrators/persona-generation.ts +3 -3
  33. package/src/core/processor.ts +167 -20
  34. package/src/core/prompt-context-builder.ts +4 -6
  35. package/src/core/state/human.ts +1 -26
  36. package/src/core/state/personas.ts +2 -2
  37. package/src/core/state-manager.ts +107 -14
  38. package/src/core/tools/builtin/read-memory.ts +13 -18
  39. package/src/core/types/data-items.ts +3 -4
  40. package/src/core/types/entities.ts +7 -4
  41. package/src/core/types/enums.ts +6 -9
  42. package/src/core/types/llm.ts +2 -2
  43. package/src/core/utils/crossFind.ts +2 -5
  44. package/src/core/utils/event-windows.ts +31 -0
  45. package/src/integrations/claude-code/importer.ts +14 -5
  46. package/src/integrations/claude-code/types.ts +3 -0
  47. package/src/integrations/cursor/importer.ts +282 -0
  48. package/src/integrations/cursor/index.ts +10 -0
  49. package/src/integrations/cursor/reader.ts +209 -0
  50. package/src/integrations/cursor/types.ts +140 -0
  51. package/src/integrations/opencode/importer.ts +14 -4
  52. package/src/prompts/AGENTS.md +73 -1
  53. package/src/prompts/ceremony/dedup.ts +0 -33
  54. package/src/prompts/ceremony/rewrite.ts +6 -41
  55. package/src/prompts/ceremony/types.ts +4 -4
  56. package/src/prompts/generation/descriptions.ts +2 -2
  57. package/src/prompts/generation/types.ts +2 -2
  58. package/src/prompts/heartbeat/types.ts +2 -2
  59. package/src/prompts/human/event-scan.ts +122 -0
  60. package/src/prompts/human/fact-find.ts +106 -0
  61. package/src/prompts/human/fact-scan.ts +0 -2
  62. package/src/prompts/human/index.ts +17 -10
  63. package/src/prompts/human/person-match.ts +65 -0
  64. package/src/prompts/human/person-scan.ts +52 -59
  65. package/src/prompts/human/person-update.ts +241 -0
  66. package/src/prompts/human/topic-match.ts +65 -0
  67. package/src/prompts/human/topic-scan.ts +51 -71
  68. package/src/prompts/human/topic-update.ts +295 -0
  69. package/src/prompts/human/types.ts +63 -40
  70. package/src/prompts/index.ts +4 -8
  71. package/src/prompts/persona/topics-update.ts +2 -2
  72. package/src/prompts/persona/traits.ts +2 -2
  73. package/src/prompts/persona/types.ts +3 -3
  74. package/src/prompts/response/index.ts +1 -1
  75. package/src/prompts/response/sections.ts +9 -12
  76. package/src/prompts/response/types.ts +2 -3
  77. package/src/storage/embeddings.ts +1 -1
  78. package/src/storage/index.ts +1 -0
  79. package/src/storage/indexed.ts +174 -0
  80. package/src/storage/merge.ts +67 -2
  81. package/tui/src/commands/me.tsx +5 -14
  82. package/tui/src/commands/settings.tsx +15 -0
  83. package/tui/src/context/ei.tsx +5 -14
  84. package/tui/src/util/yaml-serializers.ts +76 -33
  85. package/src/cli/commands/traits.ts +0 -25
  86. package/src/prompts/human/item-match.ts +0 -74
  87. package/src/prompts/human/item-update.ts +0 -364
  88. package/src/prompts/human/trait-scan.ts +0 -115
@@ -0,0 +1,241 @@
1
+ import type { PromptOutput } from "./types.js";
2
+ import type { Person, Message } from "../../core/types.js";
3
+ import { formatMessagesAsPlaceholders } from "../message-utils.js";
4
+
5
+ export interface PersonUpdatePromptData {
6
+ existing_item: Person | null;
7
+ new_person_name?: string;
8
+ new_person_description?: string;
9
+ new_person_relationship?: string;
10
+ messages_context: Message[];
11
+ messages_analyze: Message[];
12
+ persona_name: string;
13
+ }
14
+
15
+ function formatExistingPerson(person: Person): string {
16
+ return JSON.stringify({
17
+ name: person.name,
18
+ description: person.description,
19
+ sentiment: person.sentiment,
20
+ relationship: person.relationship,
21
+ exposure_current: person.exposure_current,
22
+ exposure_desired: person.exposure_desired,
23
+ }, null, 2);
24
+ }
25
+
26
+ export function buildPersonUpdatePrompt(data: PersonUpdatePromptData): PromptOutput {
27
+ if (!data.persona_name) {
28
+ throw new Error("buildPersonUpdatePrompt: persona_name is required");
29
+ }
30
+
31
+ const personaName = data.persona_name;
32
+
33
+ const nameSection = `The person's actual name, or the clearest available identifier.
34
+
35
+ Only update when you learn something more specific.
36
+
37
+ Examples: "Unknown woman" → "Carol", "Mom" → "Carol (Mom)", "David" → "David Kim"`;
38
+
39
+ const descriptionSection = `A concise summary of who this person is and how they relate to the HUMAN USER. Personas use this to recognize this person and engage meaningfully when they come up.
40
+
41
+ ## CRITICAL: Synthesize, don't accumulate
42
+
43
+ Every update must **rewrite** the description as a current-state summary. Never append to it.
44
+
45
+ **Good description**: "Borfinda, partner of 12 years. Former marine biologist, now stay-at-home parent. Tends to ground the user when they spiral; dry sense of humor. Two kids together."
46
+
47
+ **Bad description**: "Borfinda was mentioned when the user talked about moving. In a later conversation she came up again during the work stress discussion. Most recently the user said she was supportive."
48
+
49
+ The description should:
50
+ - Capture who this person IS — their role, characteristics, relationship texture
51
+ - Include what the HUMAN USER has revealed about them over time
52
+ - Be useful to a persona who's never heard this person's name before
53
+ - Read as a brief, confident summary — not a log of when they were mentioned
54
+
55
+ The description should NOT:
56
+ - Append "Most recently:", "Latest mention:", or any temporal marker
57
+ - Accumulate a session-by-session history of every time this person came up
58
+ - Speculate about the person based on thin evidence
59
+ - Exceed 3-4 sentences under any circumstances
60
+
61
+ **ABSOLUTELY VITAL**: Do **NOT** embellish — personas use their own voice. Record what the user actually said or demonstrated, not your interpretation of its emotional significance.`;
62
+
63
+ const relationshipSection = `## Relationship (\`relationship\`)
64
+
65
+ How the HUMAN USER is currently related to this PERSON.
66
+
67
+ Once known, this field changes infrequently — a "Father" may later be clarified to "Step-Father", but is unlikely to become "Uncle".
68
+
69
+ Keep it concise and specific. Avoid vague labels.
70
+
71
+ Examples: "Unknown" → "Coworker", "Mother" → "Step-Mother", "Fiance" → "Spouse", "AI Persona" → "AI Companion"`;
72
+
73
+ const exposureSection = `## Desired Exposure (\`exposure_desired\`)
74
+
75
+ How much the HUMAN USER wants to talk about this PERSON.
76
+
77
+ Scale of 0.0 to 1.0:
78
+ - 0.0: Never wants to hear about this PERSON again
79
+ - 0.5: Average amount of engagement
80
+ - 1.0: This PERSON is the sole focus of their existence
81
+
82
+ Do not make micro-adjustments. Close enough is OK.
83
+
84
+ ## Exposure Impact (\`exposure_impact\`)
85
+
86
+ Not in the current data — but include it in your response.
87
+
88
+ How much this conversation should count toward exposure tracking:
89
+ - "high": Long, detailed conversation exclusively about this PERSON
90
+ - "medium": Long OR detailed conversation about this PERSON
91
+ - "low": The conversation touched on this PERSON briefly
92
+ - "none": Only alluded to or hinted at`;
93
+
94
+ const currentDetailsSection = data.existing_item
95
+ ? `\`\`\`json
96
+ ${formatExistingPerson(data.existing_item)}
97
+ \`\`\`
98
+
99
+ You are UPDATING an existing PERSON.`
100
+ : `**NEW PERSON — NOT YET IN SYSTEM**
101
+
102
+ You are CREATING a new PERSON from what was discovered:
103
+ \`\`\`json
104
+ {
105
+ "name": "${data.new_person_name ?? "Unknown"}",
106
+ "description": "${data.new_person_description ?? "Details unknown"}",
107
+ "relationship": "${data.new_person_relationship ?? "Unknown"}"
108
+ }
109
+ \`\`\`
110
+
111
+ Return all fields based on what you find in the conversation.`;
112
+
113
+ const jsonTemplate = `{
114
+ "name": "...",
115
+ "description": "...",
116
+ "sentiment": 0.0,
117
+ "relationship": "Mother|Friend|Coworker|AI Companion|etc.",
118
+ "exposure_desired": 0.5,
119
+ "exposure_impact": "high|medium|low|none",
120
+ "quotes": [
121
+ {
122
+ "text": "exact phrase from message",
123
+ "reason": "why this matters"
124
+ }
125
+ ]
126
+ }`;
127
+
128
+ const system = `# Task
129
+
130
+ You are scanning a conversation to deeply understand a PERSON in the HUMAN USER's life.
131
+
132
+ Your job is to take that analysis and apply it to the record we already have **IF DOING SO WILL PROVIDE THE HUMAN USER WITH A BETTER EXPERIENCE IN THE FUTURE**.
133
+
134
+ This means detail you add should:
135
+ 1. Be meaningful, accurate, or still true to the HUMAN USER in six months or more
136
+ 2. **NOT** already be present in the description or name of the PERSON
137
+
138
+ This PERSON will be recorded in the HUMAN USER's profile for agents and personas to later reference.
139
+
140
+ # Field Definitions
141
+
142
+ ## Name (\`name\`)
143
+ ${nameSection}
144
+
145
+ ## Description (\`description\`)
146
+ ${descriptionSection}
147
+
148
+ ## Sentiment (\`sentiment\`)
149
+
150
+ How the HUMAN USER feels about this PERSON overall.
151
+
152
+ Scale of -1.0 to 1.0:
153
+ - -1.0: No PERSON is more despised
154
+ - -0.5: Disliked or complicated relationship, but not without value
155
+ - 0: Neutral or unknown
156
+ - 0.5: Liked and valued
157
+ - 1.0: The most important person in their life
158
+
159
+ Do not make micro-adjustments. Close enough is OK.
160
+
161
+ ${relationshipSection}
162
+
163
+ ${exposureSection}
164
+
165
+ ## Quotes
166
+
167
+ In addition to updating the PERSON, identify any **memorable, funny, important, or stand-out phrases** from the Most Recent Messages that relate to this PERSON.
168
+
169
+ ### What Makes a Quote Worth Preserving
170
+
171
+ **Prioritize:**
172
+ - Humor, wit, colorful language, creative profanity
173
+ - Emotional outbursts (positive or negative) — the raw stuff
174
+ - Phrases that reveal how the HUMAN USER feels about this PERSON
175
+ - Things you'd quote back to them later to make them laugh or think
176
+ - Unique expressions or turns of phrase about or from this PERSON
177
+ - Quotable moments from EITHER speaker — humans AND AI personas both say memorable things
178
+
179
+ **NEVER extract these — they are NOT quotes:**
180
+ - Technical identifiers: ARNs, URLs, file paths, UUIDs, config keys
181
+ - AI agent self-talk: "I notice I'm in Plan Mode", "I'll start by...", status updates
182
+ - AI apologies or acknowledgments: "You're absolutely right", "I apologize for that"
183
+ - Generic statements that could apply to anyone
184
+ - Credentials, secrets, connection strings, or anything that looks like an access token
185
+
186
+ **The litmus test**: Would you bring this up at a bar with a friend? Would it make someone laugh, think, or feel something?
187
+ - "She's the only person who can make me feel simultaneously stupid and brilliant" → YES.
188
+ - "Borfinda was mentioned in the context of the Minnesota discussion" → NO. That's a note, not a quote.
189
+
190
+ **When in doubt, leave it out.** An empty quotes array is always acceptable.
191
+
192
+ **CRITICAL**: Return the EXACT text as it appears in the message. **WE CAN ONLY USE IT IF WE FIND IT IN THE TEXT.**
193
+
194
+ # CRITICAL INSTRUCTIONS
195
+
196
+ ONLY ANALYZE the "Most Recent Messages". The "Earlier Conversation" is provided for context only — it has already been processed.
197
+
198
+ \`\`\`json
199
+ ${jsonTemplate}
200
+ \`\`\`
201
+
202
+ When returning a record, **ALWAYS** include \`name\`, \`description\`, and \`sentiment\`.
203
+
204
+ If you find **NO EVIDENCE** of this PERSON in the "Most Recent Messages", respond with: \`{}\`
205
+
206
+ If **NO CHANGES** are required, respond with: \`{}\`
207
+
208
+ An empty object is the MOST COMMON expected response.
209
+
210
+ # Current Details of PERSON
211
+
212
+ ${currentDetailsSection}
213
+ `;
214
+
215
+ const earlierSection =
216
+ data.messages_context.length > 0
217
+ ? `## Earlier Conversation
218
+ ${formatMessagesAsPlaceholders(data.messages_context, personaName)}
219
+
220
+ `
221
+ : "";
222
+
223
+ const recentSection = `## Most Recent Messages
224
+ ${formatMessagesAsPlaceholders(data.messages_analyze, personaName)}`;
225
+
226
+ const user = `# Conversation
227
+ ${earlierSection}${recentSection}
228
+
229
+ ---
230
+
231
+ Analyze the Most Recent Messages and update the PERSON if warranted.
232
+
233
+ **Return JSON:**
234
+ \`\`\`json
235
+ ${jsonTemplate}
236
+ \`\`\`
237
+
238
+ If no changes are needed, respond with: \`{}\``;
239
+
240
+ return { system, user };
241
+ }
@@ -0,0 +1,65 @@
1
+ import type { PromptOutput } from "./types.js";
2
+
3
+ export interface TopicMatchPromptData {
4
+ candidate_name: string;
5
+ candidate_description: string;
6
+ candidate_category: string;
7
+ existing_topics: Array<{
8
+ id: string;
9
+ name: string;
10
+ description: string;
11
+ category?: string;
12
+ }>;
13
+ }
14
+
15
+ export function buildTopicMatchPrompt(data: TopicMatchPromptData): PromptOutput {
16
+ if (!data.candidate_name) {
17
+ throw new Error("buildTopicMatchPrompt: candidate_name is required");
18
+ }
19
+
20
+ const system = `# Task
21
+
22
+ You are checking if a TOPIC already exists in our database.
23
+
24
+ ## Matching Rules
25
+
26
+ 1. **Exact match**: Same name or concept → return its ID
27
+ 2. **Similar match**: Clearly the same topic with different wording → return its ID
28
+ 3. **No match**: Genuinely new information → return "new"
29
+
30
+ Be conservative. If you're unsure, return "new" — a duplicate is worse than a gap.
31
+
32
+ # Existing Topics
33
+
34
+ \`\`\`json
35
+ ${JSON.stringify(data.existing_topics, null, 2)}
36
+ \`\`\`
37
+
38
+ # Response Format
39
+
40
+ Return ONLY the ID of the matching entry, or "new".
41
+
42
+ \`\`\`json
43
+ {
44
+ "matched_guid": "uuid-of-matching-entry" | "new"
45
+ }
46
+ \`\`\`
47
+
48
+ **Return JSON only.**`;
49
+
50
+ const user = `# Candidate Topic
51
+
52
+ Name: ${data.candidate_name}
53
+ Description: ${data.candidate_description}
54
+ Category: ${data.candidate_category}
55
+
56
+ Find the best match in existing topics, or return "new" if this is genuinely new.
57
+
58
+ \`\`\`json
59
+ {
60
+ "matched_guid": "..." | "new"
61
+ }
62
+ \`\`\``;
63
+
64
+ return { system, user };
65
+ }
@@ -1,6 +1,19 @@
1
- import type { TopicScanPromptData, PromptOutput } from "./types.js";
1
+ import type { TopicScanPromptData, PromptOutput, ParticipantContext } from "./types.js";
2
2
  import { formatMessagesAsPlaceholders } from "../message-utils.js";
3
3
 
4
+ function participantContextSection(ctx: ParticipantContext | undefined): string {
5
+ if (!ctx) return "";
6
+ const lines: string[] = ["# Participant Context", "The following may help you understand what themes and moments are meaningful in this conversation.", ""];
7
+ lines.push(`## Persona: ${ctx.persona_name}`);
8
+ if (ctx.persona_description) lines.push(ctx.persona_description);
9
+ lines.push("");
10
+ lines.push("## Human");
11
+ if (ctx.human_name) lines.push(`Name: ${ctx.human_name}`);
12
+ if (ctx.human_age !== undefined) lines.push(`Age: ${ctx.human_age}`);
13
+ lines.push("");
14
+ return lines.join("\n");
15
+ }
16
+
4
17
  export function buildHumanTopicScanPrompt(data: TopicScanPromptData): PromptOutput {
5
18
  if (!data.persona_name) {
6
19
  throw new Error("buildHumanTopicScanPrompt: persona_name is required");
@@ -8,98 +21,64 @@ export function buildHumanTopicScanPrompt(data: TopicScanPromptData): PromptOutp
8
21
 
9
22
  const personaName = data.persona_name;
10
23
 
11
- const taskFragment = `# Task
12
-
13
- You are scanning a conversation to quickly identify TOPICS of interest TO the HUMAN USER. Your ONLY job is to spot mentions of TOPICS. Do NOT analyze them deeply. Just detect and flag.`;
14
-
15
- const specificNeedsFragment = `## Specific Needs
16
-
17
- Your job is to quickly identify:
18
- 1. Which TOPICS were mentioned or relevant
19
- a. Only flag TOPICS that were actually discussed, not just tangentially related
20
- b. Be CONSERVATIVE - only suggest genuinely important, long-term relevant TOPICS
21
- c. Be CLEAR - state your \`reason\` for including this TOPIC with any evidence you used
22
-
23
- The goal of the system is to remember important TOPICS to the HUMAN USER in order to ask about them in the future.`;
24
-
25
- const guidelinesFragment = `## Guidelines
24
+ const system = `# Task
26
25
 
27
- # A TOPIC Is:
26
+ You are scanning a conversation to quickly identify TOPICS of interest to the HUMAN USER.
28
27
 
29
- A meaningful subject or concept relevant to the HUMAN USER. It is:
28
+ Detect and flag. Do NOT analyze deeply that happens later.
30
29
 
31
- - **Specific and Contextual:** Not a broad category or just a list of isolated facts. It must have narrative or direct relevance in the conversation.
30
+ ## What to Capture
32
31
 
33
- 1. **Primary Focus** - Capture the main idea of the conversation, not minute details
34
- 2. **Participation** - Things the HUMAN USER does or wants to do
35
- 3. **Interests** - Hobbies or concepts they spend time on BY CHOICE
36
- 4. **Responsibilities** - Tasks or requirements that occupy their time BY NECESSITY
37
- 5. **Knowledge** - Ideas they are exploring or learning about, or are expert in
38
- 6. **Dreams** - Wild ideas, hopes for the future, or vision of an ideal state
39
- 7. **Conflicts** - Things they have difficulty with or are frustrated with
40
- 8. **Concerns** - Ideas they express worry over
41
- 9. **Stories and Characters** - Extended narratives they share (more than a sentence or two)
42
- 10. **Location** - Favorite places, travel destinations
43
- 11. **Preferences** - "I like {thing}" or "I hate {thing}" statements`;
32
+ Flag a TOPIC when it was meaningfully discussed not just mentioned in passing.
44
33
 
45
- const doNotCaptureFragment = `# **IMPORTANT** The Following Are NOT TOPICS
34
+ Be **conservative**: only flag topics that are genuinely relevant to the human user long-term. Noise is worse than gaps.
46
35
 
47
- # The system tracks FACTS, TRAITS, and PEOPLE as separate types. Do NOT capture:
36
+ ## What a TOPIC Is
48
37
 
49
- ## FACTS - Tracked Separately
50
- - **Biographical Data (Do NOT Capture):** Name, Nickname, Birthday, Location, Job, Marital Status, Gender, Eye Color, Hair Color.
51
- > **CRITICAL:** The HUMAN USER's name itself, or a collection of their basic biographical facts, is NEVER a TOPIC. Even if multiple biographical facts are mentioned together (e.g., "My name is John, I live in NYC, and I'm a software engineer"), do not summarize them as a 'topic' about the user's identity.
52
- - Other Important Dates: Wedding Anniversary, Job Anniversary
53
- - Health & Well-being: Allergies, Medical Conditions, Dietary Restrictions
38
+ A meaningful subject in the human user's life: something they care about, work on, worry over, or experience. It has context and weight — not just a passing reference.
54
39
 
55
- > NOTE: Many FACTS have stories/topics around them.
56
- > "My birthday is May 26th" is a FACT. "A goat jumped out of my birthday cake" is a TOPIC.
40
+ **NOT a TOPIC:**
41
+ - Biographical facts (birthday, job title, location) those are Facts
42
+ - People (family, friends, coworkers, AI personas) — those are People
43
+ - One-off mentions, small talk, or jokes with no deeper relevance
57
44
 
58
- ## TRAITS - Tracked Separately
59
- * Personality Patterns, Communication style, Behavioral tendencies
60
- * Cognitive Style, Emotional Traits, Work Ethic, Social Orientation
45
+ ## Category
61
46
 
62
- > NOTE: Many TRAITS have stories/topics around them.
63
- > "I'm a visual learner" is a TRAIT. "I saw a picture of an atom and I FINALLY GET IT" is a TOPIC.
47
+ Assign each TOPIC one category. Pick the closest fit:
64
48
 
65
- ## PEOPLE / Relationships - Tracked Separately
66
- - Immediate family, Extended family, Friends, Coworkers, etc.
49
+ - **Interest** hobbies, activities, ongoing fascinations
50
+ - **Goal** things they want to achieve
51
+ - **Dream** — aspirational, maybe unrealistic desires
52
+ - **Conflict** — internal or external struggles, dilemmas
53
+ - **Concern** — worries, anxieties about something real
54
+ - **Fear** — things that scare them
55
+ - **Hope** — positive expectations for the future
56
+ - **Plan** — concrete intentions with steps in mind
57
+ - **Project** — active undertakings with real progress
58
+ - **Event** — a specific, significant moment that either party might reference later ("remember when...")
67
59
 
68
- > NOTE: Many PEOPLE have stories/topics around them.
69
- > "Sarah is my dream girl" is a PERSON. "I hope Sarah and I get married on the moon" is a TOPIC.
60
+ When in doubt, pick the closest match. The update step will refine it.
70
61
 
71
- ## AI PERSONAS - Tracked Separately
72
- - Do NOT record any stories or details about PERSONAS as TOPICS`;
73
-
74
- const criticalFragment = `# CRITICAL INSTRUCTIONS
75
-
76
- ONLY ANALYZE the "Most Recent Messages" in the following conversation. The "Earlier Conversation" is provided for your context and has already been processed!
77
-
78
- The JSON format is:
62
+ ## Output Format
79
63
 
80
64
  \`\`\`json
81
65
  {
82
66
  "topics": [
83
67
  {
84
- "type_of_topic": "The Topic Type from the list above",
85
- "value_of_topic": "<actual topic from the conversation>",
86
- "reason": "The justification of including this specific topic"
68
+ "name": "Short label for the topic (10-75 characters)",
69
+ "description": "1-2 sentences: what this topic is and why it matters to the user",
70
+ "category": "One of the categories above",
71
+ "reason": "Evidence from the conversation that justified flagging this topic"
87
72
  }
88
73
  ]
89
74
  }
90
75
  \`\`\`
91
76
 
92
- **Return JSON only.**`;
93
-
94
- const system = `${taskFragment}
95
-
96
- ${specificNeedsFragment}
97
-
98
- ${guidelinesFragment}
77
+ **Return JSON only.**
99
78
 
100
- ${doNotCaptureFragment}
79
+ ONLY ANALYZE the "Most Recent Messages". The "Earlier Conversation" is provided for context only — it has already been processed.
101
80
 
102
- ${criticalFragment}`;
81
+ ${participantContextSection(data.participant_context)}`;
103
82
 
104
83
  const earlierSection = data.messages_context.length > 0
105
84
  ? `## Earlier Conversation
@@ -123,9 +102,10 @@ Scan the "Most Recent Messages" for TOPICS of interest to the human user.
123
102
  {
124
103
  "topics": [
125
104
  {
126
- "type_of_topic": "The Topic Type from the list above",
127
- "value_of_topic": "<actual topic from the conversation>",
128
- "reason": "The justification of including this specific topic"
105
+ "name": "Short label for the topic (10-75 characters)",
106
+ "description": "1-2 sentences: what this topic is and why it matters to the user",
107
+ "category": "Interest|Goal|Dream|Conflict|Concern|Fear|Hope|Plan|Project|Event",
108
+ "reason": "Evidence from the conversation that justified flagging this topic"
129
109
  }
130
110
  ]
131
111
  }