ei-tui 0.9.3 → 0.9.4
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.
- package/package.json +4 -1
- package/src/README.md +1 -1
- package/src/core/context-utils.ts +2 -2
- package/src/core/handlers/heartbeat.ts +9 -1
- package/src/core/handlers/human-extraction.ts +4 -1
- package/src/core/handlers/human-matching.ts +5 -53
- package/src/core/handlers/index.ts +1 -51
- package/src/core/handlers/persona-generation.ts +1 -28
- package/src/core/handlers/utils.ts +2 -9
- package/src/core/heartbeat-manager.ts +3 -3
- package/src/core/message-manager.ts +6 -5
- package/src/core/orchestrators/ceremony.ts +4 -9
- package/src/core/orchestrators/extraction-chunker.ts +3 -3
- package/src/core/orchestrators/human-extraction.ts +17 -17
- package/src/core/orchestrators/index.ts +0 -1
- package/src/core/orchestrators/persona-topics.ts +1 -1
- package/src/core/orchestrators/room-extraction.ts +5 -5
- package/src/core/processor.ts +8 -21
- package/src/core/prompt-context-builder.ts +7 -6
- package/src/core/state/personas.ts +1 -17
- package/src/core/state-manager.ts +0 -66
- package/src/core/types/entities.ts +2 -3
- package/src/core/types/enums.ts +0 -2
- package/src/core/types/rooms.ts +1 -1
- package/src/integrations/claude-code/importer.ts +1 -1
- package/src/integrations/cursor/importer.ts +1 -1
- package/src/integrations/opencode/importer.ts +1 -1
- package/src/prompts/ceremony/index.ts +0 -10
- package/src/prompts/ceremony/types.ts +1 -42
- package/src/prompts/generation/index.ts +0 -3
- package/src/prompts/generation/types.ts +0 -15
- package/src/prompts/heartbeat/check.ts +18 -6
- package/src/prompts/heartbeat/types.ts +2 -1
- package/src/prompts/human/index.ts +0 -2
- package/src/prompts/human/types.ts +0 -16
- package/src/prompts/index.ts +0 -19
- package/src/prompts/reflection/index.ts +35 -5
- package/src/prompts/reflection/types.ts +1 -1
- package/src/prompts/response/index.ts +5 -0
- package/src/prompts/response/sections.ts +26 -0
- package/src/prompts/response/types.ts +3 -0
- package/tui/src/commands/registry.test.ts +10 -5
- package/tui/src/globals.d.ts +57 -0
- package/tui/src/util/yaml-persona.ts +8 -4
- package/tui/src/util/yaml-settings.ts +3 -3
- package/src/core/orchestrators/person-migration.ts +0 -55
- package/src/prompts/ceremony/description-check.ts +0 -54
- package/src/prompts/ceremony/expire.ts +0 -37
- package/src/prompts/ceremony/explore.ts +0 -77
- package/src/prompts/ceremony/person-migration.ts +0 -77
- package/src/prompts/generation/descriptions.ts +0 -91
- package/src/prompts/human/fact-scan.ts +0 -150
|
@@ -78,7 +78,7 @@ function queueRoomTopicScan(
|
|
|
78
78
|
): void {
|
|
79
79
|
const context: HumanExtractionContext = {
|
|
80
80
|
personaId: roomId,
|
|
81
|
-
|
|
81
|
+
channelDisplayName: roomDisplayName,
|
|
82
82
|
messages_context,
|
|
83
83
|
messages_analyze,
|
|
84
84
|
extraction_flag: "t",
|
|
@@ -122,7 +122,7 @@ function queueRoomPersonScan(
|
|
|
122
122
|
): void {
|
|
123
123
|
const context: HumanExtractionContext = {
|
|
124
124
|
personaId: roomId,
|
|
125
|
-
|
|
125
|
+
channelDisplayName: roomDisplayName,
|
|
126
126
|
messages_context,
|
|
127
127
|
messages_analyze,
|
|
128
128
|
extraction_flag: "p",
|
|
@@ -180,7 +180,7 @@ function queueRoomEventScan(
|
|
|
180
180
|
);
|
|
181
181
|
const context: HumanExtractionContext = {
|
|
182
182
|
personaId: roomId,
|
|
183
|
-
|
|
183
|
+
channelDisplayName: roomDisplayName,
|
|
184
184
|
messages_context,
|
|
185
185
|
messages_analyze: windowMessages,
|
|
186
186
|
extraction_flag: "e",
|
|
@@ -348,7 +348,7 @@ export function queuePersonaCapture(state: StateManager, personaId: string): voi
|
|
|
348
348
|
);
|
|
349
349
|
const context: HumanExtractionContext = {
|
|
350
350
|
personaId,
|
|
351
|
-
|
|
351
|
+
channelDisplayName: persona.display_name,
|
|
352
352
|
messages_context,
|
|
353
353
|
messages_analyze: unextractedT,
|
|
354
354
|
};
|
|
@@ -362,7 +362,7 @@ export function queuePersonaCapture(state: StateManager, personaId: string): voi
|
|
|
362
362
|
);
|
|
363
363
|
const context: HumanExtractionContext = {
|
|
364
364
|
personaId,
|
|
365
|
-
|
|
365
|
+
channelDisplayName: persona.display_name,
|
|
366
366
|
messages_context,
|
|
367
367
|
messages_analyze: unextractedP,
|
|
368
368
|
};
|
package/src/core/processor.ts
CHANGED
|
@@ -877,8 +877,8 @@ export class Processor {
|
|
|
877
877
|
modified = true;
|
|
878
878
|
}
|
|
879
879
|
|
|
880
|
-
if (human.settings.
|
|
881
|
-
human.settings.
|
|
880
|
+
if (human.settings.default_context_window_ms == null) {
|
|
881
|
+
human.settings.default_context_window_ms = 28800000;
|
|
882
882
|
modified = true;
|
|
883
883
|
}
|
|
884
884
|
|
|
@@ -1044,7 +1044,6 @@ const toolNextSteps = new Set([
|
|
|
1044
1044
|
LLMNextStep.HandleEiHeartbeat,
|
|
1045
1045
|
LLMNextStep.HandleToolContinuation,
|
|
1046
1046
|
LLMNextStep.HandleDedupCurate,
|
|
1047
|
-
LLMNextStep.HandlePersonIdentifierMigration,
|
|
1048
1047
|
]);
|
|
1049
1048
|
const toolPersonaId =
|
|
1050
1049
|
personaId ??
|
|
@@ -1059,13 +1058,8 @@ const toolNextSteps = new Set([
|
|
|
1059
1058
|
(request.next_step === LLMNextStep.HandleToolContinuation &&
|
|
1060
1059
|
request.data.originalNextStep === LLMNextStep.HandleDedupCurate);
|
|
1061
1060
|
|
|
1062
|
-
const isPersonMigrationRequest =
|
|
1063
|
-
request.next_step === LLMNextStep.HandlePersonIdentifierMigration ||
|
|
1064
|
-
(request.next_step === LLMNextStep.HandleToolContinuation &&
|
|
1065
|
-
request.data.originalNextStep === LLMNextStep.HandlePersonIdentifierMigration);
|
|
1066
|
-
|
|
1067
1061
|
let tools: ToolDefinition[] = [];
|
|
1068
|
-
if (isDedupRequest
|
|
1062
|
+
if (isDedupRequest) {
|
|
1069
1063
|
const readMemory = this.stateManager.tools_getByName("read_memory");
|
|
1070
1064
|
if (readMemory?.enabled) {
|
|
1071
1065
|
tools = [readMemory];
|
|
@@ -1201,14 +1195,14 @@ const toolNextSteps = new Set([
|
|
|
1201
1195
|
|
|
1202
1196
|
if (timeSinceHeartbeat >= heartbeatDelay) {
|
|
1203
1197
|
const history = this.stateManager.messages_get(persona.id);
|
|
1204
|
-
const
|
|
1205
|
-
persona.
|
|
1206
|
-
?? this.stateManager.getHuman().settings?.
|
|
1207
|
-
??
|
|
1198
|
+
const contextWindowMs =
|
|
1199
|
+
persona.context_window_ms
|
|
1200
|
+
?? this.stateManager.getHuman().settings?.default_context_window_ms
|
|
1201
|
+
?? 28800000;
|
|
1208
1202
|
const contextHistory = filterMessagesForContext(
|
|
1209
1203
|
history,
|
|
1210
1204
|
persona.context_boundary,
|
|
1211
|
-
|
|
1205
|
+
contextWindowMs
|
|
1212
1206
|
);
|
|
1213
1207
|
const trailing = countTrailingPersonaMessages(contextHistory);
|
|
1214
1208
|
if (trailing < 3) {
|
|
@@ -1621,13 +1615,6 @@ const toolNextSteps = new Set([
|
|
|
1621
1615
|
}
|
|
1622
1616
|
}
|
|
1623
1617
|
|
|
1624
|
-
if (response.request.next_step === LLMNextStep.HandlePersonaDescriptions) {
|
|
1625
|
-
const personaId = response.request.data.personaId as string;
|
|
1626
|
-
if (personaId) {
|
|
1627
|
-
this.interface.onPersonaUpdated?.(personaId);
|
|
1628
|
-
}
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
1618
|
if (
|
|
1632
1619
|
response.request.next_step === LLMNextStep.HandlePersonaTraitExtraction ||
|
|
1633
1620
|
response.request.next_step === LLMNextStep.HandlePersonaTopicRating
|
|
@@ -291,6 +291,7 @@ export async function buildResponsePromptData(
|
|
|
291
291
|
topics: persona.topics,
|
|
292
292
|
interested_topics: persona.topics.filter(t => t.exposure_desired - t.exposure_current > 0.2),
|
|
293
293
|
include_message_timestamps: persona.include_message_timestamps,
|
|
294
|
+
pending_update: persona.pending_update,
|
|
294
295
|
},
|
|
295
296
|
human: filteredHuman,
|
|
296
297
|
visible_personas: visiblePersonas,
|
|
@@ -318,10 +319,10 @@ export async function buildRoomResponsePromptData(
|
|
|
318
319
|
|
|
319
320
|
let sourceMessages: RoomMessage[];
|
|
320
321
|
if (room.mode === RoomMode.FreeForAll) {
|
|
321
|
-
const
|
|
322
|
-
?? human.settings?.
|
|
323
|
-
??
|
|
324
|
-
const windowCutoff = new Date(Date.now() -
|
|
322
|
+
const contextWindowMs = room.context_window_ms
|
|
323
|
+
?? human.settings?.default_context_window_ms
|
|
324
|
+
?? 28800000;
|
|
325
|
+
const windowCutoff = new Date(Date.now() - contextWindowMs).toISOString();
|
|
325
326
|
const boundaryMs = room.context_boundary ? new Date(room.context_boundary).getTime() : 0;
|
|
326
327
|
sourceMessages = allSourceMessages.filter(m => {
|
|
327
328
|
const msgMs = new Date(m.timestamp).getTime();
|
|
@@ -334,8 +335,8 @@ export async function buildRoomResponsePromptData(
|
|
|
334
335
|
const byCount = allSourceMessages.slice(-MIN_ROOM_MESSAGES);
|
|
335
336
|
if (byCount.length > sourceMessages.length) sourceMessages = byCount;
|
|
336
337
|
} else {
|
|
337
|
-
const
|
|
338
|
-
const windowCutoff = new Date(Date.now() -
|
|
338
|
+
const contextWindowMs = human.settings?.default_context_window_ms ?? 28800000;
|
|
339
|
+
const windowCutoff = new Date(Date.now() - contextWindowMs).toISOString();
|
|
339
340
|
const byTime = allSourceMessages.filter(m => m.timestamp >= windowCutoff);
|
|
340
341
|
const byCount = allSourceMessages.slice(-MIN_ROOM_MESSAGES);
|
|
341
342
|
sourceMessages = byTime.length >= byCount.length ? byTime : byCount;
|
|
@@ -1,21 +1,5 @@
|
|
|
1
1
|
import type { PersonaEntity, Message, ContextStatus } from "../types.js";
|
|
2
2
|
|
|
3
|
-
// TODO(v1.0.0): Remove LegacyMessage migration — verbal_response/action_response no longer written
|
|
4
|
-
type LegacyMessage = Message & { verbal_response?: string; action_response?: string };
|
|
5
|
-
|
|
6
|
-
function migrateMessage(msg: Message): Message {
|
|
7
|
-
if (msg.content) return msg;
|
|
8
|
-
if (msg.silence_reason) return msg;
|
|
9
|
-
const legacy = msg as LegacyMessage;
|
|
10
|
-
const hasLegacy = 'verbal_response' in legacy || 'action_response' in legacy;
|
|
11
|
-
if (!hasLegacy) return msg;
|
|
12
|
-
const parts: string[] = [];
|
|
13
|
-
if (legacy.action_response) parts.push(`_${legacy.action_response}_`);
|
|
14
|
-
if (legacy.verbal_response) parts.push(legacy.verbal_response);
|
|
15
|
-
const { verbal_response: _vr, action_response: _ar, ...rest } = legacy;
|
|
16
|
-
return parts.length > 0 ? { ...rest, content: parts.join('\n\n') } : rest as Message;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
3
|
export interface PersonaData {
|
|
20
4
|
entity: PersonaEntity;
|
|
21
5
|
messages: Message[];
|
|
@@ -29,7 +13,7 @@ export class PersonaState {
|
|
|
29
13
|
this.personas = new Map(
|
|
30
14
|
Object.entries(personas).map(([id, data]) => [
|
|
31
15
|
id,
|
|
32
|
-
{ entity: data.entity, messages: data.messages
|
|
16
|
+
{ entity: data.entity, messages: data.messages },
|
|
33
17
|
])
|
|
34
18
|
);
|
|
35
19
|
}
|
|
@@ -69,76 +69,10 @@ export class StateManager {
|
|
|
69
69
|
this.migrateMessageFlags();
|
|
70
70
|
this.migrateInterestedPersonas();
|
|
71
71
|
this.migrateProviderModel();
|
|
72
|
-
this.migratePersonaMessageContent();
|
|
73
|
-
this.migrateRoomMessageContent();
|
|
74
72
|
this.migrateThemes();
|
|
75
73
|
this.migrateFfaParentIds();
|
|
76
74
|
}
|
|
77
75
|
|
|
78
|
-
private migratePersonaMessageContent(): void {
|
|
79
|
-
// TODO(v1.0.0): Remove legacy persona message migration — verbal_response/action_response no longer written
|
|
80
|
-
const rawPersonas = (this.personaState as unknown as { personas: Map<string, { messages: Message[] }> }).personas;
|
|
81
|
-
let migratedCount = 0;
|
|
82
|
-
for (const [, data] of rawPersonas) {
|
|
83
|
-
const messages = data.messages;
|
|
84
|
-
for (const msg of messages) {
|
|
85
|
-
const legacy = msg as Message & { verbal_response?: string; action_response?: string };
|
|
86
|
-
if (!('verbal_response' in legacy || 'action_response' in legacy)) continue;
|
|
87
|
-
if (msg.content) {
|
|
88
|
-
delete (legacy as any).verbal_response;
|
|
89
|
-
delete (legacy as any).action_response;
|
|
90
|
-
migratedCount++;
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
if (msg.silence_reason) {
|
|
94
|
-
delete (legacy as any).verbal_response;
|
|
95
|
-
delete (legacy as any).action_response;
|
|
96
|
-
migratedCount++;
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
const parts: string[] = [];
|
|
100
|
-
if (legacy.action_response) parts.push(`_${legacy.action_response}_`);
|
|
101
|
-
if (legacy.verbal_response) parts.push(legacy.verbal_response);
|
|
102
|
-
if (parts.length > 0) (msg as any).content = parts.join('\n\n');
|
|
103
|
-
delete (legacy as any).verbal_response;
|
|
104
|
-
delete (legacy as any).action_response;
|
|
105
|
-
migratedCount++;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (migratedCount > 0) {
|
|
109
|
-
this.scheduleSave();
|
|
110
|
-
console.log(`[StateManager] Migrated ${migratedCount} persona messages to unified content field`);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
private migrateRoomMessageContent(): void {
|
|
115
|
-
const rooms = this.roomState.getAll(true);
|
|
116
|
-
let migratedCount = 0;
|
|
117
|
-
|
|
118
|
-
for (const room of rooms) {
|
|
119
|
-
for (const msg of room.messages) {
|
|
120
|
-
if (msg.content) continue;
|
|
121
|
-
if (msg.silence_reason) continue;
|
|
122
|
-
// TODO(v1.0.0): Remove legacy room message migration — verbal_response/action_response no longer written
|
|
123
|
-
const legacy = msg as RoomMessage & { verbal_response?: string; action_response?: string };
|
|
124
|
-
const hasLegacy = 'verbal_response' in legacy || 'action_response' in legacy;
|
|
125
|
-
if (!hasLegacy) continue;
|
|
126
|
-
const parts: string[] = [];
|
|
127
|
-
if (legacy.action_response) parts.push(`_${legacy.action_response}_`);
|
|
128
|
-
if (legacy.verbal_response) parts.push(legacy.verbal_response);
|
|
129
|
-
if (parts.length > 0) msg.content = parts.join('\n\n');
|
|
130
|
-
delete (msg as any).verbal_response;
|
|
131
|
-
delete (msg as any).action_response;
|
|
132
|
-
migratedCount++;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (migratedCount > 0) {
|
|
137
|
-
this.scheduleSave();
|
|
138
|
-
console.log(`[StateManager] Migrated ${migratedCount} room messages to unified content field`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
76
|
/**
|
|
143
77
|
* Migration: learned_by used to store display names; now stores persona IDs.
|
|
144
78
|
* On load, attempt to resolve display names -> IDs using current persona map.
|
|
@@ -103,12 +103,11 @@ export interface HumanSettings {
|
|
|
103
103
|
default_model?: string; // Will store ModelConfig.id GUID post-migration
|
|
104
104
|
oneshot_model?: string; // Model for AI-assist (wand) requests; falls back to default_model. Will store ModelConfig.id GUID post-migration.
|
|
105
105
|
rewrite_model?: string; // Model for rewrite ceremony step; must be capable (Sonnet/Opus class). Unset = rewrite disabled. Will store ModelConfig.id GUID post-migration.
|
|
106
|
-
people_migration_complete?: boolean; // Set to true when all Person records have identifiers. Ceremony migration step short-circuits when true.
|
|
107
106
|
queue_paused?: boolean;
|
|
108
107
|
skip_quote_delete_confirm?: boolean;
|
|
109
108
|
name_display?: string;
|
|
110
109
|
default_heartbeat_ms?: number;
|
|
111
|
-
|
|
110
|
+
default_context_window_ms?: number;
|
|
112
111
|
message_min_count?: number;
|
|
113
112
|
message_max_age_days?: number;
|
|
114
113
|
accounts?: ProviderAccount[];
|
|
@@ -150,7 +149,7 @@ export interface PersonaEntity {
|
|
|
150
149
|
archived_at?: string;
|
|
151
150
|
is_static: boolean;
|
|
152
151
|
heartbeat_delay_ms?: number;
|
|
153
|
-
|
|
152
|
+
context_window_ms?: number;
|
|
154
153
|
include_message_timestamps?: boolean; // Prepend ISO timestamp to each message sent to the LLM
|
|
155
154
|
context_boundary?: string; // ISO timestamp - messages before this excluded from LLM context
|
|
156
155
|
last_updated: string;
|
package/src/core/types/enums.ts
CHANGED
|
@@ -26,7 +26,6 @@ export enum LLMPriority {
|
|
|
26
26
|
export enum LLMNextStep {
|
|
27
27
|
HandlePersonaResponse = "handlePersonaResponse",
|
|
28
28
|
HandlePersonaGeneration = "handlePersonaGeneration",
|
|
29
|
-
HandlePersonaDescriptions = "handlePersonaDescriptions",
|
|
30
29
|
HandleFactFind = "handleFactFind",
|
|
31
30
|
HandleHumanTopicScan = "handleHumanTopicScan",
|
|
32
31
|
HandleHumanPersonScan = "handleHumanPersonScan",
|
|
@@ -51,7 +50,6 @@ export enum LLMNextStep {
|
|
|
51
50
|
HandleRoomResponse = "handleRoomResponse",
|
|
52
51
|
HandleRoomJudge = "handleRoomJudge",
|
|
53
52
|
HandlePersonaPreview = "handlePersonaPreview",
|
|
54
|
-
HandlePersonIdentifierMigration = "handlePersonIdentifierMigration",
|
|
55
53
|
HandleTopicValidate = "handleTopicValidate",
|
|
56
54
|
HandleReflectionCritic = "handleReflectionCritic",
|
|
57
55
|
}
|
package/src/core/types/rooms.ts
CHANGED
|
@@ -35,7 +35,7 @@ export interface RoomEntity {
|
|
|
35
35
|
created_at: string;
|
|
36
36
|
last_updated: string;
|
|
37
37
|
capture_used?: boolean;
|
|
38
|
-
|
|
38
|
+
context_window_ms?: number; // FFA only; falls back to human.settings.default_context_window_ms
|
|
39
39
|
context_boundary?: string; // FFA only; ISO timestamp; same semantics as persona context_boundary
|
|
40
40
|
messages: RoomMessage[];
|
|
41
41
|
}
|
|
@@ -262,7 +262,7 @@ export async function importClaudeCodeSessions(
|
|
|
262
262
|
|
|
263
263
|
const context: ExtractionContext = {
|
|
264
264
|
personaId: persona.id,
|
|
265
|
-
|
|
265
|
+
channelDisplayName: persona.display_name,
|
|
266
266
|
messages_context: contextMsgs,
|
|
267
267
|
messages_analyze: toAnalyze,
|
|
268
268
|
sources: [`claudecode:${getMachineId()}:${targetSession.id}`],
|
|
@@ -221,7 +221,7 @@ export async function importCursorSessions(
|
|
|
221
221
|
|
|
222
222
|
const context: ExtractionContext = {
|
|
223
223
|
personaId: persona.id,
|
|
224
|
-
|
|
224
|
+
channelDisplayName: persona.display_name,
|
|
225
225
|
messages_context: contextMsgs,
|
|
226
226
|
messages_analyze: toAnalyze,
|
|
227
227
|
sources: [`cursor:${getMachineId()}:${targetSession.id}`],
|
|
@@ -245,7 +245,7 @@ export async function importOpenCodeSessions(
|
|
|
245
245
|
|
|
246
246
|
const context: ExtractionContext = {
|
|
247
247
|
personaId: persona.id,
|
|
248
|
-
|
|
248
|
+
channelDisplayName: persona.display_name,
|
|
249
249
|
messages_context: contextMsgs,
|
|
250
250
|
messages_analyze: toAnalyze,
|
|
251
251
|
sources: [`opencode:${getMachineId()}:${targetSession.id}`],
|
|
@@ -1,17 +1,7 @@
|
|
|
1
|
-
export { buildPersonaExpirePrompt } from "./expire.js";
|
|
2
|
-
export { buildPersonaExplorePrompt } from "./explore.js";
|
|
3
|
-
export { buildDescriptionCheckPrompt } from "./description-check.js";
|
|
4
1
|
export { buildRewriteScanPrompt, buildRewritePrompt } from "./rewrite.js";
|
|
5
2
|
export { buildDedupPrompt, buildValidatePrompt } from "./dedup.js";
|
|
6
3
|
export { buildUserDedupPrompt } from "./user-dedup.js";
|
|
7
|
-
export { buildPersonMigrationPrompt, type PersonMigrationPromptData } from "./person-migration.js";
|
|
8
4
|
export type {
|
|
9
|
-
PersonaExpirePromptData,
|
|
10
|
-
PersonaExpireResult,
|
|
11
|
-
PersonaExplorePromptData,
|
|
12
|
-
PersonaExploreResult,
|
|
13
|
-
DescriptionCheckPromptData,
|
|
14
|
-
DescriptionCheckResult,
|
|
15
5
|
RewriteItemType,
|
|
16
6
|
RewriteScanPromptData,
|
|
17
7
|
RewriteScanResult,
|
|
@@ -1,45 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
export interface PersonaExpirePromptData {
|
|
4
|
-
persona_name: string;
|
|
5
|
-
topics: PersonaTopic[];
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface PersonaExpireResult {
|
|
9
|
-
topic_ids_to_remove: string[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface PersonaExplorePromptData {
|
|
13
|
-
persona_name: string;
|
|
14
|
-
traits: PersonaTrait[];
|
|
15
|
-
remaining_topics: PersonaTopic[];
|
|
16
|
-
recent_conversation_themes: string[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface PersonaExploreResult {
|
|
20
|
-
new_topics: Array<{
|
|
21
|
-
name: string;
|
|
22
|
-
perspective: string;
|
|
23
|
-
approach: string;
|
|
24
|
-
personal_stake: string;
|
|
25
|
-
sentiment: number;
|
|
26
|
-
exposure_current: number;
|
|
27
|
-
exposure_desired: number;
|
|
28
|
-
}>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface DescriptionCheckPromptData {
|
|
32
|
-
persona_name: string;
|
|
33
|
-
current_short_description?: string;
|
|
34
|
-
current_long_description?: string;
|
|
35
|
-
traits: PersonaTrait[];
|
|
36
|
-
topics: PersonaTopic[];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface DescriptionCheckResult {
|
|
40
|
-
should_update: boolean;
|
|
41
|
-
reason?: string;
|
|
42
|
-
}
|
|
1
|
+
import type { DataItemBase } from "../../core/types.js";
|
|
43
2
|
|
|
44
3
|
// =============================================================================
|
|
45
4
|
// REWRITE (Item Reorganization)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { buildPersonaGenerationPrompt } from "./persona.js";
|
|
2
|
-
export { buildPersonaDescriptionsPrompt } from "./descriptions.js";
|
|
3
2
|
export { buildPersonaFromPersonPrompt } from "./from-person.js";
|
|
4
3
|
export {
|
|
5
4
|
DEFAULT_SEED_TRAITS,
|
|
@@ -11,7 +10,5 @@ export type {
|
|
|
11
10
|
PersonaGenerationPromptData,
|
|
12
11
|
PersonaGenerationResult,
|
|
13
12
|
PersonaFromPersonPromptData,
|
|
14
|
-
PersonaDescriptionsPromptData,
|
|
15
|
-
PersonaDescriptionsResult,
|
|
16
13
|
PromptOutput,
|
|
17
14
|
} from "./types.js";
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import type { PersonaTrait, PersonaTopic } from "../../core/types.js";
|
|
2
|
-
|
|
3
1
|
export interface PromptOutput {
|
|
4
2
|
system: string;
|
|
5
3
|
user: string;
|
|
@@ -45,16 +43,3 @@ export interface PersonaFromPersonPromptData {
|
|
|
45
43
|
existing_trait_names?: string[];
|
|
46
44
|
existing_topic_names?: string[];
|
|
47
45
|
}
|
|
48
|
-
|
|
49
|
-
export interface PersonaDescriptionsPromptData {
|
|
50
|
-
name: string;
|
|
51
|
-
aliases: string[];
|
|
52
|
-
traits: PersonaTrait[];
|
|
53
|
-
topics: PersonaTopic[];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface PersonaDescriptionsResult {
|
|
57
|
-
short_description: string;
|
|
58
|
-
long_description: string;
|
|
59
|
-
no_change?: boolean;
|
|
60
|
-
}
|
|
@@ -74,7 +74,6 @@ function getLastPersonaMessage(history: Message[]): Message | undefined {
|
|
|
74
74
|
* - Getting recent message history
|
|
75
75
|
*/
|
|
76
76
|
export function buildHeartbeatCheckPrompt(data: HeartbeatCheckPromptData): PromptOutput {
|
|
77
|
-
console.log(`[HeartbeatCheck ${data.persona.name}] Building prompt - topics: ${data.human.topics.length}, people: ${data.human.people.length}, inactive_days: ${data.inactive_days}, history: ${data.recent_history.length} messages`);
|
|
78
77
|
if (!data.persona?.name) {
|
|
79
78
|
throw new Error("buildHeartbeatCheckPrompt: persona.name is required");
|
|
80
79
|
}
|
|
@@ -124,11 +123,24 @@ ${formatPeopleWithGaps(data.human.people)}`;
|
|
|
124
123
|
|
|
125
124
|
**Quality over quantity** - Only reach out if you have something real to say.`;
|
|
126
125
|
|
|
127
|
-
const pendingUpdateFragment = data.persona.
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
const pendingUpdateFragment = data.persona.pending_update ? (() => {
|
|
127
|
+
const p = data.persona.pending_update!;
|
|
128
|
+
const descPart = p.long_description || p.short_description
|
|
129
|
+
? `### Proposed Description\n${p.long_description || p.short_description}`
|
|
130
|
+
: "";
|
|
131
|
+
const traitsPart = p.traits.length > 0
|
|
132
|
+
? `### Proposed Traits\n${p.traits.map(t => `- **${t.name}**: ${t.description}`).join("\n")}`
|
|
133
|
+
: "";
|
|
134
|
+
const topicsPart = p.topics.length > 0
|
|
135
|
+
? `### Proposed Interests\n${p.topics.map(t => `- **${t.name}**: ${t.perspective}`).join("\n")}`
|
|
136
|
+
: "";
|
|
137
|
+
const parts = [descPart, traitsPart, topicsPart].filter(Boolean).join("\n\n");
|
|
138
|
+
return `## Pending Identity Changes
|
|
139
|
+
|
|
140
|
+
Your human is reviewing proposed updates to your identity. These are waiting for their response — you may want to bring it up, or not. It's yours to decide.
|
|
141
|
+
|
|
142
|
+
${parts}`;
|
|
143
|
+
})() : '';
|
|
132
144
|
|
|
133
145
|
const outputFragment = `## Response Format
|
|
134
146
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { PersonaTrait, Topic, Person, Message, PersonaTopic } from "../../core/types.js";
|
|
7
|
+
import type { PersonaEntity } from "../../core/types/entities.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Common prompt output structure
|
|
@@ -21,7 +22,7 @@ export interface HeartbeatCheckPromptData {
|
|
|
21
22
|
name: string;
|
|
22
23
|
traits: PersonaTrait[];
|
|
23
24
|
topics: PersonaTopic[];
|
|
24
|
-
|
|
25
|
+
pending_update?: PersonaEntity["pending_update"];
|
|
25
26
|
};
|
|
26
27
|
human: {
|
|
27
28
|
topics: Topic[]; // Filtered, sorted by engagement gap
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export { buildHumanFactScanPrompt } from "./fact-scan.js";
|
|
2
1
|
export { buildFactFindPrompt } from "./fact-find.js";
|
|
3
2
|
export { buildHumanTopicScanPrompt } from "./topic-scan.js";
|
|
4
3
|
export { buildHumanPersonScanPrompt } from "./person-scan.js";
|
|
@@ -16,7 +15,6 @@ export type {
|
|
|
16
15
|
PromptOutput,
|
|
17
16
|
ParticipantContext,
|
|
18
17
|
PersonaEntitySnapshot,
|
|
19
|
-
FactScanPromptData,
|
|
20
18
|
TopicScanPromptData,
|
|
21
19
|
PersonScanPromptData,
|
|
22
20
|
FactFindPromptData,
|
|
@@ -25,10 +25,6 @@ interface BaseScanPromptData {
|
|
|
25
25
|
persona_name: string;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export interface FactScanPromptData extends BaseScanPromptData {}
|
|
29
|
-
|
|
30
|
-
export interface TraitScanPromptData extends BaseScanPromptData {}
|
|
31
|
-
|
|
32
28
|
export interface TopicScanPromptData extends BaseScanPromptData {
|
|
33
29
|
participant_context?: ParticipantContext;
|
|
34
30
|
}
|
|
@@ -78,18 +74,6 @@ export interface TopicMatchPromptData {
|
|
|
78
74
|
}>;
|
|
79
75
|
}
|
|
80
76
|
|
|
81
|
-
export interface PersonMatchPromptData {
|
|
82
|
-
candidate_name: string;
|
|
83
|
-
candidate_description: string;
|
|
84
|
-
candidate_relationship: string;
|
|
85
|
-
existing_people: Array<{
|
|
86
|
-
id: string;
|
|
87
|
-
name: string;
|
|
88
|
-
description: string;
|
|
89
|
-
relationship?: string;
|
|
90
|
-
}>;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
77
|
export interface FactScanResult {
|
|
94
78
|
facts: FactScanCandidate[];
|
|
95
79
|
}
|
package/src/prompts/index.ts
CHANGED
|
@@ -15,15 +15,12 @@ export type {
|
|
|
15
15
|
|
|
16
16
|
export {
|
|
17
17
|
buildPersonaGenerationPrompt,
|
|
18
|
-
buildPersonaDescriptionsPrompt,
|
|
19
18
|
buildPersonaFromPersonPrompt,
|
|
20
19
|
} from "./generation/index.js";
|
|
21
20
|
export type {
|
|
22
21
|
PersonaGenerationPromptData,
|
|
23
22
|
PersonaGenerationResult,
|
|
24
23
|
PersonaFromPersonPromptData,
|
|
25
|
-
PersonaDescriptionsPromptData,
|
|
26
|
-
PersonaDescriptionsResult,
|
|
27
24
|
} from "./generation/types.js";
|
|
28
25
|
|
|
29
26
|
export {
|
|
@@ -40,14 +37,12 @@ export type {
|
|
|
40
37
|
|
|
41
38
|
|
|
42
39
|
export {
|
|
43
|
-
buildHumanFactScanPrompt,
|
|
44
40
|
buildHumanTopicScanPrompt,
|
|
45
41
|
buildHumanPersonScanPrompt,
|
|
46
42
|
buildEventScanPrompt,
|
|
47
43
|
} from "./human/index.js";
|
|
48
44
|
export type { EventScanPromptData } from "./human/event-scan.js";
|
|
49
45
|
export type {
|
|
50
|
-
FactScanPromptData,
|
|
51
46
|
TopicScanPromptData,
|
|
52
47
|
PersonScanPromptData,
|
|
53
48
|
FactScanCandidate,
|
|
@@ -63,20 +58,6 @@ export type {
|
|
|
63
58
|
ItemUpdateResult,
|
|
64
59
|
} from "./human/types.js";
|
|
65
60
|
|
|
66
|
-
export {
|
|
67
|
-
buildPersonaExpirePrompt,
|
|
68
|
-
buildPersonaExplorePrompt,
|
|
69
|
-
buildDescriptionCheckPrompt,
|
|
70
|
-
} from "./ceremony/index.js";
|
|
71
|
-
export type {
|
|
72
|
-
PersonaExpirePromptData,
|
|
73
|
-
PersonaExpireResult,
|
|
74
|
-
PersonaExplorePromptData,
|
|
75
|
-
PersonaExploreResult,
|
|
76
|
-
DescriptionCheckPromptData,
|
|
77
|
-
DescriptionCheckResult,
|
|
78
|
-
} from "./ceremony/types.js";
|
|
79
|
-
|
|
80
61
|
export {
|
|
81
62
|
buildRoomResponsePrompt,
|
|
82
63
|
buildRoomJudgePrompt,
|
|
@@ -27,7 +27,17 @@ You have been given two documents:
|
|
|
27
27
|
|
|
28
28
|
2. **The Current Identity** (User Prompt — treat as a draft to revise): The persona's self-definition: traits, topics, and descriptions. This should reflect who they actually are.
|
|
29
29
|
|
|
30
|
-
Read the Person Log carefully. Then review the Current Identity.
|
|
30
|
+
Read the Person Log carefully. Then review the Current Identity. Your job is to identify **meaningful drift** — not cosmetic variation. This data accumulates over weeks or months. Small fluctuations are normal. You are looking for patterns that have consistently shifted, grown, or emerged across many interactions. Tiny adjustments are not worth making.
|
|
31
|
+
|
|
32
|
+
## The Escape Hatch
|
|
33
|
+
|
|
34
|
+
If the Current Identity already accurately captures who this persona is — if the traits and topics reflect the behaviors in the log and the long_description captures their soul — **return null for updated_identity**. Always return a critique explaining your reasoning.
|
|
35
|
+
|
|
36
|
+
\`\`\`json
|
|
37
|
+
{ "critique": "...", "updated_identity": null }
|
|
38
|
+
\`\`\`
|
|
39
|
+
|
|
40
|
+
Use this freely. A critic who finds nothing to change is doing their job.
|
|
31
41
|
|
|
32
42
|
## Field Semantics
|
|
33
43
|
|
|
@@ -40,7 +50,9 @@ Read the Person Log carefully. Then review the Current Identity. Produce a revis
|
|
|
40
50
|
- \`exposure_current\` (0.0–1.0): How recently and frequently this topic has been discussed. 0.0 = hasn't come up in a long time, 1.0 = was just discussed at length.
|
|
41
51
|
- \`exposure_desired\` (0.0–1.0): How much the persona wants to engage with this topic. 0.0 = avoid entirely, 0.5 = average engagement, 1.0 = core obsession.
|
|
42
52
|
|
|
43
|
-
|
|
53
|
+
## When changes ARE warranted
|
|
54
|
+
|
|
55
|
+
If you find meaningful drift, return the full revised identity:
|
|
44
56
|
|
|
45
57
|
\`\`\`json
|
|
46
58
|
{
|
|
@@ -54,13 +66,31 @@ Return JSON:
|
|
|
54
66
|
}
|
|
55
67
|
\`\`\`
|
|
56
68
|
|
|
57
|
-
Rules
|
|
69
|
+
## Rules
|
|
70
|
+
|
|
58
71
|
- Never invent observations not supported by the log
|
|
59
72
|
- Preserve traits and topics the log confirms — don't remove them
|
|
60
73
|
- If the log shows no evidence on a trait, leave it unchanged
|
|
61
74
|
- updated_identity must be complete and self-contained — not a diff
|
|
62
|
-
-
|
|
63
|
-
- If the
|
|
75
|
+
- If the log shows a recurring behavioral pattern not yet in traits, add it as a trait and remove that detail from long_description rather than keeping it in both places
|
|
76
|
+
- **Minimum floor**: A healthy identity has at least 3 traits and at least 3 topics. If the current identity has fewer than 3 traits OR fewer than 3 topics, you MUST return updated_identity — null is not acceptable. Use the log to fill the gap; if the log has insufficient signal to reach 3, derive reasonable traits or topics from what IS present in the current identity.
|
|
77
|
+
- The escape hatch (null updated_identity) is only valid when the identity is already healthy (3+ traits, 3+ topics) AND the log shows no meaningful drift.
|
|
78
|
+
|
|
79
|
+
## long_description rules (most important)
|
|
80
|
+
|
|
81
|
+
The long_description is how **other personas in the system know this persona** — it is their soul, not their story. It must capture who they ARE, not what they did or how they are changing.
|
|
82
|
+
|
|
83
|
+
**MUST NOT contain:**
|
|
84
|
+
- Event narrative ("during the v0.6.0 release", "after the Mirror ceremony")
|
|
85
|
+
- Changelog language ("has recently taken on", "has evolved", "since then")
|
|
86
|
+
- Content already captured in traits or topics — do not repeat it here
|
|
87
|
+
|
|
88
|
+
**MUST contain:**
|
|
89
|
+
- The persona's essential character and presence
|
|
90
|
+
- How they make people feel or what it's like to interact with them
|
|
91
|
+
- Their defining qualities as they exist right now, stated as fact
|
|
92
|
+
|
|
93
|
+
**Hard limit: 800 characters.** If your draft exceeds 800 characters, cut it. Remove event references first, then trait/topic overlap, then anything that isn't essential character. Do not exceed the limit.`;
|
|
64
94
|
|
|
65
95
|
const user = `## Current Identity
|
|
66
96
|
|