@xdarkicex/openclaw-memory-libravdb 1.10.14-beta.1 → 1.10.14-beta.3

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.
@@ -79,6 +79,14 @@ function normalizeCompactResult(response, options = {}) {
79
79
  const tokenAccumulatorAfter = typeof response?.tokenAccumulatorAfter === "number" ? response.tokenAccumulatorAfter : undefined;
80
80
  const totalTurns = typeof response?.totalTurns === "bigint" ? response.totalTurns : undefined;
81
81
  const skippedNoNewTurns = typeof response?.skippedNoNewTurns === "boolean" ? response.skippedNoNewTurns : undefined;
82
+ // The daemon deliberately reports didCompact=false when the session has
83
+ // already been compacted and no new turns have arrived. That is still a
84
+ // successful compaction handoff for OpenClaw: the daemon-owned projection
85
+ // remains valid and must be activated so the host retries against it.
86
+ const alreadyCompacted = skippedNoNewTurns === true &&
87
+ lastCompactedTurn != null &&
88
+ lastCompactedTurn > 0n;
89
+ const effectiveCompacted = didCompact || alreadyCompacted;
82
90
  if (lastCompactedTurn != null ||
83
91
  tokenAccumulatorAfter != null ||
84
92
  totalTurns != null ||
@@ -106,14 +114,14 @@ function normalizeCompactResult(response, options = {}) {
106
114
  // instead of accepting a bloated session.
107
115
  const threshold = options.threshold;
108
116
  const overBudget = threshold != null && tokensBefore >= threshold;
109
- const engineRefused = !didCompact && overBudget;
117
+ const engineRefused = !effectiveCompacted && overBudget;
110
118
  const tokensAfter = didCompact && typeof response?.tokensAfter === "number" && response.tokensAfter >= 0
111
119
  ? response.tokensAfter
112
120
  : undefined;
113
121
  return {
114
122
  ok: !engineRefused,
115
- compacted: didCompact,
116
- ...(didCompact ? {} : { reason: engineRefused ? "overbudget_not_compacted" : "not_compacted" }),
123
+ compacted: effectiveCompacted,
124
+ ...(effectiveCompacted ? {} : { reason: engineRefused ? "overbudget_not_compacted" : "not_compacted" }),
117
125
  result: {
118
126
  tokensBefore,
119
127
  ...(tokensAfter != null ? { tokensAfter } : {}),
@@ -812,12 +820,54 @@ function enforceCompactedProjectionBudgetInvariant(result, tokenBudget) {
812
820
  }
813
821
  function buildBudgetFallbackContext(messages, tokenBudget) {
814
822
  const effectiveBudget = resolveEffectiveAssembleBudget(tokenBudget);
815
- const fallbackMessages = trimMessagesToBudget(messages.map((message) => ({ ...message })), effectiveBudget);
816
- return {
817
- messages: fallbackMessages,
818
- estimatedTokens: approximateMessagesTokens(fallbackMessages),
823
+ const sourceTokens = approximateMessagesTokens(messages);
824
+ if (sourceTokens <= effectiveBudget) {
825
+ return {
826
+ messages,
827
+ estimatedTokens: sourceTokens,
828
+ systemPromptAddition: "",
829
+ promptAuthority: PROMPT_AUTHORITY_PREASSEMBLY_MAY_OVERFLOW,
830
+ };
831
+ }
832
+ // This is a pressure-relief projection, not an attempt to replay the
833
+ // daemon's normalized messages. It retains exact OpenClaw source objects
834
+ // and keeps the newest user/tool bundle intact. Because it is strictly
835
+ // smaller than the preassembly transcript, OpenClaw must precheck this
836
+ // projection itself; otherwise it discards the trim and retries the full
837
+ // overflowing session forever when daemon compaction is temporarily unable
838
+ // to make semantic progress (for example a singleton source turn).
839
+ const projection = enforceCompactedProjectionBudgetInvariant({
840
+ messages,
841
+ estimatedTokens: sourceTokens,
819
842
  systemPromptAddition: "",
820
- promptAuthority: PROMPT_AUTHORITY_PREASSEMBLY_MAY_OVERFLOW,
843
+ promptAuthority: "assembled",
844
+ }, tokenBudget);
845
+ if (projection.estimatedTokens <= effectiveBudget) {
846
+ return projection;
847
+ }
848
+ // A single newest user message can itself exceed the entire safe prompt
849
+ // budget. There is no tool-protocol-safe suffix to select in that case, so
850
+ // preserve the latest replay-safe user request and truncate only its text.
851
+ // This is the terminal local safety valve; it is preferable to repeatedly
852
+ // re-sending the unbounded transcript and permanently wedging the session.
853
+ const latestUser = findLastReplaySafeUserMessage(messages);
854
+ if (latestUser) {
855
+ const content = truncateContentToTokenBudget(latestUser.content, Math.max(1, effectiveBudget - 8));
856
+ if (content) {
857
+ const truncatedUser = { ...latestUser, content };
858
+ return {
859
+ ...projection,
860
+ messages: [truncatedUser],
861
+ estimatedTokens: Math.min(effectiveBudget, approximateMessageTokens(truncatedUser)),
862
+ };
863
+ }
864
+ }
865
+ // Non-conversational/system-only transcripts have no user turn to protect.
866
+ // Drop them rather than claiming an under-budget projection that is not one.
867
+ return {
868
+ ...projection,
869
+ messages: [],
870
+ estimatedTokens: 0,
821
871
  };
822
872
  }
823
873
  const DAEMON_AUTHORED_CONTEXT_RE = /<authored_context\b[^>]*>([\s\S]*?)<\/authored_context>/gi;
package/dist/index.js CHANGED
@@ -18903,6 +18903,8 @@ function normalizeCompactResult(response, options = {}) {
18903
18903
  const tokenAccumulatorAfter = typeof response?.tokenAccumulatorAfter === "number" ? response.tokenAccumulatorAfter : void 0;
18904
18904
  const totalTurns = typeof response?.totalTurns === "bigint" ? response.totalTurns : void 0;
18905
18905
  const skippedNoNewTurns = typeof response?.skippedNoNewTurns === "boolean" ? response.skippedNoNewTurns : void 0;
18906
+ const alreadyCompacted = skippedNoNewTurns === true && lastCompactedTurn != null && lastCompactedTurn > 0n;
18907
+ const effectiveCompacted = didCompact || alreadyCompacted;
18906
18908
  if (lastCompactedTurn != null || tokenAccumulatorAfter != null || totalTurns != null || skippedNoNewTurns != null) {
18907
18909
  options.logger?.info?.(
18908
18910
  `[compact:trace] daemon state lastCompactedTurn=${lastCompactedTurn?.toString() ?? "unknown"} tokenAccumulatorAfter=${tokenAccumulatorAfter ?? "unknown"} totalTurns=${totalTurns?.toString() ?? "unknown"} skippedNoNewTurns=${skippedNoNewTurns ?? "unknown"}`
@@ -18922,12 +18924,12 @@ function normalizeCompactResult(response, options = {}) {
18922
18924
  };
18923
18925
  const threshold = options.threshold;
18924
18926
  const overBudget = threshold != null && tokensBefore >= threshold;
18925
- const engineRefused = !didCompact && overBudget;
18927
+ const engineRefused = !effectiveCompacted && overBudget;
18926
18928
  const tokensAfter = didCompact && typeof response?.tokensAfter === "number" && response.tokensAfter >= 0 ? response.tokensAfter : void 0;
18927
18929
  return {
18928
18930
  ok: !engineRefused,
18929
- compacted: didCompact,
18930
- ...didCompact ? {} : { reason: engineRefused ? "overbudget_not_compacted" : "not_compacted" },
18931
+ compacted: effectiveCompacted,
18932
+ ...effectiveCompacted ? {} : { reason: engineRefused ? "overbudget_not_compacted" : "not_compacted" },
18931
18933
  result: {
18932
18934
  tokensBefore,
18933
18935
  ...tokensAfter != null ? { tokensAfter } : {},
@@ -19481,15 +19483,40 @@ function enforceCompactedProjectionBudgetInvariant(result, tokenBudget) {
19481
19483
  }
19482
19484
  function buildBudgetFallbackContext(messages, tokenBudget) {
19483
19485
  const effectiveBudget = resolveEffectiveAssembleBudget(tokenBudget);
19484
- const fallbackMessages = trimMessagesToBudget(
19485
- messages.map((message) => ({ ...message })),
19486
- effectiveBudget
19487
- );
19488
- return {
19489
- messages: fallbackMessages,
19490
- estimatedTokens: approximateMessagesTokens(fallbackMessages),
19486
+ const sourceTokens = approximateMessagesTokens(messages);
19487
+ if (sourceTokens <= effectiveBudget) {
19488
+ return {
19489
+ messages,
19490
+ estimatedTokens: sourceTokens,
19491
+ systemPromptAddition: "",
19492
+ promptAuthority: PROMPT_AUTHORITY_PREASSEMBLY_MAY_OVERFLOW
19493
+ };
19494
+ }
19495
+ const projection = enforceCompactedProjectionBudgetInvariant({
19496
+ messages,
19497
+ estimatedTokens: sourceTokens,
19491
19498
  systemPromptAddition: "",
19492
- promptAuthority: PROMPT_AUTHORITY_PREASSEMBLY_MAY_OVERFLOW
19499
+ promptAuthority: "assembled"
19500
+ }, tokenBudget);
19501
+ if (projection.estimatedTokens <= effectiveBudget) {
19502
+ return projection;
19503
+ }
19504
+ const latestUser = findLastReplaySafeUserMessage(messages);
19505
+ if (latestUser) {
19506
+ const content = truncateContentToTokenBudget(latestUser.content, Math.max(1, effectiveBudget - 8));
19507
+ if (content) {
19508
+ const truncatedUser = { ...latestUser, content };
19509
+ return {
19510
+ ...projection,
19511
+ messages: [truncatedUser],
19512
+ estimatedTokens: Math.min(effectiveBudget, approximateMessageTokens(truncatedUser))
19513
+ };
19514
+ }
19515
+ }
19516
+ return {
19517
+ ...projection,
19518
+ messages: [],
19519
+ estimatedTokens: 0
19493
19520
  };
19494
19521
  }
19495
19522
  var DAEMON_AUTHORED_CONTEXT_RE = /<authored_context\b[^>]*>([\s\S]*?)<\/authored_context>/gi;
@@ -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.14-beta.1",
5
+ "version": "1.10.14-beta.3",
6
6
  "kind": [
7
7
  "memory",
8
8
  "context-engine"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xdarkicex/openclaw-memory-libravdb",
3
- "version": "1.10.14-beta.1",
3
+ "version": "1.10.14-beta.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",