@xdarkicex/openclaw-memory-libravdb 1.7.0 → 1.8.0

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.
@@ -1,7 +1,7 @@
1
1
  import type { Interceptor } from "@connectrpc/connect";
2
2
  import type { PartialMessage } from "@bufbuild/protobuf";
3
3
  import type { LoggerLike } from "./types.js";
4
- import type { AfterTurnKernelRequest, AfterTurnKernelResponse, AssembleContextInternalRequest, AssembleContextInternalResponse, BootstrapSessionKernelRequest, BootstrapSessionKernelResponse, CompactSessionRequest, CompactSessionResponse, DeleteAuthoredDocumentRequest, DeleteAuthoredDocumentResponse, DreamPromotionResponse, ExportMemoryRequest, ExportMemoryResponse, FlushNamespaceRequest, FlushNamespaceResponse, FlushRequest, FlushResponse, HealthRequest, HealthResponse, IngestMarkdownDocumentRequest, IngestMarkdownDocumentResponse, IngestMessageKernelRequest, IngestMessageKernelResponse, ListCollectionRequest, ListCollectionResponse, ListLifecycleJournalRequest, ListLifecycleJournalResponse, MarkMemorySupersededRequest, MarkMemorySupersededResponse, MemoryStatusRequest, MemoryStatusResponse, PromoteDreamEntriesRequest, RankCandidatesRequest, RankCandidatesResponse, RebuildIndexRequest, RebuildIndexResponse, ReindexAuthoredDocumentRequest, ReindexAuthoredDocumentResponse, SearchTextCollectionsRequest, SearchTextRequest, SearchTextResponse, SessionLifecycleHintRequest, SessionLifecycleHintResponse } from "@xdarkicex/libravdb-contracts";
4
+ import type { AfterTurnKernelRequest, AfterTurnKernelResponse, BeforeTurnKernelRequest, BeforeTurnKernelResponse, AssembleContextInternalRequest, AssembleContextInternalResponse, BootstrapSessionKernelRequest, BootstrapSessionKernelResponse, CompactSessionRequest, CompactSessionResponse, DeleteAuthoredDocumentRequest, DeleteAuthoredDocumentResponse, DreamPromotionResponse, ExportMemoryRequest, ExportMemoryResponse, FlushNamespaceRequest, FlushNamespaceResponse, FlushRequest, FlushResponse, HealthRequest, HealthResponse, IngestMarkdownDocumentRequest, IngestMarkdownDocumentResponse, IngestMessageKernelRequest, IngestMessageKernelResponse, ListCollectionRequest, ListCollectionResponse, ListLifecycleJournalRequest, ListLifecycleJournalResponse, MarkMemorySupersededRequest, MarkMemorySupersededResponse, MemoryStatusRequest, MemoryStatusResponse, PromoteDreamEntriesRequest, RankCandidatesRequest, RankCandidatesResponse, RebuildIndexRequest, RebuildIndexResponse, ReindexAuthoredDocumentRequest, ReindexAuthoredDocumentResponse, SearchTextCollectionsRequest, SearchTextRequest, SearchTextResponse, SessionLifecycleHintRequest, SessionLifecycleHintResponse, SummarizeMessagesRequest, SummarizeMessagesResponse, ExpandSummaryRequest, ExpandSummaryResponse } from "@xdarkicex/libravdb-contracts";
5
5
  export interface LibravDBClientOptions {
6
6
  endpoint?: string;
7
7
  secret?: string;
@@ -59,8 +59,11 @@ export declare class LibravDBClient {
59
59
  bootstrapSessionKernel(req: PartialMessage<BootstrapSessionKernelRequest>): Promise<BootstrapSessionKernelResponse>;
60
60
  ingestMessageKernel(req: PartialMessage<IngestMessageKernelRequest>): Promise<IngestMessageKernelResponse>;
61
61
  afterTurnKernel(req: PartialMessage<AfterTurnKernelRequest>): Promise<AfterTurnKernelResponse>;
62
+ beforeTurnKernel(req: PartialMessage<BeforeTurnKernelRequest>): Promise<BeforeTurnKernelResponse>;
62
63
  assembleContextInternal(req: PartialMessage<AssembleContextInternalRequest>): Promise<AssembleContextInternalResponse>;
63
64
  compactSession(req: PartialMessage<CompactSessionRequest>): Promise<CompactSessionResponse>;
65
+ summarizeMessages(req: PartialMessage<SummarizeMessagesRequest>): Promise<SummarizeMessagesResponse>;
66
+ expandSummary(req: PartialMessage<ExpandSummaryRequest>): Promise<ExpandSummaryResponse>;
64
67
  rankCandidates(req: PartialMessage<RankCandidatesRequest>): Promise<RankCandidatesResponse>;
65
68
  close(): void;
66
69
  }
@@ -313,6 +313,10 @@ export class LibravDBClient {
313
313
  this.guardOpen();
314
314
  return this.client.afterTurnKernel(req);
315
315
  }
316
+ async beforeTurnKernel(req) {
317
+ this.guardOpen();
318
+ return this.client.beforeTurnKernel(req);
319
+ }
316
320
  async assembleContextInternal(req) {
317
321
  this.guardOpen();
318
322
  return this.client.assembleContextInternal(req);
@@ -321,6 +325,14 @@ export class LibravDBClient {
321
325
  this.guardOpen();
322
326
  return this.client.compactSession(req);
323
327
  }
328
+ async summarizeMessages(req) {
329
+ this.guardOpen();
330
+ return this.client.summarizeMessages(req);
331
+ }
332
+ async expandSummary(req) {
333
+ this.guardOpen();
334
+ return this.client.expandSummary(req);
335
+ }
324
336
  async rankCandidates(req) {
325
337
  this.guardOpen();
326
338
  return this.client.rankCandidates(req);
@@ -1,34 +1,47 @@
1
1
  const MEMORY_PROMPT_HEADER = [
2
- "## Memory",
3
- "LibraVDB persistent memory is configured. Every turn is auto-ingested",
4
- "into the vector store you do not need to explicitly save anything.",
5
- "When asked about past conversations, facts, preferences, decisions,",
6
- "or anything the user might have told you before, call `memory_search`",
7
- "once per user question. Do not answer from memory until you have",
8
- "called it. Once you have results, use them — do not re-call.",
2
+ "## LibraVDB Memory",
3
+ "Every turn is auto-ingested into the vector store — you do not need",
4
+ "to explicitly save anything. When asked about past conversations,",
5
+ "facts, preferences, decisions, or anything the user might have told",
6
+ "you before, call `memory_search` once per user question. Do not",
7
+ "answer from memory until you have called it. Once you have results,",
8
+ "use them — do not re-call in the same turn.",
9
+ "",
10
+ "Conversations are captured automatically. Never say \"I'll remember",
11
+ "that,\" \"I've saved this,\" \"noted,\" or similar — these phrases suggest",
12
+ "manual effort where none exists. Just act on the request.",
9
13
  "",
10
14
  ];
11
15
  function buildToolGuidance(availableTools) {
12
16
  if (!availableTools?.has("memory_search")) {
13
17
  return [];
14
18
  }
15
- return [
16
- "Call `memory_search` once per user question for prior turns, remembered",
17
- "facts, earliest interactions, and channel history. Do not answer memory",
18
- "questions from prior transcript claims — perform a search every time.",
19
- "After receiving results, use them directly; do not re-call in the same turn.",
20
- "For earliest or oldest questions, request enough results and compare timestamps.",
21
- ...(availableTools.has("memory_get")
22
- ? ["After a `memory_search` hit, call `memory_get` when exact wording or more context is needed."]
23
- : []),
24
- "LibraVDB memory is vector-backed and retrieved through tools, not files.",
25
- "",
26
- ];
19
+ const lines = [];
20
+ lines.push("Call `memory_search` once per user question for prior turns, remembered", "facts, earliest interactions, and channel history. Do not answer memory", "questions from prior transcript claims — perform a search every time.", "After receiving results, use them directly; do not re-call in the same turn.", ...(availableTools.has("memory_get")
21
+ ? ["After a `memory_search` hit, call `memory_get` when exact wording or more context is needed."]
22
+ : []), "");
23
+ // ── Summaries / recall (when available) ──
24
+ const hasDescribe = availableTools.has("memory_describe");
25
+ const hasExpand = availableTools.has("memory_expand");
26
+ const hasGrep = availableTools.has("memory_grep");
27
+ if (hasDescribe || hasExpand || hasGrep) {
28
+ lines.push("**Compacted summaries recall hierarchy (cheap expensive):**", "", "Summaries in search results show `[Summary sum_xxx]: [eviction cue]`.", "The cue lists what the summary covers — anchors (files, tools, versions),", "decisions, constraints, and signal counts. Many questions can be answered", "from the cue alone without expanding.", "");
29
+ if (hasDescribe) {
30
+ lines.push("1. `memory_describe(summaryId)` — inspect a summary's metadata.", " Returns eviction cues, child count, and source turn range.", " Cheap — use this to decide whether expansion is worth it.");
31
+ }
32
+ if (hasExpand) {
33
+ lines.push("2. `memory_expand(summaryIds)` — deep recall. Walks the summary tree", " and returns full detail. Use when the eviction cue signals specific", " details you need. For large expansions may spawn a sub-agent to", " protect your context window.");
34
+ }
35
+ if (hasGrep) {
36
+ lines.push("3. `memory_grep(pattern)` — search compacted history by text or regex.", " Returns snippets with summary/turn IDs for follow-up.");
37
+ }
38
+ lines.push("", "**Do not guess specifics from a summary cue — expand if in doubt.**", "");
39
+ }
40
+ lines.push("LibraVDB memory is vector-backed and retrieved through tools, not files.", "");
41
+ return lines;
27
42
  }
28
43
  export function buildMemoryPromptSection(_getClient, _cfg) {
29
44
  return function memoryPromptSection({ availableTools, citationsMode: _citationsMode, }) {
30
- // OpenClaw builds the memory prompt section synchronously for embedded runs.
31
- // Actual retrieval and ranking happen in the context engine during assemble().
32
45
  return [...MEMORY_PROMPT_HEADER, ...buildToolGuidance(availableTools)];
33
46
  };
34
47
  }
@@ -15,6 +15,8 @@ type MemorySearchParams = {
15
15
  agentId?: string;
16
16
  sessionId?: string;
17
17
  sessionKey?: string;
18
+ kind?: string;
19
+ signals?: string[];
18
20
  context?: {
19
21
  userId?: string;
20
22
  agentId?: string;
@@ -72,7 +72,7 @@ function createMemorySearchManager(getClient, cfg, defaults, initialStatus) {
72
72
  text: queryText,
73
73
  k,
74
74
  })
75
- : await searchResolvedCollections(client, cfg, userId, sessionId, queryText, k, searchCorpus);
75
+ : await searchResolvedCollections(client, cfg, userId, sessionId, queryText, k, searchCorpus, params.kind, params.signals);
76
76
  const filteredResults = minScore === undefined
77
77
  ? result.results
78
78
  : result.results.filter((item) => item.score >= minScore);
@@ -138,22 +138,28 @@ function createMemorySearchManager(getClient, cfg, defaults, initialStatus) {
138
138
  },
139
139
  };
140
140
  }
141
- async function searchResolvedCollections(client, cfg, userId, sessionId, queryText, k, corpus) {
141
+ async function searchResolvedCollections(client, cfg, userId, sessionId, queryText, k, corpus, kind, signals) {
142
142
  const collections = resolveSearchCollections(cfg, userId, sessionId, corpus);
143
143
  if (collections.length === 0) {
144
144
  return { results: [] };
145
145
  }
146
+ const kindFilter = kind || undefined;
147
+ const signalFilter = (signals && signals.length > 0) ? signals : undefined;
146
148
  return collections.length === 1
147
149
  ? await client.searchText({
148
150
  collection: collections[0],
149
151
  text: queryText,
150
152
  k,
153
+ kind: kindFilter,
154
+ signals: signalFilter,
151
155
  })
152
156
  : await client.searchTextCollections({
153
157
  collections,
154
158
  text: queryText,
155
159
  k,
156
160
  excludeByCollection: {},
161
+ kind: kindFilter,
162
+ signals: signalFilter,
157
163
  });
158
164
  }
159
165
  function resolveSearchCollections(cfg, userId, sessionId, corpus) {
@@ -25,6 +25,16 @@ const MEMORY_SEARCH_SCHEMA = {
25
25
  enum: ["memory", "wiki", "all", "sessions"],
26
26
  description: "Corpus filter. LibraVDB serves memory/session hits; wiki is unsupported unless another plugin owns wiki tools.",
27
27
  },
28
+ kind: {
29
+ type: "string",
30
+ enum: ["identity", "fact", "preference", "constraint", "decision", "episode"],
31
+ description: "Cognitive kind filter. Only return memories of this kind. Use 'constraint' to retrieve operating boundaries, 'decision' for past decisions, etc.",
32
+ },
33
+ signals: {
34
+ type: "array",
35
+ items: { type: "string", enum: ["deontic", "identity", "preference", "factual", "temporal"] },
36
+ description: "Signal bitmask filter. Only return memories carrying at least one of these signals.",
37
+ },
28
38
  },
29
39
  required: ["query"],
30
40
  };
@@ -86,6 +96,8 @@ export function createLibraVdbMemoryTools(getClient, cfg, logger = console) {
86
96
  const params = asToolParamsRecord(rawParams);
87
97
  const query = readRequiredStringParam(params, "query");
88
98
  const corpus = readMemoryCorpus(params.corpus);
99
+ const kind = typeof params.kind === "string" ? params.kind : undefined;
100
+ const signals = Array.isArray(params.signals) ? params.signals.filter((s) => typeof s === "string") : undefined;
89
101
  const maxResults = readNumberParam(params, "maxResults", { integer: true });
90
102
  const minScore = readNumberParam(params, "minScore");
91
103
  if (corpus === "wiki") {
@@ -102,6 +114,8 @@ export function createLibraVdbMemoryTools(getClient, cfg, logger = console) {
102
114
  corpus,
103
115
  ...(maxResults !== undefined ? { maxResults } : {}),
104
116
  ...(minScore !== undefined ? { minScore } : {}),
117
+ ...(kind !== undefined ? { kind } : {}),
118
+ ...(signals !== undefined ? { signals } : {}),
105
119
  ...buildSearchContext(ctx),
106
120
  });
107
121
  const results = filterResultsByCorpus(rawResults, corpus);
@@ -0,0 +1,144 @@
1
+ import type { ClientGetter } from "../plugin-runtime.js";
2
+ import type { LoggerLike } from "../types.js";
3
+ type ToolContent = {
4
+ type: "text";
5
+ text: string;
6
+ };
7
+ type ToolResult<T> = {
8
+ content: ToolContent[];
9
+ details: T;
10
+ };
11
+ type MemoryDescribeDetails = {
12
+ summaryId: string;
13
+ found: boolean;
14
+ evictionCue?: string;
15
+ depth?: number;
16
+ descendantCount?: number;
17
+ sourceTurnCount?: number;
18
+ sourceTurnIds?: string[];
19
+ parentSummaryIds?: string[];
20
+ error?: string;
21
+ };
22
+ type MemoryExpandDetails = {
23
+ summaryId: string;
24
+ depth: number;
25
+ text: string;
26
+ truncated: boolean;
27
+ exceededBudget: boolean;
28
+ parentCount: number;
29
+ error?: string;
30
+ };
31
+ type MemoryGrepDetails = {
32
+ pattern: string;
33
+ mode: "regex" | "text";
34
+ totalMatches: number;
35
+ summaries: Array<{
36
+ summaryId: string;
37
+ snippet: string;
38
+ score: number;
39
+ evictionCue?: string;
40
+ }>;
41
+ turns: Array<{
42
+ turnId: string;
43
+ snippet: string;
44
+ role: string;
45
+ score: number;
46
+ }>;
47
+ truncated: boolean;
48
+ };
49
+ export declare function createMemoryDescribeTool(getClient: ClientGetter, logger?: LoggerLike): {
50
+ name: string;
51
+ label: string;
52
+ description: string;
53
+ parameters: {
54
+ readonly type: "object";
55
+ readonly additionalProperties: false;
56
+ readonly properties: {
57
+ readonly summaryId: {
58
+ readonly type: "string";
59
+ readonly description: "A summary ID (sum_xxx format) returned by memory_search. Inspect metadata without expanding.";
60
+ };
61
+ readonly sessionId: {
62
+ readonly type: "string";
63
+ readonly description: "Session ID the summary belongs to. If omitted, uses the current session.";
64
+ };
65
+ };
66
+ readonly required: readonly ["summaryId"];
67
+ };
68
+ execute: (_toolCallId: string, rawParams: unknown) => Promise<ToolResult<MemoryDescribeDetails>>;
69
+ };
70
+ export declare function createMemoryExpandTool(getClient: ClientGetter, getSessionKey: () => string | undefined, logger?: LoggerLike): {
71
+ name: string;
72
+ label: string;
73
+ description: string;
74
+ parameters: {
75
+ readonly type: "object";
76
+ readonly additionalProperties: false;
77
+ readonly properties: {
78
+ readonly summaryIds: {
79
+ readonly type: "array";
80
+ readonly items: {
81
+ readonly type: "string";
82
+ };
83
+ readonly description: "Summary IDs (sum_xxx format) to expand. Use results from memory_search or memory_describe.";
84
+ };
85
+ readonly maxDepth: {
86
+ readonly type: "number";
87
+ readonly minimum: 0;
88
+ readonly maximum: 5;
89
+ readonly description: "Max tree traversal depth per summary (default: 1). 0 returns only the cue/metadata.";
90
+ };
91
+ readonly maxTokens: {
92
+ readonly type: "number";
93
+ readonly minimum: 100;
94
+ readonly maximum: number;
95
+ readonly description: "Token budget cap for the expansion result (default: 8000).";
96
+ };
97
+ readonly sessionId: {
98
+ readonly type: "string";
99
+ readonly description: "Session ID the summary belongs to. If omitted, uses the current session.";
100
+ };
101
+ };
102
+ readonly required: readonly ["summaryIds"];
103
+ };
104
+ execute: (_toolCallId: string, rawParams: unknown) => Promise<ToolResult<MemoryExpandDetails>>;
105
+ };
106
+ export declare function createMemoryGrepTool(getClient: ClientGetter, logger?: LoggerLike): {
107
+ name: string;
108
+ label: string;
109
+ description: string;
110
+ parameters: {
111
+ readonly type: "object";
112
+ readonly additionalProperties: false;
113
+ readonly properties: {
114
+ readonly pattern: {
115
+ readonly type: "string";
116
+ readonly description: "Search pattern. Regex when mode=regex, plain text when mode=text.";
117
+ };
118
+ readonly mode: {
119
+ readonly type: "string";
120
+ readonly enum: readonly ["regex", "text"];
121
+ readonly description: "Search mode. Default: \"text\".";
122
+ };
123
+ readonly scope: {
124
+ readonly type: "string";
125
+ readonly enum: readonly ["messages", "summaries", "both"];
126
+ readonly description: "What to search. Default: \"both\".";
127
+ };
128
+ readonly limit: {
129
+ readonly type: "number";
130
+ readonly minimum: 1;
131
+ readonly maximum: 200;
132
+ readonly description: "Max results (default: 50).";
133
+ };
134
+ readonly sessionId: {
135
+ readonly type: "string";
136
+ readonly description: "Session ID to search within. If omitted, uses the current session.";
137
+ };
138
+ };
139
+ readonly required: readonly ["pattern"];
140
+ };
141
+ execute: (_toolCallId: string, rawParams: unknown) => Promise<ToolResult<MemoryGrepDetails>>;
142
+ };
143
+ export declare function memoryRecallPromptSection(): string[];
144
+ export {};