@psiclawops/hypermem-memory 0.9.3 → 0.9.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.
- package/dist/index.js +192 -0
- package/openclaw.plugin.json +199 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ import { definePluginEntry, emptyPluginConfigSchema } from 'openclaw/plugin-sdk/
|
|
|
18
18
|
import { matchTriggers, TRIGGER_REGISTRY } from '@psiclawops/hypermem';
|
|
19
19
|
import path from 'path';
|
|
20
20
|
import fs from 'fs/promises';
|
|
21
|
+
import fsSync from 'fs';
|
|
21
22
|
import os from 'os';
|
|
22
23
|
import { fileURLToPath } from 'url';
|
|
23
24
|
// ─── HyperMem singleton ────────────────────────────────────────
|
|
@@ -283,6 +284,196 @@ function createMemorySearchManager(hm, agentId, workspaceDir) {
|
|
|
283
284
|
},
|
|
284
285
|
};
|
|
285
286
|
}
|
|
287
|
+
// ─── history.query agent tool ───────────────────────────────────
|
|
288
|
+
const HISTORY_QUERY_MODES = [
|
|
289
|
+
'runtime_chain',
|
|
290
|
+
'transcript_tail',
|
|
291
|
+
'tool_events',
|
|
292
|
+
'by_topic',
|
|
293
|
+
'by_context',
|
|
294
|
+
'cross_session',
|
|
295
|
+
];
|
|
296
|
+
const HISTORY_QUERY_TOOL_PARAMETERS = {
|
|
297
|
+
type: 'object',
|
|
298
|
+
additionalProperties: false,
|
|
299
|
+
properties: {
|
|
300
|
+
mode: {
|
|
301
|
+
type: 'string',
|
|
302
|
+
enum: HISTORY_QUERY_MODES,
|
|
303
|
+
description: 'History query mode. cross_session is scoped to the current agent by default.',
|
|
304
|
+
},
|
|
305
|
+
sessionKey: {
|
|
306
|
+
type: 'string',
|
|
307
|
+
description: 'Optional session key. Defaults to the active session when available.',
|
|
308
|
+
},
|
|
309
|
+
conversationId: {
|
|
310
|
+
type: 'number',
|
|
311
|
+
description: 'Optional direct conversation id. Must belong to the current agent.',
|
|
312
|
+
},
|
|
313
|
+
contextId: {
|
|
314
|
+
type: 'number',
|
|
315
|
+
description: 'Required for by_context mode. Must belong to the current agent.',
|
|
316
|
+
},
|
|
317
|
+
topicId: {
|
|
318
|
+
type: 'string',
|
|
319
|
+
description: 'Required for by_topic mode.',
|
|
320
|
+
},
|
|
321
|
+
limit: {
|
|
322
|
+
type: 'number',
|
|
323
|
+
description: 'Optional result limit. HyperMem clamps this to the hard cap for the selected mode.',
|
|
324
|
+
},
|
|
325
|
+
minMessageId: {
|
|
326
|
+
type: 'number',
|
|
327
|
+
description: 'Optional lower message id bound for supported modes.',
|
|
328
|
+
},
|
|
329
|
+
since: {
|
|
330
|
+
type: 'string',
|
|
331
|
+
description: 'Optional ISO timestamp lower bound for cross_session mode.',
|
|
332
|
+
},
|
|
333
|
+
includeArchived: {
|
|
334
|
+
type: 'boolean',
|
|
335
|
+
description: 'Allow archived/forked contexts for by_context mode.',
|
|
336
|
+
},
|
|
337
|
+
includeToolPayloads: {
|
|
338
|
+
type: 'boolean',
|
|
339
|
+
description: 'Return raw tool payloads for tool_events. Requires owner context; default is redacted.',
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
required: ['mode'],
|
|
343
|
+
};
|
|
344
|
+
function asRecord(value) {
|
|
345
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
346
|
+
? value
|
|
347
|
+
: {};
|
|
348
|
+
}
|
|
349
|
+
function optionalString(params, key) {
|
|
350
|
+
const value = params[key];
|
|
351
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
352
|
+
}
|
|
353
|
+
function optionalNumber(params, key) {
|
|
354
|
+
const value = params[key];
|
|
355
|
+
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
356
|
+
return undefined;
|
|
357
|
+
return value;
|
|
358
|
+
}
|
|
359
|
+
function optionalBoolean(params, key) {
|
|
360
|
+
return typeof params[key] === 'boolean' ? params[key] : undefined;
|
|
361
|
+
}
|
|
362
|
+
function isHistoryQueryMode(value) {
|
|
363
|
+
return typeof value === 'string' && HISTORY_QUERY_MODES.includes(value);
|
|
364
|
+
}
|
|
365
|
+
function historyQueryTelemetryEnabled() {
|
|
366
|
+
return process.env.HYPERMEM_TELEMETRY === '1';
|
|
367
|
+
}
|
|
368
|
+
function emitHistoryQueryTelemetry(event) {
|
|
369
|
+
if (!historyQueryTelemetryEnabled())
|
|
370
|
+
return;
|
|
371
|
+
const telemetryPath = process.env.HYPERMEM_TELEMETRY_PATH || './hypermem-telemetry.jsonl';
|
|
372
|
+
try {
|
|
373
|
+
fsSync.appendFileSync(telemetryPath, `${JSON.stringify(event)}\n`, 'utf8');
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// Telemetry must never break the tool path.
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function createHistoryQueryTool(ctx) {
|
|
380
|
+
return {
|
|
381
|
+
name: 'history_query',
|
|
382
|
+
label: 'history.query',
|
|
383
|
+
description: [
|
|
384
|
+
'Query HyperMem SQLite-backed message history for the current agent.',
|
|
385
|
+
'Use this when exact conversation state is needed instead of semantic recall.',
|
|
386
|
+
'Modes: runtime_chain, transcript_tail, tool_events, by_topic, by_context, cross_session.',
|
|
387
|
+
'Tool payloads are redacted by default; raw payloads require owner context.',
|
|
388
|
+
].join(' '),
|
|
389
|
+
parameters: HISTORY_QUERY_TOOL_PARAMETERS,
|
|
390
|
+
displaySummary: 'Query HyperMem message history',
|
|
391
|
+
async execute(_toolCallId, rawParams) {
|
|
392
|
+
const started = Date.now();
|
|
393
|
+
const params = asRecord(rawParams);
|
|
394
|
+
const mode = params.mode;
|
|
395
|
+
const agentId = ctx.agentId || 'main';
|
|
396
|
+
const includeToolPayloads = optionalBoolean(params, 'includeToolPayloads') === true;
|
|
397
|
+
const baseTelemetry = {
|
|
398
|
+
ts: new Date().toISOString(),
|
|
399
|
+
agentId,
|
|
400
|
+
hasSessionKey: Boolean(optionalString(params, 'sessionKey') ?? ctx.sessionKey),
|
|
401
|
+
hasConversationId: optionalNumber(params, 'conversationId') !== undefined,
|
|
402
|
+
includeToolPayloads,
|
|
403
|
+
};
|
|
404
|
+
if (!isHistoryQueryMode(mode)) {
|
|
405
|
+
emitHistoryQueryTelemetry({
|
|
406
|
+
event: 'history-query',
|
|
407
|
+
status: 'error',
|
|
408
|
+
...baseTelemetry,
|
|
409
|
+
durationMs: Date.now() - started,
|
|
410
|
+
errorCode: 'invalid-mode',
|
|
411
|
+
});
|
|
412
|
+
throw new Error(`history.query: mode must be one of ${HISTORY_QUERY_MODES.join(', ')}`);
|
|
413
|
+
}
|
|
414
|
+
if (includeToolPayloads && !ctx.senderIsOwner) {
|
|
415
|
+
emitHistoryQueryTelemetry({
|
|
416
|
+
event: 'history-query',
|
|
417
|
+
status: 'error',
|
|
418
|
+
mode,
|
|
419
|
+
...baseTelemetry,
|
|
420
|
+
durationMs: Date.now() - started,
|
|
421
|
+
errorCode: 'owner-required',
|
|
422
|
+
});
|
|
423
|
+
throw new Error('history.query: includeToolPayloads requires owner context');
|
|
424
|
+
}
|
|
425
|
+
const query = {
|
|
426
|
+
agentId,
|
|
427
|
+
mode,
|
|
428
|
+
sessionKey: optionalString(params, 'sessionKey') ?? ctx.sessionKey,
|
|
429
|
+
conversationId: optionalNumber(params, 'conversationId'),
|
|
430
|
+
contextId: optionalNumber(params, 'contextId'),
|
|
431
|
+
topicId: optionalString(params, 'topicId'),
|
|
432
|
+
limit: optionalNumber(params, 'limit'),
|
|
433
|
+
minMessageId: optionalNumber(params, 'minMessageId'),
|
|
434
|
+
since: optionalString(params, 'since'),
|
|
435
|
+
includeArchived: optionalBoolean(params, 'includeArchived'),
|
|
436
|
+
includeToolPayloads,
|
|
437
|
+
};
|
|
438
|
+
for (const [key, value] of Object.entries(query)) {
|
|
439
|
+
if (value === undefined)
|
|
440
|
+
delete query[key];
|
|
441
|
+
}
|
|
442
|
+
try {
|
|
443
|
+
const hm = await getHyperMem();
|
|
444
|
+
const result = hm.queryHistory(query);
|
|
445
|
+
emitHistoryQueryTelemetry({
|
|
446
|
+
event: 'history-query',
|
|
447
|
+
status: 'ok',
|
|
448
|
+
mode,
|
|
449
|
+
...baseTelemetry,
|
|
450
|
+
messageCount: result.messages.length,
|
|
451
|
+
truncated: Boolean(result.truncated),
|
|
452
|
+
redacted: Boolean(result.redacted),
|
|
453
|
+
durationMs: Date.now() - started,
|
|
454
|
+
});
|
|
455
|
+
const summary = `history.query ${mode}: ${result.messages.length} message(s)`
|
|
456
|
+
+ (result.truncated ? ' (truncated)' : '')
|
|
457
|
+
+ (result.redacted ? ' (redacted)' : '');
|
|
458
|
+
return {
|
|
459
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
460
|
+
details: { status: 'ok', summary, result },
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
catch (err) {
|
|
464
|
+
emitHistoryQueryTelemetry({
|
|
465
|
+
event: 'history-query',
|
|
466
|
+
status: 'error',
|
|
467
|
+
mode,
|
|
468
|
+
...baseTelemetry,
|
|
469
|
+
durationMs: Date.now() - started,
|
|
470
|
+
errorCode: 'query-failed',
|
|
471
|
+
});
|
|
472
|
+
throw err;
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
};
|
|
476
|
+
}
|
|
286
477
|
// ─── Manager cache ──────────────────────────────────────────────
|
|
287
478
|
// One manager per agentId; closed on plugin dispose.
|
|
288
479
|
const _managers = new Map();
|
|
@@ -294,6 +485,7 @@ export default definePluginEntry({
|
|
|
294
485
|
kind: 'memory',
|
|
295
486
|
configSchema: emptyPluginConfigSchema(),
|
|
296
487
|
register(api) {
|
|
488
|
+
api.registerTool((ctx) => createHistoryQueryTool(ctx), { name: 'history_query', optional: true });
|
|
297
489
|
api.registerMemoryCapability({
|
|
298
490
|
runtime: {
|
|
299
491
|
async getMemorySearchManager(params) {
|
package/openclaw.plugin.json
CHANGED
|
@@ -3,11 +3,208 @@
|
|
|
3
3
|
"enabledByDefault": false,
|
|
4
4
|
"kind": "memory",
|
|
5
5
|
"activation": {
|
|
6
|
-
"onCapabilities": [
|
|
6
|
+
"onCapabilities": [
|
|
7
|
+
"memory"
|
|
8
|
+
]
|
|
7
9
|
},
|
|
8
10
|
"configSchema": {
|
|
9
11
|
"type": "object",
|
|
10
12
|
"additionalProperties": false,
|
|
11
|
-
"properties": {
|
|
13
|
+
"properties": {
|
|
14
|
+
"hyperMemPath": {
|
|
15
|
+
"type": "string"
|
|
16
|
+
},
|
|
17
|
+
"dataDir": {
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"contextWindowSize": {
|
|
21
|
+
"type": "integer",
|
|
22
|
+
"minimum": 1
|
|
23
|
+
},
|
|
24
|
+
"contextWindowReserve": {
|
|
25
|
+
"type": "number",
|
|
26
|
+
"minimum": 0,
|
|
27
|
+
"maximum": 0.5
|
|
28
|
+
},
|
|
29
|
+
"deferToolPruning": {
|
|
30
|
+
"type": "boolean"
|
|
31
|
+
},
|
|
32
|
+
"verboseLogging": {
|
|
33
|
+
"type": "boolean"
|
|
34
|
+
},
|
|
35
|
+
"warmCacheReplayThresholdMs": {
|
|
36
|
+
"type": "integer",
|
|
37
|
+
"minimum": 0
|
|
38
|
+
},
|
|
39
|
+
"subagentWarming": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"enum": [
|
|
42
|
+
"full",
|
|
43
|
+
"light",
|
|
44
|
+
"off"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"contextWindowOverrides": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"additionalProperties": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"additionalProperties": false,
|
|
52
|
+
"properties": {
|
|
53
|
+
"contextTokens": {
|
|
54
|
+
"type": "integer",
|
|
55
|
+
"minimum": 1
|
|
56
|
+
},
|
|
57
|
+
"contextWindow": {
|
|
58
|
+
"type": "integer",
|
|
59
|
+
"minimum": 1
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"compositor": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"additionalProperties": true
|
|
67
|
+
},
|
|
68
|
+
"eviction": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"additionalProperties": false,
|
|
71
|
+
"properties": {
|
|
72
|
+
"enabled": {
|
|
73
|
+
"type": "boolean"
|
|
74
|
+
},
|
|
75
|
+
"imageAgeTurns": {
|
|
76
|
+
"type": "integer",
|
|
77
|
+
"minimum": 0
|
|
78
|
+
},
|
|
79
|
+
"toolResultAgeTurns": {
|
|
80
|
+
"type": "integer",
|
|
81
|
+
"minimum": 0
|
|
82
|
+
},
|
|
83
|
+
"minTokensToEvict": {
|
|
84
|
+
"type": "integer",
|
|
85
|
+
"minimum": 0
|
|
86
|
+
},
|
|
87
|
+
"keepPreviewChars": {
|
|
88
|
+
"type": "integer",
|
|
89
|
+
"minimum": 0
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"embedding": {
|
|
94
|
+
"type": "object",
|
|
95
|
+
"additionalProperties": false,
|
|
96
|
+
"properties": {
|
|
97
|
+
"provider": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"enum": [
|
|
100
|
+
"none",
|
|
101
|
+
"ollama",
|
|
102
|
+
"openai",
|
|
103
|
+
"gemini"
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
"ollamaUrl": {
|
|
107
|
+
"type": "string"
|
|
108
|
+
},
|
|
109
|
+
"openaiApiKey": {
|
|
110
|
+
"type": "string"
|
|
111
|
+
},
|
|
112
|
+
"openaiBaseUrl": {
|
|
113
|
+
"type": "string"
|
|
114
|
+
},
|
|
115
|
+
"geminiApiKey": {
|
|
116
|
+
"type": "string"
|
|
117
|
+
},
|
|
118
|
+
"geminiBaseUrl": {
|
|
119
|
+
"type": "string"
|
|
120
|
+
},
|
|
121
|
+
"geminiIndexTaskType": {
|
|
122
|
+
"type": "string"
|
|
123
|
+
},
|
|
124
|
+
"geminiQueryTaskType": {
|
|
125
|
+
"type": "string"
|
|
126
|
+
},
|
|
127
|
+
"queryInputType": {
|
|
128
|
+
"type": "string"
|
|
129
|
+
},
|
|
130
|
+
"documentInputType": {
|
|
131
|
+
"type": "string"
|
|
132
|
+
},
|
|
133
|
+
"queryPrefix": {
|
|
134
|
+
"type": "string"
|
|
135
|
+
},
|
|
136
|
+
"documentPrefix": {
|
|
137
|
+
"type": "string"
|
|
138
|
+
},
|
|
139
|
+
"model": {
|
|
140
|
+
"type": "string"
|
|
141
|
+
},
|
|
142
|
+
"dimensions": {
|
|
143
|
+
"type": "integer",
|
|
144
|
+
"minimum": 1
|
|
145
|
+
},
|
|
146
|
+
"timeout": {
|
|
147
|
+
"type": "integer",
|
|
148
|
+
"minimum": 1
|
|
149
|
+
},
|
|
150
|
+
"batchSize": {
|
|
151
|
+
"type": "integer",
|
|
152
|
+
"minimum": 1
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"reranker": {
|
|
157
|
+
"type": "object",
|
|
158
|
+
"additionalProperties": false,
|
|
159
|
+
"required": [
|
|
160
|
+
"provider"
|
|
161
|
+
],
|
|
162
|
+
"properties": {
|
|
163
|
+
"provider": {
|
|
164
|
+
"type": "string",
|
|
165
|
+
"enum": [
|
|
166
|
+
"zeroentropy",
|
|
167
|
+
"openrouter",
|
|
168
|
+
"local",
|
|
169
|
+
"none"
|
|
170
|
+
]
|
|
171
|
+
},
|
|
172
|
+
"minCandidates": {
|
|
173
|
+
"type": "integer",
|
|
174
|
+
"minimum": 0
|
|
175
|
+
},
|
|
176
|
+
"maxDocuments": {
|
|
177
|
+
"type": "integer",
|
|
178
|
+
"minimum": 1
|
|
179
|
+
},
|
|
180
|
+
"topK": {
|
|
181
|
+
"type": "integer",
|
|
182
|
+
"minimum": 1
|
|
183
|
+
},
|
|
184
|
+
"timeoutMs": {
|
|
185
|
+
"type": "integer",
|
|
186
|
+
"minimum": 1
|
|
187
|
+
},
|
|
188
|
+
"zeroEntropyApiKey": {
|
|
189
|
+
"type": "string"
|
|
190
|
+
},
|
|
191
|
+
"zeroEntropyModel": {
|
|
192
|
+
"type": "string"
|
|
193
|
+
},
|
|
194
|
+
"openrouterApiKey": {
|
|
195
|
+
"type": "string"
|
|
196
|
+
},
|
|
197
|
+
"openrouterModel": {
|
|
198
|
+
"type": "string"
|
|
199
|
+
},
|
|
200
|
+
"ollamaUrl": {
|
|
201
|
+
"type": "string"
|
|
202
|
+
},
|
|
203
|
+
"ollamaModel": {
|
|
204
|
+
"type": "string"
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
12
209
|
}
|
|
13
210
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@psiclawops/hypermem-memory",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.4",
|
|
4
4
|
"description": "HyperMem memory plugin for OpenClaw \u2014 bridges HyperMem retrieval into the memory slot",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"typecheck": "tsc --noEmit"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@psiclawops/hypermem": "0.9.
|
|
43
|
+
"@psiclawops/hypermem": "^0.9.4"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"openclaw": "*",
|