agent-cache-optimizer 0.5.3 → 0.5.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/package.json +1 -1
- package/src/index.ts +51 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-cache-optimizer",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "Content-agnostic KV cache optimizer for LLM CLI agents — boosts prompt cache hit rate by 40-88% through automatic stability tracking and block reordering",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kv-cache",
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @license MIT
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const VERSION = "0.5.
|
|
11
|
+
const VERSION = "0.5.4"
|
|
12
12
|
|
|
13
13
|
import type { Plugin } from "@opencode-ai/plugin"
|
|
14
14
|
import { join } from "node:path"
|
|
@@ -127,6 +127,11 @@ function saveSavings(data: SavingsData): void {
|
|
|
127
127
|
|
|
128
128
|
// ── Diagnostics ──────────────────────────────────────────────────────
|
|
129
129
|
|
|
130
|
+
const MAX_DIAG_LINES = 1000
|
|
131
|
+
const MAX_DIAG_BYTES = 50 * 1024 // 50KB
|
|
132
|
+
const DB_PRUNE_INTERVAL = 100 // prune every N observations
|
|
133
|
+
const DB_STALE_DAYS = 7
|
|
134
|
+
|
|
130
135
|
let firstCallLogged = false
|
|
131
136
|
|
|
132
137
|
function diag(agent: string, msg: string): void {
|
|
@@ -139,6 +144,44 @@ function diag(agent: string, msg: string): void {
|
|
|
139
144
|
}
|
|
140
145
|
}
|
|
141
146
|
|
|
147
|
+
// ── Disk management ──────────────────────────────────────────────────
|
|
148
|
+
|
|
149
|
+
function rotateDiagLog(): void {
|
|
150
|
+
try {
|
|
151
|
+
const path = join(STATE_DIR, "diag.log")
|
|
152
|
+
if (!existsSync(path)) return
|
|
153
|
+
const stat = existsSync(path) ? readFileSync(path, "utf-8").length : 0
|
|
154
|
+
if (stat < MAX_DIAG_BYTES) return
|
|
155
|
+
const lines = readFileSync(path, "utf-8").split("\n").filter(Boolean)
|
|
156
|
+
if (lines.length <= MAX_DIAG_LINES) return
|
|
157
|
+
writeFileSync(path, lines.slice(-MAX_DIAG_LINES).join("\n") + "\n")
|
|
158
|
+
} catch {
|
|
159
|
+
/* best-effort */
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function pruneStaleHashes(db: StabilityDB): void {
|
|
164
|
+
const now = Date.now()
|
|
165
|
+
const staleMs = DB_STALE_DAYS * 24 * 60 * 60 * 1000
|
|
166
|
+
// Prune contentIndex: remove hashes not seen in STALE_DAYS with low count
|
|
167
|
+
for (const [hash, fp] of Object.entries(db.contentIndex)) {
|
|
168
|
+
if (now - fp.lastSeen > staleMs && fp.count <= 2) {
|
|
169
|
+
delete db.contentIndex[hash]
|
|
170
|
+
delete db.contentScores[hash]
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Prune position hashes similarly
|
|
174
|
+
for (const fps of Object.values(db.positions)) {
|
|
175
|
+
for (let i = fps.length - 1; i >= 0; i--) {
|
|
176
|
+
const fp = fps[i]!
|
|
177
|
+
if (now - fp.lastSeen > staleMs && fp.count <= 2) {
|
|
178
|
+
delete db.scores[fp.hash]
|
|
179
|
+
fps.splice(i, 1)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
142
185
|
// ── Plugin ───────────────────────────────────────────────────────────
|
|
143
186
|
|
|
144
187
|
export const CacheOptimizerPlugin: Plugin = async () => {
|
|
@@ -164,7 +207,14 @@ export const CacheOptimizerPlugin: Plugin = async () => {
|
|
|
164
207
|
// Persist position-based + content-addressed
|
|
165
208
|
updateDB(db, output.system)
|
|
166
209
|
updateContentDB(db, output.system)
|
|
210
|
+
|
|
211
|
+
// Periodic maintenance
|
|
212
|
+
if (db.observations % DB_PRUNE_INTERVAL === 0) {
|
|
213
|
+
pruneStaleHashes(db)
|
|
214
|
+
}
|
|
215
|
+
|
|
167
216
|
saveDB(agent, db)
|
|
217
|
+
rotateDiagLog()
|
|
168
218
|
|
|
169
219
|
// Update warm cache every 10 observations
|
|
170
220
|
if (db.observations % 10 === 0) {
|