@nowledge/openclaw-nowledge-mem 0.8.30 → 0.8.31
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/CHANGELOG.md +6 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/hooks/capture.js +44 -5
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to the Nowledge Mem OpenClaw plugin will be documented in th
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## [0.8.31] - 2026-07-12
|
|
8
|
+
|
|
9
|
+
### Improved
|
|
10
|
+
|
|
11
|
+
- New OpenClaw Threads use the first meaningful user message as their title instead of exposing an internal `agent:...` session key. When no user turn is available, the plugin falls back to a readable channel label such as `OpenClaw · WeChat`.
|
|
12
|
+
|
|
7
13
|
## [0.8.30] - 2026-07-12
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "openclaw-nowledge-mem",
|
|
3
3
|
"name": "Nowledge Mem",
|
|
4
4
|
"description": "Cross-tool knowledge graph memory for OpenClaw with startup context, graph search, and session distillation.",
|
|
5
|
-
"version": "0.8.
|
|
5
|
+
"version": "0.8.31",
|
|
6
6
|
"kind": ["memory", "context-engine"],
|
|
7
7
|
"contracts": {
|
|
8
8
|
"tools": [
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nowledge/openclaw-nowledge-mem",
|
|
3
3
|
"displayName": "Nowledge Mem for OpenClaw",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.31",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Nowledge Mem memory plugin for OpenClaw, local-first personal knowledge base",
|
|
7
7
|
"author": {
|
package/src/hooks/capture.js
CHANGED
|
@@ -12,6 +12,7 @@ export const DEFAULT_MAX_MESSAGE_CHARS = 800;
|
|
|
12
12
|
export const MAX_DISTILL_MESSAGE_CHARS = 2000;
|
|
13
13
|
export const MAX_CONVERSATION_CHARS = 30_000;
|
|
14
14
|
export const MIN_MESSAGES_FOR_DISTILL = 4;
|
|
15
|
+
export const MAX_THREAD_TITLE_CHARS = 80;
|
|
15
16
|
const SESSION_RESET_PROMPT_PREFIX =
|
|
16
17
|
"A new session was started via /new or /reset.";
|
|
17
18
|
const OPENCLAW_DIRECTIVE_TAG_RE =
|
|
@@ -309,9 +310,47 @@ export function normalizeRoleMessage(
|
|
|
309
310
|
};
|
|
310
311
|
}
|
|
311
312
|
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
|
|
313
|
+
function humanizeChannel(value) {
|
|
314
|
+
const normalized = String(value || "")
|
|
315
|
+
.trim()
|
|
316
|
+
.toLowerCase();
|
|
317
|
+
if (!normalized) return "";
|
|
318
|
+
const known = {
|
|
319
|
+
dashboard: "Dashboard",
|
|
320
|
+
"openclaw-weixin": "WeChat",
|
|
321
|
+
weixin: "WeChat",
|
|
322
|
+
wechat: "WeChat",
|
|
323
|
+
telegram: "Telegram",
|
|
324
|
+
discord: "Discord",
|
|
325
|
+
whatsapp: "WhatsApp",
|
|
326
|
+
};
|
|
327
|
+
if (known[normalized]) return known[normalized];
|
|
328
|
+
return normalized
|
|
329
|
+
.replace(/^openclaw[-_]/, "")
|
|
330
|
+
.split(/[-_]+/)
|
|
331
|
+
.filter(Boolean)
|
|
332
|
+
.map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
|
|
333
|
+
.join(" ");
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export function buildThreadTitle(ctx, normalizedMessages = []) {
|
|
337
|
+
const firstUserMessage = normalizedMessages.find(
|
|
338
|
+
(message) => message?.role === "user",
|
|
339
|
+
);
|
|
340
|
+
const userText = String(
|
|
341
|
+
firstUserMessage?.fullContent || firstUserMessage?.content || "",
|
|
342
|
+
)
|
|
343
|
+
.replace(/\s+/gu, " ")
|
|
344
|
+
.trim();
|
|
345
|
+
if (userText) return truncate(userText, MAX_THREAD_TITLE_CHARS);
|
|
346
|
+
|
|
347
|
+
const explicitChannel = ctx?.channel || ctx?.channelId;
|
|
348
|
+
const sessionKey = String(ctx?.sessionKey || "");
|
|
349
|
+
const sessionParts = sessionKey.split(":").filter(Boolean);
|
|
350
|
+
const sessionChannel =
|
|
351
|
+
sessionParts[0]?.toLowerCase() === "agent" ? sessionParts[2] : "";
|
|
352
|
+
const channel = humanizeChannel(explicitChannel || sessionChannel);
|
|
353
|
+
return channel ? `OpenClaw · ${channel}` : "OpenClaw conversation";
|
|
315
354
|
}
|
|
316
355
|
|
|
317
356
|
function sanitizeIdPart(input, max = 48) {
|
|
@@ -423,11 +462,11 @@ export async function appendOrCreateThread({
|
|
|
423
462
|
const threadId = buildStableThreadId(event, ctx);
|
|
424
463
|
const sessionKey = String(ctx?.sessionKey || ctx?.sessionId || "session");
|
|
425
464
|
const sessionId = String(ctx?.sessionId || "").trim();
|
|
426
|
-
const title = buildThreadTitle(ctx);
|
|
427
465
|
const normalized = rawMessages
|
|
428
466
|
.map((message) => normalizeRoleMessage(message, maxMessageChars))
|
|
429
467
|
.filter(Boolean);
|
|
430
468
|
if (normalized.length === 0) return;
|
|
469
|
+
const title = buildThreadTitle(ctx, normalized);
|
|
431
470
|
|
|
432
471
|
const buildMessages = (resolvedMessageMode) =>
|
|
433
472
|
normalized.map((message, index) => ({
|
|
@@ -669,7 +708,7 @@ export async function triageAndDistill({
|
|
|
669
708
|
|
|
670
709
|
const distillResult = await client.distillThread({
|
|
671
710
|
threadId: captureResult.threadId,
|
|
672
|
-
title: buildThreadTitle(ctx),
|
|
711
|
+
title: buildThreadTitle(ctx, captureResult.normalized),
|
|
673
712
|
content: conversationText,
|
|
674
713
|
});
|
|
675
714
|
|