engram-sdk 0.1.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 (69) hide show
  1. package/CONTRIBUTING.md +65 -0
  2. package/Dockerfile +21 -0
  3. package/EVAL-FRAMEWORK.md +70 -0
  4. package/EVAL.md +127 -0
  5. package/LICENSE +17 -0
  6. package/README.md +309 -0
  7. package/ROADMAP.md +113 -0
  8. package/deploy/fly.toml +26 -0
  9. package/dist/auto-ingest.d.ts +3 -0
  10. package/dist/auto-ingest.d.ts.map +1 -0
  11. package/dist/auto-ingest.js +334 -0
  12. package/dist/auto-ingest.js.map +1 -0
  13. package/dist/brief.d.ts +45 -0
  14. package/dist/brief.d.ts.map +1 -0
  15. package/dist/brief.js +183 -0
  16. package/dist/brief.js.map +1 -0
  17. package/dist/claude-watcher.d.ts +3 -0
  18. package/dist/claude-watcher.d.ts.map +1 -0
  19. package/dist/claude-watcher.js +385 -0
  20. package/dist/claude-watcher.js.map +1 -0
  21. package/dist/cli.d.ts +3 -0
  22. package/dist/cli.d.ts.map +1 -0
  23. package/dist/cli.js +764 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/embeddings.d.ts +42 -0
  26. package/dist/embeddings.d.ts.map +1 -0
  27. package/dist/embeddings.js +145 -0
  28. package/dist/embeddings.js.map +1 -0
  29. package/dist/eval.d.ts +2 -0
  30. package/dist/eval.d.ts.map +1 -0
  31. package/dist/eval.js +281 -0
  32. package/dist/eval.js.map +1 -0
  33. package/dist/extract.d.ts +11 -0
  34. package/dist/extract.d.ts.map +1 -0
  35. package/dist/extract.js +139 -0
  36. package/dist/extract.js.map +1 -0
  37. package/dist/hosted.d.ts +3 -0
  38. package/dist/hosted.d.ts.map +1 -0
  39. package/dist/hosted.js +144 -0
  40. package/dist/hosted.js.map +1 -0
  41. package/dist/index.d.ts +11 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +7 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/ingest.d.ts +28 -0
  46. package/dist/ingest.d.ts.map +1 -0
  47. package/dist/ingest.js +192 -0
  48. package/dist/ingest.js.map +1 -0
  49. package/dist/mcp.d.ts +3 -0
  50. package/dist/mcp.d.ts.map +1 -0
  51. package/dist/mcp.js +349 -0
  52. package/dist/mcp.js.map +1 -0
  53. package/dist/server.d.ts +17 -0
  54. package/dist/server.d.ts.map +1 -0
  55. package/dist/server.js +515 -0
  56. package/dist/server.js.map +1 -0
  57. package/dist/store.d.ts +87 -0
  58. package/dist/store.d.ts.map +1 -0
  59. package/dist/store.js +548 -0
  60. package/dist/store.js.map +1 -0
  61. package/dist/types.d.ts +204 -0
  62. package/dist/types.d.ts.map +1 -0
  63. package/dist/types.js +77 -0
  64. package/dist/types.js.map +1 -0
  65. package/dist/vault.d.ts +116 -0
  66. package/dist/vault.d.ts.map +1 -0
  67. package/dist/vault.js +1234 -0
  68. package/dist/vault.js.map +1 -0
  69. package/package.json +61 -0
@@ -0,0 +1,139 @@
1
+ // ============================================================
2
+ // Rule-Based Entity & Topic Extraction (No LLM Required)
3
+ // ============================================================
4
+ //
5
+ // Dogfooding revealed the gap: manually tagging entities and topics
6
+ // when calling remember() is tedious. This module auto-extracts
7
+ // entities and topics from raw text using simple heuristics.
8
+ //
9
+ // Not as good as LLM extraction, but works offline, costs nothing,
10
+ // and handles 80% of cases.
11
+ // Common stop words that shouldn't be entities
12
+ const STOP_WORDS = new Set([
13
+ 'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
14
+ 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
15
+ 'should', 'may', 'might', 'can', 'shall', 'to', 'of', 'in', 'for',
16
+ 'on', 'with', 'at', 'by', 'from', 'as', 'into', 'about', 'between',
17
+ 'through', 'during', 'before', 'after', 'and', 'but', 'or', 'not',
18
+ 'so', 'yet', 'both', 'either', 'neither', 'each', 'every', 'all',
19
+ 'any', 'some', 'no', 'only', 'very', 'just', 'also', 'than', 'too',
20
+ 'i', 'me', 'my', 'we', 'our', 'you', 'your', 'he', 'she', 'it',
21
+ 'they', 'them', 'his', 'her', 'its', 'their', 'this', 'that',
22
+ 'these', 'those', 'what', 'which', 'who', 'whom', 'how', 'when',
23
+ 'where', 'why', 'if', 'then', 'else', 'up', 'out', 'off', 'over',
24
+ 'under', 'again', 'once', 'here', 'there', 'more', 'most', 'other',
25
+ 'been', 'being', 'because', 'until', 'while', 'into', 'own', 'same',
26
+ 'such', 'few', 'much', 'many', 'like', 'just', 'now', 'still',
27
+ 'already', 'even', 'really', 'quite', 'well', 'back', 'way',
28
+ 'things', 'thing', 'something', 'nothing', 'everything', 'anything',
29
+ 'get', 'got', 'getting', 'make', 'made', 'making', 'take', 'took',
30
+ 'know', 'think', 'want', 'need', 'use', 'used', 'using', 'try',
31
+ 'going', 'come', 'came', 'see', 'look', 'say', 'said', 'tell',
32
+ ]);
33
+ // Topic keyword patterns
34
+ const TOPIC_PATTERNS = {
35
+ 'fitness': /\b(running|marathon|training|exercise|workout|gym|race|miles?|pace)\b/i,
36
+ 'engineering': /\b(code|programming|api|sdk|database|deploy|build|test|bug|refactor|typescript|python|react|node)\b/i,
37
+ 'career': /\b(job|work|company|team|promotion|role|position|hired|salary|interview|manager|pm|product\s*manager)\b/i,
38
+ 'preferences': /\b(prefer|prefers|preferred|like|love|hate|dislike|favorite|always|never|rather|instead|over)\b/i,
39
+ 'goals': /\b(goal|plan|want to|going to|will|hope|aim|target|dream|aspire|training for|preparing for)\b/i,
40
+ 'decisions': /\b(decided|decision|chose|picked|going with|switched to|pivoted|moved to)\b/i,
41
+ 'project': /\b(project|build|launch|ship|release|feature|roadmap|milestone|sprint)\b/i,
42
+ 'learning': /\b(learn|study|course|tutorial|reading|book|class|practice|piano)\b/i,
43
+ 'people': /\b(friend|family|wife|husband|partner|kid|child|parent|mom|dad|brother|sister|coach)\b/i,
44
+ 'strategy': /\b(strategy|approach|plan|roadmap|competitive|market|monetize|revenue|pricing)\b/i,
45
+ 'ai': /\b(ai|agent|llm|model|gpt|claude|openai|anthropic|memory|embedding|vector)\b/i,
46
+ };
47
+ // Salience signals
48
+ const HIGH_SALIENCE_PATTERNS = [
49
+ /\b(important|critical|key|must|always|never|essential|crucial)\b/i,
50
+ /\b(decided|committed|promise|goal|deadline)\b/i,
51
+ /\b(love|hate|strongly|absolutely|definitely)\b/i,
52
+ /\b(problem|issue|bug|error|broken|fix)\b/i,
53
+ ];
54
+ const LOW_SALIENCE_PATTERNS = [
55
+ /\b(maybe|perhaps|might|could|possibly|sometime|eventually)\b/i,
56
+ /\b(minor|trivial|small|little|slightly)\b/i,
57
+ ];
58
+ /**
59
+ * Extract entities and topics from raw text without an LLM.
60
+ * Uses capitalization heuristics, pattern matching, and simple NLP.
61
+ */
62
+ export function extract(text) {
63
+ const entities = extractEntities(text);
64
+ const topics = extractTopics(text);
65
+ const suggestedSalience = estimateSalience(text);
66
+ return { entities, topics, suggestedSalience };
67
+ }
68
+ function extractEntities(text) {
69
+ const entities = new Set();
70
+ // 1. Capitalized words/phrases (likely proper nouns)
71
+ // Match sequences of capitalized words, including camelCase/PascalCase compounds
72
+ const capitalizedPattern = /\b([A-Z][a-zA-Z]+(?:\s+[A-Z][a-zA-Z]+)*)\b/g;
73
+ let match;
74
+ while ((match = capitalizedPattern.exec(text)) !== null) {
75
+ const candidate = match[1];
76
+ // Skip if it's at the start of a sentence (check if preceded by . or start of string)
77
+ const before = text.substring(Math.max(0, match.index - 3), match.index).trim();
78
+ const isStartOfSentence = before === '' || before.endsWith('.') || before.endsWith('!') || before.endsWith('?') || before.endsWith(':') || before.endsWith('\n');
79
+ // If it's a single word at the start of a sentence, skip (probably just capitalized normally)
80
+ if (isStartOfSentence && !candidate.includes(' '))
81
+ continue;
82
+ // Skip common words that happen to be capitalized
83
+ if (STOP_WORDS.has(candidate.toLowerCase()))
84
+ continue;
85
+ if (candidate.length < 2)
86
+ continue;
87
+ entities.add(candidate);
88
+ }
89
+ // 2. All-caps acronyms (API, SDK, LLM, etc.)
90
+ const acronymPattern = /\b([A-Z]{2,6})\b/g;
91
+ while ((match = acronymPattern.exec(text)) !== null) {
92
+ const acr = match[1];
93
+ // Skip common non-entity acronyms
94
+ if (['OK', 'AM', 'PM', 'US', 'ID', 'VS', 'OR', 'IT', 'IF', 'DO', 'NO'].includes(acr))
95
+ continue;
96
+ entities.add(acr);
97
+ }
98
+ // 3. Technology names (often lowercase in text)
99
+ const techPattern = /\b(typescript|javascript|python|react|vue|angular|node\.?js|sqlite|postgres|redis|docker|vercel|aws|gcp|anthropic|openai|langchain|crewai)\b/gi;
100
+ while ((match = techPattern.exec(text)) !== null) {
101
+ // Normalize casing
102
+ const tech = match[1];
103
+ const normalized = tech.charAt(0).toUpperCase() + tech.slice(1).toLowerCase();
104
+ entities.add(normalized);
105
+ }
106
+ return [...entities].slice(0, 15); // Cap at 15 entities
107
+ }
108
+ function extractTopics(text) {
109
+ const topics = [];
110
+ for (const [topic, pattern] of Object.entries(TOPIC_PATTERNS)) {
111
+ if (pattern.test(text)) {
112
+ topics.push(topic);
113
+ }
114
+ }
115
+ return topics.slice(0, 8); // Cap at 8 topics
116
+ }
117
+ function estimateSalience(text) {
118
+ let salience = 0.5; // Default mid-range
119
+ // Boost for high-salience signals
120
+ for (const pattern of HIGH_SALIENCE_PATTERNS) {
121
+ if (pattern.test(text)) {
122
+ salience += 0.1;
123
+ }
124
+ }
125
+ // Reduce for low-salience signals
126
+ for (const pattern of LOW_SALIENCE_PATTERNS) {
127
+ if (pattern.test(text)) {
128
+ salience -= 0.1;
129
+ }
130
+ }
131
+ // Longer content tends to be more important
132
+ if (text.length > 200)
133
+ salience += 0.05;
134
+ if (text.length > 500)
135
+ salience += 0.05;
136
+ // Clamp to [0.1, 1.0]
137
+ return Math.max(0.1, Math.min(1.0, salience));
138
+ }
139
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../src/extract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=hosted.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hosted.d.ts","sourceRoot":"","sources":["../src/hosted.ts"],"names":[],"mappings":""}
package/dist/hosted.js ADDED
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+ // ============================================================
3
+ // Engram Hosted API — Multi-tenant server
4
+ // ============================================================
5
+ //
6
+ // Wraps createEngramServer with:
7
+ // - Dynamic API key provisioning (POST /v1/keys)
8
+ // - Per-user SQLite vaults on a persistent volume
9
+ // - Admin endpoints for key management
10
+ //
11
+ // ENV:
12
+ // ENGRAM_DATA_DIR — vault storage dir (default: /data)
13
+ // ENGRAM_ADMIN_KEY — admin key for provisioning
14
+ // ENGRAM_HOST — bind address (default: 0.0.0.0)
15
+ // ENGRAM_PORT — port (default: 3800)
16
+ // ENGRAM_LLM_PROVIDER — gemini|openai (shared across tenants)
17
+ // ENGRAM_LLM_API_KEY — LLM key (or GEMINI_API_KEY)
18
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
19
+ import { join } from 'node:path';
20
+ import { randomUUID } from 'node:crypto';
21
+ import { createEngramServer } from './server.js';
22
+ const DATA_DIR = process.env.ENGRAM_DATA_DIR ?? '/data';
23
+ const ADMIN_KEY = process.env.ENGRAM_ADMIN_KEY ?? '';
24
+ const PORT = parseInt(process.env.PORT ?? process.env.ENGRAM_PORT ?? '3800', 10);
25
+ const HOST = process.env.ENGRAM_HOST ?? '0.0.0.0';
26
+ const LLM_PROVIDER = process.env.ENGRAM_LLM_PROVIDER;
27
+ const LLM_API_KEY = process.env.ENGRAM_LLM_API_KEY ?? process.env.GEMINI_API_KEY;
28
+ const LLM_MODEL = process.env.ENGRAM_LLM_MODEL;
29
+ const EMBEDDING_MODEL = process.env.ENGRAM_EMBEDDING_MODEL;
30
+ const KEYS_PATH = join(DATA_DIR, 'keys.json');
31
+ function loadKeys() {
32
+ if (!existsSync(KEYS_PATH))
33
+ return {};
34
+ try {
35
+ return JSON.parse(readFileSync(KEYS_PATH, 'utf-8'));
36
+ }
37
+ catch {
38
+ return {};
39
+ }
40
+ }
41
+ function saveKeys(keys) {
42
+ mkdirSync(DATA_DIR, { recursive: true });
43
+ writeFileSync(KEYS_PATH, JSON.stringify(keys, null, 2));
44
+ }
45
+ // ============================================================
46
+ // Build vault configs from stored keys
47
+ // ============================================================
48
+ function keyToVaultConfig(record) {
49
+ const dbPath = join(DATA_DIR, 'vaults', `${record.owner}.db`);
50
+ mkdirSync(join(DATA_DIR, 'vaults'), { recursive: true });
51
+ return {
52
+ owner: record.owner,
53
+ dbPath,
54
+ agentId: 'hosted',
55
+ ...(LLM_PROVIDER && LLM_API_KEY ? {
56
+ llm: {
57
+ provider: LLM_PROVIDER,
58
+ apiKey: LLM_API_KEY,
59
+ model: LLM_MODEL,
60
+ embeddingModel: EMBEDDING_MODEL,
61
+ }
62
+ } : {}),
63
+ };
64
+ }
65
+ // Load existing keys and build the vaults map
66
+ const keys = loadKeys();
67
+ const vaults = {};
68
+ for (const [apiKey, record] of Object.entries(keys)) {
69
+ vaults[apiKey] = keyToVaultConfig(record);
70
+ }
71
+ // ============================================================
72
+ // Provision endpoint — injected before the core server starts
73
+ // ============================================================
74
+ // We'll intercept /v1/keys before delegating to the core server
75
+ // by wrapping the HTTP server's request handler
76
+ const coreSrv = createEngramServer({
77
+ port: PORT,
78
+ host: HOST,
79
+ vaults,
80
+ });
81
+ // Monkey-patch the underlying http server to intercept admin routes
82
+ const origHandler = coreSrv.server.listeners('request')[0];
83
+ coreSrv.server.removeAllListeners('request');
84
+ coreSrv.server.on('request', async (req, res) => {
85
+ const url = new URL(req.url, `http://${req.headers.host}`);
86
+ // Key provisioning
87
+ if (url.pathname === '/v1/keys' && req.method === 'POST') {
88
+ const auth = req.headers.authorization;
89
+ if (!ADMIN_KEY || auth !== `Bearer ${ADMIN_KEY}`) {
90
+ res.writeHead(401, { 'Content-Type': 'application/json' });
91
+ res.end(JSON.stringify({ error: 'Unauthorized' }));
92
+ return;
93
+ }
94
+ const chunks = [];
95
+ for await (const chunk of req)
96
+ chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
97
+ const body = JSON.parse(Buffer.concat(chunks).toString('utf-8'));
98
+ const owner = body.owner;
99
+ const email = body.email;
100
+ if (!owner) {
101
+ res.writeHead(400, { 'Content-Type': 'application/json' });
102
+ res.end(JSON.stringify({ error: 'owner is required' }));
103
+ return;
104
+ }
105
+ const apiKey = `engram_${randomUUID().replace(/-/g, '')}`;
106
+ const record = { apiKey, owner, email, createdAt: new Date().toISOString() };
107
+ // Register in both the keys store and the live vaults map
108
+ keys[apiKey] = record;
109
+ vaults[apiKey] = keyToVaultConfig(record);
110
+ saveKeys(keys);
111
+ res.writeHead(201, { 'Content-Type': 'application/json' });
112
+ res.end(JSON.stringify({ apiKey, owner, message: 'Use Authorization: Bearer ' + apiKey }));
113
+ return;
114
+ }
115
+ // List keys (admin)
116
+ if (url.pathname === '/v1/keys' && req.method === 'GET') {
117
+ const auth = req.headers.authorization;
118
+ if (!ADMIN_KEY || auth !== `Bearer ${ADMIN_KEY}`) {
119
+ res.writeHead(401, { 'Content-Type': 'application/json' });
120
+ res.end(JSON.stringify({ error: 'Unauthorized' }));
121
+ return;
122
+ }
123
+ const sanitized = Object.values(keys).map(k => ({
124
+ owner: k.owner, email: k.email, createdAt: k.createdAt,
125
+ apiKey: k.apiKey.slice(0, 12) + '...',
126
+ }));
127
+ res.writeHead(200, { 'Content-Type': 'application/json' });
128
+ res.end(JSON.stringify({ keys: sanitized, count: sanitized.length }));
129
+ return;
130
+ }
131
+ // Everything else → core server
132
+ origHandler(req, res);
133
+ });
134
+ // Start
135
+ coreSrv.listen().then(() => {
136
+ console.log(` Mode: hosted (multi-tenant)`);
137
+ console.log(` Data: ${DATA_DIR}`);
138
+ console.log(` Tenants: ${Object.keys(keys).length}`);
139
+ if (!ADMIN_KEY)
140
+ console.warn(' ⚠️ No ENGRAM_ADMIN_KEY — key provisioning disabled');
141
+ });
142
+ process.on('SIGINT', () => { saveKeys(keys); process.exit(0); });
143
+ process.on('SIGTERM', () => { saveKeys(keys); process.exit(0); });
144
+ //# sourceMappingURL=hosted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hosted.js","sourceRoot":"","sources":["../src/hosted.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export { Vault } from './vault.js';
2
+ export { createEngramServer } from './server.js';
3
+ export { extract } from './extract.js';
4
+ export { OpenAIEmbeddings, GeminiEmbeddings, LocalEmbeddings } from './embeddings.js';
5
+ export { ingest, ingestDailyLog } from './ingest.js';
6
+ export { brief } from './brief.js';
7
+ export type { EmbeddingProvider } from './embeddings.js';
8
+ export type { IngestOptions, IngestResult } from './ingest.js';
9
+ export type { BriefOptions, Briefing } from './brief.js';
10
+ export type { Memory, Edge, Entity, MemoryType, SourceType, EdgeType, Visibility, RememberInput, RememberParsed, RecallInput, RecallParsed, ConsolidationReport, VaultConfig, } from './types.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACtF,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/D,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EACV,MAAM,EACN,IAAI,EACJ,MAAM,EACN,UAAU,EACV,UAAU,EACV,QAAQ,EACR,UAAU,EACV,aAAa,EACb,cAAc,EACd,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,WAAW,GACZ,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { Vault } from './vault.js';
2
+ export { createEngramServer } from './server.js';
3
+ export { extract } from './extract.js';
4
+ export { OpenAIEmbeddings, GeminiEmbeddings, LocalEmbeddings } from './embeddings.js';
5
+ export { ingest, ingestDailyLog } from './ingest.js';
6
+ export { brief } from './brief.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACtF,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { Vault } from './vault.js';
2
+ import type { Memory, VaultConfig } from './types.js';
3
+ export interface IngestOptions {
4
+ agentId?: string;
5
+ sessionId?: string;
6
+ /** Who was the human in this conversation? */
7
+ humanName?: string;
8
+ /** Minimum salience threshold — skip trivial extractions */
9
+ minSalience?: number;
10
+ }
11
+ export interface IngestResult {
12
+ memoriesCreated: Memory[];
13
+ entitiesDiscovered: string[];
14
+ decisionsFound: number;
15
+ commitmentsFound: number;
16
+ }
17
+ /**
18
+ * Ingest a conversation transcript and automatically extract memories.
19
+ *
20
+ * This is the core intelligence layer — agents don't have to think about
21
+ * remembering. Feed in the conversation, get structured memories out.
22
+ */
23
+ export declare function ingest(vault: Vault, transcript: string, llmConfig: NonNullable<VaultConfig['llm']>, options?: IngestOptions): Promise<IngestResult>;
24
+ /**
25
+ * Ingest from a markdown daily log file (like OpenClaw's memory/YYYY-MM-DD.md format)
26
+ */
27
+ export declare function ingestDailyLog(vault: Vault, logContent: string, llmConfig: NonNullable<VaultConfig['llm']>, options?: IngestOptions): Promise<IngestResult>;
28
+ //# sourceMappingURL=ingest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.d.ts","sourceRoot":"","sources":["../src/ingest.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAiDD;;;;;GAKG;AACH,wBAAsB,MAAM,CAC1B,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAC1C,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA4DvB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAC1C,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA2BvB"}
package/dist/ingest.js ADDED
@@ -0,0 +1,192 @@
1
+ // ============================================================
2
+ // Conversation Ingest — Automatic memory extraction
3
+ // ============================================================
4
+ //
5
+ // The #1 gap: agents shouldn't have to manually call remember().
6
+ // This module watches conversation transcripts and automatically
7
+ // extracts structured memories using an LLM.
8
+ //
9
+ // Usage:
10
+ // const memories = await ingest(vault, transcript, { agentId, sessionId })
11
+ //
12
+ // The LLM identifies: facts, preferences, decisions, commitments,
13
+ // emotional moments, behavioral patterns — and creates memories
14
+ // with proper entity/topic/salience tagging.
15
+ const INGEST_PROMPT = `You are a memory extraction engine. Analyze this conversation and extract structured memories.
16
+
17
+ CONVERSATION:
18
+ {transcript}
19
+
20
+ CONTEXT:
21
+ - Human name: {humanName}
22
+ - Agent ID: {agentId}
23
+
24
+ Extract the following types of memories:
25
+
26
+ 1. **FACTS** — Things stated as true (preferences, biographical info, technical details)
27
+ 2. **DECISIONS** — Choices made during the conversation (what was decided and why)
28
+ 3. **COMMITMENTS** — Things either party committed to doing
29
+ 4. **INSIGHTS** — Behavioral patterns, emotional moments, relationship dynamics
30
+ 5. **PROCEDURAL** — How-to knowledge, workflows, lessons learned
31
+
32
+ For each memory, provide:
33
+ - content: Clear, standalone statement (should make sense without the conversation)
34
+ - type: "episodic" (events/specific moments), "semantic" (facts/knowledge), or "procedural" (how-to/lessons)
35
+ - entities: People, projects, tools, places mentioned
36
+ - topics: Relevant topic tags
37
+ - salience: 0.0-1.0 (how important is this for future interactions?)
38
+ - 0.9-1.0: Critical decisions, strong preferences, emotional moments
39
+ - 0.6-0.8: Useful context, project details, moderate preferences
40
+ - 0.3-0.5: Minor details, casual mentions
41
+ - 0.0-0.2: Trivial, unlikely to matter
42
+ - confidence: 0.0-1.0 (how certain is this extraction?)
43
+ - category: "fact" | "decision" | "commitment" | "insight" | "procedural"
44
+
45
+ Be SELECTIVE. Don't extract every sentence. Extract what would be valuable to recall in a future conversation days or weeks from now. Ask: "If I woke up with amnesia tomorrow and could only remember N things from this conversation, what would they be?"
46
+
47
+ Respond in this exact JSON format:
48
+ {
49
+ "memories": [
50
+ {
51
+ "content": "...",
52
+ "type": "episodic|semantic|procedural",
53
+ "entities": ["..."],
54
+ "topics": ["..."],
55
+ "salience": 0.0-1.0,
56
+ "confidence": 0.0-1.0,
57
+ "category": "fact|decision|commitment|insight|procedural"
58
+ }
59
+ ]
60
+ }`;
61
+ /**
62
+ * Ingest a conversation transcript and automatically extract memories.
63
+ *
64
+ * This is the core intelligence layer — agents don't have to think about
65
+ * remembering. Feed in the conversation, get structured memories out.
66
+ */
67
+ export async function ingest(vault, transcript, llmConfig, options = {}) {
68
+ const { agentId, sessionId, humanName = 'User', minSalience = 0.2 } = options;
69
+ const prompt = INGEST_PROMPT
70
+ .replace('{transcript}', transcript)
71
+ .replace('{humanName}', humanName)
72
+ .replace('{agentId}', agentId ?? 'unknown');
73
+ const response = await callLLM(llmConfig, prompt);
74
+ let parsed;
75
+ try {
76
+ parsed = JSON.parse(response);
77
+ }
78
+ catch {
79
+ return { memoriesCreated: [], entitiesDiscovered: [], decisionsFound: 0, commitmentsFound: 0 };
80
+ }
81
+ const memoriesCreated = [];
82
+ const entitiesSet = new Set();
83
+ let decisionsFound = 0;
84
+ let commitmentsFound = 0;
85
+ for (const mem of parsed.memories ?? []) {
86
+ if (mem.salience < minSalience)
87
+ continue;
88
+ const memory = vault.remember({
89
+ content: mem.content,
90
+ type: mem.type,
91
+ entities: mem.entities ?? [],
92
+ topics: [...(mem.topics ?? []), mem.category],
93
+ salience: mem.salience,
94
+ confidence: mem.confidence,
95
+ source: {
96
+ type: 'conversation',
97
+ agentId,
98
+ sessionId,
99
+ },
100
+ });
101
+ memoriesCreated.push(memory);
102
+ for (const e of mem.entities ?? [])
103
+ entitiesSet.add(e);
104
+ if (mem.category === 'decision')
105
+ decisionsFound++;
106
+ if (mem.category === 'commitment')
107
+ commitmentsFound++;
108
+ }
109
+ return {
110
+ memoriesCreated,
111
+ entitiesDiscovered: [...entitiesSet],
112
+ decisionsFound,
113
+ commitmentsFound,
114
+ };
115
+ }
116
+ /**
117
+ * Ingest from a markdown daily log file (like OpenClaw's memory/YYYY-MM-DD.md format)
118
+ */
119
+ export async function ingestDailyLog(vault, logContent, llmConfig, options = {}) {
120
+ // Daily logs are already semi-structured — we can be smarter about chunking
121
+ // Split into sections and process each one to avoid overwhelming the LLM
122
+ const sections = logContent.split(/^## /m).filter(s => s.trim());
123
+ const allResults = {
124
+ memoriesCreated: [],
125
+ entitiesDiscovered: [],
126
+ decisionsFound: 0,
127
+ commitmentsFound: 0,
128
+ };
129
+ for (const section of sections) {
130
+ const sectionText = `## ${section}`;
131
+ if (sectionText.length < 50)
132
+ continue; // Skip tiny sections
133
+ const result = await ingest(vault, sectionText, llmConfig, options);
134
+ allResults.memoriesCreated.push(...result.memoriesCreated);
135
+ allResults.entitiesDiscovered.push(...result.entitiesDiscovered);
136
+ allResults.decisionsFound += result.decisionsFound;
137
+ allResults.commitmentsFound += result.commitmentsFound;
138
+ }
139
+ // Deduplicate entities
140
+ allResults.entitiesDiscovered = [...new Set(allResults.entitiesDiscovered)];
141
+ return allResults;
142
+ }
143
+ // ============================================================
144
+ // LLM call helper (shared with vault.ts — TODO: extract to shared module)
145
+ // ============================================================
146
+ async function callLLM(config, prompt) {
147
+ if (config.provider === 'anthropic') {
148
+ const model = config.model ?? 'claude-3-5-haiku-20241022';
149
+ const response = await fetch('https://api.anthropic.com/v1/messages', {
150
+ method: 'POST',
151
+ headers: {
152
+ 'Content-Type': 'application/json',
153
+ 'x-api-key': config.apiKey,
154
+ 'anthropic-version': '2023-06-01',
155
+ },
156
+ body: JSON.stringify({
157
+ model,
158
+ max_tokens: 4096,
159
+ messages: [{ role: 'user', content: prompt }],
160
+ }),
161
+ });
162
+ if (!response.ok) {
163
+ throw new Error(`Anthropic API error: ${response.status}`);
164
+ }
165
+ const data = await response.json();
166
+ const text = data.content?.find(c => c.type === 'text')?.text ?? '';
167
+ const jsonMatch = text.match(/```json\s*([\s\S]*?)\s*```/) ?? text.match(/\{[\s\S]*\}/);
168
+ return jsonMatch ? (jsonMatch[1] ?? jsonMatch[0]) : text;
169
+ }
170
+ if (config.provider === 'openai') {
171
+ const model = config.model ?? 'gpt-4o-mini';
172
+ const response = await fetch('https://api.openai.com/v1/chat/completions', {
173
+ method: 'POST',
174
+ headers: {
175
+ 'Content-Type': 'application/json',
176
+ 'Authorization': `Bearer ${config.apiKey}`,
177
+ },
178
+ body: JSON.stringify({
179
+ model,
180
+ messages: [{ role: 'user', content: prompt }],
181
+ response_format: { type: 'json_object' },
182
+ }),
183
+ });
184
+ if (!response.ok) {
185
+ throw new Error(`OpenAI API error: ${response.status}`);
186
+ }
187
+ const data = await response.json();
188
+ return data.choices[0]?.message?.content ?? '';
189
+ }
190
+ throw new Error(`Unsupported provider: ${config.provider}`);
191
+ }
192
+ //# sourceMappingURL=ingest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingest.js","sourceRoot":"","sources":["../src/ingest.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,oDAAoD;AACpD,+DAA+D;AAC/D,EAAE;AACF,iEAAiE;AACjE,iEAAiE;AACjE,6CAA6C;AAC7C,EAAE;AACF,SAAS;AACT,6EAA6E;AAC7E,EAAE;AACF,kEAAkE;AAClE,gEAAgE;AAChE,6CAA6C;AAqB7C,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6CpB,CAAC;AAEH;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,KAAY,EACZ,UAAkB,EAClB,SAA0C,EAC1C,UAAyB,EAAE;IAE3B,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,MAAM,EAAE,WAAW,GAAG,GAAG,EAAE,GAAG,OAAO,CAAC;IAE9E,MAAM,MAAM,GAAG,aAAa;SACzB,OAAO,CAAC,cAAc,EAAE,UAAU,CAAC;SACnC,OAAO,CAAC,aAAa,EAAE,SAAS,CAAC;SACjC,OAAO,CAAC,WAAW,EAAE,OAAO,IAAI,SAAS,CAAC,CAAC;IAE9C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAElD,IAAI,MAQA,CAAC;IAEL,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,kBAAkB,EAAE,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC;IACjG,CAAC;IAED,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;IACtC,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,gBAAgB,GAAG,CAAC,CAAC;IAEzB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QACxC,IAAI,GAAG,CAAC,QAAQ,GAAG,WAAW;YAAE,SAAS;QAEzC,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC;YAC5B,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE;YAC5B,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC;YAC7C,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,MAAM,EAAE;gBACN,IAAI,EAAE,cAAc;gBACpB,OAAO;gBACP,SAAS;aACV;SACF,CAAC,CAAC;QAEH,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE;YAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACvD,IAAI,GAAG,CAAC,QAAQ,KAAK,UAAU;YAAE,cAAc,EAAE,CAAC;QAClD,IAAI,GAAG,CAAC,QAAQ,KAAK,YAAY;YAAE,gBAAgB,EAAE,CAAC;IACxD,CAAC;IAED,OAAO;QACL,eAAe;QACf,kBAAkB,EAAE,CAAC,GAAG,WAAW,CAAC;QACpC,cAAc;QACd,gBAAgB;KACjB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAY,EACZ,UAAkB,EAClB,SAA0C,EAC1C,UAAyB,EAAE;IAE3B,4EAA4E;IAC5E,yEAAyE;IACzE,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAEjE,MAAM,UAAU,GAAiB;QAC/B,eAAe,EAAE,EAAE;QACnB,kBAAkB,EAAE,EAAE;QACtB,cAAc,EAAE,CAAC;QACjB,gBAAgB,EAAE,CAAC;KACpB,CAAC;IAEF,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,IAAI,WAAW,CAAC,MAAM,GAAG,EAAE;YAAE,SAAS,CAAC,qBAAqB;QAE5D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QACpE,UAAU,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;QAC3D,UAAU,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACjE,UAAU,CAAC,cAAc,IAAI,MAAM,CAAC,cAAc,CAAC;QACnD,UAAU,CAAC,gBAAgB,IAAI,MAAM,CAAC,gBAAgB,CAAC;IACzD,CAAC;IAED,uBAAuB;IACvB,UAAU,CAAC,kBAAkB,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAE5E,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,+DAA+D;AAC/D,0EAA0E;AAC1E,+DAA+D;AAE/D,KAAK,UAAU,OAAO,CAAC,MAAuC,EAAE,MAAc;IAC5E,IAAI,MAAM,CAAC,QAAQ,KAAK,WAAW,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,2BAA2B,CAAC;QAC1D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,uCAAuC,EAAE;YACpE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,MAAM,CAAC,MAAM;gBAC1B,mBAAmB,EAAE,YAAY;aAClC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK;gBACL,UAAU,EAAE,IAAI;gBAChB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;aAC9C,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,wBAAwB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAwD,CAAC;QACzF,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;QACpE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,4BAA4B,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACxF,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3D,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,aAAa,CAAC;QAC5C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,4CAA4C,EAAE;YACzE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;aAC3C;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK;gBACL,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;gBAC7C,eAAe,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE;aACzC,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA0D,CAAC;QAC3F,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;IACjD,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,yBAAyB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC9D,CAAC"}
package/dist/mcp.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":""}