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.
- package/README.md +104 -0
- package/dist/core/llmClient.d.ts +14 -0
- package/dist/core/llmClient.d.ts.map +1 -0
- package/dist/core/llmClient.js +68 -0
- package/dist/core/llmClient.js.map +1 -0
- package/dist/core/retry.d.ts +21 -0
- package/dist/core/retry.d.ts.map +1 -0
- package/dist/core/retry.js +68 -0
- package/dist/core/retry.js.map +1 -0
- package/dist/core/settings.d.ts +46 -0
- package/dist/core/settings.d.ts.map +1 -0
- package/dist/core/settings.js +133 -0
- package/dist/core/settings.js.map +1 -0
- package/dist/db/database.d.ts +50 -0
- package/dist/db/database.d.ts.map +1 -0
- package/dist/db/database.js +157 -0
- package/dist/db/database.js.map +1 -0
- package/dist/demo.d.ts +16 -0
- package/dist/demo.d.ts.map +1 -0
- package/dist/demo.js +305 -0
- package/dist/demo.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/add/extractionPhase.d.ts +17 -0
- package/dist/memory/add/extractionPhase.d.ts.map +1 -0
- package/dist/memory/add/extractionPhase.js +48 -0
- package/dist/memory/add/extractionPhase.js.map +1 -0
- package/dist/memory/add/updatePhase.d.ts +11 -0
- package/dist/memory/add/updatePhase.d.ts.map +1 -0
- package/dist/memory/add/updatePhase.js +133 -0
- package/dist/memory/add/updatePhase.js.map +1 -0
- package/dist/memory/bubbleCreator.d.ts +10 -0
- package/dist/memory/bubbleCreator.d.ts.map +1 -0
- package/dist/memory/bubbleCreator.js +46 -0
- package/dist/memory/bubbleCreator.js.map +1 -0
- package/dist/memory/connectionFinder.d.ts +14 -0
- package/dist/memory/connectionFinder.d.ts.map +1 -0
- package/dist/memory/connectionFinder.js +56 -0
- package/dist/memory/connectionFinder.js.map +1 -0
- package/dist/memory/embeddings.d.ts +27 -0
- package/dist/memory/embeddings.d.ts.map +1 -0
- package/dist/memory/embeddings.js +145 -0
- package/dist/memory/embeddings.js.map +1 -0
- package/dist/memory/extractor.d.ts +20 -0
- package/dist/memory/extractor.d.ts.map +1 -0
- package/dist/memory/extractor.js +60 -0
- package/dist/memory/extractor.js.map +1 -0
- package/dist/memory/memory.d.ts +80 -0
- package/dist/memory/memory.d.ts.map +1 -0
- package/dist/memory/memory.js +342 -0
- package/dist/memory/memory.js.map +1 -0
- package/dist/memory/toolClassifier.d.ts +13 -0
- package/dist/memory/toolClassifier.d.ts.map +1 -0
- package/dist/memory/toolClassifier.js +53 -0
- package/dist/memory/toolClassifier.js.map +1 -0
- package/dist/memory/vectorStore.d.ts +40 -0
- package/dist/memory/vectorStore.d.ts.map +1 -0
- package/dist/memory/vectorStore.js +168 -0
- package/dist/memory/vectorStore.js.map +1 -0
- package/dist/summary/summaryGenerator.d.ts +14 -0
- package/dist/summary/summaryGenerator.d.ts.map +1 -0
- package/dist/summary/summaryGenerator.js +66 -0
- package/dist/summary/summaryGenerator.js.map +1 -0
- package/dist/utils/prompts.d.ts +7 -0
- package/dist/utils/prompts.d.ts.map +1 -0
- package/dist/utils/prompts.js +133 -0
- package/dist/utils/prompts.js.map +1 -0
- 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
|
+
}
|