pi-context-engine 0.1.3 → 0.2.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.
- package/README.md +59 -0
- package/docs/IMPLEMENTATION-PLAN.md +500 -0
- package/docs/RESEARCH-RETRIEVAL.md +532 -0
- package/package.json +83 -79
- package/src/compression/compressor.ts +119 -20
- package/src/config.ts +59 -3
- package/src/engine.ts +206 -12
- package/src/extension.ts +12 -1
- package/src/guidance.ts +1 -0
- package/src/indexer/chunker.ts +321 -21
- package/src/indexer/context-header.ts +86 -0
- package/src/indexer/embedder.ts +51 -3
- package/src/indexer/manifest.ts +8 -4
- package/src/indexer/pipeline.ts +223 -18
- package/src/memory/db.ts +128 -1
- package/src/retrieval/confidence.ts +53 -0
- package/src/retrieval/query-parser.ts +33 -0
- package/src/retrieval/reranker.ts +112 -0
- package/src/retrieval/retriever.ts +351 -14
- package/src/storage/fts-store.ts +48 -6
- package/src/storage/graph-store.ts +160 -4
- package/src/storage/local-backend.ts +36 -0
- package/src/storage/vector-store.ts +22 -0
package/package.json
CHANGED
|
@@ -1,81 +1,85 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
2
|
+
"name": "pi-context-engine",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Semantic code context for pi: tree-sitter index + hybrid vector/BM25 retrieval + cross-session memory, all local. Port of code-context-engine (MIT, elara-labs) as a native pi extension.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pi-package",
|
|
7
|
+
"pi-extension",
|
|
8
|
+
"context-engine",
|
|
9
|
+
"code-search",
|
|
10
|
+
"semantic-search",
|
|
11
|
+
"vector-search",
|
|
12
|
+
"tree-sitter",
|
|
13
|
+
"token-savings",
|
|
14
|
+
"memory"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"type": "module",
|
|
18
|
+
"main": "src/extension.ts",
|
|
19
|
+
"files": [
|
|
20
|
+
"src",
|
|
21
|
+
"docs",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"test:watch": "vitest watch",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"check": "npm run typecheck && npm run test",
|
|
30
|
+
"smoke:env": "node scripts/smoke-env.mjs",
|
|
31
|
+
"smoke:loader": "node scripts/smoke-loader.mjs",
|
|
32
|
+
"smoke:real-world": "tsx scripts/smoke-real-world.mjs",
|
|
33
|
+
"eval": "tsx scripts/eval-retrieval.mts",
|
|
34
|
+
"prepublishOnly": "node -e \"if(!process.env.CI)throw new Error('publish via release.yml CI: push a v* tag. Manual npm publish is blocked to guarantee provenance + version sync.')\""
|
|
35
|
+
},
|
|
36
|
+
"pi": {
|
|
37
|
+
"extensions": [
|
|
38
|
+
"./src/extension.ts"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=22.0.0"
|
|
43
|
+
},
|
|
44
|
+
"allowScripts": {
|
|
45
|
+
"better-sqlite3": true
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"better-sqlite3": "^13.0.3",
|
|
49
|
+
"chokidar": "^5.0.0",
|
|
50
|
+
"sqlite-vec": "^0.1.9",
|
|
51
|
+
"tree-sitter-wasms": "^0.1.13",
|
|
52
|
+
"web-tree-sitter": "^0.22.6",
|
|
53
|
+
"yaml": "^2.9.1"
|
|
54
|
+
},
|
|
55
|
+
"optionalDependencies": {
|
|
56
|
+
"@huggingface/transformers": "^4.3.1"
|
|
57
|
+
},
|
|
58
|
+
"peerDependencies": {
|
|
59
|
+
"@earendil-works/pi-ai": "*",
|
|
60
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
61
|
+
"typebox": "*"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@earendil-works/pi-ai": ">=0.80.0",
|
|
65
|
+
"@earendil-works/pi-coding-agent": ">=0.99.2",
|
|
66
|
+
"@types/node": "^22.0.0",
|
|
67
|
+
"typebox": "^1.0.0",
|
|
68
|
+
"tsx": "^4.23.15",
|
|
69
|
+
"typescript": "^5.9.0",
|
|
70
|
+
"vitest": "^3.1.0"
|
|
71
|
+
},
|
|
72
|
+
"publishConfig": {
|
|
73
|
+
"access": "public",
|
|
74
|
+
"provenance": true
|
|
75
|
+
},
|
|
76
|
+
"author": "alessandro@pungitore.ch",
|
|
77
|
+
"repository": {
|
|
78
|
+
"type": "git",
|
|
79
|
+
"url": "git+https://github.com/pungggi/pi-context-engine.git"
|
|
80
|
+
},
|
|
81
|
+
"bugs": {
|
|
82
|
+
"url": "https://github.com/pungggi/pi-context-engine/issues"
|
|
83
|
+
},
|
|
84
|
+
"homepage": "https://github.com/pungggi/pi-context-engine#readme"
|
|
81
85
|
}
|
|
@@ -25,7 +25,16 @@ const PROMPT_MAP: Partial<Record<ChunkType, string>> = {
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
const TRUNCATION_LIMITS: Record<string, number> = { minimal: 100, standard: 300, full: 800 };
|
|
28
|
-
|
|
28
|
+
// Query-aware selection: keep matched lines within the level budget, never more.
|
|
29
|
+
const MAX_QUERY_LINES = 40;
|
|
30
|
+
/** Words that must not win the line budget just because they recur. */
|
|
31
|
+
const QUERY_NOISE_TERMS = new Set([
|
|
32
|
+
"the", "and", "for", "with", "that", "this", "from", "are", "was", "not",
|
|
33
|
+
"you", "all", "can", "has", "its", "but", "how", "what", "when", "where",
|
|
34
|
+
"which", "who", "why", "does", "did", "should", "would", "into", "than",
|
|
35
|
+
"then", "them", "they", "use", "used", "using", "show", "find", "call",
|
|
36
|
+
"calls", "make", "made", "need", "needs", "get", "set", "returns", "return",
|
|
37
|
+
]);
|
|
29
38
|
// TTL for the Ollama liveness probe so compress() calls don't all pay it.
|
|
30
39
|
const OLLAMA_PROBE_TTL_MS = 30_000;
|
|
31
40
|
|
|
@@ -153,35 +162,58 @@ export class Compressor {
|
|
|
153
162
|
return this.probeInFlight;
|
|
154
163
|
}
|
|
155
164
|
|
|
156
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Compress chunks for serving.
|
|
167
|
+
*
|
|
168
|
+
* `query` enables R3 query-aware selection: when a truncation would cut
|
|
169
|
+
* lines (minimal/standard without the LLM path), keep the lines that
|
|
170
|
+
* mention the query's terms within the same character budget instead of
|
|
171
|
+
* the first N lines. That stops the compressor from deleting the only
|
|
172
|
+
* line that answers the question, which fixed head-cuts did routinely.
|
|
173
|
+
*
|
|
174
|
+
* `queryAware=false` preserves the old head-truncation behaviour. `full`
|
|
175
|
+
* never truncates: the retrieval token budget decides (plan R3), so
|
|
176
|
+
* there is nothing for the query to protect at that level.
|
|
177
|
+
*/
|
|
178
|
+
async compress(chunks: Chunk[], level = "standard", query?: string, queryAware = true): Promise<Chunk[]> {
|
|
157
179
|
const ollamaAvailable = await this.isOllamaAvailable();
|
|
180
|
+
const queryText = (query ?? "").trim();
|
|
181
|
+
// Query selection only applies where truncation would otherwise cut.
|
|
182
|
+
// An LLM summary is query-independent (and therefore cacheable), so it
|
|
183
|
+
// keeps precedence when Ollama is up at standard/full.
|
|
184
|
+
const querySelection =
|
|
185
|
+
queryAware && queryText.length > 0 && level !== "full" && !(ollamaAvailable && level !== "minimal");
|
|
158
186
|
for (const chunk of chunks) {
|
|
159
|
-
if (level === "full"
|
|
187
|
+
if (level === "full") {
|
|
188
|
+
// Budget-driven: the engine's maxTokens packing trims, not us.
|
|
160
189
|
chunk.compressedContent = chunk.content;
|
|
161
190
|
continue;
|
|
162
191
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
192
|
+
if (!querySelection) {
|
|
193
|
+
const cached = this.cache?.getCachedCompression(chunk.id, level);
|
|
194
|
+
if (cached !== null && cached !== undefined) {
|
|
195
|
+
chunk.compressedContent = cached;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
167
198
|
}
|
|
168
|
-
|
|
169
|
-
|
|
199
|
+
let compressed: string;
|
|
200
|
+
if (querySelection) {
|
|
201
|
+
// Never read or write the cache here: its key is (chunk, level)
|
|
202
|
+
// and would leak a stale selection from another query.
|
|
203
|
+
compressed = this.queryAwareFallback(chunk, level, queryText);
|
|
204
|
+
} else if (ollamaAvailable && level !== "minimal") {
|
|
205
|
+
compressed = await this.llmCompress(chunk, level);
|
|
170
206
|
} else {
|
|
171
|
-
|
|
207
|
+
compressed = this.fallbackCompress(chunk, level);
|
|
172
208
|
}
|
|
173
|
-
|
|
174
|
-
|
|
209
|
+
chunk.compressedContent = compressed;
|
|
210
|
+
if (this.cache && compressed && !querySelection) {
|
|
211
|
+
this.cache.putCachedCompression(chunk.id, level, compressed);
|
|
175
212
|
}
|
|
176
213
|
}
|
|
177
214
|
return chunks;
|
|
178
215
|
}
|
|
179
216
|
|
|
180
|
-
private isFullPassthrough(chunk: Chunk): boolean {
|
|
181
|
-
if (chunk.confidenceScore > FULL_PASSTHROUGH_THRESHOLD) return true;
|
|
182
|
-
return chunk.embedding === null;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
217
|
private async llmCompress(chunk: Chunk, level: string): Promise<string> {
|
|
186
218
|
const prompt = PROMPT_MAP[chunk.chunkType] ?? CODE_PROMPT;
|
|
187
219
|
try {
|
|
@@ -195,11 +227,57 @@ export class Compressor {
|
|
|
195
227
|
|
|
196
228
|
private fallbackCompress(chunk: Chunk, level: string): string {
|
|
197
229
|
const limit = TRUNCATION_LIMITS[level] ?? 300;
|
|
230
|
+
// The R1 header is retrieval context, not serving context: the result
|
|
231
|
+
// formatter already prints `[path:start]`, so paying for it again inside
|
|
232
|
+
// a 100-char signature would waste most of the budget.
|
|
233
|
+
const content = stripContextHeader(chunk.content);
|
|
198
234
|
if (chunk.chunkType === "function" || chunk.chunkType === "class") {
|
|
199
|
-
return this.extractSignature(
|
|
235
|
+
return this.extractSignature(content, limit);
|
|
236
|
+
}
|
|
237
|
+
if (content.length <= limit) return content;
|
|
238
|
+
return content.slice(0, limit) + "...";
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* R3: keep the lines that answer the query instead of the first N lines.
|
|
243
|
+
*
|
|
244
|
+
* The level's character cap still bounds the output, so serving size never
|
|
245
|
+
* grows: matched lines simply win the budget over leading boilerplate, then
|
|
246
|
+
* the selection is restored to source order for readability. When nothing
|
|
247
|
+
* matches (a vague query), plain truncation is returned — a weak query must
|
|
248
|
+
* not blank the result.
|
|
249
|
+
*/
|
|
250
|
+
private queryAwareFallback(chunk: Chunk, level: string, query: string): string {
|
|
251
|
+
const limit = TRUNCATION_LIMITS[level] ?? 300;
|
|
252
|
+
const terms = queryTerms(query);
|
|
253
|
+
const body = stripContextHeader(chunk.content);
|
|
254
|
+
if (terms.length === 0) return this.fallbackCompress(chunk, level);
|
|
255
|
+
|
|
256
|
+
const lines = body.split("\n");
|
|
257
|
+
const matches: { line: string; idx: number; hits: number }[] = [];
|
|
258
|
+
for (let i = 0; i < lines.length; i++) {
|
|
259
|
+
const line = lines[i]!;
|
|
260
|
+
if (line.trim().length === 0) continue;
|
|
261
|
+
const lower = line.toLowerCase();
|
|
262
|
+
let hits = 0;
|
|
263
|
+
for (const t of terms) if (lower.includes(t)) hits++;
|
|
264
|
+
if (hits > 0) matches.push({ line, idx: i, hits });
|
|
265
|
+
}
|
|
266
|
+
if (matches.length === 0) return this.fallbackCompress(chunk, level);
|
|
267
|
+
|
|
268
|
+
matches.sort((a, b) => b.hits - a.hits || a.idx - b.idx);
|
|
269
|
+
let budget = limit;
|
|
270
|
+
const selected: typeof matches = [];
|
|
271
|
+
let used = 0;
|
|
272
|
+
for (const m of matches) {
|
|
273
|
+
if (used + m.line.length + 1 > budget) continue;
|
|
274
|
+
selected.push(m);
|
|
275
|
+
used += m.line.length + 1;
|
|
276
|
+
if (selected.length >= MAX_QUERY_LINES) break;
|
|
200
277
|
}
|
|
201
|
-
if (
|
|
202
|
-
|
|
278
|
+
if (selected.length === 0) return this.fallbackCompress(chunk, level);
|
|
279
|
+
selected.sort((a, b) => a.idx - b.idx);
|
|
280
|
+
return selected.map((m) => m.line).join("\n");
|
|
203
281
|
}
|
|
204
282
|
|
|
205
283
|
private extractSignature(content: string, limit: number): string {
|
|
@@ -220,3 +298,24 @@ export class Compressor {
|
|
|
220
298
|
return resultLines.join("\n");
|
|
221
299
|
}
|
|
222
300
|
}
|
|
301
|
+
|
|
302
|
+
/** Drop the R1 `// file: …` header line (serving shows `[path:start]` already). */
|
|
303
|
+
function stripContextHeader(content: string): string {
|
|
304
|
+
if (!content.startsWith("// file: ")) return content;
|
|
305
|
+
const nl = content.indexOf("\n");
|
|
306
|
+
return nl < 0 ? content : content.slice(nl + 1);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Distinct query terms (>=3 chars, non-boilerplate) for line matching. */
|
|
310
|
+
function queryTerms(query: string): string[] {
|
|
311
|
+
const tokens = query.toLowerCase().match(/[a-z0-9_]+/g) ?? [];
|
|
312
|
+
const seen = new Set<string>();
|
|
313
|
+
const out: string[] = [];
|
|
314
|
+
for (const t of tokens) {
|
|
315
|
+
if (t.length < 3 || QUERY_NOISE_TERMS.has(t) || seen.has(t)) continue;
|
|
316
|
+
seen.add(t);
|
|
317
|
+
out.push(t);
|
|
318
|
+
if (out.length >= 40) break;
|
|
319
|
+
}
|
|
320
|
+
return out;
|
|
321
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -19,7 +19,7 @@ export const DEFAULT_IGNORE: string[] = [
|
|
|
19
19
|
// Dependencies (JS, PHP, Python, Ruby, Go, Rust, Java, .NET)
|
|
20
20
|
"node_modules", "vendor", "bower_components",
|
|
21
21
|
".pnpm-store", ".pnpm", ".yarn",
|
|
22
|
-
".venv", "venv", "
|
|
22
|
+
".venv", "venv", ".env",
|
|
23
23
|
".tox", ".nox", ".mypy_cache", ".pytest_cache",
|
|
24
24
|
".ruff_cache", ".cache",
|
|
25
25
|
"Pods",
|
|
@@ -41,13 +41,23 @@ export const DEFAULT_IGNORE: string[] = [
|
|
|
41
41
|
// Package locks (huge, not useful)
|
|
42
42
|
"package-lock.json", "yarn.lock", "pnpm-lock.yaml",
|
|
43
43
|
"composer.lock", "poetry.lock",
|
|
44
|
-
// Storage / logs
|
|
45
|
-
"storage", "logs", "tmp", "temp",
|
|
46
44
|
];
|
|
47
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Directory names that are ambiguous: equally plausible as junk at the project
|
|
48
|
+
* root (`./storage`, `./logs`, `./tmp`) as they are as real source trees
|
|
49
|
+
* nested below it (`src/storage/`, `app/logs/`). Matching them at any depth
|
|
50
|
+
* silently hid whole source trees from the index — including this package's
|
|
51
|
+
* own `src/storage/*.ts`. They are therefore ignored ONLY at the project root;
|
|
52
|
+
* nested dirs with these names are indexed.
|
|
53
|
+
*/
|
|
54
|
+
export const ROOT_ONLY_IGNORE: string[] = ["storage", "logs", "tmp", "temp", "env"];
|
|
55
|
+
|
|
48
56
|
export interface Config {
|
|
49
57
|
compressionLevel: "minimal" | "standard" | "full";
|
|
50
58
|
compressionModel: string;
|
|
59
|
+
/** R3: keep query-matching lines when truncating instead of the head. */
|
|
60
|
+
compressionQueryAware: boolean;
|
|
51
61
|
ollamaUrl: string;
|
|
52
62
|
embeddingModel: string;
|
|
53
63
|
ollamaEmbedModel: string;
|
|
@@ -60,7 +70,29 @@ export interface Config {
|
|
|
60
70
|
retrievalConfidenceThreshold: number;
|
|
61
71
|
retrievalTopK: number;
|
|
62
72
|
retrievalMarginalRatio: number;
|
|
73
|
+
/** R6: attach a hit's module parent + adjacent chunk (small-to-big serving). */
|
|
74
|
+
retrievalExpandContext: boolean;
|
|
75
|
+
/** R8: composite quality score at/above which a query reports `high`. */
|
|
76
|
+
retrievalConfidenceHigh: number;
|
|
77
|
+
/** R8: composite quality score below which a query reports `low` + hints. */
|
|
78
|
+
retrievalConfidenceLow: number;
|
|
79
|
+
/** R8: deterministic query elaboration fused as an extra candidate source. */
|
|
80
|
+
retrievalAutoElaborate: boolean;
|
|
81
|
+
/** R9: append a `[refine: ...]` hint line to search results. */
|
|
82
|
+
retrievalRefineHints: boolean;
|
|
83
|
+
/** R10: opt-in reranking of the fused list. `off` (default) | `local`. */
|
|
84
|
+
retrievalRerank: "off" | "local";
|
|
85
|
+
/** R10: HF model id for the local cross-encoder reranker. */
|
|
86
|
+
retrievalRerankModel: string;
|
|
87
|
+
/** R10: how many fused candidates the reranker may reorder. */
|
|
88
|
+
retrievalRerankTopn: number;
|
|
89
|
+
/** R12: chunking strategy — `legacy` function/class walk (default) or `ast-density` split-merge. */
|
|
90
|
+
indexerChunking: "legacy" | "ast-density";
|
|
91
|
+
/** R12: non-whitespace char budget per ast-density chunk. */
|
|
92
|
+
indexerChunkBudgetChars: number;
|
|
63
93
|
indexerIgnore: string[];
|
|
94
|
+
/** Prepend the R1 context header (path/lang/unit/imports) to chunk content. */
|
|
95
|
+
indexerContextHeaders: boolean;
|
|
64
96
|
indexerRedactSecrets: boolean;
|
|
65
97
|
memoryRedactPii: boolean;
|
|
66
98
|
pricingModel: string;
|
|
@@ -73,6 +105,7 @@ export function defaultConfig(): Config {
|
|
|
73
105
|
return {
|
|
74
106
|
compressionLevel: "standard",
|
|
75
107
|
compressionModel: "phi3:mini",
|
|
108
|
+
compressionQueryAware: true,
|
|
76
109
|
ollamaUrl: "http://localhost:11434",
|
|
77
110
|
embeddingModel: "local",
|
|
78
111
|
ollamaEmbedModel: "nomic-embed-text",
|
|
@@ -80,7 +113,18 @@ export function defaultConfig(): Config {
|
|
|
80
113
|
retrievalConfidenceThreshold: 0.2,
|
|
81
114
|
retrievalTopK: 20,
|
|
82
115
|
retrievalMarginalRatio: 0.75,
|
|
116
|
+
retrievalExpandContext: true,
|
|
117
|
+
retrievalConfidenceHigh: 0.55,
|
|
118
|
+
retrievalConfidenceLow: 0.45,
|
|
119
|
+
retrievalAutoElaborate: false,
|
|
120
|
+
retrievalRefineHints: true,
|
|
121
|
+
retrievalRerank: "off",
|
|
122
|
+
retrievalRerankModel: "Xenova/ms-marco-MiniLM-L-6-v2",
|
|
123
|
+
retrievalRerankTopn: 30,
|
|
124
|
+
indexerChunking: "legacy",
|
|
125
|
+
indexerChunkBudgetChars: 1200,
|
|
83
126
|
indexerIgnore: [...DEFAULT_IGNORE],
|
|
127
|
+
indexerContextHeaders: true,
|
|
84
128
|
indexerRedactSecrets: true,
|
|
85
129
|
memoryRedactPii: true,
|
|
86
130
|
pricingModel: "opus",
|
|
@@ -94,6 +138,7 @@ export function defaultConfig(): Config {
|
|
|
94
138
|
const MAPPING: Record<string, keyof Config> = {
|
|
95
139
|
"compression.level": "compressionLevel",
|
|
96
140
|
"compression.model": "compressionModel",
|
|
141
|
+
"compression.query_aware": "compressionQueryAware",
|
|
97
142
|
"compression.ollama_url": "ollamaUrl",
|
|
98
143
|
"guidance.enabled": "guidanceEnabled",
|
|
99
144
|
"embedding.model": "embeddingModel",
|
|
@@ -101,7 +146,18 @@ const MAPPING: Record<string, keyof Config> = {
|
|
|
101
146
|
"retrieval.confidence_threshold": "retrievalConfidenceThreshold",
|
|
102
147
|
"retrieval.top_k": "retrievalTopK",
|
|
103
148
|
"retrieval.marginal_ratio": "retrievalMarginalRatio",
|
|
149
|
+
"retrieval.expand_context": "retrievalExpandContext",
|
|
150
|
+
"retrieval.confidence_high": "retrievalConfidenceHigh",
|
|
151
|
+
"retrieval.confidence_low": "retrievalConfidenceLow",
|
|
152
|
+
"retrieval.auto_elaborate": "retrievalAutoElaborate",
|
|
153
|
+
"retrieval.refine_hints": "retrievalRefineHints",
|
|
154
|
+
"retrieval.rerank": "retrievalRerank",
|
|
155
|
+
"retrieval.rerank_model": "retrievalRerankModel",
|
|
156
|
+
"retrieval.rerank_topn": "retrievalRerankTopn",
|
|
157
|
+
"indexer.chunking": "indexerChunking",
|
|
158
|
+
"indexer.chunk_budget_chars": "indexerChunkBudgetChars",
|
|
104
159
|
"indexer.ignore": "indexerIgnore",
|
|
160
|
+
"indexer.context_headers": "indexerContextHeaders",
|
|
105
161
|
"indexer.redact_secrets": "indexerRedactSecrets",
|
|
106
162
|
"memory.redact_pii": "memoryRedactPii",
|
|
107
163
|
"storage.path": "storagePath",
|