@bd7pil/opencode-deep-memory 0.4.0 → 0.4.2
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 +161 -50
- 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();
|
|
@@ -829,7 +836,7 @@ ${lines.join("\n")}
|
|
|
829
836
|
}
|
|
830
837
|
|
|
831
838
|
// src/inject/system-payload.ts
|
|
832
|
-
var TOOL_HINT = 'Memory tools available: memory_search, memory_store, memory_forget. Guidelines
|
|
839
|
+
var TOOL_HINT = 'Memory tools available: memory_search, memory_store, memory_forget, memory_expand, deep_expand. Guidelines:\n (1) BEFORE making ANY technical decision, search: memory_search(query="decision OR decided OR chose OR \u9009\u62E9 OR \u51B3\u5B9A", scope="project")\n (2) BEFORE fixing an error, search for known pitfalls: memory_search(query="gotcha OR error OR bug OR \u5751 OR \u9519\u8BEF", scope="project")\n (3) AFTER fixing an error, store it: memory_store(type="gotcha", content="[error]: ... \u2192 [fix]: ...", scope="project")\n (4) WHEN user states a constraint/rule, store it: memory_store(type="constraint", content="...", scope="project")\n (5) WHEN a technical decision is made, store it: memory_store(type="decision", content="[decision]: ... \u2192 [reason]: ...", scope="project")';
|
|
833
840
|
async function composeSystemPayload(opts) {
|
|
834
841
|
const { state, sessionID, projectPath, mode, searchService, userQuery, logger, tracker } = opts;
|
|
835
842
|
const agent = sessionID ? state.agentOf(sessionID) : void 0;
|
|
@@ -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,15 +15287,28 @@ 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 };
|
|
15290
15294
|
}
|
|
15291
15295
|
|
|
15292
15296
|
// src/compress/dedup.ts
|
|
15293
|
-
var PROTECTED_TOOLS = /* @__PURE__ */ new Set([
|
|
15297
|
+
var PROTECTED_TOOLS = /* @__PURE__ */ new Set([
|
|
15298
|
+
"question",
|
|
15299
|
+
"edit",
|
|
15300
|
+
"write",
|
|
15301
|
+
"todowrite",
|
|
15302
|
+
"todoread",
|
|
15303
|
+
"memory_store",
|
|
15304
|
+
"memory_search",
|
|
15305
|
+
"memory_forget",
|
|
15306
|
+
"memory_expand",
|
|
15307
|
+
"deep_expand"
|
|
15308
|
+
]);
|
|
15309
|
+
var NEVER_DEDUP = /* @__PURE__ */ new Set(["read", "bash", "grep", "glob", "find", "search"]);
|
|
15310
|
+
var KEEP_RECENT = 8;
|
|
15311
|
+
var PROTECTED_HEAD = 3;
|
|
15294
15312
|
function createToolSignature(tool5, args) {
|
|
15295
15313
|
if (!args) return tool5;
|
|
15296
15314
|
const sorted = Object.keys(args).sort().map((k) => `${k}:${JSON.stringify(args[k])}`).join(",");
|
|
@@ -15298,8 +15316,12 @@ function createToolSignature(tool5, args) {
|
|
|
15298
15316
|
}
|
|
15299
15317
|
function deduplicateToolOutputs(messages, state) {
|
|
15300
15318
|
let deduped = 0;
|
|
15319
|
+
const totalMessages = messages.length;
|
|
15320
|
+
if (totalMessages <= KEEP_RECENT + PROTECTED_HEAD) return 0;
|
|
15321
|
+
const protectedTailStart = totalMessages - KEEP_RECENT;
|
|
15301
15322
|
const seen = /* @__PURE__ */ new Map();
|
|
15302
|
-
for (
|
|
15323
|
+
for (let i = PROTECTED_HEAD; i < protectedTailStart; i++) {
|
|
15324
|
+
const msg = messages[i];
|
|
15303
15325
|
for (const part of msg.parts) {
|
|
15304
15326
|
if (typeof part !== "object" || part === null) continue;
|
|
15305
15327
|
const p = part;
|
|
@@ -15308,24 +15330,48 @@ function deduplicateToolOutputs(messages, state) {
|
|
|
15308
15330
|
const callID = p["callID"];
|
|
15309
15331
|
if (!toolName || !callID) continue;
|
|
15310
15332
|
if (PROTECTED_TOOLS.has(toolName)) continue;
|
|
15333
|
+
if (NEVER_DEDUP.has(toolName)) continue;
|
|
15311
15334
|
const status = p["state"]?.["status"];
|
|
15312
15335
|
if (status !== "completed") continue;
|
|
15313
15336
|
const toolState = p["state"];
|
|
15337
|
+
const output = toolState["output"];
|
|
15338
|
+
if (typeof output !== "string") continue;
|
|
15339
|
+
if (output === "[superseded by duplicate call]") continue;
|
|
15340
|
+
if (output.includes("[ccr:")) continue;
|
|
15314
15341
|
const input = toolState["input"];
|
|
15315
15342
|
const signature = createToolSignature(toolName, input);
|
|
15343
|
+
const outputHash = simpleHash(output);
|
|
15316
15344
|
const existing = seen.get(signature);
|
|
15317
|
-
if (existing
|
|
15318
|
-
|
|
15319
|
-
|
|
15320
|
-
|
|
15345
|
+
if (existing) {
|
|
15346
|
+
if (existing.outputHash === outputHash) {
|
|
15347
|
+
const prevMsg = messages[existing.msgIdx];
|
|
15348
|
+
for (const prevPart of prevMsg.parts) {
|
|
15349
|
+
if (typeof prevPart !== "object" || prevPart === null) continue;
|
|
15350
|
+
const pp = prevPart;
|
|
15351
|
+
if (pp["type"] !== "tool") continue;
|
|
15352
|
+
const ppState = pp["state"];
|
|
15353
|
+
if (ppState?.["output"] === "[superseded by duplicate call]") continue;
|
|
15354
|
+
if (typeof ppState?.["output"] === "string" && simpleHash(ppState["output"]) === outputHash) {
|
|
15355
|
+
ppState["output"] = "[superseded by duplicate call]";
|
|
15356
|
+
deduped++;
|
|
15357
|
+
}
|
|
15358
|
+
}
|
|
15359
|
+
}
|
|
15360
|
+
seen.set(signature, { msgIdx: i, outputHash });
|
|
15321
15361
|
} else {
|
|
15322
|
-
seen.set(signature,
|
|
15323
|
-
state.recordToolSignature(callID, signature);
|
|
15362
|
+
seen.set(signature, { msgIdx: i, outputHash });
|
|
15324
15363
|
}
|
|
15325
15364
|
}
|
|
15326
15365
|
}
|
|
15327
15366
|
return deduped;
|
|
15328
15367
|
}
|
|
15368
|
+
function simpleHash(s) {
|
|
15369
|
+
let h = 0;
|
|
15370
|
+
for (let i = 0; i < Math.min(s.length, 1e3); i++) {
|
|
15371
|
+
h = h * 31 + s.charCodeAt(i) | 0;
|
|
15372
|
+
}
|
|
15373
|
+
return h.toString(36);
|
|
15374
|
+
}
|
|
15329
15375
|
|
|
15330
15376
|
// src/compress/error-purge.ts
|
|
15331
15377
|
var ERROR_PURGE_TURN_THRESHOLD = 4;
|
|
@@ -15552,16 +15598,70 @@ function extractKeyInfo(text) {
|
|
|
15552
15598
|
|
|
15553
15599
|
// src/compress/nudge.ts
|
|
15554
15600
|
var NUDGE_COOLDOWN = 5;
|
|
15555
|
-
function shouldInjectNudge(level,
|
|
15556
|
-
if (level !== "high"
|
|
15557
|
-
if (
|
|
15601
|
+
function shouldInjectNudge(level, messagesSinceLastNudge) {
|
|
15602
|
+
if (level !== "high") return false;
|
|
15603
|
+
if (messagesSinceLastNudge < NUDGE_COOLDOWN) return false;
|
|
15558
15604
|
return true;
|
|
15559
15605
|
}
|
|
15560
15606
|
function buildNudgeText(level) {
|
|
15561
|
-
if (level === "
|
|
15562
|
-
return '\n<dm-nudge level="
|
|
15607
|
+
if (level === "high") {
|
|
15608
|
+
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>';
|
|
15609
|
+
}
|
|
15610
|
+
return "";
|
|
15611
|
+
}
|
|
15612
|
+
|
|
15613
|
+
// src/compress/memory-nudge.ts
|
|
15614
|
+
var MEMORY_NUDGE_COOLDOWN = 3;
|
|
15615
|
+
var DECISION_PATTERNS = [
|
|
15616
|
+
/\b(?:decided|decision|chose|chosen|picked|selected)\b/i,
|
|
15617
|
+
/\b(?:采用|选择|决定|确定|选用)\b/,
|
|
15618
|
+
/\b(?:use|using|go with|went with)\b.*\b(?:because|since|due to)\b/i
|
|
15619
|
+
];
|
|
15620
|
+
var CONSTRAINT_PATTERNS = [
|
|
15621
|
+
/\b(?:must not|cannot|should not|do not|never|always)\b/i,
|
|
15622
|
+
/\b(?:constraint|restriction|limitation|requirement)\b/i,
|
|
15623
|
+
/\b(?:不能|必须|禁止|约束|限制|要求|务必)\b/
|
|
15624
|
+
];
|
|
15625
|
+
var ERROR_FIX_PATTERNS = [
|
|
15626
|
+
/\b(?:fix|fixed|resolve|resolved|patch|corrected)\b/i,
|
|
15627
|
+
/\b(?:修复|修复了|解决|解决了)\b/,
|
|
15628
|
+
/\b(?:the (?:bug|error|issue) (?:was|is)|root cause)\b/i
|
|
15629
|
+
];
|
|
15630
|
+
function detectMemoryNudge(messages, messagesSinceLastNudge) {
|
|
15631
|
+
if (messagesSinceLastNudge < MEMORY_NUDGE_COOLDOWN) {
|
|
15632
|
+
return { injected: false, type: null };
|
|
15633
|
+
}
|
|
15634
|
+
const protectedTail = Math.max(0, messages.length - 3);
|
|
15635
|
+
const recentMessages = messages.slice(protectedTail);
|
|
15636
|
+
const recentAssistantText = recentMessages.filter((m) => m.info.role === "assistant").flatMap((m) => m.parts.filter((p) => p.type === "text").map((p) => p.text || "")).join("\n");
|
|
15637
|
+
const recentUserText = recentMessages.filter((m) => m.info.role === "user").flatMap((m) => m.parts.filter((p) => p.type === "text").map((p) => p.text || "")).join("\n");
|
|
15638
|
+
const hasRecentToolError = recentMessages.some(
|
|
15639
|
+
(m) => m.parts.some((p) => p.type === "tool" && p.state?.status === "error")
|
|
15640
|
+
);
|
|
15641
|
+
if (hasRecentToolError && ERROR_FIX_PATTERNS.some((p) => p.test(recentAssistantText))) {
|
|
15642
|
+
return { injected: true, type: "gotcha" };
|
|
15643
|
+
}
|
|
15644
|
+
if (CONSTRAINT_PATTERNS.some((p) => p.test(recentUserText))) {
|
|
15645
|
+
return { injected: true, type: "constraint" };
|
|
15646
|
+
}
|
|
15647
|
+
if (DECISION_PATTERNS.some((p) => p.test(recentAssistantText))) {
|
|
15648
|
+
return { injected: true, type: "decision" };
|
|
15649
|
+
}
|
|
15650
|
+
return { injected: false, type: null };
|
|
15651
|
+
}
|
|
15652
|
+
function buildMemoryNudge(type) {
|
|
15653
|
+
switch (type) {
|
|
15654
|
+
case "gotcha":
|
|
15655
|
+
return `
|
|
15656
|
+
<memory-nudge type="gotcha">You just fixed an error. Use memory_store(type="gotcha") to save what went wrong and how you fixed it, so future sessions don't repeat this mistake.</memory-nudge>`;
|
|
15657
|
+
case "constraint":
|
|
15658
|
+
return '\n<memory-nudge type="constraint">The user expressed a constraint or rule. Use memory_store(type="constraint") to persist it across sessions.</memory-nudge>';
|
|
15659
|
+
case "decision":
|
|
15660
|
+
return `
|
|
15661
|
+
<memory-nudge type="decision">A technical decision was made. Use memory_store(type="decision") to record what was decided and why, so future sessions don't re-decide.</memory-nudge>`;
|
|
15662
|
+
default:
|
|
15663
|
+
return "";
|
|
15563
15664
|
}
|
|
15564
|
-
return '\n<dm-nudge level="high">Context is getting large. Consider compressing old tool outputs and messages to free space.</dm-nudge>';
|
|
15565
15665
|
}
|
|
15566
15666
|
|
|
15567
15667
|
// src/compress/detector.ts
|
|
@@ -15602,25 +15702,15 @@ function runCompressionPipeline(ctx) {
|
|
|
15602
15702
|
pressureLevel: pressure.level,
|
|
15603
15703
|
estimatedTokens: pressure.estimatedTokens
|
|
15604
15704
|
};
|
|
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);
|
|
15705
|
+
stats.toolDedup = deduplicateToolOutputs(messages, state);
|
|
15706
|
+
stats.errorPurge = purgeOldErrors(messages);
|
|
15707
|
+
stats.toolOutputCompressed = compressOldToolOutputs(messages, state);
|
|
15708
|
+
stats.jsonCrushed = crushJsonToolOutputs(messages, state);
|
|
15709
|
+
if (pressure.level === "medium" || pressure.level === "high") {
|
|
15621
15710
|
stats.messagePruned = pruneOldMessages(messages);
|
|
15622
15711
|
}
|
|
15623
|
-
|
|
15712
|
+
const messagesSinceNudge = state.messagesSinceLastNudge(messages.length);
|
|
15713
|
+
if (shouldInjectNudge(pressure.level, messagesSinceNudge)) {
|
|
15624
15714
|
const lastMsg = messages[messages.length - 1];
|
|
15625
15715
|
if (lastMsg) {
|
|
15626
15716
|
const textParts = lastMsg.parts.filter(
|
|
@@ -15630,11 +15720,30 @@ function runCompressionPipeline(ctx) {
|
|
|
15630
15720
|
if (lastTextPart && typeof lastTextPart.text === "string") {
|
|
15631
15721
|
lastTextPart.text += buildNudgeText(pressure.level);
|
|
15632
15722
|
stats.nudgeInjected = true;
|
|
15723
|
+
state.recordNudge(messages.length);
|
|
15633
15724
|
}
|
|
15634
15725
|
}
|
|
15635
15726
|
}
|
|
15636
|
-
|
|
15637
|
-
|
|
15727
|
+
const memoryNudge = detectMemoryNudge(messages, state.messagesSinceLastNudge(messages.length));
|
|
15728
|
+
if (memoryNudge.injected) {
|
|
15729
|
+
const lastMsg = messages[messages.length - 1];
|
|
15730
|
+
if (lastMsg) {
|
|
15731
|
+
const textParts = lastMsg.parts.filter(
|
|
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
|
+
}
|
|
15740
|
+
}
|
|
15741
|
+
}
|
|
15742
|
+
const active = stats.toolDedup > 0 || stats.errorPurge > 0 || stats.toolOutputCompressed > 0 || stats.jsonCrushed > 0 || stats.messagePruned > 0 || stats.nudgeInjected;
|
|
15743
|
+
if (active) {
|
|
15744
|
+
logger?.debug("compress: pipeline result", { ...stats });
|
|
15745
|
+
} else {
|
|
15746
|
+
logger?.debug("compress: no action needed", { ratio: pressure.ratio.toFixed(2) });
|
|
15638
15747
|
}
|
|
15639
15748
|
return { stats };
|
|
15640
15749
|
}
|
|
@@ -15651,6 +15760,7 @@ function compressOldToolOutputs(messages, state) {
|
|
|
15651
15760
|
if (!p.state.output) continue;
|
|
15652
15761
|
if (p.state.output === "[superseded by duplicate call]") continue;
|
|
15653
15762
|
if (p.state.output.startsWith("[compressed")) continue;
|
|
15763
|
+
if (p.state.output.includes("[ccr:")) continue;
|
|
15654
15764
|
const toolName = p.tool || "unknown";
|
|
15655
15765
|
const output = p.state.output;
|
|
15656
15766
|
const result = compressToolOutput(toolName, output);
|
|
@@ -15676,6 +15786,7 @@ function crushJsonToolOutputs(messages, state) {
|
|
|
15676
15786
|
if (!p.state.output) continue;
|
|
15677
15787
|
if (p.state.output.startsWith("[compressed")) continue;
|
|
15678
15788
|
if (p.state.output.startsWith("[superseded")) continue;
|
|
15789
|
+
if (p.state.output.includes("[ccr:")) continue;
|
|
15679
15790
|
if (detectContentType(p.state.output) !== "json") continue;
|
|
15680
15791
|
const original = p.state.output;
|
|
15681
15792
|
const crushed_output = crushJsonArray(original);
|
|
@@ -15690,8 +15801,8 @@ function crushJsonToolOutputs(messages, state) {
|
|
|
15690
15801
|
}
|
|
15691
15802
|
|
|
15692
15803
|
// src/hooks/messages-transform.ts
|
|
15693
|
-
var
|
|
15694
|
-
var
|
|
15804
|
+
var KEEP_RECENT2 = 8;
|
|
15805
|
+
var PROTECTED_HEAD2 = 3;
|
|
15695
15806
|
var SYSTEM_INJECTION_PATTERNS = [
|
|
15696
15807
|
/^$/,
|
|
15697
15808
|
/^<!-- OMO_INTERNAL_INITIATOR -->$/,
|
|
@@ -15777,9 +15888,9 @@ function repairOrphanedToolCalls(messages) {
|
|
|
15777
15888
|
function createMessagesTransformHandler(state, logger) {
|
|
15778
15889
|
return async (_input, output) => {
|
|
15779
15890
|
const messages = output.messages;
|
|
15780
|
-
if (messages.length <=
|
|
15781
|
-
if (messages.length <=
|
|
15782
|
-
const protectedTailStart = messages.length -
|
|
15891
|
+
if (messages.length <= KEEP_RECENT2) return;
|
|
15892
|
+
if (messages.length <= KEEP_RECENT2 + PROTECTED_HEAD2) return;
|
|
15893
|
+
const protectedTailStart = messages.length - KEEP_RECENT2;
|
|
15783
15894
|
const stats = {
|
|
15784
15895
|
reasoning_cleared: 0,
|
|
15785
15896
|
metadata_stripped: 0,
|
|
@@ -15787,7 +15898,7 @@ function createMessagesTransformHandler(state, logger) {
|
|
|
15787
15898
|
tool_errors_truncated: 0,
|
|
15788
15899
|
thinking_stripped: 0
|
|
15789
15900
|
};
|
|
15790
|
-
for (let i =
|
|
15901
|
+
for (let i = PROTECTED_HEAD2; i < protectedTailStart; i++) {
|
|
15791
15902
|
const msg = messages[i];
|
|
15792
15903
|
if (!msg?.parts?.length) continue;
|
|
15793
15904
|
if (msg.info.role === "user") continue;
|
|
@@ -15859,15 +15970,15 @@ function createMessagesTransformHandler(state, logger) {
|
|
|
15859
15970
|
compression: stats,
|
|
15860
15971
|
deepCompression: ds,
|
|
15861
15972
|
messageCount: messages.length,
|
|
15862
|
-
protectedHead:
|
|
15863
|
-
protectedTail:
|
|
15973
|
+
protectedHead: PROTECTED_HEAD2,
|
|
15974
|
+
protectedTail: KEEP_RECENT2
|
|
15864
15975
|
});
|
|
15865
15976
|
} else if (Object.values(stats).some((v) => v > 0)) {
|
|
15866
15977
|
state.mergeNotify({
|
|
15867
15978
|
compression: stats,
|
|
15868
15979
|
messageCount: messages.length,
|
|
15869
|
-
protectedHead:
|
|
15870
|
-
protectedTail:
|
|
15980
|
+
protectedHead: PROTECTED_HEAD2,
|
|
15981
|
+
protectedTail: KEEP_RECENT2
|
|
15871
15982
|
});
|
|
15872
15983
|
}
|
|
15873
15984
|
};
|