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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. 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",
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.3"
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) {