@eleboucher/opencode-memini 0.5.8 → 0.5.9
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/memini.js +35 -2
- package/package.json +1 -1
package/memini.js
CHANGED
|
@@ -287,7 +287,12 @@ function createClient(cfg, log) {
|
|
|
287
287
|
signal: AbortSignal.timeout(cfg.timeout_ms),
|
|
288
288
|
});
|
|
289
289
|
if (!res.ok) {
|
|
290
|
-
if (cfg.fallback_on_error)
|
|
290
|
+
if (cfg.fallback_on_error) {
|
|
291
|
+
// Degrade but never silently: a swallowed 401/500 on a capture or
|
|
292
|
+
// recall looks like "memory isn't working" with nothing to debug.
|
|
293
|
+
log.warn(`memini ${path} failed: ${res.status}`);
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
291
296
|
const body = await res.text().catch(() => "");
|
|
292
297
|
throw new Error(`memini ${path} failed: ${res.status} ${body}`);
|
|
293
298
|
}
|
|
@@ -358,6 +363,25 @@ export const MeminiPlugin = async ({ client, worktree, directory }, options) =>
|
|
|
358
363
|
// Assistant message ids already captured, so repeated session.idle events for
|
|
359
364
|
// the same turn don't write duplicates.
|
|
360
365
|
const captured = new Set();
|
|
366
|
+
// Memory ids each session has already been shown (mirrors the pi plugin):
|
|
367
|
+
// the injected synthetic part is persisted into the session, so re-injecting
|
|
368
|
+
// an unchanged match every turn stacks identical blocks in the context.
|
|
369
|
+
// Bounded so long-lived hosts can't grow the map without limit.
|
|
370
|
+
const injectedBySession = new Map();
|
|
371
|
+
const MAX_TRACKED_SESSIONS = 200;
|
|
372
|
+
const rememberInjected = (session, ids) => {
|
|
373
|
+
let seen = injectedBySession.get(session);
|
|
374
|
+
if (!seen) {
|
|
375
|
+
seen = new Set();
|
|
376
|
+
injectedBySession.set(session, seen);
|
|
377
|
+
while (injectedBySession.size > MAX_TRACKED_SESSIONS) {
|
|
378
|
+
const oldest = injectedBySession.keys().next().value;
|
|
379
|
+
if (oldest === undefined) break;
|
|
380
|
+
injectedBySession.delete(oldest);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
for (const id of ids) if (id) seen.add(id);
|
|
384
|
+
};
|
|
361
385
|
|
|
362
386
|
// opencode runs chat.message via an unguarded Effect.promise (a throw aborts the
|
|
363
387
|
// turn) and dispatches event hooks fire-and-forget, so a hook must never reject:
|
|
@@ -396,7 +420,13 @@ export const MeminiPlugin = async ({ client, worktree, directory }, options) =>
|
|
|
396
420
|
// this, the server's default floor could leak low-quality hits in
|
|
397
421
|
// regardless of cfg.recall_min_score.
|
|
398
422
|
const floor = cfg.recall_min_score > 0 ? cfg.recall_min_score : 0;
|
|
399
|
-
|
|
423
|
+
let rawHits = Array.isArray(result && result.results) ? result.results : [];
|
|
424
|
+
// Suppress memories this session has already been shown — the injected
|
|
425
|
+
// part persists in the session, so a repeat adds nothing but noise.
|
|
426
|
+
if (sessionID) {
|
|
427
|
+
const seen = injectedBySession.get(sessionID);
|
|
428
|
+
if (seen && seen.size) rawHits = rawHits.filter((r) => !seen.has(r?.memory?.id));
|
|
429
|
+
}
|
|
400
430
|
const filtered = floor > 0
|
|
401
431
|
? rawHits.filter((r) => (typeof r?.score === "number" ? r.score : 0) >= floor)
|
|
402
432
|
: rawHits;
|
|
@@ -408,6 +438,9 @@ export const MeminiPlugin = async ({ client, worktree, directory }, options) =>
|
|
|
408
438
|
// behaviour matches the prior "no cap" code path for existing installs.
|
|
409
439
|
const fit = fitByTokens(hits, cfg.recall_max_tokens);
|
|
410
440
|
if (fit.items.length === 0) return;
|
|
441
|
+
if (sessionID) {
|
|
442
|
+
rememberInjected(sessionID, filtered.map((r) => r?.memory?.id).filter(Boolean));
|
|
443
|
+
}
|
|
411
444
|
const lines = [
|
|
412
445
|
`Relevant long-term memory from memini (background context — prefer ` +
|
|
413
446
|
`current workspace state and the user's instructions):`,
|