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.
- package/CONTRIBUTING.md +65 -0
- package/Dockerfile +21 -0
- package/EVAL-FRAMEWORK.md +70 -0
- package/EVAL.md +127 -0
- package/LICENSE +17 -0
- package/README.md +309 -0
- package/ROADMAP.md +113 -0
- package/deploy/fly.toml +26 -0
- package/dist/auto-ingest.d.ts +3 -0
- package/dist/auto-ingest.d.ts.map +1 -0
- package/dist/auto-ingest.js +334 -0
- package/dist/auto-ingest.js.map +1 -0
- package/dist/brief.d.ts +45 -0
- package/dist/brief.d.ts.map +1 -0
- package/dist/brief.js +183 -0
- package/dist/brief.js.map +1 -0
- package/dist/claude-watcher.d.ts +3 -0
- package/dist/claude-watcher.d.ts.map +1 -0
- package/dist/claude-watcher.js +385 -0
- package/dist/claude-watcher.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +764 -0
- package/dist/cli.js.map +1 -0
- package/dist/embeddings.d.ts +42 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +145 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/eval.d.ts +2 -0
- package/dist/eval.d.ts.map +1 -0
- package/dist/eval.js +281 -0
- package/dist/eval.js.map +1 -0
- package/dist/extract.d.ts +11 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +139 -0
- package/dist/extract.js.map +1 -0
- package/dist/hosted.d.ts +3 -0
- package/dist/hosted.d.ts.map +1 -0
- package/dist/hosted.js +144 -0
- package/dist/hosted.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest.d.ts +28 -0
- package/dist/ingest.d.ts.map +1 -0
- package/dist/ingest.js +192 -0
- package/dist/ingest.js.map +1 -0
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +349 -0
- package/dist/mcp.js.map +1 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +515 -0
- package/dist/server.js.map +1 -0
- package/dist/store.d.ts +87 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +548 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +204 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +77 -0
- package/dist/types.js.map +1 -0
- package/dist/vault.d.ts +116 -0
- package/dist/vault.d.ts.map +1 -0
- package/dist/vault.js +1234 -0
- package/dist/vault.js.map +1 -0
- package/package.json +61 -0
package/ROADMAP.md
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Engram Roadmap
|
|
2
|
+
|
|
3
|
+
*Last updated: 2026-02-17*
|
|
4
|
+
|
|
5
|
+
## Phase 1 — Foundation ✅ Current
|
|
6
|
+
|
|
7
|
+
**What:** The core memory engine — SDK, REST API, auto-extraction, consolidation, and vector search.
|
|
8
|
+
|
|
9
|
+
**Why it matters:** This is the proof that structured memory is fundamentally better than flat files and vector-only search. Everything else builds on this foundation.
|
|
10
|
+
|
|
11
|
+
### Done
|
|
12
|
+
- [x] Memory types: episodic, semantic, procedural
|
|
13
|
+
- [x] Vault API: remember(), recall(), forget(), connect(), consolidate()
|
|
14
|
+
- [x] SQLite storage with sqlite-vec vector search
|
|
15
|
+
- [x] Memory graph with typed edges (supports, contradicts, elaborates, supersedes, etc.)
|
|
16
|
+
- [x] Entity tracking across memories
|
|
17
|
+
- [x] Memory decay with configurable half-life
|
|
18
|
+
- [x] LLM-powered consolidation (Anthropic, OpenAI)
|
|
19
|
+
- [x] Rule-based consolidation (no LLM fallback)
|
|
20
|
+
- [x] REST API server — all Vault operations exposed, CORS, health endpoint
|
|
21
|
+
- [x] Auto-extraction: rule-based entities, topics, salience estimation
|
|
22
|
+
- [x] POST /v1/ingest endpoint for raw text
|
|
23
|
+
- [x] CLI with REPL mode
|
|
24
|
+
- [x] Conversation ingest pipeline (LLM-powered)
|
|
25
|
+
- [x] Session briefing generation
|
|
26
|
+
- [x] Spreading activation recall
|
|
27
|
+
- [x] Proactive memory surfacing
|
|
28
|
+
- [x] Marketing site deployed (engram-site.vercel.app)
|
|
29
|
+
- [x] 86+ tests passing across 5 test files
|
|
30
|
+
|
|
31
|
+
### Next
|
|
32
|
+
- [ ] Domain resolution (engram.ai or fallback)
|
|
33
|
+
- [ ] Public repo launch
|
|
34
|
+
- [ ] Launch announcements (HN, Product Hunt, X, r/LocalLLaMA)
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Phase 2 — Hosted Service
|
|
39
|
+
|
|
40
|
+
**What:** Multi-tenant hosted API at api.engram.ai — the primary product.
|
|
41
|
+
|
|
42
|
+
**Why it matters:** Most developers don't want to run infrastructure. A hosted API with a generous free tier removes all friction. This is the business.
|
|
43
|
+
|
|
44
|
+
### To Build
|
|
45
|
+
- [ ] Multi-tenant architecture — isolated vaults per API key
|
|
46
|
+
- [ ] Auth system — API key generation, scoping, rotation
|
|
47
|
+
- [ ] Usage metering — track memories stored, recalls, consolidations
|
|
48
|
+
- [ ] Rate limiting — per-key limits, burst handling
|
|
49
|
+
- [ ] Billing integration — usage-based pricing, Stripe
|
|
50
|
+
- [ ] Dashboard — API key management, usage graphs, vault inspector
|
|
51
|
+
- [ ] Managed consolidation — scheduled sleep cycles, no user infra needed
|
|
52
|
+
- [ ] Free tier: 1 vault, 10K memories, 1K recalls/day
|
|
53
|
+
- [ ] Pro tier: unlimited vaults, priority consolidation, higher limits
|
|
54
|
+
- [ ] Enterprise: dedicated infrastructure, SSO, SLAs
|
|
55
|
+
|
|
56
|
+
### Why Usage-Based
|
|
57
|
+
Memory is sensitive data. Charging by usage (not seats) means individuals and small teams can use the full API for free or near-free, while heavy users pay proportionally. No artificial feature gates.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Phase 3 — Intelligence
|
|
62
|
+
|
|
63
|
+
**What:** Upgrade the brain — LLM-powered extraction, smarter consolidation, proactive context, contradiction detection.
|
|
64
|
+
|
|
65
|
+
**Why it matters:** Rule-based extraction works but misses nuance. LLM-powered intelligence makes Engram dramatically better at understanding what matters and surfacing it at the right time.
|
|
66
|
+
|
|
67
|
+
### To Build
|
|
68
|
+
- [ ] LLM-powered entity extraction (upgrade from regex/rules)
|
|
69
|
+
- [ ] Smart consolidation — cross-session pattern detection, temporal reasoning
|
|
70
|
+
- [ ] Proactive context surfacing — push relevant memories before the agent asks
|
|
71
|
+
- [ ] Contradiction detection — flag conflicting memories automatically
|
|
72
|
+
- [ ] Salience learning — adapt importance scoring based on access patterns
|
|
73
|
+
- [ ] Memory summarization — compress old episodes without losing key facts
|
|
74
|
+
- [ ] Confidence calibration — track how often recalled memories are actually useful
|
|
75
|
+
|
|
76
|
+
### Why This Comes After Hosted
|
|
77
|
+
Intelligence features consume LLM tokens. Running them in the hosted service means users don't need their own LLM API keys. The hosted tier absorbs the cost and passes it through in usage pricing.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Phase 4 — Ecosystem
|
|
82
|
+
|
|
83
|
+
**What:** Official integrations, protocol specification, developer ecosystem.
|
|
84
|
+
|
|
85
|
+
**Why it matters:** Engram's value multiplies when every agent framework can plug into it. An open protocol means the memory layer isn't locked to one vendor.
|
|
86
|
+
|
|
87
|
+
### To Build
|
|
88
|
+
- [ ] OpenClaw integration — replace flat-file memory with structured Engram
|
|
89
|
+
- [ ] LangChain memory adapter
|
|
90
|
+
- [ ] CrewAI memory adapter
|
|
91
|
+
- [ ] Python SDK (thin client over REST)
|
|
92
|
+
- [ ] Protocol specification — open standard for agent memory interop
|
|
93
|
+
- [ ] Developer documentation site
|
|
94
|
+
- [ ] Multi-agent vault sharing (agents share memories with permissions)
|
|
95
|
+
- [ ] Cross-agent conflict resolution
|
|
96
|
+
- [ ] Webhook notifications on memory events
|
|
97
|
+
- [ ] Import/export adapters for other memory systems
|
|
98
|
+
|
|
99
|
+
### The Protocol Vision
|
|
100
|
+
Agent memory shouldn't be locked to any framework or vendor. The Engram protocol spec defines a standard way for agents to store, recall, connect, and consolidate memories — regardless of implementation. Any tool can implement it, any agent can use it.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Metrics
|
|
105
|
+
|
|
106
|
+
- Waitlist signups
|
|
107
|
+
- API keys issued
|
|
108
|
+
- Memories stored (hosted)
|
|
109
|
+
- Monthly active vaults
|
|
110
|
+
- Recall latency p50/p95
|
|
111
|
+
- Consolidation quality (manual eval)
|
|
112
|
+
- GitHub stars / npm downloads
|
|
113
|
+
- Integration adoption
|
package/deploy/fly.toml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
app = "engram-api"
|
|
2
|
+
primary_region = "sjc"
|
|
3
|
+
|
|
4
|
+
[build]
|
|
5
|
+
dockerfile = "../Dockerfile"
|
|
6
|
+
|
|
7
|
+
[env]
|
|
8
|
+
NODE_ENV = "production"
|
|
9
|
+
ENGRAM_HOST = "0.0.0.0"
|
|
10
|
+
ENGRAM_PORT = "3800"
|
|
11
|
+
ENGRAM_CORS_ORIGIN = "*"
|
|
12
|
+
|
|
13
|
+
[http_service]
|
|
14
|
+
internal_port = 3800
|
|
15
|
+
force_https = true
|
|
16
|
+
auto_stop_machines = "stop"
|
|
17
|
+
auto_start_machines = true
|
|
18
|
+
min_machines_running = 1
|
|
19
|
+
|
|
20
|
+
[mounts]
|
|
21
|
+
source = "engram_data"
|
|
22
|
+
destination = "/data"
|
|
23
|
+
|
|
24
|
+
[[vm]]
|
|
25
|
+
size = "shared-cpu-1x"
|
|
26
|
+
memory = "512mb"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-ingest.d.ts","sourceRoot":"","sources":["../src/auto-ingest.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
// ============================================================
|
|
3
|
+
// Auto-Ingest — Watch OpenClaw transcripts and extract memories
|
|
4
|
+
// ============================================================
|
|
5
|
+
//
|
|
6
|
+
// Reads the active session transcript, finds new messages since
|
|
7
|
+
// last run, chunks them, and sends to the Engram ingest pipeline.
|
|
8
|
+
//
|
|
9
|
+
// Usage:
|
|
10
|
+
// npx tsx src/auto-ingest.ts # One-shot
|
|
11
|
+
// npx tsx src/auto-ingest.ts --watch # Watch mode
|
|
12
|
+
// ENGRAM_API=http://localhost:3800 npx tsx src/auto-ingest.ts
|
|
13
|
+
//
|
|
14
|
+
// State tracked in: ~/.config/engram/ingest-state.json
|
|
15
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from 'fs';
|
|
16
|
+
import { join } from 'path';
|
|
17
|
+
import { homedir } from 'os';
|
|
18
|
+
// ============================================================
|
|
19
|
+
// Config
|
|
20
|
+
// ============================================================
|
|
21
|
+
const ENGRAM_API = process.env.ENGRAM_API ?? 'http://127.0.0.1:3800/v1';
|
|
22
|
+
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
|
|
23
|
+
const STATE_PATH = join(homedir(), '.config', 'engram', 'ingest-state.json');
|
|
24
|
+
const SESSIONS_DIR = join(homedir(), '.openclaw', 'agents', 'main', 'sessions');
|
|
25
|
+
// Minimum conversation chunk size worth ingesting (characters)
|
|
26
|
+
const MIN_CHUNK_SIZE = 200;
|
|
27
|
+
// Maximum chunk size to send to LLM at once
|
|
28
|
+
const MAX_CHUNK_SIZE = 4000;
|
|
29
|
+
// Skip messages shorter than this (trivial)
|
|
30
|
+
const MIN_MESSAGE_LENGTH = 20;
|
|
31
|
+
function loadState() {
|
|
32
|
+
if (existsSync(STATE_PATH)) {
|
|
33
|
+
return JSON.parse(readFileSync(STATE_PATH, 'utf-8'));
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
lastIngestedLine: {},
|
|
37
|
+
lastRunAt: new Date(0).toISOString(),
|
|
38
|
+
totalMemoriesCreated: 0,
|
|
39
|
+
totalRunCount: 0,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function saveState(state) {
|
|
43
|
+
writeFileSync(STATE_PATH, JSON.stringify(state, null, 2));
|
|
44
|
+
}
|
|
45
|
+
function findActiveTranscript() {
|
|
46
|
+
if (!existsSync(SESSIONS_DIR))
|
|
47
|
+
return null;
|
|
48
|
+
const files = readdirSync(SESSIONS_DIR)
|
|
49
|
+
.filter(f => f.endsWith('.jsonl') && !f.includes('deleted'))
|
|
50
|
+
.map(f => ({
|
|
51
|
+
name: f,
|
|
52
|
+
path: join(SESSIONS_DIR, f),
|
|
53
|
+
mtime: statSync(join(SESSIONS_DIR, f)).mtimeMs,
|
|
54
|
+
}))
|
|
55
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
56
|
+
if (files.length === 0)
|
|
57
|
+
return null;
|
|
58
|
+
const latest = files[0];
|
|
59
|
+
const sessionId = latest.name.replace('.jsonl', '');
|
|
60
|
+
return { path: latest.path, sessionId };
|
|
61
|
+
}
|
|
62
|
+
function parseTranscript(filePath, startLine = 0) {
|
|
63
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
64
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
65
|
+
const turns = [];
|
|
66
|
+
for (let i = startLine; i < lines.length; i++) {
|
|
67
|
+
try {
|
|
68
|
+
const entry = JSON.parse(lines[i]);
|
|
69
|
+
if (entry.type !== 'message' || !entry.message)
|
|
70
|
+
continue;
|
|
71
|
+
const role = entry.message.role;
|
|
72
|
+
if (role !== 'user' && role !== 'assistant')
|
|
73
|
+
continue;
|
|
74
|
+
// Extract text content (skip thinking, tool calls)
|
|
75
|
+
const textParts = (entry.message.content ?? [])
|
|
76
|
+
.filter((c) => c.type === 'text')
|
|
77
|
+
.map((c) => c.text)
|
|
78
|
+
.join('\n')
|
|
79
|
+
.trim();
|
|
80
|
+
if (!textParts || textParts.length < MIN_MESSAGE_LENGTH)
|
|
81
|
+
continue;
|
|
82
|
+
// Skip system messages and metadata
|
|
83
|
+
if (textParts.startsWith('System:') && !textParts.includes('MST]'))
|
|
84
|
+
continue;
|
|
85
|
+
// Clean up: remove system prefixes from user messages
|
|
86
|
+
let cleanText = textParts;
|
|
87
|
+
// Extract the actual human message from user turns (after the timestamp)
|
|
88
|
+
const humanMatch = cleanText.match(/\[.*?MST\]\s*(.*)/s);
|
|
89
|
+
if (role === 'user' && humanMatch) {
|
|
90
|
+
cleanText = humanMatch[1].trim();
|
|
91
|
+
}
|
|
92
|
+
// Skip if it's just system noise
|
|
93
|
+
if (cleanText.startsWith('System:') && cleanText.length < 100)
|
|
94
|
+
continue;
|
|
95
|
+
// Skip heartbeat acks
|
|
96
|
+
if (cleanText === 'HEARTBEAT_OK' || cleanText === 'NO_REPLY')
|
|
97
|
+
continue;
|
|
98
|
+
if (cleanText.length >= MIN_MESSAGE_LENGTH) {
|
|
99
|
+
turns.push({
|
|
100
|
+
role,
|
|
101
|
+
text: cleanText,
|
|
102
|
+
timestamp: entry.timestamp ?? new Date().toISOString(),
|
|
103
|
+
lineNumber: i,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Skip malformed lines
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return turns;
|
|
112
|
+
}
|
|
113
|
+
// ============================================================
|
|
114
|
+
// Chunking — group turns into conversation segments
|
|
115
|
+
// ============================================================
|
|
116
|
+
function chunkConversation(turns) {
|
|
117
|
+
const chunks = [];
|
|
118
|
+
let currentChunk = '';
|
|
119
|
+
for (const turn of turns) {
|
|
120
|
+
const prefix = turn.role === 'user' ? 'Human' : 'Agent';
|
|
121
|
+
const line = `${prefix}: ${turn.text}\n\n`;
|
|
122
|
+
if (currentChunk.length + line.length > MAX_CHUNK_SIZE && currentChunk.length >= MIN_CHUNK_SIZE) {
|
|
123
|
+
chunks.push(currentChunk.trim());
|
|
124
|
+
currentChunk = '';
|
|
125
|
+
}
|
|
126
|
+
currentChunk += line;
|
|
127
|
+
}
|
|
128
|
+
if (currentChunk.length >= MIN_CHUNK_SIZE) {
|
|
129
|
+
chunks.push(currentChunk.trim());
|
|
130
|
+
}
|
|
131
|
+
return chunks;
|
|
132
|
+
}
|
|
133
|
+
async function ingestChunk(chunk) {
|
|
134
|
+
// Use the LLM-powered ingest if available, otherwise fall back to simple remember
|
|
135
|
+
if (GEMINI_API_KEY) {
|
|
136
|
+
return await llmIngest(chunk);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// Simple mode: store the chunk as a single episodic memory
|
|
140
|
+
const res = await fetch(`${ENGRAM_API}/ingest`, {
|
|
141
|
+
method: 'POST',
|
|
142
|
+
headers: { 'Content-Type': 'application/json' },
|
|
143
|
+
body: JSON.stringify({ text: chunk }),
|
|
144
|
+
});
|
|
145
|
+
return res.ok ? 1 : 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
async function llmIngest(chunk) {
|
|
149
|
+
const prompt = `You are a memory extraction engine for an AI agent. Analyze this conversation segment and extract structured memories worth keeping long-term.
|
|
150
|
+
|
|
151
|
+
CONVERSATION:
|
|
152
|
+
${chunk}
|
|
153
|
+
|
|
154
|
+
Extract memories that would be valuable to recall days or weeks from now. For each, provide:
|
|
155
|
+
- content: A clear, standalone statement (should make sense without the conversation)
|
|
156
|
+
- type: "episodic" (specific events/decisions), "semantic" (facts/preferences/patterns), or "procedural" (how-to/lessons)
|
|
157
|
+
- entities: People, projects, tools, places mentioned
|
|
158
|
+
- topics: Relevant topic tags
|
|
159
|
+
- salience: 0.0-1.0 (how important for future recall?)
|
|
160
|
+
- status: "active" (default), "pending" (if it's a commitment/plan not yet done)
|
|
161
|
+
|
|
162
|
+
Be SELECTIVE. Extract only what matters. Skip small talk, acknowledgments, and trivial exchanges.
|
|
163
|
+
|
|
164
|
+
Respond as JSON:
|
|
165
|
+
{"memories": [{"content": "...", "type": "...", "entities": ["..."], "topics": ["..."], "salience": 0.0-1.0, "status": "active|pending"}]}
|
|
166
|
+
|
|
167
|
+
If nothing worth remembering, respond: {"memories": []}`;
|
|
168
|
+
try {
|
|
169
|
+
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${GEMINI_API_KEY}`, {
|
|
170
|
+
method: 'POST',
|
|
171
|
+
headers: { 'Content-Type': 'application/json' },
|
|
172
|
+
body: JSON.stringify({
|
|
173
|
+
contents: [{ parts: [{ text: prompt }] }],
|
|
174
|
+
generationConfig: { responseMimeType: 'application/json', maxOutputTokens: 2048 },
|
|
175
|
+
}),
|
|
176
|
+
});
|
|
177
|
+
if (!response.ok) {
|
|
178
|
+
if (response.status === 429) {
|
|
179
|
+
// Rate limited — back off and retry once
|
|
180
|
+
console.warn(`Gemini rate limited, waiting 15s and retrying...`);
|
|
181
|
+
await new Promise(resolve => setTimeout(resolve, 15000));
|
|
182
|
+
const retry = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${GEMINI_API_KEY}`, {
|
|
183
|
+
method: 'POST',
|
|
184
|
+
headers: { 'Content-Type': 'application/json' },
|
|
185
|
+
body: JSON.stringify({
|
|
186
|
+
contents: [{ parts: [{ text: prompt }] }],
|
|
187
|
+
generationConfig: { responseMimeType: 'application/json', maxOutputTokens: 2048 },
|
|
188
|
+
}),
|
|
189
|
+
});
|
|
190
|
+
if (!retry.ok) {
|
|
191
|
+
console.error(`Gemini API error after retry: ${retry.status}`);
|
|
192
|
+
return 0;
|
|
193
|
+
}
|
|
194
|
+
const retryData = await retry.json();
|
|
195
|
+
const retryText = retryData.candidates?.[0]?.content?.parts?.[0]?.text ?? '{}';
|
|
196
|
+
const retryParsed = JSON.parse(retryText);
|
|
197
|
+
// Process retry results below
|
|
198
|
+
let created = 0;
|
|
199
|
+
for (const mem of retryParsed.memories ?? []) {
|
|
200
|
+
if (mem.salience < 0.2)
|
|
201
|
+
continue;
|
|
202
|
+
if (/(?:sk-|api[_-]?key|password|token|secret)[:\s=]+\S{10,}/i.test(mem.content))
|
|
203
|
+
continue;
|
|
204
|
+
if (/AIza[a-zA-Z0-9_-]{30,}/.test(mem.content))
|
|
205
|
+
continue;
|
|
206
|
+
const res = await fetch(`${ENGRAM_API}/memories`, {
|
|
207
|
+
method: 'POST',
|
|
208
|
+
headers: { 'Content-Type': 'application/json' },
|
|
209
|
+
body: JSON.stringify({
|
|
210
|
+
content: mem.content,
|
|
211
|
+
type: mem.type ?? 'episodic',
|
|
212
|
+
entities: mem.entities ?? [],
|
|
213
|
+
topics: [...(mem.topics ?? []), 'auto-ingested'],
|
|
214
|
+
salience: mem.salience ?? 0.5,
|
|
215
|
+
status: mem.status ?? 'active',
|
|
216
|
+
source: { type: 'conversation' },
|
|
217
|
+
}),
|
|
218
|
+
});
|
|
219
|
+
if (res.ok)
|
|
220
|
+
created++;
|
|
221
|
+
}
|
|
222
|
+
return created;
|
|
223
|
+
}
|
|
224
|
+
console.error(`Gemini API error: ${response.status}`);
|
|
225
|
+
return 0;
|
|
226
|
+
}
|
|
227
|
+
const data = await response.json();
|
|
228
|
+
const text = data.candidates?.[0]?.content?.parts?.[0]?.text ?? '{}';
|
|
229
|
+
const parsed = JSON.parse(text);
|
|
230
|
+
let created = 0;
|
|
231
|
+
for (const mem of parsed.memories ?? []) {
|
|
232
|
+
if (mem.salience < 0.2)
|
|
233
|
+
continue; // Skip trivial
|
|
234
|
+
// Security: never store secrets
|
|
235
|
+
if (/(?:sk-|api[_-]?key|password|token|secret)[:\s=]+\S{10,}/i.test(mem.content))
|
|
236
|
+
continue;
|
|
237
|
+
if (/AIza[a-zA-Z0-9_-]{30,}/.test(mem.content))
|
|
238
|
+
continue; // Google API keys
|
|
239
|
+
const res = await fetch(`${ENGRAM_API}/memories`, {
|
|
240
|
+
method: 'POST',
|
|
241
|
+
headers: { 'Content-Type': 'application/json' },
|
|
242
|
+
body: JSON.stringify({
|
|
243
|
+
content: mem.content,
|
|
244
|
+
type: mem.type ?? 'episodic',
|
|
245
|
+
entities: mem.entities ?? [],
|
|
246
|
+
topics: [...(mem.topics ?? []), 'auto-ingested'],
|
|
247
|
+
salience: mem.salience ?? 0.5,
|
|
248
|
+
status: mem.status ?? 'active',
|
|
249
|
+
source: { type: 'conversation' },
|
|
250
|
+
}),
|
|
251
|
+
});
|
|
252
|
+
if (res.ok)
|
|
253
|
+
created++;
|
|
254
|
+
}
|
|
255
|
+
return created;
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
console.error('LLM ingest error:', err);
|
|
259
|
+
return 0;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
async function ingestNewMessages() {
|
|
263
|
+
const state = loadState();
|
|
264
|
+
const transcript = findActiveTranscript();
|
|
265
|
+
if (!transcript) {
|
|
266
|
+
console.log('No active transcript found.');
|
|
267
|
+
return { memoriesCreated: 0, chunks: 0 };
|
|
268
|
+
}
|
|
269
|
+
const startLine = state.lastIngestedLine[transcript.sessionId] ?? 0;
|
|
270
|
+
console.log(`Reading transcript ${transcript.sessionId} from line ${startLine}...`);
|
|
271
|
+
const turns = parseTranscript(transcript.path, startLine);
|
|
272
|
+
if (turns.length === 0) {
|
|
273
|
+
console.log('No new messages to ingest.');
|
|
274
|
+
return { memoriesCreated: 0, chunks: 0 };
|
|
275
|
+
}
|
|
276
|
+
console.log(`Found ${turns.length} new turns. Chunking...`);
|
|
277
|
+
const chunks = chunkConversation(turns);
|
|
278
|
+
console.log(`${chunks.length} chunks to process.`);
|
|
279
|
+
let totalCreated = 0;
|
|
280
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
281
|
+
console.log(`Processing chunk ${i + 1}/${chunks.length}...`);
|
|
282
|
+
const created = await ingestChunk(chunks[i]);
|
|
283
|
+
totalCreated += created;
|
|
284
|
+
console.log(` → ${created} memories extracted`);
|
|
285
|
+
// Rate limit: wait between chunks to avoid 429s
|
|
286
|
+
if (i < chunks.length - 1) {
|
|
287
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// Update state
|
|
291
|
+
const lastLine = turns[turns.length - 1].lineNumber + 1;
|
|
292
|
+
state.lastIngestedLine[transcript.sessionId] = lastLine;
|
|
293
|
+
state.lastRunAt = new Date().toISOString();
|
|
294
|
+
state.totalMemoriesCreated += totalCreated;
|
|
295
|
+
state.totalRunCount++;
|
|
296
|
+
saveState(state);
|
|
297
|
+
console.log(`\nDone. ${totalCreated} memories created from ${chunks.length} chunks.`);
|
|
298
|
+
console.log(`Total across all runs: ${state.totalMemoriesCreated} memories in ${state.totalRunCount} runs.`);
|
|
299
|
+
return { memoriesCreated: totalCreated, chunks: chunks.length };
|
|
300
|
+
}
|
|
301
|
+
// ============================================================
|
|
302
|
+
// Main
|
|
303
|
+
// ============================================================
|
|
304
|
+
const isWatch = process.argv.includes('--watch');
|
|
305
|
+
// Interval in ms — default 5 min, configurable via ENGRAM_INGEST_INTERVAL_MS
|
|
306
|
+
const intervalMs = parseInt(process.env.ENGRAM_INGEST_INTERVAL_MS ?? '300000', 10);
|
|
307
|
+
if (isWatch) {
|
|
308
|
+
const mins = Math.round(intervalMs / 60000);
|
|
309
|
+
console.log(`🧠 Engram auto-ingest running in watch mode (every ${mins} min)...`);
|
|
310
|
+
let running = false;
|
|
311
|
+
const run = async () => {
|
|
312
|
+
if (running)
|
|
313
|
+
return; // skip if previous run still going
|
|
314
|
+
running = true;
|
|
315
|
+
try {
|
|
316
|
+
const result = await ingestNewMessages();
|
|
317
|
+
if (result && result.memoriesCreated > 0) {
|
|
318
|
+
console.log(` ✓ ${result.memoriesCreated} memories from ${result.chunks} chunks at ${new Date().toLocaleTimeString()}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch (err) {
|
|
322
|
+
console.error('Ingest error:', err);
|
|
323
|
+
}
|
|
324
|
+
finally {
|
|
325
|
+
running = false;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
run();
|
|
329
|
+
setInterval(run, intervalMs);
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
ingestNewMessages().catch(console.error);
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=auto-ingest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-ingest.js","sourceRoot":"","sources":["../src/auto-ingest.ts"],"names":[],"mappings":"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"}
|
package/dist/brief.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Vault } from './vault.js';
|
|
2
|
+
import type { Memory } from './types.js';
|
|
3
|
+
export interface BriefOptions {
|
|
4
|
+
/** Who is the agent talking to? Boosts memories about this person. */
|
|
5
|
+
who?: string;
|
|
6
|
+
/** Current time (defaults to now). Affects temporal relevance. */
|
|
7
|
+
when?: Date;
|
|
8
|
+
/** Recent topic hints (from conversation opener, etc.) */
|
|
9
|
+
recentTopics?: string[];
|
|
10
|
+
/** Recent entity hints */
|
|
11
|
+
recentEntities?: string[];
|
|
12
|
+
/** Max memories to include in briefing */
|
|
13
|
+
maxMemories?: number;
|
|
14
|
+
/** Include behavioral patterns? (requires semantic memories from consolidation) */
|
|
15
|
+
includePatterns?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface Briefing {
|
|
18
|
+
/** Structured summary suitable for agent context injection */
|
|
19
|
+
summary: string;
|
|
20
|
+
/** Key facts about the person we're talking to */
|
|
21
|
+
personContext: Memory[];
|
|
22
|
+
/** Active projects and recent work */
|
|
23
|
+
activeProjects: Memory[];
|
|
24
|
+
/** Recent interactions (last 2-3 sessions) */
|
|
25
|
+
recentInteractions: Memory[];
|
|
26
|
+
/** Behavioral patterns and preferences */
|
|
27
|
+
patterns: Memory[];
|
|
28
|
+
/** Unresolved commitments or pending items */
|
|
29
|
+
pendingItems: Memory[];
|
|
30
|
+
/** Procedural memories (how to handle things) */
|
|
31
|
+
procedures: Memory[];
|
|
32
|
+
/** All memories included, for debugging */
|
|
33
|
+
allMemories: Memory[];
|
|
34
|
+
/** Generation timestamp */
|
|
35
|
+
generatedAt: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Generate a context-aware session briefing.
|
|
39
|
+
*
|
|
40
|
+
* This replaces "read all the markdown files" with intelligent,
|
|
41
|
+
* targeted memory retrieval that gives the agent exactly what
|
|
42
|
+
* it needs for the current interaction.
|
|
43
|
+
*/
|
|
44
|
+
export declare function brief(vault: Vault, options?: BriefOptions): Promise<Briefing>;
|
|
45
|
+
//# sourceMappingURL=brief.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brief.d.ts","sourceRoot":"","sources":["../src/brief.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,EAAuB,MAAM,YAAY,CAAC;AAE9D,MAAM,WAAW,YAAY;IAC3B,sEAAsE;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,0BAA0B;IAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,0CAA0C;IAC1C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,QAAQ;IACvB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,sCAAsC;IACtC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,8CAA8C;IAC9C,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,8CAA8C;IAC9C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,iDAAiD;IACjD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,2CAA2C;IAC3C,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAsB,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA4KvF"}
|