UNPKG

akm-cli

Version:

akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cur

187 lines (186 loc) • 8.42 kB
// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. /** * The promote pass's coverage gate (#998): before a memory becomes a * `knowledge/` proposal, ask whether `knowledge/` already says it. * * The rule: a memory is covered when at least {@link COVERAGE_MIN_CONTAINMENT} * (30%) of its distinct {@link COVERAGE_SHINGLE_WORDS}-word shingles appear in * one of the knowledge docs nearest to it. It is a containment of the MEMORY in * the doc, not a similarity: a long guide that quotes the memory covers it; a * memory that quotes a short doc and adds claims of its own does not. * * Why this rule and this cut. The model never sees `knowledge/`, and the * mint-time checks before this one only catch the same slug or the same whole * body, so one edit or paraphrase defeats them. The evidence is #998's, from * the owner's bundle (run `consolidate-1790666282516`: 327 decided proposals, * 103 accepted, 224 rejected, 215 of those as "duplicate of / covered by / * overlaps" an existing knowledge doc): the share of a proposal's distinct * 5-word shingles found in the best OTHER knowledge doc was >= 0.5 for 122 of * the 224 rejected proposals and for none of the 103 accepted ones. 0.5 is the * cut that sample supports: no accepted promotion would have been skipped. That * sample compared each proposal with EVERY other knowledge doc, so 122 of 224 * (up to about 54%) is what the rule can take out of review at most, not what * this gate achieves: it reads only the {@link PAIR_NEIGHBOR_FETCH_K} nearest * knowledge docs (below), and a covering doc that ranks lower goes unseen. The * recall over that candidate set is unmeasured. The rest of the rejected * proposals (paraphrases, partial overlaps) still reach review. 0.5 let * paraphrases through: of the 54 promotions minted on 2026-10-07, 18 of the 51 * later rejected held 30% or more of their text in a neighbouring doc. The cut is * now 0.3, between the two measured points: 0.2 (169 of 224 rejected) also * skipped 2 of the 103 accepted ones. At 0.3, none of the 5 promotions graded * good in the 2026-10-05 review sample would be skipped (their best doc holds * at most 1% of them) while 5 of its 15 bad ones would. A wrong skip is a * promotion nobody gets to review. * * Candidates are the memory's {@link PAIR_NEIGHBOR_FETCH_K} nearest knowledge * docs in its bundle by stored vector (`getNeighborsByEntryId`, the lookup the * pair pass runs, scoped to the bundle's knowledge entries), never a scan of * `knowledge/`. There is no similarity floor, only a rank: a guide that quotes * the memory is found however far it sits from it by vector, as long as fewer * than that many other knowledge docs in the bundle are nearer. With no stored * vector (semantic search off, the memory not indexed yet, no index at all) * there are no candidates and the gate does nothing: the exact-slug and * whole-body checks still run, and nothing throws. */ import fs from "node:fs"; import { closeDatabase, openExistingDatabase } from "../../../storage/repositories/index-connection.js"; import { getEntryById, getEntryIdByFilePath } from "../../../storage/repositories/index-entries-repository.js"; import { getNeighborsByEntryId } from "../../../storage/repositories/index-vec-repository.js"; import { stripFrontmatterBody } from "../content-hash.js"; import { PAIR_NEIGHBOR_FETCH_K } from "./pair-pass.js"; /** Words per shingle. */ export const COVERAGE_SHINGLE_WORDS = 5; /** Share of a memory's distinct shingles one knowledge doc must hold for the memory to count as covered. */ export const COVERAGE_MIN_CONTAINMENT = 0.3; const WORD = /[\p{L}\p{N}]+/gu; /** The distinct lower-cased word n-grams of `text`; empty when it has fewer than {@link COVERAGE_SHINGLE_WORDS} words. */ export function wordShingles(text) { const words = text.toLowerCase().match(WORD) ?? []; const shingles = new Set(); for (let i = 0; i + COVERAGE_SHINGLE_WORDS <= words.length; i++) { shingles.add(words.slice(i, i + COVERAGE_SHINGLE_WORDS).join(" ")); } return shingles; } /** The share (0..1) of `memory`'s shingles that also occur in `doc`; 0 when the memory has none. */ export function shingleContainment(memory, doc) { if (memory.size === 0) return 0; const docShingles = wordShingles(doc); let shared = 0; for (const shingle of memory) if (docShingles.has(shingle)) shared++; return shared / memory.size; } /** * The {@link PAIR_NEIGHBOR_FETCH_K} knowledge docs in `bundleId` nearest to the * memory at `filePath`, nearest first. A memory the index does not know has no * stored vector and so no neighbours. */ function knowledgeNeighbours(db, bundleId, filePath) { const entryId = getEntryIdByFilePath(db, filePath); if (entryId === undefined) return []; const out = []; for (const hit of getNeighborsByEntryId(db, entryId, PAIR_NEIGHBOR_FETCH_K, { type: "knowledge", bundleId })) { const neighbour = getEntryById(db, hit.id); if (!neighbour) continue; let raw; try { raw = fs.readFileSync(neighbour.filePath, "utf8"); } catch { continue; // the index outlived the file } out.push({ ref: neighbour.conceptId, description: neighbour.entry.description ?? "", body: stripFrontmatterBody(raw), }); } return out; } /** * The best-covering knowledge doc among the {@link PAIR_NEIGHBOR_FETCH_K} * knowledge docs in `bundleId` nearest to the memory. `filePath` is the * memory's indexed file; a memory the index does not know has no stored * vector and so no candidates. */ export function findCoveringKnowledge(db, bundleId, filePath, body) { const shingles = wordShingles(body); if (shingles.size === 0) return undefined; let best; for (const neighbour of knowledgeNeighbours(db, bundleId, filePath)) { const containment = shingleContainment(shingles, neighbour.body); if (containment >= COVERAGE_MIN_CONTAINMENT && (best === undefined || containment > best.containment)) { best = { ref: neighbour.ref, containment }; } } return best; } /** Knowledge docs a reviewer is shown for a promotion, nearest first. */ export const NEIGHBOUR_NOTE_COUNT = 5; export const NEIGHBOUR_EXCERPT_CHARS = 300; /** * The knowledge notes nearest to the memory at `memoryPath`, for the drain's * judge to compare a promotion against: the nearest {@link NEIGHBOUR_NOTE_COUNT} * of the same candidates the coverage gate reads. The memory's bundle is the one * the index recorded for it. Empty when the index has no vector for the memory * or cannot be opened; never throws. */ export function nearestKnowledgeNotes(memoryPath) { let db; try { db = openExistingDatabase(); const entryId = getEntryIdByFilePath(db, memoryPath); const bundleId = entryId === undefined ? undefined : getEntryById(db, entryId)?.bundleId; if (bundleId === undefined) return []; return knowledgeNeighbours(db, bundleId, memoryPath) .slice(0, NEIGHBOUR_NOTE_COUNT) .map((n) => ({ ref: n.ref, description: n.description, excerpt: n.body.length > NEIGHBOUR_EXCERPT_CHARS ? `${n.body.slice(0, NEIGHBOUR_EXCERPT_CHARS)}...` : n.body, })); } catch { return []; } finally { if (db) closeDatabase(db); } } /** * The gate for one run, holding its own read handle on `index.db` for the * promotions that run emits; `undefined` when there is no bundle or no index * to look in. A lookup that throws counts as "not known to be covered". */ export function openKnowledgeCoverage(bundleId) { if (!bundleId) return undefined; let db; try { db = openExistingDatabase(); } catch { return undefined; } return { find: (filePath, body) => { try { return findCoveringKnowledge(db, bundleId, filePath, body); } catch { return undefined; } }, close: () => closeDatabase(db), }; }