vektor-slipstream 1.3.9 → 1.4.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.
@@ -1,656 +1,220 @@
1
1
  'use strict';
2
-
3
2
  /**
4
- * VEKTOR SLIPSTREAM Claude Desktop MCP Server v1.4
3
+ * example-claude-mcp.jsVEKTOR Slipstream + Claude
4
+ * ─────────────────────────────────────────────────────────────────────────────
5
+ * Auto-memory: every conversation turn is stored in the MAGMA graph.
6
+ * Claude recalls relevant context before every response.
7
+ * No setup required — memory just works.
5
8
  *
6
- * Tools:
7
- * Memory: vektor_recall, vektor_store, vektor_graph, vektor_delta
8
- * Cloak: cloak_fetch, cloak_render, cloak_diff, cloak_diff_text,
9
- * cloak_passport, tokens_saved, cloak_fetch_smart,
10
- * cloak_detect_captcha, cloak_solve_captcha,
11
- * cloak_identity_create, cloak_identity_use, cloak_identity_list,
12
- * turbo_quant_stats, turbo_quant_compress
13
- * Warmup: cloak_warmup_session, cloak_warmup_stats
14
- * Behav: cloak_inject_behaviour, cloak_behaviour_stats, cloak_load_pattern
15
- * Pattern: cloak_pattern_stats, cloak_pattern_list, cloak_pattern_prune, cloak_pattern_seed
9
+ * Usage (MCP server for Claude Desktop):
10
+ * node example-claude-mcp.js --mcp
16
11
  *
17
- * Windows-safe: no shebang line (breaks Windows Node.js when invoked directly)
12
+ * Usage (direct chat):
13
+ * ANTHROPIC_API_KEY=sk-ant-... VEKTOR_LICENCE_KEY=... node example-claude-mcp.js
18
14
  */
19
15
 
20
- const path = require('path');
21
- const os = require('os');
22
-
23
- const IS_MCP = process.argv.includes('--mcp');
24
- if (!IS_MCP) { require('./example-claude-direct'); return; }
25
-
26
- // ── Tool definitions ───────────────────────────────────────────────────────────
27
-
28
- const TOOLS = [
29
-
30
- // ── Memory tools ──────────────────────────────────────────────────────────────
31
- {
32
- name: 'vektor_recall',
33
- description: 'Search persistent memory. Call before answering anything that might have prior context.',
34
- inputSchema: {
35
- type: 'object',
36
- properties: {
37
- query: { type: 'string', description: 'What to search for.' },
38
- top_k: { type: 'integer', description: 'Number of results (default 5).', default: 5 },
39
- },
40
- required: ['query'],
41
- },
42
- },
43
- {
44
- name: 'vektor_store',
45
- description: 'Store a fact, preference, or decision in persistent memory.',
46
- inputSchema: {
47
- type: 'object',
48
- properties: {
49
- content: { type: 'string', description: 'What to remember.' },
50
- importance: { type: 'number', description: 'Importance 1-5 (default 3).', default: 3 },
51
- },
52
- required: ['content'],
53
- },
54
- },
55
- {
56
- name: 'vektor_graph',
57
- description: 'Traverse the memory graph from a concept.',
58
- inputSchema: {
59
- type: 'object',
60
- properties: {
61
- concept: { type: 'string', description: 'Concept to traverse from.' },
62
- hops: { type: 'integer', description: 'Graph depth (default 2).', default: 2 },
63
- },
64
- required: ['concept'],
65
- },
66
- },
67
- {
68
- name: 'vektor_delta',
69
- description: 'See what changed in memory on a topic.',
70
- inputSchema: {
71
- type: 'object',
72
- properties: {
73
- topic: { type: 'string', description: 'Topic to check.' },
74
- days: { type: 'integer', description: 'How many days back (default 7).', default: 7 },
75
- },
76
- required: ['topic'],
77
- },
78
- },
79
-
80
- // ── v1.1 Cloak tools ──────────────────────────────────────────────────────────
81
- {
82
- name: 'cloak_fetch',
83
- description: 'Fetch a URL using stealth headless browser. Returns clean compressed text. Saves tokens vs raw HTML.',
84
- inputSchema: {
85
- type: 'object',
86
- properties: {
87
- url: { type: 'string' },
88
- force: { type: 'boolean' },
89
- limit: { type: 'integer', description: 'Max characters to return' },
90
- },
91
- required: ['url'],
92
- },
93
- },
94
- {
95
- name: 'cloak_render',
96
- description: 'Render a page and return computed CSS layout, fonts, and gap analysis.',
97
- inputSchema: {
98
- type: 'object',
99
- properties: {
100
- url: { type: 'string' },
101
- selectors: { type: 'array', items: { type: 'string' } },
102
- mobile: { type: 'boolean' },
103
- },
104
- required: ['url'],
105
- },
106
- },
107
- {
108
- name: 'cloak_diff',
109
- description: 'Return what semantically changed on a URL since last fetch.',
110
- inputSchema: {
111
- type: 'object',
112
- properties: { url: { type: 'string' } },
113
- required: ['url'],
114
- },
115
- },
116
- {
117
- name: 'cloak_diff_text',
118
- description: 'Diff two text strings and return a semantic change summary.',
119
- inputSchema: {
120
- type: 'object',
121
- properties: {
122
- a: { type: 'string', description: 'Original text' },
123
- b: { type: 'string', description: 'New text' },
124
- },
125
- required: ['a', 'b'],
126
- },
127
- },
128
- {
129
- name: 'cloak_passport',
130
- description: 'Read/write to AES-256 encrypted credential vault. Omit value to read.',
131
- inputSchema: {
132
- type: 'object',
133
- properties: {
134
- key: { type: 'string' },
135
- value: { type: 'string' },
136
- },
137
- required: ['key'],
138
- },
139
- },
140
- {
141
- name: 'tokens_saved',
142
- description: 'Calculate token savings and ROI for a session.',
143
- inputSchema: {
144
- type: 'object',
145
- properties: {
146
- raw_tokens: { type: 'number' },
147
- actual_tokens: { type: 'number' },
148
- agent_id: { type: 'string' },
149
- provider: { type: 'string' },
150
- cost_per_1m: { type: 'number' },
151
- },
152
- required: ['raw_tokens', 'actual_tokens'],
153
- },
154
- },
155
-
156
- // ── v1.2 Cloak tools ──────────────────────────────────────────────────────────
157
- {
158
- name: 'cloak_fetch_smart',
159
- description: 'Smart fetch — checks llms.txt first, falls back to stealth browser.',
160
- inputSchema: {
161
- type: 'object',
162
- properties: {
163
- url: { type: 'string' },
164
- force: { type: 'boolean' },
165
- skipLlmsCheck: { type: 'boolean' },
166
- },
167
- required: ['url'],
168
- },
169
- },
170
- {
171
- name: 'cloak_detect_captcha',
172
- description: 'Navigate to a URL and detect if a CAPTCHA is present.',
173
- inputSchema: {
174
- type: 'object',
175
- properties: { url: { type: 'string' } },
176
- required: ['url'],
177
- },
178
- },
179
- {
180
- name: 'cloak_solve_captcha',
181
- description: 'Detect and solve any CAPTCHA using vision AI. Injects solution automatically.',
182
- inputSchema: {
183
- type: 'object',
184
- properties: {
185
- url: { type: 'string' },
186
- provider: { type: 'string', description: '"claude" (default) or "openai"' },
187
- },
188
- required: ['url'],
189
- },
190
- },
191
- {
192
- name: 'cloak_identity_create',
193
- description: 'Create a persistent browser identity with full fingerprint.',
194
- inputSchema: {
195
- type: 'object',
196
- properties: {
197
- name: { type: 'string' },
198
- seed: { type: 'string' },
199
- },
200
- required: ['name'],
201
- },
202
- },
203
- {
204
- name: 'cloak_identity_use',
205
- description: 'Browse a URL using a saved identity. Maintains cookies across sessions.',
206
- inputSchema: {
207
- type: 'object',
208
- properties: {
209
- name: { type: 'string' },
210
- url: { type: 'string' },
211
- },
212
- required: ['name', 'url'],
213
- },
214
- },
215
- {
216
- name: 'cloak_identity_list',
217
- description: 'List all saved browser identities.',
218
- inputSchema: { type: 'object', properties: {} },
219
- },
220
- {
221
- name: 'turbo_quant_stats',
222
- description: 'Show TurboQuant 3-bit compression stats.',
223
- inputSchema: { type: 'object', properties: {} },
224
- },
225
- {
226
- name: 'turbo_quant_compress',
227
- description: 'Migrate memory database to TurboQuant 3-bit compressed storage. ~10x size reduction.',
228
- inputSchema: {
229
- type: 'object',
230
- properties: {
231
- dbPath: { type: 'string' },
232
- },
233
- },
234
- },
235
-
236
- // ── v1.3 Warmup & Behaviour tools ─────────────────────────────────────────────
237
- {
238
- name: 'cloak_warmup_session',
239
- description: 'Run a session warmup before navigating to a bot-protected URL. Primes reCAPTCHA trust score.',
240
- inputSchema: {
241
- type: 'object',
242
- properties: {
243
- targetUrl: { type: 'string' },
244
- identityName: { type: 'string' },
245
- sites: { type: 'integer', default: 3 },
246
- dwellMs: { type: 'integer', default: 2500 },
247
- primeGoogle: { type: 'boolean', default: true },
248
- visitRoot: { type: 'boolean', default: true },
249
- customSites: { type: 'array', items: { type: 'string' } },
250
- },
251
- required: ['targetUrl'],
252
- },
253
- },
254
- {
255
- name: 'cloak_warmup_stats',
256
- description: 'Show warmup strategy details — trust signals, referrer chains, timing.',
257
- inputSchema: { type: 'object', properties: {} },
258
- },
259
- {
260
- name: 'cloak_inject_behaviour',
261
- description: 'Inject human-realistic mouse/scroll behaviour into a browser session.',
262
- inputSchema: {
263
- type: 'object',
264
- properties: {
265
- url: { type: 'string' },
266
- category: { type: 'string', enum: ['reading', 'form', 'shopping', 'login', 'idle'] },
267
- patternName: { type: 'string' },
268
- speedFactor: { type: 'number' },
269
- synthetic: { type: 'boolean' },
270
- durationMs: { type: 'integer' },
271
- },
272
- required: ['url'],
273
- },
274
- },
275
- {
276
- name: 'cloak_behaviour_stats',
277
- description: 'List available behaviour patterns and categories.',
278
- inputSchema: { type: 'object', properties: {} },
279
- },
280
- {
281
- name: 'cloak_load_pattern',
282
- description: 'Load a custom behaviour pattern recorded with cloak-recorder-snippet.js.',
283
- inputSchema: {
284
- type: 'object',
285
- properties: {
286
- name: { type: 'string' },
287
- pattern: { type: 'string', description: 'JSON string from recorder' },
288
- save: { type: 'boolean' },
289
- },
290
- required: ['name', 'pattern'],
291
- },
292
- },
293
-
294
- // ── v1.4 Pattern store tools ──────────────────────────────────────────────────
295
- {
296
- name: 'cloak_pattern_stats',
297
- description: 'Show self-improving pattern store stats — tier breakdown, win/loss rates.',
298
- inputSchema: { type: 'object', properties: {} },
299
- },
300
- {
301
- name: 'cloak_pattern_list',
302
- description: 'List all behaviour patterns with score, tier, wins, and losses.',
303
- inputSchema: {
304
- type: 'object',
305
- properties: {
306
- tier: { type: 'string', enum: ['elite', 'active', 'probation'] },
307
- },
308
- },
309
- },
310
- {
311
- name: 'cloak_pattern_prune',
312
- description: 'Force prune the pattern store — removes stale and low-scoring patterns.',
313
- inputSchema: { type: 'object', properties: {} },
314
- },
315
- {
316
- name: 'cloak_pattern_seed',
317
- description: 'Seed the store with built-in patterns (only runs if store is empty).',
318
- inputSchema: { type: 'object', properties: {} },
319
- },
320
- ];
321
-
322
- // ── Lazy loaders ──────────────────────────────────────────────────────────────
16
+ const { createMemory } = require('vektor-slipstream');
17
+ const readline = require('readline');
323
18
 
19
+ // ── Memory init ───────────────────────────────────────────────────────────────
324
20
  let _memory = null;
325
21
  async function getMemory() {
326
22
  if (_memory) return _memory;
327
- const { createMemory } = require('vektor-slipstream');
328
- const dbPath = process.env.VEKTOR_DB_PATH ||
329
- path.join(os.homedir(), 'vektor-slipstream-memory.db');
330
23
  _memory = await createMemory({
331
- agentId: 'claude-mcp',
332
- dbPath,
333
- silent: true,
24
+ agentId: process.env.SLIPSTREAM_AGENT_ID || 'claude-vektor',
334
25
  licenceKey: process.env.VEKTOR_LICENCE_KEY,
26
+ dbPath: process.env.VEKTOR_DB_PATH,
27
+ silent: true,
335
28
  });
336
29
  return _memory;
337
30
  }
338
31
 
339
- let _cloak = null;
340
- function getCloak() {
341
- if (!_cloak) _cloak = require('vektor-slipstream/cloak');
342
- return _cloak;
343
- }
32
+ // ── Auto-store: extract memorable facts from a conversation turn ──────────────
33
+ async function autoStore(memory, userMsg, assistantResponse) {
34
+ // Store the user message if it contains memorable content
35
+ const memorable = isMemorableContent(userMsg);
36
+ if (memorable) {
37
+ await memory.remember(userMsg, { importance: memorable.importance }).catch(() => {});
38
+ }
344
39
 
345
- let _warmup = null;
346
- function getWarmup() {
347
- if (!_warmup) _warmup = require('vektor-slipstream/cloak-warmup');
348
- return _warmup;
40
+ // Store a condensed version of the exchange
41
+ const exchange = `User: ${userMsg.slice(0, 200)} | Assistant: ${assistantResponse.slice(0, 300)}`;
42
+ await memory.remember(exchange, { importance: 2 }).catch(() => {});
349
43
  }
350
44
 
351
- let _behaviour = null;
352
- function getBehaviour() {
353
- if (!_behaviour) _behaviour = require('vektor-slipstream/cloak-behaviour');
354
- return _behaviour;
355
- }
45
+ // ── Heuristic: is this content worth storing? ─────────────────────────────────
46
+ function isMemorableContent(text) {
47
+ const t = text.toLowerCase();
356
48
 
357
- let _patternStore = null;
358
- function getPatternStore() {
359
- if (!_patternStore) _patternStore = require('vektor-slipstream/cloak-pattern-store');
360
- return _patternStore;
49
+ // High importance — preferences, decisions, critical facts
50
+ if (/prefer|always|never|hate|love|my name|i am|i'm a|i work|my project|deadline|important|remember/.test(t)) {
51
+ return { importance: 4 };
52
+ }
53
+ // Medium importance — project details, tech choices, context
54
+ if (/project|build|using|stack|version|deploy|api|database|language|framework|decided|going with/.test(t)) {
55
+ return { importance: 3 };
56
+ }
57
+ // Low importance — general context worth keeping
58
+ if (text.length > 80) {
59
+ return { importance: 2 };
60
+ }
61
+ return null;
361
62
  }
362
63
 
363
- // ── Tool runner ───────────────────────────────────────────────────────────────
364
-
365
- async function runTool(name, input) {
366
- switch (name) {
367
-
368
- case 'vektor_recall': {
369
- const mem = await getMemory();
370
- const results = await mem.recall(input.query, input.top_k || 5);
371
- return { found: results.length, memories: results.map(r => ({ content: r.content, score: r.score, id: r.id })) };
372
- }
373
-
374
- case 'vektor_store': {
375
- const mem = await getMemory();
376
- const { id } = await mem.remember(input.content, { importance: input.importance || 3 });
377
- return { stored: true, id, content: input.content };
378
- }
379
-
380
- case 'vektor_graph': {
381
- const mem = await getMemory();
382
- const { nodes, edges } = await mem.graph(input.concept, { hops: input.hops || 2 });
383
- return { nodes: nodes.slice(0, 10).map(n => ({ id: n.id, content: n.content })), edge_count: edges.length };
384
- }
385
-
386
- case 'vektor_delta': {
387
- const mem = await getMemory();
388
- const changes = await mem.delta(input.topic, input.days || 7);
389
- return { topic: input.topic, changes: changes.slice(0, 10) };
390
- }
391
-
392
- case 'cloak_fetch': {
393
- const r = await getCloak().cloak_fetch(input.url, { force: input.force, limit: input.limit });
394
- return { text: r.text, tokens_saved: r.tokensSaved, from_cache: r.fromCache };
395
- }
396
-
397
- case 'cloak_render': {
398
- return await getCloak().cloak_render(input.url, input.selectors || [], { mobile: input.mobile });
399
- }
400
-
401
- case 'cloak_diff': {
402
- return await getCloak().cloak_diff(input.url);
403
- }
404
-
405
- case 'cloak_diff_text': {
406
- return getCloak().cloak_diff_text(input.a, input.b);
407
- }
408
-
409
- case 'cloak_passport': {
410
- return { result: getCloak().cloak_passport(input.key, input.value) || null };
411
- }
412
-
413
- case 'tokens_saved': {
414
- return getCloak().tokens_saved({
415
- raw_tokens: input.raw_tokens,
416
- actual_tokens: input.actual_tokens,
417
- agent_id: input.agent_id,
418
- provider: input.provider,
419
- cost_per_1m: input.cost_per_1m,
420
- });
421
- }
422
-
423
- case 'cloak_fetch_smart': {
424
- const result = await getCloak().cloak_fetch_smart(input.url, {
425
- force: input.force, skipLlmsCheck: input.skipLlmsCheck,
426
- });
427
- return { text: result.text, tokens_saved: result.tokensSaved, from_cache: result.fromCache, source: result.source, llms_friendly: result.llmsFriendly };
428
- }
429
-
430
- case 'cloak_detect_captcha': {
431
- const { captcha } = getCloak();
432
- const { chromium } = require('playwright');
433
- let browser;
434
- try {
435
- browser = await chromium.launch({ headless: true });
436
- const page = await browser.newPage();
437
- await page.goto(input.url, { waitUntil: 'domcontentloaded', timeout: 20000 });
438
- const detected = await captcha.detectCaptcha(page);
439
- return detected || { found: false };
440
- } finally {
441
- if (browser) await browser.close().catch(() => {});
64
+ // ── MCP Server mode ───────────────────────────────────────────────────────────
65
+ if (process.argv.includes('--mcp')) {
66
+ const TOOLS = [
67
+ {
68
+ name: 'vektor_recall',
69
+ description: 'Search persistent memory for relevant context. Call before answering anything that might have prior context.',
70
+ inputSchema: { type: 'object', properties: { query: { type: 'string' }, top_k: { type: 'integer', default: 5 } }, required: ['query'] },
71
+ },
72
+ {
73
+ name: 'vektor_store',
74
+ description: 'Store a fact, preference, decision, or context in persistent memory.',
75
+ inputSchema: { type: 'object', properties: { content: { type: 'string' }, importance: { type: 'integer', default: 3 } }, required: ['content'] },
76
+ },
77
+ {
78
+ name: 'vektor_graph',
79
+ description: 'Traverse the associative memory graph to find connected memories.',
80
+ inputSchema: { type: 'object', properties: { topic: { type: 'string' }, depth: { type: 'integer', default: 2 } }, required: ['topic'] },
81
+ },
82
+ {
83
+ name: 'vektor_delta',
84
+ description: 'See what changed in memory on a topic recently.',
85
+ inputSchema: { type: 'object', properties: { topic: { type: 'string' }, days: { type: 'integer', default: 7 } }, required: ['topic'] },
86
+ },
87
+ {
88
+ name: 'vektor_briefing',
89
+ description: 'Generate a briefing summary from recent memories.',
90
+ inputSchema: { type: 'object', properties: {} },
91
+ },
92
+ ];
93
+
94
+ async function runTool(name, input) {
95
+ const mem = await getMemory();
96
+ switch (name) {
97
+ case 'vektor_recall': {
98
+ const results = await mem.recall(input.query, input.top_k || 5);
99
+ return { results: (results || []).map(r => ({ id: r.id, content: r.content, score: r.score })) };
442
100
  }
443
- }
444
-
445
- case 'cloak_solve_captcha': {
446
- const { captcha } = getCloak();
447
- const { chromium } = require('playwright');
448
- let browser;
449
- try {
450
- browser = await chromium.launch({ headless: true });
451
- const page = await browser.newPage();
452
- await page.goto(input.url, { waitUntil: 'domcontentloaded', timeout: 20000 });
453
- const detected = await captcha.detectCaptcha(page);
454
- if (!detected) return { solved: false, reason: 'No CAPTCHA detected' };
455
- const token = await captcha.solveCaptcha(page, detected, {
456
- provider: input.provider || 'claude',
457
- anthropicKey: process.env.ANTHROPIC_API_KEY,
458
- });
459
- if (token) {
460
- await captcha.injectCaptchaSolution(page, detected, token);
461
- return { solved: true, type: detected.type, token: token.slice ? token.slice(0, 20) + '...' : token };
462
- }
463
- return { solved: false, type: detected.type, reason: 'Vision model returned no selection' };
464
- } finally {
465
- if (browser) await browser.close().catch(() => {});
101
+ case 'vektor_store': {
102
+ const { id } = await mem.remember(input.content, { importance: input.importance || 3 });
103
+ return { id, stored: true };
466
104
  }
105
+ case 'vektor_graph': return await mem.graph(input.topic, input.depth || 2);
106
+ case 'vektor_delta': return await mem.delta(input.topic, input.days || 7);
107
+ case 'vektor_briefing': return { briefing: await mem.briefing() };
108
+ default: throw new Error(`Unknown tool: ${name}`);
467
109
  }
110
+ }
468
111
 
469
- case 'cloak_identity_create': {
470
- const { CloakIdentity } = getCloak();
471
- const id = CloakIdentity.create(input.name, input.seed || null);
472
- id.save();
473
- return { created: true, ...id.summary };
474
- }
475
-
476
- case 'cloak_identity_use': {
477
- const { CloakIdentity } = getCloak();
478
- const { chromium } = require('playwright');
479
- const id = CloakIdentity.load(input.name);
480
- if (!id) return { error: `Identity "${input.name}" not found. Create with cloak_identity_create first.` };
481
- let browser;
482
- try {
483
- browser = await chromium.launch({ headless: true });
484
- const context = await browser.newContext({
485
- viewport: id.profile.viewport, userAgent: id.profile.userAgent,
486
- timezoneId: id.profile.timezone, locale: id.profile.language,
487
- });
488
- await id.applyToContext(context);
489
- const page = await context.newPage();
490
- await page.goto(input.url, { waitUntil: 'domcontentloaded', timeout: 30000 });
491
- const text = await page.evaluate(() => {
492
- document.querySelectorAll('script,style,nav,footer').forEach(el => el.remove());
493
- return document.body?.innerText || '';
494
- });
495
- await id.saveCookiesFromContext(context);
496
- id.recordVisit(input.url);
497
- id.save();
498
- return { text: text.slice(0, 8000), identity: id.summary, url: input.url };
499
- } finally {
500
- if (browser) await browser.close().catch(() => {});
501
- }
502
- }
503
-
504
- case 'cloak_identity_list': {
505
- const { CloakIdentity } = getCloak();
506
- return CloakIdentity.list().map(n => CloakIdentity.load(n)?.summary).filter(Boolean);
507
- }
508
-
509
- case 'turbo_quant_stats': {
510
- return getCloak().turboQuant.compressionStats(384);
511
- }
512
-
513
- case 'turbo_quant_compress': {
514
- const { turboQuant } = getCloak();
515
- const dbPath = input.dbPath || process.env.VEKTOR_DB_PATH ||
516
- path.join(os.homedir(), 'vektor-slipstream-memory.db');
517
- const Database = require('better-sqlite3');
518
- const db = new Database(dbPath);
519
- const result = turboQuant.migrateDatabase(db);
520
- db.close();
521
- return { ...result, dbPath };
522
- }
523
-
524
- case 'cloak_warmup_session': {
525
- const { quickWarmup } = getWarmup();
526
- let identityProfile = null;
527
- if (input.identityName) {
528
- try {
529
- const { CloakIdentity } = getCloak();
530
- const id = CloakIdentity.load(input.identityName);
531
- if (id) identityProfile = id.profile;
532
- } catch (_) {}
112
+ process.stdin.setEncoding('utf8');
113
+ let buffer = '';
114
+ const send = obj => process.stdout.write(JSON.stringify(obj) + '\n');
115
+
116
+ process.stdin.on('data', async chunk => {
117
+ buffer += chunk;
118
+ const lines = buffer.split('\n');
119
+ buffer = lines.pop();
120
+ for (const line of lines) {
121
+ if (!line.trim()) continue;
122
+ let req;
123
+ try { req = JSON.parse(line); } catch {
124
+ send({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } });
125
+ continue;
533
126
  }
534
- return await quickWarmup(input.targetUrl, identityProfile, {
535
- sites: input.sites ?? 3, dwellMs: input.dwellMs ?? 2500,
536
- primeGoogle: input.primeGoogle ?? true, visitRoot: input.visitRoot ?? true,
537
- customSites: input.customSites || null,
538
- });
539
- }
540
-
541
- case 'cloak_warmup_stats': {
542
- return getWarmup().warmupStats();
543
- }
544
-
545
- case 'cloak_inject_behaviour': {
546
- const { injectBehaviour, replayPattern, syntheticBrowse } = getBehaviour();
547
- const { chromium } = require('playwright');
548
- let browser;
127
+ if (req.method?.startsWith('notifications/')) continue;
549
128
  try {
550
- browser = await chromium.launch({ headless: true });
551
- const page = await (await browser.newContext()).newPage();
552
- await page.goto(input.url, { waitUntil: 'domcontentloaded', timeout: 30000 });
553
- let result;
554
- if (input.synthetic) {
555
- result = await syntheticBrowse(page, { durationMs: input.durationMs ?? 5000, scrollDepth: 0.6, pauseCount: 3 });
556
- } else if (input.patternName) {
557
- result = await replayPattern(page, input.patternName, { speedFactor: input.speedFactor ?? 1.0 });
558
- } else {
559
- result = await injectBehaviour(page, input.category || 'reading', { speedFactor: input.speedFactor ?? 1.0 });
129
+ switch (req.method) {
130
+ case 'initialize':
131
+ send({ jsonrpc: '2.0', id: req.id, result: {
132
+ protocolVersion: '2024-11-05',
133
+ serverInfo: { name: 'vektor-slipstream', version: '1.3.9' },
134
+ capabilities: { tools: { listChanged: false } },
135
+ }});
136
+ break;
137
+ case 'tools/list':
138
+ send({ jsonrpc: '2.0', id: req.id, result: { tools: TOOLS } });
139
+ break;
140
+ case 'tools/call': {
141
+ const { name, arguments: args } = req.params;
142
+ const result = await runTool(name, args || {});
143
+ send({ jsonrpc: '2.0', id: req.id, result: {
144
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
145
+ isError: false,
146
+ }});
147
+ break;
148
+ }
149
+ default:
150
+ send({ jsonrpc: '2.0', id: req.id, error: { code: -32601, message: `Method not found: ${req.method}` }});
560
151
  }
561
- return { injected: true, url: input.url, ...result };
562
- } finally {
563
- if (browser) await browser.close().catch(() => {});
152
+ } catch(e) {
153
+ send({ jsonrpc: '2.0', id: req.id, error: { code: -32603, message: e.message }});
564
154
  }
565
155
  }
156
+ });
157
+ process.stdin.on('end', () => process.exit(0));
158
+ process.on('uncaughtException', e => process.stderr.write('[vektor-mcp] ' + e.message + '\n'));
566
159
 
567
- case 'cloak_behaviour_stats': {
568
- return getBehaviour().behaviourStats();
569
- }
160
+ } else {
161
+ // ── Direct chat mode with auto-memory ───────────────────────────────────────
162
+ const Anthropic = require('@anthropic-ai/sdk');
570
163
 
571
- case 'cloak_load_pattern': {
572
- const { loadCustomPattern, saveCustomPattern } = getBehaviour();
573
- let data;
574
- try { data = JSON.parse(input.pattern); } catch (e) { return { error: 'Invalid JSON: ' + e.message }; }
575
- const result = loadCustomPattern(input.name, data);
576
- if (input.save !== false) { try { saveCustomPattern(input.name); } catch (_) {} }
577
- return result;
578
- }
164
+ async function main() {
165
+ const memory = await getMemory();
166
+ const client = new Anthropic();
167
+ const messages = [];
579
168
 
580
- case 'cloak_pattern_stats': {
581
- const ps = getPatternStore();
582
- ps.seedBuiltins();
583
- return ps.storeStats();
584
- }
169
+ // Morning briefing
170
+ const brief = await memory.briefing().catch(() => '');
585
171
 
586
- case 'cloak_pattern_list': {
587
- return getPatternStore().listPatterns(input.tier || null);
588
- }
172
+ const systemPrompt = [
173
+ 'You are a helpful assistant with persistent memory via VEKTOR Slipstream.',
174
+ 'Your memory persists across all sessions — you remember everything.',
175
+ brief ? `\nMEMORY BRIEFING (last 24h):\n${brief}` : '',
176
+ '\nWhen the user shares preferences, decisions, or important facts — they are automatically remembered.',
177
+ 'Recall relevant context before answering. Store important new facts as they arise.',
178
+ ].filter(Boolean).join('\n');
589
179
 
590
- case 'cloak_pattern_prune': {
591
- return getPatternStore().pruneNow();
592
- }
180
+ console.log('\n🧠 VEKTOR Memory active — all conversations stored in MAGMA graph');
181
+ console.log('Type your message (Ctrl+C to exit)\n');
593
182
 
594
- case 'cloak_pattern_seed': {
595
- return getPatternStore().seedBuiltins();
596
- }
183
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
597
184
 
598
- default:
599
- return { error: `Unknown tool: ${name}` };
600
- }
601
- }
185
+ const ask = () => rl.question('You: ', async userInput => {
186
+ if (!userInput.trim()) return ask();
602
187
 
603
- // ── MCP stdio server ──────────────────────────────────────────────────────────
188
+ // Auto-recall before responding
189
+ const recalled = await memory.recall(userInput, 5).catch(() => []);
190
+ const context = recalled.length
191
+ ? '\n\nRELEVANT MEMORY:\n' + recalled.map(r => `- ${r.content} (score: ${r.score?.toFixed(2)})`).join('\n')
192
+ : '';
604
193
 
605
- process.stdin.setEncoding('utf8');
606
- let buf = '';
194
+ messages.push({ role: 'user', content: userInput + context });
607
195
 
608
- function send(obj) { process.stdout.write(JSON.stringify(obj) + '\n'); }
196
+ try {
197
+ const res = await client.messages.create({
198
+ model: 'claude-opus-4-5',
199
+ max_tokens: 1024,
200
+ system: systemPrompt,
201
+ messages,
202
+ });
609
203
 
610
- process.stdin.on('data', async chunk => {
611
- buf += chunk;
612
- const lines = buf.split('\n');
613
- buf = lines.pop();
204
+ const reply = res.content[0].text;
205
+ console.log(`\nClaude: ${reply}\n`);
206
+ messages.push({ role: 'assistant', content: reply });
614
207
 
615
- for (const line of lines) {
616
- if (!line.trim()) continue;
617
- let req;
618
- try { req = JSON.parse(line); } catch {
619
- send({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } });
620
- continue;
621
- }
622
- if (!req || typeof req.method !== 'string') continue;
623
- if (req.method.startsWith('notifications/')) continue;
624
- if (!('id' in req)) continue;
208
+ // Auto-store the exchange into MAGMA graph
209
+ await autoStore(memory, userInput, reply);
625
210
 
626
- try {
627
- if (req.method === 'initialize') {
628
- send({ jsonrpc: '2.0', id: req.id, result: {
629
- protocolVersion: '2025-11-25',
630
- serverInfo: { name: 'vektor-slipstream', version: '1.2.0' },
631
- capabilities: { tools: {} },
632
- }});
633
- getMemory().catch(e => process.stderr.write('[vektor-mcp] Memory init: ' + e.message + '\n'));
634
- continue;
211
+ } catch (err) {
212
+ console.error('API error:', err.message);
635
213
  }
636
- if (req.method === 'tools/list') {
637
- send({ jsonrpc: '2.0', id: req.id, result: { tools: TOOLS } });
638
- continue;
639
- }
640
- if (req.method === 'tools/call') {
641
- const { name, arguments: args } = req.params;
642
- const result = await runTool(name, args || {});
643
- send({ jsonrpc: '2.0', id: req.id, result: {
644
- content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
645
- }});
646
- continue;
647
- }
648
- send({ jsonrpc: '2.0', id: req.id, error: { code: -32601, message: 'Method not found' } });
649
- } catch (e) {
650
- process.stderr.write('[vektor-mcp] Error: ' + e.message + '\n');
651
- send({ jsonrpc: '2.0', id: req.id, error: { code: -32603, message: e.message } });
652
- }
214
+
215
+ ask();
216
+ });
653
217
  }
654
- });
655
218
 
656
- process.stdin.resume();
219
+ main().catch(console.error);
220
+ }
@@ -1,116 +1,82 @@
1
+ 'use strict';
1
2
  /**
2
- * example-langchain-researcher.js
3
- * VEKTOR SLIPSTREAM — LangChain Research Agent Example
4
- * ─────────────────────────────────────────────────────
5
- * A research agent that uses LangChain to search the web,
6
- * summarise findings, and store everything in persistent
7
- * Slipstream memory so it learns across sessions.
8
- *
9
- * Install:
10
- * npm install vektor-slipstream langchain @langchain/openai
3
+ * example-langchain-researcher.js — VEKTOR Slipstream + LangChain
4
+ * ─────────────────────────────────────────────────────────────────────────────
5
+ * Auto-memory: agent context, research results, and decisions flow
6
+ * into the MAGMA graph automatically after every run.
11
7
  *
12
8
  * Usage:
13
- * OPENAI_API_KEY=sk-... node example-langchain-researcher.js
9
+ * OPENAI_API_KEY=sk-... VEKTOR_LICENCE_KEY=... node example-langchain-researcher.js
14
10
  */
15
11
 
16
- 'use strict';
17
-
18
- const { createMemory } = require('vektor-slipstream');
19
- const { ChatOpenAI } = require('@langchain/openai');
20
- const { AgentExecutor } = require('langchain/agents');
21
- const { createOpenAIFunctionsAgent } = require('langchain/agents');
22
- const { TavilySearchResults } = require('@langchain/community/tools/tavily_search');
23
- const { ChatPromptTemplate, MessagesPlaceholder } = require('@langchain/core/prompts');
24
-
25
- // ── Config ────────────────────────────────────────────────────────────────────
26
-
27
- const AGENT_ID = 'langchain-researcher';
28
- const TOPIC = process.argv[2] || 'latest developments in agentic AI memory systems';
29
-
30
- // ── Boot ──────────────────────────────────────────────────────────────────────
12
+ const { createMemory } = require('vektor-slipstream');
13
+ const { ChatOpenAI } = require('@langchain/openai');
14
+ const { AgentExecutor, createOpenAIFunctionsAgent } = require('langchain/agents');
15
+ const { TavilySearchResults } = require('@langchain/community/tools/tavily_search');
16
+ const { ChatPromptTemplate, MessagesPlaceholder } = require('@langchain/core/prompts');
17
+ const readline = require('readline');
31
18
 
32
19
  async function main() {
33
- console.log('\n[RESEARCHER] Booting Slipstream memory...');
34
- const memory = await createMemory({ agentId: AGENT_ID, dbPath: './research-memory.db', licenceKey: process.env.VEKTOR_LICENCE_KEY });
35
-
36
- // ── 1. Recall what we already know ──────────────────────────────────────────
37
- console.log(`[RESEARCHER] Recalling prior knowledge on: "${TOPIC}"`);
38
- const priorKnowledge = await memory.recall(TOPIC, 5);
39
-
40
- let priorContext = 'No prior research on this topic.';
41
- if (priorKnowledge.length > 0) {
42
- priorContext = priorKnowledge
43
- .map((m, i) => `${i + 1}. [score: ${m.score}] ${m.content}`)
44
- .join('\n');
45
- console.log(`[RESEARCHER] Found ${priorKnowledge.length} prior memories.`);
46
- } else {
47
- console.log('[RESEARCHER] No prior memories starting fresh.');
48
- }
49
-
50
- // ── 2. Build the LangChain agent ────────────────────────────────────────────
51
- const llm = new ChatOpenAI({ modelName: 'gpt-4o-mini', temperature: 0.1 });
52
- const tools = [new TavilySearchResults({ maxResults: 5 })];
53
-
54
- const prompt = ChatPromptTemplate.fromMessages([
55
- ['system', `You are a meticulous research agent with persistent memory.
56
-
57
- PRIOR KNOWLEDGE FROM MEMORY:
58
- ${priorContext}
59
-
60
- Instructions:
61
- - Search for new information on the given topic
62
- - Compare findings with prior knowledge — note what's changed or new
63
- - Produce a concise research summary (3-5 paragraphs)
64
- - End with a "KEY FINDINGS:" section listing 3-5 bullet points
65
- - Be specific: cite sources, dates, and data points`],
66
- ['human', '{input}'],
67
- new MessagesPlaceholder('agent_scratchpad'),
68
- ]);
69
-
70
- const agent = await createOpenAIFunctionsAgent({ llm, tools, prompt });
71
- const executor = new AgentExecutor({ agent, tools, verbose: false });
72
-
73
- // ── 3. Run research ──────────────────────────────────────────────────────────
74
- console.log('[RESEARCHER] Running LangChain agent...\n');
75
- const result = await executor.invoke({ input: `Research this topic thoroughly: ${TOPIC}` });
76
- const output = result.output;
77
-
78
- console.log('─'.repeat(60));
79
- console.log(output);
80
- console.log('─'.repeat(60));
81
-
82
- // ── 4. Store findings in Slipstream ─────────────────────────────────────────
83
- console.log('\n[RESEARCHER] Storing findings in Slipstream memory...');
84
-
85
- // Store the full summary
86
- await memory.remember(
87
- `[RESEARCH] ${TOPIC}: ${output}`,
88
- { importance: 2 }
89
- );
90
-
91
- // Extract and store each KEY FINDING separately for granular recall
92
- const keyFindingsMatch = output.match(/KEY FINDINGS:([\s\S]+?)(?:\n\n|$)/i);
93
- if (keyFindingsMatch) {
94
- const findings = keyFindingsMatch[1]
95
- .split('\n')
96
- .map(l => l.replace(/^[-•*]\s*/, '').trim())
97
- .filter(Boolean);
98
-
99
- for (const finding of findings) {
100
- await memory.remember(`[FINDING] ${finding}`, { importance: 3 });
20
+ // ── Init VEKTOR memory ──────────────────────────────────────────────────────
21
+ const memory = await createMemory({
22
+ agentId: process.env.SLIPSTREAM_AGENT_ID || 'langchain-vektor',
23
+ licenceKey: process.env.VEKTOR_LICENCE_KEY,
24
+ dbPath: process.env.VEKTOR_DB_PATH,
25
+ silent: true,
26
+ });
27
+
28
+ const brief = await memory.briefing().catch(() => '');
29
+ console.log('\n🧠 VEKTOR Memory active — research stored in MAGMA graph');
30
+ if (brief) console.log(`\nBriefing: ${brief}\n`);
31
+
32
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
33
+
34
+ const ask = () => rl.question('\nResearch topic (Ctrl+C to exit): ', async topic => {
35
+ if (!topic.trim()) return ask();
36
+
37
+ // ── Recall prior research on this topic ─────────────────────────────────
38
+ const prior = await memory.recall(topic, 5).catch(() => []);
39
+ const priorText = prior.length
40
+ ? 'PRIOR RESEARCH:\n' + prior.map(r => `- ${r.content}`).join('\n')
41
+ : 'No prior research found on this topic.';
42
+
43
+ // ── Build agent ──────────────────────────────────────────────────────────
44
+ const llm = new ChatOpenAI({ modelName: 'gpt-4o-mini', temperature: 0.1 });
45
+ const tools = [new TavilySearchResults({ maxResults: 5 })];
46
+
47
+ const prompt = ChatPromptTemplate.fromMessages([
48
+ ['system', `You are a research agent with persistent memory.\n\n${priorText}\n\nBuild on prior research. Identify new findings. Be concise.`],
49
+ ['human', '{input}'],
50
+ new MessagesPlaceholder('agent_scratchpad'),
51
+ ]);
52
+
53
+ const agent = await createOpenAIFunctionsAgent({ llm, tools, prompt });
54
+ const executor = new AgentExecutor({ agent, tools, verbose: false });
55
+
56
+ try {
57
+ console.log(`\nResearching: ${topic}...`);
58
+ const result = await executor.invoke({ input: topic });
59
+
60
+ console.log(`\nFindings:\n${result.output}\n`);
61
+
62
+ // ── Auto-store findings into MAGMA graph ─────────────────────────────
63
+ await memory.remember(`Research topic: ${topic}`, { importance: 3 }).catch(() => {});
64
+ await memory.remember(`Research findings: ${result.output.slice(0, 500)}`, { importance: 4 }).catch(() => {});
65
+
66
+ // Store key sentences as individual memories for better graph connectivity
67
+ const sentences = result.output.split(/[.!?]+/).filter(s => s.trim().length > 40);
68
+ for (const sentence of sentences.slice(0, 5)) {
69
+ await memory.remember(sentence.trim(), { importance: 2 }).catch(() => {});
70
+ }
71
+
72
+ console.log(`✓ ${sentences.slice(0, 5).length + 2} memories stored in MAGMA graph`);
73
+
74
+ } catch (err) {
75
+ console.error('Agent error:', err.message);
101
76
  }
102
- console.log(`[RESEARCHER] Stored ${findings.length} key findings separately.`);
103
- }
104
-
105
- // ── 5. Show memory briefing ──────────────────────────────────────────────────
106
- const briefing = await memory.briefing();
107
- console.log('\n[RESEARCHER] Memory briefing (last 24h):');
108
- console.log(briefing);
109
77
 
110
- console.log('\n[RESEARCHER] Done. Run again tomorrow — agent will build on today\'s findings.');
78
+ ask();
79
+ });
111
80
  }
112
81
 
113
- main().catch(e => {
114
- console.error('[RESEARCHER] Error:', e.message);
115
- process.exit(1);
116
- });
82
+ main().catch(console.error);
@@ -1,195 +1,84 @@
1
+ 'use strict';
1
2
  /**
2
- * example-openai-assistant.js
3
- * VEKTOR SLIPSTREAM — OpenAI Agents SDK Assistant Loop Example
4
- * ─────────────────────────────────────────────────────────────
5
- * A persistent assistant that remembers every conversation.
6
- * Uses the OpenAI Agents SDK for tool use and Slipstream for
7
- * cross-session memory — the assistant genuinely knows who you
8
- * are and what you've discussed before.
9
- *
10
- * Install:
11
- * npm install vektor-slipstream openai @openai/agents readline
3
+ * example-openai-assistant.js — VEKTOR Slipstream + OpenAI
4
+ * ─────────────────────────────────────────────────────────────────────────────
5
+ * Auto-memory: every conversation turn flows into the MAGMA graph.
6
+ * No setup required memory just works from the first message.
12
7
  *
13
8
  * Usage:
14
- * OPENAI_API_KEY=sk-... node example-openai-assistant.js
9
+ * OPENAI_API_KEY=sk-... VEKTOR_LICENCE_KEY=... node example-openai-assistant.js
15
10
  */
16
11
 
17
- 'use strict';
18
-
19
12
  const { createMemory } = require('vektor-slipstream');
20
13
  const OpenAI = require('openai');
21
14
  const readline = require('readline');
22
15
 
23
- // ── Config ────────────────────────────────────────────────────────────────────
24
-
25
- const AGENT_ID = 'openai-assistant';
26
- const MODEL = 'gpt-4o-mini';
27
-
28
- // ── Tools available to the assistant ─────────────────────────────────────────
29
-
30
- function buildTools(memory) {
31
- return [
32
- {
33
- type: 'function',
34
- function: {
35
- name: 'remember',
36
- description: 'Store an important fact, preference, or decision in long-term memory. Call this whenever the user shares something worth remembering across sessions.',
37
- parameters: {
38
- type: 'object',
39
- properties: {
40
- content: {
41
- type: 'string',
42
- description: 'The fact or information to remember, written as a clear complete sentence.',
43
- },
44
- importance: {
45
- type: 'number',
46
- description: 'Importance score 1-5. Use 5 for critical facts (name, key decisions), 3 for useful context, 1 for minor details.',
47
- },
48
- },
49
- required: ['content'],
50
- },
51
- },
52
- },
53
- {
54
- type: 'function',
55
- function: {
56
- name: 'recall',
57
- description: 'Search long-term memory for relevant information. Call this when you need context about the user or a topic discussed previously.',
58
- parameters: {
59
- type: 'object',
60
- properties: {
61
- query: {
62
- type: 'string',
63
- description: 'What to search for in memory.',
64
- },
65
- },
66
- required: ['query'],
67
- },
68
- },
69
- },
70
- {
71
- type: 'function',
72
- function: {
73
- name: 'memory_graph',
74
- description: 'Explore connected memories around a concept. Use this to understand the full context around a topic.',
75
- parameters: {
76
- type: 'object',
77
- properties: {
78
- concept: { type: 'string', description: 'The concept to explore.' },
79
- hops: { type: 'number', description: 'How many hops to traverse (1-3). Default 2.' },
80
- },
81
- required: ['concept'],
82
- },
83
- },
84
- },
85
- ];
16
+ // ── Heuristic: importance scoring ────────────────────────────────────────────
17
+ function scoreImportance(text) {
18
+ const t = text.toLowerCase();
19
+ if (/prefer|always|never|my name|i am|i'm a|i work|my project|deadline|critical|remember/.test(t)) return 4;
20
+ if (/project|build|using|stack|deploy|api|database|decided|going with|language|framework/.test(t)) return 3;
21
+ if (text.length > 80) return 2;
22
+ return null;
86
23
  }
87
24
 
88
- // ── Tool execution ────────────────────────────────────────────────────────────
89
-
90
- async function executeTool(name, args, memory) {
91
- switch (name) {
92
- case 'remember': {
93
- const { id } = await memory.remember(args.content, { importance: args.importance || 2 });
94
- return `Stored memory #${id}: "${args.content.slice(0, 80)}${args.content.length > 80 ? '...' : ''}"`;
95
- }
96
- case 'recall': {
97
- const results = await memory.recall(args.query, 5);
98
- if (!results.length) return 'No relevant memories found.';
99
- return results.map((r, i) =>
100
- `${i + 1}. [relevance: ${r.score}] ${r.content}`
101
- ).join('\n');
102
- }
103
- case 'memory_graph': {
104
- const { nodes, edges } = await memory.graph(args.concept, { hops: args.hops || 2 });
105
- return `Found ${nodes.length} connected memories and ${edges.length} relationships.\n` +
106
- nodes.slice(0, 5).map(n => `• ${n.content.slice(0, 100)}`).join('\n');
107
- }
108
- default:
109
- return 'Unknown tool.';
110
- }
111
- }
112
-
113
- // ── Main assistant loop ───────────────────────────────────────────────────────
114
-
115
25
  async function main() {
116
- console.log('\n[ASSISTANT] Booting Slipstream memory...');
117
- const memory = await createMemory({ agentId: AGENT_ID, dbPath: './assistant-memory.db', licenceKey: process.env.VEKTOR_LICENCE_KEY });
26
+ const memory = await createMemory({
27
+ agentId: process.env.SLIPSTREAM_AGENT_ID || 'openai-vektor',
28
+ licenceKey: process.env.VEKTOR_LICENCE_KEY,
29
+ dbPath: process.env.VEKTOR_DB_PATH,
30
+ silent: true,
31
+ });
118
32
 
119
33
  const client = new OpenAI();
120
- const tools = buildTools(memory);
121
34
  const messages = [];
122
35
 
123
- // Inject morning briefing as system context
124
- const briefing = await memory.briefing();
125
- const systemPrompt = `You are a persistent personal assistant with long-term memory powered by VEKTOR Slipstream.
36
+ // Boot briefing inject yesterday's context
37
+ const brief = await memory.briefing().catch(() => '');
38
+ const system = [
39
+ 'You are a helpful assistant with persistent memory. You remember everything across sessions.',
40
+ brief ? `\nMEMORY BRIEFING:\n${brief}` : '',
41
+ ].filter(Boolean).join('\n');
126
42
 
127
- You have access to tools to remember and recall information across sessions.
128
- Always recall relevant memories before answering questions about past conversations or the user's context.
129
- When the user shares important information, use the remember tool to store it.
43
+ console.log('\n🧠 VEKTOR Memory active conversations stored in MAGMA graph');
44
+ console.log('Type your message (Ctrl+C to exit)\n');
130
45
 
131
- ${briefing}`;
46
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
132
47
 
133
- messages.push({ role: 'system', content: systemPrompt });
48
+ const ask = () => rl.question('You: ', async userInput => {
49
+ if (!userInput.trim()) return ask();
134
50
 
135
- // Terminal interface
136
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
137
- const prompt = () => new Promise(resolve => rl.question('\nYou: ', resolve));
51
+ // Auto-recall relevant context
52
+ const recalled = await memory.recall(userInput, 5).catch(() => []);
53
+ const context = recalled.length
54
+ ? '\n\n[MEMORY CONTEXT]\n' + recalled.map(r => `- ${r.content}`).join('\n') + '\n[/MEMORY CONTEXT]'
55
+ : '';
138
56
 
139
- console.log('\n[ASSISTANT] Ready. Your memories persist across sessions.');
140
- console.log('[ASSISTANT] Type "exit" to quit, "briefing" to see memory summary.\n');
57
+ messages.push({ role: 'user', content: userInput + context });
141
58
 
142
- while (true) {
143
- const userInput = (await prompt()).trim();
144
- if (!userInput) continue;
145
- if (userInput.toLowerCase() === 'exit') { rl.close(); break; }
59
+ try {
60
+ const res = await client.chat.completions.create({ model: 'gpt-4o-mini', messages: [{ role: 'system', content: system }, ...messages] });
61
+ const reply = res.choices[0].message.content;
146
62
 
147
- if (userInput.toLowerCase() === 'briefing') {
148
- console.log('\n' + await memory.briefing());
149
- continue;
150
- }
63
+ console.log(`\nAssistant: ${reply}\n`);
64
+ messages.push({ role: 'assistant', content: reply });
151
65
 
152
- messages.push({ role: 'user', content: userInput });
153
-
154
- // Agent loop handles tool calls automatically
155
- let response;
156
- while (true) {
157
- response = await client.chat.completions.create({
158
- model: MODEL,
159
- messages,
160
- tools,
161
- tool_choice: 'auto',
162
- });
163
-
164
- const msg = response.choices[0].message;
165
- messages.push(msg);
166
-
167
- if (!msg.tool_calls?.length) break; // Done
168
-
169
- // Execute all tool calls
170
- const toolResults = await Promise.all(
171
- msg.tool_calls.map(async tc => {
172
- const args = JSON.parse(tc.function.arguments);
173
- const result = await executeTool(tc.function.name, args, memory);
174
- console.log(` [tool:${tc.function.name}] ${result.slice(0, 120)}`);
175
- return {
176
- role: 'tool',
177
- tool_call_id: tc.id,
178
- content: result,
179
- };
180
- })
181
- );
182
- messages.push(...toolResults);
183
- }
66
+ // Auto-store user input if memorable
67
+ const imp = scoreImportance(userInput);
68
+ if (imp) await memory.remember(userInput, { importance: imp }).catch(() => {});
184
69
 
185
- const reply = response.choices[0].message.content;
186
- console.log(`\nAssistant: ${reply}`);
187
- }
70
+ // Always store the exchange summary
71
+ await memory.remember(
72
+ `Exchange — User: ${userInput.slice(0, 150)} | Assistant: ${reply.slice(0, 200)}`,
73
+ { importance: 2 }
74
+ ).catch(() => {});
75
+
76
+ } catch (err) {
77
+ console.error('API error:', err.message);
78
+ }
188
79
 
189
- console.log('\n[ASSISTANT] Session ended. Memories saved for next time.');
80
+ ask();
81
+ });
190
82
  }
191
83
 
192
- main().catch(e => {
193
- console.error('[ASSISTANT] Error:', e.message);
194
- process.exit(1);
195
- });
84
+ main().catch(console.error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vektor-slipstream",
3
- "version": "1.3.9",
3
+ "version": "1.4.0",
4
4
  "description": "Hardware-accelerated persistent memory for AI agents. Local-first, zero cloud dependency, $0 embedding cost.",
5
5
  "main": "slipstream-core-extended.js",
6
6
  "types": "./types/index.d.ts",
@@ -72,7 +72,7 @@
72
72
  "dependencies": {
73
73
  "better-sqlite3": "^12.8.0",
74
74
  "onnxruntime-node": "^1.17.3",
75
- "vektor-slipstream": "^1.3.9"
75
+ "vektor-slipstream": "^1.4.0"
76
76
  },
77
77
  "optionalDependencies": {
78
78
  "@anthropic-ai/sdk": "^0.82.0",
Binary file