@xdarkicex/openclaw-memory-libravdb 1.4.12 → 1.4.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.
@@ -1,5 +1,6 @@
1
1
  const APPROX_CHARS_PER_TOKEN = 4;
2
2
  const ASSEMBLE_BUDGET_HEADROOM_TOKENS = 256;
3
+ const DEFAULT_COMPACTION_THRESHOLD_FRACTION = 0.8;
3
4
  function requireSessionId(sessionId, operation) {
4
5
  const normalized = typeof sessionId === "string" ? sessionId.trim() : "";
5
6
  if (normalized.length > 0) {
@@ -100,6 +101,33 @@ function approximateMessageTokens(message) {
100
101
  function approximateMessagesTokens(messages) {
101
102
  return messages.reduce((sum, message) => sum + approximateMessageTokens(message), 0);
102
103
  }
104
+ function normalizeTokenBudget(tokenBudget) {
105
+ if (typeof tokenBudget !== "number" || !Number.isFinite(tokenBudget) || tokenBudget <= 0) {
106
+ return undefined;
107
+ }
108
+ return Math.max(1, Math.floor(tokenBudget));
109
+ }
110
+ function resolveEffectiveAssembleBudget(tokenBudget) {
111
+ const normalized = normalizeTokenBudget(tokenBudget) ?? 1;
112
+ return Math.max(1, normalized - ASSEMBLE_BUDGET_HEADROOM_TOKENS);
113
+ }
114
+ function normalizeThresholdFraction(fraction) {
115
+ if (typeof fraction !== "number" || !Number.isFinite(fraction)) {
116
+ return DEFAULT_COMPACTION_THRESHOLD_FRACTION;
117
+ }
118
+ return Math.min(0.99, Math.max(0.05, fraction));
119
+ }
120
+ function resolveDynamicCompactThreshold(tokenBudget, compactThreshold, compactionThresholdFraction) {
121
+ if (typeof compactThreshold === "number" && Number.isFinite(compactThreshold) && compactThreshold > 0) {
122
+ return Math.max(1, Math.floor(compactThreshold));
123
+ }
124
+ const normalizedBudget = normalizeTokenBudget(tokenBudget);
125
+ if (normalizedBudget == null) {
126
+ return undefined;
127
+ }
128
+ const fraction = normalizeThresholdFraction(compactionThresholdFraction);
129
+ return Math.max(1, Math.floor(normalizedBudget * fraction));
130
+ }
103
131
  function truncateContentToTokenBudget(content, tokenBudget) {
104
132
  if (tokenBudget <= 0)
105
133
  return "";
@@ -140,7 +168,7 @@ function enforceTokenBudgetInvariant(result, tokenBudget) {
140
168
  return result;
141
169
  }
142
170
  const hardBudget = Math.max(1, Math.floor(tokenBudget));
143
- const effectiveBudget = Math.max(1, hardBudget - ASSEMBLE_BUDGET_HEADROOM_TOKENS);
171
+ const effectiveBudget = resolveEffectiveAssembleBudget(hardBudget);
144
172
  const estimated = typeof result.estimatedTokens === "number" ? result.estimatedTokens : 0;
145
173
  const approxFromMessages = approximateMessagesTokens(result.messages);
146
174
  if (estimated <= effectiveBudget && approxFromMessages <= effectiveBudget) {
@@ -154,6 +182,15 @@ function enforceTokenBudgetInvariant(result, tokenBudget) {
154
182
  estimatedTokens: Math.min(effectiveBudget, trimmedEstimate),
155
183
  };
156
184
  }
185
+ function buildBudgetFallbackContext(messages, tokenBudget) {
186
+ const effectiveBudget = resolveEffectiveAssembleBudget(tokenBudget);
187
+ const fallbackMessages = trimMessagesToBudget(messages.map((message) => ({ ...message })), effectiveBudget);
188
+ return {
189
+ messages: fallbackMessages,
190
+ estimatedTokens: approximateMessagesTokens(fallbackMessages),
191
+ systemPromptAddition: "",
192
+ };
193
+ }
157
194
  export function normalizeKernelMessage(message) {
158
195
  return {
159
196
  role: message.role,
@@ -184,6 +221,38 @@ export function normalizeAssembleResult(result) {
184
221
  };
185
222
  }
186
223
  export function buildContextEngineFactory(runtime, cfg, recallCache, logger = console) {
224
+ const getDynamicCompactThreshold = (tokenBudget) => resolveDynamicCompactThreshold(tokenBudget, cfg.compactThreshold, cfg.compactionThresholdFraction);
225
+ const buildAssemblyConfig = (tokenBudget) => ({
226
+ useSessionRecallProjection: cfg.useSessionRecallProjection,
227
+ useSessionSummarySearchExperiment: cfg.useSessionSummarySearchExperiment,
228
+ tokenBudgetFraction: cfg.tokenBudgetFraction,
229
+ authoredHardBudgetFraction: cfg.authoredHardBudgetFraction,
230
+ authoredSoftBudgetFraction: cfg.authoredSoftBudgetFraction,
231
+ elevatedGuidanceBudgetFraction: cfg.elevatedGuidanceBudgetFraction,
232
+ topK: cfg.topK,
233
+ continuityMinTurns: cfg.continuityMinTurns,
234
+ continuityTailBudgetTokens: cfg.continuityTailBudgetTokens,
235
+ continuityPriorContextTokens: cfg.continuityPriorContextTokens,
236
+ compactThreshold: getDynamicCompactThreshold(tokenBudget),
237
+ compactSessionTokenBudget: cfg.compactSessionTokenBudget,
238
+ section7Theta1: cfg.section7Theta1,
239
+ section7Kappa: cfg.section7Kappa,
240
+ section7HopEta: cfg.section7HopEta,
241
+ section7HopThreshold: cfg.section7HopThreshold,
242
+ section7CoarseTopK: cfg.section7CoarseTopK,
243
+ section7SecondPassTopK: cfg.section7SecondPassTopK,
244
+ section7AuthorityRecencyLambda: cfg.section7AuthorityRecencyLambda,
245
+ section7AuthorityRecencyWeight: cfg.section7AuthorityRecencyWeight,
246
+ section7AuthorityFrequencyWeight: cfg.section7AuthorityFrequencyWeight,
247
+ section7AuthorityAuthoredWeight: cfg.section7AuthorityAuthoredWeight,
248
+ recoveryFloorScore: cfg.recoveryFloorScore,
249
+ recoveryMinTopK: cfg.recoveryMinTopK,
250
+ recoveryMinConfidenceMean: cfg.recoveryMinConfidenceMean,
251
+ recencyLambdaSession: cfg.recencyLambdaSession,
252
+ recencyLambdaUser: cfg.recencyLambdaUser,
253
+ recencyLambdaGlobal: cfg.recencyLambdaGlobal,
254
+ ingestionGateThreshold: cfg.ingestionGateThreshold,
255
+ });
187
256
  function buildCompactSessionRequest(args) {
188
257
  // OpenClaw core now requests budget-style compaction using tokenBudget,
189
258
  // but the current LibraVDB compact_session wire contract still expects
@@ -205,6 +274,24 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
205
274
  : {}),
206
275
  };
207
276
  }
277
+ async function runCompaction(args) {
278
+ const request = buildCompactSessionRequest(args);
279
+ const kernel = runtime.getKernel();
280
+ try {
281
+ if (kernel) {
282
+ return normalizeCompactResult(await kernel.compactSession(request));
283
+ }
284
+ const rpc = await runtime.getRpc();
285
+ return normalizeCompactResult(await rpc.call("compact_session", request));
286
+ }
287
+ catch (error) {
288
+ return {
289
+ ok: false,
290
+ compacted: false,
291
+ reason: error instanceof Error ? error.message : String(error),
292
+ };
293
+ }
294
+ }
208
295
  return {
209
296
  info: { id: "libravdb-memory", name: "LibraVDB Memory", ownsCompaction: true },
210
297
  ownsCompaction: true,
@@ -249,6 +336,20 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
249
336
  },
250
337
  async assemble(args) {
251
338
  const messages = normalizeKernelMessages(args.messages);
339
+ const currentContextTokens = approximateMessagesTokens(messages) + approximateTokenCount(args.prompt ?? "");
340
+ const dynamicCompactThreshold = getDynamicCompactThreshold(args.tokenBudget);
341
+ if (dynamicCompactThreshold != null &&
342
+ currentContextTokens >= dynamicCompactThreshold) {
343
+ const compactionResult = await runCompaction({
344
+ sessionId: args.sessionId,
345
+ tokenBudget: args.tokenBudget,
346
+ force: true,
347
+ });
348
+ if (!compactionResult.ok || !compactionResult.compacted) {
349
+ logger.warn?.(`LibraVDB predictive compaction blocked assemble path at ${currentContextTokens} tokens (threshold=${dynamicCompactThreshold}): ${compactionResult.reason ?? "compaction declined"}`);
350
+ return buildBudgetFallbackContext(messages, args.tokenBudget);
351
+ }
352
+ }
252
353
  const kernel = runtime.getKernel();
253
354
  if (kernel) {
254
355
  try {
@@ -259,18 +360,13 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
259
360
  queryText: args.prompt ?? "",
260
361
  visibleMessages: messages,
261
362
  tokenBudget: args.tokenBudget,
262
- config: {},
363
+ config: buildAssemblyConfig(args.tokenBudget),
263
364
  emitDebug: true
264
365
  })), args.tokenBudget);
265
366
  }
266
367
  catch (error) {
267
368
  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
- };
369
+ return buildBudgetFallbackContext(messages, args.tokenBudget);
274
370
  }
275
371
  }
276
372
  const rpc = await runtime.getRpc();
@@ -283,58 +379,17 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
283
379
  tokenBudget: args.tokenBudget,
284
380
  prompt: args.prompt,
285
381
  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
- },
382
+ config: buildAssemblyConfig(args.tokenBudget),
317
383
  });
318
384
  return enforceTokenBudgetInvariant(normalizeAssembleResult(resp), args.tokenBudget);
319
385
  }
320
386
  catch (error) {
321
387
  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
- };
388
+ return buildBudgetFallbackContext(messages, args.tokenBudget);
328
389
  }
329
390
  },
330
391
  async compact(args) {
331
- const request = buildCompactSessionRequest(args);
332
- const kernel = runtime.getKernel();
333
- if (kernel) {
334
- return normalizeCompactResult(await kernel.compactSession(request));
335
- }
336
- const rpc = await runtime.getRpc();
337
- return normalizeCompactResult(await rpc.call("compact_session", request));
392
+ return await runCompaction(args);
338
393
  },
339
394
  async afterTurn(args) {
340
395
  const messages = normalizeKernelMessages(args.messages);
package/dist/types.d.ts CHANGED
@@ -63,6 +63,7 @@ export interface PluginConfig {
63
63
  continuityTailBudgetTokens?: number;
64
64
  continuityPriorContextTokens?: number;
65
65
  compactThreshold?: number;
66
+ compactionThresholdFraction?: number;
66
67
  compactSessionTokenBudget?: number;
67
68
  section7CoarseTopK?: number;
68
69
  section7SecondPassTopK?: number;
@@ -2,7 +2,7 @@
2
2
  "id": "libravdb-memory",
3
3
  "name": "LibraVDB Memory",
4
4
  "description": "Persistent vector memory with three-tier hybrid scoring",
5
- "version": "1.4.12",
5
+ "version": "1.4.13",
6
6
  "kind": [
7
7
  "memory",
8
8
  "context-engine"
@@ -237,6 +237,11 @@
237
237
  "compactThreshold": {
238
238
  "type": "number"
239
239
  },
240
+ "compactionThresholdFraction": {
241
+ "type": "number",
242
+ "default": 0.8,
243
+ "description": "Dynamic predictive compaction trigger ratio against the active token budget. Used when compactThreshold is not explicitly set."
244
+ },
240
245
  "compactSessionTokenBudget": {
241
246
  "type": "number",
242
247
  "default": 2000,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xdarkicex/openclaw-memory-libravdb",
3
- "version": "1.4.12",
3
+ "version": "1.4.13",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",