vektor-slipstream 1.3.8 → 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
|
-
*
|
|
3
|
+
* example-claude-mcp.js — VEKTOR 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
|
-
*
|
|
7
|
-
*
|
|
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
|
-
*
|
|
12
|
+
* Usage (direct chat):
|
|
13
|
+
* ANTHROPIC_API_KEY=sk-ant-... VEKTOR_LICENCE_KEY=... node example-claude-mcp.js
|
|
18
14
|
*/
|
|
19
15
|
|
|
20
|
-
const
|
|
21
|
-
const
|
|
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-
|
|
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
|
-
|
|
340
|
-
function
|
|
341
|
-
if
|
|
342
|
-
|
|
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
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
-
|
|
352
|
-
function
|
|
353
|
-
|
|
354
|
-
return _behaviour;
|
|
355
|
-
}
|
|
45
|
+
// ── Heuristic: is this content worth storing? ─────────────────────────────────
|
|
46
|
+
function isMemorableContent(text) {
|
|
47
|
+
const t = text.toLowerCase();
|
|
356
48
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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
|
-
// ──
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
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
|
-
|
|
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
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
-
|
|
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
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
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
|
-
|
|
562
|
-
|
|
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
|
-
|
|
568
|
-
|
|
569
|
-
|
|
160
|
+
} else {
|
|
161
|
+
// ── Direct chat mode with auto-memory ───────────────────────────────────────
|
|
162
|
+
const Anthropic = require('@anthropic-ai/sdk');
|
|
570
163
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
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
|
-
|
|
581
|
-
|
|
582
|
-
ps.seedBuiltins();
|
|
583
|
-
return ps.storeStats();
|
|
584
|
-
}
|
|
169
|
+
// Morning briefing
|
|
170
|
+
const brief = await memory.briefing().catch(() => '');
|
|
585
171
|
|
|
586
|
-
|
|
587
|
-
|
|
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
|
-
|
|
591
|
-
|
|
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
|
-
|
|
595
|
-
return getPatternStore().seedBuiltins();
|
|
596
|
-
}
|
|
183
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
597
184
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
}
|
|
601
|
-
}
|
|
185
|
+
const ask = () => rl.question('You: ', async userInput => {
|
|
186
|
+
if (!userInput.trim()) return ask();
|
|
602
187
|
|
|
603
|
-
//
|
|
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
|
-
|
|
606
|
-
let buf = '';
|
|
194
|
+
messages.push({ role: 'user', content: userInput + context });
|
|
607
195
|
|
|
608
|
-
|
|
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
|
-
|
|
611
|
-
|
|
612
|
-
|
|
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
|
-
|
|
616
|
-
|
|
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
|
-
|
|
627
|
-
|
|
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
|
-
|
|
637
|
-
|
|
638
|
-
|
|
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
|
-
|
|
219
|
+
main().catch(console.error);
|
|
220
|
+
}
|
|
@@ -1,116 +1,82 @@
|
|
|
1
|
+
'use strict';
|
|
1
2
|
/**
|
|
2
|
-
* example-langchain-researcher.js
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
const {
|
|
19
|
-
const {
|
|
20
|
-
const {
|
|
21
|
-
const
|
|
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
|
-
|
|
34
|
-
const memory = await createMemory({
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
new
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
78
|
+
ask();
|
|
79
|
+
});
|
|
111
80
|
}
|
|
112
81
|
|
|
113
|
-
main().catch(
|
|
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
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
// ──
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
117
|
-
|
|
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
|
-
//
|
|
124
|
-
const
|
|
125
|
-
const
|
|
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
|
-
|
|
128
|
-
|
|
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
|
-
|
|
46
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
132
47
|
|
|
133
|
-
|
|
48
|
+
const ask = () => rl.question('You: ', async userInput => {
|
|
49
|
+
if (!userInput.trim()) return ask();
|
|
134
50
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
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
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
63
|
+
console.log(`\nAssistant: ${reply}\n`);
|
|
64
|
+
messages.push({ role: 'assistant', content: reply });
|
|
151
65
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
186
|
-
|
|
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
|
-
|
|
80
|
+
ask();
|
|
81
|
+
});
|
|
190
82
|
}
|
|
191
83
|
|
|
192
|
-
main().catch(
|
|
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
|
+
"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",
|
|
@@ -71,7 +71,8 @@
|
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
73
|
"better-sqlite3": "^12.8.0",
|
|
74
|
-
"onnxruntime-node": "^1.17.3"
|
|
74
|
+
"onnxruntime-node": "^1.17.3",
|
|
75
|
+
"vektor-slipstream": "^1.4.0"
|
|
75
76
|
},
|
|
76
77
|
"optionalDependencies": {
|
|
77
78
|
"@anthropic-ai/sdk": "^0.82.0",
|
package/vektor-slipstream.dxt
CHANGED
|
Binary file
|