@bd7pil/opencode-deep-memory 0.4.2 → 0.4.4
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 +62 -43
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -390,6 +390,10 @@ var PluginState = class {
|
|
|
390
390
|
return this._toolSignatures.get(callID);
|
|
391
391
|
}
|
|
392
392
|
ccStore(hash2, entry) {
|
|
393
|
+
const now = Date.now();
|
|
394
|
+
for (const [k, v] of this._ccrCache) {
|
|
395
|
+
if (now - v.createdAt > 3e5) this._ccrCache.delete(k);
|
|
396
|
+
}
|
|
393
397
|
if (this._ccrCache.size > 200) {
|
|
394
398
|
const oldest = [...this._ccrCache.entries()].sort((a, b) => a[1].createdAt - b[1].createdAt).slice(0, 50);
|
|
395
399
|
for (const [k] of oldest) this._ccrCache.delete(k);
|
|
@@ -15215,19 +15219,21 @@ function createCompactingHandler(args) {
|
|
|
15215
15219
|
}
|
|
15216
15220
|
|
|
15217
15221
|
// src/compress/pressure.ts
|
|
15218
|
-
var
|
|
15222
|
+
var FALLBACK_MAX_CONTEXT = 128e3;
|
|
15223
|
+
var OPENCODE_COMPACTION_RATIO = 0.75;
|
|
15219
15224
|
var THRESHOLDS = {
|
|
15220
15225
|
medium: 0.3,
|
|
15221
15226
|
high: 0.5
|
|
15222
15227
|
};
|
|
15223
|
-
var
|
|
15224
|
-
|
|
15225
|
-
|
|
15226
|
-
|
|
15227
|
-
|
|
15228
|
-
|
|
15229
|
-
|
|
15230
|
-
|
|
15228
|
+
var calibratedMaxContext = 0;
|
|
15229
|
+
function calibrateFromCompaction(lastInputTokens) {
|
|
15230
|
+
if (lastInputTokens <= 0) return;
|
|
15231
|
+
const derived = Math.round(lastInputTokens / OPENCODE_COMPACTION_RATIO);
|
|
15232
|
+
calibratedMaxContext = derived;
|
|
15233
|
+
}
|
|
15234
|
+
function getCalibratedMaxContext() {
|
|
15235
|
+
return calibratedMaxContext;
|
|
15236
|
+
}
|
|
15231
15237
|
function estimateTokens2(text) {
|
|
15232
15238
|
let cjk = 0;
|
|
15233
15239
|
let other = 0;
|
|
@@ -15281,8 +15287,8 @@ function extractInputTokensFromMessages(messages) {
|
|
|
15281
15287
|
}
|
|
15282
15288
|
return 0;
|
|
15283
15289
|
}
|
|
15284
|
-
function detectPressure(messages
|
|
15285
|
-
const maxContext =
|
|
15290
|
+
function detectPressure(messages) {
|
|
15291
|
+
const maxContext = calibratedMaxContext || FALLBACK_MAX_CONTEXT;
|
|
15286
15292
|
const inputTokens = extractInputTokensFromMessages(messages);
|
|
15287
15293
|
const estimated = inputTokens > 0 ? inputTokens : extractTokensFromMessages(messages);
|
|
15288
15294
|
const ratio = Math.min(estimated / maxContext, 1);
|
|
@@ -15290,7 +15296,7 @@ function detectPressure(messages, modelId) {
|
|
|
15290
15296
|
if (ratio >= THRESHOLDS.high) level = "high";
|
|
15291
15297
|
else if (ratio >= THRESHOLDS.medium) level = "medium";
|
|
15292
15298
|
else level = "low";
|
|
15293
|
-
return { level, ratio, estimatedTokens: estimated };
|
|
15299
|
+
return { level, ratio, estimatedTokens: estimated, maxContext };
|
|
15294
15300
|
}
|
|
15295
15301
|
|
|
15296
15302
|
// src/compress/dedup.ts
|
|
@@ -15366,11 +15372,17 @@ function deduplicateToolOutputs(messages, state) {
|
|
|
15366
15372
|
return deduped;
|
|
15367
15373
|
}
|
|
15368
15374
|
function simpleHash(s) {
|
|
15369
|
-
|
|
15370
|
-
|
|
15375
|
+
const len = s.length;
|
|
15376
|
+
const sampleSize = 500;
|
|
15377
|
+
let h = len;
|
|
15378
|
+
for (let i = 0; i < Math.min(len, sampleSize); i++) {
|
|
15379
|
+
h = h * 31 + s.charCodeAt(i) | 0;
|
|
15380
|
+
}
|
|
15381
|
+
const tailStart = Math.max(sampleSize, len - sampleSize);
|
|
15382
|
+
for (let i = tailStart; i < len; i++) {
|
|
15371
15383
|
h = h * 31 + s.charCodeAt(i) | 0;
|
|
15372
15384
|
}
|
|
15373
|
-
return h.toString(36)
|
|
15385
|
+
return `${len}:${h.toString(36)}`;
|
|
15374
15386
|
}
|
|
15375
15387
|
|
|
15376
15388
|
// src/compress/error-purge.ts
|
|
@@ -15562,7 +15574,8 @@ function pruneOldMessages(messages) {
|
|
|
15562
15574
|
if (p["type"] !== "text" || typeof p["text"] !== "string") continue;
|
|
15563
15575
|
const text = p["text"];
|
|
15564
15576
|
if (text.length < 500) continue;
|
|
15565
|
-
if (text === "[cleared]" || text === "[stripped]"
|
|
15577
|
+
if (text === "[cleared]" || text === "[stripped]") continue;
|
|
15578
|
+
if (text.includes("[compressed from")) continue;
|
|
15566
15579
|
const keyInfo = extractKeyInfo(text);
|
|
15567
15580
|
if (keyInfo.length < text.length * 0.6) {
|
|
15568
15581
|
p["text"] = keyInfo + "\n[compressed from " + text.length + " chars]";
|
|
@@ -15678,7 +15691,7 @@ function detectContentType(content) {
|
|
|
15678
15691
|
if (/Traceback \(most recent call last\)|at \S+\.\S+\(|Error: |Exception: |TypeError: |ReferenceError: /m.test(content)) return "error-trace";
|
|
15679
15692
|
if (/<[a-z][\s\S]*>/i.test(content) && /<(html|div|span|body|head|script|style)[\s>]/i.test(content)) return "html";
|
|
15680
15693
|
const lines = content.split("\n");
|
|
15681
|
-
const logLineCount = lines.filter((l) => /^\d{4}-\d{2}-\d{2}
|
|
15694
|
+
const logLineCount = lines.filter((l) => /^\s*(\d{4}-\d{2}-\d{2}|\[\d{4}|ERROR\b|WARN\b|INFO\b|DEBUG\b|FATAL\b|TRACE\b)/.test(l)).length;
|
|
15682
15695
|
if (lines.length > 5 && logLineCount / lines.length > 0.3) return "log";
|
|
15683
15696
|
const codePatterns = /\b(function |class |def |import |from .+ import|const |let |var |export |interface |type |struct |fn |func |pub |private |protected )\b/;
|
|
15684
15697
|
const codeLines = lines.filter((l) => codePatterns.test(l)).length;
|
|
@@ -15689,7 +15702,7 @@ function detectContentType(content) {
|
|
|
15689
15702
|
// src/compress/index.ts
|
|
15690
15703
|
function runCompressionPipeline(ctx) {
|
|
15691
15704
|
const { messages, state, logger } = ctx;
|
|
15692
|
-
const pressure = detectPressure(messages
|
|
15705
|
+
const pressure = detectPressure(messages);
|
|
15693
15706
|
state.recordInputTokens(pressure.estimatedTokens);
|
|
15694
15707
|
const stats = {
|
|
15695
15708
|
toolDedup: 0,
|
|
@@ -15704,39 +15717,23 @@ function runCompressionPipeline(ctx) {
|
|
|
15704
15717
|
};
|
|
15705
15718
|
stats.toolDedup = deduplicateToolOutputs(messages, state);
|
|
15706
15719
|
stats.errorPurge = purgeOldErrors(messages);
|
|
15707
|
-
stats.toolOutputCompressed = compressOldToolOutputs(messages, state);
|
|
15708
15720
|
stats.jsonCrushed = crushJsonToolOutputs(messages, state);
|
|
15721
|
+
stats.toolOutputCompressed = compressOldToolOutputs(messages, state);
|
|
15709
15722
|
if (pressure.level === "medium" || pressure.level === "high") {
|
|
15710
15723
|
stats.messagePruned = pruneOldMessages(messages);
|
|
15711
15724
|
}
|
|
15712
15725
|
const messagesSinceNudge = state.messagesSinceLastNudge(messages.length);
|
|
15713
15726
|
if (shouldInjectNudge(pressure.level, messagesSinceNudge)) {
|
|
15714
|
-
|
|
15715
|
-
|
|
15716
|
-
|
|
15717
|
-
(p) => typeof p === "object" && p !== null && p.type === "text"
|
|
15718
|
-
);
|
|
15719
|
-
const lastTextPart = textParts[textParts.length - 1];
|
|
15720
|
-
if (lastTextPart && typeof lastTextPart.text === "string") {
|
|
15721
|
-
lastTextPart.text += buildNudgeText(pressure.level);
|
|
15722
|
-
stats.nudgeInjected = true;
|
|
15723
|
-
state.recordNudge(messages.length);
|
|
15724
|
-
}
|
|
15727
|
+
if (injectIntoLastAssistant(messages, buildNudgeText(pressure.level))) {
|
|
15728
|
+
stats.nudgeInjected = true;
|
|
15729
|
+
state.recordNudge(messages.length);
|
|
15725
15730
|
}
|
|
15726
15731
|
}
|
|
15727
15732
|
const memoryNudge = detectMemoryNudge(messages, state.messagesSinceLastNudge(messages.length));
|
|
15728
15733
|
if (memoryNudge.injected) {
|
|
15729
|
-
|
|
15730
|
-
|
|
15731
|
-
|
|
15732
|
-
(p) => typeof p === "object" && p !== null && p.type === "text"
|
|
15733
|
-
);
|
|
15734
|
-
const lastTextPart = textParts[textParts.length - 1];
|
|
15735
|
-
if (lastTextPart && typeof lastTextPart.text === "string") {
|
|
15736
|
-
lastTextPart.text += buildMemoryNudge(memoryNudge.type);
|
|
15737
|
-
state.recordNudge(messages.length);
|
|
15738
|
-
logger?.debug("compress: memory nudge", { type: memoryNudge.type });
|
|
15739
|
-
}
|
|
15734
|
+
if (injectIntoLastAssistant(messages, buildMemoryNudge(memoryNudge.type))) {
|
|
15735
|
+
state.recordNudge(messages.length);
|
|
15736
|
+
logger?.debug("compress: memory nudge", { type: memoryNudge.type });
|
|
15740
15737
|
}
|
|
15741
15738
|
}
|
|
15742
15739
|
const active = stats.toolDedup > 0 || stats.errorPurge > 0 || stats.toolOutputCompressed > 0 || stats.jsonCrushed > 0 || stats.messagePruned > 0 || stats.nudgeInjected;
|
|
@@ -15747,6 +15744,21 @@ function runCompressionPipeline(ctx) {
|
|
|
15747
15744
|
}
|
|
15748
15745
|
return { stats };
|
|
15749
15746
|
}
|
|
15747
|
+
function injectIntoLastAssistant(messages, text) {
|
|
15748
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
15749
|
+
const msg = messages[i];
|
|
15750
|
+
if (msg.info.role !== "assistant") continue;
|
|
15751
|
+
const textParts = msg.parts.filter(
|
|
15752
|
+
(p) => typeof p === "object" && p !== null && p.type === "text"
|
|
15753
|
+
);
|
|
15754
|
+
const lastTextPart = textParts[textParts.length - 1];
|
|
15755
|
+
if (lastTextPart && typeof lastTextPart.text === "string") {
|
|
15756
|
+
lastTextPart.text += text;
|
|
15757
|
+
return true;
|
|
15758
|
+
}
|
|
15759
|
+
}
|
|
15760
|
+
return false;
|
|
15761
|
+
}
|
|
15750
15762
|
function compressOldToolOutputs(messages, state) {
|
|
15751
15763
|
let compressed = 0;
|
|
15752
15764
|
const protectedTail = messages.length - 8;
|
|
@@ -15759,7 +15771,6 @@ function compressOldToolOutputs(messages, state) {
|
|
|
15759
15771
|
if (p.state?.status !== "completed") continue;
|
|
15760
15772
|
if (!p.state.output) continue;
|
|
15761
15773
|
if (p.state.output === "[superseded by duplicate call]") continue;
|
|
15762
|
-
if (p.state.output.startsWith("[compressed")) continue;
|
|
15763
15774
|
if (p.state.output.includes("[ccr:")) continue;
|
|
15764
15775
|
const toolName = p.tool || "unknown";
|
|
15765
15776
|
const output = p.state.output;
|
|
@@ -15784,7 +15795,6 @@ function crushJsonToolOutputs(messages, state) {
|
|
|
15784
15795
|
if (p.type !== "tool") continue;
|
|
15785
15796
|
if (p.state?.status !== "completed") continue;
|
|
15786
15797
|
if (!p.state.output) continue;
|
|
15787
|
-
if (p.state.output.startsWith("[compressed")) continue;
|
|
15788
15798
|
if (p.state.output.startsWith("[superseded")) continue;
|
|
15789
15799
|
if (p.state.output.includes("[ccr:")) continue;
|
|
15790
15800
|
if (detectContentType(p.state.output) !== "json") continue;
|
|
@@ -16549,6 +16559,15 @@ var deepMemoryPlugin = async (input) => {
|
|
|
16549
16559
|
if (event.type === "session.compacted") {
|
|
16550
16560
|
const compactedSessionID = event.properties.sessionID;
|
|
16551
16561
|
logger.info("event session.compacted", { sessionID: compactedSessionID });
|
|
16562
|
+
const lastTokens = state.lastInputTokens();
|
|
16563
|
+
if (lastTokens > 0) {
|
|
16564
|
+
calibrateFromCompaction(lastTokens);
|
|
16565
|
+
logger.info("pressure calibrated", {
|
|
16566
|
+
trigger: "compaction",
|
|
16567
|
+
lastInputTokens: lastTokens,
|
|
16568
|
+
derivedMaxContext: getCalibratedMaxContext()
|
|
16569
|
+
});
|
|
16570
|
+
}
|
|
16552
16571
|
try {
|
|
16553
16572
|
const auditLogDir = projectMemoryDir(projectPath);
|
|
16554
16573
|
await mkdir4(auditLogDir, { recursive: true });
|