@nowledge/openclaw-nowledge-mem 0.8.34 → 0.8.36

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 CHANGED
@@ -4,6 +4,20 @@ All notable changes to the Nowledge Mem OpenClaw plugin will be documented in th
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## [0.8.36] - 2026-10-11
8
+
9
+ ### Fixed
10
+
11
+ - Search first, inspect at most one small targeted thread range per question, and report evidence gaps rather than walking offsets.
12
+ - Preserve explicit target ranges, progressive graph exploration and existing session capture.
13
+ - Default thread reads to eight messages when no limit is supplied.
14
+ - Preserve matched-message positions so late-thread evidence can be selected without page walking.
15
+
16
+ ## [0.8.35] - 2026-10-08
17
+
18
+ - Align ClawHub-first code-plugin install metadata with the supported host baseline.
19
+ - Publish the scoped code plugin and npm package through GitHub OIDC with independent artifact receipts. Memory and capture behavior are unchanged.
20
+
7
21
  ## [0.8.34] - 2026-08-31
8
22
 
9
23
  - Fixed automatic capture for agent-scoped OpenClaw 2.0 Incognito session keys.
package/CLAUDE.md CHANGED
@@ -49,7 +49,7 @@ src/
49
49
  timeline.js - activity feed: daily grouping, event_type filter, memoryId hints
50
50
  forget.js - memory deletion by ID or search
51
51
  thread-search.js - search past conversations by keyword
52
- thread-fetch.js - fetch full messages from a thread with pagination
52
+ thread-fetch.js - read one small targeted message range (default 8)
53
53
  skills/
54
54
  memory-guide/
55
55
  SKILL.md - agent behavioral skill: when/how to search, save, explore memory (auto-discovered by OpenClaw)
@@ -139,9 +139,9 @@ When `contextEngine` points elsewhere (or is absent), hooks handle everything. N
139
139
  - `nowledge_mem_timeline` - activity feed via `nmem f`. Groups by day. `event_type` filter. Exact date range via `date_from`/`date_to` (YYYY-MM-DD). Entries include `(id: <memoryId>)` for chaining to connections.
140
140
  - `nowledge_mem_forget` - delete by ID or fuzzy query.
141
141
 
142
- ### Thread Tools (progressive conversation retrieval)
142
+ ### Thread Tools (bounded conversation retrieval)
143
143
  - `nowledge_mem_thread_search` - search past conversations by keyword. Returns threads with matched message snippets, relevance scores, and message counts. Supports `source` filter.
144
- - `nowledge_mem_thread_fetch` - fetch messages from a specific thread. Start with a small page, then use `offset` + `limit` for progressive retrieval only when more context is needed.
144
+ - `nowledge_mem_thread_fetch` - read one small targeted message range from a specific thread. Choose the needed range from search results before the single read; use a known `offset` once and a small `limit` (default 8).
145
145
 
146
146
  ### Diagnostics
147
147
  - `nowledge_mem_status` - show plugin trust status, memory slot status, effective config (mode, apiUrl, apiKey set, sessionContext, sessionDigest, etc.), backend connectivity, and version. Checks `plugins.allow`: warns if set but plugin not included (loading blocked); shows tip if not set (plugin loads via `entries.enabled` but trust is implicit). Warns if the memory slot points to `memory-core` instead of `openclaw-nowledge-mem` (common after OpenClaw 3.22+ upgrade). No parameters.
@@ -216,7 +216,7 @@ Legacy aliases accepted silently in all sources for backward compat:
216
216
  | `nmem --json m delete <id>` | `client.execJson()` in forget.js | Delete |
217
217
  | `GET /threads/search?query=&limit=` | `client.searchThreads()` | Thread search enrichment (best-effort, API-only) |
218
218
  | `nmem --json t search <q> -n N` | `client.searchThreadsFull()` | Full thread search (CLI-first, API fallback) |
219
- | `nmem --json t show <id> -n N --offset O` | `client.fetchThread()` | Fetch thread messages with pagination |
219
+ | `nmem --json t show <id> -n N --offset O` | `client.fetchThread()` | Read one small targeted message range (default 8) |
220
220
 
221
221
  All commands have API fallback for older CLI versions.
222
222
 
@@ -272,3 +272,9 @@ After bumping, commit inside the `community/` submodule, then stage the updated
272
272
  - Do NOT expose full WM overwrite from agents - section-level patch is the right granularity.
273
273
  - Do NOT add cloud dependencies to the core path.
274
274
  - Do NOT accept unknown config keys (strict parser in `config.js`).
275
+
276
+ ### Bounded thread reads
277
+
278
+ Search memories or threads first, then choose the specific conversation and message range needed. Call `thread_fetch_messages`, a host thread-fetch tool, or `nmem --json t show` at most once per question, using a small message limit (for example 8) and a content limit of 1200 where supported. A known target range may use a nonzero offset once.
279
+
280
+ Never loop over offsets to reconstruct a conversation. Do not raise `--content-limit` to compensate for a slow or incomplete read. Small output limits do not guarantee cheap server-side work on every deployed backend. If a read is slow, incomplete, fails or times out, stop, report the evidence gap, and refine the search rather than retrying pages. A later explicit user request for another range is a new bounded read; a routine “continue” is not permission to drain the thread.
package/README.md CHANGED
@@ -19,7 +19,7 @@ the user intentionally asks Mem to keep.
19
19
  ## Installation
20
20
 
21
21
  ```bash
22
- openclaw plugins install clawhub:nowledge-mem
22
+ openclaw plugins install clawhub:@nowledge/openclaw-nowledge-mem
23
23
  ```
24
24
 
25
25
  OpenClaw's installer writes the install record, enables the plugin, and switches the `memory` slot to `openclaw-nowledge-mem`. On current OpenClaw builds, that same install flow may also set `plugins.slots.contextEngine` to `openclaw-nowledge-mem`. Plugin `0.8.18+` accepts that automatically as a compatibility alias.
@@ -35,7 +35,7 @@ If `openclaw config get tools` shows a restrictive profile such as `coding`, pre
35
35
  To update the plugin, re-run the ClawHub install with `--force`:
36
36
 
37
37
  ```bash
38
- openclaw plugins install clawhub:nowledge-mem --force
38
+ openclaw plugins install clawhub:@nowledge/openclaw-nowledge-mem --force
39
39
  ```
40
40
 
41
41
  Use this instead of `openclaw plugins update openclaw-nowledge-mem` when an old install record is pinned to a specific version.
@@ -196,7 +196,7 @@ The behavioral skill and always-on hook nudge the agent to **search before answe
196
196
  | "What was I doing last week?" | `nowledge_mem_timeline` | Activity feed grouped by day. Supports exact date ranges. |
197
197
  | "How is X connected to Y?" | `nowledge_mem_connections` | Graph walk: edges, entities, EVOLVES chains, document provenance. |
198
198
  | Need startup context or today's focus/priorities | `nowledge_mem_context` | Read Context Bundle when available, with Working Memory fallback. Supports Working Memory section-level patch. |
199
- | Memory has `sourceThreadId` | `nowledge_mem_thread_fetch` | Fetch full source conversation. Pagination via `offset` + `limit`. |
199
+ | Memory has `sourceThreadId` | `nowledge_mem_thread_fetch` | Read one small targeted source-message range; do not walk offsets. |
200
200
  | "Find our discussion about X" | `nowledge_mem_thread_search` | Search past conversations by keyword. Returns matched snippets. |
201
201
  | "Forget X" | `nowledge_mem_forget` | Delete by ID or search query. |
202
202
  | "Is my setup working?" | `nowledge_mem_status` | Show effective config, backend connectivity, and version. |
@@ -230,17 +230,17 @@ flowchart TD
230
230
  - Distilled memories carry `sourceThreadId`, linking them back to the source conversation
231
231
  - Cooldown (`digestMinInterval`, default 300s) prevents burst distillation
232
232
 
233
- ### Progressive Retrieval (Memory -> Thread -> Messages)
233
+ ### Targeted Retrieval (Memory -> Thread -> Messages)
234
234
 
235
235
  Memories distilled from conversations carry a `sourceThreadId`. This creates a retrieval chain:
236
236
 
237
237
  ```mermaid
238
238
  flowchart TD
239
239
  A["memory_search'PostgreSQL decision'"] --> B["Result includessourceThreadId"]
240
- B --> C["nowledge_mem_thread_fetch(offset=0, limit=50)"]
241
- C --> D["50 messageshasMore: true"]
242
- D --> E["nowledge_mem_thread_fetch(offset=50, limit=50)"]
243
- E --> F["Next page"]
240
+ B --> C["Choose one known target message range"]
241
+ C --> D["nowledge_mem_thread_fetch(offset=target, limit=8) once"]
242
+ D --> E["Answer from evidence or report the gap"]
243
+ E --> F["Refine search if specific evidence is still missing"]
244
244
  ```
245
245
 
246
246
  Direct conversation search also works:
@@ -365,15 +365,15 @@ last_n_days: 7
365
365
 
366
366
  **nowledge_mem_thread_search** - Search past conversations by keyword. Returns matched threads with message snippets and relevance scores. Use when the user asks about a past discussion or wants to find a conversation from a specific time.
367
367
 
368
- **nowledge_mem_thread_fetch** - Fetch full messages from a conversation thread with pagination. Pass a `sourceThreadId` from memory results or a `threadId` from thread search. Supports `offset` and `limit` for progressive retrieval of long conversations.
368
+ **nowledge_mem_thread_fetch** - Read one small targeted message range. Pass a `sourceThreadId` from memory results or a `threadId` from thread search. Supports `offset` and `limit` (default 8); a known nonzero offset is valid once, not a reason to walk pages.
369
369
 
370
370
  ```
371
371
  threadId: "openclaw-db-arch-a1b2c3"
372
- offset: 0, limit: 50
372
+ offset: 0, limit: 8
373
373
  -> Thread: "Database architecture discussion" (128 messages)
374
374
  [user] We need to decide on the database for task events...
375
375
  [assistant] Based on the requirements, PostgreSQL with JSONB...
376
- ... (126 more messages, use offset=50 for next page)
376
+ ... (126 messages not shown; refine search for the specific evidence needed)
377
377
  ```
378
378
 
379
379
  ## Operating Modes
@@ -543,7 +543,7 @@ If you also use linked or workspace copies, review `plugins.load.paths` before r
543
543
  The memory slot is probably still set to the built-in `memory-core`. OpenClaw 3.22+ defaults to `memory-core` when no explicit slot is configured. Reinstall to reset the slot automatically:
544
544
 
545
545
  ```bash
546
- openclaw plugins install clawhub:nowledge-mem
546
+ openclaw plugins install clawhub:@nowledge/openclaw-nowledge-mem
547
547
  ```
548
548
 
549
549
  Or set the slot manually in `~/.openclaw/openclaw.json`:
@@ -644,3 +644,9 @@ Run `nmem config client show` and confirm the effective URL and API key state. T
644
644
  ## License
645
645
 
646
646
  MIT
647
+
648
+ ### Bounded thread reads
649
+
650
+ Search memories or threads first, then choose the specific conversation and message range needed. Call `thread_fetch_messages`, a host thread-fetch tool, or `nmem --json t show` at most once per question, using a small message limit (for example 8) and a content limit of 1200 where supported. A known target range may use a nonzero offset once.
651
+
652
+ Never loop over offsets to reconstruct a conversation. Do not raise `--content-limit` to compensate for a slow or incomplete read. Small output limits do not guarantee cheap server-side work on every deployed backend. If a read is slow, incomplete, fails or times out, stop, report the evidence gap, and refine the search rather than retrying pages. A later explicit user request for another range is a new bounded read; a routine “continue” is not permission to drain the thread.
package/SKILL.md CHANGED
@@ -105,7 +105,7 @@ Success means the backend responds correctly through `nmem`. Do not skip this st
105
105
  Default install:
106
106
 
107
107
  ```bash
108
- openclaw plugins install clawhub:nowledge-mem
108
+ openclaw plugins install clawhub:@nowledge/openclaw-nowledge-mem
109
109
  ```
110
110
 
111
111
  If this fails with `archive integrity mismatch`, update OpenClaw first, then
@@ -114,7 +114,7 @@ retry. Current ClawHub packages require OpenClaw 2026.5.3 or later.
114
114
  To update an existing install:
115
115
 
116
116
  ```bash
117
- openclaw plugins install clawhub:nowledge-mem --force
117
+ openclaw plugins install clawhub:@nowledge/openclaw-nowledge-mem --force
118
118
  ```
119
119
 
120
120
  Alternatively, if the user is installing from OpenClaw's default registry rather than ClawHub, this also works:
@@ -232,7 +232,7 @@ If only `memory_search` and `memory_get` tools are available (other Nowledge Mem
232
232
  }
233
233
  ```
234
234
 
235
- If missing, reinstall (`openclaw plugins install clawhub:nowledge-mem`) which sets the slot automatically. This is common after upgrading OpenClaw to 3.22+ where the default memory slot changed.
235
+ If missing, reinstall (`openclaw plugins install clawhub:@nowledge/openclaw-nowledge-mem`) which sets the slot automatically. This is common after upgrading OpenClaw to 3.22+ where the default memory slot changed.
236
236
 
237
237
  Then verify in chat.
238
238
 
@@ -282,7 +282,7 @@ What to expect:
282
282
  | `nmem --json status` fails in local mode | Start Nowledge Mem locally first |
283
283
  | Remote mode fails | Re-run `nmem --json --api-url ... status` with the exact URL and auth you plan to use |
284
284
  | `openclaw nowledge-mem status` fails after install | Restart OpenClaw and confirm the plugin was installed successfully |
285
- | ClawHub reports `archive integrity mismatch` | Update OpenClaw to 2026.5.3+ or latest, then reinstall with `openclaw plugins install clawhub:nowledge-mem --force` |
285
+ | ClawHub reports `archive integrity mismatch` | Update OpenClaw to 2026.5.3+ or latest, then reinstall with `openclaw plugins install clawhub:@nowledge/openclaw-nowledge-mem --force` |
286
286
  | `plugins.allow is empty` warning | Add `openclaw-nowledge-mem` to `plugins.allow` if the user wants explicit trust |
287
287
  | Remote config seems ignored | Check whether `~/.nowledge-mem/openclaw.json` is overriding plugin settings |
288
288
  | Local mode unexpectedly talks to a remote server | Check for stale `NMEM_API_URL` / `NMEM_API_KEY` in the environment or an overriding `~/.nowledge-mem/openclaw.json` |
@@ -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.34",
5
+ "version": "0.8.36",
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.34",
4
+ "version": "0.8.36",
5
5
  "type": "module",
6
6
  "description": "Nowledge Mem memory plugin for OpenClaw, local-first personal knowledge base",
7
7
  "author": {
@@ -29,7 +29,7 @@
29
29
  "./src/index.js"
30
30
  ],
31
31
  "install": {
32
- "clawhubSpec": "clawhub:nowledge-mem",
32
+ "clawhubSpec": "clawhub:@nowledge/openclaw-nowledge-mem",
33
33
  "npmSpec": "@nowledge/openclaw-nowledge-mem",
34
34
  "defaultChoice": "clawhub"
35
35
  },
@@ -22,7 +22,7 @@ Use natural language queries. This is semantic search, not file search.
22
22
 
23
23
  Results include `matchedVia` (scoring breakdown), `importance`, `labels`, `sourceThreadId`.
24
24
 
25
- When results include `relatedThreads`, use `nowledge_mem_thread_fetch` with the `threadId` for full conversation context. Start with a small page; fetch more via `offset` + `limit` only when needed.
25
+ When results include `relatedThreads`, use `nowledge_mem_thread_fetch` with the `threadId` for one small targeted message range. A known offset may select that range; do not advance through pages. Follow the bounded thread-read policy below.
26
26
 
27
27
  Bi-temporal filters narrow results by time:
28
28
 
@@ -52,7 +52,7 @@ Browse recent activity grouped by day. Filter by `event_type` or exact `date_fro
52
52
 
53
53
  ## Threads (nowledge_mem_thread_search + nowledge_mem_thread_fetch)
54
54
 
55
- Find past conversations by keyword, then progressively fetch messages. Threads span all sources: this tool, other AI tools, browser capture, imports.
55
+ Find past conversations by keyword, then once for the specific messages needed fetch messages. Threads span all sources: this tool, other AI tools, browser capture, imports.
56
56
 
57
57
  ## Startup Context (nowledge_mem_context)
58
58
 
@@ -63,3 +63,9 @@ Read Context Bundle when identity, active space, active rules, or current priori
63
63
  - Search uses natural language queries, not file paths. Never search for "MEMORY.md" or "memory/*.md".
64
64
  - When `relatedThreads` appear in results, they often contain the most useful context.
65
65
  - Use tools directly; do not tell the user to "check your memory."
66
+
67
+ ### Bounded thread reads
68
+
69
+ Search memories or threads first, then choose the specific conversation and message range needed. Call `thread_fetch_messages`, a host thread-fetch tool, or `nmem --json t show` at most once per question, using a small message limit (for example 8) and a content limit of 1200 where supported. A known target range may use a nonzero offset once.
70
+
71
+ Never loop over offsets to reconstruct a conversation. Do not raise `--content-limit` to compensate for a slow or incomplete read. Small output limits do not guarantee cheap server-side work on every deployed backend. If a read is slow, incomplete, fails or times out, stop, report the evidence gap, and refine the search rather than retrying pages. A later explicit user request for another range is a new bounded read; a routine “continue” is not permission to drain the thread.
package/src/client.js CHANGED
@@ -968,8 +968,8 @@ export class NowledgeMemClient {
968
968
  }
969
969
 
970
970
  /**
971
- * Fetch full messages from a specific thread.
972
- * Supports pagination for progressive retrieval of long conversations.
971
+ * Read one small targeted message range from a specific thread.
972
+ * A known target offset is supported; do not walk offsets to reconstruct a conversation.
973
973
  *
974
974
  * Uses CLI: `nmem --json t show <id> -n N --offset O`
975
975
  * Falls back to API: GET /threads/{id}
@@ -977,13 +977,13 @@ export class NowledgeMemClient {
977
977
  * @param {string} threadId Thread ID
978
978
  * @param {{ offset?: number; limit?: number }} [options]
979
979
  */
980
- async fetchThread(threadId, { offset = 0, limit = 50 } = {}) {
980
+ async fetchThread(threadId, { offset = 0, limit = 8 } = {}) {
981
981
  const id = String(threadId || "").trim();
982
982
  if (!id) throw new Error("fetchThread requires threadId");
983
983
 
984
984
  const normalizedLimit = Math.min(
985
985
  200,
986
- Math.max(1, Math.trunc(Number(limit) || 50)),
986
+ Math.max(1, Math.trunc(Number(limit) || 8)),
987
987
  );
988
988
  const normalizedOffset = Math.max(0, Math.trunc(Number(offset) || 0));
989
989
 
@@ -17,11 +17,13 @@
17
17
 
18
18
  import { ceState } from "../ce-state.js";
19
19
 
20
+ const THREAD_READ_GUIDANCE = "When results include a sourceThreadId, use nowledge_mem_thread_fetch for at most one small targeted message range per question (for example 8 messages). Never loop over offsets or increase content limits. If the read is slow, incomplete or fails, stop, report the evidence gap and refine search.";
21
+
20
22
  export const BASE_GUIDANCE = [
21
23
  "<nowledge-mem-guidance>",
22
24
  "You have access to the user's personal knowledge graph (Nowledge Mem).",
23
25
  "Search proactively with memory_search when past context would improve your answer. Do not wait to be asked. Use natural language queries, not file paths.",
24
- "When results include a sourceThreadId, use nowledge_mem_thread_fetch for full conversation context.",
26
+ THREAD_READ_GUIDANCE,
25
27
  "Save autonomously with nowledge_mem_save when the conversation produces a decision, preference, plan, procedure, or learning. Do not wait to be asked.",
26
28
  "</nowledge-mem-guidance>",
27
29
  ].join("\n");
@@ -31,7 +33,7 @@ export const SESSION_CONTEXT_GUIDANCE = [
31
33
  "You have access to the user's personal knowledge graph (Nowledge Mem).",
32
34
  "Relevant memories and your Working Memory have already been injected into this prompt.",
33
35
  "Use memory_search for specifics beyond what was auto-recalled, or when the user references prior work not covered above. Natural language queries, not file paths.",
34
- "When results include a sourceThreadId, use nowledge_mem_thread_fetch for full conversation context.",
36
+ THREAD_READ_GUIDANCE,
35
37
  "Save autonomously with nowledge_mem_save when the conversation produces a decision, preference, plan, procedure, or learning. Do not wait to be asked.",
36
38
  "</nowledge-mem-guidance>",
37
39
  ].join("\n");
@@ -20,6 +20,7 @@ export function createMemorySearchTool(client, logger) {
20
20
  "Uses multi-signal scoring: semantic, BM25 keyword, label, graph & community signals, recency/importance decay. " +
21
21
  "Returns snippets with memoryIds — pass a memoryId to nowledge_mem_connections for cross-topic synthesis or source provenance. " +
22
22
  "Also returns relevant past conversation snippets (relatedThreads) when available. " +
23
+ "Use a matched messageIndex, when present, to choose one small targeted thread range; never walk offsets or invent missing positions. " +
23
24
  "Supports bi-temporal filtering: event_date_from/to (when the fact HAPPENED), recorded_date_from/to (when it was SAVED). " +
24
25
  "For browsing recent activity by day use nowledge_mem_timeline instead.",
25
26
  parameters: {
@@ -163,6 +164,8 @@ export function createMemorySearchTool(client, logger) {
163
164
  matchedMessages: msgs.map((m) => ({
164
165
  role: m.role,
165
166
  snippet: truncateSnippet(m.snippet, 200),
167
+ ...(Number.isInteger(m.message_index) && m.message_index >= 0
168
+ ? { messageIndex: m.message_index } : {}),
166
169
  })),
167
170
  };
168
171
  });
@@ -2,11 +2,11 @@ export function createThreadFetchTool(client, logger) {
2
2
  return {
3
3
  name: "nowledge_mem_thread_fetch",
4
4
  description:
5
- "Fetch full messages from a conversation thread. Use to read the complete context " +
5
+ "Fetch a targeted range of messages from a conversation thread. Use to read context " +
6
6
  "around a memory — pass the sourceThreadId from memory_search or memory_get results, " +
7
7
  "or a threadId from nowledge_mem_thread_search. " +
8
- "Supports pagination for long conversations: set offset to skip earlier messages. " +
9
- "Useful for progressive retrieval — fetch the first page, then request more if needed.",
8
+ "Use a known target offset to skip earlier messages once. " +
9
+ "Search first, then fetch at most one small targeted message range per question. Never loop over offsets to reconstruct a conversation or increase content limits. If the read is slow, incomplete or fails, stop, report the evidence gap and refine search.",
10
10
  parameters: {
11
11
  type: "object",
12
12
  properties: {
@@ -17,11 +17,11 @@ export function createThreadFetchTool(client, logger) {
17
17
  },
18
18
  offset: {
19
19
  type: "number",
20
- description: "Skip first N messages (for pagination, default 0)",
20
+ description: "Known target message offset (default 0); never walk successive pages",
21
21
  },
22
22
  limit: {
23
23
  type: "number",
24
- description: "Max messages to return (1-200, default 50)",
24
+ description: "Max messages to return (1-200, default 8)",
25
25
  },
26
26
  },
27
27
  required: ["threadId"],
@@ -35,7 +35,7 @@ export function createThreadFetchTool(client, logger) {
35
35
  );
36
36
  const limit = Math.min(
37
37
  200,
38
- Math.max(1, Math.trunc(Number(safeParams.limit ?? 50) || 50)),
38
+ Math.max(1, Math.trunc(Number(safeParams.limit ?? 8) || 8)),
39
39
  );
40
40
 
41
41
  if (!threadId) {
@@ -10,10 +10,12 @@ export function createThreadSearchTool(client, logger) {
10
10
  name: "nowledge_mem_thread_search",
11
11
  description:
12
12
  "Search past conversations by keyword. Use when the user asks about a past discussion, " +
13
- "wants to find a conversation from a specific time, or when you want to explore the full context " +
13
+ "wants to find a conversation from a specific time, or when you want to find relevant source messages " +
14
14
  "around a topic beyond what memory_search returned. " +
15
15
  "Returns matched threads with message snippets and relevance scores. " +
16
- "To read full messages from a thread, pass its threadId to nowledge_mem_thread_fetch.",
16
+ "A match's messageIndex, when present, identifies a target offset for a nearby range; do not invent positions when absent. " +
17
+ "Pass its threadId to nowledge_mem_thread_fetch for at most one small targeted message range per question. " +
18
+ "Never loop over offsets; on slow, incomplete or failed reads, report the evidence gap and refine search.",
17
19
  parameters: {
18
20
  type: "object",
19
21
  properties: {
@@ -74,6 +76,8 @@ export function createThreadSearchTool(client, logger) {
74
76
  matchedMessages: msgs.map((m) => ({
75
77
  role: m.role,
76
78
  snippet: truncateSnippet(m.snippet),
79
+ ...(Number.isInteger(m.message_index) && m.message_index >= 0
80
+ ? { messageIndex: m.message_index } : {}),
77
81
  })),
78
82
  };
79
83
  });