@bd7pil/opencode-deep-memory 0.4.0 → 0.4.1
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/README.md +4 -4
- package/dist/index.js +31 -31
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,10 +79,9 @@ Activates when context pressure exceeds thresholds. Inspired by
|
|
|
79
79
|
|
|
80
80
|
| Pressure | Threshold | Actions |
|
|
81
81
|
|----------|-----------|---------|
|
|
82
|
-
| **
|
|
83
|
-
| **medium** |
|
|
84
|
-
| **high** |
|
|
85
|
-
| **critical** | > 85% | + aggressive nudge (model prompted to compress) |
|
|
82
|
+
| **always** | every turn | tool dedup + error purge + tool output compress + JSON crush (all reversible via CCR) |
|
|
83
|
+
| **medium** | ≥ 30% context | + old message text truncation (lossy, extracts key info) |
|
|
84
|
+
| **high** | ≥ 50% context | + nudge (alerts model to save important findings)
|
|
86
85
|
|
|
87
86
|
What gets compressed at medium+:
|
|
88
87
|
|
|
@@ -179,6 +178,7 @@ updated incrementally on writes.
|
|
|
179
178
|
| `memory_forget` | Remove memory entries matching a query |
|
|
180
179
|
| `memory_expand` | Decompress a sentinel reference to its original content |
|
|
181
180
|
| `deep_expand` | Retrieve original content compressed by CCR (use `[ccr:HASH]` marker) |
|
|
181
|
+
| `deep_expand` | Retrieve original content compressed by CCR (use `[ccr:HASH]` marker) |
|
|
182
182
|
|
|
183
183
|
## Commands
|
|
184
184
|
|
package/dist/index.js
CHANGED
|
@@ -260,6 +260,7 @@ var PluginState = class {
|
|
|
260
260
|
_toolSignatures = /* @__PURE__ */ new Map();
|
|
261
261
|
_ccrCache = /* @__PURE__ */ new Map();
|
|
262
262
|
_lastInputTokens = 0;
|
|
263
|
+
_lastNudgeMessageCount = 0;
|
|
263
264
|
agentOf(sessionID) {
|
|
264
265
|
return this._agents.get(sessionID);
|
|
265
266
|
}
|
|
@@ -404,6 +405,12 @@ var PluginState = class {
|
|
|
404
405
|
lastInputTokens() {
|
|
405
406
|
return this._lastInputTokens;
|
|
406
407
|
}
|
|
408
|
+
recordNudge(messageCount) {
|
|
409
|
+
this._lastNudgeMessageCount = messageCount;
|
|
410
|
+
}
|
|
411
|
+
messagesSinceLastNudge(currentMessageCount) {
|
|
412
|
+
return currentMessageCount - this._lastNudgeMessageCount;
|
|
413
|
+
}
|
|
407
414
|
};
|
|
408
415
|
function createPluginState() {
|
|
409
416
|
return new PluginState();
|
|
@@ -15210,10 +15217,8 @@ function createCompactingHandler(args) {
|
|
|
15210
15217
|
// src/compress/pressure.ts
|
|
15211
15218
|
var DEFAULT_MAX_CONTEXT = 128e3;
|
|
15212
15219
|
var THRESHOLDS = {
|
|
15213
|
-
|
|
15214
|
-
|
|
15215
|
-
high: 0.85,
|
|
15216
|
-
critical: 0.95
|
|
15220
|
+
medium: 0.3,
|
|
15221
|
+
high: 0.5
|
|
15217
15222
|
};
|
|
15218
15223
|
var MODEL_CONTEXT_LIMITS = {
|
|
15219
15224
|
"deepseek-chat": 64e3,
|
|
@@ -15282,8 +15287,7 @@ function detectPressure(messages, modelId) {
|
|
|
15282
15287
|
const estimated = inputTokens > 0 ? inputTokens : extractTokensFromMessages(messages);
|
|
15283
15288
|
const ratio = Math.min(estimated / maxContext, 1);
|
|
15284
15289
|
let level;
|
|
15285
|
-
if (ratio >= THRESHOLDS.
|
|
15286
|
-
else if (ratio >= THRESHOLDS.high) level = "high";
|
|
15290
|
+
if (ratio >= THRESHOLDS.high) level = "high";
|
|
15287
15291
|
else if (ratio >= THRESHOLDS.medium) level = "medium";
|
|
15288
15292
|
else level = "low";
|
|
15289
15293
|
return { level, ratio, estimatedTokens: estimated };
|
|
@@ -15552,16 +15556,16 @@ function extractKeyInfo(text) {
|
|
|
15552
15556
|
|
|
15553
15557
|
// src/compress/nudge.ts
|
|
15554
15558
|
var NUDGE_COOLDOWN = 5;
|
|
15555
|
-
function shouldInjectNudge(level,
|
|
15556
|
-
if (level !== "high"
|
|
15557
|
-
if (
|
|
15559
|
+
function shouldInjectNudge(level, messagesSinceLastNudge) {
|
|
15560
|
+
if (level !== "high") return false;
|
|
15561
|
+
if (messagesSinceLastNudge < NUDGE_COOLDOWN) return false;
|
|
15558
15562
|
return true;
|
|
15559
15563
|
}
|
|
15560
15564
|
function buildNudgeText(level) {
|
|
15561
|
-
if (level === "
|
|
15562
|
-
return '\n<dm-nudge level="
|
|
15565
|
+
if (level === "high") {
|
|
15566
|
+
return '\n<dm-nudge level="high">Context pressure is high. Consider summarizing old completed tasks and moving on. Use memory_store to persist important findings before they are compressed.</dm-nudge>';
|
|
15563
15567
|
}
|
|
15564
|
-
return
|
|
15568
|
+
return "";
|
|
15565
15569
|
}
|
|
15566
15570
|
|
|
15567
15571
|
// src/compress/detector.ts
|
|
@@ -15602,25 +15606,15 @@ function runCompressionPipeline(ctx) {
|
|
|
15602
15606
|
pressureLevel: pressure.level,
|
|
15603
15607
|
estimatedTokens: pressure.estimatedTokens
|
|
15604
15608
|
};
|
|
15605
|
-
|
|
15606
|
-
|
|
15607
|
-
|
|
15608
|
-
|
|
15609
|
-
|
|
15610
|
-
level: pressure.level,
|
|
15611
|
-
ratio: pressure.ratio.toFixed(2),
|
|
15612
|
-
tokens: pressure.estimatedTokens
|
|
15613
|
-
});
|
|
15614
|
-
if (pressure.level === "medium" || pressure.level === "high" || pressure.level === "critical") {
|
|
15615
|
-
stats.toolDedup = deduplicateToolOutputs(messages, state);
|
|
15616
|
-
stats.errorPurge = purgeOldErrors(messages);
|
|
15617
|
-
stats.toolOutputCompressed = compressOldToolOutputs(messages, state);
|
|
15618
|
-
}
|
|
15619
|
-
if (pressure.level === "high" || pressure.level === "critical") {
|
|
15620
|
-
stats.jsonCrushed = crushJsonToolOutputs(messages, state);
|
|
15609
|
+
stats.toolDedup = deduplicateToolOutputs(messages, state);
|
|
15610
|
+
stats.errorPurge = purgeOldErrors(messages);
|
|
15611
|
+
stats.toolOutputCompressed = compressOldToolOutputs(messages, state);
|
|
15612
|
+
stats.jsonCrushed = crushJsonToolOutputs(messages, state);
|
|
15613
|
+
if (pressure.level === "medium" || pressure.level === "high") {
|
|
15621
15614
|
stats.messagePruned = pruneOldMessages(messages);
|
|
15622
15615
|
}
|
|
15623
|
-
|
|
15616
|
+
const messagesSinceNudge = state.messagesSinceLastNudge(messages.length);
|
|
15617
|
+
if (shouldInjectNudge(pressure.level, messagesSinceNudge)) {
|
|
15624
15618
|
const lastMsg = messages[messages.length - 1];
|
|
15625
15619
|
if (lastMsg) {
|
|
15626
15620
|
const textParts = lastMsg.parts.filter(
|
|
@@ -15630,11 +15624,15 @@ function runCompressionPipeline(ctx) {
|
|
|
15630
15624
|
if (lastTextPart && typeof lastTextPart.text === "string") {
|
|
15631
15625
|
lastTextPart.text += buildNudgeText(pressure.level);
|
|
15632
15626
|
stats.nudgeInjected = true;
|
|
15627
|
+
state.recordNudge(messages.length);
|
|
15633
15628
|
}
|
|
15634
15629
|
}
|
|
15635
15630
|
}
|
|
15636
|
-
|
|
15637
|
-
|
|
15631
|
+
const active = stats.toolDedup > 0 || stats.errorPurge > 0 || stats.toolOutputCompressed > 0 || stats.jsonCrushed > 0 || stats.messagePruned > 0 || stats.nudgeInjected;
|
|
15632
|
+
if (active) {
|
|
15633
|
+
logger?.debug("compress: pipeline result", { ...stats });
|
|
15634
|
+
} else {
|
|
15635
|
+
logger?.debug("compress: no action needed", { ratio: pressure.ratio.toFixed(2) });
|
|
15638
15636
|
}
|
|
15639
15637
|
return { stats };
|
|
15640
15638
|
}
|
|
@@ -15651,6 +15649,7 @@ function compressOldToolOutputs(messages, state) {
|
|
|
15651
15649
|
if (!p.state.output) continue;
|
|
15652
15650
|
if (p.state.output === "[superseded by duplicate call]") continue;
|
|
15653
15651
|
if (p.state.output.startsWith("[compressed")) continue;
|
|
15652
|
+
if (p.state.output.includes("[ccr:")) continue;
|
|
15654
15653
|
const toolName = p.tool || "unknown";
|
|
15655
15654
|
const output = p.state.output;
|
|
15656
15655
|
const result = compressToolOutput(toolName, output);
|
|
@@ -15676,6 +15675,7 @@ function crushJsonToolOutputs(messages, state) {
|
|
|
15676
15675
|
if (!p.state.output) continue;
|
|
15677
15676
|
if (p.state.output.startsWith("[compressed")) continue;
|
|
15678
15677
|
if (p.state.output.startsWith("[superseded")) continue;
|
|
15678
|
+
if (p.state.output.includes("[ccr:")) continue;
|
|
15679
15679
|
if (detectContentType(p.state.output) !== "json") continue;
|
|
15680
15680
|
const original = p.state.output;
|
|
15681
15681
|
const crushed_output = crushJsonArray(original);
|