@unblocklabs/unblock-memory 0.3.22 → 0.3.24
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/README.md +86 -967
- package/dist/src/config.js +2 -2
- package/dist/src/contracts.d.ts +5 -3
- package/dist/src/diagnostics.d.ts +31 -4
- package/dist/src/diagnostics.js +13 -3
- package/dist/src/manager.d.ts +27 -1
- package/dist/src/manager.js +42 -7
- package/dist/src/memory-whisperer.js +24 -10
- package/dist/src/people-store.d.ts +37 -3
- package/dist/src/people-store.js +23 -9
- package/dist/src/people-tools.js +5 -5
- package/dist/src/plugin.js +31 -35
- package/dist/src/retrieval-telemetry.d.ts +39 -0
- package/dist/src/retrieval-telemetry.js +40 -0
- package/dist/src/session-projector.d.ts +32 -1
- package/dist/src/session-projector.js +84 -12
- package/dist/src/session-sync.d.ts +3 -2
- package/dist/src/session-sync.js +7 -5
- package/dist/src/slack-directory.js +3 -2
- package/dist/src/typesafe-review.d.ts +1 -2
- package/dist/src/typesafe-review.js +3 -11
- package/dist/src/typesafe-transport.d.ts +10 -0
- package/dist/src/typesafe-transport.js +26 -0
- package/dist/src/typesafe.d.ts +1 -1
- package/dist/src/typesafe.js +27 -62
- package/docs/configuration.md +381 -0
- package/docs/peoplesql.md +223 -0
- package/docs/response-audit.md +217 -0
- package/docs/retrieval.md +607 -0
- package/openclaw.plugin.json +10 -8
- package/package.json +7 -2
- package/skills/memory-curator/SKILL.md +5 -0
- package/skills/people-whisperer/SKILL.md +10 -0
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
# Retrieval, whisperers and maintenance
|
|
2
|
+
|
|
3
|
+
[Overview](../README.md) · [Configuration and credentials](configuration.md)
|
|
4
|
+
|
|
5
|
+
## Search and read
|
|
6
|
+
|
|
7
|
+
`memory_search` searches every configured **non-skill** corpus for this agent by
|
|
8
|
+
default. Select named corpora, or use `["all"]` alone. An empty list or unknown
|
|
9
|
+
name is an error. Default: **5 results**, vector `minScore: 0.3`; configurable
|
|
10
|
+
`maxResults` is 1–20 and `minScore` is 0–1. No TypeSafe, BM25, query expansion
|
|
11
|
+
or reranker runs in this tool.
|
|
12
|
+
|
|
13
|
+
Example tool input (the `memory` corpus exists by default):
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{ "query": "Who approved the staging rollout?", "corpora": ["memory"], "maxResults": 5 }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Results use compact JSON and carry `path`, `startLine`, `endLine`, `snippet`,
|
|
20
|
+
`corpus`, and `score`/`vectorScore` rounded to hundredths. Ranking and threshold
|
|
21
|
+
filtering still use full precision. The constant `source` and top-level `provider`
|
|
22
|
+
fields are omitted; `path` plus line numbers replace the redundant `citation`.
|
|
23
|
+
Session hits also carry session metadata and, when available,
|
|
24
|
+
`messageTimestamp`: the original timestamp text (including timezone) of the message
|
|
25
|
+
containing the matched chunk. It stays tied to that message even when the excerpt
|
|
26
|
+
expands to the surrounding turn. Missing timestamps are omitted, not replaced by
|
|
27
|
+
session start time. Vector similarity is a retrieval signal, not confidence in
|
|
28
|
+
the truth of a claim.
|
|
29
|
+
|
|
30
|
+
Session `snippet` values are arrays of messages, in source order:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
[{ "type": "assistant", "name": "Bill", "timestamp": "2026-08-17 15:40:09 EDT", "body": "**Original message text**, including Markdown." }]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Each message has its own timestamp. Only generated transcript headings are removed;
|
|
37
|
+
body formatting, code, mentions and HTML entities are preserved. `partial: true`
|
|
38
|
+
means the returned body is an excerpt, not the complete message. Metadata is resolved
|
|
39
|
+
from the full indexed document even when a chunk starts mid-message. Assistant agent
|
|
40
|
+
IDs are mapped to the configured identity name when available; other names are kept.
|
|
41
|
+
Unattributable legacy text is retained as `{ "body": "…", "partial": true }`, without
|
|
42
|
+
inventing a role, name or timestamp. File-backed snippets remain strings.
|
|
43
|
+
`memory_get` still returns indexed Markdown, and internal search/Whisperer contracts
|
|
44
|
+
still use strings. This changes output structure, not retrieval ranking.
|
|
45
|
+
|
|
46
|
+
Read the **returned** path, substituting its actual source/line values:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{ "path": "qmd://source-RETURNED_ID/memory/example.md", "from": 12, "lines": 40 }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`memory_get` reads the indexed snapshot, not arbitrary filesystem paths or QMD
|
|
53
|
+
docids. It accepts exact configured `qmd://` paths, excludes skills, defaults to
|
|
54
|
+
120 lines and bounds content to 12,000 characters. `from` is 1-based; requested
|
|
55
|
+
`lines` is 1–1,000. `status: "ok"` can still have `truncated: true`: use
|
|
56
|
+
`nextFrom` to continue when present. A single oversized line can be clipped
|
|
57
|
+
without a continuation line; inspect the authorized original source if that
|
|
58
|
+
complete line matters. `not_found` and `unavailable` are not successful empty reads.
|
|
59
|
+
|
|
60
|
+
Search snippets are leads. Inspect attribution, qualifications, dates and adjacent
|
|
61
|
+
context before relying on a factual claim. An old plan is not proof it happened,
|
|
62
|
+
and memory does not grant permission to act. No results may mean the wrong corpus,
|
|
63
|
+
a high threshold, an unsynced session or an unavailable index—not absence of the fact.
|
|
64
|
+
Search initialization errors include an `error` alongside empty `results`;
|
|
65
|
+
other failures may surface as tool errors. Investigate them instead of reporting
|
|
66
|
+
“nothing is remembered.”
|
|
67
|
+
|
|
68
|
+
Corpora and session filters select evidence; they are not audience ACLs. Normal
|
|
69
|
+
tools can access this agent's configured non-skill corpora, not just its current
|
|
70
|
+
chat. Only index material suitable for the agent's tool callers. Per-feature
|
|
71
|
+
TypeSafe allowlists do not restrict ordinary retrieval.
|
|
72
|
+
|
|
73
|
+
## QMD search modes
|
|
74
|
+
|
|
75
|
+
The following describes QMD's TypeSafe-ranked `query` API (2.10+). Use the exact
|
|
76
|
+
dependency in the installed plugin's package metadata when diagnosing an older
|
|
77
|
+
installation.
|
|
78
|
+
|
|
79
|
+
| Surface | Retrieval/ranking | Score / useful distinction |
|
|
80
|
+
| --- | --- | --- |
|
|
81
|
+
| Plugin `memory_search` | Direct vector search, expansion off | Vector similarity; ordinary agent recall |
|
|
82
|
+
| QMD CLI `search` / SDK `searchLex` | Local BM25 | Normalized lexical relevance; useful for names, identifiers and exact phrases |
|
|
83
|
+
| QMD CLI/SDK `vsearch` | Local vectors; standalone default includes local query expansion | Vector similarity; `--no-expand` / `expand:false` selects literal retrieval |
|
|
84
|
+
| QMD CLI/MCP `query` / SDK `search` | Literal vectors + BM25, deduplicated source excerpts, independent TypeSafe usefulness ranking | Usefulness divided by 3, not cosine similarity; default limit 10/minScore 0 |
|
|
85
|
+
| QMD `query --no-rerank` / SDK/MCP `rerank:false` | Local retrieval, best reciprocal retrieval-rank ordering | 1 / rank; explicitly skips remote scoring |
|
|
86
|
+
|
|
87
|
+
Plain `query` takes `ceil(1.5 × limit)` candidates per backend, without local
|
|
88
|
+
expansion or local reranking. Explicit `lex`/`vec`/`hyde` variants share the
|
|
89
|
+
TypeSafe ranking policy by default. A supplied hypothetical `hyde` passage is
|
|
90
|
+
a retrieval input, not evidence. Scores across modes are not interchangeable.
|
|
91
|
+
|
|
92
|
+
**Migration:** Memory 0.3.22 removed the temporary `memory_xsearch` tool. QMD's
|
|
93
|
+
`query` provides that hybrid retrieval/ranking functionality; there is no plugin
|
|
94
|
+
`memory_query`, and `memory_search` did not become hybrid.
|
|
95
|
+
|
|
96
|
+
Standalone QMD is a separate entry point. Its project/named/global index is not
|
|
97
|
+
automatically this agent's `unblock-memory/index.sqlite`. Plugin corpus names
|
|
98
|
+
also are not QMD collection IDs: each configured path maps to a `source-<hash>`
|
|
99
|
+
collection, and a corpus can contain several. Establish the intended index,
|
|
100
|
+
collection scope and installed QMD version before using CLI/MCP as an alternative.
|
|
101
|
+
Do not run standalone collection/update/embed maintenance against a live
|
|
102
|
+
plugin-managed index as a casual search fallback.
|
|
103
|
+
|
|
104
|
+
QMD CLI/MCP read `TYPESAFE_API_KEY` or `TYPESAFE_API_KEY_FILE` from their own
|
|
105
|
+
process; SDK callers can supply credentials. Plugin `typesafe.apiKeyFile` does
|
|
106
|
+
not export a key to those processes. Ranked query sends the query, intent,
|
|
107
|
+
selected excerpts, source paths and evaluation time to TypeSafe. Missing keys or
|
|
108
|
+
scoring failures return errors, not vector fallback or a successful empty answer.
|
|
109
|
+
Use an explicitly local mode when appropriate.
|
|
110
|
+
|
|
111
|
+
See the [QMD guide](https://github.com/unblocklabs-ai/qmd#readme) for CLI/MCP syntax.
|
|
112
|
+
Private skill frontmatter retrieval and response-audit lexical investigations are
|
|
113
|
+
internal workflows, not extra public plugin search modes.
|
|
114
|
+
|
|
115
|
+
## Sessions
|
|
116
|
+
|
|
117
|
+
Add a `sessions` entry alongside `memory` in your configured corpora (see the
|
|
118
|
+
[session profile](configuration.md#example-profiles)). Start a manual refresh with
|
|
119
|
+
`memory_sync_sessions({})`, then poll `memory_sync_status({})` until completed
|
|
120
|
+
or failed. `started` / `already_running` only acknowledge background work.
|
|
121
|
+
Check completion counts, including per-session failures, before assuming freshness.
|
|
122
|
+
|
|
123
|
+
Use `sessionFilter` to restrict session results by metadata while leaving file
|
|
124
|
+
corpora searchable. Supported fields are `startedFrom` and `startedTo`
|
|
125
|
+
(inclusive ISO 8601 timestamps), `provider`, `chatType`, `accountId`, and
|
|
126
|
+
`conversationId`:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"query": "deployment decision",
|
|
131
|
+
"sessionFilter": {
|
|
132
|
+
"startedFrom": "2026-08-01T00:00:00Z",
|
|
133
|
+
"provider": "slack",
|
|
134
|
+
"chatType": "channel"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Provider matching is case-normalized; `chatType` uses the lowercase values
|
|
140
|
+
shown in the configuration example. Account and conversation IDs are trimmed
|
|
141
|
+
and matched exactly. When only `sessions` is selected and no sessions match,
|
|
142
|
+
search returns no results. With other corpora selected, their results remain
|
|
143
|
+
eligible.
|
|
144
|
+
|
|
145
|
+
The date bounds remain inclusive **session start times**; `messageTimestamp`
|
|
146
|
+
dates the matched message but is not a search filter. These metadata filters
|
|
147
|
+
do not change the selected file corpora or authorize disclosure to another audience.
|
|
148
|
+
|
|
149
|
+
The optional `sessions` corpus reads the current agent's normal OpenClaw SQLite
|
|
150
|
+
store and indexes its active user/assistant transcript branch. It defaults to
|
|
151
|
+
channel and group conversations; add `direct` explicitly to include DMs. A
|
|
152
|
+
session vector hit expands to its complete user/assistant turn when the turn
|
|
153
|
+
fits `maxExpandedTokens`, or to its complete enclosing message when only that
|
|
154
|
+
fits. The default is `500`; the original semantic chunk is preserved when
|
|
155
|
+
neither complete context fits, so expansion never clips the matched evidence.
|
|
156
|
+
Run
|
|
157
|
+
`memory_sync_sessions` to start a refresh, then use `memory_sync_status` to
|
|
158
|
+
check its progress or result. The read-only adapter explicitly supports OpenClaw
|
|
159
|
+
agent database schemas 17, 18, and 19 and validates its required columns before
|
|
160
|
+
reading. Projections are private derived Markdown under the
|
|
161
|
+
agent's `unblock-memory/sessions` state directory and can be rebuilt from
|
|
162
|
+
OpenClaw at any time. Their embedded text contains only `# Transcript` and
|
|
163
|
+
role-labeled, timestamped speaker messages; filtering metadata remains in the
|
|
164
|
+
session manifest. Projection v7 also retains message metadata and exact character
|
|
165
|
+
boundaries there, without duplicating message bodies. Readers use those boundaries
|
|
166
|
+
only when the projection hash matches the indexed document. Older/mismatched snapshots
|
|
167
|
+
use a conservative heading parser that skips code fences and blockquotes; an unfenced
|
|
168
|
+
literal heading can still be ambiguous until the next session refresh rebuilds the
|
|
169
|
+
metadata. The projected file modification time matches the session
|
|
170
|
+
start time for meaningful chronological cluster reads. Session results include
|
|
171
|
+
provider, chat type, conversation identity, and start time as an ISO 8601 timestamp. They
|
|
172
|
+
participate in the same search and clustering index as file memory. The plugin
|
|
173
|
+
automatically checks each configured agent's sessions every 60 minutes while
|
|
174
|
+
the Gateway runs. Set `syncIntervalMinutes` on the `sessions` corpus to an integer
|
|
175
|
+
from `1` to `1440`, or `0` for manual-only syncing. For example:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{ "name": "sessions", "kind": "sessions", "syncIntervalMinutes": 60 }
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The first refresh runs after one interval, not during startup. Restart the
|
|
182
|
+
Gateway after changing the interval. Refreshes are incremental; an already-running
|
|
183
|
+
sync is skipped, and failures are visible through `memory_sync_status` and retried
|
|
184
|
+
at the next interval. `memory_sync_sessions` still provides an immediate manual
|
|
185
|
+
refresh. Syncing and embedding run inside the Gateway process, without an LLM turn.
|
|
186
|
+
|
|
187
|
+
Quiet checks compare source metadata and the last successful index checkpoint
|
|
188
|
+
before initializing the memory manager. Unchanged sessions skip QMD updates and
|
|
189
|
+
embedding. New assistant answers count too, not just human messages. Changed
|
|
190
|
+
transcripts are projected and content-hashed; tool-only or filtered additions
|
|
191
|
+
that leave the indexed text unchanged also skip indexing. Empty/filtered sessions
|
|
192
|
+
are remembered. Index changes, missing projections, changed projection settings,
|
|
193
|
+
QMD upgrades and incomplete runs invalidate the skip checkpoint; `force: true`
|
|
194
|
+
bypasses both gates. `memory_sync_status` reports `lastCheckedAt`, `lastIndexedAt`
|
|
195
|
+
and `skipReason` (`no_changes` or `no_indexable_changes`) separately. Existing
|
|
196
|
+
explicit intervals remain unchanged on upgrade; set them to `60` for hourly checks.
|
|
197
|
+
|
|
198
|
+
Indexes live at `~/.openclaw/agents/<agentId>/unblock-memory/index.sqlite` (or the
|
|
199
|
+
equivalent configured OpenClaw state directory). Durable agent-supplied event
|
|
200
|
+
dates, maintenance proposals, people/dossiers and response audits live separately
|
|
201
|
+
in `unblock-memory.sqlite`, so a QMD
|
|
202
|
+
index rebuild does not discard them. The first lookup builds the index;
|
|
203
|
+
Markdown filesystem changes queue a debounced, serialized background refresh.
|
|
204
|
+
|
|
205
|
+
### Loggie meeting interoperability
|
|
206
|
+
|
|
207
|
+
Loggie v0.1.12+ persists versioned, speaker-attributed meeting Markdown separately
|
|
208
|
+
from its workflow prompt. Session projection recognizes that format and also
|
|
209
|
+
normalizes complete legacy Loggie JSON envelopes. Unrecognized, malformed or
|
|
210
|
+
truncated legacy payloads keep their original text; source sessions are never
|
|
211
|
+
rewritten. Summaries remain labeled as generated material, distinct from speech.
|
|
212
|
+
|
|
213
|
+
QMD groups adjacent speaker blocks rather than forcing one chunk per speaker.
|
|
214
|
+
Search expands around the matching exchange within its existing budget. Long
|
|
215
|
+
monologue excerpts regain the source speaker label while citations still point
|
|
216
|
+
to the exact original source lines. No identity or timestamp is invented.
|
|
217
|
+
|
|
218
|
+
Within a session, identical replayed transcripts are suppressed; distinct
|
|
219
|
+
complete revisions with ordered source sequence numbers retain their history
|
|
220
|
+
and assistant follow-ups, with older versions marked superseded. Account,
|
|
221
|
+
workspace, meeting and external transcript identifiers scope the comparison.
|
|
222
|
+
Ambiguous/partial revisions are preserved. Separate session windows are not
|
|
223
|
+
globally deduplicated.
|
|
224
|
+
|
|
225
|
+
Use the session projection as the searchable meeting copy. Loggie raw archives
|
|
226
|
+
remain opt-in and should stay outside file-corpus globs (new default:
|
|
227
|
+
`transcripts/loggie-archive`). Memory never follows archive paths embedded in
|
|
228
|
+
messages. Truncated sessions stay explicitly incomplete; enabling archive
|
|
229
|
+
enrichment is not part of this version.
|
|
230
|
+
|
|
231
|
+
### Conservative ingestion cleanup
|
|
232
|
+
|
|
233
|
+
Session projections unwrap complete, recognized task/attachment envelopes while
|
|
234
|
+
keeping the actual result, task/status, filename, MIME type, and untrusted-content
|
|
235
|
+
label. Internal task cleanup requires structured inter-session provenance, not
|
|
236
|
+
just matching text. Unknown formats, malformed envelopes, and code examples stay
|
|
237
|
+
intact. Assistant messages and Loggie's separate projection path are unaffected.
|
|
238
|
+
Raw session events and workspace memory files are never rewritten.
|
|
239
|
+
Attachment matching has a fixed work budget; oversized or repeatedly nested/
|
|
240
|
+
incomplete envelopes leave the entire message unchanged rather than blocking sync.
|
|
241
|
+
|
|
242
|
+
The companion QMD semantic-chunking update skips only source-confirmed standalone
|
|
243
|
+
REM heading/marker spans and orphan closing fences. Reflections and useful text
|
|
244
|
+
remain searchable, with original source offsets. These are deterministic rules,
|
|
245
|
+
not TypeSafe judgments; audit flags never authorize automatic memory deletion.
|
|
246
|
+
|
|
247
|
+
The plugin installs its exact release-pinned QMD dependency (see
|
|
248
|
+
[package metadata](../package.json)). Projector/chunker version changes refresh derived
|
|
249
|
+
projections and embeddings on their next normal sync; the first sync may take
|
|
250
|
+
longer while re-embedding. No manual deletion of source memories or review tasks
|
|
251
|
+
is needed.
|
|
252
|
+
|
|
253
|
+
## Memory Whisperer
|
|
254
|
+
|
|
255
|
+
Memory Whisperer is optional and **off by default**. It proactively retrieves
|
|
256
|
+
historical context before user-triggered turns, without changing `memory_search`
|
|
257
|
+
or `memory_get`. Enable it in the plugin config with an explicit corpus allowlist:
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{
|
|
261
|
+
"memoryWhisperer": {
|
|
262
|
+
"enabled": true,
|
|
263
|
+
"corpora": ["knowledge"],
|
|
264
|
+
"historyMessages": 5,
|
|
265
|
+
"minUsefulness": 0.7,
|
|
266
|
+
"maxHints": 2,
|
|
267
|
+
"cooldownTurns": 10,
|
|
268
|
+
"timeoutMs": 3000
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Requires `hooks.allowConversationAccess: true` on the plugin entry, prompt
|
|
274
|
+
injection permission, and [shared TypeSafe credentials](configuration.md#shared-typesafe-credentials).
|
|
275
|
+
An empty allowlist is invalid when enabled; `all`, unknown names, and `skills`
|
|
276
|
+
are not accepted. When `sessions` is enabled for Memory Whisperer, automatic recall
|
|
277
|
+
can retrieve across this agent's indexed sessions. The sessions corpus's `chatTypes`
|
|
278
|
+
setting controls whether direct messages are included; no additional session-scope
|
|
279
|
+
toggle is required. Selected excerpts are sent to TypeSafe and may be injected into
|
|
280
|
+
any conversation using this agent. Session availability still depends on the normal
|
|
281
|
+
indexing/sync schedule.
|
|
282
|
+
|
|
283
|
+
The example is a plugin config fragment; `knowledge` must already be configured.
|
|
284
|
+
For a complete corpus example, use the [configuration profiles](configuration.md#example-profiles).
|
|
285
|
+
|
|
286
|
+
QMD searches the current request plus the last N user/assistant messages (at most
|
|
287
|
+
12,000 characters), retrieving up to eight vector candidates without query expansion,
|
|
288
|
+
the local reranker, or a similarity-score cutoff. TypeSafe evaluates one independent
|
|
289
|
+
Noul question per candidate in a single request: does the excerpt add material value
|
|
290
|
+
beyond what the conversation already contains? Merely related, redundant,
|
|
291
|
+
wrong-person/project, and clearly superseded information should be rejected;
|
|
292
|
+
useful contradictory evidence can qualify. `minUsefulness` defaults to `0.7` and
|
|
293
|
+
thresholds the probability of yes, not a calibrated guarantee of accuracy.
|
|
294
|
+
Explicit configured thresholds are preserved. Evaluate it on your own conversations.
|
|
295
|
+
|
|
296
|
+
**Privacy and budgets:** this feature sends up to 16,000 characters of the available
|
|
297
|
+
user/assistant conversation, prioritizing the current request and recent messages,
|
|
298
|
+
plus up to eight 1,200-character excerpts, corpus names, and matched-message timestamps
|
|
299
|
+
when available to `api.typesafe.ai`. The same `messageTimestamp` accompanies the
|
|
300
|
+
injected hint: it records when something was said, without inferring event dates.
|
|
301
|
+
Session excerpts retain a complete turn or message when it fits,
|
|
302
|
+
otherwise the complete matched chunk. Chunks exceeding the excerpt budget are
|
|
303
|
+
skipped, never sliced; ordinary `memory_search` is unchanged.
|
|
304
|
+
It does not fetch a complete historical transcript; the host may
|
|
305
|
+
already have compacted the available context. Truncation is marked in the judge's
|
|
306
|
+
input. System messages, thinking blocks, images, and tool-result messages are omitted;
|
|
307
|
+
anything quoted in ordinary user/assistant text can still be transmitted.
|
|
308
|
+
|
|
309
|
+
At most two qualifying excerpts are injected verbatim with source references and
|
|
310
|
+
historical/untrusted-data framing. Excerpts are deduplicated by normalized content
|
|
311
|
+
and overlapping source lines; recently injected content has a ten-user-turn cooldown
|
|
312
|
+
by default. Cooldown state is in memory and resets on session end or Gateway restart.
|
|
313
|
+
The complete hint payload is capped at 5,000 characters plus a short framing paragraph.
|
|
314
|
+
|
|
315
|
+
Unlike Skill Whisperer, **disabled TypeSafe, a missing key, no qualifying hits, or any
|
|
316
|
+
failure means no memory hint**—there is no vector-only fallback. The overall process
|
|
317
|
+
has a 3-second deadline, with the shared 1.5-second TypeSafe request deadline inside it;
|
|
318
|
+
neither performs retries. Timed-out or superseded runs cannot inject late hints.
|
|
319
|
+
Already-running local QMD work may finish in the background, but does not keep the
|
|
320
|
+
agent waiting beyond the deadline. No new indexing, clustering, or summarization runs
|
|
321
|
+
are triggered by this feature beyond the memory manager's normal initialization.
|
|
322
|
+
|
|
323
|
+
## Skill Whisperer
|
|
324
|
+
|
|
325
|
+
Skill Whisperer is an optional semantic reminder for user turns. Configure one
|
|
326
|
+
isolated `skills` corpus, set `skillWhisperer.enabled` to `true`, and authorize
|
|
327
|
+
`plugins.entries.unblock-memory.hooks.allowConversationAccess`. The feature
|
|
328
|
+
embeds the current prompt plus the configured number of prior user/assistant
|
|
329
|
+
messages, compares it with each configured skill's frontmatter `name` and
|
|
330
|
+
`description`. With TypeSafe enabled and a key available, the top three valid
|
|
331
|
+
candidates are sent to TypeSafe, without a vector-score cutoff. TypeSafe chooses
|
|
332
|
+
one skill or none. A "none" decision never falls back to a vector hint. Full skill
|
|
333
|
+
procedures do not influence routing; no skill is invoked automatically.
|
|
334
|
+
|
|
335
|
+
See [shared TypeSafe credentials](configuration.md#shared-typesafe-credentials) for key setup,
|
|
336
|
+
rotation and the `enabled: true` / `timeoutMs: 1500` defaults.
|
|
337
|
+
|
|
338
|
+
If TypeSafe is disabled or no key is found, selection uses the original local
|
|
339
|
+
vector process and `skillWhisperer.minScore`. With a key present, an API error,
|
|
340
|
+
invalid response, or timeout emits no hint and logs a sanitized warning; it does
|
|
341
|
+
not switch to vector-only selection. There are no automatic HTTP retries. Other
|
|
342
|
+
credential-file read errors likewise produce a warning and no hint.
|
|
343
|
+
|
|
344
|
+
**Privacy:** enabled TypeSafe selection sends up to 12,000 characters of current
|
|
345
|
+
prompt/recent user-assistant text, plus the shortlisted names/descriptions, to
|
|
346
|
+
`api.typesafe.ai`. Source-path fields, full skill procedures, tool-result messages,
|
|
347
|
+
and system messages are excluded; dossiers and ordinary memory files are not read
|
|
348
|
+
for this call. Material already quoted in user/assistant text can still be included.
|
|
349
|
+
Disable `typesafe.enabled` to keep Skill Whisperer entirely local. The pinned model
|
|
350
|
+
is `jev-1.13.0`.
|
|
351
|
+
|
|
352
|
+
The defaults use five prior messages, a vector-only score threshold of `0.5`,
|
|
353
|
+
and a ten-turn cooldown. A skill is cooling down after either a suggestion or a
|
|
354
|
+
successful direct `read` of its indexed `SKILL.md`. When the selected
|
|
355
|
+
skill is cooling down, no hint is emitted; Skill Whisperer does not fall through
|
|
356
|
+
to a weaker match. Cooldown state is per session and intentionally resets with
|
|
357
|
+
the Gateway. Shell-command reads are not tracked.
|
|
358
|
+
|
|
359
|
+
The `skills` corpus shares the existing QMD store and warm embedding model but
|
|
360
|
+
is private to Skill Whisperer: it is excluded from ordinary `memory_search`
|
|
361
|
+
(including `corpora: ["all"]`), `memory_get`, clustering, and memory-maintenance
|
|
362
|
+
tasks. Paths are explicit by design; the plugin does not reconstruct
|
|
363
|
+
OpenClaw's effective skill inventory from `openclaw.json`. Configured skill
|
|
364
|
+
globs follow symlinked directories, including OpenClaw's `plugin-skills`
|
|
365
|
+
directory.
|
|
366
|
+
|
|
367
|
+
## Review and diagnostics
|
|
368
|
+
|
|
369
|
+
- `memory_diagnostics` reports credential **availability only**, per-agent process-local
|
|
370
|
+
whisperer counters, projection version, old indexed-session projection count, and
|
|
371
|
+
embedding readiness. Counters are bounded to 100 agents and reset on restart.
|
|
372
|
+
This is not a complete people/response feature-status report; it makes no TypeSafe
|
|
373
|
+
request, but can initialize the memory manager/index on first use.
|
|
374
|
+
No prompts, excerpts, paths, keys, or provider error bodies enter these counters.
|
|
375
|
+
Parser cleanup/budget-skip counts are persisted with the latest completed
|
|
376
|
+
`memory_sync_status`; unchanged sessions are not counted again. QMD structural
|
|
377
|
+
omission counts cover this manager's embedding passes, not the whole corpus.
|
|
378
|
+
- Quality-audit groups distinguish `preserve_evidence_repair`, `inspect_scaffolding`,
|
|
379
|
+
and `context_review`, reusing cached noise/evidence judgments without another call.
|
|
380
|
+
Evidence-preserving repair tasks sort first. Maintenance tasks expose indexed
|
|
381
|
+
fingerprint presence; `not_present_in_index` is **not** a verified repair and
|
|
382
|
+
never resolves or deletes the task. Chunk boundaries may simply have changed.
|
|
383
|
+
- `memory_review_cluster` uses the existing `qualityAudit` opt-in/corpus allowlist.
|
|
384
|
+
It judges up to three representative and three low-membership members, deduplicates
|
|
385
|
+
the sample, and skips unapproved or >2,000-character chunks whole. Repeated defect
|
|
386
|
+
labels are investigation leads only. Stale/changed samples are rejected; useful
|
|
387
|
+
or uncertain members are retained. No tasks or sources are modified.
|
|
388
|
+
- `memory_review_claim` accepts one atomic claim (up to 2,000 characters) and 1–3
|
|
389
|
+
citations `{path, from, lines}`. It reads approved indexed evidence itself (at
|
|
390
|
+
most 6,000 characters), returns supports/contradicts/insufficient_evidence with
|
|
391
|
+
confidence and source hashes, and never writes or authorizes a write. Support
|
|
392
|
+
below 0.9 confidence is marked for review. This threshold is provisional, not a
|
|
393
|
+
guarantee of truth; read original evidence and verify current-state claims.
|
|
394
|
+
|
|
395
|
+
Optional plugin config fragment (corpora must already be configured):
|
|
396
|
+
|
|
397
|
+
```json
|
|
398
|
+
{
|
|
399
|
+
"evidenceReview": { "enabled": true, "corpora": ["memory", "knowledge", "sessions"] },
|
|
400
|
+
"memoryWhisperer": {
|
|
401
|
+
"enabled": true, "corpora": ["memory", "knowledge"], "complementaryHints": true
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
Both additions default off. Claim review sends the proposed claim and approved
|
|
407
|
+
source excerpts to TypeSafe; cluster review sends approved sampled excerpts.
|
|
408
|
+
Complementary hints use one extra bounded call over at most four already-useful
|
|
409
|
+
candidates (six directional comparisons). Only redundancy probability >=0.9
|
|
410
|
+
removes a hint; distinct evidence and contradictions should remain. Provider errors
|
|
411
|
+
retain baseline hints, while the existing total turn deadline/cancellation still
|
|
412
|
+
suppresses late results. Missing keys or disabled TypeSafe never enable these calls.
|
|
413
|
+
The retrieval corpus/session boundaries are unchanged.
|
|
414
|
+
|
|
415
|
+
## Memory quality audit
|
|
416
|
+
|
|
417
|
+
`memory_audit_quality` is an on-demand, source-read-only audit. TypeSafe flags likely
|
|
418
|
+
ingestion noise for agent investigation; it never deletes, rewrites, or suppresses
|
|
419
|
+
memory. Enable it with explicit approval for the corpora sent to TypeSafe:
|
|
420
|
+
|
|
421
|
+
```json
|
|
422
|
+
{
|
|
423
|
+
"qualityAudit": {
|
|
424
|
+
"enabled": true,
|
|
425
|
+
"corpora": ["memory", "knowledge"],
|
|
426
|
+
"minNoise": 0.8
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
This is a plugin config fragment; both corpora must already be configured.
|
|
432
|
+
Off by default. Uses the shared TypeSafe credentials and request timeout. Missing
|
|
433
|
+
credentials or disabled TypeSafe produces no audit. Approval includes transmission
|
|
434
|
+
of full eligible chunks and visibility of findings to all audiences using the agent.
|
|
435
|
+
Unlike Memory Whisperer, approving `sessions` includes **all indexed sessions** in
|
|
436
|
+
that corpus, including configured direct conversations. Only approve that when intended.
|
|
437
|
+
|
|
438
|
+
Call with `{ "limit": 10 }` (maximum 20 indexed chunk occurrences per page), then
|
|
439
|
+
pass the returned `next` as `after` until `done` is true. A `partial` result preserves
|
|
440
|
+
the completed cursor; retry there, or from the beginning if no cursor exists. This
|
|
441
|
+
is not a full-document audit: unindexed content is not scanned. Chunks over 6,000
|
|
442
|
+
characters are counted as skipped, not silently truncated. No clustering is required.
|
|
443
|
+
|
|
444
|
+
Two independent Noul questions distinguish ingestion noise from identifiable useful
|
|
445
|
+
evidence. High values for both can indicate valuable content trapped in a wrapper.
|
|
446
|
+
Low evidence alone does not create a junk finding. JSON, logs, code, terse facts,
|
|
447
|
+
historical records, and missing context are not automatically defects. Empty chunks
|
|
448
|
+
are detected locally. A JSON string that decodes to a message envelope is also
|
|
449
|
+
flagged as a possible double-encoding defect, even when its content is useful.
|
|
450
|
+
An ordinary JSON message object is not flagged from its shape alone. These are
|
|
451
|
+
review clues, never verdicts about whether the information should be kept.
|
|
452
|
+
|
|
453
|
+
At most four unique chunks (24,000 characters) and their source kinds are sent in
|
|
454
|
+
one request, without conversation context or source paths. Requests do not retry
|
|
455
|
+
automatically and stop starting new work after a 30-second audit deadline; existing
|
|
456
|
+
manager initialization/indexing may finish later. Judgments are cached in the
|
|
457
|
+
curation database by content, source kind, model and question version. A rescan from
|
|
458
|
+
the beginning reuses cached results, including after corpus/index changes. Changes
|
|
459
|
+
behind a page cursor are picked up on the next rescan.
|
|
460
|
+
|
|
461
|
+
Suspect chunks become `quality_review` tasks in `memory_list_maintenance_tasks`.
|
|
462
|
+
The audit returns page-local groups by configured source and suspected issue,
|
|
463
|
+
with up to three examples each, not a claim that a whole cluster is defective.
|
|
464
|
+
Findings include source references, bounded previews, probabilities and content
|
|
465
|
+
fingerprints. Reviewed tasks are not reopened for unchanged content. The curator
|
|
466
|
+
inspects the original source and ingestion path, proposes or performs authorized
|
|
467
|
+
repairs, and verifies the resulting source/index before resolving with a required
|
|
468
|
+
note. Prefer repairing a common extractor or inclusion rule over many symptoms;
|
|
469
|
+
never manually edit generated session projections. Thresholds need evaluation on
|
|
470
|
+
your data; model probability is not proof of a defect.
|
|
471
|
+
|
|
472
|
+
## Memory analysis
|
|
473
|
+
|
|
474
|
+
Analysis is opt-in. Core indexing, `memory_search`, and `memory_get` need only
|
|
475
|
+
Unblock Memory and its automatically installed QMD dependency. To enable
|
|
476
|
+
clustering, install the public
|
|
477
|
+
[`unblock-cluster`](https://github.com/unblocklabs-ai/unblock-cluster) worker once
|
|
478
|
+
on the same host:
|
|
479
|
+
|
|
480
|
+
```bash
|
|
481
|
+
git clone https://github.com/unblocklabs-ai/unblock-cluster.git
|
|
482
|
+
cd unblock-cluster
|
|
483
|
+
python3 -m venv .venv
|
|
484
|
+
.venv/bin/python -m pip install -r requirements-analysis.txt
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Set `analysis.executable` to the absolute path of
|
|
488
|
+
`bin/unblock-memory-analysis` in that checkout. One worker installation can
|
|
489
|
+
serve every agent on the host. The plugin invokes it directly with
|
|
490
|
+
`--db <the agent's known index path>`, the plugin's non-skill collection IDs,
|
|
491
|
+
and, when requested, a validated `--config-json <clustering options>` payload.
|
|
492
|
+
Agents cannot choose a database, executable, collection, shell command, or
|
|
493
|
+
arbitrary arguments.
|
|
494
|
+
|
|
495
|
+
Without the worker, `memory_list_clusters` reports that memory has not been
|
|
496
|
+
analyzed and `memory_recluster` reports that analysis is unavailable. Ordinary
|
|
497
|
+
memory search and reads continue to work.
|
|
498
|
+
|
|
499
|
+
The analysis worker reads QMD's existing semantic vectors and writes only
|
|
500
|
+
derived results into four namespaced tables in that same `index.sqlite`:
|
|
501
|
+
|
|
502
|
+
- `memory_analysis_runs`
|
|
503
|
+
- `memory_analysis_clusters`
|
|
504
|
+
- `memory_analysis_memberships`
|
|
505
|
+
- `memory_analysis_duplicate_occurrences`
|
|
506
|
+
|
|
507
|
+
Unblock Memory exposes:
|
|
508
|
+
|
|
509
|
+
- `memory_list_clusters` to cheaply list current clusters and report whether the
|
|
510
|
+
retained analysis is stale
|
|
511
|
+
- `memory_recluster` to explicitly rebuild clusters when the list is missing or stale
|
|
512
|
+
- `memory_fetch_cluster` to return a sorted, paginated selection of QMD chunks
|
|
513
|
+
for a short `clusterId` returned by `memory_list_clusters`
|
|
514
|
+
|
|
515
|
+
`memory_recluster` optionally accepts UMAP controls (`method`, components,
|
|
516
|
+
neighbors, and minimum distance), HDBSCAN controls (minimum cluster size,
|
|
517
|
+
minimum samples, selection method and epsilon, and single-cluster behavior),
|
|
518
|
+
and a deterministic seed. Omitting them uses the worker's defaults.
|
|
519
|
+
|
|
520
|
+
`memory_fetch_cluster` accepts `topK` (1–50), a zero-based `offset`, and
|
|
521
|
+
`sort`: `representative` (the default), `score_desc`, `score_asc`, `date_desc`,
|
|
522
|
+
or `date_asc`. Score is cluster membership probability for normal clusters and
|
|
523
|
+
outlier score for noise. Each member reports raw `sourceModifiedAt` separately
|
|
524
|
+
from `eventTime` and `eventTimeBasis`. Session start times and dated memory paths
|
|
525
|
+
resolve programmatically; reviewed annotations resolve otherwise ambiguous
|
|
526
|
+
chunks or whole documents. Date sorting uses resolved event time when available
|
|
527
|
+
and the clearly labeled source modification time only as a fallback. Responses
|
|
528
|
+
include page totals and the next offset when more members remain.
|
|
529
|
+
|
|
530
|
+
A chronological cluster read creates a coalesced maintenance proposal only for
|
|
531
|
+
returned documents whose event time remains ambiguous; it does not scan the
|
|
532
|
+
whole corpus for chores. Persisted exact-duplicate analysis can likewise create
|
|
533
|
+
review proposals for non-session Markdown. `memory_list_maintenance_tasks`
|
|
534
|
+
returns at most ten tasks, while `memory_update_maintenance_task` can resolve,
|
|
535
|
+
defer, or mark one irrelevant and optionally attach a supported event date.
|
|
536
|
+
For duplicate proposals, defer confirmed cleanup until the source change is
|
|
537
|
+
complete, mark intentional repetition irrelevant, and resolve only completed
|
|
538
|
+
work. These tools never edit or delete source Markdown. Duplicate cleanup
|
|
539
|
+
remains a reviewed source change outside the maintenance tool, and generated
|
|
540
|
+
session projections must never be edited directly.
|
|
541
|
+
|
|
542
|
+
Member excerpts are capped at 2 KB each and 12 KB across a response; source
|
|
543
|
+
aliases are capped at five per member and 50 across a response. These budgets
|
|
544
|
+
are shared across the page so every returned member receives a useful excerpt
|
|
545
|
+
and at least one source path, including a full 50-member page.
|
|
546
|
+
|
|
547
|
+
If indexing changes content or vectors, the previous derived analysis is kept
|
|
548
|
+
and marked stale. Cluster reads include the analysis timestamp, stale timestamp,
|
|
549
|
+
and a hint to call `memory_recluster`; unavailable chunks reduce `availableSize`
|
|
550
|
+
without copying canonical text into analysis tables. A no-op sync stays fresh.
|
|
551
|
+
A failed rebuild leaves the stale result intact, while a successful rebuild
|
|
552
|
+
atomically replaces it. Analysis is never scheduled automatically. If the worker
|
|
553
|
+
is absent or fails, `memory_search` and `memory_get` continue to work.
|
|
554
|
+
|
|
555
|
+
## Curating knowledge
|
|
556
|
+
|
|
557
|
+
The plugin bundles the `memory-curator` skill for turning useful clusters into
|
|
558
|
+
durable knowledge. It becomes available when the plugin is enabled. If the
|
|
559
|
+
agent has an explicit skill allowlist, include `memory-curator`.
|
|
560
|
+
|
|
561
|
+
Keep maintained knowledge outside `memory/**` so each file belongs to only one
|
|
562
|
+
corpus. Use stable topic files updated in place:
|
|
563
|
+
|
|
564
|
+
```text
|
|
565
|
+
knowledge/
|
|
566
|
+
├── fleet.md
|
|
567
|
+
├── people/
|
|
568
|
+
│ └── rico.md
|
|
569
|
+
└── projects/
|
|
570
|
+
└── unblock-memory.md
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
Knowledge is the agent's maintained, current understanding of its unique world:
|
|
574
|
+
facts such as fleet membership, local decisions and preferences, assessments,
|
|
575
|
+
and explicit uncertainty that would be expensive to reconstruct from scattered
|
|
576
|
+
history. Each claim should carry its own epistemic qualification so it remains
|
|
577
|
+
honest when semantic chunking retrieves it alone. Remove stale conclusions
|
|
578
|
+
instead of preserving history, changelogs, or `Supersedes` passages in the same
|
|
579
|
+
file; raw memory and sessions retain the evidence history.
|
|
580
|
+
|
|
581
|
+
Public or vendor-owned facts, generic command syntax, and behavior likely to
|
|
582
|
+
change with third-party releases should normally be looked up from the current
|
|
583
|
+
authoritative source. A local policy or deliberate divergence may belong in
|
|
584
|
+
knowledge, but the local decision—not copied generic documentation—is the
|
|
585
|
+
durable content.
|
|
586
|
+
|
|
587
|
+
For a manual run, ask the agent:
|
|
588
|
+
|
|
589
|
+
```text
|
|
590
|
+
Use $memory-curator to review my memory clusters and curate any durable updates.
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
For recurring curation, use an OpenClaw automation with the same thin message:
|
|
594
|
+
|
|
595
|
+
```text
|
|
596
|
+
Use $memory-curator to run the scheduled memory curation cycle.
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
The skill treats a cluster as an incomplete attention signal. It frames the
|
|
600
|
+
question raised, uses representative, score, and chronological views as useful,
|
|
601
|
+
searches existing knowledge and adjacent corpora, and investigates live systems,
|
|
602
|
+
files, documentation, or the web when those are better evidence. It then updates
|
|
603
|
+
a stable knowledge topic or correctly writes nothing. Its own writes are indexed
|
|
604
|
+
for the next cycle; it does not recluster recursively in the same run.
|
|
605
|
+
|
|
606
|
+
Existing `unblock-qmd` indexes are derived caches and may be left in place;
|
|
607
|
+
Unblock Memory rebuilds its own index from configured corpora.
|