memory-lancedb-pro 1.0.25 → 1.0.26

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/src/tools.ts CHANGED
@@ -16,7 +16,13 @@ import type { Embedder } from "./embedder.js";
16
16
  // Types
17
17
  // ============================================================================
18
18
 
19
- export const MEMORY_CATEGORIES = ["preference", "fact", "decision", "entity", "other"] as const;
19
+ export const MEMORY_CATEGORIES = [
20
+ "preference",
21
+ "fact",
22
+ "decision",
23
+ "entity",
24
+ "other",
25
+ ] as const;
20
26
 
21
27
  interface ToolContext {
22
28
  retriever: MemoryRetriever;
@@ -47,7 +53,7 @@ function clamp01(value: number, fallback = 0.7): number {
47
53
  }
48
54
 
49
55
  function sanitizeMemoryForSerialization(results: RetrievalResult[]) {
50
- return results.map(r => ({
56
+ return results.map((r) => ({
51
57
  id: r.entry.id,
52
58
  text: r.entry.text,
53
59
  category: r.entry.category,
@@ -62,22 +68,41 @@ function sanitizeMemoryForSerialization(results: RetrievalResult[]) {
62
68
  // Core Tools (Backward Compatible)
63
69
  // ============================================================================
64
70
 
65
- export function registerMemoryRecallTool(api: OpenClawPluginApi, context: ToolContext) {
71
+ export function registerMemoryRecallTool(
72
+ api: OpenClawPluginApi,
73
+ context: ToolContext,
74
+ ) {
66
75
  api.registerTool(
67
76
  (toolCtx) => {
68
77
  const agentId = resolveAgentId((toolCtx as any)?.agentId, context.agentId) ?? "main";
69
78
  return {
70
79
  name: "memory_recall",
71
80
  label: "Memory Recall",
72
- description: "Search through long-term memories using hybrid retrieval (vector + keyword search). Use when you need context about user preferences, past decisions, or previously discussed topics.",
81
+ description:
82
+ "Search through long-term memories using hybrid retrieval (vector + keyword search). Use when you need context about user preferences, past decisions, or previously discussed topics.",
73
83
  parameters: Type.Object({
74
- query: Type.String({ description: "Search query for finding relevant memories" }),
75
- limit: Type.Optional(Type.Number({ description: "Max results to return (default: 5, max: 20)" })),
76
- scope: Type.Optional(Type.String({ description: "Specific memory scope to search in (optional)" })),
84
+ query: Type.String({
85
+ description: "Search query for finding relevant memories",
86
+ }),
87
+ limit: Type.Optional(
88
+ Type.Number({
89
+ description: "Max results to return (default: 5, max: 20)",
90
+ }),
91
+ ),
92
+ scope: Type.Optional(
93
+ Type.String({
94
+ description: "Specific memory scope to search in (optional)",
95
+ }),
96
+ ),
77
97
  category: Type.Optional(stringEnum(MEMORY_CATEGORIES)),
78
98
  }),
79
99
  async execute(_toolCallId, params) {
80
- const { query, limit = 5, scope, category } = params as {
100
+ const {
101
+ query,
102
+ limit = 5,
103
+ scope,
104
+ category,
105
+ } = params as {
81
106
  query: string;
82
107
  limit?: number;
83
108
  scope?: string;
@@ -94,8 +119,13 @@ export function registerMemoryRecallTool(api: OpenClawPluginApi, context: ToolCo
94
119
  scopeFilter = [scope];
95
120
  } else {
96
121
  return {
97
- content: [{ type: "text", text: `Access denied to scope: ${scope}` }],
98
- details: { error: "scope_access_denied", requestedScope: scope },
122
+ content: [
123
+ { type: "text", text: `Access denied to scope: ${scope}` },
124
+ ],
125
+ details: {
126
+ error: "scope_access_denied",
127
+ requestedScope: scope,
128
+ },
99
129
  };
100
130
  }
101
131
  }
@@ -105,6 +135,7 @@ export function registerMemoryRecallTool(api: OpenClawPluginApi, context: ToolCo
105
135
  limit: safeLimit,
106
136
  scopeFilter,
107
137
  category,
138
+ source: "manual",
108
139
  });
109
140
 
110
141
  if (results.length === 0) {
@@ -121,12 +152,17 @@ export function registerMemoryRecallTool(api: OpenClawPluginApi, context: ToolCo
121
152
  if (r.sources.bm25) sources.push("BM25");
122
153
  if (r.sources.reranked) sources.push("reranked");
123
154
 
124
- return `${i + 1}. [${r.entry.id}] [${r.entry.category}:${r.entry.scope}] ${r.entry.text} (${(r.score * 100).toFixed(0)}%${sources.length > 0 ? `, ${sources.join('+')}` : ''})`;
155
+ return `${i + 1}. [${r.entry.id}] [${r.entry.category}:${r.entry.scope}] ${r.entry.text} (${(r.score * 100).toFixed(0)}%${sources.length > 0 ? `, ${sources.join("+")}` : ""})`;
125
156
  })
126
157
  .join("\n");
127
158
 
128
159
  return {
129
- content: [{ type: "text", text: `Found ${results.length} memories:\n\n${text}` }],
160
+ content: [
161
+ {
162
+ type: "text",
163
+ text: `Found ${results.length} memories:\n\n${text}`,
164
+ },
165
+ ],
130
166
  details: {
131
167
  count: results.length,
132
168
  memories: sanitizeMemoryForSerialization(results),
@@ -137,30 +173,45 @@ export function registerMemoryRecallTool(api: OpenClawPluginApi, context: ToolCo
137
173
  };
138
174
  } catch (error) {
139
175
  return {
140
- content: [{ type: "text", text: `Memory recall failed: ${error instanceof Error ? error.message : String(error)}` }],
176
+ content: [
177
+ {
178
+ type: "text",
179
+ text: `Memory recall failed: ${error instanceof Error ? error.message : String(error)}`,
180
+ },
181
+ ],
141
182
  details: { error: "recall_failed", message: String(error) },
142
183
  };
143
184
  }
144
185
  },
145
186
  };
146
187
  },
147
- { name: "memory_recall" }
188
+ { name: "memory_recall" },
148
189
  );
149
190
  }
150
191
 
151
- export function registerMemoryStoreTool(api: OpenClawPluginApi, context: ToolContext) {
192
+ export function registerMemoryStoreTool(
193
+ api: OpenClawPluginApi,
194
+ context: ToolContext,
195
+ ) {
152
196
  api.registerTool(
153
197
  (toolCtx) => {
154
198
  const agentId = resolveAgentId((toolCtx as any)?.agentId, context.agentId) ?? "main";
155
199
  return {
156
200
  name: "memory_store",
157
201
  label: "Memory Store",
158
- description: "Save important information in long-term memory. Use for preferences, facts, decisions, and other notable information.",
202
+ description:
203
+ "Save important information in long-term memory. Use for preferences, facts, decisions, and other notable information.",
159
204
  parameters: Type.Object({
160
205
  text: Type.String({ description: "Information to remember" }),
161
- importance: Type.Optional(Type.Number({ description: "Importance score 0-1 (default: 0.7)" })),
206
+ importance: Type.Optional(
207
+ Type.Number({ description: "Importance score 0-1 (default: 0.7)" }),
208
+ ),
162
209
  category: Type.Optional(stringEnum(MEMORY_CATEGORIES)),
163
- scope: Type.Optional(Type.String({ description: "Memory scope (optional, defaults to agent scope)" })),
210
+ scope: Type.Optional(
211
+ Type.String({
212
+ description: "Memory scope (optional, defaults to agent scope)",
213
+ }),
214
+ ),
164
215
  }),
165
216
  async execute(_toolCallId, params) {
166
217
  const {
@@ -182,15 +233,28 @@ export function registerMemoryStoreTool(api: OpenClawPluginApi, context: ToolCon
182
233
  // Validate scope access
183
234
  if (!context.scopeManager.isAccessible(targetScope, agentId)) {
184
235
  return {
185
- content: [{ type: "text", text: `Access denied to scope: ${targetScope}` }],
186
- details: { error: "scope_access_denied", requestedScope: targetScope },
236
+ content: [
237
+ {
238
+ type: "text",
239
+ text: `Access denied to scope: ${targetScope}`,
240
+ },
241
+ ],
242
+ details: {
243
+ error: "scope_access_denied",
244
+ requestedScope: targetScope,
245
+ },
187
246
  };
188
247
  }
189
248
 
190
249
  // Reject noise before wasting an embedding API call
191
250
  if (isNoise(text)) {
192
251
  return {
193
- content: [{ type: "text", text: `Skipped: text detected as noise (greeting, boilerplate, or meta-question)` }],
252
+ content: [
253
+ {
254
+ type: "text",
255
+ text: `Skipped: text detected as noise (greeting, boilerplate, or meta-question)`,
256
+ },
257
+ ],
194
258
  details: { action: "noise_filtered", text: text.slice(0, 60) },
195
259
  };
196
260
  }
@@ -199,7 +263,9 @@ export function registerMemoryStoreTool(api: OpenClawPluginApi, context: ToolCon
199
263
  const vector = await context.embedder.embedPassage(text);
200
264
 
201
265
  // Check for duplicates using raw vector similarity (bypasses importance/recency weighting)
202
- const existing = await context.store.vectorSearch(vector, 1, 0.1, [targetScope]);
266
+ const existing = await context.store.vectorSearch(vector, 1, 0.1, [
267
+ targetScope,
268
+ ]);
203
269
 
204
270
  if (existing.length > 0 && existing[0].score > 0.98) {
205
271
  return {
@@ -228,7 +294,12 @@ export function registerMemoryStoreTool(api: OpenClawPluginApi, context: ToolCon
228
294
  });
229
295
 
230
296
  return {
231
- content: [{ type: "text", text: `Stored: "${text.slice(0, 100)}${text.length > 100 ? '...' : ''}" in scope '${targetScope}'` }],
297
+ content: [
298
+ {
299
+ type: "text",
300
+ text: `Stored: "${text.slice(0, 100)}${text.length > 100 ? "..." : ""}" in scope '${targetScope}'`,
301
+ },
302
+ ],
232
303
  details: {
233
304
  action: "created",
234
305
  id: entry.id,
@@ -239,29 +310,46 @@ export function registerMemoryStoreTool(api: OpenClawPluginApi, context: ToolCon
239
310
  };
240
311
  } catch (error) {
241
312
  return {
242
- content: [{ type: "text", text: `Memory storage failed: ${error instanceof Error ? error.message : String(error)}` }],
313
+ content: [
314
+ {
315
+ type: "text",
316
+ text: `Memory storage failed: ${error instanceof Error ? error.message : String(error)}`,
317
+ },
318
+ ],
243
319
  details: { error: "store_failed", message: String(error) },
244
320
  };
245
321
  }
246
322
  },
247
323
  };
248
324
  },
249
- { name: "memory_store" }
325
+ { name: "memory_store" },
250
326
  );
251
327
  }
252
328
 
253
- export function registerMemoryForgetTool(api: OpenClawPluginApi, context: ToolContext) {
329
+ export function registerMemoryForgetTool(
330
+ api: OpenClawPluginApi,
331
+ context: ToolContext,
332
+ ) {
254
333
  api.registerTool(
255
334
  (toolCtx) => {
256
335
  const agentId = resolveAgentId((toolCtx as any)?.agentId, context.agentId) ?? "main";
257
336
  return {
258
337
  name: "memory_forget",
259
338
  label: "Memory Forget",
260
- description: "Delete specific memories. Supports both search-based and direct ID-based deletion.",
339
+ description:
340
+ "Delete specific memories. Supports both search-based and direct ID-based deletion.",
261
341
  parameters: Type.Object({
262
- query: Type.Optional(Type.String({ description: "Search query to find memory to delete" })),
263
- memoryId: Type.Optional(Type.String({ description: "Specific memory ID to delete" })),
264
- scope: Type.Optional(Type.String({ description: "Scope to search/delete from (optional)" })),
342
+ query: Type.Optional(
343
+ Type.String({ description: "Search query to find memory to delete" }),
344
+ ),
345
+ memoryId: Type.Optional(
346
+ Type.String({ description: "Specific memory ID to delete" }),
347
+ ),
348
+ scope: Type.Optional(
349
+ Type.String({
350
+ description: "Scope to search/delete from (optional)",
351
+ }),
352
+ ),
265
353
  }),
266
354
  async execute(_toolCallId, params) {
267
355
  const { query, memoryId, scope } = params as {
@@ -278,8 +366,13 @@ export function registerMemoryForgetTool(api: OpenClawPluginApi, context: ToolCo
278
366
  scopeFilter = [scope];
279
367
  } else {
280
368
  return {
281
- content: [{ type: "text", text: `Access denied to scope: ${scope}` }],
282
- details: { error: "scope_access_denied", requestedScope: scope },
369
+ content: [
370
+ { type: "text", text: `Access denied to scope: ${scope}` },
371
+ ],
372
+ details: {
373
+ error: "scope_access_denied",
374
+ requestedScope: scope,
375
+ },
283
376
  };
284
377
  }
285
378
  }
@@ -288,12 +381,19 @@ export function registerMemoryForgetTool(api: OpenClawPluginApi, context: ToolCo
288
381
  const deleted = await context.store.delete(memoryId, scopeFilter);
289
382
  if (deleted) {
290
383
  return {
291
- content: [{ type: "text", text: `Memory ${memoryId} forgotten.` }],
384
+ content: [
385
+ { type: "text", text: `Memory ${memoryId} forgotten.` },
386
+ ],
292
387
  details: { action: "deleted", id: memoryId },
293
388
  };
294
389
  } else {
295
390
  return {
296
- content: [{ type: "text", text: `Memory ${memoryId} not found or access denied.` }],
391
+ content: [
392
+ {
393
+ type: "text",
394
+ text: `Memory ${memoryId} not found or access denied.`,
395
+ },
396
+ ],
297
397
  details: { error: "not_found", id: memoryId },
298
398
  };
299
399
  }
@@ -308,23 +408,36 @@ export function registerMemoryForgetTool(api: OpenClawPluginApi, context: ToolCo
308
408
 
309
409
  if (results.length === 0) {
310
410
  return {
311
- content: [{ type: "text", text: "No matching memories found." }],
411
+ content: [
412
+ { type: "text", text: "No matching memories found." },
413
+ ],
312
414
  details: { found: 0, query },
313
415
  };
314
416
  }
315
417
 
316
418
  if (results.length === 1 && results[0].score > 0.9) {
317
- const deleted = await context.store.delete(results[0].entry.id, scopeFilter);
419
+ const deleted = await context.store.delete(
420
+ results[0].entry.id,
421
+ scopeFilter,
422
+ );
318
423
  if (deleted) {
319
424
  return {
320
- content: [{ type: "text", text: `Forgotten: "${results[0].entry.text}"` }],
425
+ content: [
426
+ {
427
+ type: "text",
428
+ text: `Forgotten: "${results[0].entry.text}"`,
429
+ },
430
+ ],
321
431
  details: { action: "deleted", id: results[0].entry.id },
322
432
  };
323
433
  }
324
434
  }
325
435
 
326
436
  const list = results
327
- .map(r => `- [${r.entry.id.slice(0, 8)}] ${r.entry.text.slice(0, 60)}${r.entry.text.length > 60 ? '...' : ''}`)
437
+ .map(
438
+ (r) =>
439
+ `- [${r.entry.id.slice(0, 8)}] ${r.entry.text.slice(0, 60)}${r.entry.text.length > 60 ? "..." : ""}`,
440
+ )
328
441
  .join("\n");
329
442
 
330
443
  return {
@@ -342,19 +455,29 @@ export function registerMemoryForgetTool(api: OpenClawPluginApi, context: ToolCo
342
455
  }
343
456
 
344
457
  return {
345
- content: [{ type: "text", text: "Provide either 'query' to search for memories or 'memoryId' to delete specific memory." }],
458
+ content: [
459
+ {
460
+ type: "text",
461
+ text: "Provide either 'query' to search for memories or 'memoryId' to delete specific memory.",
462
+ },
463
+ ],
346
464
  details: { error: "missing_param" },
347
465
  };
348
466
  } catch (error) {
349
467
  return {
350
- content: [{ type: "text", text: `Memory deletion failed: ${error instanceof Error ? error.message : String(error)}` }],
468
+ content: [
469
+ {
470
+ type: "text",
471
+ text: `Memory deletion failed: ${error instanceof Error ? error.message : String(error)}`,
472
+ },
473
+ ],
351
474
  details: { error: "delete_failed", message: String(error) },
352
475
  };
353
476
  }
354
477
  },
355
478
  };
356
479
  },
357
- { name: "memory_forget" }
480
+ { name: "memory_forget" },
358
481
  );
359
482
  }
360
483
 
@@ -362,18 +485,31 @@ export function registerMemoryForgetTool(api: OpenClawPluginApi, context: ToolCo
362
485
  // Update Tool
363
486
  // ============================================================================
364
487
 
365
- export function registerMemoryUpdateTool(api: OpenClawPluginApi, context: ToolContext) {
488
+ export function registerMemoryUpdateTool(
489
+ api: OpenClawPluginApi,
490
+ context: ToolContext,
491
+ ) {
366
492
  api.registerTool(
367
493
  (toolCtx) => {
368
494
  const agentId = resolveAgentId((toolCtx as any)?.agentId, context.agentId) ?? "main";
369
495
  return {
370
496
  name: "memory_update",
371
497
  label: "Memory Update",
372
- description: "Update an existing memory in-place. Preserves original timestamp. Use when correcting outdated info or adjusting importance/category without losing creation date.",
498
+ description:
499
+ "Update an existing memory in-place. Preserves original timestamp. Use when correcting outdated info or adjusting importance/category without losing creation date.",
373
500
  parameters: Type.Object({
374
- memoryId: Type.String({ description: "ID of the memory to update (full UUID or 8+ char prefix)" }),
375
- text: Type.Optional(Type.String({ description: "New text content (triggers re-embedding)" })),
376
- importance: Type.Optional(Type.Number({ description: "New importance score 0-1" })),
501
+ memoryId: Type.String({
502
+ description:
503
+ "ID of the memory to update (full UUID or 8+ char prefix)",
504
+ }),
505
+ text: Type.Optional(
506
+ Type.String({
507
+ description: "New text content (triggers re-embedding)",
508
+ }),
509
+ ),
510
+ importance: Type.Optional(
511
+ Type.Number({ description: "New importance score 0-1" }),
512
+ ),
377
513
  category: Type.Optional(stringEnum(MEMORY_CATEGORIES)),
378
514
  }),
379
515
  async execute(_toolCallId, params) {
@@ -387,7 +523,12 @@ export function registerMemoryUpdateTool(api: OpenClawPluginApi, context: ToolCo
387
523
  try {
388
524
  if (!text && importance === undefined && !category) {
389
525
  return {
390
- content: [{ type: "text", text: "Nothing to update. Provide at least one of: text, importance, category." }],
526
+ content: [
527
+ {
528
+ type: "text",
529
+ text: "Nothing to update. Provide at least one of: text, importance, category.",
530
+ },
531
+ ],
391
532
  details: { error: "no_updates" },
392
533
  };
393
534
  }
@@ -407,7 +548,12 @@ export function registerMemoryUpdateTool(api: OpenClawPluginApi, context: ToolCo
407
548
  });
408
549
  if (results.length === 0) {
409
550
  return {
410
- content: [{ type: "text", text: `No memory found matching "${memoryId}".` }],
551
+ content: [
552
+ {
553
+ type: "text",
554
+ text: `No memory found matching "${memoryId}".`,
555
+ },
556
+ ],
411
557
  details: { error: "not_found", query: memoryId },
412
558
  };
413
559
  }
@@ -415,11 +561,22 @@ export function registerMemoryUpdateTool(api: OpenClawPluginApi, context: ToolCo
415
561
  resolvedId = results[0].entry.id;
416
562
  } else {
417
563
  const list = results
418
- .map(r => `- [${r.entry.id.slice(0, 8)}] ${r.entry.text.slice(0, 60)}${r.entry.text.length > 60 ? '...' : ''}`)
564
+ .map(
565
+ (r) =>
566
+ `- [${r.entry.id.slice(0, 8)}] ${r.entry.text.slice(0, 60)}${r.entry.text.length > 60 ? "..." : ""}`,
567
+ )
419
568
  .join("\n");
420
569
  return {
421
- content: [{ type: "text", text: `Multiple matches. Specify memoryId:\n${list}` }],
422
- details: { action: "candidates", candidates: sanitizeMemoryForSerialization(results) },
570
+ content: [
571
+ {
572
+ type: "text",
573
+ text: `Multiple matches. Specify memoryId:\n${list}`,
574
+ },
575
+ ],
576
+ details: {
577
+ action: "candidates",
578
+ candidates: sanitizeMemoryForSerialization(results),
579
+ },
423
580
  };
424
581
  }
425
582
  }
@@ -429,7 +586,12 @@ export function registerMemoryUpdateTool(api: OpenClawPluginApi, context: ToolCo
429
586
  if (text) {
430
587
  if (isNoise(text)) {
431
588
  return {
432
- content: [{ type: "text", text: "Skipped: updated text detected as noise" }],
589
+ content: [
590
+ {
591
+ type: "text",
592
+ text: "Skipped: updated text detected as noise",
593
+ },
594
+ ],
433
595
  details: { action: "noise_filtered" },
434
596
  };
435
597
  }
@@ -439,20 +601,35 @@ export function registerMemoryUpdateTool(api: OpenClawPluginApi, context: ToolCo
439
601
  const updates: Record<string, any> = {};
440
602
  if (text) updates.text = text;
441
603
  if (newVector) updates.vector = newVector;
442
- if (importance !== undefined) updates.importance = clamp01(importance, 0.7);
604
+ if (importance !== undefined)
605
+ updates.importance = clamp01(importance, 0.7);
443
606
  if (category) updates.category = category;
444
607
 
445
- const updated = await context.store.update(resolvedId, updates, scopeFilter);
608
+ const updated = await context.store.update(
609
+ resolvedId,
610
+ updates,
611
+ scopeFilter,
612
+ );
446
613
 
447
614
  if (!updated) {
448
615
  return {
449
- content: [{ type: "text", text: `Memory ${resolvedId.slice(0, 8)}... not found or access denied.` }],
616
+ content: [
617
+ {
618
+ type: "text",
619
+ text: `Memory ${resolvedId.slice(0, 8)}... not found or access denied.`,
620
+ },
621
+ ],
450
622
  details: { error: "not_found", id: resolvedId },
451
623
  };
452
624
  }
453
625
 
454
626
  return {
455
- content: [{ type: "text", text: `Updated memory ${updated.id.slice(0, 8)}...: "${updated.text.slice(0, 80)}${updated.text.length > 80 ? '...' : ''}"` }],
627
+ content: [
628
+ {
629
+ type: "text",
630
+ text: `Updated memory ${updated.id.slice(0, 8)}...: "${updated.text.slice(0, 80)}${updated.text.length > 80 ? "..." : ""}"`,
631
+ },
632
+ ],
456
633
  details: {
457
634
  action: "updated",
458
635
  id: updated.id,
@@ -464,14 +641,19 @@ export function registerMemoryUpdateTool(api: OpenClawPluginApi, context: ToolCo
464
641
  };
465
642
  } catch (error) {
466
643
  return {
467
- content: [{ type: "text", text: `Memory update failed: ${error instanceof Error ? error.message : String(error)}` }],
644
+ content: [
645
+ {
646
+ type: "text",
647
+ text: `Memory update failed: ${error instanceof Error ? error.message : String(error)}`,
648
+ },
649
+ ],
468
650
  details: { error: "update_failed", message: String(error) },
469
651
  };
470
652
  }
471
653
  },
472
654
  };
473
655
  },
474
- { name: "memory_update" }
656
+ { name: "memory_update" },
475
657
  );
476
658
  }
477
659
 
@@ -479,7 +661,10 @@ export function registerMemoryUpdateTool(api: OpenClawPluginApi, context: ToolCo
479
661
  // Management Tools (Optional)
480
662
  // ============================================================================
481
663
 
482
- export function registerMemoryStatsTool(api: OpenClawPluginApi, context: ToolContext) {
664
+ export function registerMemoryStatsTool(
665
+ api: OpenClawPluginApi,
666
+ context: ToolContext,
667
+ ) {
483
668
  api.registerTool(
484
669
  (toolCtx) => {
485
670
  const agentId = resolveAgentId((toolCtx as any)?.agentId, context.agentId) ?? "main";
@@ -488,7 +673,11 @@ export function registerMemoryStatsTool(api: OpenClawPluginApi, context: ToolCon
488
673
  label: "Memory Statistics",
489
674
  description: "Get statistics about memory usage, scopes, and categories.",
490
675
  parameters: Type.Object({
491
- scope: Type.Optional(Type.String({ description: "Specific scope to get stats for (optional)" })),
676
+ scope: Type.Optional(
677
+ Type.String({
678
+ description: "Specific scope to get stats for (optional)",
679
+ }),
680
+ ),
492
681
  }),
493
682
  async execute(_toolCallId, params) {
494
683
  const { scope } = params as { scope?: string };
@@ -501,8 +690,13 @@ export function registerMemoryStatsTool(api: OpenClawPluginApi, context: ToolCon
501
690
  scopeFilter = [scope];
502
691
  } else {
503
692
  return {
504
- content: [{ type: "text", text: `Access denied to scope: ${scope}` }],
505
- details: { error: "scope_access_denied", requestedScope: scope },
693
+ content: [
694
+ { type: "text", text: `Access denied to scope: ${scope}` },
695
+ ],
696
+ details: {
697
+ error: "scope_access_denied",
698
+ requestedScope: scope,
699
+ },
506
700
  };
507
701
  }
508
702
  }
@@ -516,14 +710,18 @@ export function registerMemoryStatsTool(api: OpenClawPluginApi, context: ToolCon
516
710
  `• Total memories: ${stats.totalCount}`,
517
711
  `• Available scopes: ${scopeManagerStats.totalScopes}`,
518
712
  `• Retrieval mode: ${retrievalConfig.mode}`,
519
- `• FTS support: ${context.store.hasFtsSupport ? 'Yes' : 'No'}`,
713
+ `• FTS support: ${context.store.hasFtsSupport ? "Yes" : "No"}`,
520
714
  ``,
521
715
  `Memories by scope:`,
522
- ...Object.entries(stats.scopeCounts).map(([s, count]) => ` • ${s}: ${count}`),
716
+ ...Object.entries(stats.scopeCounts).map(
717
+ ([s, count]) => ` • ${s}: ${count}`,
718
+ ),
523
719
  ``,
524
720
  `Memories by category:`,
525
- ...Object.entries(stats.categoryCounts).map(([c, count]) => ` • ${c}: ${count}`),
526
- ].join('\n');
721
+ ...Object.entries(stats.categoryCounts).map(
722
+ ([c, count]) => ` • ${c}: ${count}`,
723
+ ),
724
+ ].join("\n");
527
725
 
528
726
  return {
529
727
  content: [{ type: "text", text }],
@@ -539,30 +737,49 @@ export function registerMemoryStatsTool(api: OpenClawPluginApi, context: ToolCon
539
737
  };
540
738
  } catch (error) {
541
739
  return {
542
- content: [{ type: "text", text: `Failed to get memory stats: ${error instanceof Error ? error.message : String(error)}` }],
740
+ content: [
741
+ {
742
+ type: "text",
743
+ text: `Failed to get memory stats: ${error instanceof Error ? error.message : String(error)}`,
744
+ },
745
+ ],
543
746
  details: { error: "stats_failed", message: String(error) },
544
747
  };
545
748
  }
546
749
  },
547
750
  };
548
751
  },
549
- { name: "memory_stats" }
752
+ { name: "memory_stats" },
550
753
  );
551
754
  }
552
755
 
553
- export function registerMemoryListTool(api: OpenClawPluginApi, context: ToolContext) {
756
+ export function registerMemoryListTool(
757
+ api: OpenClawPluginApi,
758
+ context: ToolContext,
759
+ ) {
554
760
  api.registerTool(
555
761
  (toolCtx) => {
556
762
  const agentId = resolveAgentId((toolCtx as any)?.agentId, context.agentId) ?? "main";
557
763
  return {
558
764
  name: "memory_list",
559
765
  label: "Memory List",
560
- description: "List recent memories with optional filtering by scope and category.",
766
+ description:
767
+ "List recent memories with optional filtering by scope and category.",
561
768
  parameters: Type.Object({
562
- limit: Type.Optional(Type.Number({ description: "Max memories to list (default: 10, max: 50)" })),
563
- scope: Type.Optional(Type.String({ description: "Filter by specific scope (optional)" })),
769
+ limit: Type.Optional(
770
+ Type.Number({
771
+ description: "Max memories to list (default: 10, max: 50)",
772
+ }),
773
+ ),
774
+ scope: Type.Optional(
775
+ Type.String({ description: "Filter by specific scope (optional)" }),
776
+ ),
564
777
  category: Type.Optional(stringEnum(MEMORY_CATEGORIES)),
565
- offset: Type.Optional(Type.Number({ description: "Number of memories to skip (default: 0)" })),
778
+ offset: Type.Optional(
779
+ Type.Number({
780
+ description: "Number of memories to skip (default: 0)",
781
+ }),
782
+ ),
566
783
  }),
567
784
  async execute(_toolCallId, params) {
568
785
  const {
@@ -588,33 +805,58 @@ export function registerMemoryListTool(api: OpenClawPluginApi, context: ToolCont
588
805
  scopeFilter = [scope];
589
806
  } else {
590
807
  return {
591
- content: [{ type: "text", text: `Access denied to scope: ${scope}` }],
592
- details: { error: "scope_access_denied", requestedScope: scope },
808
+ content: [
809
+ { type: "text", text: `Access denied to scope: ${scope}` },
810
+ ],
811
+ details: {
812
+ error: "scope_access_denied",
813
+ requestedScope: scope,
814
+ },
593
815
  };
594
816
  }
595
817
  }
596
818
 
597
- const entries = await context.store.list(scopeFilter, category, safeLimit, safeOffset);
819
+ const entries = await context.store.list(
820
+ scopeFilter,
821
+ category,
822
+ safeLimit,
823
+ safeOffset,
824
+ );
598
825
 
599
826
  if (entries.length === 0) {
600
827
  return {
601
828
  content: [{ type: "text", text: "No memories found." }],
602
- details: { count: 0, filters: { scope, category, limit: safeLimit, offset: safeOffset } },
829
+ details: {
830
+ count: 0,
831
+ filters: {
832
+ scope,
833
+ category,
834
+ limit: safeLimit,
835
+ offset: safeOffset,
836
+ },
837
+ },
603
838
  };
604
839
  }
605
840
 
606
841
  const text = entries
607
842
  .map((entry, i) => {
608
- const date = new Date(entry.timestamp).toISOString().split('T')[0];
609
- return `${safeOffset + i + 1}. [${entry.id}] [${entry.category}:${entry.scope}] ${entry.text.slice(0, 100)}${entry.text.length > 100 ? '...' : ''} (${date})`;
843
+ const date = new Date(entry.timestamp)
844
+ .toISOString()
845
+ .split("T")[0];
846
+ return `${safeOffset + i + 1}. [${entry.id}] [${entry.category}:${entry.scope}] ${entry.text.slice(0, 100)}${entry.text.length > 100 ? "..." : ""} (${date})`;
610
847
  })
611
- .join('\n');
848
+ .join("\n");
612
849
 
613
850
  return {
614
- content: [{ type: "text", text: `Recent memories (showing ${entries.length}):\n\n${text}` }],
851
+ content: [
852
+ {
853
+ type: "text",
854
+ text: `Recent memories (showing ${entries.length}):\n\n${text}`,
855
+ },
856
+ ],
615
857
  details: {
616
858
  count: entries.length,
617
- memories: entries.map(e => ({
859
+ memories: entries.map((e) => ({
618
860
  id: e.id,
619
861
  text: e.text,
620
862
  category: e.category,
@@ -622,19 +864,29 @@ export function registerMemoryListTool(api: OpenClawPluginApi, context: ToolCont
622
864
  importance: e.importance,
623
865
  timestamp: e.timestamp,
624
866
  })),
625
- filters: { scope, category, limit: safeLimit, offset: safeOffset },
867
+ filters: {
868
+ scope,
869
+ category,
870
+ limit: safeLimit,
871
+ offset: safeOffset,
872
+ },
626
873
  },
627
874
  };
628
875
  } catch (error) {
629
876
  return {
630
- content: [{ type: "text", text: `Failed to list memories: ${error instanceof Error ? error.message : String(error)}` }],
877
+ content: [
878
+ {
879
+ type: "text",
880
+ text: `Failed to list memories: ${error instanceof Error ? error.message : String(error)}`,
881
+ },
882
+ ],
631
883
  details: { error: "list_failed", message: String(error) },
632
884
  };
633
885
  }
634
886
  },
635
887
  };
636
888
  },
637
- { name: "memory_list" }
889
+ { name: "memory_list" },
638
890
  );
639
891
  }
640
892
 
@@ -647,7 +899,7 @@ export function registerAllMemoryTools(
647
899
  context: ToolContext,
648
900
  options: {
649
901
  enableManagementTools?: boolean;
650
- } = {}
902
+ } = {},
651
903
  ) {
652
904
  // Core tools (always enabled)
653
905
  registerMemoryRecallTool(api, context);
@@ -660,4 +912,4 @@ export function registerAllMemoryTools(
660
912
  registerMemoryStatsTool(api, context);
661
913
  registerMemoryListTool(api, context);
662
914
  }
663
- }
915
+ }