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
package/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # context-memory-ts 🧠
2
+
3
+ High-performance, standalone, zero-binary long-term adaptive memory system for AI agents and LLM applications in TypeScript & Node.js.
4
+
5
+ Ported and optimized from the Python `contextmemory` package.
6
+
7
+ ---
8
+
9
+ ## ✨ Features
10
+
11
+ - ⚡ **Zero Binary Vector Search:** Flat cosine similarity search in pure TypeScript. No C++ compilation or heavy FAISS binaries needed.
12
+ - 🗄️ **High Performance Local Database:** Fast SQLite persistence via `better-sqlite3`.
13
+ - 🧠 **Dual Memory Engine:** Automatically classifies information into:
14
+ - **Semantic Facts:** Long-term durable user knowledge (profile, skills, preferences).
15
+ - **Episodic Bubbles:** Time-sensitive events, tasks, and deadlines with importance scoring.
16
+ - 🔄 **Smart Contradiction Resolution:** LLM agent dynamically decides whether to `ADD`, `UPDATE`, `REPLACE`, `DELETE`, or `NOOP` incoming facts.
17
+ - 🎯 **MMR (Maximum Marginal Relevance) Search:** Re-ranks query results for optimal relevance and diversity.
18
+ - 🚀 **Batch & Cached Embeddings:** Built-in LRU cache and single-call batch embedding to minimize API latency and cost.
19
+ - 🔁 **Resilient Auto-Retry:** Exponential backoff retry wrapper handles rate limits (429) and transient errors automatically.
20
+ - 🤖 **Multi-Provider Support:** Plug-and-play support for **OpenAI** and **OpenRouter**.
21
+
22
+ ---
23
+
24
+ ## 📦 Installation
25
+
26
+ ```bash
27
+ npm install context-memory-ts
28
+ ```
29
+
30
+ *Or install from local tarball bundle:*
31
+ ```bash
32
+ npm install /path/to/context-memory-ts-1.0.0.tgz
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 🚀 Quick Start
38
+
39
+ ```typescript
40
+ import { configure, createTables, getDb, ContextMemory } from 'context-memory-ts';
41
+
42
+ // 1. Configure provider and model
43
+ configure({
44
+ openrouterApiKey: process.env.OPENROUTER_API_KEY, // or openaiApiKey
45
+ llmProvider: 'openrouter',
46
+ llmModel: 'openai/gpt-4o-mini',
47
+ });
48
+
49
+ // 2. Initialize database schema
50
+ createTables();
51
+
52
+ // 3. Instantiate memory manager
53
+ const db = getDb();
54
+ const memory = new ContextMemory(db);
55
+
56
+ const CONVERSATION_ID = 1;
57
+
58
+ // 4. Extract and store memories from chat turns
59
+ await memory.add([
60
+ { role: 'user', content: "My name is Prince and I'm a TypeScript developer." },
61
+ { role: 'assistant', content: "Nice to meet you, Prince!" }
62
+ ], CONVERSATION_ID);
63
+
64
+ // 5. Semantic MMR Search
65
+ const searchResult = await memory.search("what is the user's primary programming language?", CONVERSATION_ID);
66
+ console.log(searchResult.results);
67
+ ```
68
+
69
+ ---
70
+
71
+ ## 🛠️ API Reference
72
+
73
+ ### `configure(options: ContextMemoryConfig)`
74
+ Configures the global LLM provider, API keys, and embedding models.
75
+
76
+ ### `createTables()`
77
+ Initializes SQLite database tables and index migrations.
78
+
79
+ ### `memory.add(messages, conversationId)`
80
+ Extracts semantic facts and episodic bubbles from recent conversation turns, resolves contradictions, and saves to database & vector store.
81
+
82
+ ### `memory.search(query, conversationId, options)`
83
+ Performs MMR-ranked semantic search. Options include:
84
+ - `limit?: number` (default 10)
85
+ - `mmrLambda?: number` (default 0.6; 0.0 = max diversity, 1.0 = max similarity)
86
+ - `category?: string` (filter by category: `'profile' | 'skill' | 'preference' | ...`)
87
+
88
+ ### `memory.getAll(conversationId, category?)`
89
+ Lists all active memories for a conversation.
90
+
91
+ ### `memory.getStats(conversationId)`
92
+ Returns total count, breakdown by type/category, and embedding cache hit rates.
93
+
94
+ ### `memory.consolidate(conversationId)`
95
+ Scans for near-duplicate semantic facts and merges them into clean, concise facts via LLM.
96
+
97
+ ### `memory.purgeOldBubbles(conversationId, olderThanDays)`
98
+ Soft-deletes episodic bubbles older than $N$ days (default 30 days).
99
+
100
+ ---
101
+
102
+ ## 📄 License
103
+
104
+ MIT
@@ -0,0 +1,14 @@
1
+ /**
2
+ * LLM & Embedding client factory — TypeScript port of Python openai_client.py
3
+ *
4
+ * Uses lazy initialization so clients are created only on first use.
5
+ * Supports OpenAI and OpenRouter (OpenAI-compatible interface).
6
+ */
7
+ import OpenAI from "openai";
8
+ /** Get (or lazily create) the LLM client */
9
+ export declare function getLlmClient(): OpenAI;
10
+ /** Get (or lazily create) the embedding client */
11
+ export declare function getEmbeddingClient(): OpenAI;
12
+ /** Reset clients (useful for testing or after reconfigure) */
13
+ export declare function resetClients(): void;
14
+ //# sourceMappingURL=llmClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llmClient.d.ts","sourceRoot":"","sources":["../../src/core/llmClient.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAM5B,4CAA4C;AAC5C,wBAAgB,YAAY,IAAI,MAAM,CAmBrC;AAED,kDAAkD;AAClD,wBAAgB,kBAAkB,IAAI,MAAM,CAsB3C;AAED,8DAA8D;AAC9D,wBAAgB,YAAY,IAAI,IAAI,CAGnC"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * LLM & Embedding client factory — TypeScript port of Python openai_client.py
4
+ *
5
+ * Uses lazy initialization so clients are created only on first use.
6
+ * Supports OpenAI and OpenRouter (OpenAI-compatible interface).
7
+ */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getLlmClient = getLlmClient;
13
+ exports.getEmbeddingClient = getEmbeddingClient;
14
+ exports.resetClients = resetClients;
15
+ const openai_1 = __importDefault(require("openai"));
16
+ const settings_js_1 = require("./settings.js");
17
+ let _llmClient = null;
18
+ let _embeddingClient = null;
19
+ /** Get (or lazily create) the LLM client */
20
+ function getLlmClient() {
21
+ if (!_llmClient) {
22
+ const s = (0, settings_js_1.getSettings)();
23
+ s.validate();
24
+ if (s.llmProvider === "openrouter") {
25
+ _llmClient = new openai_1.default({
26
+ apiKey: s.openrouterApiKey,
27
+ baseURL: "https://openrouter.ai/api/v1",
28
+ defaultHeaders: {
29
+ "HTTP-Referer": "https://github.com/contextmemory",
30
+ "X-Title": "ContextMemory",
31
+ },
32
+ });
33
+ }
34
+ else {
35
+ _llmClient = new openai_1.default({ apiKey: s.openaiApiKey });
36
+ }
37
+ }
38
+ return _llmClient;
39
+ }
40
+ /** Get (or lazily create) the embedding client */
41
+ function getEmbeddingClient() {
42
+ if (!_embeddingClient) {
43
+ const s = (0, settings_js_1.getSettings)();
44
+ if (s.llmProvider === "openrouter" && s.openrouterApiKey) {
45
+ _embeddingClient = new openai_1.default({
46
+ apiKey: s.openrouterApiKey,
47
+ baseURL: "https://openrouter.ai/api/v1",
48
+ defaultHeaders: {
49
+ "HTTP-Referer": "https://github.com/contextmemory",
50
+ "X-Title": "ContextMemory",
51
+ },
52
+ });
53
+ }
54
+ else if (s.openaiApiKey) {
55
+ _embeddingClient = new openai_1.default({ apiKey: s.openaiApiKey });
56
+ }
57
+ else {
58
+ throw new Error("API key required for embeddings. Set OPENAI_API_KEY or OPENROUTER_API_KEY.");
59
+ }
60
+ }
61
+ return _embeddingClient;
62
+ }
63
+ /** Reset clients (useful for testing or after reconfigure) */
64
+ function resetClients() {
65
+ _llmClient = null;
66
+ _embeddingClient = null;
67
+ }
68
+ //# sourceMappingURL=llmClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llmClient.js","sourceRoot":"","sources":["../../src/core/llmClient.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;AASH,oCAmBC;AAGD,gDAsBC;AAGD,oCAGC;AAzDD,oDAA4B;AAC5B,+CAA4C;AAE5C,IAAI,UAAU,GAAkB,IAAI,CAAC;AACrC,IAAI,gBAAgB,GAAkB,IAAI,CAAC;AAE3C,4CAA4C;AAC5C,SAAgB,YAAY;IAC1B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,CAAC,GAAG,IAAA,yBAAW,GAAE,CAAC;QACxB,CAAC,CAAC,QAAQ,EAAE,CAAC;QAEb,IAAI,CAAC,CAAC,WAAW,KAAK,YAAY,EAAE,CAAC;YACnC,UAAU,GAAG,IAAI,gBAAM,CAAC;gBACtB,MAAM,EAAE,CAAC,CAAC,gBAAiB;gBAC3B,OAAO,EAAE,8BAA8B;gBACvC,cAAc,EAAE;oBACd,cAAc,EAAE,kCAAkC;oBAClD,SAAS,EAAE,eAAe;iBAC3B;aACF,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,UAAU,GAAG,IAAI,gBAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,YAAa,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,kDAAkD;AAClD,SAAgB,kBAAkB;IAChC,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,IAAA,yBAAW,GAAE,CAAC;QAExB,IAAI,CAAC,CAAC,WAAW,KAAK,YAAY,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;YACzD,gBAAgB,GAAG,IAAI,gBAAM,CAAC;gBAC5B,MAAM,EAAE,CAAC,CAAC,gBAAgB;gBAC1B,OAAO,EAAE,8BAA8B;gBACvC,cAAc,EAAE;oBACd,cAAc,EAAE,kCAAkC;oBAClD,SAAS,EAAE,eAAe;iBAC3B;aACF,CAAC,CAAC;QACL,CAAC;aAAM,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;YAC1B,gBAAgB,GAAG,IAAI,gBAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CACb,4EAA4E,CAC7E,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,8DAA8D;AAC9D,SAAgB,YAAY;IAC1B,UAAU,GAAG,IAAI,CAAC;IAClB,gBAAgB,GAAG,IAAI,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Retry utility with exponential backoff.
3
+ *
4
+ * Wraps any async function and retries on transient errors (rate limits, 5xx).
5
+ * Default: 3 attempts, 500ms initial delay, 2x backoff, jitter.
6
+ */
7
+ export interface RetryOptions {
8
+ attempts?: number;
9
+ initialDelayMs?: number;
10
+ maxDelayMs?: number;
11
+ factor?: number;
12
+ jitter?: boolean;
13
+ }
14
+ /**
15
+ * Retry `fn` up to `attempts` times with exponential backoff.
16
+ *
17
+ * @example
18
+ * const result = await withRetry(() => openai.chat.completions.create(...));
19
+ */
20
+ export declare function withRetry<T>(fn: () => Promise<T>, opts?: RetryOptions): Promise<T>;
21
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/core/retry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA2BD;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,CAAC,CAAC,CA+BZ"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * Retry utility with exponential backoff.
4
+ *
5
+ * Wraps any async function and retries on transient errors (rate limits, 5xx).
6
+ * Default: 3 attempts, 500ms initial delay, 2x backoff, jitter.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.withRetry = withRetry;
10
+ /** Error codes that should NOT be retried (bad request, auth failure, etc.) */
11
+ const FATAL_CODES = new Set([400, 401, 403, 404, 422]);
12
+ function isRetryable(err) {
13
+ if (err instanceof Error) {
14
+ const msg = err.message.toLowerCase();
15
+ // Rate limit or server error
16
+ if (msg.includes("rate limit") || msg.includes("429"))
17
+ return true;
18
+ if (msg.includes("5") && msg.includes("0"))
19
+ return true; // 500, 503 etc.
20
+ if (msg.includes("timeout") || msg.includes("econnreset"))
21
+ return true;
22
+ }
23
+ // Check status codes on OpenAI-style errors
24
+ const e = err;
25
+ const code = e.status ?? e.statusCode;
26
+ if (code != null) {
27
+ if (FATAL_CODES.has(code))
28
+ return false;
29
+ if (code === 429 || code >= 500)
30
+ return true;
31
+ }
32
+ return false;
33
+ }
34
+ function sleep(ms) {
35
+ return new Promise((resolve) => setTimeout(resolve, ms));
36
+ }
37
+ /**
38
+ * Retry `fn` up to `attempts` times with exponential backoff.
39
+ *
40
+ * @example
41
+ * const result = await withRetry(() => openai.chat.completions.create(...));
42
+ */
43
+ async function withRetry(fn, opts = {}) {
44
+ const attempts = opts.attempts ?? 3;
45
+ const initialDelay = opts.initialDelayMs ?? 500;
46
+ const maxDelay = opts.maxDelayMs ?? 10_000;
47
+ const factor = opts.factor ?? 2;
48
+ const jitter = opts.jitter ?? true;
49
+ let lastError;
50
+ for (let attempt = 1; attempt <= attempts; attempt++) {
51
+ try {
52
+ return await fn();
53
+ }
54
+ catch (err) {
55
+ lastError = err;
56
+ if (attempt === attempts || !isRetryable(err)) {
57
+ throw err;
58
+ }
59
+ let delay = Math.min(initialDelay * Math.pow(factor, attempt - 1), maxDelay);
60
+ if (jitter)
61
+ delay *= 0.8 + Math.random() * 0.4; // ±20% jitter
62
+ console.warn(`[ContextMemory] API error (attempt ${attempt}/${attempts}), retrying in ${Math.round(delay)}ms...`, err instanceof Error ? err.message : err);
63
+ await sleep(delay);
64
+ }
65
+ }
66
+ throw lastError;
67
+ }
68
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/core/retry.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAyCH,8BAkCC;AAjED,+EAA+E;AAC/E,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAEvD,SAAS,WAAW,CAAC,GAAY;IAC/B,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACtC,6BAA6B;QAC7B,IAAI,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACnE,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC,CAAC,gBAAgB;QACzE,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,OAAO,IAAI,CAAC;IACzE,CAAC;IACD,4CAA4C;IAC5C,MAAM,CAAC,GAAG,GAA+C,CAAC;IAC1D,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,UAAU,CAAC;IACtC,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;QACjB,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QACxC,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,IAAI,GAAG;YAAE,OAAO,IAAI,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,SAAS,CAC7B,EAAoB,EACpB,OAAqB,EAAE;IAEvB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;IACpC,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,IAAI,GAAG,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;IAEnC,IAAI,SAAkB,CAAC;IAEvB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC;QACrD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,SAAS,GAAG,GAAG,CAAC;YAEhB,IAAI,OAAO,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC9C,MAAM,GAAG,CAAC;YACZ,CAAC;YAED,IAAI,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;YAC7E,IAAI,MAAM;gBAAE,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,cAAc;YAE9D,OAAO,CAAC,IAAI,CACV,sCAAsC,OAAO,IAAI,QAAQ,kBAAkB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EACnG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CACzC,CAAC;YACF,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,MAAM,SAAS,CAAC;AAClB,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * ContextMemory Settings — TypeScript port of Python settings.py
3
+ *
4
+ * Supports two config methods:
5
+ * 1. Programmatic: configure({ openaiApiKey: "..." })
6
+ * 2. Environment variables: OPENAI_API_KEY, OPENROUTER_API_KEY, DATABASE_URL, ...
7
+ */
8
+ export type LLMProvider = "openai" | "openrouter";
9
+ export interface ContextMemoryConfig {
10
+ openaiApiKey?: string;
11
+ openrouterApiKey?: string;
12
+ databaseUrl?: string;
13
+ llmProvider?: LLMProvider;
14
+ llmModel?: string;
15
+ embeddingModel?: string;
16
+ debug?: boolean;
17
+ }
18
+ export declare class ContextMemorySettings {
19
+ openaiApiKey?: string;
20
+ openrouterApiKey?: string;
21
+ databaseUrl?: string;
22
+ llmProvider: LLMProvider;
23
+ llmModel: string;
24
+ embeddingModel: string;
25
+ debug: boolean;
26
+ constructor(cfg?: ContextMemoryConfig);
27
+ /** Return DB path — defaults to ~/.contextmemory/memory.db (SQLite) */
28
+ getDatabaseUrl(): string;
29
+ /** Get the correct API key for the active provider */
30
+ getApiKey(): string;
31
+ /** Base URL for the LLM provider */
32
+ getBaseUrl(): string | undefined;
33
+ validate(): void;
34
+ }
35
+ /**
36
+ * Configure ContextMemory programmatically.
37
+ * Call this once at app startup before using any Memory instances.
38
+ */
39
+ export declare function configure(cfg: ContextMemoryConfig): void;
40
+ /**
41
+ * Get current settings. Auto-loads from env vars if configure() not called.
42
+ */
43
+ export declare function getSettings(): ContextMemorySettings;
44
+ /** Reset settings (useful for testing) */
45
+ export declare function resetSettings(): void;
46
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/core/settings.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,YAAY,CAAC;AAElD,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,qBAAqB;IAChC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;gBAEH,GAAG,GAAE,mBAAwB;IAUzC,uEAAuE;IACvE,cAAc,IAAI,MAAM;IAOxB,sDAAsD;IACtD,SAAS,IAAI,MAAM;IAenB,oCAAoC;IACpC,UAAU,IAAI,MAAM,GAAG,SAAS;IAMhC,QAAQ,IAAI,IAAI;CAGjB;AAsBD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,mBAAmB,GAAG,IAAI,CAExD;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,qBAAqB,CAGnD;AAED,0CAA0C;AAC1C,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ /**
3
+ * ContextMemory Settings — TypeScript port of Python settings.py
4
+ *
5
+ * Supports two config methods:
6
+ * 1. Programmatic: configure({ openaiApiKey: "..." })
7
+ * 2. Environment variables: OPENAI_API_KEY, OPENROUTER_API_KEY, DATABASE_URL, ...
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.ContextMemorySettings = void 0;
44
+ exports.configure = configure;
45
+ exports.getSettings = getSettings;
46
+ exports.resetSettings = resetSettings;
47
+ const dotenv = __importStar(require("dotenv"));
48
+ const path = __importStar(require("path"));
49
+ const fs = __importStar(require("fs"));
50
+ const os = __importStar(require("os"));
51
+ dotenv.config();
52
+ class ContextMemorySettings {
53
+ openaiApiKey;
54
+ openrouterApiKey;
55
+ databaseUrl;
56
+ llmProvider;
57
+ llmModel;
58
+ embeddingModel;
59
+ debug;
60
+ constructor(cfg = {}) {
61
+ this.openaiApiKey = cfg.openaiApiKey;
62
+ this.openrouterApiKey = cfg.openrouterApiKey;
63
+ this.databaseUrl = cfg.databaseUrl;
64
+ this.llmProvider = cfg.llmProvider ?? "openai";
65
+ this.llmModel = cfg.llmModel ?? "gpt-4o-mini";
66
+ this.embeddingModel = cfg.embeddingModel ?? "text-embedding-3-small";
67
+ this.debug = cfg.debug ?? false;
68
+ }
69
+ /** Return DB path — defaults to ~/.contextmemory/memory.db (SQLite) */
70
+ getDatabaseUrl() {
71
+ if (this.databaseUrl)
72
+ return this.databaseUrl;
73
+ const dir = path.join(os.homedir(), ".contextmemory");
74
+ fs.mkdirSync(dir, { recursive: true });
75
+ return path.join(dir, "memory.db");
76
+ }
77
+ /** Get the correct API key for the active provider */
78
+ getApiKey() {
79
+ if (this.llmProvider === "openrouter") {
80
+ if (!this.openrouterApiKey)
81
+ throw new Error("OpenRouter API key is required. Call configure({ openrouterApiKey: '...' }) or set OPENROUTER_API_KEY.");
82
+ return this.openrouterApiKey;
83
+ }
84
+ if (!this.openaiApiKey)
85
+ throw new Error("OpenAI API key is required. Call configure({ openaiApiKey: '...' }) or set OPENAI_API_KEY.");
86
+ return this.openaiApiKey;
87
+ }
88
+ /** Base URL for the LLM provider */
89
+ getBaseUrl() {
90
+ return this.llmProvider === "openrouter"
91
+ ? "https://openrouter.ai/api/v1"
92
+ : undefined;
93
+ }
94
+ validate() {
95
+ this.getApiKey(); // throws if missing
96
+ }
97
+ }
98
+ exports.ContextMemorySettings = ContextMemorySettings;
99
+ // ─── Global singleton ──────────────────────────────────────────────────────
100
+ let _settings = null;
101
+ /** Load settings from environment variables */
102
+ function fromEnv() {
103
+ const provider = process.env.LLM_PROVIDER === "openrouter" ? "openrouter" : "openai";
104
+ return new ContextMemorySettings({
105
+ openaiApiKey: process.env.OPENAI_API_KEY,
106
+ openrouterApiKey: process.env.OPENROUTER_API_KEY,
107
+ databaseUrl: process.env.DATABASE_URL,
108
+ llmProvider: provider,
109
+ llmModel: process.env.LLM_MODEL ?? "gpt-4o-mini",
110
+ embeddingModel: process.env.EMBEDDING_MODEL ?? "text-embedding-3-small",
111
+ debug: ["true", "1", "yes"].includes((process.env.DEBUG ?? "").toLowerCase()),
112
+ });
113
+ }
114
+ /**
115
+ * Configure ContextMemory programmatically.
116
+ * Call this once at app startup before using any Memory instances.
117
+ */
118
+ function configure(cfg) {
119
+ _settings = new ContextMemorySettings(cfg);
120
+ }
121
+ /**
122
+ * Get current settings. Auto-loads from env vars if configure() not called.
123
+ */
124
+ function getSettings() {
125
+ if (!_settings)
126
+ _settings = fromEnv();
127
+ return _settings;
128
+ }
129
+ /** Reset settings (useful for testing) */
130
+ function resetSettings() {
131
+ _settings = null;
132
+ }
133
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/core/settings.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoGH,8BAEC;AAKD,kCAGC;AAGD,sCAEC;AAjHD,+CAAiC;AACjC,2CAA6B;AAC7B,uCAAyB;AACzB,uCAAyB;AAEzB,MAAM,CAAC,MAAM,EAAE,CAAC;AAchB,MAAa,qBAAqB;IAChC,YAAY,CAAU;IACtB,gBAAgB,CAAU;IAC1B,WAAW,CAAU;IACrB,WAAW,CAAc;IACzB,QAAQ,CAAS;IACjB,cAAc,CAAS;IACvB,KAAK,CAAU;IAEf,YAAY,MAA2B,EAAE;QACvC,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;QACrC,IAAI,CAAC,gBAAgB,GAAG,GAAG,CAAC,gBAAgB,CAAC;QAC7C,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;QACnC,IAAI,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,IAAI,QAAQ,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,aAAa,CAAC;QAC9C,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC,cAAc,IAAI,wBAAwB,CAAC;QACrE,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC;IAClC,CAAC;IAED,uEAAuE;IACvE,cAAc;QACZ,IAAI,IAAI,CAAC,WAAW;YAAE,OAAO,IAAI,CAAC,WAAW,CAAC;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,gBAAgB,CAAC,CAAC;QACtD,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACrC,CAAC;IAED,sDAAsD;IACtD,SAAS;QACP,IAAI,IAAI,CAAC,WAAW,KAAK,YAAY,EAAE,CAAC;YACtC,IAAI,CAAC,IAAI,CAAC,gBAAgB;gBACxB,MAAM,IAAI,KAAK,CACb,wGAAwG,CACzG,CAAC;YACJ,OAAO,IAAI,CAAC,gBAAgB,CAAC;QAC/B,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,YAAY;YACpB,MAAM,IAAI,KAAK,CACb,4FAA4F,CAC7F,CAAC;QACJ,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,oCAAoC;IACpC,UAAU;QACR,OAAO,IAAI,CAAC,WAAW,KAAK,YAAY;YACtC,CAAC,CAAC,8BAA8B;YAChC,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,oBAAoB;IACxC,CAAC;CACF;AArDD,sDAqDC;AAED,8EAA8E;AAC9E,IAAI,SAAS,GAAiC,IAAI,CAAC;AAEnD,+CAA+C;AAC/C,SAAS,OAAO;IACd,MAAM,QAAQ,GACZ,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;IACtE,OAAO,IAAI,qBAAqB,CAAC;QAC/B,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc;QACxC,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAChD,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;QACrC,WAAW,EAAE,QAAQ;QACrB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,aAAa;QAChD,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,wBAAwB;QACvE,KAAK,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,QAAQ,CAClC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CACxC;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAgB,SAAS,CAAC,GAAwB;IAChD,SAAS,GAAG,IAAI,qBAAqB,CAAC,GAAG,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW;IACzB,IAAI,CAAC,SAAS;QAAE,SAAS,GAAG,OAAO,EAAE,CAAC;IACtC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,0CAA0C;AAC1C,SAAgB,aAAa;IAC3B,SAAS,GAAG,IAAI,CAAC;AACnB,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * SQLite Database — TypeScript port using better-sqlite3 + Drizzle ORM schema.
3
+ *
4
+ * Tables:
5
+ * conversations — one row per conversation
6
+ * messages — chat turns (user / assistant)
7
+ * conversation_summary — rolling LLM-generated summary
8
+ * memories — semantic & episodic memory facts
9
+ */
10
+ import Database from "better-sqlite3";
11
+ export declare function getDb(): Database.Database;
12
+ /** Close and reset the DB connection (useful for testing) */
13
+ export declare function resetDb(): void;
14
+ export declare function createTables(): void;
15
+ export interface ConversationRow {
16
+ id: number;
17
+ created_at: string;
18
+ updated_at: string;
19
+ }
20
+ export interface MessageRow {
21
+ id: number;
22
+ conversation_id: number;
23
+ sender: "user" | "assistant";
24
+ message_text: string;
25
+ timestamp: string;
26
+ }
27
+ export interface SummaryRow {
28
+ id: number;
29
+ conversation_id: number;
30
+ summary_text: string | null;
31
+ updated_at: string;
32
+ }
33
+ export interface MemoryRow {
34
+ id: number;
35
+ conversation_id: number;
36
+ memory_text: string;
37
+ category: string | null;
38
+ embedding: string | null;
39
+ memory_metadata: string | null;
40
+ is_episodic: number;
41
+ occurred_at: string | null;
42
+ session_id: number | null;
43
+ importance: number;
44
+ is_active: number;
45
+ created_at: string;
46
+ updated_at: string;
47
+ }
48
+ export declare function parseEmbedding(row: MemoryRow): number[] | null;
49
+ export declare function parseMeta(row: MemoryRow): Record<string, unknown>;
50
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAStC,wBAAgB,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAYzC;AAED,6DAA6D;AAC7D,wBAAgB,OAAO,IAAI,IAAI,CAK9B;AAGD,wBAAgB,YAAY,IAAI,IAAI,CAuDnC;AAGD,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAGD,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,EAAE,GAAG,IAAI,CAG9D;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAGjE"}