@memtensor/memos-local-openclaw-plugin 0.1.2 → 0.1.4

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.
Files changed (77) hide show
  1. package/.env.example +13 -5
  2. package/README.md +180 -68
  3. package/dist/capture/index.d.ts +5 -7
  4. package/dist/capture/index.d.ts.map +1 -1
  5. package/dist/capture/index.js +72 -43
  6. package/dist/capture/index.js.map +1 -1
  7. package/dist/ingest/providers/anthropic.d.ts +2 -0
  8. package/dist/ingest/providers/anthropic.d.ts.map +1 -1
  9. package/dist/ingest/providers/anthropic.js +110 -1
  10. package/dist/ingest/providers/anthropic.js.map +1 -1
  11. package/dist/ingest/providers/bedrock.d.ts +2 -5
  12. package/dist/ingest/providers/bedrock.d.ts.map +1 -1
  13. package/dist/ingest/providers/bedrock.js +110 -6
  14. package/dist/ingest/providers/bedrock.js.map +1 -1
  15. package/dist/ingest/providers/gemini.d.ts +2 -0
  16. package/dist/ingest/providers/gemini.d.ts.map +1 -1
  17. package/dist/ingest/providers/gemini.js +106 -1
  18. package/dist/ingest/providers/gemini.js.map +1 -1
  19. package/dist/ingest/providers/index.d.ts +9 -0
  20. package/dist/ingest/providers/index.d.ts.map +1 -1
  21. package/dist/ingest/providers/index.js +66 -4
  22. package/dist/ingest/providers/index.js.map +1 -1
  23. package/dist/ingest/providers/openai.d.ts +2 -0
  24. package/dist/ingest/providers/openai.d.ts.map +1 -1
  25. package/dist/ingest/providers/openai.js +112 -1
  26. package/dist/ingest/providers/openai.js.map +1 -1
  27. package/dist/ingest/task-processor.d.ts +63 -0
  28. package/dist/ingest/task-processor.d.ts.map +1 -0
  29. package/dist/ingest/task-processor.js +339 -0
  30. package/dist/ingest/task-processor.js.map +1 -0
  31. package/dist/ingest/worker.d.ts +1 -1
  32. package/dist/ingest/worker.d.ts.map +1 -1
  33. package/dist/ingest/worker.js +18 -13
  34. package/dist/ingest/worker.js.map +1 -1
  35. package/dist/recall/engine.d.ts +1 -0
  36. package/dist/recall/engine.d.ts.map +1 -1
  37. package/dist/recall/engine.js +21 -11
  38. package/dist/recall/engine.js.map +1 -1
  39. package/dist/recall/mmr.d.ts.map +1 -1
  40. package/dist/recall/mmr.js +3 -1
  41. package/dist/recall/mmr.js.map +1 -1
  42. package/dist/storage/sqlite.d.ts +67 -1
  43. package/dist/storage/sqlite.d.ts.map +1 -1
  44. package/dist/storage/sqlite.js +251 -5
  45. package/dist/storage/sqlite.js.map +1 -1
  46. package/dist/types.d.ts +15 -0
  47. package/dist/types.d.ts.map +1 -1
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +1 -1
  50. package/dist/viewer/html.d.ts +1 -1
  51. package/dist/viewer/html.d.ts.map +1 -1
  52. package/dist/viewer/html.js +955 -115
  53. package/dist/viewer/html.js.map +1 -1
  54. package/dist/viewer/server.d.ts +3 -0
  55. package/dist/viewer/server.d.ts.map +1 -1
  56. package/dist/viewer/server.js +59 -1
  57. package/dist/viewer/server.js.map +1 -1
  58. package/index.ts +221 -45
  59. package/openclaw.plugin.json +20 -45
  60. package/package.json +3 -4
  61. package/skill/SKILL.md +59 -0
  62. package/src/capture/index.ts +85 -45
  63. package/src/ingest/providers/anthropic.ts +128 -1
  64. package/src/ingest/providers/bedrock.ts +130 -6
  65. package/src/ingest/providers/gemini.ts +128 -1
  66. package/src/ingest/providers/index.ts +74 -8
  67. package/src/ingest/providers/openai.ts +130 -1
  68. package/src/ingest/task-processor.ts +380 -0
  69. package/src/ingest/worker.ts +21 -15
  70. package/src/recall/engine.ts +22 -12
  71. package/src/recall/mmr.ts +3 -1
  72. package/src/storage/sqlite.ts +298 -5
  73. package/src/types.ts +19 -0
  74. package/src/viewer/html.ts +955 -115
  75. package/src/viewer/server.ts +63 -1
  76. package/SKILL.md +0 -43
  77. package/www/index.html +0 -606
@@ -155,7 +155,10 @@ export class ViewerServer {
155
155
 
156
156
  if (p === "/api/memories" && req.method === "GET") this.serveMemories(res, url);
157
157
  else if (p === "/api/stats") this.serveStats(res);
158
+ else if (p === "/api/metrics") this.serveMetrics(res, url);
158
159
  else if (p === "/api/search") this.serveSearch(req, res, url);
160
+ else if (p === "/api/tasks" && req.method === "GET") this.serveTasks(res, url);
161
+ else if (p.startsWith("/api/task/") && req.method === "GET") this.serveTaskDetail(res, p);
159
162
  else if (p === "/api/memory" && req.method === "POST") this.handleCreate(req, res);
160
163
  else if (p.startsWith("/api/memory/") && req.method === "PUT") this.handleUpdate(req, res, p);
161
164
  else if (p.startsWith("/api/memory/") && req.method === "DELETE") this.handleDelete(res, p);
@@ -302,12 +305,70 @@ export class ViewerServer {
302
305
  const totalRow = db.prepare("SELECT COUNT(*) as count FROM chunks" + where).get(...params) as any;
303
306
  const memories = db.prepare("SELECT * FROM chunks" + where + ` ORDER BY created_at ${sortBy} LIMIT ? OFFSET ?`).all(...params, limit, offset);
304
307
 
308
+ this.store.recordViewerEvent("list");
305
309
  this.jsonResponse(res, {
306
310
  memories, page, limit, total: totalRow.count,
307
311
  totalPages: Math.ceil(totalRow.count / limit),
308
312
  });
309
313
  }
310
314
 
315
+ private serveMetrics(res: http.ServerResponse, url: URL): void {
316
+ const days = Math.min(90, Math.max(7, Number(url.searchParams.get("days")) || 30));
317
+ const data = this.store.getMetrics(days);
318
+ this.jsonResponse(res, data);
319
+ }
320
+
321
+ private serveTasks(res: http.ServerResponse, url: URL): void {
322
+ this.store.recordViewerEvent("tasks_list");
323
+ const status = url.searchParams.get("status") ?? undefined;
324
+ const limit = Math.min(100, Math.max(1, Number(url.searchParams.get("limit")) || 50));
325
+ const offset = Math.max(0, Number(url.searchParams.get("offset")) || 0);
326
+ const { tasks, total } = this.store.listTasks({ status, limit, offset });
327
+
328
+ const items = tasks.map((t) => ({
329
+ id: t.id,
330
+ sessionKey: t.sessionKey,
331
+ title: t.title,
332
+ summary: t.summary ? (t.summary.length > 300 ? t.summary.slice(0, 297) + "..." : t.summary) : "",
333
+ status: t.status,
334
+ startedAt: t.startedAt,
335
+ endedAt: t.endedAt,
336
+ chunkCount: this.store.countChunksByTask(t.id),
337
+ }));
338
+
339
+ this.jsonResponse(res, { tasks: items, total, limit, offset });
340
+ }
341
+
342
+ private serveTaskDetail(res: http.ServerResponse, urlPath: string): void {
343
+ const taskId = urlPath.replace("/api/task/", "");
344
+ const task = this.store.getTask(taskId);
345
+ if (!task) {
346
+ res.writeHead(404, { "Content-Type": "application/json" });
347
+ res.end(JSON.stringify({ error: "Task not found" }));
348
+ return;
349
+ }
350
+
351
+ const chunks = this.store.getChunksByTask(taskId);
352
+ const chunkItems = chunks.map((c) => ({
353
+ id: c.id,
354
+ role: c.role,
355
+ content: c.content.length > 500 ? c.content.slice(0, 497) + "..." : c.content,
356
+ summary: c.summary,
357
+ createdAt: c.createdAt,
358
+ }));
359
+
360
+ this.jsonResponse(res, {
361
+ id: task.id,
362
+ sessionKey: task.sessionKey,
363
+ title: task.title,
364
+ summary: task.summary,
365
+ status: task.status,
366
+ startedAt: task.startedAt,
367
+ endedAt: task.endedAt,
368
+ chunks: chunkItems,
369
+ });
370
+ }
371
+
311
372
  private serveStats(res: http.ServerResponse): void {
312
373
  const db = (this.store as any).db;
313
374
  const total = db.prepare("SELECT COUNT(*) as count FROM chunks").get() as any;
@@ -385,6 +446,7 @@ export class ViewerServer {
385
446
  if (!seenIds.has(r.id)) { seenIds.add(r.id); merged.push(r); }
386
447
  }
387
448
 
449
+ this.store.recordViewerEvent("search");
388
450
  this.jsonResponse(res, {
389
451
  results: merged,
390
452
  query: q,
@@ -407,7 +469,7 @@ export class ViewerServer {
407
469
  id, sessionKey: data.session_key || "manual", turnId: `manual-${now}`, seq: 0,
408
470
  role: data.role || "user", content: data.content || "", kind: data.kind || "paragraph",
409
471
  summary: data.summary || data.content?.slice(0, 100) || "",
410
- createdAt: now, updatedAt: now, embedding: null,
472
+ taskId: null, createdAt: now, updatedAt: now, embedding: null,
411
473
  });
412
474
  this.jsonResponse(res, { ok: true, id, message: "Memory created" });
413
475
  } catch (err) {
package/SKILL.md DELETED
@@ -1,43 +0,0 @@
1
- # Memory Recall Skill — memos-local
2
-
3
- You have access to long-term conversation memory through three tools:
4
- `memory_search`, `memory_timeline`, `memory_get`.
5
-
6
- ## When to Search
7
-
8
- - **DO search** when the user asks about a previous conversation, a specific detail (command, error, parameter, decision) you don't have in the current context, or when the topic clearly references past interactions.
9
- - **DO NOT search** when the current context already contains enough information to answer accurately.
10
-
11
- ## Progressive Recall Chain
12
-
13
- Follow this 3-step chain. Stop as soon as you have sufficient evidence.
14
-
15
- ### Step 1 — `memory_search`
16
-
17
- Start with the default call (no extra parameters → top 6 results, minScore 0.45).
18
-
19
- - If results are insufficient, **refine the query first** (add entity names, exact commands, error keywords).
20
- - If still insufficient, increase `maxResults` to 12, then 20.
21
- - As a last resort, lower `minScore` to 0.35.
22
- - **Never repeat the exact same query with the same parameters** — vary query wording or adjust parameters.
23
-
24
- ### Step 2 — `memory_timeline`
25
-
26
- When a search hit looks relevant but the `original_excerpt` is too short to confirm, call `memory_timeline` with the hit's `ref` to get surrounding context (±2 turns by default).
27
-
28
- ### Step 3 — `memory_get`
29
-
30
- When you need the exact original text (to verify a command, a code snippet, an error stack), call `memory_get` with the `ref` and request up to 2000 characters (max 8000).
31
-
32
- ## How to Answer
33
-
34
- 1. **Evidence-based**: Only state facts backed by `original_excerpt`, timeline entries, or `memory_get` content. Do not fabricate details.
35
- 2. **Cite sources**: When referencing a memory, mention the approximate time and context (e.g., "In our conversation about deploying the API…").
36
- 3. **Acknowledge gaps**: If memory search returns no relevant results, say so honestly rather than guessing.
37
-
38
- ## Anti-Patterns to Avoid
39
-
40
- - Searching on every single turn (only search when needed).
41
- - Repeating the same failed query without modification.
42
- - Ignoring `original_excerpt` and only using `summary` — the excerpt is the primary evidence.
43
- - Making claims based solely on `summary` without checking the original text when details matter.