@nowledge/openclaw-nowledge-mem 0.6.8 → 0.6.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/CHANGELOG.md +10 -0
- package/CLAUDE.md +1 -0
- package/README.md +8 -0
- package/openclaw.plugin.json +17 -6
- package/package.json +1 -1
- package/src/config.js +18 -1
- package/src/hooks/capture.js +7 -2
- package/src/hooks/recall.js +147 -9
- package/src/tools/connections.js +1 -3
- package/src/tools/status.js +7 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the Nowledge Mem OpenClaw plugin will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.6.9] - 2026-03-05
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **Auto-recall searched with full prompt instead of user message**: `event.prompt` contains the entire conversation history (system prompt + all prior turns), making recalled memories irrelevant as conversation grows. Now uses a tiered query strategy: substantial messages (>=40 chars) search alone; short messages (3-39 chars, likely follow-ups like "explain that more") include the last 3 messages as context for topic grounding; tiny messages (<3 chars) skip recall. Falls back to truncated `event.prompt` (500 chars) only when `event.messages` is unavailable.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`recallMinScore` config option** (0-100, default 0): Minimum relevance score threshold for auto-recalled memories. Set to e.g. 30 to filter out low-confidence results. Configurable via OpenClaw Config UI, config file, or `NMEM_RECALL_MIN_SCORE` env var.
|
|
14
|
+
|
|
5
15
|
## [0.6.8] - 2026-02-27
|
|
6
16
|
|
|
7
17
|
### Changed
|
package/CLAUDE.md
CHANGED
|
@@ -91,6 +91,7 @@ Optional config file at `~/.nowledge-mem/openclaw.json`. Falls through to OpenCl
|
|
|
91
91
|
| `sessionDigest` | boolean | `true` | `NMEM_SESSION_DIGEST` | Thread capture + LLM distillation at session end |
|
|
92
92
|
| `digestMinInterval` | integer 0-86400 | `300` | `NMEM_DIGEST_MIN_INTERVAL` | Minimum seconds between session digests |
|
|
93
93
|
| `maxContextResults` | integer 1-20 | `5` | `NMEM_MAX_CONTEXT_RESULTS` | How many memories to inject at prompt time |
|
|
94
|
+
| `recallMinScore` | integer 0-100 | `0` | `NMEM_RECALL_MIN_SCORE` | Min relevance score (%) to include in auto-recall |
|
|
94
95
|
| `apiUrl` | string | `""` | `NMEM_API_URL` | Remote server URL. Empty = local (127.0.0.1:14242) |
|
|
95
96
|
| `apiKey` | string | `""` | `NMEM_API_KEY` | API key. Never logged. |
|
|
96
97
|
|
package/README.md
CHANGED
|
@@ -51,6 +51,11 @@ Or use a config file at `~/.nowledge-mem/openclaw.json`:
|
|
|
51
51
|
|
|
52
52
|
The `apiKey` is injected as `NMEM_API_KEY` into the nmem CLI process. Never passed as a CLI argument, never logged.
|
|
53
53
|
|
|
54
|
+
### Configure via WebUI of OpenClaw
|
|
55
|
+
|
|
56
|
+
<img width="1192" height="2007" alt="openclaw-config" src="https://github.com/user-attachments/assets/a4abd855-db56-4a1f-b0ac-0114909d0c20" />
|
|
57
|
+
|
|
58
|
+
|
|
54
59
|
## How It Works
|
|
55
60
|
|
|
56
61
|
### Per-Turn Flow
|
|
@@ -332,6 +337,7 @@ To change settings, use the OpenClaw plugin settings UI. Changes take effect on
|
|
|
332
337
|
| `sessionDigest` | boolean | `true` | Thread capture + LLM distillation at session end |
|
|
333
338
|
| `digestMinInterval` | integer | `300` | Minimum seconds between session digests for the same thread (0-86400) |
|
|
334
339
|
| `maxContextResults` | integer | `5` | Max memories to inject at prompt time (1-20, only used when sessionContext is enabled) |
|
|
340
|
+
| `recallMinScore` | integer | `0` | Min relevance score (0-100%) to include in auto-recall. 0 = include all |
|
|
335
341
|
| `apiUrl` | string | `""` | Remote server URL. Empty = local (`http://127.0.0.1:14242`) |
|
|
336
342
|
| `apiKey` | string | `""` | API key for remote access. Injected as `NMEM_API_KEY` env var, never logged |
|
|
337
343
|
|
|
@@ -345,6 +351,7 @@ For persistent or scripted config, create `~/.nowledge-mem/openclaw.json`:
|
|
|
345
351
|
"sessionDigest": true,
|
|
346
352
|
"digestMinInterval": 300,
|
|
347
353
|
"maxContextResults": 5,
|
|
354
|
+
"recallMinScore": 0,
|
|
348
355
|
"apiUrl": "",
|
|
349
356
|
"apiKey": ""
|
|
350
357
|
}
|
|
@@ -361,6 +368,7 @@ NMEM_SESSION_CONTEXT=true
|
|
|
361
368
|
NMEM_SESSION_DIGEST=true
|
|
362
369
|
NMEM_DIGEST_MIN_INTERVAL=300
|
|
363
370
|
NMEM_MAX_CONTEXT_RESULTS=5
|
|
371
|
+
NMEM_RECALL_MIN_SCORE=0
|
|
364
372
|
NMEM_API_URL=https://...
|
|
365
373
|
NMEM_API_KEY=your-key
|
|
366
374
|
```
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "openclaw-nowledge-mem",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.9",
|
|
4
4
|
"kind": "memory",
|
|
5
5
|
"uiHints": {
|
|
6
6
|
"sessionContext": {
|
|
7
7
|
"label": "Session context injection",
|
|
8
|
-
"help": "Inject Working Memory and relevant memories at prompt time. Off by default
|
|
8
|
+
"help": "Inject Working Memory and relevant memories at prompt time. Off by default; the agent can call memory_search on demand instead."
|
|
9
9
|
},
|
|
10
10
|
"sessionDigest": {
|
|
11
11
|
"label": "Session digest at end",
|
|
12
|
-
"help": "Capture conversation threads and distill key memories via LLM at session end. On by default
|
|
12
|
+
"help": "Capture conversation threads and distill key memories via LLM at session end. On by default. Negligible cost, one triage call per session."
|
|
13
13
|
},
|
|
14
14
|
"digestMinInterval": {
|
|
15
15
|
"label": "Minimum digest interval (seconds)",
|
|
@@ -17,7 +17,11 @@
|
|
|
17
17
|
},
|
|
18
18
|
"maxContextResults": {
|
|
19
19
|
"label": "Max context results",
|
|
20
|
-
"help": "How many memories to inject for each context cycle (1
|
|
20
|
+
"help": "How many memories to inject for each context cycle (1-20)"
|
|
21
|
+
},
|
|
22
|
+
"recallMinScore": {
|
|
23
|
+
"label": "Min recall score (%)",
|
|
24
|
+
"help": "Only inject memories with relevance score above this threshold (0-100). Set to 0 to include all results."
|
|
21
25
|
},
|
|
22
26
|
"apiUrl": {
|
|
23
27
|
"label": "Server URL (remote mode)",
|
|
@@ -25,7 +29,7 @@
|
|
|
25
29
|
},
|
|
26
30
|
"apiKey": {
|
|
27
31
|
"label": "API key (remote mode)",
|
|
28
|
-
"help": "Required when connecting to a remote server. Never logged or passed as a CLI argument
|
|
32
|
+
"help": "Required when connecting to a remote server. Never logged or passed as a CLI argument. Injected as NMEM_API_KEY env var only.",
|
|
29
33
|
"secret": true
|
|
30
34
|
}
|
|
31
35
|
},
|
|
@@ -35,7 +39,7 @@
|
|
|
35
39
|
"sessionContext": {
|
|
36
40
|
"type": "boolean",
|
|
37
41
|
"default": false,
|
|
38
|
-
"description": "Inject Working Memory and recalled memories at prompt time. Off by default
|
|
42
|
+
"description": "Inject Working Memory and recalled memories at prompt time. Off by default; the agent queries memory on demand via tools."
|
|
39
43
|
},
|
|
40
44
|
"sessionDigest": {
|
|
41
45
|
"type": "boolean",
|
|
@@ -56,6 +60,13 @@
|
|
|
56
60
|
"maximum": 20,
|
|
57
61
|
"description": "Maximum memories to inject at prompt time (only used when sessionContext is enabled)"
|
|
58
62
|
},
|
|
63
|
+
"recallMinScore": {
|
|
64
|
+
"type": "integer",
|
|
65
|
+
"default": 0,
|
|
66
|
+
"minimum": 0,
|
|
67
|
+
"maximum": 100,
|
|
68
|
+
"description": "Minimum relevance score (0-100%) to include a memory in auto-recall. Set to 0 to include all results."
|
|
69
|
+
},
|
|
59
70
|
"apiUrl": {
|
|
60
71
|
"type": "string",
|
|
61
72
|
"default": "",
|
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -19,6 +19,7 @@ const ALLOWED_KEYS = new Set([
|
|
|
19
19
|
"sessionDigest",
|
|
20
20
|
"digestMinInterval",
|
|
21
21
|
"maxContextResults",
|
|
22
|
+
"recallMinScore",
|
|
22
23
|
"apiUrl",
|
|
23
24
|
"apiKey",
|
|
24
25
|
// Legacy aliases — accepted but not advertised
|
|
@@ -135,7 +136,7 @@ function firstDefined(...options) {
|
|
|
135
136
|
* will configure via OpenClaw's plugin settings UI (pluginConfig).
|
|
136
137
|
*
|
|
137
138
|
* Canonical keys: sessionContext, sessionDigest, digestMinInterval,
|
|
138
|
-
* maxContextResults, apiUrl, apiKey
|
|
139
|
+
* maxContextResults, recallMinScore, apiUrl, apiKey
|
|
139
140
|
*
|
|
140
141
|
* Legacy aliases (accepted from all sources; never shown in docs):
|
|
141
142
|
* autoRecall → sessionContext
|
|
@@ -148,6 +149,7 @@ function firstDefined(...options) {
|
|
|
148
149
|
* NMEM_SESSION_DIGEST — true/1/yes to enable (alias: NMEM_AUTO_CAPTURE)
|
|
149
150
|
* NMEM_DIGEST_MIN_INTERVAL — seconds (0-86400)
|
|
150
151
|
* NMEM_MAX_CONTEXT_RESULTS — integer (1-20)
|
|
152
|
+
* NMEM_RECALL_MIN_SCORE — integer (0-100)
|
|
151
153
|
* NMEM_API_URL — remote server URL
|
|
152
154
|
* NMEM_API_KEY — API key (never logged)
|
|
153
155
|
*/
|
|
@@ -234,6 +236,20 @@ export function parseConfig(raw, logger) {
|
|
|
234
236
|
const maxContextResults = Math.min(20, Math.max(1, Math.trunc(mcr.value)));
|
|
235
237
|
_sources.maxContextResults = mcr.source;
|
|
236
238
|
|
|
239
|
+
// --- recallMinScore: file > pluginConfig > env > default ---
|
|
240
|
+
const rmsEnv = envInt("NMEM_RECALL_MIN_SCORE");
|
|
241
|
+
const rms = firstDefined(
|
|
242
|
+
{ value: pickNum(resolvedFile, "recallMinScore"), source: "file" },
|
|
243
|
+
{
|
|
244
|
+
value: pickNum(resolvedPlugin, "recallMinScore"),
|
|
245
|
+
source: "pluginConfig",
|
|
246
|
+
},
|
|
247
|
+
{ value: rmsEnv, source: "env" },
|
|
248
|
+
{ value: 0, source: "default" },
|
|
249
|
+
);
|
|
250
|
+
const recallMinScore = Math.min(100, Math.max(0, Math.trunc(rms.value)));
|
|
251
|
+
_sources.recallMinScore = rms.source;
|
|
252
|
+
|
|
237
253
|
// --- apiUrl: file > pluginConfig > env > "" ---
|
|
238
254
|
const fileUrl =
|
|
239
255
|
typeof resolvedFile.apiUrl === "string" && resolvedFile.apiUrl.trim();
|
|
@@ -267,6 +283,7 @@ export function parseConfig(raw, logger) {
|
|
|
267
283
|
sessionDigest,
|
|
268
284
|
digestMinInterval,
|
|
269
285
|
maxContextResults,
|
|
286
|
+
recallMinScore,
|
|
270
287
|
apiUrl,
|
|
271
288
|
apiKey,
|
|
272
289
|
_sources,
|
package/src/hooks/capture.js
CHANGED
|
@@ -250,7 +250,10 @@ function buildConversationText(normalized) {
|
|
|
250
250
|
const parts = [];
|
|
251
251
|
let total = 0;
|
|
252
252
|
for (const m of normalized) {
|
|
253
|
-
const text = truncate(
|
|
253
|
+
const text = truncate(
|
|
254
|
+
m.fullContent || m.content,
|
|
255
|
+
MAX_DISTILL_MESSAGE_CHARS,
|
|
256
|
+
);
|
|
254
257
|
const line = `${m.role}: ${text}`;
|
|
255
258
|
if (total + line.length > MAX_CONVERSATION_CHARS) break;
|
|
256
259
|
parts.push(line);
|
|
@@ -297,7 +300,9 @@ export function buildAgentEndCaptureHandler(client, cfg, logger) {
|
|
|
297
300
|
|
|
298
301
|
// Skip when no new messages were added (e.g. heartbeat re-sync).
|
|
299
302
|
if (!result || result.messagesAdded === 0) {
|
|
300
|
-
logger.debug?.(
|
|
303
|
+
logger.debug?.(
|
|
304
|
+
"capture: no new messages since last sync, skipping triage",
|
|
305
|
+
);
|
|
301
306
|
return;
|
|
302
307
|
}
|
|
303
308
|
|
package/src/hooks/recall.js
CHANGED
|
@@ -13,20 +13,148 @@ function escapeForPrompt(text) {
|
|
|
13
13
|
);
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/** Max query length sent to search — longer messages get truncated. */
|
|
17
|
+
const MAX_QUERY_LENGTH = 500;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Messages shorter than this get augmented with recent conversational
|
|
21
|
+
* context. Below this threshold, a message is likely referential
|
|
22
|
+
* ("explain that more", "what about the second point?") and needs
|
|
23
|
+
* surrounding context to produce useful search results.
|
|
24
|
+
*
|
|
25
|
+
* Messages at or above this threshold are substantial enough to
|
|
26
|
+
* search on their own ("openviking 不好用", "how do I deploy to k8s?").
|
|
27
|
+
*/
|
|
28
|
+
const SHORT_QUERY_THRESHOLD = 40;
|
|
29
|
+
|
|
30
|
+
/** How many recent messages to include for short-query context. */
|
|
31
|
+
const CONTEXT_MESSAGES = 3;
|
|
32
|
+
|
|
33
|
+
/** Per-message cap when building context window. */
|
|
34
|
+
const CONTEXT_MSG_MAX_CHARS = 150;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Extract text from message content (string or structured blocks).
|
|
38
|
+
* Mirrors the pattern from capture.js.
|
|
39
|
+
*/
|
|
40
|
+
function extractText(content) {
|
|
41
|
+
if (typeof content === "string") return content.trim();
|
|
42
|
+
if (!Array.isArray(content)) return "";
|
|
43
|
+
const parts = [];
|
|
44
|
+
for (const block of content) {
|
|
45
|
+
if (!block || typeof block !== "object") continue;
|
|
46
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
47
|
+
const text = block.text.trim();
|
|
48
|
+
if (text) parts.push(text);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return parts.join("\n").trim();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Normalize a raw message entry to { role, text }.
|
|
56
|
+
* Handles both flat { role, content } and nested { message: { role, content } }.
|
|
57
|
+
* Returns null for non-user/assistant messages, empty content, or slash commands.
|
|
58
|
+
*/
|
|
59
|
+
function normalizeMessage(raw) {
|
|
60
|
+
if (!raw || typeof raw !== "object") return null;
|
|
61
|
+
const msg =
|
|
62
|
+
raw.message && typeof raw.message === "object" ? raw.message : raw;
|
|
63
|
+
const role = typeof msg.role === "string" ? msg.role : "";
|
|
64
|
+
if (role !== "user" && role !== "assistant") return null;
|
|
65
|
+
const text = extractText(msg.content);
|
|
66
|
+
if (!text) return null;
|
|
67
|
+
// Skip slash commands — they're plugin directives, not conversational
|
|
68
|
+
if (role === "user" && text.startsWith("/")) return null;
|
|
69
|
+
return { role, text };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Build the search query from the hook event.
|
|
74
|
+
*
|
|
75
|
+
* Three tiers:
|
|
76
|
+
* >= 40 chars : latest user message alone (self-contained)
|
|
77
|
+
* 3-39 chars : latest user message + recent context (likely referential)
|
|
78
|
+
* < 3 chars : skip recall (too short — "ok", emoji, etc.)
|
|
79
|
+
*
|
|
80
|
+
* The event object provides:
|
|
81
|
+
* - event.messages: structured array of {role, content} messages (preferred)
|
|
82
|
+
* - event.prompt: the full formatted prompt (fallback, truncated)
|
|
83
|
+
*/
|
|
84
|
+
function buildSearchQuery(event) {
|
|
85
|
+
const messages = event?.messages;
|
|
86
|
+
|
|
87
|
+
if (Array.isArray(messages) && messages.length > 0) {
|
|
88
|
+
// Find the latest user message (walk backwards)
|
|
89
|
+
let latestUserIdx = -1;
|
|
90
|
+
let latestUserText = "";
|
|
91
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
92
|
+
const norm = normalizeMessage(messages[i]);
|
|
93
|
+
if (norm && norm.role === "user") {
|
|
94
|
+
latestUserIdx = i;
|
|
95
|
+
latestUserText = norm.text;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!latestUserText || latestUserText.length < 3) return "";
|
|
101
|
+
|
|
102
|
+
// Substantial message — use it alone
|
|
103
|
+
if (latestUserText.length >= SHORT_QUERY_THRESHOLD) {
|
|
104
|
+
return latestUserText.slice(0, MAX_QUERY_LENGTH);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Short message — likely a follow-up. Add recent context so
|
|
108
|
+
// the search engine sees what topic the conversation is about.
|
|
109
|
+
// Collect up to CONTEXT_MESSAGES messages preceding the latest user
|
|
110
|
+
// message (both user and assistant, for topic grounding).
|
|
111
|
+
const contextParts = [];
|
|
112
|
+
const scanFrom = Math.max(0, latestUserIdx - CONTEXT_MESSAGES);
|
|
113
|
+
for (let i = scanFrom; i < latestUserIdx; i++) {
|
|
114
|
+
const norm = normalizeMessage(messages[i]);
|
|
115
|
+
if (!norm) continue;
|
|
116
|
+
const truncated =
|
|
117
|
+
norm.text.length > CONTEXT_MSG_MAX_CHARS
|
|
118
|
+
? `${norm.text.slice(0, CONTEXT_MSG_MAX_CHARS)}…`
|
|
119
|
+
: norm.text;
|
|
120
|
+
contextParts.push(truncated);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (contextParts.length > 0) {
|
|
124
|
+
// Latest message first (primary intent), then context
|
|
125
|
+
const combined = `${latestUserText}\n\n${contextParts.join("\n")}`;
|
|
126
|
+
return combined.slice(0, MAX_QUERY_LENGTH);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// No prior context available (first message) — use as-is
|
|
130
|
+
return latestUserText;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Fallback: use event.prompt but truncate aggressively.
|
|
134
|
+
// This path only fires when OpenClaw doesn't provide event.messages.
|
|
135
|
+
if (typeof event?.prompt === "string" && event.prompt.length >= 5) {
|
|
136
|
+
return event.prompt.slice(0, MAX_QUERY_LENGTH);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return "";
|
|
140
|
+
}
|
|
141
|
+
|
|
16
142
|
/**
|
|
17
|
-
* Builds the
|
|
143
|
+
* Builds the before_prompt_build hook handler.
|
|
18
144
|
*
|
|
19
|
-
* Injects two layers of context at
|
|
145
|
+
* Injects two layers of context at prompt time:
|
|
20
146
|
* 1. Working Memory — today's focus, priorities, unresolved flags
|
|
21
|
-
* 2. Relevant memories —
|
|
147
|
+
* 2. Relevant memories — searched using the user's latest message
|
|
22
148
|
*
|
|
23
149
|
* Tool guidance is minimal — the agent already sees full tool descriptions
|
|
24
150
|
* in its tool list. We only add a brief behavioral note.
|
|
25
151
|
*/
|
|
26
152
|
export function buildRecallHandler(client, cfg, logger) {
|
|
153
|
+
const minScore = (cfg.recallMinScore ?? 0) / 100; // config is 0-100, API is 0-1
|
|
154
|
+
|
|
27
155
|
return async (event) => {
|
|
28
|
-
const
|
|
29
|
-
if (!
|
|
156
|
+
const searchQuery = buildSearchQuery(event);
|
|
157
|
+
if (!searchQuery) return;
|
|
30
158
|
|
|
31
159
|
const sections = [];
|
|
32
160
|
|
|
@@ -44,9 +172,17 @@ export function buildRecallHandler(client, cfg, logger) {
|
|
|
44
172
|
|
|
45
173
|
// 2. Relevant memories — enriched with scoring signals and labels
|
|
46
174
|
try {
|
|
47
|
-
const results = await client.searchRich(
|
|
48
|
-
|
|
49
|
-
|
|
175
|
+
const results = await client.searchRich(
|
|
176
|
+
searchQuery,
|
|
177
|
+
cfg.maxContextResults,
|
|
178
|
+
);
|
|
179
|
+
// Filter by minimum score if configured
|
|
180
|
+
const filtered =
|
|
181
|
+
minScore > 0
|
|
182
|
+
? results.filter((r) => (r.score ?? 0) >= minScore)
|
|
183
|
+
: results;
|
|
184
|
+
if (filtered.length > 0) {
|
|
185
|
+
const lines = filtered.map((r) => {
|
|
50
186
|
const title = r.title || "(untitled)";
|
|
51
187
|
const score = `${(r.score * 100).toFixed(0)}%`;
|
|
52
188
|
const labels =
|
|
@@ -82,7 +218,9 @@ export function buildRecallHandler(client, cfg, logger) {
|
|
|
82
218
|
"</nowledge-mem>",
|
|
83
219
|
].join("\n");
|
|
84
220
|
|
|
85
|
-
logger.debug?.(
|
|
221
|
+
logger.debug?.(
|
|
222
|
+
`recall: injecting ${context.length} chars (query: ${searchQuery.slice(0, 80)}…)`,
|
|
223
|
+
);
|
|
86
224
|
return { prependContext: context };
|
|
87
225
|
};
|
|
88
226
|
}
|
package/src/tools/connections.js
CHANGED
|
@@ -293,9 +293,7 @@ export function createConnectionsTool(client, logger) {
|
|
|
293
293
|
const otherTitle = isOlderNode
|
|
294
294
|
? edge.newer_title || "(untitled)"
|
|
295
295
|
: edge.older_title || "(untitled)";
|
|
296
|
-
const otherId = isOlderNode
|
|
297
|
-
? edge.newer_id
|
|
298
|
-
: edge.older_id;
|
|
296
|
+
const otherId = isOlderNode ? edge.newer_id : edge.older_id;
|
|
299
297
|
const direction = isOlderNode ? "→" : "←";
|
|
300
298
|
const idLine = otherId ? `\n → id: ${otherId}` : "";
|
|
301
299
|
return ` ${direction} ${otherTitle}${relLabel ? ` — ${relLabel}` : ""}${idLine}`;
|
package/src/tools/status.js
CHANGED
|
@@ -106,6 +106,9 @@ export function createStatusTool(client, _logger, cfg) {
|
|
|
106
106
|
lines.push(
|
|
107
107
|
` maxContextResults: ${cfg.maxContextResults} (${sources.maxContextResults || "?"})`,
|
|
108
108
|
);
|
|
109
|
+
lines.push(
|
|
110
|
+
` recallMinScore: ${cfg.recallMinScore}% (${sources.recallMinScore || "?"})`,
|
|
111
|
+
);
|
|
109
112
|
|
|
110
113
|
details.config = {
|
|
111
114
|
sessionContext: {
|
|
@@ -124,6 +127,10 @@ export function createStatusTool(client, _logger, cfg) {
|
|
|
124
127
|
value: cfg.maxContextResults,
|
|
125
128
|
source: sources.maxContextResults,
|
|
126
129
|
},
|
|
130
|
+
recallMinScore: {
|
|
131
|
+
value: cfg.recallMinScore,
|
|
132
|
+
source: sources.recallMinScore,
|
|
133
|
+
},
|
|
127
134
|
apiUrl: { value: cfg.apiUrl || "(local)", source: sources.apiUrl },
|
|
128
135
|
apiKey: {
|
|
129
136
|
value: cfg.apiKey ? "(set)" : "(not set)",
|