@xdarkicex/openclaw-memory-libravdb 1.4.11 → 1.4.12
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.d.ts +13 -1
- package/dist/context-engine.js +170 -51
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/context-engine.d.ts
CHANGED
|
@@ -17,6 +17,18 @@ type OpenClawCompatibleAssembleResult = {
|
|
|
17
17
|
systemPromptAddition: string;
|
|
18
18
|
debug?: AssembleContextInternalResponse["debug"];
|
|
19
19
|
};
|
|
20
|
+
type OpenClawCompatibleCompactResult = {
|
|
21
|
+
ok: boolean;
|
|
22
|
+
compacted: boolean;
|
|
23
|
+
reason?: string;
|
|
24
|
+
result?: {
|
|
25
|
+
summary?: string;
|
|
26
|
+
firstKeptEntryId?: string;
|
|
27
|
+
tokensBefore: number;
|
|
28
|
+
tokensAfter?: number;
|
|
29
|
+
details?: unknown;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
20
32
|
export declare function normalizeKernelMessage(message: {
|
|
21
33
|
role: string;
|
|
22
34
|
content: unknown;
|
|
@@ -77,7 +89,7 @@ export declare function buildContextEngineFactory(runtime: PluginRuntime, cfg: P
|
|
|
77
89
|
force?: boolean;
|
|
78
90
|
targetSize?: number;
|
|
79
91
|
tokenBudget?: number;
|
|
80
|
-
}): Promise<
|
|
92
|
+
}): Promise<OpenClawCompatibleCompactResult>;
|
|
81
93
|
afterTurn(args: {
|
|
82
94
|
sessionId: string;
|
|
83
95
|
sessionKey?: string;
|
package/dist/context-engine.js
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
const APPROX_CHARS_PER_TOKEN = 4;
|
|
2
|
+
const ASSEMBLE_BUDGET_HEADROOM_TOKENS = 256;
|
|
3
|
+
function requireSessionId(sessionId, operation) {
|
|
4
|
+
const normalized = typeof sessionId === "string" ? sessionId.trim() : "";
|
|
5
|
+
if (normalized.length > 0) {
|
|
6
|
+
return normalized;
|
|
7
|
+
}
|
|
8
|
+
throw new Error(`LibraVDB ${operation} requires a non-empty sessionId; refusing ambiguous request.`);
|
|
9
|
+
}
|
|
10
|
+
function normalizeCompactResult(response) {
|
|
11
|
+
const didCompact = response?.didCompact === true;
|
|
12
|
+
const details = {
|
|
13
|
+
clustersFormed: typeof response?.clustersFormed === "number" ? response.clustersFormed : undefined,
|
|
14
|
+
clustersDeclined: typeof response?.clustersDeclined === "number" ? response.clustersDeclined : undefined,
|
|
15
|
+
turnsRemoved: typeof response?.turnsRemoved === "number" ? response.turnsRemoved : undefined,
|
|
16
|
+
summaryMethod: typeof response?.summaryMethod === "string" && response.summaryMethod.length > 0
|
|
17
|
+
? response.summaryMethod
|
|
18
|
+
: undefined,
|
|
19
|
+
meanConfidence: typeof response?.meanConfidence === "number" ? response.meanConfidence : undefined,
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
ok: true,
|
|
23
|
+
compacted: didCompact,
|
|
24
|
+
...(didCompact ? {} : { reason: "not_compacted" }),
|
|
25
|
+
result: {
|
|
26
|
+
tokensBefore: 0,
|
|
27
|
+
...(details.summaryMethod ? { summary: details.summaryMethod } : {}),
|
|
28
|
+
details,
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
1
32
|
function describeUnexpectedContent(value) {
|
|
2
33
|
try {
|
|
3
34
|
const serialized = JSON.stringify(value);
|
|
@@ -57,6 +88,72 @@ function normalizeKernelContent(content) {
|
|
|
57
88
|
}
|
|
58
89
|
return content.map(stringifyKernelBlock).filter((part) => part.length > 0).join("\n");
|
|
59
90
|
}
|
|
91
|
+
function approximateTokenCount(text) {
|
|
92
|
+
if (!text)
|
|
93
|
+
return 0;
|
|
94
|
+
return Math.ceil(text.length / APPROX_CHARS_PER_TOKEN);
|
|
95
|
+
}
|
|
96
|
+
function approximateMessageTokens(message) {
|
|
97
|
+
// Approximate per-message wrapper overhead so trimming is conservative.
|
|
98
|
+
return approximateTokenCount(message.content) + 8;
|
|
99
|
+
}
|
|
100
|
+
function approximateMessagesTokens(messages) {
|
|
101
|
+
return messages.reduce((sum, message) => sum + approximateMessageTokens(message), 0);
|
|
102
|
+
}
|
|
103
|
+
function truncateContentToTokenBudget(content, tokenBudget) {
|
|
104
|
+
if (tokenBudget <= 0)
|
|
105
|
+
return "";
|
|
106
|
+
const maxChars = Math.max(1, tokenBudget * APPROX_CHARS_PER_TOKEN);
|
|
107
|
+
if (content.length <= maxChars)
|
|
108
|
+
return content;
|
|
109
|
+
// Keep the tail so recent tool output / latest answer content is preserved.
|
|
110
|
+
return content.slice(content.length - maxChars);
|
|
111
|
+
}
|
|
112
|
+
function trimMessagesToBudget(messages, tokenBudget) {
|
|
113
|
+
if (tokenBudget <= 0 || messages.length === 0) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
const kept = [];
|
|
117
|
+
let used = 0;
|
|
118
|
+
for (let i = messages.length - 1; i >= 0; i -= 1) {
|
|
119
|
+
const candidate = messages[i];
|
|
120
|
+
const cost = approximateMessageTokens(candidate);
|
|
121
|
+
if (used + cost > tokenBudget) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
kept.push(candidate);
|
|
125
|
+
used += cost;
|
|
126
|
+
}
|
|
127
|
+
if (kept.length > 0) {
|
|
128
|
+
return kept.reverse();
|
|
129
|
+
}
|
|
130
|
+
const last = messages[messages.length - 1];
|
|
131
|
+
const contentBudget = Math.max(1, tokenBudget - 8);
|
|
132
|
+
const truncated = truncateContentToTokenBudget(last.content, contentBudget);
|
|
133
|
+
if (!truncated) {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
return [{ ...last, content: truncated }];
|
|
137
|
+
}
|
|
138
|
+
function enforceTokenBudgetInvariant(result, tokenBudget) {
|
|
139
|
+
if (typeof tokenBudget !== "number" || !Number.isFinite(tokenBudget) || tokenBudget <= 0) {
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
const hardBudget = Math.max(1, Math.floor(tokenBudget));
|
|
143
|
+
const effectiveBudget = Math.max(1, hardBudget - ASSEMBLE_BUDGET_HEADROOM_TOKENS);
|
|
144
|
+
const estimated = typeof result.estimatedTokens === "number" ? result.estimatedTokens : 0;
|
|
145
|
+
const approxFromMessages = approximateMessagesTokens(result.messages);
|
|
146
|
+
if (estimated <= effectiveBudget && approxFromMessages <= effectiveBudget) {
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
const trimmedMessages = trimMessagesToBudget(result.messages, effectiveBudget);
|
|
150
|
+
const trimmedEstimate = approximateMessagesTokens(trimmedMessages);
|
|
151
|
+
return {
|
|
152
|
+
...result,
|
|
153
|
+
messages: trimmedMessages,
|
|
154
|
+
estimatedTokens: Math.min(effectiveBudget, trimmedEstimate),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
60
157
|
export function normalizeKernelMessage(message) {
|
|
61
158
|
return {
|
|
62
159
|
role: message.role,
|
|
@@ -94,7 +191,7 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
|
|
|
94
191
|
// timeout retries still compact toward the host's requested prompt budget.
|
|
95
192
|
const targetSize = args.targetSize ?? args.tokenBudget;
|
|
96
193
|
return {
|
|
97
|
-
sessionId: args.sessionId,
|
|
194
|
+
sessionId: requireSessionId(args.sessionId, "compact"),
|
|
98
195
|
force: args.force,
|
|
99
196
|
...(typeof targetSize === "number" ? { targetSize } : {}),
|
|
100
197
|
...(typeof cfg.continuityMinTurns === "number"
|
|
@@ -154,68 +251,90 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
|
|
|
154
251
|
const messages = normalizeKernelMessages(args.messages);
|
|
155
252
|
const kernel = runtime.getKernel();
|
|
156
253
|
if (kernel) {
|
|
157
|
-
|
|
254
|
+
try {
|
|
255
|
+
return enforceTokenBudgetInvariant(normalizeAssembleResult(await kernel.assembleContext({
|
|
256
|
+
sessionId: args.sessionId,
|
|
257
|
+
sessionKey: args.sessionKey,
|
|
258
|
+
userId: args.userId,
|
|
259
|
+
queryText: args.prompt ?? "",
|
|
260
|
+
visibleMessages: messages,
|
|
261
|
+
tokenBudget: args.tokenBudget,
|
|
262
|
+
config: {},
|
|
263
|
+
emitDebug: true
|
|
264
|
+
})), args.tokenBudget);
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
logger.warn?.(`LibraVDB assemble kernel failed, using budget-clamped fallback context: ${error instanceof Error ? error.message : String(error)}`);
|
|
268
|
+
const fallbackMessages = trimMessagesToBudget(messages.map((message) => ({ ...message })), Math.max(1, Math.floor(args.tokenBudget) - ASSEMBLE_BUDGET_HEADROOM_TOKENS));
|
|
269
|
+
return {
|
|
270
|
+
messages: fallbackMessages,
|
|
271
|
+
estimatedTokens: approximateMessagesTokens(fallbackMessages),
|
|
272
|
+
systemPromptAddition: "",
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const rpc = await runtime.getRpc();
|
|
277
|
+
try {
|
|
278
|
+
const resp = await rpc.call("assemble_context_internal", {
|
|
158
279
|
sessionId: args.sessionId,
|
|
159
280
|
sessionKey: args.sessionKey,
|
|
160
281
|
userId: args.userId,
|
|
161
|
-
|
|
162
|
-
visibleMessages: messages,
|
|
282
|
+
messages,
|
|
163
283
|
tokenBudget: args.tokenBudget,
|
|
164
|
-
|
|
165
|
-
emitDebug: true
|
|
166
|
-
|
|
284
|
+
prompt: args.prompt,
|
|
285
|
+
emitDebug: true,
|
|
286
|
+
config: {
|
|
287
|
+
useSessionRecallProjection: cfg.useSessionRecallProjection,
|
|
288
|
+
useSessionSummarySearchExperiment: cfg.useSessionSummarySearchExperiment,
|
|
289
|
+
tokenBudgetFraction: cfg.tokenBudgetFraction,
|
|
290
|
+
authoredHardBudgetFraction: cfg.authoredHardBudgetFraction,
|
|
291
|
+
authoredSoftBudgetFraction: cfg.authoredSoftBudgetFraction,
|
|
292
|
+
elevatedGuidanceBudgetFraction: cfg.elevatedGuidanceBudgetFraction,
|
|
293
|
+
topK: cfg.topK,
|
|
294
|
+
continuityMinTurns: cfg.continuityMinTurns,
|
|
295
|
+
continuityTailBudgetTokens: cfg.continuityTailBudgetTokens,
|
|
296
|
+
continuityPriorContextTokens: cfg.continuityPriorContextTokens,
|
|
297
|
+
compactThreshold: cfg.compactThreshold,
|
|
298
|
+
compactSessionTokenBudget: cfg.compactSessionTokenBudget,
|
|
299
|
+
section7Theta1: cfg.section7Theta1,
|
|
300
|
+
section7Kappa: cfg.section7Kappa,
|
|
301
|
+
section7HopEta: cfg.section7HopEta,
|
|
302
|
+
section7HopThreshold: cfg.section7HopThreshold,
|
|
303
|
+
section7CoarseTopK: cfg.section7CoarseTopK,
|
|
304
|
+
section7SecondPassTopK: cfg.section7SecondPassTopK,
|
|
305
|
+
section7AuthorityRecencyLambda: cfg.section7AuthorityRecencyLambda,
|
|
306
|
+
section7AuthorityRecencyWeight: cfg.section7AuthorityRecencyWeight,
|
|
307
|
+
section7AuthorityFrequencyWeight: cfg.section7AuthorityFrequencyWeight,
|
|
308
|
+
section7AuthorityAuthoredWeight: cfg.section7AuthorityAuthoredWeight,
|
|
309
|
+
recoveryFloorScore: cfg.recoveryFloorScore,
|
|
310
|
+
recoveryMinTopK: cfg.recoveryMinTopK,
|
|
311
|
+
recoveryMinConfidenceMean: cfg.recoveryMinConfidenceMean,
|
|
312
|
+
recencyLambdaSession: cfg.recencyLambdaSession,
|
|
313
|
+
recencyLambdaUser: cfg.recencyLambdaUser,
|
|
314
|
+
recencyLambdaGlobal: cfg.recencyLambdaGlobal,
|
|
315
|
+
ingestionGateThreshold: cfg.ingestionGateThreshold,
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
return enforceTokenBudgetInvariant(normalizeAssembleResult(resp), args.tokenBudget);
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
logger.warn?.(`LibraVDB assemble sidecar failed, using budget-clamped fallback context: ${error instanceof Error ? error.message : String(error)}`);
|
|
322
|
+
const fallbackMessages = trimMessagesToBudget(messages.map((message) => ({ ...message })), Math.max(1, Math.floor(args.tokenBudget) - ASSEMBLE_BUDGET_HEADROOM_TOKENS));
|
|
323
|
+
return {
|
|
324
|
+
messages: fallbackMessages,
|
|
325
|
+
estimatedTokens: approximateMessagesTokens(fallbackMessages),
|
|
326
|
+
systemPromptAddition: "",
|
|
327
|
+
};
|
|
167
328
|
}
|
|
168
|
-
const rpc = await runtime.getRpc();
|
|
169
|
-
const resp = await rpc.call("assemble_context_internal", {
|
|
170
|
-
sessionId: args.sessionId,
|
|
171
|
-
sessionKey: args.sessionKey,
|
|
172
|
-
userId: args.userId,
|
|
173
|
-
messages,
|
|
174
|
-
tokenBudget: args.tokenBudget,
|
|
175
|
-
prompt: args.prompt,
|
|
176
|
-
emitDebug: true,
|
|
177
|
-
config: {
|
|
178
|
-
useSessionRecallProjection: cfg.useSessionRecallProjection,
|
|
179
|
-
useSessionSummarySearchExperiment: cfg.useSessionSummarySearchExperiment,
|
|
180
|
-
tokenBudgetFraction: cfg.tokenBudgetFraction,
|
|
181
|
-
authoredHardBudgetFraction: cfg.authoredHardBudgetFraction,
|
|
182
|
-
authoredSoftBudgetFraction: cfg.authoredSoftBudgetFraction,
|
|
183
|
-
elevatedGuidanceBudgetFraction: cfg.elevatedGuidanceBudgetFraction,
|
|
184
|
-
topK: cfg.topK,
|
|
185
|
-
continuityMinTurns: cfg.continuityMinTurns,
|
|
186
|
-
continuityTailBudgetTokens: cfg.continuityTailBudgetTokens,
|
|
187
|
-
continuityPriorContextTokens: cfg.continuityPriorContextTokens,
|
|
188
|
-
compactThreshold: cfg.compactThreshold,
|
|
189
|
-
compactSessionTokenBudget: cfg.compactSessionTokenBudget,
|
|
190
|
-
section7Theta1: cfg.section7Theta1,
|
|
191
|
-
section7Kappa: cfg.section7Kappa,
|
|
192
|
-
section7HopEta: cfg.section7HopEta,
|
|
193
|
-
section7HopThreshold: cfg.section7HopThreshold,
|
|
194
|
-
section7CoarseTopK: cfg.section7CoarseTopK,
|
|
195
|
-
section7SecondPassTopK: cfg.section7SecondPassTopK,
|
|
196
|
-
section7AuthorityRecencyLambda: cfg.section7AuthorityRecencyLambda,
|
|
197
|
-
section7AuthorityRecencyWeight: cfg.section7AuthorityRecencyWeight,
|
|
198
|
-
section7AuthorityFrequencyWeight: cfg.section7AuthorityFrequencyWeight,
|
|
199
|
-
section7AuthorityAuthoredWeight: cfg.section7AuthorityAuthoredWeight,
|
|
200
|
-
recoveryFloorScore: cfg.recoveryFloorScore,
|
|
201
|
-
recoveryMinTopK: cfg.recoveryMinTopK,
|
|
202
|
-
recoveryMinConfidenceMean: cfg.recoveryMinConfidenceMean,
|
|
203
|
-
recencyLambdaSession: cfg.recencyLambdaSession,
|
|
204
|
-
recencyLambdaUser: cfg.recencyLambdaUser,
|
|
205
|
-
recencyLambdaGlobal: cfg.recencyLambdaGlobal,
|
|
206
|
-
ingestionGateThreshold: cfg.ingestionGateThreshold,
|
|
207
|
-
},
|
|
208
|
-
});
|
|
209
|
-
return normalizeAssembleResult(resp);
|
|
210
329
|
},
|
|
211
330
|
async compact(args) {
|
|
212
331
|
const request = buildCompactSessionRequest(args);
|
|
213
332
|
const kernel = runtime.getKernel();
|
|
214
333
|
if (kernel) {
|
|
215
|
-
return await kernel.compactSession(request);
|
|
334
|
+
return normalizeCompactResult(await kernel.compactSession(request));
|
|
216
335
|
}
|
|
217
336
|
const rpc = await runtime.getRpc();
|
|
218
|
-
return await rpc.call("compact_session", request);
|
|
337
|
+
return normalizeCompactResult(await rpc.call("compact_session", request));
|
|
219
338
|
},
|
|
220
339
|
async afterTurn(args) {
|
|
221
340
|
const messages = normalizeKernelMessages(args.messages);
|
package/openclaw.plugin.json
CHANGED