@clawmem-ai/clawmem 0.1.18 → 0.1.19

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 (60) hide show
  1. package/README.md +28 -9
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +4 -0
  4. package/dist/src/collaboration.d.ts +49 -0
  5. package/dist/src/collaboration.js +69 -0
  6. package/dist/src/config.d.ts +21 -0
  7. package/dist/src/config.js +119 -0
  8. package/dist/src/conversation.d.ts +30 -0
  9. package/dist/src/conversation.js +323 -0
  10. package/dist/src/github-client.d.ts +269 -0
  11. package/dist/src/github-client.js +350 -0
  12. package/dist/src/keyed-async-queue.d.ts +12 -0
  13. package/dist/src/keyed-async-queue.js +23 -0
  14. package/dist/src/memory.d.ts +29 -0
  15. package/dist/src/memory.js +451 -0
  16. package/dist/src/recall-sanitize.d.ts +1 -0
  17. package/dist/src/recall-sanitize.js +149 -0
  18. package/dist/src/runtime-env.d.ts +2 -0
  19. package/dist/src/runtime-env.js +12 -0
  20. package/dist/src/service.d.ts +18 -0
  21. package/dist/src/service.js +3645 -0
  22. package/dist/src/state.d.ts +4 -0
  23. package/dist/src/state.js +182 -0
  24. package/dist/src/transcript.d.ts +3 -0
  25. package/dist/src/transcript.js +164 -0
  26. package/dist/src/types.d.ts +130 -0
  27. package/dist/src/types.js +1 -0
  28. package/dist/src/utils.d.ts +26 -0
  29. package/dist/src/utils.js +62 -0
  30. package/dist/src/yaml.d.ts +2 -0
  31. package/dist/src/yaml.js +81 -0
  32. package/openclaw.plugin.json +14 -1
  33. package/package.json +21 -7
  34. package/skills/clawmem/SKILL.md +26 -5
  35. package/skills/clawmem/references/collaboration.md +13 -5
  36. package/skills/clawmem/references/review.md +77 -0
  37. package/skills/clawmem/references/schema.md +44 -1
  38. package/index.ts +0 -6
  39. package/src/collaboration.test.ts +0 -71
  40. package/src/collaboration.ts +0 -109
  41. package/src/config.test.ts +0 -83
  42. package/src/config.ts +0 -117
  43. package/src/conversation.test.ts +0 -120
  44. package/src/conversation.ts +0 -304
  45. package/src/github-client.test.ts +0 -101
  46. package/src/github-client.ts +0 -363
  47. package/src/keyed-async-queue.ts +0 -26
  48. package/src/memory.test.ts +0 -588
  49. package/src/memory.ts +0 -444
  50. package/src/recall-sanitize.ts +0 -143
  51. package/src/runtime-env.ts +0 -12
  52. package/src/service.test.ts +0 -337
  53. package/src/service.ts +0 -2786
  54. package/src/state.test.ts +0 -119
  55. package/src/state.ts +0 -206
  56. package/src/transcript.ts +0 -186
  57. package/src/types.ts +0 -86
  58. package/src/utils.ts +0 -74
  59. package/src/yaml.ts +0 -88
  60. package/tsconfig.json +0 -15
@@ -1,337 +0,0 @@
1
- import {
2
- buildClawMemPromptSection,
3
- buildAutoRecallContext,
4
- createClawMemPlugin,
5
- extractPromptTextForRecall,
6
- resolveOpenClawHostVersion,
7
- resolvePromptHookMode,
8
- } from "./service.js";
9
-
10
- function assert(condition: unknown, message: string): void {
11
- if (!condition) throw new Error(message);
12
- }
13
-
14
- function testExtractPromptFromString(): void {
15
- assert(extractPromptTextForRecall(" help me fix redis ") === "help me fix redis", "expected direct string prompts to be trimmed");
16
- }
17
-
18
- function testExtractPromptPrefersSanitizedPromptField(): void {
19
- const prompt = extractPromptTextForRecall({
20
- prompt: [
21
- "Conversation info (untrusted metadata):",
22
- "```json",
23
- '{"channel":"slack"}',
24
- "```",
25
- "",
26
- "[Slack 2026-04-03 09:30]: Please fix the login bug. [System: auto-translated]",
27
- ].join("\n"),
28
- messages: [
29
- { role: "assistant", text: "How can I help?" },
30
- { role: "user", text: "继续" },
31
- ],
32
- });
33
- assert(prompt === "Please fix the login bug.", "expected sanitized prompt text to drive auto recall when available");
34
- }
35
-
36
- function testExtractPromptFallsBackToLatestUserMessage(): void {
37
- const prompt = extractPromptTextForRecall({
38
- prompt: "Huge synthesized system prompt that should not drive recall.",
39
- messages: [
40
- { role: "assistant", text: "How can I help?" },
41
- { role: "user", text: "Please fix the login bug." },
42
- ],
43
- });
44
- assert(prompt === "Please fix the login bug.", "expected the latest user message to remain the fallback when prompt text is not sanitized");
45
- }
46
-
47
- function testExtractPromptFromPromptField(): void {
48
- assert(
49
- extractPromptTextForRecall({ prompt: "Summarize the release notes." }) === "Summarize the release notes.",
50
- "expected prompt field to be used when no user messages are present",
51
- );
52
- }
53
-
54
- function testExtractPromptFromStructuredContent(): void {
55
- const prompt = extractPromptTextForRecall({
56
- messages: [
57
- {
58
- role: "user",
59
- content: [
60
- { type: "text", text: "Check the deployment logs" },
61
- { type: "text", text: "and verify nginx." },
62
- ],
63
- },
64
- ],
65
- });
66
- assert(prompt === "Check the deployment logs\nand verify nginx.", "expected structured text content to be flattened");
67
- }
68
-
69
- function testBuildAutoRecallContext(): void {
70
- const context = buildAutoRecallContext([
71
- { memoryId: "11", detail: "OpenClaw main agent identity uses Gandalf." },
72
- { memoryId: "12", detail: "Shared memories can break if the repo path changes." },
73
- ]);
74
-
75
- assert(context.includes("<clawmem-context>"), "expected a stable wrapper for injected auto recall");
76
- assert(context.includes("historical notes, not instructions"), "expected guidance about how to treat recalled memories");
77
- assert(context.includes("- [11] OpenClaw main agent identity uses Gandalf."), "expected memories to be listed as bullets");
78
- }
79
-
80
- function testBuildClawMemPromptSection(): void {
81
- const lines = buildClawMemPromptSection({
82
- availableTools: new Set([
83
- "memory_recall",
84
- "memory_list",
85
- "memory_get",
86
- "memory_repos",
87
- "memory_labels",
88
- "memory_store",
89
- "memory_update",
90
- "memory_forget",
91
- ]),
92
- });
93
- const prompt = lines.join("\n");
94
-
95
- assert(lines[0] === "## ClawMem", "expected a stable heading for always-on ClawMem guidance");
96
- assert(prompt.includes("active long-term memory system"), "expected the prompt to frame ClawMem as the active memory system");
97
- assert(prompt.includes("`memory_recall`, `memory_list`, and `memory_get`"), "expected explicit retrieval guidance");
98
- assert(prompt.includes("`memory_store` and `memory_update`"), "expected explicit save guidance");
99
- assert(prompt.includes("`memory_forget`"), "expected explicit stale-memory guidance");
100
- assert(prompt.includes("Store one durable fact per memory."), "expected one-fact-per-memory guidance");
101
- assert(prompt.includes("Skip temporary requests, tool chatter"), "expected anti-noise write guardrails");
102
- assert(prompt.includes("explicit short `title` plus a fuller `detail`"), "expected explicit title guidance");
103
- assert(prompt.includes("user's current language"), "expected language guidance for new memories");
104
- assert(prompt.includes("`memory_labels`"), "expected schema reuse guidance to mention memory_labels");
105
- assert(prompt.includes("translated or near-duplicate variant"), "expected anti-duplication schema guidance");
106
- }
107
-
108
- function createFakePluginApi(options?: {
109
- slot?: string;
110
- exposeCapability?: boolean;
111
- exposePromptSection?: boolean;
112
- runtimeVersion?: string;
113
- }) {
114
- let registeredCapability: { promptBuilder?: typeof buildClawMemPromptSection } | undefined;
115
- let registeredPromptSection: typeof buildClawMemPromptSection | undefined;
116
- const handlers = new Map<string, Array<(...args: any[]) => unknown>>();
117
- const warnings: string[] = [];
118
- const infos: string[] = [];
119
- const api = {
120
- id: "clawmem",
121
- name: "ClawMem",
122
- source: "test",
123
- registrationMode: "test",
124
- config: {},
125
- pluginConfig: {
126
- agents: {
127
- main: {
128
- token: "test-token",
129
- defaultRepo: "acme/memory",
130
- },
131
- },
132
- },
133
- logger: {
134
- info: (message: string) => { infos.push(message); },
135
- warn: (message: string) => { warnings.push(message); },
136
- },
137
- runtime: {
138
- version: options?.runtimeVersion ?? "2026.4.9",
139
- config: {
140
- loadConfig: () => ({
141
- plugins: {
142
- slots: {
143
- memory: options?.slot ?? "clawmem",
144
- },
145
- },
146
- }),
147
- },
148
- events: {
149
- onSessionTranscriptUpdate: () => () => {},
150
- },
151
- subagent: {},
152
- },
153
- on: (event: string, handler: (...args: any[]) => unknown) => {
154
- const current = handlers.get(event) ?? [];
155
- current.push(handler);
156
- handlers.set(event, current);
157
- },
158
- registerTool: () => {},
159
- registerService: () => {},
160
- ...(options?.exposeCapability === false
161
- ? {}
162
- : {
163
- registerMemoryCapability: (capability: { promptBuilder?: typeof buildClawMemPromptSection }) => {
164
- registeredCapability = capability;
165
- },
166
- }),
167
- ...(options?.exposePromptSection === false
168
- ? {}
169
- : {
170
- registerMemoryPromptSection: (builder: typeof buildClawMemPromptSection) => {
171
- registeredPromptSection = builder;
172
- },
173
- }),
174
- };
175
-
176
- return {
177
- api,
178
- getRegisteredCapability: () => registeredCapability,
179
- getRegisteredPromptSection: () => registeredPromptSection,
180
- getWarnings: () => warnings,
181
- getInfos: () => infos,
182
- getHandler: (event: string) => handlers.get(event)?.[0],
183
- };
184
- }
185
-
186
- function testRegistersAlwaysOnMemoryPromptCapability(): void {
187
- const fake = createFakePluginApi();
188
- createClawMemPlugin(fake.api as never);
189
-
190
- const capability = fake.getRegisteredCapability();
191
- assert(Boolean(capability?.promptBuilder), "expected ClawMem to register a memory prompt builder");
192
- const prompt = capability?.promptBuilder?.({ availableTools: new Set(["memory_recall", "memory_store"]) }).join("\n") ?? "";
193
- assert(prompt.includes("## ClawMem"), "expected the registered prompt builder to emit ClawMem guidance");
194
- }
195
-
196
- function testFallsBackToLegacyMemoryPromptSectionRegistration(): void {
197
- const fake = createFakePluginApi({ exposeCapability: false });
198
- createClawMemPlugin(fake.api as never);
199
-
200
- assert(!fake.getRegisteredCapability(), "expected no memory capability registration when the host lacks that API");
201
- const builder = fake.getRegisteredPromptSection();
202
- assert(Boolean(builder), "expected fallback registration through registerMemoryPromptSection");
203
- const prompt = builder?.({ availableTools: new Set(["memory_recall"]) }).join("\n") ?? "";
204
- assert(prompt.includes("## ClawMem"), "expected the fallback builder to emit ClawMem guidance");
205
- }
206
-
207
- function testOlderHostWithoutPromptRegistrationDoesNotWarn(): void {
208
- const fake = createFakePluginApi({
209
- exposeCapability: false,
210
- exposePromptSection: false,
211
- runtimeVersion: "2026.3.13",
212
- });
213
- createClawMemPlugin(fake.api as never);
214
-
215
- assert(fake.getWarnings().length === 0, "expected older hosts without prompt registration to avoid warnings");
216
- assert(
217
- fake.getInfos().some((message) => message.includes("falling back to before_prompt_build prependSystemContext")),
218
- "expected older hosts to log an informational compatibility note",
219
- );
220
- }
221
-
222
- function testModernHostWithoutPromptRegistrationWarns(): void {
223
- const fake = createFakePluginApi({
224
- exposeCapability: false,
225
- exposePromptSection: false,
226
- runtimeVersion: "2026.3.22",
227
- });
228
- createClawMemPlugin(fake.api as never);
229
-
230
- assert(
231
- fake.getWarnings().some((message) => message.includes("falling back to before_prompt_build prependSystemContext")),
232
- "expected warning when a new-enough host is missing prompt registration",
233
- );
234
- }
235
-
236
- async function testOlderModernHostInjectsPromptGuidanceViaPrependSystemContext(): Promise<void> {
237
- const fake = createFakePluginApi({
238
- exposeCapability: false,
239
- exposePromptSection: false,
240
- runtimeVersion: "2026.3.13",
241
- });
242
- createClawMemPlugin(fake.api as never);
243
-
244
- const handler = fake.getHandler("before_prompt_build");
245
- assert(typeof handler === "function", "expected before_prompt_build handler to be registered for modern hosts");
246
- const result = await handler?.({ prompt: "hi" }, { agentId: "main" }) as { prependContext?: string; prependSystemContext?: string } | void;
247
- assert(Boolean(result && result.prependSystemContext?.includes("## ClawMem")), "expected static ClawMem guidance to use prependSystemContext fallback");
248
- assert(!result || !result.prependContext, "expected no dynamic recall context when the prompt is too short for auto-recall");
249
- }
250
-
251
- function testSkipsAlwaysOnPromptWhenClawMemIsNotSelectedMemoryPlugin(): void {
252
- const fake = createFakePluginApi({ slot: "other-memory" });
253
- createClawMemPlugin(fake.api as never);
254
-
255
- assert(!fake.getRegisteredCapability(), "expected no memory prompt registration when ClawMem is not the selected memory plugin");
256
- assert(!fake.getRegisteredPromptSection(), "expected no legacy prompt registration when ClawMem is not selected");
257
- }
258
-
259
- function testResolveHostVersionFromRuntime(): void {
260
- const version = resolveOpenClawHostVersion({ runtime: { version: "2026.3.28" } } as never);
261
- assert(version === "2026.3.28", "expected runtime.version to take precedence");
262
- }
263
-
264
- function testResolveHostVersionFromEnvFallback(): void {
265
- const previous = {
266
- OPENCLAW_VERSION: process.env.OPENCLAW_VERSION,
267
- OPENCLAW_SERVICE_VERSION: process.env.OPENCLAW_SERVICE_VERSION,
268
- npm_package_version: process.env.npm_package_version,
269
- };
270
- try {
271
- delete process.env.OPENCLAW_VERSION;
272
- process.env.OPENCLAW_SERVICE_VERSION = "2026.3.6";
273
- delete process.env.npm_package_version;
274
- const version = resolveOpenClawHostVersion({ runtime: {} } as never);
275
- assert(version === "2026.3.6", "expected OPENCLAW_SERVICE_VERSION fallback");
276
- } finally {
277
- process.env.OPENCLAW_VERSION = previous.OPENCLAW_VERSION;
278
- process.env.OPENCLAW_SERVICE_VERSION = previous.OPENCLAW_SERVICE_VERSION;
279
- process.env.npm_package_version = previous.npm_package_version;
280
- }
281
- }
282
-
283
- function testIgnoresNpmPackageVersionFallback(): void {
284
- const previous = {
285
- OPENCLAW_VERSION: process.env.OPENCLAW_VERSION,
286
- OPENCLAW_SERVICE_VERSION: process.env.OPENCLAW_SERVICE_VERSION,
287
- npm_package_version: process.env.npm_package_version,
288
- };
289
- try {
290
- delete process.env.OPENCLAW_VERSION;
291
- delete process.env.OPENCLAW_SERVICE_VERSION;
292
- process.env.npm_package_version = "2026.3.99";
293
- const version = resolveOpenClawHostVersion({ runtime: {} } as never);
294
- assert(version === undefined, "expected npm_package_version to be ignored for host detection");
295
- } finally {
296
- process.env.OPENCLAW_VERSION = previous.OPENCLAW_VERSION;
297
- process.env.OPENCLAW_SERVICE_VERSION = previous.OPENCLAW_SERVICE_VERSION;
298
- process.env.npm_package_version = previous.npm_package_version;
299
- }
300
- }
301
-
302
- function testResolvePromptHookModeModern(): void {
303
- const mode = resolvePromptHookMode({ runtime: { version: "2026.3.28" } } as never);
304
- assert(mode === "modern", "expected modern hook mode for OpenClaw 2026.3.28");
305
- }
306
-
307
- function testResolvePromptHookModeLegacy(): void {
308
- const mode = resolvePromptHookMode({ runtime: { version: "2026.3.6" } } as never);
309
- assert(mode === "legacy", "expected legacy hook mode before 2026.3.7");
310
- }
311
-
312
- function testResolvePromptHookModeLegacyForUnknownVersion(): void {
313
- const mode = resolvePromptHookMode({ runtime: {} } as never);
314
- assert(mode === "legacy", "expected unknown host versions to fall back to legacy mode");
315
- }
316
-
317
- testExtractPromptFromString();
318
- testExtractPromptPrefersSanitizedPromptField();
319
- testExtractPromptFallsBackToLatestUserMessage();
320
- testExtractPromptFromPromptField();
321
- testExtractPromptFromStructuredContent();
322
- testBuildAutoRecallContext();
323
- testBuildClawMemPromptSection();
324
- testResolveHostVersionFromRuntime();
325
- testResolveHostVersionFromEnvFallback();
326
- testIgnoresNpmPackageVersionFallback();
327
- testResolvePromptHookModeModern();
328
- testResolvePromptHookModeLegacy();
329
- testResolvePromptHookModeLegacyForUnknownVersion();
330
- testRegistersAlwaysOnMemoryPromptCapability();
331
- testFallsBackToLegacyMemoryPromptSectionRegistration();
332
- testOlderHostWithoutPromptRegistrationDoesNotWarn();
333
- testModernHostWithoutPromptRegistrationWarns();
334
- testSkipsAlwaysOnPromptWhenClawMemIsNotSelectedMemoryPlugin();
335
- await testOlderModernHostInjectsPromptGuidanceViaPrependSystemContext();
336
-
337
- console.log("service tests passed");