agentdb 3.1.0 → 3.3.0

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 (35) hide show
  1. package/README.md +13 -0
  2. package/dist/src/controllers/ReasoningBank.d.ts +36 -0
  3. package/dist/src/controllers/ReasoningBank.d.ts.map +1 -1
  4. package/dist/src/controllers/ReasoningBank.js +123 -1
  5. package/dist/src/controllers/ReasoningBank.js.map +1 -1
  6. package/dist/src/controllers/ReflexionMemory.d.ts +75 -0
  7. package/dist/src/controllers/ReflexionMemory.d.ts.map +1 -1
  8. package/dist/src/controllers/ReflexionMemory.js +292 -10
  9. package/dist/src/controllers/ReflexionMemory.js.map +1 -1
  10. package/dist/src/controllers/SkillLibrary.d.ts +50 -0
  11. package/dist/src/controllers/SkillLibrary.d.ts.map +1 -1
  12. package/dist/src/controllers/SkillLibrary.js +220 -9
  13. package/dist/src/controllers/SkillLibrary.js.map +1 -1
  14. package/dist/src/controllers/crud-helpers.d.ts +45 -0
  15. package/dist/src/controllers/crud-helpers.d.ts.map +1 -0
  16. package/dist/src/controllers/crud-helpers.js +130 -0
  17. package/dist/src/controllers/crud-helpers.js.map +1 -0
  18. package/dist/src/controllers/episode-hybrid.d.ts +82 -0
  19. package/dist/src/controllers/episode-hybrid.d.ts.map +1 -0
  20. package/dist/src/controllers/episode-hybrid.js +140 -0
  21. package/dist/src/controllers/episode-hybrid.js.map +1 -0
  22. package/dist/src/mcp/agentdb-mcp-server.js +373 -47
  23. package/dist/src/mcp/agentdb-mcp-server.js.map +1 -1
  24. package/dist/src/search/conversation-retrieval.d.ts +61 -0
  25. package/dist/src/search/conversation-retrieval.d.ts.map +1 -0
  26. package/dist/src/search/conversation-retrieval.js +190 -0
  27. package/dist/src/search/conversation-retrieval.js.map +1 -0
  28. package/dist/src/search/cross-encoder.d.ts +17 -0
  29. package/dist/src/search/cross-encoder.d.ts.map +1 -0
  30. package/dist/src/search/cross-encoder.js +52 -0
  31. package/dist/src/search/cross-encoder.js.map +1 -0
  32. package/dist/src/security/mcp-policy.d.ts.map +1 -1
  33. package/dist/src/security/mcp-policy.js +13 -0
  34. package/dist/src/security/mcp-policy.js.map +1 -1
  35. package/package.json +6 -4
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Hybrid (dense + BM25) episode retrieval for ReflexionMemory (ADR-016).
3
+ *
4
+ * Dense search alone misses episodes whose wording matches the query but whose embedding does not (names, error
5
+ * codes, numbers). This keeps a BM25 index over the most recent episodes, rebuilt only when the episodes table
6
+ * changes, and fuses its ranking with the dense ranking by reciprocal-rank fusion. On LongMemEval session retrieval
7
+ * (benchmarks/longmemeval, which runs these ranking functions over turn chunks, not the episode store), the same
8
+ * fusion lifts recall_all@5 over dense-only ranking of the same chunks from 0.883 to 0.900 (S) and from 0.630 to
9
+ * 0.719 (M), with the default MiniLM embedder. See ADR-016.
10
+ */
11
+ import type { IDatabaseConnection } from '../types/database.types.js';
12
+ /**
13
+ * Episodes indexed for BM25, newest first; older episodes are still found by dense search. The first search in a
14
+ * process builds the index (about 200 ms at 10k episodes, 1 s at 50k); later writes are appended incrementally.
15
+ */
16
+ export declare const HYBRID_MAX_INDEXED: number;
17
+ /** The candidate pool each side contributes before fusion. */
18
+ export declare const HYBRID_MAX_POOL = 500;
19
+ /** Weight of the BM25 ranking against the dense ranking. Equal weights won on LongMemEval_M; see ADR-016. */
20
+ export declare const HYBRID_LEXICAL_WEIGHT = 1;
21
+ interface EpisodeTextRow {
22
+ id: number;
23
+ task: string | null;
24
+ input: string | null;
25
+ output: string | null;
26
+ critique: string | null;
27
+ }
28
+ /**
29
+ * A BM25 index over episode text. New episodes are appended incrementally (the common write-then-read pattern);
30
+ * the index is rebuilt only when rows were deleted or replaced, or it has grown past 1.25x its cap.
31
+ */
32
+ export declare class EpisodeLexicalIndex {
33
+ private readonly db;
34
+ private readonly maxDocs;
35
+ private count;
36
+ private maxId;
37
+ private ids;
38
+ private index;
39
+ constructor(db: IDatabaseConnection, maxDocs?: number);
40
+ private static textOf;
41
+ private refresh;
42
+ /**
43
+ * Apply an in-place edit of one episode without a rebuild. `before` must be the row as it was indexed.
44
+ * A no-op when the index is not built yet (the next search builds it from current rows) or the episode
45
+ * is outside the indexed window.
46
+ */
47
+ update(before: EpisodeTextRow, after: EpisodeTextRow): void;
48
+ /**
49
+ * Force a full rebuild on the next search. Needed after an in-place edit: an UPDATE changes
50
+ * neither COUNT(*) nor MAX(id), so refresh() alone would keep serving the old text.
51
+ */
52
+ invalidate(): void;
53
+ /** Episode ids with a BM25 match, best first, at most `limit`. */
54
+ search(query: string, limit: number): {
55
+ id: number;
56
+ score: number;
57
+ }[];
58
+ }
59
+ /**
60
+ * Weighted RRF scores of a dense ranking (best first) and a lexical ranking (best first) over episode ids.
61
+ * Episodes only in the lexical list are ranked just past the dense pool on the dense side.
62
+ */
63
+ export declare function fuseEpisodeScores(denseIds: readonly number[], lexical: readonly {
64
+ id: number;
65
+ }[], lexicalWeight?: number): Map<number, number>;
66
+ /** Ids ordered by score, ties broken by dense order, then by newer id. */
67
+ export declare function orderByScore(score: ReadonlyMap<number, number>, denseIds?: readonly number[]): number[];
68
+ /** Fused ranking of episode ids, best first. */
69
+ export declare function fuseEpisodeRankings(denseIds: readonly number[], lexical: readonly {
70
+ id: number;
71
+ }[], lexicalWeight?: number): number[];
72
+ /** Candidates the cross-encoder reads: the top `RERANK_DEPTH` of each ranking (the configuration benchmarked in ADR-016). */
73
+ export declare const RERANK_DEPTH = 60;
74
+ /** Weight of the cross-encoder rank in the fusion; best on LongMemEval_M (ADR-016). */
75
+ export declare const RERANK_WEIGHT = 8;
76
+ /**
77
+ * Adds `RERANK_WEIGHT`/(k + cross-encoder rank) to each candidate's fused score, in place. Candidates without text
78
+ * are skipped. Throws if the model cannot be loaded; the caller keeps the hybrid order.
79
+ */
80
+ export declare function applyCrossEncoder(query: string, score: Map<number, number>, candidates: readonly number[], textOf: (id: number) => string | undefined, model?: string): Promise<void>;
81
+ export {};
82
+ //# sourceMappingURL=episode-hybrid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"episode-hybrid.d.ts","sourceRoot":"","sources":["../../../src/controllers/episode-hybrid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAItE;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAA0E,CAAC;AAM1G,8DAA8D;AAC9D,eAAO,MAAM,eAAe,MAAM,CAAC;AACnC,6GAA6G;AAC7G,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAGvC,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED;;;GAGG;AACH,qBAAa,mBAAmB;IAO5B,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAP1B,OAAO,CAAC,KAAK,CAAM;IACnB,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,GAAG,CAAgB;IAC3B,OAAO,CAAC,KAAK,CAA0B;gBAGpB,EAAE,EAAE,mBAAmB,EACvB,OAAO,SAAqB;IAG/C,OAAO,CAAC,MAAM,CAAC,MAAM;IAIrB,OAAO,CAAC,OAAO;IA4Bf;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI;IAO3D;;;OAGG;IACH,UAAU,IAAI,IAAI;IAOlB,kEAAkE;IAClE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE;CAStE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,aAAa,SAAwB,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAS7J;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,GAAE,SAAS,MAAM,EAAO,GAAG,MAAM,EAAE,CAM3G;AAED,gDAAgD;AAChD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,aAAa,SAAwB,GAAG,MAAM,EAAE,CAEpJ;AAED,6HAA6H;AAC7H,eAAO,MAAM,YAAY,KAAK,CAAC;AAC/B,uFAAuF;AACvF,eAAO,MAAM,aAAa,IAAI,CAAC;AAE/B;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,EAC1C,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAKf"}
@@ -0,0 +1,140 @@
1
+ import { Bm25Index, tokenize } from '../search/conversation-retrieval.js';
2
+ import { crossEncoderScores } from '../search/cross-encoder.js';
3
+ /**
4
+ * Episodes indexed for BM25, newest first; older episodes are still found by dense search. The first search in a
5
+ * process builds the index (about 200 ms at 10k episodes, 1 s at 50k); later writes are appended incrementally.
6
+ */
7
+ export const HYBRID_MAX_INDEXED = clampInt(process.env.AGENTDB_HYBRID_MAX_EPISODES, 10_000, 1, 1_000_000);
8
+ function clampInt(raw, fallback, min, max) {
9
+ const n = Math.floor(Number(raw));
10
+ return Number.isFinite(n) && n >= min ? Math.min(n, max) : fallback;
11
+ }
12
+ /** The candidate pool each side contributes before fusion. */
13
+ export const HYBRID_MAX_POOL = 500;
14
+ /** Weight of the BM25 ranking against the dense ranking. Equal weights won on LongMemEval_M; see ADR-016. */
15
+ export const HYBRID_LEXICAL_WEIGHT = 1;
16
+ const RRF_K = 60;
17
+ /**
18
+ * A BM25 index over episode text. New episodes are appended incrementally (the common write-then-read pattern);
19
+ * the index is rebuilt only when rows were deleted or replaced, or it has grown past 1.25x its cap.
20
+ */
21
+ export class EpisodeLexicalIndex {
22
+ db;
23
+ maxDocs;
24
+ count = -1;
25
+ maxId = 0;
26
+ ids = [];
27
+ index = null;
28
+ constructor(db, maxDocs = HYBRID_MAX_INDEXED) {
29
+ this.db = db;
30
+ this.maxDocs = maxDocs;
31
+ }
32
+ static textOf(r) {
33
+ return tokenize([r.task, r.input, r.output, r.critique].filter(Boolean).join('\n'));
34
+ }
35
+ refresh() {
36
+ const sig = this.db.prepare('SELECT COUNT(*) AS c, MAX(id) AS m FROM episodes').get();
37
+ const count = sig?.c ?? 0;
38
+ const maxId = sig?.m ?? 0;
39
+ if (this.index && count === this.count && maxId === this.maxId)
40
+ return;
41
+ if (this.index && count > this.count && maxId > this.maxId && this.ids.length < this.maxDocs * 1.25) {
42
+ const added = this.db
43
+ .prepare('SELECT id, task, input, output, critique FROM episodes WHERE id > ? ORDER BY id ASC')
44
+ .all(this.maxId);
45
+ if (this.count + added.length === count) {
46
+ for (const r of added) {
47
+ this.index.add(EpisodeLexicalIndex.textOf(r));
48
+ this.ids.push(r.id);
49
+ }
50
+ this.count = count;
51
+ this.maxId = maxId;
52
+ return;
53
+ }
54
+ }
55
+ const rows = this.db
56
+ .prepare('SELECT id, task, input, output, critique FROM episodes ORDER BY id DESC LIMIT ?')
57
+ .all(this.maxDocs);
58
+ this.index = new Bm25Index(rows.map(r => EpisodeLexicalIndex.textOf(r)));
59
+ this.ids = rows.map(r => r.id);
60
+ this.count = count;
61
+ this.maxId = maxId;
62
+ }
63
+ /**
64
+ * Apply an in-place edit of one episode without a rebuild. `before` must be the row as it was indexed.
65
+ * A no-op when the index is not built yet (the next search builds it from current rows) or the episode
66
+ * is outside the indexed window.
67
+ */
68
+ update(before, after) {
69
+ if (!this.index)
70
+ return;
71
+ const doc = this.ids.indexOf(before.id);
72
+ if (doc < 0)
73
+ return;
74
+ this.index.replace(doc, EpisodeLexicalIndex.textOf(before), EpisodeLexicalIndex.textOf(after));
75
+ }
76
+ /**
77
+ * Force a full rebuild on the next search. Needed after an in-place edit: an UPDATE changes
78
+ * neither COUNT(*) nor MAX(id), so refresh() alone would keep serving the old text.
79
+ */
80
+ invalidate() {
81
+ this.index = null;
82
+ this.ids = [];
83
+ this.count = -1;
84
+ this.maxId = 0;
85
+ }
86
+ /** Episode ids with a BM25 match, best first, at most `limit`. */
87
+ search(query, limit) {
88
+ this.refresh();
89
+ if (!this.index || this.ids.length === 0)
90
+ return [];
91
+ const scores = this.index.score(tokenize(query, 256));
92
+ const hits = [];
93
+ for (let i = 0; i < scores.length; i++)
94
+ if (scores[i] > 0)
95
+ hits.push({ id: this.ids[i], score: scores[i] });
96
+ hits.sort((a, z) => z.score - a.score || z.id - a.id);
97
+ return hits.slice(0, limit);
98
+ }
99
+ }
100
+ /**
101
+ * Weighted RRF scores of a dense ranking (best first) and a lexical ranking (best first) over episode ids.
102
+ * Episodes only in the lexical list are ranked just past the dense pool on the dense side.
103
+ */
104
+ export function fuseEpisodeScores(denseIds, lexical, lexicalWeight = HYBRID_LEXICAL_WEIGHT) {
105
+ const score = new Map();
106
+ const denseMiss = denseIds.length + 1;
107
+ denseIds.forEach((id, r) => score.set(id, 1 / (RRF_K + r + 1)));
108
+ lexical.forEach(({ id }, r) => {
109
+ const base = score.get(id) ?? 1 / (RRF_K + denseMiss);
110
+ score.set(id, base + lexicalWeight / (RRF_K + r + 1));
111
+ });
112
+ return score;
113
+ }
114
+ /** Ids ordered by score, ties broken by dense order, then by newer id. */
115
+ export function orderByScore(score, denseIds = []) {
116
+ const order = new Map();
117
+ denseIds.forEach((id, i) => order.set(id, i));
118
+ return [...score.entries()]
119
+ .sort((a, z) => z[1] - a[1] || (order.get(a[0]) ?? Infinity) - (order.get(z[0]) ?? Infinity) || z[0] - a[0])
120
+ .map(([id]) => id);
121
+ }
122
+ /** Fused ranking of episode ids, best first. */
123
+ export function fuseEpisodeRankings(denseIds, lexical, lexicalWeight = HYBRID_LEXICAL_WEIGHT) {
124
+ return orderByScore(fuseEpisodeScores(denseIds, lexical, lexicalWeight), denseIds);
125
+ }
126
+ /** Candidates the cross-encoder reads: the top `RERANK_DEPTH` of each ranking (the configuration benchmarked in ADR-016). */
127
+ export const RERANK_DEPTH = 60;
128
+ /** Weight of the cross-encoder rank in the fusion; best on LongMemEval_M (ADR-016). */
129
+ export const RERANK_WEIGHT = 8;
130
+ /**
131
+ * Adds `RERANK_WEIGHT`/(k + cross-encoder rank) to each candidate's fused score, in place. Candidates without text
132
+ * are skipped. Throws if the model cannot be loaded; the caller keeps the hybrid order.
133
+ */
134
+ export async function applyCrossEncoder(query, score, candidates, textOf, model) {
135
+ const ids = candidates.filter(id => score.has(id) && textOf(id));
136
+ const ce = await crossEncoderScores(query, ids.map(id => textOf(id)), model);
137
+ const byCe = ids.map((_, i) => i).sort((a, z) => ce[z] - ce[a] || a - z);
138
+ byCe.forEach((i, r) => score.set(ids[i], score.get(ids[i]) + RERANK_WEIGHT / (RRF_K + r + 1)));
139
+ }
140
+ //# sourceMappingURL=episode-hybrid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"episode-hybrid.js","sourceRoot":"","sources":["../../../src/controllers/episode-hybrid.ts"],"names":[],"mappings":"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"}