@pentatonic-ai/openclaw-memory-plugin 0.4.8 → 0.4.9

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/index.js CHANGED
@@ -237,110 +237,99 @@ export default {
237
237
  id: "pentatonic-memory",
238
238
  name: "Pentatonic Memory",
239
239
  description: "Persistent, searchable memory with multi-signal retrieval and HyDE query expansion",
240
+ kind: "context-engine",
240
241
 
241
242
  register(api) {
242
243
  const config = api.config || {};
243
244
  const hosted = !!(config.tes_endpoint && config.tes_api_key);
244
245
  const baseUrl = config.memory_url || "http://localhost:3333";
246
+ const searchLimit = config.search_limit || 5;
247
+ const minScore = config.min_score || 0.3;
245
248
  const log = (msg) => process.stderr.write(`[pentatonic-memory] ${msg}\n`);
246
249
 
247
- // --- Always register tools ---
248
-
249
- if (hosted) {
250
- // Hosted mode tools
251
- log("Hosted mode — routing through TES");
252
-
253
- api.registerTool({
254
- name: "memory_search",
255
- description: "Search memories for relevant context. Use when you need to recall past conversations, decisions, or knowledge.",
256
- parameters: {
257
- type: "object",
258
- properties: {
259
- query: { type: "string", description: "What to search for" },
260
- limit: { type: "number", description: "Max results (default 5)" },
261
- },
262
- required: ["query"],
263
- },
264
- async execute({ query, limit }) {
265
- return formatResults(await hostedSearch(config, query, limit || 5, 0.3));
266
- },
267
- });
268
-
269
- api.registerTool({
270
- name: "memory_store",
271
- description: "Explicitly store something important. Use for decisions, solutions, or facts worth remembering.",
272
- parameters: {
273
- type: "object",
274
- properties: { content: { type: "string", description: "What to remember" } },
275
- required: ["content"],
276
- },
277
- async execute({ content }) {
278
- const result = await hostedStore(config, content, { source: "openclaw-tool" });
279
- return result ? "Memory stored." : "Failed to store memory.";
280
- },
281
- });
282
-
283
- // Register context engine for hosted
284
- api.registerContextEngine("pentatonic-memory", () =>
285
- createHostedContextEngine(config, {
286
- searchLimit: config.search_limit || 5,
287
- minScore: config.min_score || 0.3,
288
- logger: log,
289
- })
290
- );
291
-
292
- log("Plugin registered (hosted)");
293
- } else {
294
- // Local mode tools — always point at baseUrl
295
- log(`Local mode — ${baseUrl}`);
296
-
297
- api.registerTool({
298
- name: "memory_search",
299
- description: "Search memories for relevant context. Use when you need to recall past conversations, decisions, or knowledge.",
300
- parameters: {
301
- type: "object",
302
- properties: {
303
- query: { type: "string", description: "What to search for" },
304
- limit: { type: "number", description: "Max results (default 5)" },
305
- },
306
- required: ["query"],
307
- },
308
- async execute({ query, limit }) {
309
- return formatResults(await localSearch(baseUrl, query, limit || 5, 0.3));
310
- },
311
- });
312
-
313
- api.registerTool({
314
- name: "memory_store",
315
- description: "Explicitly store something important. Use for decisions, solutions, or facts worth remembering.",
316
- parameters: {
317
- type: "object",
318
- properties: { content: { type: "string", description: "What to remember" } },
319
- required: ["content"],
320
- },
321
- async execute({ content }) {
322
- const result = await localStore(baseUrl, content, { source: "openclaw-tool" });
323
- return result ? `Stored: ${result.id}` : "Failed to store memory.";
324
- },
325
- });
326
-
327
- // Auto-detect: check if local memory server is running, register context engine if so
328
- localHealth(baseUrl).then((ok) => {
329
- if (ok) {
330
- api.registerContextEngine("pentatonic-memory", () =>
331
- createLocalContextEngine(baseUrl, {
332
- searchLimit: config.search_limit || 5,
333
- minScore: config.min_score || 0.3,
334
- logger: log,
335
- })
336
- );
337
- log("Memory server detected — context engine registered");
338
- } else {
339
- log(`Memory server not reachable at ${baseUrl} — tools available, no auto-ingest/assemble`);
250
+ // Unified search/store that routes to local or hosted
251
+ const search = hosted
252
+ ? (query, limit, score) => hostedSearch(config, query, limit, score)
253
+ : (query, limit, score) => localSearch(baseUrl, query, limit, score);
254
+
255
+ const store = hosted
256
+ ? (content, metadata) => hostedStore(config, content, metadata)
257
+ : (content, metadata) => localStore(baseUrl, content, metadata);
258
+
259
+ // --- Context engine: always registered, proxies to backend ---
260
+ // Methods return graceful empty results if backend is unavailable.
261
+
262
+ api.registerContextEngine("pentatonic-memory", () => ({
263
+ info: {
264
+ id: "pentatonic-memory",
265
+ name: `Pentatonic Memory (${hosted ? "Hosted" : "Local"})`,
266
+ ownsCompaction: false,
267
+ },
268
+
269
+ async ingest({ sessionId, message }) {
270
+ if (!message?.content) return { ingested: false };
271
+ const role = message.role || message.type;
272
+ if (role !== "user" && role !== "assistant") return { ingested: false };
273
+ try {
274
+ await store(message.content, { session_id: sessionId, role });
275
+ return { ingested: true };
276
+ } catch {
277
+ return { ingested: false };
278
+ }
279
+ },
280
+
281
+ async assemble({ sessionId, messages }) {
282
+ const lastUserMsg = [...messages].reverse().find((m) => m.role === "user" || m.type === "user");
283
+ if (!lastUserMsg?.content) return { messages, estimatedTokens: 0 };
284
+ try {
285
+ const results = await search(lastUserMsg.content, searchLimit, minScore);
286
+ if (!results.length) return { messages, estimatedTokens: 0 };
287
+ const memoryText = results
288
+ .map((m) => `- [${Math.round((m.similarity || 0) * 100)}%] ${m.content}`)
289
+ .join("\n");
290
+ const addition = `[Memory] Relevant context from past conversations:\n${memoryText}`;
291
+ return { messages, estimatedTokens: Math.ceil(addition.length / 4), systemPromptAddition: addition };
292
+ } catch {
293
+ return { messages, estimatedTokens: 0 };
340
294
  }
341
- });
295
+ },
296
+
297
+ async compact() { return { ok: true, compacted: false }; },
298
+ async afterTurn() {},
299
+ }));
300
+
301
+ // --- Tools: agent-driven search and store ---
302
+
303
+ api.registerTool({
304
+ name: "memory_search",
305
+ description: "Search memories for relevant context. Use when you need to recall past conversations, decisions, or knowledge.",
306
+ parameters: {
307
+ type: "object",
308
+ properties: {
309
+ query: { type: "string", description: "What to search for" },
310
+ limit: { type: "number", description: "Max results (default 5)" },
311
+ },
312
+ required: ["query"],
313
+ },
314
+ async execute({ query, limit }) {
315
+ return formatResults(await search(query, limit || 5, 0.3));
316
+ },
317
+ });
318
+
319
+ api.registerTool({
320
+ name: "memory_store",
321
+ description: "Explicitly store something important. Use for decisions, solutions, or facts worth remembering.",
322
+ parameters: {
323
+ type: "object",
324
+ properties: { content: { type: "string", description: "What to remember" } },
325
+ required: ["content"],
326
+ },
327
+ async execute({ content }) {
328
+ const result = await store(content, { source: "openclaw-tool" });
329
+ return result ? "Memory stored." : "Failed to store memory.";
330
+ },
331
+ });
342
332
 
343
- log("Plugin registered (local)");
344
- }
333
+ log(`Plugin registered (${hosted ? "hosted" : "local"} — ${hosted ? config.tes_endpoint : baseUrl})`);
345
334
  },
346
335
  };
@@ -3,7 +3,7 @@
3
3
  "name": "Pentatonic Memory",
4
4
  "description": "Persistent, searchable memory with multi-signal retrieval and HyDE query expansion. Local (Docker + Ollama) or hosted (Pentatonic TES).",
5
5
  "version": "0.4.4",
6
- "kind": "tool",
6
+ "kind": "context-engine",
7
7
  "configSchema": {
8
8
  "type": "object",
9
9
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pentatonic-ai/openclaw-memory-plugin",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "Pentatonic Memory plugin for OpenClaw — persistent, searchable memory with multi-signal retrieval and HyDE query expansion",
5
5
  "type": "module",
6
6
  "main": "index.js",