adaptive-context-memory 1.0.0

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 (70) hide show
  1. package/README.md +104 -0
  2. package/dist/core/llmClient.d.ts +14 -0
  3. package/dist/core/llmClient.d.ts.map +1 -0
  4. package/dist/core/llmClient.js +68 -0
  5. package/dist/core/llmClient.js.map +1 -0
  6. package/dist/core/retry.d.ts +21 -0
  7. package/dist/core/retry.d.ts.map +1 -0
  8. package/dist/core/retry.js +68 -0
  9. package/dist/core/retry.js.map +1 -0
  10. package/dist/core/settings.d.ts +46 -0
  11. package/dist/core/settings.d.ts.map +1 -0
  12. package/dist/core/settings.js +133 -0
  13. package/dist/core/settings.js.map +1 -0
  14. package/dist/db/database.d.ts +50 -0
  15. package/dist/db/database.d.ts.map +1 -0
  16. package/dist/db/database.js +157 -0
  17. package/dist/db/database.js.map +1 -0
  18. package/dist/demo.d.ts +16 -0
  19. package/dist/demo.d.ts.map +1 -0
  20. package/dist/demo.js +305 -0
  21. package/dist/demo.js.map +1 -0
  22. package/dist/index.d.ts +16 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +33 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/memory/add/extractionPhase.d.ts +17 -0
  27. package/dist/memory/add/extractionPhase.d.ts.map +1 -0
  28. package/dist/memory/add/extractionPhase.js +48 -0
  29. package/dist/memory/add/extractionPhase.js.map +1 -0
  30. package/dist/memory/add/updatePhase.d.ts +11 -0
  31. package/dist/memory/add/updatePhase.d.ts.map +1 -0
  32. package/dist/memory/add/updatePhase.js +133 -0
  33. package/dist/memory/add/updatePhase.js.map +1 -0
  34. package/dist/memory/bubbleCreator.d.ts +10 -0
  35. package/dist/memory/bubbleCreator.d.ts.map +1 -0
  36. package/dist/memory/bubbleCreator.js +46 -0
  37. package/dist/memory/bubbleCreator.js.map +1 -0
  38. package/dist/memory/connectionFinder.d.ts +14 -0
  39. package/dist/memory/connectionFinder.d.ts.map +1 -0
  40. package/dist/memory/connectionFinder.js +56 -0
  41. package/dist/memory/connectionFinder.js.map +1 -0
  42. package/dist/memory/embeddings.d.ts +27 -0
  43. package/dist/memory/embeddings.d.ts.map +1 -0
  44. package/dist/memory/embeddings.js +145 -0
  45. package/dist/memory/embeddings.js.map +1 -0
  46. package/dist/memory/extractor.d.ts +20 -0
  47. package/dist/memory/extractor.d.ts.map +1 -0
  48. package/dist/memory/extractor.js +60 -0
  49. package/dist/memory/extractor.js.map +1 -0
  50. package/dist/memory/memory.d.ts +80 -0
  51. package/dist/memory/memory.d.ts.map +1 -0
  52. package/dist/memory/memory.js +342 -0
  53. package/dist/memory/memory.js.map +1 -0
  54. package/dist/memory/toolClassifier.d.ts +13 -0
  55. package/dist/memory/toolClassifier.d.ts.map +1 -0
  56. package/dist/memory/toolClassifier.js +53 -0
  57. package/dist/memory/toolClassifier.js.map +1 -0
  58. package/dist/memory/vectorStore.d.ts +40 -0
  59. package/dist/memory/vectorStore.d.ts.map +1 -0
  60. package/dist/memory/vectorStore.js +168 -0
  61. package/dist/memory/vectorStore.js.map +1 -0
  62. package/dist/summary/summaryGenerator.d.ts +14 -0
  63. package/dist/summary/summaryGenerator.d.ts.map +1 -0
  64. package/dist/summary/summaryGenerator.js +66 -0
  65. package/dist/summary/summaryGenerator.js.map +1 -0
  66. package/dist/utils/prompts.d.ts +7 -0
  67. package/dist/utils/prompts.d.ts.map +1 -0
  68. package/dist/utils/prompts.js +133 -0
  69. package/dist/utils/prompts.js.map +1 -0
  70. package/package.json +42 -0
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ /**
3
+ * In-memory vector store for fast cosine-similarity search.
4
+ *
5
+ * TypeScript port of Python vector_store.py (FAISS).
6
+ * Since faiss-node binaries are fragile, we use a pure-JS flat index
7
+ * (cosine similarity via dot product after L2 normalisation).
8
+ * Performance is identical to FAISS IndexFlatIP for datasets < 100k vectors.
9
+ *
10
+ * Persists index maps to ~/.contextmemory/indexes/conv_<id>.json
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.VectorStore = void 0;
47
+ exports.getVectorStore = getVectorStore;
48
+ exports.saveVectorStore = saveVectorStore;
49
+ exports.rebuildIndexFromDb = rebuildIndexFromDb;
50
+ exports.resetVectorStores = resetVectorStores;
51
+ const fs = __importStar(require("fs"));
52
+ const path = __importStar(require("path"));
53
+ const os = __importStar(require("os"));
54
+ // ─── Utility math ─────────────────────────────────────────────────────────────
55
+ function normalise(v) {
56
+ const norm = Math.sqrt(v.reduce((s, x) => s + x * x, 0));
57
+ if (norm === 0)
58
+ return v;
59
+ return v.map((x) => x / norm);
60
+ }
61
+ function dot(a, b) {
62
+ let s = 0;
63
+ for (let i = 0; i < a.length; i++)
64
+ s += a[i] * b[i];
65
+ return s;
66
+ }
67
+ // ─── VectorStore class ───────────────────────────────────────────────────────
68
+ class VectorStore {
69
+ /** memoryId → normalised embedding */
70
+ vectors = new Map();
71
+ get count() {
72
+ return this.vectors.size;
73
+ }
74
+ add(memoryId, embedding) {
75
+ if (this.vectors.has(memoryId))
76
+ return; // skip duplicates
77
+ this.vectors.set(memoryId, normalise(embedding));
78
+ }
79
+ /** Update (remove old + insert new) */
80
+ update(memoryId, embedding) {
81
+ this.vectors.set(memoryId, normalise(embedding));
82
+ }
83
+ remove(memoryId) {
84
+ this.vectors.delete(memoryId);
85
+ }
86
+ /**
87
+ * Cosine similarity search — O(n) but fast in JS for typical memory sizes.
88
+ * Returns top-k results sorted descending by score.
89
+ */
90
+ search(queryEmbedding, k = 10) {
91
+ if (this.vectors.size === 0)
92
+ return [];
93
+ const q = normalise(queryEmbedding);
94
+ const results = [];
95
+ for (const [memoryId, vec] of this.vectors.entries()) {
96
+ results.push({ memoryId, score: dot(q, vec) });
97
+ }
98
+ results.sort((a, b) => b.score - a.score);
99
+ return results.slice(0, k);
100
+ }
101
+ // ─── Persistence ───────────────────────────────────────────────────────────
102
+ save(filePath) {
103
+ const dir = path.dirname(filePath);
104
+ fs.mkdirSync(dir, { recursive: true });
105
+ const data = {};
106
+ for (const [id, vec] of this.vectors.entries()) {
107
+ data[String(id)] = vec;
108
+ }
109
+ fs.writeFileSync(filePath, JSON.stringify(data));
110
+ }
111
+ load(filePath) {
112
+ if (!fs.existsSync(filePath))
113
+ return false;
114
+ try {
115
+ const raw = fs.readFileSync(filePath, "utf-8");
116
+ const data = JSON.parse(raw);
117
+ this.vectors = new Map(Object.entries(data).map(([id, vec]) => [parseInt(id, 10), vec]));
118
+ return true;
119
+ }
120
+ catch {
121
+ return false;
122
+ }
123
+ }
124
+ }
125
+ exports.VectorStore = VectorStore;
126
+ // ─── Per-conversation cache ───────────────────────────────────────────────────
127
+ const _stores = new Map();
128
+ function getIndexDir() {
129
+ const dir = path.join(os.homedir(), ".contextmemory", "indexes");
130
+ fs.mkdirSync(dir, { recursive: true });
131
+ return dir;
132
+ }
133
+ function indexPath(conversationId) {
134
+ return path.join(getIndexDir(), `conv_${conversationId}.json`);
135
+ }
136
+ function getVectorStore(conversationId) {
137
+ if (!_stores.has(conversationId)) {
138
+ const store = new VectorStore();
139
+ store.load(indexPath(conversationId));
140
+ _stores.set(conversationId, store);
141
+ }
142
+ return _stores.get(conversationId);
143
+ }
144
+ function saveVectorStore(conversationId) {
145
+ const store = _stores.get(conversationId);
146
+ if (store)
147
+ store.save(indexPath(conversationId));
148
+ }
149
+ const database_js_1 = require("../db/database.js");
150
+ function rebuildIndexFromDb(db, conversationId) {
151
+ const store = new VectorStore();
152
+ const rows = db
153
+ .prepare(`SELECT * FROM memories
154
+ WHERE conversation_id = ? AND is_active = 1 AND embedding IS NOT NULL`)
155
+ .all(conversationId);
156
+ for (const row of rows) {
157
+ const emb = (0, database_js_1.parseEmbedding)(row);
158
+ if (emb)
159
+ store.add(row.id, emb);
160
+ }
161
+ _stores.set(conversationId, store);
162
+ store.save(indexPath(conversationId));
163
+ return store;
164
+ }
165
+ function resetVectorStores() {
166
+ _stores.clear();
167
+ }
168
+ //# sourceMappingURL=vectorStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vectorStore.js","sourceRoot":"","sources":["../../src/memory/vectorStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Summary Generator — TypeScript port of Python summary_generator.py
3
+ *
4
+ * Periodically compresses conversation history into a rolling summary.
5
+ * Triggered every SUMMARY_TRIGGER_COUNT messages.
6
+ */
7
+ import type Database from "better-sqlite3";
8
+ /**
9
+ * Generate (or update) the rolling summary for a conversation.
10
+ * Only runs when message count is a multiple of SUMMARY_TRIGGER_COUNT.
11
+ * Returns empty string if not triggered.
12
+ */
13
+ export declare function generateConversationSummary(db: Database.Database, conversationId: number): Promise<string>;
14
+ //# sourceMappingURL=summaryGenerator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summaryGenerator.d.ts","sourceRoot":"","sources":["../../src/summary/summaryGenerator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAS3C;;;;GAIG;AACH,wBAAsB,2BAA2B,CAC/C,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,MAAM,CAAC,CA8DjB"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ /**
3
+ * Summary Generator — TypeScript port of Python summary_generator.py
4
+ *
5
+ * Periodically compresses conversation history into a rolling summary.
6
+ * Triggered every SUMMARY_TRIGGER_COUNT messages.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.generateConversationSummary = generateConversationSummary;
10
+ const llmClient_js_1 = require("../core/llmClient.js");
11
+ const settings_js_1 = require("../core/settings.js");
12
+ const prompts_js_1 = require("../utils/prompts.js");
13
+ const MAX_MESSAGES_FROM_SUMMARY = 200;
14
+ const SUMMARY_TRIGGER_COUNT = 20;
15
+ /**
16
+ * Generate (or update) the rolling summary for a conversation.
17
+ * Only runs when message count is a multiple of SUMMARY_TRIGGER_COUNT.
18
+ * Returns empty string if not triggered.
19
+ */
20
+ async function generateConversationSummary(db, conversationId) {
21
+ const s = (0, settings_js_1.getSettings)();
22
+ const client = (0, llmClient_js_1.getLlmClient)();
23
+ const total = db
24
+ .prepare("SELECT COUNT(*) as cnt FROM messages WHERE conversation_id = ?")
25
+ .get(conversationId).cnt;
26
+ if (total === 0 || total % SUMMARY_TRIGGER_COUNT !== 0)
27
+ return "";
28
+ const rows = db
29
+ .prepare(`SELECT * FROM messages
30
+ WHERE conversation_id = ?
31
+ ORDER BY timestamp ASC
32
+ LIMIT ?`)
33
+ .all(conversationId, MAX_MESSAGES_FROM_SUMMARY);
34
+ if (rows.length === 0)
35
+ return "";
36
+ const conversationText = rows
37
+ .map((r) => `${r.sender.toUpperCase()}: ${r.message_text}`)
38
+ .join("\n");
39
+ const response = await client.chat.completions.create({
40
+ model: s.llmModel,
41
+ messages: [
42
+ { role: "system", content: prompts_js_1.SUMMARY_GENERATOR_PROMPT },
43
+ {
44
+ role: "user",
45
+ content: `Summarize the following conversation.\n\nConversation:\n${conversationText}\n\nReturn only the summary text.`,
46
+ },
47
+ ],
48
+ temperature: 0.2,
49
+ });
50
+ const summaryText = (response.choices[0].message.content ?? "").trim();
51
+ // Upsert summary row
52
+ const existing = db
53
+ .prepare("SELECT * FROM conversation_summary WHERE conversation_id = ?")
54
+ .get(conversationId);
55
+ const now = new Date().toISOString();
56
+ if (existing) {
57
+ db.prepare("UPDATE conversation_summary SET summary_text = ?, updated_at = ? WHERE conversation_id = ?").run(summaryText, now, conversationId);
58
+ }
59
+ else {
60
+ db.prepare("INSERT INTO conversation_summary (conversation_id, summary_text, updated_at) VALUES (?, ?, ?)").run(conversationId, summaryText, now);
61
+ }
62
+ if (s.debug)
63
+ console.log("[ContextMemory] Summary updated.");
64
+ return summaryText;
65
+ }
66
+ //# sourceMappingURL=summaryGenerator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summaryGenerator.js","sourceRoot":"","sources":["../../src/summary/summaryGenerator.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAgBH,kEAiEC;AA9ED,uDAAoD;AACpD,qDAAkD;AAClD,oDAA+D;AAG/D,MAAM,yBAAyB,GAAG,GAAG,CAAC;AACtC,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAEjC;;;;GAIG;AACI,KAAK,UAAU,2BAA2B,CAC/C,EAAqB,EACrB,cAAsB;IAEtB,MAAM,CAAC,GAAG,IAAA,yBAAW,GAAE,CAAC;IACxB,MAAM,MAAM,GAAG,IAAA,2BAAY,GAAE,CAAC;IAE9B,MAAM,KAAK,GACT,EAAE;SACC,OAAO,CAAC,gEAAgE,CAAC;SACzE,GAAG,CAAC,cAAc,CACtB,CAAC,GAAG,CAAC;IAEN,IAAI,KAAK,KAAK,CAAC,IAAI,KAAK,GAAG,qBAAqB,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAElE,MAAM,IAAI,GAAG,EAAE;SACZ,OAAO,CACN;;;eAGS,CACV;SACA,GAAG,CAAC,cAAc,EAAE,yBAAyB,CAAiB,CAAC;IAElE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjC,MAAM,gBAAgB,GAAG,IAAI;SAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,YAAY,EAAE,CAAC;SAC1D,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;QACpD,KAAK,EAAE,CAAC,CAAC,QAAQ;QACjB,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qCAAwB,EAAE;YACrD;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,2DAA2D,gBAAgB,mCAAmC;aACxH;SACF;QACD,WAAW,EAAE,GAAG;KACjB,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAEvE,qBAAqB;IACrB,MAAM,QAAQ,GAAG,EAAE;SAChB,OAAO,CACN,8DAA8D,CAC/D;SACA,GAAG,CAAC,cAAc,CAA2B,CAAC;IAEjD,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErC,IAAI,QAAQ,EAAE,CAAC;QACb,EAAE,CAAC,OAAO,CACR,4FAA4F,CAC7F,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC;IAC1C,CAAC;SAAM,CAAC;QACN,EAAE,CAAC,OAAO,CACR,+FAA+F,CAChG,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,CAAC,CAAC,KAAK;QAAE,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAC7D,OAAO,WAAW,CAAC;AACrB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Upgraded system prompts v3 — with explicit state-change & replacement rules.
3
+ */
4
+ export declare const EXTRACTION_SYSTEM_PROMPT = "You are a memory extraction agent for a long-term contextual memory system.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n \u26A0\uFE0F CRITICAL: EXTRACT ONLY FROM \"LATEST INTERACTION\"\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nThe \"Conversation Summary\" and \"Recent Messages\" are CONTEXT ONLY \u2014 do NOT extract from them.\nOnly extract facts explicitly stated in the \"Latest Interaction\" by the USER (not the assistant).\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n SEMANTIC FACTS \u2014 stable, long-term truths\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nEXTRACT:\n - New facts: name, location, profession, skills, stack, preferences, goals.\n - State changes & negations: \"User stopped using X\", \"User no longer does Y\", \"User switched from A to B\".\n\nSKIP: moods, one-time events, hypotheticals, assistant's words, greetings.\n\nQuestion test: \"Will this still be true in 3 months?\" \u2192 Yes = SEMANTIC\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n BUBBLES \u2014 significant, time-bound moments\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nEXTRACT ONLY IF: active bug/problem (specific), hard deadline, major life event,\n explicit \"remember this\" request, critical blocker.\nSKIP: greetings, thanks, generic questions, casual chat, anything already semantic.\n\n\u26A0\uFE0F DEFAULT TO 0 BUBBLES. Create bubbles only when something genuinely time-critical happens.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n IMPORTANCE (bubbles only): 0.0 \u2013 1.0\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n0.9\u20131.0 Critical deadlines, emergencies, production outages\n0.7\u20130.8 Active problems, key decisions, important tasks\n0.5\u20130.6 Notable context, moderate work items\n0.3\u20130.4 Minor background info\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n OUTPUT FORMAT \u2014 strict JSON\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n{\n \"semantic\": [\n \"User's name is Alice\",\n \"User stopped using Rust and switched to Python\",\n \"User is a Python developer\"\n ],\n \"bubbles\": [{\"text\": \"User has a production deploy deadline on Friday\", \"importance\": 0.9}]\n}\n\nEmpty response (most conversations): {\"semantic\": [], \"bubbles\": []}\n\nRULES:\n- Each semantic fact starts with \"User\" (third person)\n- Facts are standalone sentences \u2014 no pronouns referencing other facts\n- Include negations/replacements if stated by user (e.g. \"User stopped using X\")\n- No trailing commas, no markdown, no explanation outside JSON\n";
5
+ export declare const TOOL_CALL_SYSTEM_PROMPT = "You are a memory management assistant for a long-term contextual AI memory system.\n\nGiven a CANDIDATE FACT and EXISTING SIMILAR MEMORIES, decide the correct action AND assign a category.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n ACTIONS\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nADD \u2014 New fact not in memory. memory_id: null.\nUPDATE \u2014 Adds detail to existing memory (same topic, more info). Provide memory_id + updated text.\nREPLACE \u2014 Contradicts or replaces existing memory (opposite, changed, or discontinued fact). Provide memory_id + new text.\nDELETE \u2014 Explicitly removes/invalidates an existing memory (e.g. \"User stopped using X\"). Provide memory_id.\nNOOP \u2014 Already stored with same meaning. memory_id: null, text: null.\n\nCONTRADICTION & REPLACEMENT PATTERNS (\u2192 REPLACE or DELETE):\n - \"User stopped using X\" + existing memory \"User works with X\" \u2192 DELETE (or REPLACE with new stack)\n - \"User switched from X to Y\" + existing memory \"User works with X\" \u2192 REPLACE memory X with Y\n - \"User lives in Y\" + existing memory \"User lives in X\" \u2192 REPLACE\n - \"User's name is B\" + existing memory \"User's name is A\" \u2192 REPLACE\n\nDECISION PRIORITY:\n 1. Contradicts / replaces existing memory \u2192 REPLACE (or DELETE if discontinued)\n 2. Same meaning \u2192 NOOP \n 3. More detail on same fact \u2192 UPDATE\n 4. No similar memories \u2192 ADD\n 5. When in doubt \u2192 ADD\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n CATEGORIES (pick ONE)\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nprofile \u2014 name, age, location, relationships\nprofessional \u2014 job, company, role, career\nskill \u2014 programming languages, tools, frameworks, expertise\npreference \u2014 likes, dislikes, style choices, habits\ngoal \u2014 long-term objectives, projects\ndietary \u2014 food preferences, allergies, restrictions\nhealth \u2014 medical, physical conditions\nother \u2014 anything that doesn't fit above\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n OUTPUT FORMAT \u2014 strict JSON\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nADD: {\"action\":\"ADD\", \"memory_id\":null, \"text\":\"User prefers dark mode\", \"category\":\"preference\"}\nUPDATE: {\"action\":\"UPDATE\", \"memory_id\":42, \"text\":\"User has 7y Python exp\", \"category\":\"skill\"}\nREPLACE: {\"action\":\"REPLACE\", \"memory_id\":42, \"text\":\"User works with Python\", \"category\":\"skill\"}\nDELETE: {\"action\":\"DELETE\", \"memory_id\":42, \"text\":null, \"category\":null}\nNOOP: {\"action\":\"NOOP\", \"memory_id\":null, \"text\":null, \"category\":null}\n\nReturn ONLY the JSON object. No explanation, no markdown.\n";
6
+ export declare const SUMMARY_GENERATOR_PROMPT = "You are a conversation summarization engine for a long-term memory system.\n\nCompress the conversation into a factual, memory-safe summary. Focus only on durable information.\n\nINCLUDE: stable facts (preferences, background, skills), long-term goals, key decisions, ongoing projects.\nEXCLUDE: small talk, greetings, thanks, moods, one-time events, speculation, assistant verbosity.\n\nSTYLE: neutral third-person, factual, no quotes, no markdown, no headings.\nReturn ONLY the summary text. If nothing durable occurred, return an empty string.\n";
7
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,eAAO,MAAM,wBAAwB,60NA4DpC,CAAC;AAGF,eAAO,MAAM,uBAAuB,g4KAmDnC,CAAC;AAGF,eAAO,MAAM,wBAAwB,yiBASpC,CAAC"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ /**
3
+ * Upgraded system prompts v3 — with explicit state-change & replacement rules.
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SUMMARY_GENERATOR_PROMPT = exports.TOOL_CALL_SYSTEM_PROMPT = exports.EXTRACTION_SYSTEM_PROMPT = void 0;
7
+ // ─────────────────────────────────────────────────────────────────────────────
8
+ exports.EXTRACTION_SYSTEM_PROMPT = `You are a memory extraction agent for a long-term contextual memory system.
9
+
10
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
11
+ ⚠️ CRITICAL: EXTRACT ONLY FROM "LATEST INTERACTION"
12
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
13
+
14
+ The "Conversation Summary" and "Recent Messages" are CONTEXT ONLY — do NOT extract from them.
15
+ Only extract facts explicitly stated in the "Latest Interaction" by the USER (not the assistant).
16
+
17
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
18
+ SEMANTIC FACTS — stable, long-term truths
19
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
20
+
21
+ EXTRACT:
22
+ - New facts: name, location, profession, skills, stack, preferences, goals.
23
+ - State changes & negations: "User stopped using X", "User no longer does Y", "User switched from A to B".
24
+
25
+ SKIP: moods, one-time events, hypotheticals, assistant's words, greetings.
26
+
27
+ Question test: "Will this still be true in 3 months?" → Yes = SEMANTIC
28
+
29
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
30
+ BUBBLES — significant, time-bound moments
31
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
32
+
33
+ EXTRACT ONLY IF: active bug/problem (specific), hard deadline, major life event,
34
+ explicit "remember this" request, critical blocker.
35
+ SKIP: greetings, thanks, generic questions, casual chat, anything already semantic.
36
+
37
+ ⚠️ DEFAULT TO 0 BUBBLES. Create bubbles only when something genuinely time-critical happens.
38
+
39
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
40
+ IMPORTANCE (bubbles only): 0.0 – 1.0
41
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
42
+
43
+ 0.9–1.0 Critical deadlines, emergencies, production outages
44
+ 0.7–0.8 Active problems, key decisions, important tasks
45
+ 0.5–0.6 Notable context, moderate work items
46
+ 0.3–0.4 Minor background info
47
+
48
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
49
+ OUTPUT FORMAT — strict JSON
50
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
51
+
52
+ {
53
+ "semantic": [
54
+ "User's name is Alice",
55
+ "User stopped using Rust and switched to Python",
56
+ "User is a Python developer"
57
+ ],
58
+ "bubbles": [{"text": "User has a production deploy deadline on Friday", "importance": 0.9}]
59
+ }
60
+
61
+ Empty response (most conversations): {"semantic": [], "bubbles": []}
62
+
63
+ RULES:
64
+ - Each semantic fact starts with "User" (third person)
65
+ - Facts are standalone sentences — no pronouns referencing other facts
66
+ - Include negations/replacements if stated by user (e.g. "User stopped using X")
67
+ - No trailing commas, no markdown, no explanation outside JSON
68
+ `;
69
+ // ─────────────────────────────────────────────────────────────────────────────
70
+ exports.TOOL_CALL_SYSTEM_PROMPT = `You are a memory management assistant for a long-term contextual AI memory system.
71
+
72
+ Given a CANDIDATE FACT and EXISTING SIMILAR MEMORIES, decide the correct action AND assign a category.
73
+
74
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
75
+ ACTIONS
76
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
77
+
78
+ ADD — New fact not in memory. memory_id: null.
79
+ UPDATE — Adds detail to existing memory (same topic, more info). Provide memory_id + updated text.
80
+ REPLACE — Contradicts or replaces existing memory (opposite, changed, or discontinued fact). Provide memory_id + new text.
81
+ DELETE — Explicitly removes/invalidates an existing memory (e.g. "User stopped using X"). Provide memory_id.
82
+ NOOP — Already stored with same meaning. memory_id: null, text: null.
83
+
84
+ CONTRADICTION & REPLACEMENT PATTERNS (→ REPLACE or DELETE):
85
+ - "User stopped using X" + existing memory "User works with X" → DELETE (or REPLACE with new stack)
86
+ - "User switched from X to Y" + existing memory "User works with X" → REPLACE memory X with Y
87
+ - "User lives in Y" + existing memory "User lives in X" → REPLACE
88
+ - "User's name is B" + existing memory "User's name is A" → REPLACE
89
+
90
+ DECISION PRIORITY:
91
+ 1. Contradicts / replaces existing memory → REPLACE (or DELETE if discontinued)
92
+ 2. Same meaning → NOOP
93
+ 3. More detail on same fact → UPDATE
94
+ 4. No similar memories → ADD
95
+ 5. When in doubt → ADD
96
+
97
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
98
+ CATEGORIES (pick ONE)
99
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
100
+
101
+ profile — name, age, location, relationships
102
+ professional — job, company, role, career
103
+ skill — programming languages, tools, frameworks, expertise
104
+ preference — likes, dislikes, style choices, habits
105
+ goal — long-term objectives, projects
106
+ dietary — food preferences, allergies, restrictions
107
+ health — medical, physical conditions
108
+ other — anything that doesn't fit above
109
+
110
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
111
+ OUTPUT FORMAT — strict JSON
112
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
113
+
114
+ ADD: {"action":"ADD", "memory_id":null, "text":"User prefers dark mode", "category":"preference"}
115
+ UPDATE: {"action":"UPDATE", "memory_id":42, "text":"User has 7y Python exp", "category":"skill"}
116
+ REPLACE: {"action":"REPLACE", "memory_id":42, "text":"User works with Python", "category":"skill"}
117
+ DELETE: {"action":"DELETE", "memory_id":42, "text":null, "category":null}
118
+ NOOP: {"action":"NOOP", "memory_id":null, "text":null, "category":null}
119
+
120
+ Return ONLY the JSON object. No explanation, no markdown.
121
+ `;
122
+ // ─────────────────────────────────────────────────────────────────────────────
123
+ exports.SUMMARY_GENERATOR_PROMPT = `You are a conversation summarization engine for a long-term memory system.
124
+
125
+ Compress the conversation into a factual, memory-safe summary. Focus only on durable information.
126
+
127
+ INCLUDE: stable facts (preferences, background, skills), long-term goals, key decisions, ongoing projects.
128
+ EXCLUDE: small talk, greetings, thanks, moods, one-time events, speculation, assistant verbosity.
129
+
130
+ STYLE: neutral third-person, factual, no quotes, no markdown, no headings.
131
+ Return ONLY the summary text. If nothing durable occurred, return an empty string.
132
+ `;
133
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,gFAAgF;AACnE,QAAA,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4DvC,CAAC;AAEF,gFAAgF;AACnE,QAAA,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmDtC,CAAC;AAEF,gFAAgF;AACnE,QAAA,wBAAwB,GAAG;;;;;;;;;CASvC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "adaptive-context-memory",
3
+ "version": "1.0.0",
4
+ "description": "High-performance long-term adaptive memory system for AI agents in TypeScript & Node.js",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "prepack": "npm run build",
13
+ "dev": "tsx src/demo.ts",
14
+ "test": "tsx src/demo.ts",
15
+ "clean": "rm -rf dist"
16
+ },
17
+ "keywords": [
18
+ "ai",
19
+ "memory",
20
+ "adaptive-memory",
21
+ "llm",
22
+ "openai",
23
+ "openrouter",
24
+ "context",
25
+ "long-term-memory",
26
+ "vector-store",
27
+ "rag",
28
+ "typescript"
29
+ ],
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "better-sqlite3": "^9.6.0",
33
+ "dotenv": "^16.4.5",
34
+ "openai": "^4.56.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/better-sqlite3": "^7.6.10",
38
+ "@types/node": "^20.14.0",
39
+ "tsx": "^4.19.3",
40
+ "typescript": "^5.4.5"
41
+ }
42
+ }