@xdarkicex/openclaw-memory-libravdb 1.10.9 → 1.10.13
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/dist/context-engine.js +26 -2
- package/dist/index.js +83 -2
- package/dist/memory-provider.js +5 -2
- package/dist/tools/memory-recall.d.ts +34 -0
- package/dist/tools/memory-recall.js +56 -0
- package/openclaw.plugin.json +4 -2
- package/package.json +1 -1
package/dist/context-engine.js
CHANGED
|
@@ -1725,6 +1725,26 @@ export function buildContextEngineFactory(runtime, cfg, logger = console) {
|
|
|
1725
1725
|
return null;
|
|
1726
1726
|
}
|
|
1727
1727
|
}
|
|
1728
|
+
async function injectPersonaContext(params) {
|
|
1729
|
+
try {
|
|
1730
|
+
const resp = await params.client.getUserCard({ userId: "__bot_persona__" });
|
|
1731
|
+
if (!resp.cardJson)
|
|
1732
|
+
return null;
|
|
1733
|
+
let card;
|
|
1734
|
+
try {
|
|
1735
|
+
card = JSON.parse(resp.cardJson).card ?? resp.cardJson;
|
|
1736
|
+
}
|
|
1737
|
+
catch {
|
|
1738
|
+
card = resp.cardJson;
|
|
1739
|
+
}
|
|
1740
|
+
if (!card || card.trim().length === 0)
|
|
1741
|
+
return null;
|
|
1742
|
+
return '<bot_persona>\n' + card + '\n</bot_persona>';
|
|
1743
|
+
}
|
|
1744
|
+
catch {
|
|
1745
|
+
return null;
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1728
1748
|
async function runCompaction(args) {
|
|
1729
1749
|
const request = buildCompactSessionRequest(args);
|
|
1730
1750
|
try {
|
|
@@ -2029,12 +2049,16 @@ export function buildContextEngineFactory(runtime, cfg, logger = console) {
|
|
|
2029
2049
|
systemPromptAddition: assembled.systemPromptAddition,
|
|
2030
2050
|
});
|
|
2031
2051
|
const userCardContext = await injectUserCardContext({ client, userId });
|
|
2052
|
+
const personaContext = await injectPersonaContext({ client });
|
|
2032
2053
|
const rulesContext = buildRulesContext();
|
|
2033
|
-
// Only inject
|
|
2034
|
-
// After the first turn, predictive context handles it.
|
|
2054
|
+
// Only inject on session bootstrap.
|
|
2035
2055
|
const isSessionBootstrap = messages.length <= 1;
|
|
2036
2056
|
let withContext = assembled;
|
|
2037
2057
|
if (isSessionBootstrap) {
|
|
2058
|
+
// Persona first — identity of the bot itself.
|
|
2059
|
+
if (personaContext) {
|
|
2060
|
+
withContext = { ...withContext, systemPromptAddition: appendSystemPromptAddition(withContext.systemPromptAddition, personaContext) };
|
|
2061
|
+
}
|
|
2038
2062
|
if (userCardContext) {
|
|
2039
2063
|
withContext = { ...withContext, systemPromptAddition: appendSystemPromptAddition(withContext.systemPromptAddition, userCardContext) };
|
|
2040
2064
|
}
|
package/dist/index.js
CHANGED
|
@@ -20281,6 +20281,22 @@ ${cached}
|
|
|
20281
20281
|
return null;
|
|
20282
20282
|
}
|
|
20283
20283
|
}
|
|
20284
|
+
async function injectPersonaContext(params) {
|
|
20285
|
+
try {
|
|
20286
|
+
const resp = await params.client.getUserCard({ userId: "__bot_persona__" });
|
|
20287
|
+
if (!resp.cardJson) return null;
|
|
20288
|
+
let card;
|
|
20289
|
+
try {
|
|
20290
|
+
card = JSON.parse(resp.cardJson).card ?? resp.cardJson;
|
|
20291
|
+
} catch {
|
|
20292
|
+
card = resp.cardJson;
|
|
20293
|
+
}
|
|
20294
|
+
if (!card || card.trim().length === 0) return null;
|
|
20295
|
+
return "<bot_persona>\n" + card + "\n</bot_persona>";
|
|
20296
|
+
} catch {
|
|
20297
|
+
return null;
|
|
20298
|
+
}
|
|
20299
|
+
}
|
|
20284
20300
|
async function runCompaction(args) {
|
|
20285
20301
|
const request3 = buildCompactSessionRequest(args);
|
|
20286
20302
|
try {
|
|
@@ -20575,10 +20591,14 @@ ${cached}
|
|
|
20575
20591
|
systemPromptAddition: assembled.systemPromptAddition
|
|
20576
20592
|
});
|
|
20577
20593
|
const userCardContext = await injectUserCardContext({ client, userId });
|
|
20594
|
+
const personaContext = await injectPersonaContext({ client });
|
|
20578
20595
|
const rulesContext = buildRulesContext();
|
|
20579
20596
|
const isSessionBootstrap = messages.length <= 1;
|
|
20580
20597
|
let withContext = assembled;
|
|
20581
20598
|
if (isSessionBootstrap) {
|
|
20599
|
+
if (personaContext) {
|
|
20600
|
+
withContext = { ...withContext, systemPromptAddition: appendSystemPromptAddition(withContext.systemPromptAddition, personaContext) };
|
|
20601
|
+
}
|
|
20582
20602
|
if (userCardContext) {
|
|
20583
20603
|
withContext = { ...withContext, systemPromptAddition: appendSystemPromptAddition(withContext.systemPromptAddition, userCardContext) };
|
|
20584
20604
|
}
|
|
@@ -31187,7 +31207,8 @@ function buildToolGuidance(availableTools) {
|
|
|
31187
31207
|
"Only use memory_search if the card is empty or missing.",
|
|
31188
31208
|
"",
|
|
31189
31209
|
"**Autonomous card maintenance:**",
|
|
31190
|
-
hasGetCard ? "- When
|
|
31210
|
+
hasGetCard ? "- When ANY speaker is mentioned with new or changed information (status, relationships, jobs, life events, feelings), call `update_user_card` BEFORE responding. Update the card first, then reply. Do NOT wait to be asked. Build the world picture proactively. Every person the user mentions matters." : "",
|
|
31211
|
+
hasGetCard ? "- If a card for the speaker doesn't exist yet, CREATE one with `update_user_card`. Better to have a stub card than no card at all." : "",
|
|
31191
31212
|
""
|
|
31192
31213
|
);
|
|
31193
31214
|
}
|
|
@@ -31196,7 +31217,10 @@ function buildToolGuidance(availableTools) {
|
|
|
31196
31217
|
"facts, earliest interactions, and channel history. Do not answer memory",
|
|
31197
31218
|
"questions from prior transcript claims \u2014 perform a search every time.",
|
|
31198
31219
|
"After receiving results, use them directly; do not re-call in the same turn.",
|
|
31199
|
-
...availableTools.has("memory_get") ? [
|
|
31220
|
+
...availableTools.has("memory_get") ? [
|
|
31221
|
+
"After a `memory_search` hit, call `memory_get` when exact wording or more context is needed.",
|
|
31222
|
+
"IMPORTANT: If a search snippet is cluttered with metadata, do NOT claim nothing was found. Call `memory_get` on the hit's path to read the full record first. The data is there \u2014 expand before giving up."
|
|
31223
|
+
] : [],
|
|
31200
31224
|
""
|
|
31201
31225
|
);
|
|
31202
31226
|
const hasDescribe = availableTools.has("memory_describe");
|
|
@@ -31784,6 +31808,55 @@ function createListUserCardsTool(getClient, logger = console) {
|
|
|
31784
31808
|
}
|
|
31785
31809
|
};
|
|
31786
31810
|
}
|
|
31811
|
+
function createSetPersonaTool(getClient, logger = console) {
|
|
31812
|
+
return {
|
|
31813
|
+
name: "set_persona",
|
|
31814
|
+
label: "Set Persona",
|
|
31815
|
+
description: "Define who YOU are \u2014 your personality, tone, boundaries, and behavior. Write in prose like you're describing yourself. This is injected as <bot_persona> at the start of every session. Update it when your persona changes. The LLM will embody this persona in all interactions.",
|
|
31816
|
+
parameters: {
|
|
31817
|
+
type: "object",
|
|
31818
|
+
additionalProperties: false,
|
|
31819
|
+
properties: {
|
|
31820
|
+
persona: { type: "string", description: "Prose description of how you should behave." }
|
|
31821
|
+
},
|
|
31822
|
+
required: ["persona"]
|
|
31823
|
+
},
|
|
31824
|
+
execute: async (_toolCallId, rawParams) => {
|
|
31825
|
+
const params = rawParams;
|
|
31826
|
+
const persona = typeof params?.persona === "string" ? params.persona.trim() : "";
|
|
31827
|
+
if (!persona) return jsonResult2({ ok: false, error: "set_persona requires a persona string" });
|
|
31828
|
+
try {
|
|
31829
|
+
const client = await getClient();
|
|
31830
|
+
const resp = await client.upsertUserCard({
|
|
31831
|
+
userId: "__bot_persona__",
|
|
31832
|
+
cardJson: JSON.stringify({ card: persona, updatedAt: Date.now() })
|
|
31833
|
+
});
|
|
31834
|
+
return jsonResult2({ ok: resp.ok });
|
|
31835
|
+
} catch (error2) {
|
|
31836
|
+
logger.warn?.(`set_persona failed: ${formatError(error2)}`);
|
|
31837
|
+
return jsonResult2({ ok: false, error: formatError(error2) });
|
|
31838
|
+
}
|
|
31839
|
+
}
|
|
31840
|
+
};
|
|
31841
|
+
}
|
|
31842
|
+
function createGetPersonaTool(getClient, logger = console) {
|
|
31843
|
+
return {
|
|
31844
|
+
name: "get_persona",
|
|
31845
|
+
label: "Get Persona",
|
|
31846
|
+
description: "Read your current persona. Returns the full prose description of how you should behave.",
|
|
31847
|
+
parameters: { type: "object", additionalProperties: false, properties: {} },
|
|
31848
|
+
execute: async () => {
|
|
31849
|
+
try {
|
|
31850
|
+
const client = await getClient();
|
|
31851
|
+
const resp = await client.getUserCard({ userId: "__bot_persona__" });
|
|
31852
|
+
return jsonResult2({ persona: resp.cardJson || null });
|
|
31853
|
+
} catch (error2) {
|
|
31854
|
+
logger.warn?.(`get_persona failed: ${formatError(error2)}`);
|
|
31855
|
+
return jsonResult2({ error: formatError(error2) });
|
|
31856
|
+
}
|
|
31857
|
+
}
|
|
31858
|
+
};
|
|
31859
|
+
}
|
|
31787
31860
|
|
|
31788
31861
|
// src/memory-tools.ts
|
|
31789
31862
|
var MEMORY_SEARCH_SCHEMA = {
|
|
@@ -35605,6 +35678,14 @@ function register(api) {
|
|
|
35605
35678
|
api.registerTool?.(() => createGetRuleTool(logger), { names: ["get_rule"] });
|
|
35606
35679
|
api.registerTool?.(() => createListRulesTool(logger), { names: ["list_rules"] });
|
|
35607
35680
|
api.registerTool?.(() => createDeleteRuleTool(logger), { names: ["delete_rule"] });
|
|
35681
|
+
api.registerTool?.(() => {
|
|
35682
|
+
const getClient = runtimeOrNull.getClient;
|
|
35683
|
+
return createSetPersonaTool(getClient, logger);
|
|
35684
|
+
}, { names: ["set_persona"] });
|
|
35685
|
+
api.registerTool?.(() => {
|
|
35686
|
+
const getClient = runtimeOrNull.getClient;
|
|
35687
|
+
return createGetPersonaTool(getClient, logger);
|
|
35688
|
+
}, { names: ["get_persona"] });
|
|
35608
35689
|
}
|
|
35609
35690
|
if (isLightweight || isDiscovery) {
|
|
35610
35691
|
if (!isLightweight) {
|
package/dist/memory-provider.js
CHANGED
|
@@ -29,10 +29,13 @@ function buildToolGuidance(availableTools) {
|
|
|
29
29
|
const hasGetCard = availableTools.has("get_user_card");
|
|
30
30
|
const hasListCards = availableTools.has("list_user_cards");
|
|
31
31
|
if (hasGetCard || hasListCards) {
|
|
32
|
-
lines.push("**Identity/Entity questions — MANDATORY card lookup:**", "BEFORE answering any question about a person, pet, place, or named thing:", hasGetCard ? "- `get_user_card(user_id)` — MANDATORY lookup for a specific entity." : "", hasListCards ? "- `list_user_cards()` — MANDATORY roster check. Call if unsure whether a card exists." : "", "Cards are the canonical record. You MUST call these tools. Do NOT answer from", "memory, context, or training data without checking the card first.", "Only use memory_search if the card is empty or missing.", "", "**Autonomous card maintenance:**", hasGetCard ? "- When
|
|
32
|
+
lines.push("**Identity/Entity questions — MANDATORY card lookup:**", "BEFORE answering any question about a person, pet, place, or named thing:", hasGetCard ? "- `get_user_card(user_id)` — MANDATORY lookup for a specific entity." : "", hasListCards ? "- `list_user_cards()` — MANDATORY roster check. Call if unsure whether a card exists." : "", "Cards are the canonical record. You MUST call these tools. Do NOT answer from", "memory, context, or training data without checking the card first.", "Only use memory_search if the card is empty or missing.", "", "**Autonomous card maintenance:**", hasGetCard ? "- When ANY speaker is mentioned with new or changed information (status, relationships, jobs, life events, feelings), call `update_user_card` BEFORE responding. Update the card first, then reply. Do NOT wait to be asked. Build the world picture proactively. Every person the user mentions matters." : "", hasGetCard ? "- If a card for the speaker doesn't exist yet, CREATE one with `update_user_card`. Better to have a stub card than no card at all." : "", "");
|
|
33
33
|
}
|
|
34
34
|
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")
|
|
35
|
-
? [
|
|
35
|
+
? [
|
|
36
|
+
"After a `memory_search` hit, call `memory_get` when exact wording or more context is needed.",
|
|
37
|
+
"IMPORTANT: If a search snippet is cluttered with metadata, do NOT claim nothing was found. Call `memory_get` on the hit's path to read the full record first. The data is there — expand before giving up."
|
|
38
|
+
]
|
|
36
39
|
: []), "");
|
|
37
40
|
// ── Summaries / recall (when available) ──
|
|
38
41
|
const hasDescribe = availableTools.has("memory_describe");
|
|
@@ -213,4 +213,38 @@ export declare function createListUserCardsTool(getClient: ClientGetter, logger?
|
|
|
213
213
|
};
|
|
214
214
|
execute: (_toolCallId: string, _rawParams: unknown) => Promise<ToolResult<ListUserCardsDetails>>;
|
|
215
215
|
};
|
|
216
|
+
export declare function createSetPersonaTool(getClient: ClientGetter, logger?: LoggerLike): {
|
|
217
|
+
name: string;
|
|
218
|
+
label: string;
|
|
219
|
+
description: string;
|
|
220
|
+
parameters: {
|
|
221
|
+
readonly type: "object";
|
|
222
|
+
readonly additionalProperties: false;
|
|
223
|
+
readonly properties: {
|
|
224
|
+
readonly persona: {
|
|
225
|
+
readonly type: "string";
|
|
226
|
+
readonly description: "Prose description of how you should behave.";
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
readonly required: readonly ["persona"];
|
|
230
|
+
};
|
|
231
|
+
execute: (_toolCallId: string, rawParams: unknown) => Promise<ToolResult<{
|
|
232
|
+
ok: boolean;
|
|
233
|
+
error?: string;
|
|
234
|
+
}>>;
|
|
235
|
+
};
|
|
236
|
+
export declare function createGetPersonaTool(getClient: ClientGetter, logger?: LoggerLike): {
|
|
237
|
+
name: string;
|
|
238
|
+
label: string;
|
|
239
|
+
description: string;
|
|
240
|
+
parameters: {
|
|
241
|
+
readonly type: "object";
|
|
242
|
+
readonly additionalProperties: false;
|
|
243
|
+
readonly properties: {};
|
|
244
|
+
};
|
|
245
|
+
execute: () => Promise<ToolResult<{
|
|
246
|
+
persona?: string | null;
|
|
247
|
+
error?: string;
|
|
248
|
+
}>>;
|
|
249
|
+
};
|
|
216
250
|
export {};
|
|
@@ -601,3 +601,59 @@ export function createListUserCardsTool(getClient, logger = console) {
|
|
|
601
601
|
},
|
|
602
602
|
};
|
|
603
603
|
}
|
|
604
|
+
// ── Persona tools — identity of the bot itself ──
|
|
605
|
+
export function createSetPersonaTool(getClient, logger = console) {
|
|
606
|
+
return {
|
|
607
|
+
name: "set_persona",
|
|
608
|
+
label: "Set Persona",
|
|
609
|
+
description: "Define who YOU are — your personality, tone, boundaries, and behavior. " +
|
|
610
|
+
"Write in prose like you're describing yourself. This is injected as " +
|
|
611
|
+
"<bot_persona> at the start of every session. Update it when your persona " +
|
|
612
|
+
"changes. The LLM will embody this persona in all interactions.",
|
|
613
|
+
parameters: {
|
|
614
|
+
type: "object",
|
|
615
|
+
additionalProperties: false,
|
|
616
|
+
properties: {
|
|
617
|
+
persona: { type: "string", description: "Prose description of how you should behave." },
|
|
618
|
+
},
|
|
619
|
+
required: ["persona"],
|
|
620
|
+
},
|
|
621
|
+
execute: async (_toolCallId, rawParams) => {
|
|
622
|
+
const params = rawParams;
|
|
623
|
+
const persona = typeof params?.persona === "string" ? params.persona.trim() : "";
|
|
624
|
+
if (!persona)
|
|
625
|
+
return jsonResult({ ok: false, error: "set_persona requires a persona string" });
|
|
626
|
+
try {
|
|
627
|
+
const client = await getClient();
|
|
628
|
+
const resp = await client.upsertUserCard({
|
|
629
|
+
userId: "__bot_persona__",
|
|
630
|
+
cardJson: JSON.stringify({ card: persona, updatedAt: Date.now() }),
|
|
631
|
+
});
|
|
632
|
+
return jsonResult({ ok: resp.ok });
|
|
633
|
+
}
|
|
634
|
+
catch (error) {
|
|
635
|
+
logger.warn?.(`set_persona failed: ${formatError(error)}`);
|
|
636
|
+
return jsonResult({ ok: false, error: formatError(error) });
|
|
637
|
+
}
|
|
638
|
+
},
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
export function createGetPersonaTool(getClient, logger = console) {
|
|
642
|
+
return {
|
|
643
|
+
name: "get_persona",
|
|
644
|
+
label: "Get Persona",
|
|
645
|
+
description: "Read your current persona. Returns the full prose description of how you should behave.",
|
|
646
|
+
parameters: { type: "object", additionalProperties: false, properties: {} },
|
|
647
|
+
execute: async () => {
|
|
648
|
+
try {
|
|
649
|
+
const client = await getClient();
|
|
650
|
+
const resp = await client.getUserCard({ userId: "__bot_persona__" });
|
|
651
|
+
return jsonResult({ persona: resp.cardJson || null });
|
|
652
|
+
}
|
|
653
|
+
catch (error) {
|
|
654
|
+
logger.warn?.(`get_persona failed: ${formatError(error)}`);
|
|
655
|
+
return jsonResult({ error: formatError(error) });
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
};
|
|
659
|
+
}
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "libravdb-memory",
|
|
3
3
|
"name": "LibraVDB Memory",
|
|
4
4
|
"description": "Cognitive memory engine — causal graph reasoning, predictive context, identity tracking, and hybrid vector recall with back-door adjustment scoring",
|
|
5
|
-
"version": "1.10.
|
|
5
|
+
"version": "1.10.13",
|
|
6
6
|
"kind": [
|
|
7
7
|
"memory",
|
|
8
8
|
"context-engine"
|
|
@@ -22,7 +22,9 @@
|
|
|
22
22
|
"set_rule",
|
|
23
23
|
"get_rule",
|
|
24
24
|
"list_rules",
|
|
25
|
-
"delete_rule"
|
|
25
|
+
"delete_rule",
|
|
26
|
+
"set_persona",
|
|
27
|
+
"get_persona"
|
|
26
28
|
]
|
|
27
29
|
},
|
|
28
30
|
"activation": {
|