@memberjunction/search-engine 5.33.0 → 5.34.1
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/generic/BaseReRanker.d.ts +164 -0
- package/dist/generic/BaseReRanker.d.ts.map +1 -0
- package/dist/generic/BaseReRanker.js +209 -0
- package/dist/generic/BaseReRanker.js.map +1 -0
- package/dist/generic/EntitySearchProvider.d.ts +36 -4
- package/dist/generic/EntitySearchProvider.d.ts.map +1 -1
- package/dist/generic/EntitySearchProvider.js +95 -19
- package/dist/generic/EntitySearchProvider.js.map +1 -1
- package/dist/generic/FullTextSearchProvider.d.ts +2 -2
- package/dist/generic/FullTextSearchProvider.d.ts.map +1 -1
- package/dist/generic/FullTextSearchProvider.js +14 -3
- package/dist/generic/FullTextSearchProvider.js.map +1 -1
- package/dist/generic/ISearchProvider.d.ts +44 -2
- package/dist/generic/ISearchProvider.d.ts.map +1 -1
- package/dist/generic/ISearchProvider.js +35 -1
- package/dist/generic/ISearchProvider.js.map +1 -1
- package/dist/generic/NoopReRanker.d.ts +28 -0
- package/dist/generic/NoopReRanker.d.ts.map +1 -0
- package/dist/generic/NoopReRanker.js +49 -0
- package/dist/generic/NoopReRanker.js.map +1 -0
- package/dist/generic/ScopeTemplateRenderer.d.ts +36 -0
- package/dist/generic/ScopeTemplateRenderer.d.ts.map +1 -0
- package/dist/generic/ScopeTemplateRenderer.js +110 -0
- package/dist/generic/ScopeTemplateRenderer.js.map +1 -0
- package/dist/generic/SearchEngine.d.ts +154 -12
- package/dist/generic/SearchEngine.d.ts.map +1 -1
- package/dist/generic/SearchEngine.js +662 -39
- package/dist/generic/SearchEngine.js.map +1 -1
- package/dist/generic/SearchFusion.d.ts +40 -6
- package/dist/generic/SearchFusion.d.ts.map +1 -1
- package/dist/generic/SearchFusion.js +139 -18
- package/dist/generic/SearchFusion.js.map +1 -1
- package/dist/generic/StorageSearchProvider.d.ts +9 -2
- package/dist/generic/StorageSearchProvider.d.ts.map +1 -1
- package/dist/generic/StorageSearchProvider.js +44 -12
- package/dist/generic/StorageSearchProvider.js.map +1 -1
- package/dist/generic/VectorSearchProvider.d.ts +9 -2
- package/dist/generic/VectorSearchProvider.d.ts.map +1 -1
- package/dist/generic/VectorSearchProvider.js +83 -13
- package/dist/generic/VectorSearchProvider.js.map +1 -1
- package/dist/generic/search.types.d.ts +206 -0
- package/dist/generic/search.types.d.ts.map +1 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -1
- package/dist/permissions/SearchScopePermissionResolver.d.ts +109 -0
- package/dist/permissions/SearchScopePermissionResolver.d.ts.map +1 -0
- package/dist/permissions/SearchScopePermissionResolver.js +159 -0
- package/dist/permissions/SearchScopePermissionResolver.js.map +1 -0
- package/dist/providers/AzureAISearchProvider.d.ts +37 -0
- package/dist/providers/AzureAISearchProvider.d.ts.map +1 -0
- package/dist/providers/AzureAISearchProvider.js +180 -0
- package/dist/providers/AzureAISearchProvider.js.map +1 -0
- package/dist/providers/ElasticsearchSearchProvider.d.ts +43 -0
- package/dist/providers/ElasticsearchSearchProvider.d.ts.map +1 -0
- package/dist/providers/ElasticsearchSearchProvider.js +200 -0
- package/dist/providers/ElasticsearchSearchProvider.js.map +1 -0
- package/dist/providers/OpenSearchSearchProvider.d.ts +36 -0
- package/dist/providers/OpenSearchSearchProvider.d.ts.map +1 -0
- package/dist/providers/OpenSearchSearchProvider.js +167 -0
- package/dist/providers/OpenSearchSearchProvider.js.map +1 -0
- package/dist/providers/TypesenseSearchProvider.d.ts +36 -0
- package/dist/providers/TypesenseSearchProvider.d.ts.map +1 -0
- package/dist/providers/TypesenseSearchProvider.js +161 -0
- package/dist/providers/TypesenseSearchProvider.js.map +1 -0
- package/dist/rerankers/BGEReRanker.d.ts +57 -0
- package/dist/rerankers/BGEReRanker.d.ts.map +1 -0
- package/dist/rerankers/BGEReRanker.js +193 -0
- package/dist/rerankers/BGEReRanker.js.map +1 -0
- package/dist/rerankers/CohereReRanker.d.ts +65 -0
- package/dist/rerankers/CohereReRanker.d.ts.map +1 -0
- package/dist/rerankers/CohereReRanker.js +155 -0
- package/dist/rerankers/CohereReRanker.js.map +1 -0
- package/dist/rerankers/OpenAIReRanker.d.ts +62 -0
- package/dist/rerankers/OpenAIReRanker.d.ts.map +1 -0
- package/dist/rerankers/OpenAIReRanker.js +197 -0
- package/dist/rerankers/OpenAIReRanker.js.map +1 -0
- package/dist/rerankers/RerankerBudgetGuard.d.ts +54 -0
- package/dist/rerankers/RerankerBudgetGuard.d.ts.map +1 -0
- package/dist/rerankers/RerankerBudgetGuard.js +67 -0
- package/dist/rerankers/RerankerBudgetGuard.js.map +1 -0
- package/dist/rerankers/VoyageReRanker.d.ts +59 -0
- package/dist/rerankers/VoyageReRanker.d.ts.map +1 -0
- package/dist/rerankers/VoyageReRanker.js +184 -0
- package/dist/rerankers/VoyageReRanker.js.map +1 -0
- package/package.json +13 -8
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview BGE local-model re-ranker (P2D.5).
|
|
3
|
+
*
|
|
4
|
+
* Self-hosted reranker for deployments that don't want to send candidate documents
|
|
5
|
+
* to a third-party API. Wraps `@xenova/transformers`' `pipeline('text-classification')`
|
|
6
|
+
* loaded with a Xenova-converted BGE reranker model (e.g. `Xenova/bge-reranker-base`,
|
|
7
|
+
* `Xenova/bge-reranker-large`, `Xenova/bge-reranker-v2-m3`).
|
|
8
|
+
*
|
|
9
|
+
* **Cost.** Zero — local model. Reports 0 cents to the budget guard.
|
|
10
|
+
*
|
|
11
|
+
* **Model loading.** Lazy: the model is downloaded on first use into the configured
|
|
12
|
+
* `TRANSFORMERS_CACHE_DIR` (or the transformers.js default). The model is NOT bundled
|
|
13
|
+
* in the npm package. Override the model and cache directory via:
|
|
14
|
+
* - `ScopeConfig.reRanker.config.model` — HuggingFace ID or local path
|
|
15
|
+
* - `ScopeConfig.reRanker.config.cacheDir` — override TRANSFORMERS_CACHE_DIR
|
|
16
|
+
*
|
|
17
|
+
* **Optional peer dep.** `@xenova/transformers` is in `optionalDependencies`. Loaded
|
|
18
|
+
* via dynamic import per CLAUDE.md rule #8 case 2 — consumers who don't want a
|
|
19
|
+
* local-model reranker don't pay the bundle cost.
|
|
20
|
+
*
|
|
21
|
+
* @module @memberjunction/search-engine
|
|
22
|
+
*/
|
|
23
|
+
import { UserInfo } from '@memberjunction/core';
|
|
24
|
+
import { BaseReRanker } from '../generic/BaseReRanker.js';
|
|
25
|
+
import { SearchResultItem } from '../generic/search.types.js';
|
|
26
|
+
/**
|
|
27
|
+
* Local BGE reranker. Configure per scope via
|
|
28
|
+
* `SearchScope.ScopeConfig.reRanker.driverClass = 'BGEReRanker'`.
|
|
29
|
+
*/
|
|
30
|
+
export declare class BGEReRanker extends BaseReRanker {
|
|
31
|
+
get DriverClass(): string;
|
|
32
|
+
get Name(): string;
|
|
33
|
+
get Version(): string;
|
|
34
|
+
/**
|
|
35
|
+
* No hard cap from the model itself, but practical memory limits apply. We cap at
|
|
36
|
+
* 5000 to match what fits comfortably in 16 GB RAM with `bge-reranker-base`.
|
|
37
|
+
*/
|
|
38
|
+
GetMaxResultCount(): number;
|
|
39
|
+
/** Local model — no per-call charge. */
|
|
40
|
+
EstimateCostCents(_resultCount: number): number;
|
|
41
|
+
ReRank(query: string, candidates: SearchResultItem[], topN: number, _contextUser: UserInfo, config?: Record<string, unknown>): Promise<SearchResultItem[]>;
|
|
42
|
+
/** Subclasses can override to customize the candidate's text representation. */
|
|
43
|
+
protected buildText(item: SearchResultItem): string;
|
|
44
|
+
/**
|
|
45
|
+
* Normalize the various shapes transformers.js may return into a flat number[]
|
|
46
|
+
* with one score per input pair. Throws when the shape doesn't match.
|
|
47
|
+
*/
|
|
48
|
+
protected extractScores(raw: unknown, expectedLength: number): number[];
|
|
49
|
+
}
|
|
50
|
+
/** Tree-shake prevention helper. */
|
|
51
|
+
export declare function LoadBGEReRanker(): void;
|
|
52
|
+
/**
|
|
53
|
+
* Test-only export: clear the per-model pipeline cache. Used by tests so each test
|
|
54
|
+
* can install its own mock pipeline.
|
|
55
|
+
*/
|
|
56
|
+
export declare function __resetBGEPipelineCacheForTests(): void;
|
|
57
|
+
//# sourceMappingURL=BGEReRanker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BGEReRanker.d.ts","sourceRoot":"","sources":["../../src/rerankers/BGEReRanker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AA6D3D;;;GAGG;AACH,qBACa,WAAY,SAAQ,YAAY;IACzC,IAAW,WAAW,IAAI,MAAM,CAE/B;IACD,IAAoB,IAAI,IAAI,MAAM,CAEjC;IACD,IAAoB,OAAO,IAAI,MAAM,CAEpC;IAED;;;OAGG;IACa,iBAAiB,IAAI,MAAM;IAI3C,wCAAwC;IACxB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM;IAIzC,MAAM,CACxB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,gBAAgB,EAAE,EAC9B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,QAAQ,EACtB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAiD9B,gFAAgF;IAChF,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,MAAM;IAKnD;;;OAGG;IACH,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,EAAE;CAqB1E;AAED,oCAAoC;AACpC,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,IAAI,IAAI,CAGtD"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview BGE local-model re-ranker (P2D.5).
|
|
3
|
+
*
|
|
4
|
+
* Self-hosted reranker for deployments that don't want to send candidate documents
|
|
5
|
+
* to a third-party API. Wraps `@xenova/transformers`' `pipeline('text-classification')`
|
|
6
|
+
* loaded with a Xenova-converted BGE reranker model (e.g. `Xenova/bge-reranker-base`,
|
|
7
|
+
* `Xenova/bge-reranker-large`, `Xenova/bge-reranker-v2-m3`).
|
|
8
|
+
*
|
|
9
|
+
* **Cost.** Zero — local model. Reports 0 cents to the budget guard.
|
|
10
|
+
*
|
|
11
|
+
* **Model loading.** Lazy: the model is downloaded on first use into the configured
|
|
12
|
+
* `TRANSFORMERS_CACHE_DIR` (or the transformers.js default). The model is NOT bundled
|
|
13
|
+
* in the npm package. Override the model and cache directory via:
|
|
14
|
+
* - `ScopeConfig.reRanker.config.model` — HuggingFace ID or local path
|
|
15
|
+
* - `ScopeConfig.reRanker.config.cacheDir` — override TRANSFORMERS_CACHE_DIR
|
|
16
|
+
*
|
|
17
|
+
* **Optional peer dep.** `@xenova/transformers` is in `optionalDependencies`. Loaded
|
|
18
|
+
* via dynamic import per CLAUDE.md rule #8 case 2 — consumers who don't want a
|
|
19
|
+
* local-model reranker don't pay the bundle cost.
|
|
20
|
+
*
|
|
21
|
+
* @module @memberjunction/search-engine
|
|
22
|
+
*/
|
|
23
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
24
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
25
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
26
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
27
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
28
|
+
};
|
|
29
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
30
|
+
import { LogError } from '@memberjunction/core';
|
|
31
|
+
import { BaseReRanker } from '../generic/BaseReRanker.js';
|
|
32
|
+
/**
|
|
33
|
+
* Memoized loader for the transformers.js module. Same pattern as LocalEmbedding —
|
|
34
|
+
* a single dynamic import the first time, reused thereafter.
|
|
35
|
+
*/
|
|
36
|
+
let transformersPromise = null;
|
|
37
|
+
function loadTransformers() {
|
|
38
|
+
if (!transformersPromise) {
|
|
39
|
+
transformersPromise = (async () => {
|
|
40
|
+
try {
|
|
41
|
+
// SearchEngine is ESM (`"type": "module"`), so a real dynamic import is
|
|
42
|
+
// safe here — no need for the `eval('import(...)')` workaround that
|
|
43
|
+
// packages-as-CJS use. This is also what allows tests to vi.mock().
|
|
44
|
+
const mod = await import('@xenova/transformers');
|
|
45
|
+
return mod;
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
throw new Error(`BGEReRanker: '@xenova/transformers' is not installed. Add it to your project's dependencies if you intend to use the BGE local reranker. Underlying error: ${err instanceof Error ? err.message : String(err)}`);
|
|
49
|
+
}
|
|
50
|
+
})();
|
|
51
|
+
}
|
|
52
|
+
return transformersPromise;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Per-model pipeline cache. Keyed by `${modelId}|${cacheDir}` so the same process can
|
|
56
|
+
* host multiple BGE variants without thrashing.
|
|
57
|
+
*/
|
|
58
|
+
const pipelineCache = new Map();
|
|
59
|
+
async function getPipeline(modelId, cacheDir) {
|
|
60
|
+
const key = `${modelId}|${cacheDir ?? ''}`;
|
|
61
|
+
let cached = pipelineCache.get(key);
|
|
62
|
+
if (!cached) {
|
|
63
|
+
cached = (async () => {
|
|
64
|
+
const transformers = await loadTransformers();
|
|
65
|
+
if (cacheDir)
|
|
66
|
+
transformers.env.cacheDir = cacheDir;
|
|
67
|
+
return transformers.pipeline('text-classification', modelId, { quantized: true });
|
|
68
|
+
})();
|
|
69
|
+
pipelineCache.set(key, cached);
|
|
70
|
+
}
|
|
71
|
+
return cached;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Local BGE reranker. Configure per scope via
|
|
75
|
+
* `SearchScope.ScopeConfig.reRanker.driverClass = 'BGEReRanker'`.
|
|
76
|
+
*/
|
|
77
|
+
let BGEReRanker = class BGEReRanker extends BaseReRanker {
|
|
78
|
+
get DriverClass() {
|
|
79
|
+
return 'BGEReRanker';
|
|
80
|
+
}
|
|
81
|
+
get Name() {
|
|
82
|
+
return 'BGE';
|
|
83
|
+
}
|
|
84
|
+
get Version() {
|
|
85
|
+
return '1';
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* No hard cap from the model itself, but practical memory limits apply. We cap at
|
|
89
|
+
* 5000 to match what fits comfortably in 16 GB RAM with `bge-reranker-base`.
|
|
90
|
+
*/
|
|
91
|
+
GetMaxResultCount() {
|
|
92
|
+
return 5000;
|
|
93
|
+
}
|
|
94
|
+
/** Local model — no per-call charge. */
|
|
95
|
+
EstimateCostCents(_resultCount) {
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
async ReRank(query, candidates, topN, _contextUser, config) {
|
|
99
|
+
if (topN <= 0 || candidates.length === 0)
|
|
100
|
+
return [];
|
|
101
|
+
const modelId = config?.['model'] ?? 'Xenova/bge-reranker-base';
|
|
102
|
+
const cacheDir = config?.['cacheDir'];
|
|
103
|
+
let scoreFor;
|
|
104
|
+
try {
|
|
105
|
+
scoreFor = await getPipeline(modelId, cacheDir);
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
LogError(`BGEReRanker: failed to load pipeline for "${modelId}": ${err instanceof Error ? err.message : String(err)}`);
|
|
109
|
+
// Fall back to a top-N slice when the local model can't be loaded.
|
|
110
|
+
return candidates.slice(0, topN);
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
// For cross-encoder reranking we feed each candidate as a [query, doc] pair.
|
|
114
|
+
// transformers.js text-classification accepts an array of pairs — call once
|
|
115
|
+
// with all pairs to get one response per pair.
|
|
116
|
+
const pairs = candidates.map(c => [query, this.buildText(c)]);
|
|
117
|
+
const raw = await scoreFor(pairs);
|
|
118
|
+
// The pipeline returns either an array of `{label, score}` (one per pair) or
|
|
119
|
+
// an array of arrays when multi-label is enabled. Normalize to a flat array
|
|
120
|
+
// of scores. We treat `score` as relevance directly; for binary cross-encoders
|
|
121
|
+
// the model emits a logit-style score we use as-is for ranking purposes.
|
|
122
|
+
const scores = this.extractScores(raw, candidates.length);
|
|
123
|
+
const ranked = candidates
|
|
124
|
+
.map((c, i) => ({
|
|
125
|
+
item: c,
|
|
126
|
+
score: scores[i] ?? 0,
|
|
127
|
+
}))
|
|
128
|
+
.sort((a, b) => b.score - a.score)
|
|
129
|
+
.slice(0, topN)
|
|
130
|
+
.map(p => ({
|
|
131
|
+
...p.item,
|
|
132
|
+
Score: p.score,
|
|
133
|
+
ScoreBreakdown: { ...p.item.ScoreBreakdown, ReRank: p.score },
|
|
134
|
+
}));
|
|
135
|
+
// Local model — no cost reported.
|
|
136
|
+
return ranked;
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
LogError(`BGEReRanker: rerank failed for "${modelId}": ${err instanceof Error ? err.message : String(err)}`);
|
|
140
|
+
return candidates.slice(0, topN);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/** Subclasses can override to customize the candidate's text representation. */
|
|
144
|
+
buildText(item) {
|
|
145
|
+
const parts = [item.Title, item.Snippet].filter(p => p != null && p.length > 0);
|
|
146
|
+
return parts.join('\n');
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Normalize the various shapes transformers.js may return into a flat number[]
|
|
150
|
+
* with one score per input pair. Throws when the shape doesn't match.
|
|
151
|
+
*/
|
|
152
|
+
extractScores(raw, expectedLength) {
|
|
153
|
+
if (!Array.isArray(raw)) {
|
|
154
|
+
throw new Error('BGEReRanker: pipeline did not return an array');
|
|
155
|
+
}
|
|
156
|
+
const out = [];
|
|
157
|
+
for (const entry of raw) {
|
|
158
|
+
if (entry && typeof entry === 'object' && 'score' in entry && typeof entry.score === 'number') {
|
|
159
|
+
out.push(entry.score);
|
|
160
|
+
}
|
|
161
|
+
else if (Array.isArray(entry)) {
|
|
162
|
+
// Multi-label form — take the first label's score
|
|
163
|
+
const first = entry[0];
|
|
164
|
+
out.push(first && typeof first.score === 'number' ? first.score : 0);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
out.push(0);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (out.length !== expectedLength) {
|
|
171
|
+
throw new Error(`BGEReRanker: pipeline returned ${out.length} scores for ${expectedLength} inputs`);
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
BGEReRanker = __decorate([
|
|
177
|
+
RegisterClass(BaseReRanker, 'BGEReRanker')
|
|
178
|
+
], BGEReRanker);
|
|
179
|
+
export { BGEReRanker };
|
|
180
|
+
/** Tree-shake prevention helper. */
|
|
181
|
+
export function LoadBGEReRanker() {
|
|
182
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
183
|
+
const _ref = BGEReRanker;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Test-only export: clear the per-model pipeline cache. Used by tests so each test
|
|
187
|
+
* can install its own mock pipeline.
|
|
188
|
+
*/
|
|
189
|
+
export function __resetBGEPipelineCacheForTests() {
|
|
190
|
+
pipelineCache.clear();
|
|
191
|
+
transformersPromise = null;
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=BGEReRanker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BGEReRanker.js","sourceRoot":"","sources":["../../src/rerankers/BGEReRanker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Cohere Rerank API integration (P2D.2).
|
|
3
|
+
*
|
|
4
|
+
* Wraps Cohere's `rerank-v3.5` (English) and `rerank-multilingual-v3.0` endpoints
|
|
5
|
+
* for use as a SearchEngine re-ranker. Distinct from `@memberjunction/ai-cohere`'s
|
|
6
|
+
* `CohereReranker` which is purpose-built for memory-note rerank with a specific
|
|
7
|
+
* augmented prompt — scope search needs the raw query passed through unchanged
|
|
8
|
+
* for accurate semantic similarity.
|
|
9
|
+
*
|
|
10
|
+
* **Cost model.** Cohere bills per "search," where one search reranks up to 100
|
|
11
|
+
* documents. Above 100 docs, larger requests count as multiple searches.
|
|
12
|
+
* Pricing as of 2026-04: $2.00 per 1k searches → 0.2¢ / search.
|
|
13
|
+
*
|
|
14
|
+
* **API key resolution.** Uses `GetAIAPIKey('CohereLLM')` — same key the AI-layer
|
|
15
|
+
* Cohere reranker uses, sourced from the AIAPIKey registry (driver class
|
|
16
|
+
* `CohereLLM` → env var `AI_VENDOR_API_KEY__COHERELLM`).
|
|
17
|
+
*
|
|
18
|
+
* **Optional peer dependency.** `cohere-ai` is declared in `optionalDependencies`
|
|
19
|
+
* so SearchEngine consumers who don't use Cohere don't pay the bundle cost.
|
|
20
|
+
* Loaded via a dynamic import per CLAUDE.md rule #8 case 2 (optional peer).
|
|
21
|
+
*
|
|
22
|
+
* @module @memberjunction/search-engine
|
|
23
|
+
*/
|
|
24
|
+
import { UserInfo } from '@memberjunction/core';
|
|
25
|
+
import { BaseReranker as AIBaseReranker } from '@memberjunction/ai';
|
|
26
|
+
import { BaseReRanker } from '../generic/BaseReRanker.js';
|
|
27
|
+
import { SearchResultItem } from '../generic/search.types.js';
|
|
28
|
+
/**
|
|
29
|
+
* Cohere `rerank-v3.5` re-ranker for SearchEngine. Configured per scope via
|
|
30
|
+
* `SearchScope.ScopeConfig.reRanker.driverClass = 'CohereReRanker'`.
|
|
31
|
+
*
|
|
32
|
+
* The model name can be overridden via `ScopeConfig.reRanker.config.model`
|
|
33
|
+
* (e.g. `'rerank-multilingual-v3.0'`).
|
|
34
|
+
*/
|
|
35
|
+
export declare class CohereReRanker extends BaseReRanker {
|
|
36
|
+
get DriverClass(): string;
|
|
37
|
+
get Name(): string;
|
|
38
|
+
get Version(): string;
|
|
39
|
+
/**
|
|
40
|
+
* Cohere caps a single rerank call at 1000 documents. Above this, the SearchEngine
|
|
41
|
+
* should chunk (not implemented yet — most realistic candidate lists are <100).
|
|
42
|
+
*/
|
|
43
|
+
GetMaxResultCount(): number;
|
|
44
|
+
/**
|
|
45
|
+
* Cohere bills per "search". 1 search reranks up to 100 documents; above 100,
|
|
46
|
+
* count as `ceil(N/100)` searches. As of 2026-04, $2.00 per 1k searches = 0.2¢
|
|
47
|
+
* per search. Override via `config.cents_per_search` if Cohere's pricing changes.
|
|
48
|
+
*/
|
|
49
|
+
EstimateCostCents(resultCount: number): number;
|
|
50
|
+
protected getAIReranker(config: Record<string, unknown> | undefined, _contextUser: UserInfo): AIBaseReranker | null;
|
|
51
|
+
/**
|
|
52
|
+
* Override `ReRank` to record actual cost via the inherited `reportCost` helper
|
|
53
|
+
* after a successful Cohere call. Cohere bills per request (not per token), so
|
|
54
|
+
* the post-call cost equals the pre-call estimate — no separate measurement
|
|
55
|
+
* required.
|
|
56
|
+
*/
|
|
57
|
+
ReRank(query: string, candidates: SearchResultItem[], topN: number, contextUser: UserInfo, config?: Record<string, unknown>): Promise<SearchResultItem[]>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Tree-shake prevention helper. Call from a consumer's `public-api.ts` (or from
|
|
61
|
+
* `LoadCohereReRanker()` in a generated registration manifest) to guarantee the
|
|
62
|
+
* `@RegisterClass` side-effect runs.
|
|
63
|
+
*/
|
|
64
|
+
export declare function LoadCohereReRanker(): void;
|
|
65
|
+
//# sourceMappingURL=CohereReRanker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CohereReRanker.d.ts","sourceRoot":"","sources":["../../src/rerankers/CohereReRanker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EACH,YAAY,IAAI,cAAc,EAIjC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAkE3D;;;;;;GAMG;AACH,qBACa,cAAe,SAAQ,YAAY;IAC5C,IAAW,WAAW,IAAI,MAAM,CAE/B;IACD,IAAoB,IAAI,IAAI,MAAM,CAEjC;IACD,IAAoB,OAAO,IAAI,MAAM,CAEpC;IAED;;;OAGG;IACa,iBAAiB,IAAI,MAAM;IAI3C;;;;OAIG;IACa,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;cAK3C,aAAa,CAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC3C,YAAY,EAAE,QAAQ,GACvB,cAAc,GAAG,IAAI;IAUxB;;;;;OAKG;IACmB,MAAM,CACxB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,gBAAgB,EAAE,EAC9B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,QAAQ,EACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAUjC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Cohere Rerank API integration (P2D.2).
|
|
3
|
+
*
|
|
4
|
+
* Wraps Cohere's `rerank-v3.5` (English) and `rerank-multilingual-v3.0` endpoints
|
|
5
|
+
* for use as a SearchEngine re-ranker. Distinct from `@memberjunction/ai-cohere`'s
|
|
6
|
+
* `CohereReranker` which is purpose-built for memory-note rerank with a specific
|
|
7
|
+
* augmented prompt — scope search needs the raw query passed through unchanged
|
|
8
|
+
* for accurate semantic similarity.
|
|
9
|
+
*
|
|
10
|
+
* **Cost model.** Cohere bills per "search," where one search reranks up to 100
|
|
11
|
+
* documents. Above 100 docs, larger requests count as multiple searches.
|
|
12
|
+
* Pricing as of 2026-04: $2.00 per 1k searches → 0.2¢ / search.
|
|
13
|
+
*
|
|
14
|
+
* **API key resolution.** Uses `GetAIAPIKey('CohereLLM')` — same key the AI-layer
|
|
15
|
+
* Cohere reranker uses, sourced from the AIAPIKey registry (driver class
|
|
16
|
+
* `CohereLLM` → env var `AI_VENDOR_API_KEY__COHERELLM`).
|
|
17
|
+
*
|
|
18
|
+
* **Optional peer dependency.** `cohere-ai` is declared in `optionalDependencies`
|
|
19
|
+
* so SearchEngine consumers who don't use Cohere don't pay the bundle cost.
|
|
20
|
+
* Loaded via a dynamic import per CLAUDE.md rule #8 case 2 (optional peer).
|
|
21
|
+
*
|
|
22
|
+
* @module @memberjunction/search-engine
|
|
23
|
+
*/
|
|
24
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
25
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
26
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
27
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
28
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
29
|
+
};
|
|
30
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
31
|
+
import { LogError } from '@memberjunction/core';
|
|
32
|
+
import { BaseReranker as AIBaseReranker, GetAIAPIKey, } from '@memberjunction/ai';
|
|
33
|
+
import { BaseReRanker } from '../generic/BaseReRanker.js';
|
|
34
|
+
/**
|
|
35
|
+
* Memoized loader for the Cohere SDK. The dynamic import is the **single** approved
|
|
36
|
+
* use of `import()` in this file (CLAUDE.md #8 case 2 — optional peer dep). Caching
|
|
37
|
+
* the resolved client constructor avoids paying the dynamic import cost on every
|
|
38
|
+
* Rerank call.
|
|
39
|
+
*/
|
|
40
|
+
let cohereClientCtorPromise = null;
|
|
41
|
+
async function getCohereClientCtor() {
|
|
42
|
+
if (!cohereClientCtorPromise) {
|
|
43
|
+
cohereClientCtorPromise = (async () => {
|
|
44
|
+
try {
|
|
45
|
+
const mod = await import('cohere-ai');
|
|
46
|
+
return mod.CohereClient;
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
throw new Error(`CohereReRanker: 'cohere-ai' is not installed. Add it to your project's dependencies if you intend to use the Cohere reranker. Underlying error: ${err instanceof Error ? err.message : String(err)}`);
|
|
50
|
+
}
|
|
51
|
+
})();
|
|
52
|
+
}
|
|
53
|
+
return cohereClientCtorPromise;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Inline AI-layer reranker that calls Cohere's `rerank` endpoint with the raw query
|
|
57
|
+
* (no enhanced prompt). Distinct from `@memberjunction/ai-cohere`'s `CohereReranker`
|
|
58
|
+
* which augments the query for memory-note semantics.
|
|
59
|
+
*/
|
|
60
|
+
class CohereScopeAIReranker extends AIBaseReranker {
|
|
61
|
+
constructor(apiKey, modelName) {
|
|
62
|
+
super(apiKey, modelName);
|
|
63
|
+
this._clientPromise = getCohereClientCtor().then(Ctor => new Ctor({ token: this.apiKey }));
|
|
64
|
+
}
|
|
65
|
+
async doRerank(params) {
|
|
66
|
+
const client = await this._clientPromise;
|
|
67
|
+
const response = await client.rerank({
|
|
68
|
+
model: this._modelName,
|
|
69
|
+
query: params.query,
|
|
70
|
+
documents: params.documents.map(d => d.text),
|
|
71
|
+
topN: params.topK ?? params.documents.length,
|
|
72
|
+
returnDocuments: false,
|
|
73
|
+
});
|
|
74
|
+
return response.results.map((r, idx) => ({
|
|
75
|
+
id: params.documents[r.index].id,
|
|
76
|
+
relevanceScore: r.relevanceScore,
|
|
77
|
+
document: params.documents[r.index],
|
|
78
|
+
rank: idx,
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Cohere `rerank-v3.5` re-ranker for SearchEngine. Configured per scope via
|
|
84
|
+
* `SearchScope.ScopeConfig.reRanker.driverClass = 'CohereReRanker'`.
|
|
85
|
+
*
|
|
86
|
+
* The model name can be overridden via `ScopeConfig.reRanker.config.model`
|
|
87
|
+
* (e.g. `'rerank-multilingual-v3.0'`).
|
|
88
|
+
*/
|
|
89
|
+
let CohereReRanker = class CohereReRanker extends BaseReRanker {
|
|
90
|
+
get DriverClass() {
|
|
91
|
+
return 'CohereReRanker';
|
|
92
|
+
}
|
|
93
|
+
get Name() {
|
|
94
|
+
return 'Cohere';
|
|
95
|
+
}
|
|
96
|
+
get Version() {
|
|
97
|
+
return '1';
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Cohere caps a single rerank call at 1000 documents. Above this, the SearchEngine
|
|
101
|
+
* should chunk (not implemented yet — most realistic candidate lists are <100).
|
|
102
|
+
*/
|
|
103
|
+
GetMaxResultCount() {
|
|
104
|
+
return 1000;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Cohere bills per "search". 1 search reranks up to 100 documents; above 100,
|
|
108
|
+
* count as `ceil(N/100)` searches. As of 2026-04, $2.00 per 1k searches = 0.2¢
|
|
109
|
+
* per search. Override via `config.cents_per_search` if Cohere's pricing changes.
|
|
110
|
+
*/
|
|
111
|
+
EstimateCostCents(resultCount) {
|
|
112
|
+
const searches = Math.max(1, Math.ceil(resultCount / 100));
|
|
113
|
+
return searches * 0.2;
|
|
114
|
+
}
|
|
115
|
+
getAIReranker(config, _contextUser) {
|
|
116
|
+
const apiKey = GetAIAPIKey('CohereLLM');
|
|
117
|
+
if (!apiKey) {
|
|
118
|
+
LogError('CohereReRanker: no API key found for driver "CohereLLM" — set AI_VENDOR_API_KEY__COHERELLM or register an AIAPIKeys subclass.');
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const modelName = config?.['model'] ?? 'rerank-v3.5';
|
|
122
|
+
return new CohereScopeAIReranker(apiKey, modelName);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Override `ReRank` to record actual cost via the inherited `reportCost` helper
|
|
126
|
+
* after a successful Cohere call. Cohere bills per request (not per token), so
|
|
127
|
+
* the post-call cost equals the pre-call estimate — no separate measurement
|
|
128
|
+
* required.
|
|
129
|
+
*/
|
|
130
|
+
async ReRank(query, candidates, topN, contextUser, config) {
|
|
131
|
+
if (topN <= 0 || candidates.length === 0)
|
|
132
|
+
return [];
|
|
133
|
+
const result = await super.ReRank(query, candidates, topN, contextUser, config);
|
|
134
|
+
// Charge cost only when the call actually went out — when getAIReranker
|
|
135
|
+
// returns null, super.ReRank short-circuits to a slice and we shouldn't bill.
|
|
136
|
+
if (this.getAIReranker(config, contextUser)) {
|
|
137
|
+
this.reportCost(this.EstimateCostCents(candidates.length));
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
CohereReRanker = __decorate([
|
|
143
|
+
RegisterClass(BaseReRanker, 'CohereReRanker')
|
|
144
|
+
], CohereReRanker);
|
|
145
|
+
export { CohereReRanker };
|
|
146
|
+
/**
|
|
147
|
+
* Tree-shake prevention helper. Call from a consumer's `public-api.ts` (or from
|
|
148
|
+
* `LoadCohereReRanker()` in a generated registration manifest) to guarantee the
|
|
149
|
+
* `@RegisterClass` side-effect runs.
|
|
150
|
+
*/
|
|
151
|
+
export function LoadCohereReRanker() {
|
|
152
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
153
|
+
const _ref = CohereReRanker;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=CohereReRanker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CohereReRanker.js","sourceRoot":"","sources":["../../src/rerankers/CohereReRanker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview OpenAI chat-judge re-ranker (P2D.4).
|
|
3
|
+
*
|
|
4
|
+
* **Decision (2026-04-28):** OpenAI does not publish a first-party reranker endpoint.
|
|
5
|
+
* Their offerings are completions, chat, embeddings, and moderation — there is no
|
|
6
|
+
* dedicated `/rerank`. This implementation uses the documented fallback from the plan:
|
|
7
|
+
* a small chat-completion-based "judge" that scores each candidate's relevance to the
|
|
8
|
+
* query and returns the new ordering. Re-evaluate this decision when OpenAI ships a
|
|
9
|
+
* first-party reranker — the canonical plan calls out swapping in the first-party
|
|
10
|
+
* endpoint as soon as it exists.
|
|
11
|
+
*
|
|
12
|
+
* **Approach.** Single chat completion call, JSON-mode response. The model receives
|
|
13
|
+
* the query and a numbered list of documents and returns
|
|
14
|
+
* `{ "scores": [<number 0..1>, ...] }` with one score per document, in input order.
|
|
15
|
+
* We then sort by score, slice to topN, and return.
|
|
16
|
+
*
|
|
17
|
+
* **Cost.** `gpt-4o-mini` defaults: $0.15 / 1M input tokens, $0.60 / 1M output tokens
|
|
18
|
+
* (2026-04 pricing). Pre-call estimate uses a conservative ~80 tokens/doc input plus
|
|
19
|
+
* 8 tokens/doc output. Post-call cost reports the exact `usage.{prompt,completion}_tokens`
|
|
20
|
+
* from OpenAI so the budget guard sees real spend.
|
|
21
|
+
*
|
|
22
|
+
* **API key.** `GetAIAPIKey('OpenAILLM')` —
|
|
23
|
+
* AI_VENDOR_API_KEY__OPENAILLM or any registered AIAPIKeys subclass.
|
|
24
|
+
*
|
|
25
|
+
* @module @memberjunction/search-engine
|
|
26
|
+
*/
|
|
27
|
+
import { UserInfo } from '@memberjunction/core';
|
|
28
|
+
import { BaseReranker as AIBaseReranker } from '@memberjunction/ai';
|
|
29
|
+
import { BaseReRanker } from '../generic/BaseReRanker.js';
|
|
30
|
+
import { SearchResultItem } from '../generic/search.types.js';
|
|
31
|
+
/**
|
|
32
|
+
* Chat-completion-based "judge" reranker. Configure per scope via
|
|
33
|
+
* `SearchScope.ScopeConfig.reRanker.driverClass = 'OpenAIReRanker'`.
|
|
34
|
+
*
|
|
35
|
+
* Override the model via `ScopeConfig.reRanker.config.model`
|
|
36
|
+
* (default: `gpt-4o-mini` — change when a first-party OpenAI rerank endpoint launches).
|
|
37
|
+
*/
|
|
38
|
+
export declare class OpenAIReRanker extends BaseReRanker {
|
|
39
|
+
/** Pricing in cents-per-token. As of 2026-04. */
|
|
40
|
+
private static readonly PRICING;
|
|
41
|
+
private currentAIReranker;
|
|
42
|
+
get DriverClass(): string;
|
|
43
|
+
get Name(): string;
|
|
44
|
+
get Version(): string;
|
|
45
|
+
/**
|
|
46
|
+
* Effective limit when the candidate list plus prompt fits in the model's input
|
|
47
|
+
* window. With gpt-4o-mini's 128k input context and ~80 tokens/doc, the practical
|
|
48
|
+
* cap is well above 1000. Returning 1000 to match the other rerankers; the
|
|
49
|
+
* SearchEngine will chunk above this when chunking is implemented.
|
|
50
|
+
*/
|
|
51
|
+
GetMaxResultCount(): number;
|
|
52
|
+
/**
|
|
53
|
+
* Pre-call cost estimate. ~80 input tokens/doc + 50 system/query tokens, plus
|
|
54
|
+
* 8 output tokens/doc. Conservative — actual usage tends to be lower.
|
|
55
|
+
*/
|
|
56
|
+
EstimateCostCents(resultCount: number): number;
|
|
57
|
+
protected getAIReranker(config: Record<string, unknown> | undefined, _contextUser: UserInfo): AIBaseReranker | null;
|
|
58
|
+
ReRank(query: string, candidates: SearchResultItem[], topN: number, contextUser: UserInfo, config?: Record<string, unknown>): Promise<SearchResultItem[]>;
|
|
59
|
+
}
|
|
60
|
+
/** Tree-shake prevention helper. */
|
|
61
|
+
export declare function LoadOpenAIReRanker(): void;
|
|
62
|
+
//# sourceMappingURL=OpenAIReRanker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OpenAIReRanker.d.ts","sourceRoot":"","sources":["../../src/rerankers/OpenAIReRanker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAY,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EACH,YAAY,IAAI,cAAc,EAIjC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AA0F3D;;;;;;GAMG;AACH,qBACa,cAAe,SAAQ,YAAY;IAC5C,iDAAiD;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAK7B;IAEF,OAAO,CAAC,iBAAiB,CAAsC;IAE/D,IAAW,WAAW,IAAI,MAAM,CAE/B;IACD,IAAoB,IAAI,IAAI,MAAM,CAEjC;IACD,IAAoB,OAAO,IAAI,MAAM,CAEpC;IAED;;;;;OAKG;IACa,iBAAiB,IAAI,MAAM;IAI3C;;;OAGG;IACa,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;cAO3C,aAAa,CAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC3C,YAAY,EAAE,QAAQ,GACvB,cAAc,GAAG,IAAI;IAaF,MAAM,CACxB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,gBAAgB,EAAE,EAC9B,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,QAAQ,EACrB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAiBjC;AAED,oCAAoC;AACpC,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC"}
|