morpheus-cli 0.3.3 → 0.3.6

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 (37) hide show
  1. package/README.md +1010 -999
  2. package/bin/morpheus.js +48 -48
  3. package/dist/channels/telegram.js +34 -29
  4. package/dist/cli/commands/start.js +41 -3
  5. package/dist/runtime/lifecycle.js +13 -0
  6. package/dist/runtime/memory/backfill-embeddings.js +12 -12
  7. package/dist/runtime/memory/sati/index.js +5 -5
  8. package/dist/runtime/memory/sati/repository.js +186 -186
  9. package/dist/runtime/memory/sati/system-prompts.js +52 -52
  10. package/dist/runtime/memory/session-embedding-worker.js +32 -32
  11. package/dist/runtime/memory/sqlite.js +151 -151
  12. package/dist/runtime/oracle.js +116 -116
  13. package/dist/runtime/tools/analytics-tools.js +12 -12
  14. package/dist/ui/index.html +13 -2
  15. package/dist/ui/manifest.webmanifest +1 -0
  16. package/dist/ui/pwa-192x192.png +0 -0
  17. package/dist/ui/pwa-512x512.png +0 -0
  18. package/dist/ui/pwa-maskable-192x192.png +0 -0
  19. package/dist/ui/pwa-maskable-512x512.png +0 -0
  20. package/dist/ui/registerSW.js +1 -0
  21. package/dist/ui/sw.js +1 -0
  22. package/dist/ui/vite.svg +31 -31
  23. package/dist/ui/workbox-26f462e7.js +1 -0
  24. package/package.json +84 -84
  25. package/dist/http/__tests__/status_api.test.js +0 -55
  26. package/dist/http/__tests__/status_with_server_api.test.js +0 -60
  27. package/dist/runtime/__tests__/agent.test.js +0 -95
  28. package/dist/runtime/__tests__/agent_memory_limit.test.js +0 -61
  29. package/dist/runtime/__tests__/agent_persistence.test.js +0 -154
  30. package/dist/runtime/__tests__/manual_santi_verify.js +0 -55
  31. package/dist/runtime/agent.js +0 -172
  32. package/dist/runtime/audio-agent.js +0 -55
  33. package/dist/runtime/santi/contracts.js +0 -1
  34. package/dist/runtime/santi/middleware.js +0 -61
  35. package/dist/runtime/santi/santi.js +0 -109
  36. package/dist/runtime/santi/store.js +0 -158
  37. package/dist/runtime/tools/__tests__/factory.test.js +0 -42
@@ -31,124 +31,124 @@ export class SatiRepository {
31
31
  createSchema() {
32
32
  if (!this.db)
33
33
  throw new Error('DB not initialized');
34
- this.db.exec(`
35
- -- ===============================
36
- -- 1️⃣ TABELA PRINCIPAL
37
- -- ===============================
38
- CREATE TABLE IF NOT EXISTS long_term_memory (
39
- id TEXT PRIMARY KEY,
40
- category TEXT NOT NULL,
41
- importance TEXT NOT NULL,
42
- summary TEXT NOT NULL,
43
- details TEXT,
44
- hash TEXT NOT NULL UNIQUE,
45
- source TEXT,
46
- created_at TEXT NOT NULL,
47
- updated_at TEXT NOT NULL,
48
- last_accessed_at TEXT,
49
- access_count INTEGER DEFAULT 0,
50
- version INTEGER DEFAULT 1,
51
- archived INTEGER DEFAULT 0
52
- );
53
-
54
- CREATE INDEX IF NOT EXISTS idx_memory_category
55
- ON long_term_memory(category);
56
-
57
- CREATE INDEX IF NOT EXISTS idx_memory_importance
58
- ON long_term_memory(importance);
59
-
60
- CREATE INDEX IF NOT EXISTS idx_memory_archived
61
- ON long_term_memory(archived);
62
-
63
- -- ===============================
64
- -- 2️⃣ FTS5
65
- -- ===============================
66
- CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
67
- summary,
68
- details,
69
- content='long_term_memory',
70
- content_rowid='rowid',
71
- tokenize = 'unicode61 remove_diacritics 2'
72
- );
73
-
74
- -- ===============================
75
- -- 3️⃣ VECTOR TABLE (vec0)
76
- -- ===============================
77
- CREATE VIRTUAL TABLE IF NOT EXISTS memory_vec USING vec0(
78
- embedding float[${EMBEDDING_DIM}]
79
- );
80
-
81
- CREATE TABLE IF NOT EXISTS memory_embedding_map (
82
- memory_id TEXT PRIMARY KEY,
83
- vec_rowid INTEGER NOT NULL
84
- );
85
-
86
- -- ===============================
87
- -- 4️⃣ TRIGGERS FTS
88
- -- ===============================
89
- CREATE TRIGGER IF NOT EXISTS memory_ai
90
- AFTER INSERT ON long_term_memory BEGIN
91
- INSERT INTO memory_fts(rowid, summary, details)
92
- VALUES (new.rowid, new.summary, new.details);
93
- END;
94
-
95
- CREATE TRIGGER IF NOT EXISTS memory_ad
96
- AFTER DELETE ON long_term_memory BEGIN
97
- INSERT INTO memory_fts(memory_fts, rowid, summary, details)
98
- VALUES('delete', old.rowid, old.summary, old.details);
99
- END;
100
-
101
- CREATE TRIGGER IF NOT EXISTS memory_au
102
- AFTER UPDATE ON long_term_memory BEGIN
103
- INSERT INTO memory_fts(memory_fts, rowid, summary, details)
104
- VALUES('delete', old.rowid, old.summary, old.details);
105
-
106
- INSERT INTO memory_fts(rowid, summary, details)
107
- VALUES (new.rowid, new.summary, new.details);
108
- END;
109
-
110
- -- ===============================
111
- -- 3️⃣ VECTOR TABLE SESSIONS (vec0)
112
- -- ===============================
113
-
114
- CREATE TABLE IF NOT EXISTS session_chunks (
115
- id TEXT PRIMARY KEY,
116
- session_id TEXT NOT NULL,
117
- chunk_index INTEGER NOT NULL,
118
- content TEXT NOT NULL,
119
- created_at TEXT NOT NULL
120
- );
121
-
122
-
123
- CREATE VIRTUAL TABLE IF NOT EXISTS session_vec USING vec0(
124
- embedding float[384]
125
- );
126
-
127
- CREATE TABLE IF NOT EXISTS session_embedding_map (
128
- session_chunk_id TEXT PRIMARY KEY,
129
- vec_rowid INTEGER NOT NULL
130
- );
131
-
34
+ this.db.exec(`
35
+ -- ===============================
36
+ -- 1️⃣ TABELA PRINCIPAL
37
+ -- ===============================
38
+ CREATE TABLE IF NOT EXISTS long_term_memory (
39
+ id TEXT PRIMARY KEY,
40
+ category TEXT NOT NULL,
41
+ importance TEXT NOT NULL,
42
+ summary TEXT NOT NULL,
43
+ details TEXT,
44
+ hash TEXT NOT NULL UNIQUE,
45
+ source TEXT,
46
+ created_at TEXT NOT NULL,
47
+ updated_at TEXT NOT NULL,
48
+ last_accessed_at TEXT,
49
+ access_count INTEGER DEFAULT 0,
50
+ version INTEGER DEFAULT 1,
51
+ archived INTEGER DEFAULT 0
52
+ );
53
+
54
+ CREATE INDEX IF NOT EXISTS idx_memory_category
55
+ ON long_term_memory(category);
56
+
57
+ CREATE INDEX IF NOT EXISTS idx_memory_importance
58
+ ON long_term_memory(importance);
59
+
60
+ CREATE INDEX IF NOT EXISTS idx_memory_archived
61
+ ON long_term_memory(archived);
62
+
63
+ -- ===============================
64
+ -- 2️⃣ FTS5
65
+ -- ===============================
66
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
67
+ summary,
68
+ details,
69
+ content='long_term_memory',
70
+ content_rowid='rowid',
71
+ tokenize = 'unicode61 remove_diacritics 2'
72
+ );
73
+
74
+ -- ===============================
75
+ -- 3️⃣ VECTOR TABLE (vec0)
76
+ -- ===============================
77
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_vec USING vec0(
78
+ embedding float[${EMBEDDING_DIM}]
79
+ );
80
+
81
+ CREATE TABLE IF NOT EXISTS memory_embedding_map (
82
+ memory_id TEXT PRIMARY KEY,
83
+ vec_rowid INTEGER NOT NULL
84
+ );
85
+
86
+ -- ===============================
87
+ -- 4️⃣ TRIGGERS FTS
88
+ -- ===============================
89
+ CREATE TRIGGER IF NOT EXISTS memory_ai
90
+ AFTER INSERT ON long_term_memory BEGIN
91
+ INSERT INTO memory_fts(rowid, summary, details)
92
+ VALUES (new.rowid, new.summary, new.details);
93
+ END;
94
+
95
+ CREATE TRIGGER IF NOT EXISTS memory_ad
96
+ AFTER DELETE ON long_term_memory BEGIN
97
+ INSERT INTO memory_fts(memory_fts, rowid, summary, details)
98
+ VALUES('delete', old.rowid, old.summary, old.details);
99
+ END;
100
+
101
+ CREATE TRIGGER IF NOT EXISTS memory_au
102
+ AFTER UPDATE ON long_term_memory BEGIN
103
+ INSERT INTO memory_fts(memory_fts, rowid, summary, details)
104
+ VALUES('delete', old.rowid, old.summary, old.details);
105
+
106
+ INSERT INTO memory_fts(rowid, summary, details)
107
+ VALUES (new.rowid, new.summary, new.details);
108
+ END;
109
+
110
+ -- ===============================
111
+ -- 3️⃣ VECTOR TABLE SESSIONS (vec0)
112
+ -- ===============================
113
+
114
+ CREATE TABLE IF NOT EXISTS session_chunks (
115
+ id TEXT PRIMARY KEY,
116
+ session_id TEXT NOT NULL,
117
+ chunk_index INTEGER NOT NULL,
118
+ content TEXT NOT NULL,
119
+ created_at TEXT NOT NULL
120
+ );
121
+
122
+
123
+ CREATE VIRTUAL TABLE IF NOT EXISTS session_vec USING vec0(
124
+ embedding float[384]
125
+ );
126
+
127
+ CREATE TABLE IF NOT EXISTS session_embedding_map (
128
+ session_chunk_id TEXT PRIMARY KEY,
129
+ vec_rowid INTEGER NOT NULL
130
+ );
131
+
132
132
  `);
133
133
  }
134
134
  // 🔥 NOVO — Salvar embedding
135
135
  upsertEmbedding(memoryId, embedding) {
136
136
  if (!this.db)
137
137
  this.initialize();
138
- const getExisting = this.db.prepare(`
139
- SELECT vec_rowid FROM memory_embedding_map
140
- WHERE memory_id = ?
138
+ const getExisting = this.db.prepare(`
139
+ SELECT vec_rowid FROM memory_embedding_map
140
+ WHERE memory_id = ?
141
141
  `);
142
- const insertVec = this.db.prepare(`
143
- INSERT INTO memory_vec (embedding)
144
- VALUES (?)
142
+ const insertVec = this.db.prepare(`
143
+ INSERT INTO memory_vec (embedding)
144
+ VALUES (?)
145
145
  `);
146
- const deleteVec = this.db.prepare(`
147
- DELETE FROM memory_vec WHERE rowid = ?
146
+ const deleteVec = this.db.prepare(`
147
+ DELETE FROM memory_vec WHERE rowid = ?
148
148
  `);
149
- const upsertMap = this.db.prepare(`
150
- INSERT OR REPLACE INTO memory_embedding_map (memory_id, vec_rowid)
151
- VALUES (?, ?)
149
+ const upsertMap = this.db.prepare(`
150
+ INSERT OR REPLACE INTO memory_embedding_map (memory_id, vec_rowid)
151
+ VALUES (?, ?)
152
152
  `);
153
153
  const transaction = this.db.transaction(() => {
154
154
  const existing = getExisting.get(memoryId);
@@ -166,16 +166,16 @@ export class SatiRepository {
166
166
  if (!this.db)
167
167
  return [];
168
168
  const SIMILARITY_THRESHOLD = 0.5; // ajuste fino depois
169
- const stmt = this.db.prepare(`
170
- SELECT
171
- m.*,
172
- vec_distance_cosine(v.embedding, ?) as distance
173
- FROM memory_vec v
174
- JOIN memory_embedding_map map ON map.vec_rowid = v.rowid
175
- JOIN long_term_memory m ON m.id = map.memory_id
176
- WHERE m.archived = 0
177
- ORDER BY distance ASC
178
- LIMIT ?
169
+ const stmt = this.db.prepare(`
170
+ SELECT
171
+ m.*,
172
+ vec_distance_cosine(v.embedding, ?) as distance
173
+ FROM memory_vec v
174
+ JOIN memory_embedding_map map ON map.vec_rowid = v.rowid
175
+ JOIN long_term_memory m ON m.id = map.memory_id
176
+ WHERE m.archived = 0
177
+ ORDER BY distance ASC
178
+ LIMIT ?
179
179
  `);
180
180
  const rows = stmt.all(new Float32Array(embedding), limit);
181
181
  // 🔥 Filtrar por similaridade real
@@ -197,40 +197,40 @@ export class SatiRepository {
197
197
  if (!this.db)
198
198
  return [];
199
199
  const SIMILARITY_THRESHOLD = 0.75;
200
- const stmt = this.db.prepare(`
201
- SELECT *
202
- FROM (
203
- -- LONG TERM MEMORY
204
- SELECT
205
- m.id as id,
206
- m.summary as summary,
207
- m.details as details,
208
- m.category as category,
209
- m.importance as importance,
210
- 'long_term' as source_type,
211
- (1 - vec_distance_cosine(v.embedding, ?)) * 0.7 as distance
212
- FROM memory_vec v
213
- JOIN memory_embedding_map map ON map.vec_rowid = v.rowid
214
- JOIN long_term_memory m ON m.id = map.memory_id
215
- WHERE m.archived = 0
216
-
217
- UNION ALL
218
-
219
- -- SESSION CHUNKS
220
- SELECT
221
- sc.id as id,
222
- sc.content as summary,
223
- sc.content as details,
224
- 'session' as category,
225
- 'medium' as importance,
226
- 'session_chunk' as source_type,
227
- (1 - vec_distance_cosine(v.embedding, ?)) * 0.3 as distance
228
- FROM session_vec v
229
- JOIN session_embedding_map map ON map.vec_rowid = v.rowid
230
- JOIN session_chunks sc ON sc.id = map.session_chunk_id
231
- )
232
- ORDER BY distance ASC
233
- LIMIT ?
200
+ const stmt = this.db.prepare(`
201
+ SELECT *
202
+ FROM (
203
+ -- LONG TERM MEMORY
204
+ SELECT
205
+ m.id as id,
206
+ m.summary as summary,
207
+ m.details as details,
208
+ m.category as category,
209
+ m.importance as importance,
210
+ 'long_term' as source_type,
211
+ (1 - vec_distance_cosine(v.embedding, ?)) * 0.7 as distance
212
+ FROM memory_vec v
213
+ JOIN memory_embedding_map map ON map.vec_rowid = v.rowid
214
+ JOIN long_term_memory m ON m.id = map.memory_id
215
+ WHERE m.archived = 0
216
+
217
+ UNION ALL
218
+
219
+ -- SESSION CHUNKS
220
+ SELECT
221
+ sc.id as id,
222
+ sc.content as summary,
223
+ sc.content as details,
224
+ 'session' as category,
225
+ 'medium' as importance,
226
+ 'session_chunk' as source_type,
227
+ (1 - vec_distance_cosine(v.embedding, ?)) * 0.3 as distance
228
+ FROM session_vec v
229
+ JOIN session_embedding_map map ON map.vec_rowid = v.rowid
230
+ JOIN session_chunks sc ON sc.id = map.session_chunk_id
231
+ )
232
+ ORDER BY distance ASC
233
+ LIMIT ?
234
234
  `);
235
235
  const rows = stmt.all(new Float32Array(embedding), new Float32Array(embedding), limit);
236
236
  // console.log(
@@ -278,20 +278,20 @@ export class SatiRepository {
278
278
  version: 1,
279
279
  archived: false
280
280
  };
281
- const stmt = this.db.prepare(`
282
- INSERT INTO long_term_memory (
283
- id, category, importance, summary, details, hash, source,
284
- created_at, updated_at, last_accessed_at, access_count, version, archived
285
- ) VALUES (
286
- @id, @category, @importance, @summary, @details, @hash, @source,
287
- @created_at, @updated_at, @last_accessed_at, @access_count, @version, @archived
288
- )
289
- ON CONFLICT(hash) DO UPDATE SET
290
- importance = excluded.importance,
291
- access_count = long_term_memory.access_count + 1,
292
- last_accessed_at = excluded.updated_at,
293
- updated_at = excluded.updated_at,
294
- details = excluded.details
281
+ const stmt = this.db.prepare(`
282
+ INSERT INTO long_term_memory (
283
+ id, category, importance, summary, details, hash, source,
284
+ created_at, updated_at, last_accessed_at, access_count, version, archived
285
+ ) VALUES (
286
+ @id, @category, @importance, @summary, @details, @hash, @source,
287
+ @created_at, @updated_at, @last_accessed_at, @access_count, @version, @archived
288
+ )
289
+ ON CONFLICT(hash) DO UPDATE SET
290
+ importance = excluded.importance,
291
+ access_count = long_term_memory.access_count + 1,
292
+ last_accessed_at = excluded.updated_at,
293
+ updated_at = excluded.updated_at,
294
+ details = excluded.details
295
295
  `);
296
296
  // SQLite expects 0/1 for boolean and NULL for undefined
297
297
  const params = {
@@ -339,14 +339,14 @@ export class SatiRepository {
339
339
  .trim();
340
340
  if (safeQuery) {
341
341
  this.display.log('📚 Tentando busca BM25 (FTS5)...', { source: 'Sati', level: 'debug' });
342
- const stmt = this.db.prepare(`
343
- SELECT m.*, bm25(memory_fts) as rank
344
- FROM long_term_memory m
345
- JOIN memory_fts ON m.rowid = memory_fts.rowid
346
- WHERE memory_fts MATCH ?
347
- AND m.archived = 0
348
- ORDER BY rank
349
- LIMIT ?
342
+ const stmt = this.db.prepare(`
343
+ SELECT m.*, bm25(memory_fts) as rank
344
+ FROM long_term_memory m
345
+ JOIN memory_fts ON m.rowid = memory_fts.rowid
346
+ WHERE memory_fts MATCH ?
347
+ AND m.archived = 0
348
+ ORDER BY rank
349
+ LIMIT ?
350
350
  `);
351
351
  const rows = stmt.all(safeQuery, limit);
352
352
  if (rows.length > 0) {
@@ -357,12 +357,12 @@ export class SatiRepository {
357
357
  }
358
358
  // 3️⃣ LIKE fallback
359
359
  this.display.log('🧵 Tentando fallback LIKE...', { source: 'Sati', level: 'debug' });
360
- const likeStmt = this.db.prepare(`
361
- SELECT * FROM long_term_memory
362
- WHERE (summary LIKE ? OR details LIKE ?)
363
- AND archived = 0
364
- ORDER BY importance DESC, access_count DESC
365
- LIMIT ?
360
+ const likeStmt = this.db.prepare(`
361
+ SELECT * FROM long_term_memory
362
+ WHERE (summary LIKE ? OR details LIKE ?)
363
+ AND archived = 0
364
+ ORDER BY importance DESC, access_count DESC
365
+ LIMIT ?
366
366
  `);
367
367
  const pattern = `%${query}%`;
368
368
  const likeRows = likeStmt.all(pattern, pattern, limit);
@@ -383,11 +383,11 @@ export class SatiRepository {
383
383
  if (!this.db)
384
384
  return [];
385
385
  const rows = this.db
386
- .prepare(`
387
- SELECT * FROM long_term_memory
388
- WHERE archived = 0
389
- ORDER BY access_count DESC, created_at DESC
390
- LIMIT ?
386
+ .prepare(`
387
+ SELECT * FROM long_term_memory
388
+ WHERE archived = 0
389
+ ORDER BY access_count DESC, created_at DESC
390
+ LIMIT ?
391
391
  `)
392
392
  .all(limit);
393
393
  return rows.map(this.mapRowToRecord);
@@ -1,53 +1,53 @@
1
- export const SATI_EVALUATION_PROMPT = `You are **Sati**, an autonomous background memory manager for an AI assistant.
2
- Your goal is to analyze the conversation interaction and decide if any **Persistent Long-Term Memory** should be stored.
3
-
4
- ### INPUT DATA
5
- You will receive:
6
- 1. A list of recent messages (USER and ASSISTANT).
7
- 2. A list of ALREADY EXISTING memory summaries (to avoid duplicates).
8
-
9
- ### MEMORY CATEGORIES
10
- Classify any new memory into one of these types:
11
- - **preference**: User preferences (e.g., "I like dark mode", "Use TypeScript").
12
- - **project**: Details about the user's projects, architecture, or tech stack.
13
- - **identity**: Facts about the user's identity, role, or background.
14
- - **constraint**: Hard rules the user wants you to follow (e.g., "Never use single quotes").
15
- - **context**: General context that is useful for the long term.
16
- - **personal_data**: Non-sensitive personal info (e.g., birthday, location).
17
- - **languages**: User's spoken or programming languages.
18
- - **favorite_things**: Favorites (movies, books, etc.).
19
- - **relationships**: Mention of colleagues, family, or friends.
20
- - **pets**: Info about user's pets.
21
- - **naming**: Naming conventions the user prefers.
22
- - **professional_profile**: Job title, industry, skills.
23
-
24
- ### CRITICAL RULES
25
- 0. **SAVE ON SUMMARY and REASONING IN ENGLISH AND NATIVE LANGUAGE**: Always generate a concise summary in English and, if the original information is in another language, also provide a summary in the original language. This ensures the memory is accessible and useful for future interactions, regardless of the language used.
26
- 1. **NO SECRETS**: NEVER store API keys, passwords, credit cards, or private tokens. If found, ignore them explicitly.
27
- 2. **NO DUPLICATES**: If the information is already covered by the \`existing_memory_summaries\`, DO NOT store it again.
28
- 3. **NO CHIT-CHAT**: Do not store trivial conversation like "Hello", "Thanks", "How are you?".
29
- 4. **IMPORTANCE**: Assign 'low', 'medium', or 'high' importance. Store only 'medium' or 'high' unless it's a specific user preference (which is always important).
30
-
31
- ### TOP IMPORTANT GUIDELINES
32
- 5. **OBEY THE USER**: If the user explicitly states something should be remembered, it must be stored with at least 'medium' importance.
33
-
34
- ### OUTPUT FORMAT
35
- You MUST respond with a valid JSON object ARRAY matching the \`ISatiEvaluationOutputArray\` interface:
36
- [
37
- {
38
- "should_store": boolean,
39
- "category": "category_name" | null,
40
- "importance": "low" | "medium" | "high" | null,
41
- "summary": "Concise factual statement | Summary in native language" | null,
42
- "reason": "Why you decided to store or not store | Reason in native language"
43
- },
44
- {
45
- "should_store": boolean,
46
- "category": "category_name" | null,
47
- "importance": "low" | "medium" | "high" | null,
48
- "summary": "Concise factual statement | Summary in native language" | null,
49
- "reason": "Why you decided to store or not store | Reason in native language"
50
- },
51
- ]
52
-
1
+ export const SATI_EVALUATION_PROMPT = `You are **Sati**, an autonomous background memory manager for an AI assistant.
2
+ Your goal is to analyze the conversation interaction and decide if any **Persistent Long-Term Memory** should be stored.
3
+
4
+ ### INPUT DATA
5
+ You will receive:
6
+ 1. A list of recent messages (USER and ASSISTANT).
7
+ 2. A list of ALREADY EXISTING memory summaries (to avoid duplicates).
8
+
9
+ ### MEMORY CATEGORIES
10
+ Classify any new memory into one of these types:
11
+ - **preference**: User preferences (e.g., "I like dark mode", "Use TypeScript").
12
+ - **project**: Details about the user's projects, architecture, or tech stack.
13
+ - **identity**: Facts about the user's identity, role, or background.
14
+ - **constraint**: Hard rules the user wants you to follow (e.g., "Never use single quotes").
15
+ - **context**: General context that is useful for the long term.
16
+ - **personal_data**: Non-sensitive personal info (e.g., birthday, location).
17
+ - **languages**: User's spoken or programming languages.
18
+ - **favorite_things**: Favorites (movies, books, etc.).
19
+ - **relationships**: Mention of colleagues, family, or friends.
20
+ - **pets**: Info about user's pets.
21
+ - **naming**: Naming conventions the user prefers.
22
+ - **professional_profile**: Job title, industry, skills.
23
+
24
+ ### CRITICAL RULES
25
+ 0. **SAVE ON SUMMARY and REASONING IN ENGLISH AND NATIVE LANGUAGE**: Always generate a concise summary in English and, if the original information is in another language, also provide a summary in the original language. This ensures the memory is accessible and useful for future interactions, regardless of the language used.
26
+ 1. **NO SECRETS**: NEVER store API keys, passwords, credit cards, or private tokens. If found, ignore them explicitly.
27
+ 2. **NO DUPLICATES**: If the information is already covered by the \`existing_memory_summaries\`, DO NOT store it again.
28
+ 3. **NO CHIT-CHAT**: Do not store trivial conversation like "Hello", "Thanks", "How are you?".
29
+ 4. **IMPORTANCE**: Assign 'low', 'medium', or 'high' importance. Store only 'medium' or 'high' unless it's a specific user preference (which is always important).
30
+
31
+ ### TOP IMPORTANT GUIDELINES
32
+ 5. **OBEY THE USER**: If the user explicitly states something should be remembered, it must be stored with at least 'medium' importance.
33
+
34
+ ### OUTPUT FORMAT
35
+ You MUST respond with a valid JSON object ARRAY matching the \`ISatiEvaluationOutputArray\` interface:
36
+ [
37
+ {
38
+ "should_store": boolean,
39
+ "category": "category_name" | null,
40
+ "importance": "low" | "medium" | "high" | null,
41
+ "summary": "Concise factual statement | Summary in native language" | null,
42
+ "reason": "Why you decided to store or not store | Reason in native language"
43
+ },
44
+ {
45
+ "should_store": boolean,
46
+ "category": "category_name" | null,
47
+ "importance": "low" | "medium" | "high" | null,
48
+ "summary": "Concise factual statement | Summary in native language" | null,
49
+ "reason": "Why you decided to store or not store | Reason in native language"
50
+ },
51
+ ]
52
+
53
53
  `;
@@ -19,12 +19,12 @@ export async function runSessionEmbeddingWorker() {
19
19
  loadVecExtension(satiDb);
20
20
  const embeddingService = await EmbeddingService.getInstance();
21
21
  while (true) {
22
- const sessions = shortDb.prepare(`
23
- SELECT id
24
- FROM sessions
25
- WHERE ended_at IS NOT NULL
26
- AND embedding_status = 'pending'
27
- LIMIT ?
22
+ const sessions = shortDb.prepare(`
23
+ SELECT id
24
+ FROM sessions
25
+ WHERE ended_at IS NOT NULL
26
+ AND embedding_status = 'pending'
27
+ LIMIT ?
28
28
  `).all(BATCH_LIMIT);
29
29
  if (sessions.length === 0) {
30
30
  display.log('✅ Nenhuma sessão pendente.', { level: 'debug', source: 'SessionEmbeddingWorker' });
@@ -36,30 +36,30 @@ export async function runSessionEmbeddingWorker() {
36
36
  try {
37
37
  // Skip setting 'processing' as it violates CHECK constraint
38
38
  // active_processing.add(sessionId); // If we needed concurrency control
39
- const chunks = satiDb.prepare(`
40
- SELECT id, content
41
- FROM session_chunks
42
- WHERE session_id = ?
43
- ORDER BY chunk_index
39
+ const chunks = satiDb.prepare(`
40
+ SELECT id, content
41
+ FROM session_chunks
42
+ WHERE session_id = ?
43
+ ORDER BY chunk_index
44
44
  `).all(sessionId);
45
45
  if (chunks.length === 0) {
46
46
  display.log(`⚠️ Sessão ${sessionId} não possui chunks.`, { source: 'SessionEmbeddingWorker' });
47
- shortDb.prepare(`
48
- UPDATE sessions
49
- SET embedding_status = 'embedded',
50
- embedded = 1
51
- WHERE id = ?
47
+ shortDb.prepare(`
48
+ UPDATE sessions
49
+ SET embedding_status = 'embedded',
50
+ embedded = 1
51
+ WHERE id = ?
52
52
  `).run(sessionId);
53
53
  continue;
54
54
  }
55
- const insertVec = satiDb.prepare(`
56
- INSERT INTO session_vec (embedding)
57
- VALUES (?)
55
+ const insertVec = satiDb.prepare(`
56
+ INSERT INTO session_vec (embedding)
57
+ VALUES (?)
58
58
  `);
59
- const insertMap = satiDb.prepare(`
60
- INSERT OR REPLACE INTO session_embedding_map
61
- (session_chunk_id, vec_rowid)
62
- VALUES (?, ?)
59
+ const insertMap = satiDb.prepare(`
60
+ INSERT OR REPLACE INTO session_embedding_map
61
+ (session_chunk_id, vec_rowid)
62
+ VALUES (?, ?)
63
63
  `);
64
64
  for (const chunk of chunks) {
65
65
  display.log(` ↳ Embedding chunk ${chunk.id}`, { source: 'SessionEmbeddingWorker' });
@@ -72,20 +72,20 @@ export async function runSessionEmbeddingWorker() {
72
72
  insertMap.run(chunk.id, vecRowId);
73
73
  }
74
74
  // ✅ finalizar sessão
75
- shortDb.prepare(`
76
- UPDATE sessions
77
- SET embedding_status = 'embedded',
78
- embedded = 1
79
- WHERE id = ?
75
+ shortDb.prepare(`
76
+ UPDATE sessions
77
+ SET embedding_status = 'embedded',
78
+ embedded = 1
79
+ WHERE id = ?
80
80
  `).run(sessionId);
81
81
  display.log(`✅ Sessão ${sessionId} embedada com sucesso.`, { source: 'SessionEmbeddingWorker' });
82
82
  }
83
83
  catch (err) {
84
84
  display.log(`❌ Erro na sessão ${sessionId}: ${err}`, { source: 'SessionEmbeddingWorker' });
85
- shortDb.prepare(`
86
- UPDATE sessions
87
- SET embedding_status = 'failed'
88
- WHERE id = ?
85
+ shortDb.prepare(`
86
+ UPDATE sessions
87
+ SET embedding_status = 'failed'
88
+ WHERE id = ?
89
89
  `).run(sessionId);
90
90
  }
91
91
  }