@framers/agentos 0.1.247 → 0.1.249
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/dist/memory/CognitiveMemoryManager.d.ts +47 -0
- package/dist/memory/CognitiveMemoryManager.d.ts.map +1 -1
- package/dist/memory/CognitiveMemoryManager.js +54 -0
- package/dist/memory/CognitiveMemoryManager.js.map +1 -1
- package/dist/memory/core/types.d.ts +31 -0
- package/dist/memory/core/types.d.ts.map +1 -1
- package/dist/memory/index.d.ts +13 -1
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +24 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/ingest/SessionSummarizer.d.ts +155 -0
- package/dist/memory/ingest/SessionSummarizer.d.ts.map +1 -0
- package/dist/memory/ingest/SessionSummarizer.js +178 -0
- package/dist/memory/ingest/SessionSummarizer.js.map +1 -0
- package/dist/memory/retrieval/fact-supersession/FactSupersession.d.ts +82 -0
- package/dist/memory/retrieval/fact-supersession/FactSupersession.d.ts.map +1 -0
- package/dist/memory/retrieval/fact-supersession/FactSupersession.js +159 -0
- package/dist/memory/retrieval/fact-supersession/FactSupersession.js.map +1 -0
- package/dist/memory/retrieval/fact-supersession/index.d.ts +10 -0
- package/dist/memory/retrieval/fact-supersession/index.d.ts.map +1 -0
- package/dist/memory/retrieval/fact-supersession/index.js +9 -0
- package/dist/memory/retrieval/fact-supersession/index.js.map +1 -0
- package/dist/memory/retrieval/hybrid/HybridRetriever.d.ts +151 -0
- package/dist/memory/retrieval/hybrid/HybridRetriever.d.ts.map +1 -0
- package/dist/memory/retrieval/hybrid/HybridRetriever.js +287 -0
- package/dist/memory/retrieval/hybrid/HybridRetriever.js.map +1 -0
- package/dist/memory/retrieval/hybrid/index.d.ts +12 -0
- package/dist/memory/retrieval/hybrid/index.d.ts.map +1 -0
- package/dist/memory/retrieval/hybrid/index.js +10 -0
- package/dist/memory/retrieval/hybrid/index.js.map +1 -0
- package/dist/memory/retrieval/hybrid/reciprocalRankFusion.d.ts +87 -0
- package/dist/memory/retrieval/hybrid/reciprocalRankFusion.d.ts.map +1 -0
- package/dist/memory/retrieval/hybrid/reciprocalRankFusion.js +88 -0
- package/dist/memory/retrieval/hybrid/reciprocalRankFusion.js.map +1 -0
- package/dist/memory/retrieval/session/SessionRetriever.d.ts +123 -0
- package/dist/memory/retrieval/session/SessionRetriever.d.ts.map +1 -0
- package/dist/memory/retrieval/session/SessionRetriever.js +220 -0
- package/dist/memory/retrieval/session/SessionRetriever.js.map +1 -0
- package/dist/memory/retrieval/session/SessionSummaryStore.d.ts +122 -0
- package/dist/memory/retrieval/session/SessionSummaryStore.d.ts.map +1 -0
- package/dist/memory/retrieval/session/SessionSummaryStore.js +142 -0
- package/dist/memory/retrieval/session/SessionSummaryStore.js.map +1 -0
- package/dist/memory/retrieval/session/index.d.ts +12 -0
- package/dist/memory/retrieval/session/index.d.ts.map +1 -0
- package/dist/memory/retrieval/session/index.js +10 -0
- package/dist/memory/retrieval/session/index.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file reciprocalRankFusion.ts
|
|
3
|
+
* @description Rank-based fusion of two ranked document lists using
|
|
4
|
+
* the Reciprocal Rank Fusion (RRF) algorithm (Cormack et al. 2009).
|
|
5
|
+
*
|
|
6
|
+
* ## What this does
|
|
7
|
+
*
|
|
8
|
+
* Takes two 1-based ranked lists of document ids (one from dense
|
|
9
|
+
* retrieval, one from sparse retrieval) and merges them into a single
|
|
10
|
+
* ranked list via:
|
|
11
|
+
*
|
|
12
|
+
* ```
|
|
13
|
+
* score(d) = w_dense / (k + rank_dense(d)) + w_sparse / (k + rank_sparse(d))
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Missing ranks (a doc appearing on only one side) contribute zero
|
|
17
|
+
* from the other side.
|
|
18
|
+
*
|
|
19
|
+
* ## Why rank-based (not score-based)
|
|
20
|
+
*
|
|
21
|
+
* Dense scorers (cosine similarity, cognitive composites) and sparse
|
|
22
|
+
* scorers (BM25) produce values on different scales with different
|
|
23
|
+
* distributions. Score-weighted fusion requires calibration; rank
|
|
24
|
+
* fusion sidesteps this entirely. Published RAG literature
|
|
25
|
+
* consistently prefers RRF over weighted-sum for heterogeneous
|
|
26
|
+
* retrievers.
|
|
27
|
+
*
|
|
28
|
+
* ## Stable ordering
|
|
29
|
+
*
|
|
30
|
+
* When two documents have identical RRF scores, they are ordered by
|
|
31
|
+
* id ascending. Deterministic across process restarts.
|
|
32
|
+
*
|
|
33
|
+
* @module agentos/memory/retrieval/hybrid/reciprocalRankFusion
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Merge two ranked retrieval results via Reciprocal Rank Fusion.
|
|
37
|
+
*
|
|
38
|
+
* @param denseRanked - 1-based ranked list from dense retrieval.
|
|
39
|
+
* @param sparseRanked - 1-based ranked list from sparse retrieval.
|
|
40
|
+
* @param options - {@link RRFOptions}; defaults to w_dense=0.7, w_sparse=0.3, k=60.
|
|
41
|
+
* @returns Merged results sorted by fused score descending, stable
|
|
42
|
+
* tiebreak by id ascending.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* const dense = [{ id: 'a', rank: 1 }, { id: 'b', rank: 2 }];
|
|
47
|
+
* const sparse = [{ id: 'b', rank: 1 }, { id: 'c', rank: 2 }];
|
|
48
|
+
* const merged = reciprocalRankFusion(dense, sparse);
|
|
49
|
+
* // => [{ id: 'b', score: 0.0162, denseRank: 2, sparseRank: 1 }, ...]
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function reciprocalRankFusion(denseRanked, sparseRanked, options = {}) {
|
|
53
|
+
const wDense = options.denseWeight ?? 0.7;
|
|
54
|
+
const wSparse = options.sparseWeight ?? 0.3;
|
|
55
|
+
const k = options.k ?? 60;
|
|
56
|
+
const byId = new Map();
|
|
57
|
+
for (const { id, rank } of denseRanked) {
|
|
58
|
+
const prev = byId.get(id);
|
|
59
|
+
const denseContribution = wDense / (k + rank);
|
|
60
|
+
if (prev) {
|
|
61
|
+
prev.score += denseContribution;
|
|
62
|
+
prev.denseRank = rank;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
byId.set(id, { id, score: denseContribution, denseRank: rank });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
for (const { id, rank } of sparseRanked) {
|
|
69
|
+
const prev = byId.get(id);
|
|
70
|
+
const sparseContribution = wSparse / (k + rank);
|
|
71
|
+
if (prev) {
|
|
72
|
+
prev.score += sparseContribution;
|
|
73
|
+
prev.sparseRank = rank;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
byId.set(id, { id, score: sparseContribution, sparseRank: rank });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const merged = Array.from(byId.values());
|
|
80
|
+
// Sort by score desc, stable tiebreak by id asc for determinism.
|
|
81
|
+
merged.sort((a, b) => {
|
|
82
|
+
if (b.score !== a.score)
|
|
83
|
+
return b.score - a.score;
|
|
84
|
+
return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
|
|
85
|
+
});
|
|
86
|
+
return merged;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=reciprocalRankFusion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reciprocalRankFusion.js","sourceRoot":"","sources":["../../../../src/memory/retrieval/hybrid/reciprocalRankFusion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAuCH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,oBAAoB,CAClC,WAAwB,EACxB,YAAyB,EACzB,UAAsB,EAAE;IAExB,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,IAAI,GAAG,CAAC;IAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,IAAI,GAAG,CAAC;IAC5C,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAE1B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAqB,CAAC;IAE1C,KAAK,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,WAAW,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1B,MAAM,iBAAiB,GAAG,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC9C,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,KAAK,IAAI,iBAAiB,CAAC;YAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAED,KAAK,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,YAAY,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1B,MAAM,kBAAkB,GAAG,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAChD,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,KAAK,IAAI,kBAAkB,CAAC;YACjC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACzC,iEAAiE;IACjE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACnB,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;YAAE,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;QAClD,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file SessionRetriever.ts
|
|
3
|
+
* @description Two-stage hierarchical retriever: select top-K sessions
|
|
4
|
+
* by summary similarity, then return top-M chunks per selected session
|
|
5
|
+
* from the underlying {@link MemoryStore}. Optional rerank pass over
|
|
6
|
+
* the merged pool. Returns a standard `CognitiveRetrievalResult` so
|
|
7
|
+
* downstream consumers (prompt assembly, bench adapters) don't change
|
|
8
|
+
* shape.
|
|
9
|
+
*
|
|
10
|
+
* ## What this does
|
|
11
|
+
*
|
|
12
|
+
* Implements the xMemory (arxiv 2602.02007v3) / TACITREE (EMNLP 2025)
|
|
13
|
+
* hierarchical-retrieval pattern, session-granularity variant: a
|
|
14
|
+
* coverage mechanism that guarantees the reader sees chunks from
|
|
15
|
+
* multiple distinct sessions on multi-session queries. Single-stage
|
|
16
|
+
* retrieval tends to cluster on the single most-relevant session,
|
|
17
|
+
* missing multi-session evidence; this retriever forces diversity by
|
|
18
|
+
* construction.
|
|
19
|
+
*
|
|
20
|
+
* ## Why a separate class, not a `CognitiveMemoryManager` option
|
|
21
|
+
*
|
|
22
|
+
* Keeps the existing manager retrieval path untouched. Step 2 MVP.
|
|
23
|
+
* Future steps may promote session-level retrieval into the manager
|
|
24
|
+
* once it's proven on benchmarks.
|
|
25
|
+
*
|
|
26
|
+
* ## Two-stage flow
|
|
27
|
+
*
|
|
28
|
+
* 1. Stage 1: `summaryStore.querySessions(query, topK=K)` — select
|
|
29
|
+
* top-K sessions.
|
|
30
|
+
* 2. Stage 2: single `memoryStore.query(query, topK=K*M*OVER_FETCH)` —
|
|
31
|
+
* over-fetch to ensure chunks from Stage-1 sessions land in the
|
|
32
|
+
* candidate pool.
|
|
33
|
+
* 3. Post-filter: keep only traces whose `bench-session:<id>` tag
|
|
34
|
+
* matches a Stage-1 session.
|
|
35
|
+
* 4. Group by session, take top-`chunksPerSession` (M) per session.
|
|
36
|
+
* 5. Optional rerank over the merged pool.
|
|
37
|
+
* 6. Truncate to `recallTopK`.
|
|
38
|
+
*
|
|
39
|
+
* ## Fallbacks
|
|
40
|
+
*
|
|
41
|
+
* - Stage 1 returns zero sessions (cold scope, no summaries indexed):
|
|
42
|
+
* fall through to `memoryStore.query` and return its top-
|
|
43
|
+
* `recallTopK` directly. Diagnostics tag
|
|
44
|
+
* `escalations: ['session-retriever:stage1-empty']`.
|
|
45
|
+
* - Stage 2 post-filter wipes the pool: return the raw Stage-2 top-
|
|
46
|
+
* `recallTopK` without session filtering. Diagnostics tag
|
|
47
|
+
* `escalations: ['session-retriever:stage2-empty']`.
|
|
48
|
+
*
|
|
49
|
+
* @module agentos/memory/retrieval/session/SessionRetriever
|
|
50
|
+
*/
|
|
51
|
+
import type { IEmbeddingManager } from '../../../core/embeddings/IEmbeddingManager.js';
|
|
52
|
+
import type { MemoryStore } from '../store/MemoryStore.js';
|
|
53
|
+
import type { RerankerService } from '../../../rag/reranking/RerankerService.js';
|
|
54
|
+
import type { CognitiveRetrievalResult, MemoryScope } from '../../core/types.js';
|
|
55
|
+
import type { PADState } from '../../core/config.js';
|
|
56
|
+
import type { SessionSummaryStore } from './SessionSummaryStore.js';
|
|
57
|
+
/**
|
|
58
|
+
* Options for constructing a {@link SessionRetriever}.
|
|
59
|
+
*/
|
|
60
|
+
export interface SessionRetrieverOptions {
|
|
61
|
+
summaryStore: SessionSummaryStore;
|
|
62
|
+
memoryStore: MemoryStore;
|
|
63
|
+
embeddingManager: IEmbeddingManager;
|
|
64
|
+
/** Optional reranker. When provided, the merged chunk pool is reranked before truncation. */
|
|
65
|
+
rerankerService?: RerankerService;
|
|
66
|
+
/** Default K (sessions to select in Stage 1). @default 5 */
|
|
67
|
+
defaultTopSessions?: number;
|
|
68
|
+
/** Default M (chunks per session in Stage 2). @default 3 */
|
|
69
|
+
defaultChunksPerSession?: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Per-call options for {@link SessionRetriever.retrieve}.
|
|
73
|
+
*/
|
|
74
|
+
export interface SessionRetrieveOptions {
|
|
75
|
+
/** Override K (sessions). */
|
|
76
|
+
topSessions?: number;
|
|
77
|
+
/** Override M (chunks per session). */
|
|
78
|
+
chunksPerSession?: number;
|
|
79
|
+
/** Final truncation after merge and rerank. @default 10 */
|
|
80
|
+
recallTopK?: number;
|
|
81
|
+
/** Prefix for parsing session IDs off trace tags. @default 'bench-session:' */
|
|
82
|
+
sessionTagPrefix?: string;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Two-stage hierarchical retriever.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const retriever = new SessionRetriever({
|
|
90
|
+
* summaryStore,
|
|
91
|
+
* memoryStore,
|
|
92
|
+
* embeddingManager,
|
|
93
|
+
* rerankerService,
|
|
94
|
+
* defaultTopSessions: 5,
|
|
95
|
+
* defaultChunksPerSession: 3,
|
|
96
|
+
* });
|
|
97
|
+
* const result = await retriever.retrieve(
|
|
98
|
+
* 'What did the user say about their rescue dog?',
|
|
99
|
+
* { valence: 0, arousal: 0, dominance: 0 },
|
|
100
|
+
* { scope: 'user', scopeId: 'u42' },
|
|
101
|
+
* { recallTopK: 10 },
|
|
102
|
+
* );
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export declare class SessionRetriever {
|
|
106
|
+
private readonly opts;
|
|
107
|
+
constructor(opts: SessionRetrieverOptions);
|
|
108
|
+
/**
|
|
109
|
+
* Two-stage retrieve. Returns a `CognitiveRetrievalResult`
|
|
110
|
+
* compatible with the existing `CognitiveMemoryManager.retrieve`
|
|
111
|
+
* shape.
|
|
112
|
+
*
|
|
113
|
+
* Diagnostics are best-effort: timings reflect wall-clock of each
|
|
114
|
+
* stage, not the cognitive-scorer internal accounting.
|
|
115
|
+
*/
|
|
116
|
+
retrieve(query: string, mood: PADState, scope: {
|
|
117
|
+
scope: MemoryScope;
|
|
118
|
+
scopeId: string;
|
|
119
|
+
}, options?: SessionRetrieveOptions): Promise<CognitiveRetrievalResult>;
|
|
120
|
+
/** Assemble the CognitiveRetrievalResult shape. */
|
|
121
|
+
private buildResult;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=SessionRetriever.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionRetriever.d.ts","sourceRoot":"","sources":["../../../../src/memory/retrieval/session/SessionRetriever.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AACvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,KAAK,EACV,wBAAwB,EACxB,WAAW,EAEZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAapE;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,mBAAmB,CAAC;IAClC,WAAW,EAAE,WAAW,CAAC;IACzB,gBAAgB,EAAE,iBAAiB,CAAC;IACpC,6FAA6F;IAC7F,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,4DAA4D;IAC5D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,4DAA4D;IAC5D,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAEnB;gBAEU,IAAI,EAAE,uBAAuB;IAWzC;;;;;;;OAOG;IACG,QAAQ,CACZ,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAC9C,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,wBAAwB,CAAC;IAsHpC,mDAAmD;IACnD,OAAO,CAAC,WAAW;CAsBpB"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file SessionRetriever.ts
|
|
3
|
+
* @description Two-stage hierarchical retriever: select top-K sessions
|
|
4
|
+
* by summary similarity, then return top-M chunks per selected session
|
|
5
|
+
* from the underlying {@link MemoryStore}. Optional rerank pass over
|
|
6
|
+
* the merged pool. Returns a standard `CognitiveRetrievalResult` so
|
|
7
|
+
* downstream consumers (prompt assembly, bench adapters) don't change
|
|
8
|
+
* shape.
|
|
9
|
+
*
|
|
10
|
+
* ## What this does
|
|
11
|
+
*
|
|
12
|
+
* Implements the xMemory (arxiv 2602.02007v3) / TACITREE (EMNLP 2025)
|
|
13
|
+
* hierarchical-retrieval pattern, session-granularity variant: a
|
|
14
|
+
* coverage mechanism that guarantees the reader sees chunks from
|
|
15
|
+
* multiple distinct sessions on multi-session queries. Single-stage
|
|
16
|
+
* retrieval tends to cluster on the single most-relevant session,
|
|
17
|
+
* missing multi-session evidence; this retriever forces diversity by
|
|
18
|
+
* construction.
|
|
19
|
+
*
|
|
20
|
+
* ## Why a separate class, not a `CognitiveMemoryManager` option
|
|
21
|
+
*
|
|
22
|
+
* Keeps the existing manager retrieval path untouched. Step 2 MVP.
|
|
23
|
+
* Future steps may promote session-level retrieval into the manager
|
|
24
|
+
* once it's proven on benchmarks.
|
|
25
|
+
*
|
|
26
|
+
* ## Two-stage flow
|
|
27
|
+
*
|
|
28
|
+
* 1. Stage 1: `summaryStore.querySessions(query, topK=K)` — select
|
|
29
|
+
* top-K sessions.
|
|
30
|
+
* 2. Stage 2: single `memoryStore.query(query, topK=K*M*OVER_FETCH)` —
|
|
31
|
+
* over-fetch to ensure chunks from Stage-1 sessions land in the
|
|
32
|
+
* candidate pool.
|
|
33
|
+
* 3. Post-filter: keep only traces whose `bench-session:<id>` tag
|
|
34
|
+
* matches a Stage-1 session.
|
|
35
|
+
* 4. Group by session, take top-`chunksPerSession` (M) per session.
|
|
36
|
+
* 5. Optional rerank over the merged pool.
|
|
37
|
+
* 6. Truncate to `recallTopK`.
|
|
38
|
+
*
|
|
39
|
+
* ## Fallbacks
|
|
40
|
+
*
|
|
41
|
+
* - Stage 1 returns zero sessions (cold scope, no summaries indexed):
|
|
42
|
+
* fall through to `memoryStore.query` and return its top-
|
|
43
|
+
* `recallTopK` directly. Diagnostics tag
|
|
44
|
+
* `escalations: ['session-retriever:stage1-empty']`.
|
|
45
|
+
* - Stage 2 post-filter wipes the pool: return the raw Stage-2 top-
|
|
46
|
+
* `recallTopK` without session filtering. Diagnostics tag
|
|
47
|
+
* `escalations: ['session-retriever:stage2-empty']`.
|
|
48
|
+
*
|
|
49
|
+
* @module agentos/memory/retrieval/session/SessionRetriever
|
|
50
|
+
*/
|
|
51
|
+
/**
|
|
52
|
+
* Over-fetch multiplier applied to the Stage-2 `MemoryStore.query`
|
|
53
|
+
* topK, so post-filtering by session tag has enough candidates to
|
|
54
|
+
* find chunks from every Stage-1 session.
|
|
55
|
+
*
|
|
56
|
+
* At the defaults (K=5 sessions × M=3 chunks), Stage-2 requests
|
|
57
|
+
* `5 * 3 * 3 = 45` candidates. Empirically this is enough overhead
|
|
58
|
+
* even when the question is topically dominated by one session.
|
|
59
|
+
*/
|
|
60
|
+
const STAGE2_OVER_FETCH = 3;
|
|
61
|
+
/**
|
|
62
|
+
* Two-stage hierarchical retriever.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* const retriever = new SessionRetriever({
|
|
67
|
+
* summaryStore,
|
|
68
|
+
* memoryStore,
|
|
69
|
+
* embeddingManager,
|
|
70
|
+
* rerankerService,
|
|
71
|
+
* defaultTopSessions: 5,
|
|
72
|
+
* defaultChunksPerSession: 3,
|
|
73
|
+
* });
|
|
74
|
+
* const result = await retriever.retrieve(
|
|
75
|
+
* 'What did the user say about their rescue dog?',
|
|
76
|
+
* { valence: 0, arousal: 0, dominance: 0 },
|
|
77
|
+
* { scope: 'user', scopeId: 'u42' },
|
|
78
|
+
* { recallTopK: 10 },
|
|
79
|
+
* );
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
export class SessionRetriever {
|
|
83
|
+
constructor(opts) {
|
|
84
|
+
this.opts = {
|
|
85
|
+
summaryStore: opts.summaryStore,
|
|
86
|
+
memoryStore: opts.memoryStore,
|
|
87
|
+
embeddingManager: opts.embeddingManager,
|
|
88
|
+
rerankerService: opts.rerankerService,
|
|
89
|
+
defaultTopSessions: opts.defaultTopSessions ?? 5,
|
|
90
|
+
defaultChunksPerSession: opts.defaultChunksPerSession ?? 3,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Two-stage retrieve. Returns a `CognitiveRetrievalResult`
|
|
95
|
+
* compatible with the existing `CognitiveMemoryManager.retrieve`
|
|
96
|
+
* shape.
|
|
97
|
+
*
|
|
98
|
+
* Diagnostics are best-effort: timings reflect wall-clock of each
|
|
99
|
+
* stage, not the cognitive-scorer internal accounting.
|
|
100
|
+
*/
|
|
101
|
+
async retrieve(query, mood, scope, options = {}) {
|
|
102
|
+
const startTime = Date.now();
|
|
103
|
+
const K = options.topSessions ?? this.opts.defaultTopSessions;
|
|
104
|
+
const M = options.chunksPerSession ?? this.opts.defaultChunksPerSession;
|
|
105
|
+
const recallTopK = options.recallTopK ?? 10;
|
|
106
|
+
const tagPrefix = options.sessionTagPrefix ?? 'bench-session:';
|
|
107
|
+
// Stage 1: select top-K sessions by summary similarity.
|
|
108
|
+
const stage1Start = Date.now();
|
|
109
|
+
const sessions = await this.opts.summaryStore.querySessions(query, {
|
|
110
|
+
scope: scope.scope,
|
|
111
|
+
scopeId: scope.scopeId,
|
|
112
|
+
topK: K,
|
|
113
|
+
});
|
|
114
|
+
const stage1Ms = Date.now() - stage1Start;
|
|
115
|
+
// Stage-1 fallback: no summaries indexed for this scope.
|
|
116
|
+
if (sessions.length === 0) {
|
|
117
|
+
const { scored, timings } = await this.opts.memoryStore.query(query, mood, {
|
|
118
|
+
topK: recallTopK,
|
|
119
|
+
scopes: [scope],
|
|
120
|
+
});
|
|
121
|
+
return this.buildResult(scored.slice(0, recallTopK), {
|
|
122
|
+
fallback: 'stage1-empty',
|
|
123
|
+
candidatesScanned: scored.length,
|
|
124
|
+
vectorSearchMs: timings.vectorSearchMs,
|
|
125
|
+
scoringMs: timings.scoringMs,
|
|
126
|
+
totalMs: Date.now() - startTime,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// Stage 2: over-fetch from MemoryStore so post-filter has enough
|
|
130
|
+
// candidates per session.
|
|
131
|
+
const overFetchTopK = K * M * STAGE2_OVER_FETCH;
|
|
132
|
+
const { scored: stage2Pool, timings: stage2Timings } = await this.opts.memoryStore.query(query, mood, { topK: overFetchTopK, scopes: [scope] });
|
|
133
|
+
// Post-filter: keep only traces whose bench-session tag matches a
|
|
134
|
+
// Stage-1 session. Group by session.
|
|
135
|
+
const selectedIds = new Set(sessions.map((s) => s.sessionId));
|
|
136
|
+
const bySession = new Map();
|
|
137
|
+
for (const trace of stage2Pool) {
|
|
138
|
+
const tag = trace.tags.find((t) => t.startsWith(tagPrefix));
|
|
139
|
+
if (!tag)
|
|
140
|
+
continue;
|
|
141
|
+
const sid = tag.slice(tagPrefix.length);
|
|
142
|
+
if (!selectedIds.has(sid))
|
|
143
|
+
continue;
|
|
144
|
+
const bucket = bySession.get(sid) ?? [];
|
|
145
|
+
bucket.push(trace);
|
|
146
|
+
bySession.set(sid, bucket);
|
|
147
|
+
}
|
|
148
|
+
// Stage-2 fallback: post-filter wiped the pool. Return raw Stage-2
|
|
149
|
+
// top-recallTopK without session filtering.
|
|
150
|
+
if (bySession.size === 0) {
|
|
151
|
+
return this.buildResult(stage2Pool.slice(0, recallTopK), {
|
|
152
|
+
fallback: 'stage2-empty',
|
|
153
|
+
candidatesScanned: stage2Pool.length,
|
|
154
|
+
vectorSearchMs: stage2Timings.vectorSearchMs,
|
|
155
|
+
scoringMs: stage2Timings.scoringMs,
|
|
156
|
+
totalMs: Date.now() - startTime,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
// Take top-M per session (bucket is already sorted by retrieval
|
|
160
|
+
// score — MemoryStore.query returns scored traces in descending
|
|
161
|
+
// order).
|
|
162
|
+
const merged = [];
|
|
163
|
+
for (const [, bucket] of bySession)
|
|
164
|
+
merged.push(...bucket.slice(0, M));
|
|
165
|
+
// Optional rerank over the merged pool.
|
|
166
|
+
const final = merged;
|
|
167
|
+
if (this.opts.rerankerService && final.length > 0) {
|
|
168
|
+
try {
|
|
169
|
+
const rerankerOutput = await this.opts.rerankerService.rerank({
|
|
170
|
+
query,
|
|
171
|
+
documents: final.map((t) => ({
|
|
172
|
+
id: t.id,
|
|
173
|
+
content: t.content,
|
|
174
|
+
originalScore: t.retrievalScore,
|
|
175
|
+
})),
|
|
176
|
+
}, { topN: final.length });
|
|
177
|
+
const rerankedScores = new Map(rerankerOutput.results.map((r) => [r.id, r.relevanceScore]));
|
|
178
|
+
for (const trace of final) {
|
|
179
|
+
const neural = rerankedScores.get(trace.id);
|
|
180
|
+
if (neural !== undefined) {
|
|
181
|
+
// Blend identical to CognitiveMemoryManager.retrieve: 0.7 cognitive + 0.3 neural.
|
|
182
|
+
trace.retrievalScore = 0.7 * trace.retrievalScore + 0.3 * neural;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
final.sort((a, b) => b.retrievalScore - a.retrievalScore);
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// Reranker errors are non-critical; degrade to cognitive-only ordering.
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
// No rerank: sort by cognitive score (bucket grouping left order
|
|
193
|
+
// per-session, not global).
|
|
194
|
+
final.sort((a, b) => b.retrievalScore - a.retrievalScore);
|
|
195
|
+
}
|
|
196
|
+
// Truncate to recallTopK.
|
|
197
|
+
const truncated = final.slice(0, recallTopK);
|
|
198
|
+
return this.buildResult(truncated, {
|
|
199
|
+
candidatesScanned: stage2Pool.length,
|
|
200
|
+
vectorSearchMs: stage2Timings.vectorSearchMs + stage1Ms,
|
|
201
|
+
scoringMs: stage2Timings.scoringMs,
|
|
202
|
+
totalMs: Date.now() - startTime,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/** Assemble the CognitiveRetrievalResult shape. */
|
|
206
|
+
buildResult(retrieved, d) {
|
|
207
|
+
return {
|
|
208
|
+
retrieved,
|
|
209
|
+
partiallyRetrieved: [],
|
|
210
|
+
diagnostics: {
|
|
211
|
+
candidatesScanned: d.candidatesScanned,
|
|
212
|
+
vectorSearchTimeMs: d.vectorSearchMs,
|
|
213
|
+
scoringTimeMs: d.scoringMs,
|
|
214
|
+
totalTimeMs: d.totalMs,
|
|
215
|
+
...(d.fallback ? { escalations: [`session-retriever:${d.fallback}`] } : {}),
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=SessionRetriever.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionRetriever.js","sourceRoot":"","sources":["../../../../src/memory/retrieval/session/SessionRetriever.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file SessionSummaryStore.ts
|
|
3
|
+
* @description Vector store for session-level summaries, used by
|
|
4
|
+
* {@link SessionRetriever} to select top-K relevant sessions at
|
|
5
|
+
* retrieval time before drilling into chunk-level results.
|
|
6
|
+
*
|
|
7
|
+
* ## What this does
|
|
8
|
+
*
|
|
9
|
+
* Maintains a per-scope vector collection
|
|
10
|
+
* `<collectionPrefix>_<scope>_<scopeId>` (default prefix
|
|
11
|
+
* `cogmem_sessions`) with one vector per unique session. Each vector
|
|
12
|
+
* is the embedding of that session's {@link SessionSummarizer}
|
|
13
|
+
* output: a 50-100 token dense fact-laden summary.
|
|
14
|
+
*
|
|
15
|
+
* ## Why a dedicated collection
|
|
16
|
+
*
|
|
17
|
+
* Session summaries are a structurally different retrieval target
|
|
18
|
+
* than individual memory traces: there's one per conversation thread,
|
|
19
|
+
* they live longer, and they want to be searched in their own metric
|
|
20
|
+
* space without dilution from per-chunk vectors. A dedicated
|
|
21
|
+
* collection also lets {@link SessionRetriever} do Stage 1 session
|
|
22
|
+
* selection with a single cheap vector search, independent of the
|
|
23
|
+
* chunk-level trace store.
|
|
24
|
+
*
|
|
25
|
+
* ## Relation to Anthropic contextual retrieval
|
|
26
|
+
*
|
|
27
|
+
* `SessionSummarizer` implements the Anthropic Sep-2024
|
|
28
|
+
* contextual-retrieval pattern at session granularity: it prepends
|
|
29
|
+
* a summary to every chunk before embedding. This store is the
|
|
30
|
+
* retrieval-time counterpart. It lets callers search the summaries
|
|
31
|
+
* directly rather than relying on the prepended-summary chunks to
|
|
32
|
+
* surface via their own query embeddings. Together they form the
|
|
33
|
+
* `SessionRetriever` two-stage flow documented in the Step 2 design
|
|
34
|
+
* spec.
|
|
35
|
+
*
|
|
36
|
+
* @module agentos/memory/retrieval/session/SessionSummaryStore
|
|
37
|
+
*/
|
|
38
|
+
import type { IVectorStore } from '../../../core/vector-store/IVectorStore.js';
|
|
39
|
+
import type { IEmbeddingManager } from '../../../core/embeddings/IEmbeddingManager.js';
|
|
40
|
+
import type { MemoryScope } from '../../core/types.js';
|
|
41
|
+
/**
|
|
42
|
+
* Options for constructing a {@link SessionSummaryStore}.
|
|
43
|
+
*/
|
|
44
|
+
export interface SessionSummaryStoreOptions {
|
|
45
|
+
/** Vector store to use for the summary collection. */
|
|
46
|
+
vectorStore: IVectorStore;
|
|
47
|
+
/** Embedding manager shared with the rest of the memory stack (reuse for cache hits). */
|
|
48
|
+
embeddingManager: IEmbeddingManager;
|
|
49
|
+
/**
|
|
50
|
+
* Collection-name prefix. Final collection is
|
|
51
|
+
* `<prefix>_<scope>_<scopeId>`.
|
|
52
|
+
* @default 'cogmem_sessions'
|
|
53
|
+
*/
|
|
54
|
+
collectionPrefix?: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Input for {@link SessionSummaryStore.indexSession}.
|
|
58
|
+
*/
|
|
59
|
+
export interface IndexSessionInput {
|
|
60
|
+
scope: MemoryScope;
|
|
61
|
+
scopeId: string;
|
|
62
|
+
sessionId: string;
|
|
63
|
+
/** The summary text produced by `SessionSummarizer`. Must be non-empty. */
|
|
64
|
+
summary: string;
|
|
65
|
+
/** Optional ISO date for the session. Stored for future temporal filtering. */
|
|
66
|
+
sessionDate?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* One row from {@link SessionSummaryStore.querySessions}.
|
|
70
|
+
*/
|
|
71
|
+
export interface QueriedSession {
|
|
72
|
+
sessionId: string;
|
|
73
|
+
/** Similarity in the vector store's configured metric (cosine by default, range [-1, 1]). */
|
|
74
|
+
similarityScore: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Dedicated vector store wrapper for session-level summaries.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* const store = new SessionSummaryStore({ vectorStore, embeddingManager });
|
|
82
|
+
* await store.indexSession({
|
|
83
|
+
* scope: 'user', scopeId: 'u42', sessionId: 's-7',
|
|
84
|
+
* summary: 'User discussed adopting a rescue dog from Portland shelter...',
|
|
85
|
+
* });
|
|
86
|
+
* const hits = await store.querySessions('rescue dog adoption', {
|
|
87
|
+
* scope: 'user', scopeId: 'u42', topK: 5,
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare class SessionSummaryStore {
|
|
92
|
+
private readonly vectorStore;
|
|
93
|
+
private readonly embeddingManager;
|
|
94
|
+
private readonly collectionPrefix;
|
|
95
|
+
constructor(opts: SessionSummaryStoreOptions);
|
|
96
|
+
/**
|
|
97
|
+
* Embed the summary and upsert into the scope-specific collection.
|
|
98
|
+
* Upsert is idempotent: re-indexing the same `sessionId` replaces
|
|
99
|
+
* the prior vector rather than appending a duplicate.
|
|
100
|
+
*/
|
|
101
|
+
indexSession(input: IndexSessionInput): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Embed the query and return the top-K sessions for the given
|
|
104
|
+
* scope, ordered by descending similarity. Returns `[]` when the
|
|
105
|
+
* collection does not yet exist (cold scope).
|
|
106
|
+
*/
|
|
107
|
+
querySessions(query: string, options: {
|
|
108
|
+
scope: MemoryScope;
|
|
109
|
+
scopeId: string;
|
|
110
|
+
topK: number;
|
|
111
|
+
}): Promise<QueriedSession[]>;
|
|
112
|
+
/** Compose the per-scope collection name. */
|
|
113
|
+
private collectionName;
|
|
114
|
+
/**
|
|
115
|
+
* Lazily create the collection with the embedding dimension from
|
|
116
|
+
* the first indexed vector. Idempotent on the `InMemoryVectorStore`
|
|
117
|
+
* implementation; other providers' `createCollection` variants
|
|
118
|
+
* honour `overwriteIfExists: false`.
|
|
119
|
+
*/
|
|
120
|
+
private ensureCollection;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=SessionSummaryStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionSummaryStore.d.ts","sourceRoot":"","sources":["../../../../src/memory/retrieval/session/SessionSummaryStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,4CAA4C,CAAC;AACpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AACvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,sDAAsD;IACtD,WAAW,EAAE,YAAY,CAAC;IAC1B,yFAAyF;IACzF,gBAAgB,EAAE,iBAAiB,CAAC;IACpC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,6FAA6F;IAC7F,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAe;IAC3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoB;IACrD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,IAAI,EAAE,0BAA0B;IAM5C;;;;OAIG;IACG,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB3D;;;;OAIG;IACG,aAAa,CACjB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAC7D,OAAO,CAAC,cAAc,EAAE,CAAC;IAwB5B,6CAA6C;IAC7C,OAAO,CAAC,cAAc;IAItB;;;;;OAKG;YACW,gBAAgB;CAc/B"}
|