@bd7pil/opencode-deep-memory 0.4.4 → 0.5.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.
package/dist/index.js CHANGED
@@ -261,6 +261,7 @@ var PluginState = class {
261
261
  _ccrCache = /* @__PURE__ */ new Map();
262
262
  _lastInputTokens = 0;
263
263
  _lastNudgeMessageCount = 0;
264
+ _modelContextWindow = 0;
264
265
  agentOf(sessionID) {
265
266
  return this._agents.get(sessionID);
266
267
  }
@@ -415,6 +416,12 @@ var PluginState = class {
415
416
  messagesSinceLastNudge(currentMessageCount) {
416
417
  return currentMessageCount - this._lastNudgeMessageCount;
417
418
  }
419
+ setModelContextWindow(tokens) {
420
+ if (tokens > 0) this._modelContextWindow = tokens;
421
+ }
422
+ getModelContextWindow() {
423
+ return this._modelContextWindow;
424
+ }
418
425
  };
419
426
  function createPluginState() {
420
427
  return new PluginState();
@@ -15228,12 +15235,16 @@ var THRESHOLDS = {
15228
15235
  var calibratedMaxContext = 0;
15229
15236
  function calibrateFromCompaction(lastInputTokens) {
15230
15237
  if (lastInputTokens <= 0) return;
15231
- const derived = Math.round(lastInputTokens / OPENCODE_COMPACTION_RATIO);
15232
- calibratedMaxContext = derived;
15238
+ calibratedMaxContext = Math.round(lastInputTokens / OPENCODE_COMPACTION_RATIO);
15233
15239
  }
15234
15240
  function getCalibratedMaxContext() {
15235
15241
  return calibratedMaxContext;
15236
15242
  }
15243
+ function maxContextFrom(modelContextWindow) {
15244
+ if (modelContextWindow > 0) return modelContextWindow;
15245
+ if (calibratedMaxContext > 0) return calibratedMaxContext;
15246
+ return FALLBACK_MAX_CONTEXT;
15247
+ }
15237
15248
  function estimateTokens2(text) {
15238
15249
  let cjk = 0;
15239
15250
  let other = 0;
@@ -15287,16 +15298,16 @@ function extractInputTokensFromMessages(messages) {
15287
15298
  }
15288
15299
  return 0;
15289
15300
  }
15290
- function detectPressure(messages) {
15291
- const maxContext = calibratedMaxContext || FALLBACK_MAX_CONTEXT;
15301
+ function detectPressure(messages, modelContextWindow) {
15302
+ const ctx = maxContextFrom(modelContextWindow || 0);
15292
15303
  const inputTokens = extractInputTokensFromMessages(messages);
15293
15304
  const estimated = inputTokens > 0 ? inputTokens : extractTokensFromMessages(messages);
15294
- const ratio = Math.min(estimated / maxContext, 1);
15305
+ const ratio = Math.min(estimated / ctx, 1);
15295
15306
  let level;
15296
15307
  if (ratio >= THRESHOLDS.high) level = "high";
15297
15308
  else if (ratio >= THRESHOLDS.medium) level = "medium";
15298
15309
  else level = "low";
15299
- return { level, ratio, estimatedTokens: estimated, maxContext };
15310
+ return { level, ratio, estimatedTokens: estimated, maxContext: ctx };
15300
15311
  }
15301
15312
 
15302
15313
  // src/compress/dedup.ts
@@ -15404,7 +15415,7 @@ function purgeOldErrors(messages) {
15404
15415
  const input = toolState["input"];
15405
15416
  for (const key of Object.keys(input)) {
15406
15417
  if (key === "command" || key === "query" || key === "path" || key === "filePath") continue;
15407
- input[key] = "[purged]";
15418
+ delete input[key];
15408
15419
  }
15409
15420
  }
15410
15421
  purged++;
@@ -15560,55 +15571,6 @@ function sha2562(data) {
15560
15571
  return createHash3("sha256").update(data).digest("hex");
15561
15572
  }
15562
15573
 
15563
- // src/compress/message-prune.ts
15564
- var PRUNE_THRESHOLD = 8;
15565
- function pruneOldMessages(messages) {
15566
- let pruned = 0;
15567
- const protectedTail = messages.length - PRUNE_THRESHOLD;
15568
- for (let i = 3; i < protectedTail; i++) {
15569
- const msg = messages[i];
15570
- if (msg.info.role !== "assistant") continue;
15571
- for (const part of msg.parts) {
15572
- if (typeof part !== "object" || part === null) continue;
15573
- const p = part;
15574
- if (p["type"] !== "text" || typeof p["text"] !== "string") continue;
15575
- const text = p["text"];
15576
- if (text.length < 500) continue;
15577
- if (text === "[cleared]" || text === "[stripped]") continue;
15578
- if (text.includes("[compressed from")) continue;
15579
- const keyInfo = extractKeyInfo(text);
15580
- if (keyInfo.length < text.length * 0.6) {
15581
- p["text"] = keyInfo + "\n[compressed from " + text.length + " chars]";
15582
- pruned++;
15583
- }
15584
- }
15585
- }
15586
- return pruned;
15587
- }
15588
- function extractKeyInfo(text) {
15589
- const lines = text.split("\n");
15590
- const keyLines = [];
15591
- let inCodeBlock = false;
15592
- for (const line of lines) {
15593
- if (line.trim().startsWith("```")) {
15594
- inCodeBlock = !inCodeBlock;
15595
- if (inCodeBlock) keyLines.push(line);
15596
- continue;
15597
- }
15598
- if (inCodeBlock) {
15599
- if (keyLines.length < 30 && line.trim()) keyLines.push(line);
15600
- continue;
15601
- }
15602
- if (/^#{1,3}\s/.test(line) || /error|fail|warning|important|critical|decision|constraint/i.test(line) || /^\s*[-*]\s/.test(line) || /^\s*\d+\.\s/.test(line)) {
15603
- keyLines.push(line);
15604
- }
15605
- }
15606
- if (keyLines.length < 3) {
15607
- return lines.slice(0, 5).join("\n");
15608
- }
15609
- return keyLines.join("\n");
15610
- }
15611
-
15612
15574
  // src/compress/nudge.ts
15613
15575
  var NUDGE_COOLDOWN = 5;
15614
15576
  function shouldInjectNudge(level, messagesSinceLastNudge) {
@@ -15702,14 +15664,13 @@ function detectContentType(content) {
15702
15664
  // src/compress/index.ts
15703
15665
  function runCompressionPipeline(ctx) {
15704
15666
  const { messages, state, logger } = ctx;
15705
- const pressure = detectPressure(messages);
15667
+ const pressure = detectPressure(messages, state.getModelContextWindow());
15706
15668
  state.recordInputTokens(pressure.estimatedTokens);
15707
15669
  const stats = {
15708
15670
  toolDedup: 0,
15709
15671
  errorPurge: 0,
15710
15672
  toolOutputCompressed: 0,
15711
15673
  jsonCrushed: 0,
15712
- messagePruned: 0,
15713
15674
  ccrStored: 0,
15714
15675
  nudgeInjected: false,
15715
15676
  pressureLevel: pressure.level,
@@ -15719,9 +15680,6 @@ function runCompressionPipeline(ctx) {
15719
15680
  stats.errorPurge = purgeOldErrors(messages);
15720
15681
  stats.jsonCrushed = crushJsonToolOutputs(messages, state);
15721
15682
  stats.toolOutputCompressed = compressOldToolOutputs(messages, state);
15722
- if (pressure.level === "medium" || pressure.level === "high") {
15723
- stats.messagePruned = pruneOldMessages(messages);
15724
- }
15725
15683
  const messagesSinceNudge = state.messagesSinceLastNudge(messages.length);
15726
15684
  if (shouldInjectNudge(pressure.level, messagesSinceNudge)) {
15727
15685
  if (injectIntoLastAssistant(messages, buildNudgeText(pressure.level))) {
@@ -15736,7 +15694,7 @@ function runCompressionPipeline(ctx) {
15736
15694
  logger?.debug("compress: memory nudge", { type: memoryNudge.type });
15737
15695
  }
15738
15696
  }
15739
- const active = stats.toolDedup > 0 || stats.errorPurge > 0 || stats.toolOutputCompressed > 0 || stats.jsonCrushed > 0 || stats.messagePruned > 0 || stats.nudgeInjected;
15697
+ const active = stats.toolDedup > 0 || stats.errorPurge > 0 || stats.toolOutputCompressed > 0 || stats.jsonCrushed > 0 || stats.nudgeInjected;
15740
15698
  if (active) {
15741
15699
  logger?.debug("compress: pipeline result", { ...stats });
15742
15700
  } else {
@@ -15908,11 +15866,12 @@ function createMessagesTransformHandler(state, logger) {
15908
15866
  tool_errors_truncated: 0,
15909
15867
  thinking_stripped: 0
15910
15868
  };
15869
+ const toRemove = [];
15911
15870
  for (let i = PROTECTED_HEAD2; i < protectedTailStart; i++) {
15912
15871
  const msg = messages[i];
15913
15872
  if (!msg?.parts?.length) continue;
15914
15873
  if (msg.info.role === "user") continue;
15915
- for (let j = 0; j < msg.parts.length; j++) {
15874
+ for (let j = msg.parts.length - 1; j >= 0; j--) {
15916
15875
  const part = msg.parts[j];
15917
15876
  if (typeof part !== "object" || part === null) continue;
15918
15877
  const p = part;
@@ -15928,10 +15887,9 @@ function createMessagesTransformHandler(state, logger) {
15928
15887
  stats.metadata_stripped++;
15929
15888
  }
15930
15889
  }
15931
- if (typeof p["text"] === "string" && p["text"] !== "[cleared]") {
15932
- p["text"] = "[cleared]";
15933
- stats.reasoning_cleared++;
15934
- }
15890
+ msg.parts.splice(j, 1);
15891
+ stats.reasoning_cleared++;
15892
+ continue;
15935
15893
  }
15936
15894
  if (partType === "tool") {
15937
15895
  const meta = p["metadata"];
@@ -15959,11 +15917,13 @@ function createMessagesTransformHandler(state, logger) {
15959
15917
  }
15960
15918
  }
15961
15919
  if (isSystemInjected(msg)) {
15962
- msg.parts.length = 0;
15963
- msg.parts.push({ type: "text", text: "[stripped]" });
15920
+ toRemove.push(i);
15964
15921
  stats.system_neutralized++;
15965
15922
  }
15966
15923
  }
15924
+ for (let r = toRemove.length - 1; r >= 0; r--) {
15925
+ messages.splice(toRemove[r], 1);
15926
+ }
15967
15927
  repairOrphanedToolCalls(messages);
15968
15928
  if (Object.values(stats).some((v) => v > 0)) {
15969
15929
  logger?.debug("messages.transform: stripped", stats);
@@ -15974,7 +15934,7 @@ function createMessagesTransformHandler(state, logger) {
15974
15934
  logger
15975
15935
  });
15976
15936
  const ds = pipelineResult.stats;
15977
- if (ds.toolDedup > 0 || ds.errorPurge > 0 || ds.toolOutputCompressed > 0 || ds.jsonCrushed > 0 || ds.messagePruned > 0 || ds.nudgeInjected) {
15937
+ if (ds.toolDedup > 0 || ds.errorPurge > 0 || ds.toolOutputCompressed > 0 || ds.jsonCrushed > 0 || ds.nudgeInjected) {
15978
15938
  logger?.debug("messages.transform: deep compression", { ...ds });
15979
15939
  state.mergeNotify({
15980
15940
  compression: stats,