@mem9/mem9 0.3.5-rc.1 → 0.3.5-rc.3

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 (3) hide show
  1. package/hooks.ts +28 -8
  2. package/index.ts +8 -3
  3. package/package.json +1 -1
package/hooks.ts CHANGED
@@ -46,6 +46,19 @@ interface HookApi {
46
46
  on: (hookName: string, handler: (...args: unknown[]) => unknown, opts?: { priority?: number }) => void;
47
47
  }
48
48
 
49
+ /**
50
+ * Runtime context passed as the second argument to agent_end by the OpenClaw
51
+ * framework. Fields are inferred from observed OpenClaw runtime behavior — no
52
+ * official SDK type is published. Kept local to avoid importing OpenClaw types
53
+ * at the module level (same pattern as HookApi above).
54
+ */
55
+ interface HookContext {
56
+ agentId?: string;
57
+ sessionId?: string;
58
+ /** Legacy alias for sessionId used by older OpenClaw versions. */
59
+ sessionKey?: string;
60
+ }
61
+
49
62
  // ---------------------------------------------------------------------------
50
63
  // Message selection (size-aware)
51
64
  // ---------------------------------------------------------------------------
@@ -165,6 +178,10 @@ function stripInjectedContext(content: string): string {
165
178
  return s.trim();
166
179
  }
167
180
 
181
+ function nonEmptyString(value: unknown): string | null {
182
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
183
+ }
184
+
168
185
  // ---------------------------------------------------------------------------
169
186
  // Hook registration
170
187
  // ---------------------------------------------------------------------------
@@ -173,7 +190,7 @@ export function registerHooks(
173
190
  api: HookApi,
174
191
  backend: MemoryBackend,
175
192
  logger: Logger,
176
- options?: { maxIngestBytes?: number },
193
+ options?: { maxIngestBytes?: number; fallbackAgentId?: string },
177
194
  ): void {
178
195
  const maxIngestBytes = options?.maxIngestBytes ?? DEFAULT_MAX_INGEST_BYTES;
179
196
 
@@ -261,7 +278,7 @@ export function registerHooks(
261
278
  // accumulating until byte budget is hit. Then POST to tenant-scoped ingest endpoint.
262
279
  // for server-side LLM extraction + reconciliation.
263
280
  // --------------------------------------------------------------------------
264
- api.on("agent_end", async (event: unknown) => {
281
+ api.on("agent_end", async (event: unknown, context: unknown) => {
265
282
  try {
266
283
  const evt = event as {
267
284
  success?: boolean;
@@ -269,6 +286,7 @@ export function registerHooks(
269
286
  sessionId?: string;
270
287
  agentId?: string;
271
288
  };
289
+ const hookCtx = (context ?? {}) as HookContext;
272
290
  if (!evt?.success || !evt.messages || evt.messages.length === 0) return;
273
291
 
274
292
  // Format raw messages into IngestMessage format
@@ -312,13 +330,15 @@ export function registerHooks(
312
330
 
313
331
  if (selected.length === 0) return;
314
332
 
315
- const sessionId = typeof evt.sessionId === "string"
316
- ? evt.sessionId
317
- : `ses_${Date.now()}`;
333
+ const sessionId = nonEmptyString(evt.sessionId)
334
+ ?? nonEmptyString(hookCtx.sessionId)
335
+ ?? nonEmptyString(hookCtx.sessionKey)
336
+ ?? `ses_${Date.now()}`;
318
337
 
319
- const agentId = typeof evt.agentId === "string"
320
- ? evt.agentId
321
- : AUTO_CAPTURE_SOURCE;
338
+ const agentId = nonEmptyString(evt.agentId)
339
+ ?? nonEmptyString(hookCtx.agentId)
340
+ ?? nonEmptyString(options?.fallbackAgentId)
341
+ ?? AUTO_CAPTURE_SOURCE;
322
342
 
323
343
  // POST messages to unified memories endpoint — server handles LLM extraction + reconciliation
324
344
  const result = await backend.ingest({
package/index.ts CHANGED
@@ -270,6 +270,8 @@ const mnemoPlugin = {
270
270
 
271
271
  api.logger.info("[mem9] Server mode (v1alpha2)");
272
272
 
273
+ const hookAgentId = cfg.agentName ?? "agent";
274
+
273
275
  const factory: ToolFactory = (ctx: ToolContext) => {
274
276
  const agentId = ctx.agentId ?? cfg.agentName ?? "agent";
275
277
  const backend = new LazyServerBackend(
@@ -286,10 +288,13 @@ const mnemoPlugin = {
286
288
  // Uses the default workspace/agent context for hook-triggered operations.
287
289
  const hookBackend = new LazyServerBackend(
288
290
  effectiveApiUrl,
289
- () => resolveAPIKey(cfg.agentName ?? "agent"),
290
- cfg.agentName ?? "agent",
291
+ () => resolveAPIKey(hookAgentId),
292
+ hookAgentId,
291
293
  );
292
- registerHooks(api, hookBackend, api.logger, { maxIngestBytes: cfg.maxIngestBytes });
294
+ registerHooks(api, hookBackend, api.logger, {
295
+ maxIngestBytes: cfg.maxIngestBytes,
296
+ fallbackAgentId: hookAgentId,
297
+ });
293
298
  },
294
299
  };
295
300
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mem9/mem9",
3
- "version": "0.3.5-rc.1",
3
+ "version": "0.3.5-rc.3",
4
4
  "description": "OpenClaw shared memory plugin — cloud-persistent memory with hybrid vector + keyword search via mnemo-server",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",