@memclaw/memclaw 0.9.17 → 0.9.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +23 -23
- package/dist/plugin-impl.d.ts +4 -1
- package/dist/plugin-impl.d.ts.map +1 -1
- package/dist/plugin-impl.js +396 -77
- package/dist/plugin-impl.js.map +1 -1
- package/dist/src/client.d.ts +85 -42
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +138 -80
- package/dist/src/client.js.map +1 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +260 -272
- package/dist/src/config.js.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/memclaw/SKILL.md +185 -71
- package/skills/memclaw/references/best-practices.md +195 -272
- package/skills/memclaw/references/memory-structure.md +160 -0
- package/skills/memclaw/references/security.md +31 -0
- package/skills/memclaw/references/tools.md +243 -122
- package/skills/memclaw-maintance/SKILL.md +67 -39
- package/skills/memclaw-maintance/references/tools.md +10 -148
- package/skills/lagacy/SKILL.md +0 -239
- package/skills/lagacy/references/maintenance.md +0 -110
- package/skills/lagacy/references/setup.md +0 -279
- package/skills/lagacy/references/tools.md +0 -170
package/dist/plugin-impl.js
CHANGED
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Provides layered semantic memory for OpenClaw with:
|
|
6
6
|
* - Automatic service startup
|
|
7
|
-
* - Memory tools (search, recall, add,
|
|
7
|
+
* - Memory tools (search, recall, add, close)
|
|
8
|
+
* - Tiered access (L0/L1/L2)
|
|
9
|
+
* - Filesystem browsing
|
|
10
|
+
* - Smart exploration
|
|
8
11
|
* - Migration from OpenClaw native memory
|
|
9
12
|
*/
|
|
10
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -18,12 +21,18 @@ const toolSchemas = {
|
|
|
18
21
|
cortex_search: {
|
|
19
22
|
name: 'cortex_search',
|
|
20
23
|
description: `Layered semantic search across memory using L0/L1/L2 tiered retrieval.
|
|
21
|
-
Returns relevant memories ranked by relevance score.
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
|
|
25
|
+
**Key Features:**
|
|
26
|
+
- Tiered retrieval: L0 (abstract) -> L1 (overview) -> L2 (full content)
|
|
27
|
+
- Token-efficient: Control exactly which layers to return
|
|
28
|
+
|
|
29
|
+
**Parameters:**
|
|
30
|
+
- return_layers: ["L0"] (default, ~100 tokens), ["L0","L1"] (~2100 tokens), ["L0","L1","L2"] (full)
|
|
31
|
+
|
|
32
|
+
**When to use:**
|
|
33
|
+
- Finding past conversations or decisions
|
|
34
|
+
- Searching across all sessions
|
|
35
|
+
- Discovering related memories by semantic similarity`,
|
|
27
36
|
inputSchema: {
|
|
28
37
|
type: 'object',
|
|
29
38
|
properties: {
|
|
@@ -44,6 +53,15 @@ Use this tool when you need to:
|
|
|
44
53
|
type: 'number',
|
|
45
54
|
description: 'Minimum relevance score threshold (0-1, default: 0.6)',
|
|
46
55
|
default: 0.6
|
|
56
|
+
},
|
|
57
|
+
return_layers: {
|
|
58
|
+
type: 'array',
|
|
59
|
+
items: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
enum: ['L0', 'L1', 'L2']
|
|
62
|
+
},
|
|
63
|
+
description: 'Which layers to return. Default: ["L0"]. Use ["L0","L1"] for more context, ["L0","L1","L2"] for full content.',
|
|
64
|
+
default: ['L0']
|
|
47
65
|
}
|
|
48
66
|
},
|
|
49
67
|
required: ['query']
|
|
@@ -51,16 +69,10 @@ Use this tool when you need to:
|
|
|
51
69
|
},
|
|
52
70
|
cortex_recall: {
|
|
53
71
|
name: 'cortex_recall',
|
|
54
|
-
description: `Recall memories
|
|
55
|
-
|
|
56
|
-
The search engine internally performs tiered retrieval:
|
|
57
|
-
- L0 (Abstract): Quick filtering by summary
|
|
58
|
-
- L1 (Overview): Context refinement
|
|
59
|
-
- L2 (Full): Precise matching with full content
|
|
72
|
+
description: `Recall memories with full context (L0 snippet + L2 content).
|
|
60
73
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
Use this when you need memories with more context than a simple search.`,
|
|
74
|
+
This is a convenience wrapper that returns both abstract and full content.
|
|
75
|
+
Use cortex_search with return_layers=["L0","L2"] for more control.`,
|
|
64
76
|
inputSchema: {
|
|
65
77
|
type: 'object',
|
|
66
78
|
properties: {
|
|
@@ -84,10 +96,14 @@ Use this when you need memories with more context than a simple search.`,
|
|
|
84
96
|
cortex_add_memory: {
|
|
85
97
|
name: 'cortex_add_memory',
|
|
86
98
|
description: `Add a message to memory for a specific session.
|
|
99
|
+
|
|
87
100
|
This stores the message and automatically triggers:
|
|
88
101
|
- Vector embedding for semantic search
|
|
89
102
|
- L0/L1 layer generation (async)
|
|
90
103
|
|
|
104
|
+
**Metadata support:**
|
|
105
|
+
You can attach metadata like tags, importance, or custom fields.
|
|
106
|
+
|
|
91
107
|
Use this to persist important information that should be searchable later.`,
|
|
92
108
|
inputSchema: {
|
|
93
109
|
type: 'object',
|
|
@@ -105,20 +121,16 @@ Use this to persist important information that should be searchable later.`,
|
|
|
105
121
|
session_id: {
|
|
106
122
|
type: 'string',
|
|
107
123
|
description: 'Session/thread ID (uses default if not specified)'
|
|
124
|
+
},
|
|
125
|
+
metadata: {
|
|
126
|
+
type: 'object',
|
|
127
|
+
description: 'Optional metadata (tags, importance, custom fields)',
|
|
128
|
+
additionalProperties: true
|
|
108
129
|
}
|
|
109
130
|
},
|
|
110
131
|
required: ['content']
|
|
111
132
|
}
|
|
112
133
|
},
|
|
113
|
-
cortex_list_sessions: {
|
|
114
|
-
name: 'cortex_list_sessions',
|
|
115
|
-
description: `List all memory sessions with their status.
|
|
116
|
-
Shows session IDs, message counts, and creation/update times.`,
|
|
117
|
-
inputSchema: {
|
|
118
|
-
type: 'object',
|
|
119
|
-
properties: {}
|
|
120
|
-
}
|
|
121
|
-
},
|
|
122
134
|
cortex_close_session: {
|
|
123
135
|
name: 'cortex_close_session',
|
|
124
136
|
description: `Trigger memory extraction and archival for accumulated conversation content.
|
|
@@ -154,6 +166,154 @@ This triggers the complete memory processing pipeline:
|
|
|
154
166
|
}
|
|
155
167
|
}
|
|
156
168
|
},
|
|
169
|
+
// ==================== Filesystem Tools ====================
|
|
170
|
+
cortex_ls: {
|
|
171
|
+
name: 'cortex_ls',
|
|
172
|
+
description: `List directory contents to browse the memory space like a virtual filesystem.
|
|
173
|
+
|
|
174
|
+
This allows you to explore the hierarchical structure of memories:
|
|
175
|
+
- cortex://session - List all sessions
|
|
176
|
+
- cortex://session/{session_id} - Browse a specific session's contents
|
|
177
|
+
- cortex://session/{session_id}/timeline - View timeline messages
|
|
178
|
+
- cortex://session/{session_id}/memories - View extracted memories
|
|
179
|
+
|
|
180
|
+
**Parameters:**
|
|
181
|
+
- recursive: List all subdirectories recursively
|
|
182
|
+
- include_abstracts: Show L0 abstracts for each file (for quick preview)
|
|
183
|
+
|
|
184
|
+
Use this when:
|
|
185
|
+
- Semantic search doesn't find what you need
|
|
186
|
+
- You want to understand the overall memory layout
|
|
187
|
+
- You need to manually navigate to find specific information`,
|
|
188
|
+
inputSchema: {
|
|
189
|
+
type: 'object',
|
|
190
|
+
properties: {
|
|
191
|
+
uri: {
|
|
192
|
+
type: 'string',
|
|
193
|
+
description: 'Directory URI to list (default: cortex://session)',
|
|
194
|
+
default: 'cortex://session'
|
|
195
|
+
},
|
|
196
|
+
recursive: {
|
|
197
|
+
type: 'boolean',
|
|
198
|
+
description: 'Whether to recursively list subdirectories',
|
|
199
|
+
default: false
|
|
200
|
+
},
|
|
201
|
+
include_abstracts: {
|
|
202
|
+
type: 'boolean',
|
|
203
|
+
description: 'Whether to include L0 abstracts for each file',
|
|
204
|
+
default: false
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
// ==================== Tiered Access Tools ====================
|
|
210
|
+
cortex_get_abstract: {
|
|
211
|
+
name: 'cortex_get_abstract',
|
|
212
|
+
description: `Get L0 abstract layer (~100 tokens) for quick relevance checking.
|
|
213
|
+
|
|
214
|
+
Abstracts are short summaries ideal for quickly determining if content is relevant
|
|
215
|
+
before committing to reading more. Use this to minimize token consumption.
|
|
216
|
+
|
|
217
|
+
Use when:
|
|
218
|
+
- You found a URI from cortex_ls and want to quickly check relevance
|
|
219
|
+
- You need to filter many candidates before deep reading
|
|
220
|
+
- You want the most token-efficient preview`,
|
|
221
|
+
inputSchema: {
|
|
222
|
+
type: 'object',
|
|
223
|
+
properties: {
|
|
224
|
+
uri: {
|
|
225
|
+
type: 'string',
|
|
226
|
+
description: 'Content URI (file or directory)'
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
required: ['uri']
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
cortex_get_overview: {
|
|
233
|
+
name: 'cortex_get_overview',
|
|
234
|
+
description: `Get L1 overview layer (~2000 tokens) with core information and context.
|
|
235
|
+
|
|
236
|
+
Overviews contain key points and contextual information. Use this when:
|
|
237
|
+
- The abstract was relevant but you need more details
|
|
238
|
+
- You want to understand the gist without full content
|
|
239
|
+
- You need moderate detail for decision making`,
|
|
240
|
+
inputSchema: {
|
|
241
|
+
type: 'object',
|
|
242
|
+
properties: {
|
|
243
|
+
uri: {
|
|
244
|
+
type: 'string',
|
|
245
|
+
description: 'Content URI (file or directory)'
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
required: ['uri']
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
cortex_get_content: {
|
|
252
|
+
name: 'cortex_get_content',
|
|
253
|
+
description: `Get L2 full content layer - the complete original content.
|
|
254
|
+
|
|
255
|
+
Use this ONLY when you need the complete, unprocessed content.
|
|
256
|
+
This returns the full content which may be large.
|
|
257
|
+
|
|
258
|
+
Use when:
|
|
259
|
+
- You need exact details or quotes
|
|
260
|
+
- Abstract and overview don't provide enough information
|
|
261
|
+
- You need to see the original, unsummarized content`,
|
|
262
|
+
inputSchema: {
|
|
263
|
+
type: 'object',
|
|
264
|
+
properties: {
|
|
265
|
+
uri: {
|
|
266
|
+
type: 'string',
|
|
267
|
+
description: 'Content URI (file only)'
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
required: ['uri']
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
// ==================== Exploration Tool ====================
|
|
274
|
+
cortex_explore: {
|
|
275
|
+
name: 'cortex_explore',
|
|
276
|
+
description: `Smart exploration of memory space, combining search and browsing.
|
|
277
|
+
|
|
278
|
+
This tool performs a guided exploration:
|
|
279
|
+
1. Searches within a specified scope (start_uri)
|
|
280
|
+
2. Returns an exploration path showing relevance scores
|
|
281
|
+
3. Returns matching results with requested layers
|
|
282
|
+
|
|
283
|
+
**When to use:**
|
|
284
|
+
- When you need to "wander" through memories with a purpose
|
|
285
|
+
- When you want to discover related content in a specific area
|
|
286
|
+
- When combining keyword hints with semantic discovery
|
|
287
|
+
|
|
288
|
+
**Parameters:**
|
|
289
|
+
- start_uri: Where to begin exploration (default: cortex://session)
|
|
290
|
+
- return_layers: Which layers to include in matches`,
|
|
291
|
+
inputSchema: {
|
|
292
|
+
type: 'object',
|
|
293
|
+
properties: {
|
|
294
|
+
query: {
|
|
295
|
+
type: 'string',
|
|
296
|
+
description: 'Exploration query - what to look for'
|
|
297
|
+
},
|
|
298
|
+
start_uri: {
|
|
299
|
+
type: 'string',
|
|
300
|
+
description: 'Starting URI for exploration',
|
|
301
|
+
default: 'cortex://session'
|
|
302
|
+
},
|
|
303
|
+
return_layers: {
|
|
304
|
+
type: 'array',
|
|
305
|
+
items: {
|
|
306
|
+
type: 'string',
|
|
307
|
+
enum: ['L0', 'L1', 'L2']
|
|
308
|
+
},
|
|
309
|
+
description: 'Which layers to return in matches',
|
|
310
|
+
default: ['L0']
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
required: ['query']
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
// ==================== Migration & Maintenance ====================
|
|
157
317
|
cortex_migrate: {
|
|
158
318
|
name: 'cortex_migrate',
|
|
159
319
|
description: `Migrate memories from OpenClaw's native memory system to MemClaw.
|
|
@@ -229,8 +389,8 @@ function createPlugin(api) {
|
|
|
229
389
|
log(`Created configuration file: ${configPath}`);
|
|
230
390
|
log('Opening configuration file for editing...');
|
|
231
391
|
(0, config_js_1.openConfigFile)(configPath).catch((err) => {
|
|
232
|
-
api.logger.warn(`Could not open config file: ${err}`);
|
|
233
|
-
api.logger.warn(`Please manually edit: ${configPath}`);
|
|
392
|
+
api.logger.warn(`[memclaw] Could not open config file: ${err}`);
|
|
393
|
+
api.logger.warn(`[memclaw] Please manually edit: ${configPath}`);
|
|
234
394
|
});
|
|
235
395
|
api.logger.info(`
|
|
236
396
|
╔══════════════════════════════════════════════════════════╗
|
|
@@ -286,8 +446,8 @@ function createPlugin(api) {
|
|
|
286
446
|
const mergedConfig = (0, config_js_1.mergeConfigWithPlugin)(fileConfig, pluginProvidedConfig);
|
|
287
447
|
const validation = (0, config_js_1.validateConfig)(mergedConfig);
|
|
288
448
|
if (!validation.valid) {
|
|
289
|
-
api.logger.warn(`Configuration incomplete: ${validation.errors.join(', ')}`);
|
|
290
|
-
api.logger.warn(`Please configure LLM/Embedding API keys in OpenClaw plugin settings or edit: ${configPath}`);
|
|
449
|
+
api.logger.warn(`[memclaw] Configuration incomplete: ${validation.errors.join(', ')}`);
|
|
450
|
+
api.logger.warn(`[memclaw] Please configure LLM/Embedding API keys in OpenClaw plugin settings or edit: ${configPath}`);
|
|
291
451
|
return;
|
|
292
452
|
}
|
|
293
453
|
// Start services
|
|
@@ -303,7 +463,7 @@ function createPlugin(api) {
|
|
|
303
463
|
maintenanceTimer = setInterval(async () => {
|
|
304
464
|
try {
|
|
305
465
|
log('Running scheduled maintenance...');
|
|
306
|
-
const
|
|
466
|
+
const currentConfigPath = (0, config_js_1.getConfigPath)();
|
|
307
467
|
// Run maintenance commands
|
|
308
468
|
const commands = [
|
|
309
469
|
['vector', 'prune'],
|
|
@@ -311,7 +471,7 @@ function createPlugin(api) {
|
|
|
311
471
|
['layers', 'ensure-all']
|
|
312
472
|
];
|
|
313
473
|
for (const cmd of commands) {
|
|
314
|
-
const result = await (0, binaries_js_1.executeCliCommand)(cmd,
|
|
474
|
+
const result = await (0, binaries_js_1.executeCliCommand)(cmd, currentConfigPath, tenantId, 300000);
|
|
315
475
|
if (!result.success) {
|
|
316
476
|
log(`Maintenance command '${cmd.join(' ')}' failed: ${result.stderr}`);
|
|
317
477
|
}
|
|
@@ -325,8 +485,8 @@ function createPlugin(api) {
|
|
|
325
485
|
log('Maintenance timer started (runs every 3 hours)');
|
|
326
486
|
}
|
|
327
487
|
catch (err) {
|
|
328
|
-
api.logger.error(`Failed to start services: ${err}`);
|
|
329
|
-
api.logger.warn('Memory features may not work correctly');
|
|
488
|
+
api.logger.error(`[memclaw] Failed to start services: ${err}`);
|
|
489
|
+
api.logger.warn('[memclaw] Memory features may not work correctly');
|
|
330
490
|
}
|
|
331
491
|
},
|
|
332
492
|
stop: async () => {
|
|
@@ -349,7 +509,7 @@ function createPlugin(api) {
|
|
|
349
509
|
}
|
|
350
510
|
}
|
|
351
511
|
};
|
|
352
|
-
// Register
|
|
512
|
+
// ==================== Register Tools ====================
|
|
353
513
|
// cortex_search
|
|
354
514
|
api.registerTool({
|
|
355
515
|
name: toolSchemas.cortex_search.name,
|
|
@@ -363,24 +523,40 @@ function createPlugin(api) {
|
|
|
363
523
|
query: input.query,
|
|
364
524
|
thread: input.scope,
|
|
365
525
|
limit: input.limit ?? searchLimit,
|
|
366
|
-
min_score: input.min_score ?? minScore
|
|
526
|
+
min_score: input.min_score ?? minScore,
|
|
527
|
+
return_layers: input.return_layers ?? ['L0']
|
|
367
528
|
});
|
|
368
529
|
const formatted = results
|
|
369
|
-
.map((r, i) =>
|
|
370
|
-
.
|
|
530
|
+
.map((r, i) => {
|
|
531
|
+
let content = `${i + 1}. [Score: ${r.score.toFixed(2)}] URI: ${r.uri}\n`;
|
|
532
|
+
content += ` Layers: ${r.layers.join(', ')}\n`;
|
|
533
|
+
content += ` Snippet: ${r.snippet}\n`;
|
|
534
|
+
if (r.overview) {
|
|
535
|
+
content += ` Overview: ${r.overview.substring(0, 200)}...\n`;
|
|
536
|
+
}
|
|
537
|
+
if (r.content) {
|
|
538
|
+
const preview = r.content.length > 200 ? r.content.substring(0, 200) + '...' : r.content;
|
|
539
|
+
content += ` Content: ${preview}\n`;
|
|
540
|
+
}
|
|
541
|
+
return content;
|
|
542
|
+
})
|
|
543
|
+
.join('\n');
|
|
371
544
|
return {
|
|
372
545
|
content: `Found ${results.length} results for "${input.query}":\n\n${formatted}`,
|
|
373
546
|
results: results.map((r) => ({
|
|
374
547
|
uri: r.uri,
|
|
375
548
|
score: r.score,
|
|
376
|
-
snippet: r.snippet
|
|
549
|
+
snippet: r.snippet,
|
|
550
|
+
overview: r.overview,
|
|
551
|
+
content: r.content,
|
|
552
|
+
layers: r.layers
|
|
377
553
|
})),
|
|
378
554
|
total: results.length
|
|
379
555
|
};
|
|
380
556
|
}
|
|
381
557
|
catch (error) {
|
|
382
558
|
const message = error instanceof Error ? error.message : String(error);
|
|
383
|
-
api.logger.error(`cortex_search failed: ${message}`);
|
|
559
|
+
api.logger.error(`[memclaw] cortex_search failed: ${message}`);
|
|
384
560
|
return { error: `Search failed: ${message}` };
|
|
385
561
|
}
|
|
386
562
|
}
|
|
@@ -414,7 +590,7 @@ function createPlugin(api) {
|
|
|
414
590
|
}
|
|
415
591
|
catch (error) {
|
|
416
592
|
const message = error instanceof Error ? error.message : String(error);
|
|
417
|
-
api.logger.error(`cortex_recall failed: ${message}`);
|
|
593
|
+
api.logger.error(`[memclaw] cortex_recall failed: ${message}`);
|
|
418
594
|
return { error: `Recall failed: ${message}` };
|
|
419
595
|
}
|
|
420
596
|
}
|
|
@@ -431,7 +607,8 @@ function createPlugin(api) {
|
|
|
431
607
|
const sessionId = input.session_id ?? defaultSessionId;
|
|
432
608
|
const result = await client.addMessage(sessionId, {
|
|
433
609
|
role: (input.role ?? 'user'),
|
|
434
|
-
content: input.content
|
|
610
|
+
content: input.content,
|
|
611
|
+
metadata: input.metadata
|
|
435
612
|
});
|
|
436
613
|
return {
|
|
437
614
|
content: `Memory stored successfully in session "${sessionId}".\nResult: ${result}`,
|
|
@@ -441,71 +618,213 @@ function createPlugin(api) {
|
|
|
441
618
|
}
|
|
442
619
|
catch (error) {
|
|
443
620
|
const message = error instanceof Error ? error.message : String(error);
|
|
444
|
-
api.logger.error(`cortex_add_memory failed: ${message}`);
|
|
621
|
+
api.logger.error(`[memclaw] cortex_add_memory failed: ${message}`);
|
|
445
622
|
return { error: `Failed to add memory: ${message}` };
|
|
446
623
|
}
|
|
447
624
|
}
|
|
448
625
|
});
|
|
449
|
-
//
|
|
626
|
+
// cortex_close_session
|
|
450
627
|
api.registerTool({
|
|
451
|
-
name: toolSchemas.
|
|
452
|
-
description: toolSchemas.
|
|
453
|
-
parameters: toolSchemas.
|
|
454
|
-
execute: async (_id,
|
|
628
|
+
name: toolSchemas.cortex_close_session.name,
|
|
629
|
+
description: toolSchemas.cortex_close_session.description,
|
|
630
|
+
parameters: toolSchemas.cortex_close_session.inputSchema,
|
|
631
|
+
execute: async (_id, params) => {
|
|
632
|
+
const input = params;
|
|
633
|
+
try {
|
|
634
|
+
await ensureServicesReady();
|
|
635
|
+
const sessionId = input.session_id ?? defaultSessionId;
|
|
636
|
+
const result = await client.closeSession(sessionId);
|
|
637
|
+
return {
|
|
638
|
+
content: `Session "${sessionId}" closed successfully.\nStatus: ${result.status}, Messages: ${result.message_count}\n\nMemory extraction pipeline triggered.`,
|
|
639
|
+
success: true,
|
|
640
|
+
session: {
|
|
641
|
+
thread_id: result.thread_id,
|
|
642
|
+
status: result.status,
|
|
643
|
+
message_count: result.message_count
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
catch (error) {
|
|
648
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
649
|
+
api.logger.error(`[memclaw] cortex_close_session failed: ${message}`);
|
|
650
|
+
return { error: `Failed to close session: ${message}` };
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
// cortex_ls
|
|
655
|
+
api.registerTool({
|
|
656
|
+
name: toolSchemas.cortex_ls.name,
|
|
657
|
+
description: toolSchemas.cortex_ls.description,
|
|
658
|
+
parameters: toolSchemas.cortex_ls.inputSchema,
|
|
659
|
+
execute: async (_id, params) => {
|
|
660
|
+
const input = params;
|
|
455
661
|
try {
|
|
456
662
|
await ensureServicesReady();
|
|
457
|
-
const
|
|
458
|
-
|
|
459
|
-
|
|
663
|
+
const result = await client.ls({
|
|
664
|
+
uri: input.uri ?? 'cortex://session',
|
|
665
|
+
recursive: input.recursive ?? false,
|
|
666
|
+
include_abstracts: input.include_abstracts ?? false
|
|
667
|
+
});
|
|
668
|
+
if (result.entries.length === 0) {
|
|
669
|
+
return { content: `Directory "${result.uri}" is empty or does not exist.` };
|
|
460
670
|
}
|
|
461
|
-
const formatted =
|
|
462
|
-
.map((
|
|
463
|
-
|
|
464
|
-
|
|
671
|
+
const formatted = result.entries
|
|
672
|
+
.map((e, i) => {
|
|
673
|
+
let content = `${i + 1}. ${e.is_directory ? '📁' : '📄'} ${e.name}\n`;
|
|
674
|
+
content += ` URI: ${e.uri}\n`;
|
|
675
|
+
if (e.is_directory) {
|
|
676
|
+
content += ` Type: Directory\n`;
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
content += ` Size: ${e.size} bytes\n`;
|
|
680
|
+
}
|
|
681
|
+
if (e.abstract_text) {
|
|
682
|
+
const preview = e.abstract_text.length > 100
|
|
683
|
+
? e.abstract_text.substring(0, 100) + '...'
|
|
684
|
+
: e.abstract_text;
|
|
685
|
+
content += ` Abstract: ${preview}\n`;
|
|
686
|
+
}
|
|
687
|
+
return content;
|
|
465
688
|
})
|
|
466
689
|
.join('\n');
|
|
467
690
|
return {
|
|
468
|
-
content: `
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
status: s.status,
|
|
472
|
-
message_count: s.message_count,
|
|
473
|
-
created_at: s.created_at
|
|
474
|
-
}))
|
|
691
|
+
content: `Directory "${result.uri}" (${result.total} entries):\n\n${formatted}`,
|
|
692
|
+
entries: result.entries,
|
|
693
|
+
total: result.total
|
|
475
694
|
};
|
|
476
695
|
}
|
|
477
696
|
catch (error) {
|
|
478
697
|
const message = error instanceof Error ? error.message : String(error);
|
|
479
|
-
api.logger.error(`
|
|
480
|
-
return { error: `
|
|
698
|
+
api.logger.error(`[memclaw] cortex_ls failed: ${message}`);
|
|
699
|
+
return { error: `List directory failed: ${message}` };
|
|
481
700
|
}
|
|
482
701
|
}
|
|
483
702
|
});
|
|
484
|
-
//
|
|
703
|
+
// cortex_get_abstract
|
|
485
704
|
api.registerTool({
|
|
486
|
-
name: toolSchemas.
|
|
487
|
-
description: toolSchemas.
|
|
488
|
-
parameters: toolSchemas.
|
|
705
|
+
name: toolSchemas.cortex_get_abstract.name,
|
|
706
|
+
description: toolSchemas.cortex_get_abstract.description,
|
|
707
|
+
parameters: toolSchemas.cortex_get_abstract.inputSchema,
|
|
489
708
|
execute: async (_id, params) => {
|
|
490
709
|
const input = params;
|
|
491
710
|
try {
|
|
492
711
|
await ensureServicesReady();
|
|
493
|
-
const
|
|
494
|
-
const result = await client.closeSession(sessionId);
|
|
712
|
+
const result = await client.getAbstract(input.uri);
|
|
495
713
|
return {
|
|
496
|
-
content: `
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
714
|
+
content: `L0 Abstract for "${result.uri}" (~${result.token_count} tokens):\n\n${result.content}`,
|
|
715
|
+
uri: result.uri,
|
|
716
|
+
abstract: result.content,
|
|
717
|
+
token_count: result.token_count,
|
|
718
|
+
layer: result.layer
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
catch (error) {
|
|
722
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
723
|
+
api.logger.error(`[memclaw] cortex_get_abstract failed: ${message}`);
|
|
724
|
+
return { error: `Get abstract failed: ${message}` };
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
// cortex_get_overview
|
|
729
|
+
api.registerTool({
|
|
730
|
+
name: toolSchemas.cortex_get_overview.name,
|
|
731
|
+
description: toolSchemas.cortex_get_overview.description,
|
|
732
|
+
parameters: toolSchemas.cortex_get_overview.inputSchema,
|
|
733
|
+
execute: async (_id, params) => {
|
|
734
|
+
const input = params;
|
|
735
|
+
try {
|
|
736
|
+
await ensureServicesReady();
|
|
737
|
+
const result = await client.getOverview(input.uri);
|
|
738
|
+
return {
|
|
739
|
+
content: `L1 Overview for "${result.uri}" (~${result.token_count} tokens):\n\n${result.content}`,
|
|
740
|
+
uri: result.uri,
|
|
741
|
+
overview: result.content,
|
|
742
|
+
token_count: result.token_count,
|
|
743
|
+
layer: result.layer
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
catch (error) {
|
|
747
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
748
|
+
api.logger.error(`[memclaw] cortex_get_overview failed: ${message}`);
|
|
749
|
+
return { error: `Get overview failed: ${message}` };
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
// cortex_get_content
|
|
754
|
+
api.registerTool({
|
|
755
|
+
name: toolSchemas.cortex_get_content.name,
|
|
756
|
+
description: toolSchemas.cortex_get_content.description,
|
|
757
|
+
parameters: toolSchemas.cortex_get_content.inputSchema,
|
|
758
|
+
execute: async (_id, params) => {
|
|
759
|
+
const input = params;
|
|
760
|
+
try {
|
|
761
|
+
await ensureServicesReady();
|
|
762
|
+
const result = await client.getContent(input.uri);
|
|
763
|
+
return {
|
|
764
|
+
content: `L2 Full Content for "${result.uri}" (~${result.token_count} tokens):\n\n${result.content}`,
|
|
765
|
+
uri: result.uri,
|
|
766
|
+
full_content: result.content,
|
|
767
|
+
token_count: result.token_count,
|
|
768
|
+
layer: result.layer
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
catch (error) {
|
|
772
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
773
|
+
api.logger.error(`[memclaw] cortex_get_content failed: ${message}`);
|
|
774
|
+
return { error: `Get content failed: ${message}` };
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
});
|
|
778
|
+
// cortex_explore
|
|
779
|
+
api.registerTool({
|
|
780
|
+
name: toolSchemas.cortex_explore.name,
|
|
781
|
+
description: toolSchemas.cortex_explore.description,
|
|
782
|
+
parameters: toolSchemas.cortex_explore.inputSchema,
|
|
783
|
+
execute: async (_id, params) => {
|
|
784
|
+
const input = params;
|
|
785
|
+
try {
|
|
786
|
+
await ensureServicesReady();
|
|
787
|
+
const result = await client.explore({
|
|
788
|
+
query: input.query,
|
|
789
|
+
start_uri: input.start_uri ?? 'cortex://session',
|
|
790
|
+
return_layers: input.return_layers ?? ['L0']
|
|
791
|
+
});
|
|
792
|
+
// Format exploration path
|
|
793
|
+
const pathFormatted = result.exploration_path
|
|
794
|
+
.map((item, i) => {
|
|
795
|
+
let content = `${i + 1}. [${item.relevance_score.toFixed(2)}] ${item.uri}\n`;
|
|
796
|
+
if (item.abstract_text) {
|
|
797
|
+
const preview = item.abstract_text.length > 80
|
|
798
|
+
? item.abstract_text.substring(0, 80) + '...'
|
|
799
|
+
: item.abstract_text;
|
|
800
|
+
content += ` Abstract: ${preview}\n`;
|
|
502
801
|
}
|
|
802
|
+
return content;
|
|
803
|
+
})
|
|
804
|
+
.join('\n');
|
|
805
|
+
// Format matches
|
|
806
|
+
const matchesFormatted = result.matches
|
|
807
|
+
.map((m, i) => {
|
|
808
|
+
let content = `${i + 1}. [${m.score.toFixed(2)}] ${m.uri}\n`;
|
|
809
|
+
content += ` Layers: ${m.layers.join(', ')}\n`;
|
|
810
|
+
content += ` Snippet: ${m.snippet}\n`;
|
|
811
|
+
return content;
|
|
812
|
+
})
|
|
813
|
+
.join('\n');
|
|
814
|
+
return {
|
|
815
|
+
content: `Exploration for "${input.query}" starting from "${input.start_uri ?? 'cortex://session'}":\n\n` +
|
|
816
|
+
`**Exploration Path** (${result.total_explored} items):\n${pathFormatted}\n\n` +
|
|
817
|
+
`**Matches** (${result.total_matches} found):\n${matchesFormatted}`,
|
|
818
|
+
exploration_path: result.exploration_path,
|
|
819
|
+
matches: result.matches,
|
|
820
|
+
total_explored: result.total_explored,
|
|
821
|
+
total_matches: result.total_matches
|
|
503
822
|
};
|
|
504
823
|
}
|
|
505
824
|
catch (error) {
|
|
506
825
|
const message = error instanceof Error ? error.message : String(error);
|
|
507
|
-
api.logger.error(`
|
|
508
|
-
return { error: `
|
|
826
|
+
api.logger.error(`[memclaw] cortex_explore failed: ${message}`);
|
|
827
|
+
return { error: `Explore failed: ${message}` };
|
|
509
828
|
}
|
|
510
829
|
}
|
|
511
830
|
});
|
|
@@ -577,7 +896,7 @@ function createPlugin(api) {
|
|
|
577
896
|
output: result.stdout || result.stderr
|
|
578
897
|
});
|
|
579
898
|
if (!result.success) {
|
|
580
|
-
api.logger.warn(`[maintenance] ${description} failed: ${result.stderr}`);
|
|
899
|
+
api.logger.warn(`[memclaw] [maintenance] ${description} failed: ${result.stderr}`);
|
|
581
900
|
}
|
|
582
901
|
}
|
|
583
902
|
catch (error) {
|