@cortexkit/pi-magic-context 0.47.0 → 0.49.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/dist/auto-search-worker.js +27 -22
- package/dist/embedding-activity-ew6dshfd.js +10 -0
- package/dist/embedding-backfill-b71dvfs8.js +20 -0
- package/dist/embedding-cache-7rp4gqzr.js +16 -0
- package/dist/embedding-worker.js +11 -8
- package/dist/harness-9872e0ym.js +10 -0
- package/dist/historian-calibration-extension.js +30 -4
- package/dist/index-041ex0cj.js +519 -0
- package/dist/index-0h2mkab2.js +17 -0
- package/dist/{index-2p1e8706.js → index-0vrkp1jq.js} +3 -3
- package/dist/index-135e8hvg.js +43 -0
- package/dist/{index-vgcemg0n.js → index-1evzceyw.js} +151 -2452
- package/dist/index-21v1kfs7.js +2309 -0
- package/dist/{index-n3g5mwa8.js → index-290tzwp1.js} +3 -3
- package/dist/{index-0qejsd7f.js → index-3cgbv47m.js} +289 -45
- package/dist/{index-xpbh1ypk.js → index-3mgf68pn.js} +38 -741
- package/dist/index-3rea6zd9.js +2396 -0
- package/dist/index-674f6qs2.js +16 -0
- package/dist/index-8976mezv.js +209 -0
- package/dist/index-904reqtg.js +152 -0
- package/dist/index-9p40dgkm.js +22 -0
- package/dist/index-9x1f96r8.js +11 -0
- package/dist/index-bejpsj10.js +1060 -0
- package/dist/{index-spk5vrhy.js → index-bgmv2kaf.js} +1 -16
- package/dist/{index-k3ezsjng.js → index-ehybv5nr.js} +14657 -13951
- package/dist/index-fapenpch.js +13 -0
- package/dist/index-hwqb3s7f.js +3804 -0
- package/dist/index-kjd1fj55.js +3106 -0
- package/dist/{index-td885aah.js → index-mcgehvgw.js} +181 -230
- package/dist/index-r024r8da.js +171 -0
- package/dist/{index-266qrgss.js → index-r56xgha8.js} +301 -27
- package/dist/{index-kztsbkqq.js → index-t7xfqtg6.js} +171 -168
- package/dist/index-vakawmbc.js +1262 -0
- package/dist/{index-7n8gb6j3.js → index-x3dcnxh0.js} +34 -33
- package/dist/index-xjqheg7a.js +931 -0
- package/dist/index-yarjn32j.js +3026 -0
- package/dist/index-yhzhdp3m.js +143 -0
- package/dist/index-yzcjxnt2.js +787 -0
- package/dist/{index-w76x3af7.js → index-zh1jw8qp.js} +107 -4
- package/dist/index.js +4926 -2437
- package/dist/logger-j6tecd1h.js +19 -0
- package/dist/message-index-bounded-qz5dz2se.js +120 -0
- package/dist/{message-time-backfill-d3db2etr.js → message-time-backfill-05ppypkz.js} +7 -6
- package/dist/migration-worker.js +20 -14
- package/dist/project-embedding-registry-ky7wrkr1.js +85 -0
- package/dist/raw-ordinal-warmup-worker.js +60 -0
- package/dist/{read-session-chunk-atxsyfqv.js → read-session-chunk-24sd89tf.js} +14 -6
- package/dist/read-session-raw-npx3920c.js +57 -0
- package/dist/{safe-notification-target-6cn3z99t.js → safe-notification-target-vn9kpmv4.js} +3 -2
- package/dist/search-jbh28nwy.js +40 -0
- package/dist/sqlite-3yye76ht.js +44 -0
- package/dist/sqlite-context-pragmas-gcgch6qz.js +6 -0
- package/dist/storage-memory-1z20y55x.js +71 -0
- package/dist/storage-tags-kjnsqbdb.js +127 -0
- package/dist/subagent-entry.js +35 -17
- package/dist/transformers-node-wasm.js +18415 -18415
- package/package.json +3 -3
- package/dist/index-7s8vw2y0.js +0 -5207
- package/dist/index-qaa5j277.js +0 -8544
- /package/dist/{index-en1k8h8m.js → index-5prbx026.js} +0 -0
|
@@ -0,0 +1,1060 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getTokenEstimatorFingerprint,
|
|
3
|
+
estimateTokens
|
|
4
|
+
} from "./index-r56xgha8.js";
|
|
5
|
+
import {
|
|
6
|
+
getHarness2
|
|
7
|
+
} from "./index-0h2mkab2.js";
|
|
8
|
+
import {
|
|
9
|
+
log2
|
|
10
|
+
} from "./index-x3dcnxh0.js";
|
|
11
|
+
import {
|
|
12
|
+
isSynapseEmbeddingTruncated
|
|
13
|
+
} from "./index-21v1kfs7.js";
|
|
14
|
+
import {
|
|
15
|
+
messageFtsOrdinalRangeIsMapped
|
|
16
|
+
} from "./index-r024r8da.js";
|
|
17
|
+
|
|
18
|
+
// ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
|
|
19
|
+
import { createHash } from "node:crypto";
|
|
20
|
+
|
|
21
|
+
// ../plugin/src/features/magic-context/recursive-text-splitter.ts
|
|
22
|
+
var DEFAULT_SEPARATORS = [`
|
|
23
|
+
|
|
24
|
+
`, `
|
|
25
|
+
`, " ", ""];
|
|
26
|
+
function splitOnSeparator(text, separator) {
|
|
27
|
+
const splits = separator ? text.split(separator) : text.split("");
|
|
28
|
+
return splits.filter((s) => s !== "");
|
|
29
|
+
}
|
|
30
|
+
function mergeSplits(splits, separator, chunkSize, lengthFunction) {
|
|
31
|
+
const docs = [];
|
|
32
|
+
const currentDoc = [];
|
|
33
|
+
let total = 0;
|
|
34
|
+
const joinDocs = (docsToJoin) => {
|
|
35
|
+
const joined = docsToJoin.join(separator).trim();
|
|
36
|
+
return joined === "" ? null : joined;
|
|
37
|
+
};
|
|
38
|
+
for (const d of splits) {
|
|
39
|
+
const len = lengthFunction(d);
|
|
40
|
+
if (total + len + currentDoc.length * separator.length > chunkSize) {
|
|
41
|
+
if (currentDoc.length > 0) {
|
|
42
|
+
const doc = joinDocs(currentDoc);
|
|
43
|
+
if (doc !== null)
|
|
44
|
+
docs.push(doc);
|
|
45
|
+
while (total > 0 && currentDoc.length > 0) {
|
|
46
|
+
total -= lengthFunction(currentDoc[0]);
|
|
47
|
+
currentDoc.shift();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
currentDoc.push(d);
|
|
52
|
+
total += len;
|
|
53
|
+
}
|
|
54
|
+
const doc = joinDocs(currentDoc);
|
|
55
|
+
if (doc !== null)
|
|
56
|
+
docs.push(doc);
|
|
57
|
+
return docs;
|
|
58
|
+
}
|
|
59
|
+
function splitTextRecursive(text, separators, chunkSize, lengthFunction) {
|
|
60
|
+
const finalChunks = [];
|
|
61
|
+
let separator = separators[separators.length - 1];
|
|
62
|
+
let newSeparators;
|
|
63
|
+
for (let i = 0;i < separators.length; i += 1) {
|
|
64
|
+
const s = separators[i];
|
|
65
|
+
if (s === "") {
|
|
66
|
+
separator = s;
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
if (text.includes(s)) {
|
|
70
|
+
separator = s;
|
|
71
|
+
newSeparators = separators.slice(i + 1);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const splits = splitOnSeparator(text, separator);
|
|
76
|
+
let goodSplits = [];
|
|
77
|
+
for (const s of splits) {
|
|
78
|
+
if (lengthFunction(s) < chunkSize) {
|
|
79
|
+
goodSplits.push(s);
|
|
80
|
+
} else {
|
|
81
|
+
if (goodSplits.length) {
|
|
82
|
+
finalChunks.push(...mergeSplits(goodSplits, separator, chunkSize, lengthFunction));
|
|
83
|
+
goodSplits = [];
|
|
84
|
+
}
|
|
85
|
+
if (!newSeparators) {
|
|
86
|
+
finalChunks.push(s);
|
|
87
|
+
} else {
|
|
88
|
+
finalChunks.push(...splitTextRecursive(s, newSeparators, chunkSize, lengthFunction));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (goodSplits.length) {
|
|
93
|
+
finalChunks.push(...mergeSplits(goodSplits, separator, chunkSize, lengthFunction));
|
|
94
|
+
}
|
|
95
|
+
return finalChunks;
|
|
96
|
+
}
|
|
97
|
+
function recursiveCharacterSplit(text, options) {
|
|
98
|
+
const chunkSize = options.chunkSize;
|
|
99
|
+
const lengthFunction = options.lengthFunction ?? ((t) => t.length);
|
|
100
|
+
const separators = options.separators ?? DEFAULT_SEPARATORS;
|
|
101
|
+
if (text.length === 0)
|
|
102
|
+
return [];
|
|
103
|
+
return splitTextRecursive(text, separators, chunkSize, lengthFunction);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
|
|
107
|
+
var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512;
|
|
108
|
+
var CHUNK_WINDOW_SAFETY_RATIO = 0.9;
|
|
109
|
+
var MESSAGE_FTS_CHUNK_LOAD_SQL = `SELECT map.message_ordinal AS messageOrdinal, fts.role, fts.content
|
|
110
|
+
FROM message_fts_rowid_map AS map
|
|
111
|
+
CROSS JOIN message_history_fts AS fts
|
|
112
|
+
ON fts.rowid = map.fts_rowid
|
|
113
|
+
WHERE map.session_id = ?
|
|
114
|
+
AND map.message_ordinal BETWEEN ? AND ?
|
|
115
|
+
AND fts.role IN ('user', 'assistant')
|
|
116
|
+
ORDER BY map.message_ordinal ASC`;
|
|
117
|
+
var loadFtsRowsStatements = new WeakMap;
|
|
118
|
+
var searchPoolCompartmentStatements = new WeakMap;
|
|
119
|
+
var existingHashStatements = new WeakMap;
|
|
120
|
+
var existingHashByProjectStatements = new WeakMap;
|
|
121
|
+
var deleteByCompartmentStatements = new WeakMap;
|
|
122
|
+
var insertEmbeddingStatements = new WeakMap;
|
|
123
|
+
var renumberEmbeddingWindowStatements = new WeakMap;
|
|
124
|
+
var searchRowsStatements = new WeakMap;
|
|
125
|
+
var searchRowsByModelStatements = new WeakMap;
|
|
126
|
+
var datedSearchRowsByModelStatements = new WeakMap;
|
|
127
|
+
var searchPoolProbeStatements = new WeakMap;
|
|
128
|
+
var backfillCandidateStatements = new WeakMap;
|
|
129
|
+
var shadowBackfillCandidateStatements = new WeakMap;
|
|
130
|
+
var DECODED_SEARCH_POOL_CACHE_MAX_BYTES = 256 * 1024 * 1024;
|
|
131
|
+
var decodedSearchPools = new WeakMap;
|
|
132
|
+
var decodedSearchPoolLru = new Map;
|
|
133
|
+
var decodedSearchPoolBytes = 0;
|
|
134
|
+
function getLoadFtsRowsStatement(db) {
|
|
135
|
+
let stmt = loadFtsRowsStatements.get(db);
|
|
136
|
+
if (!stmt) {
|
|
137
|
+
stmt = db.prepare(MESSAGE_FTS_CHUNK_LOAD_SQL);
|
|
138
|
+
loadFtsRowsStatements.set(db, stmt);
|
|
139
|
+
}
|
|
140
|
+
return stmt;
|
|
141
|
+
}
|
|
142
|
+
function getExistingHashStatement(db, scopedToProject) {
|
|
143
|
+
const map = scopedToProject ? existingHashByProjectStatements : existingHashStatements;
|
|
144
|
+
let stmt = map.get(db);
|
|
145
|
+
if (!stmt) {
|
|
146
|
+
stmt = db.prepare(`SELECT window_index AS windowIndex, chunk_hash AS chunkHash
|
|
147
|
+
FROM compartment_chunk_embeddings
|
|
148
|
+
WHERE compartment_id = ?
|
|
149
|
+
AND model_id = ?
|
|
150
|
+
${scopedToProject ? "AND project_path = ?" : ""}
|
|
151
|
+
ORDER BY window_index ASC`);
|
|
152
|
+
map.set(db, stmt);
|
|
153
|
+
}
|
|
154
|
+
return stmt;
|
|
155
|
+
}
|
|
156
|
+
function getDeleteByCompartmentStatement(db) {
|
|
157
|
+
let stmt = deleteByCompartmentStatements.get(db);
|
|
158
|
+
if (!stmt) {
|
|
159
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE compartment_id = ? AND model_id = ?");
|
|
160
|
+
deleteByCompartmentStatements.set(db, stmt);
|
|
161
|
+
}
|
|
162
|
+
return stmt;
|
|
163
|
+
}
|
|
164
|
+
function getInsertEmbeddingStatement(db) {
|
|
165
|
+
let stmt = insertEmbeddingStatements.get(db);
|
|
166
|
+
if (!stmt) {
|
|
167
|
+
stmt = db.prepare(`INSERT INTO compartment_chunk_embeddings (
|
|
168
|
+
compartment_id, session_id, project_path, harness, window_index,
|
|
169
|
+
start_ordinal, end_ordinal, chunk_hash, model_id, dims, vector, created_at
|
|
170
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
171
|
+
insertEmbeddingStatements.set(db, stmt);
|
|
172
|
+
}
|
|
173
|
+
return stmt;
|
|
174
|
+
}
|
|
175
|
+
function getRenumberEmbeddingWindowStatement(db) {
|
|
176
|
+
let stmt = renumberEmbeddingWindowStatements.get(db);
|
|
177
|
+
if (!stmt) {
|
|
178
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
179
|
+
SET window_index = ?
|
|
180
|
+
WHERE compartment_id = ?
|
|
181
|
+
AND model_id = ?
|
|
182
|
+
AND project_path = ?
|
|
183
|
+
AND window_index = ?`);
|
|
184
|
+
renumberEmbeddingWindowStatements.set(db, stmt);
|
|
185
|
+
}
|
|
186
|
+
return stmt;
|
|
187
|
+
}
|
|
188
|
+
function getSearchPoolProbeStatement(db) {
|
|
189
|
+
let stmt = searchPoolProbeStatements.get(db);
|
|
190
|
+
if (!stmt) {
|
|
191
|
+
stmt = db.prepare(`SELECT COUNT(*) AS rowCount, MAX(id) AS maxRowId
|
|
192
|
+
FROM compartment_chunk_embeddings
|
|
193
|
+
WHERE session_id = ? AND project_path = ? AND model_id = ?`);
|
|
194
|
+
searchPoolProbeStatements.set(db, stmt);
|
|
195
|
+
}
|
|
196
|
+
return stmt;
|
|
197
|
+
}
|
|
198
|
+
function getSearchPoolCompartmentStatement(db) {
|
|
199
|
+
let stmt = searchPoolCompartmentStatements.get(db);
|
|
200
|
+
if (!stmt) {
|
|
201
|
+
stmt = db.prepare(`SELECT id, title, start_message AS startOrdinal, end_message AS endOrdinal
|
|
202
|
+
FROM compartments
|
|
203
|
+
WHERE id IN (
|
|
204
|
+
SELECT compartment_id FROM compartment_chunk_embeddings
|
|
205
|
+
WHERE session_id = ? AND project_path = ? AND model_id = ?
|
|
206
|
+
)`);
|
|
207
|
+
searchPoolCompartmentStatements.set(db, stmt);
|
|
208
|
+
}
|
|
209
|
+
return stmt;
|
|
210
|
+
}
|
|
211
|
+
function refreshPoolCompartmentFields(db, sessionId, projectPath, modelId, rows) {
|
|
212
|
+
const current = new Map;
|
|
213
|
+
for (const row of getSearchPoolCompartmentStatement(db).all(sessionId, projectPath, modelId)) {
|
|
214
|
+
current.set(row.id, row);
|
|
215
|
+
}
|
|
216
|
+
let missing = false;
|
|
217
|
+
for (const row of rows) {
|
|
218
|
+
const compartment = current.get(row.compartmentId);
|
|
219
|
+
if (!compartment) {
|
|
220
|
+
missing = true;
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
row.title = compartment.title;
|
|
224
|
+
row.startOrdinal = compartment.startOrdinal;
|
|
225
|
+
row.endOrdinal = compartment.endOrdinal;
|
|
226
|
+
}
|
|
227
|
+
return missing ? rows.filter((row) => current.has(row.compartmentId)) : rows;
|
|
228
|
+
}
|
|
229
|
+
function getSearchRowsStatement(db, withModel) {
|
|
230
|
+
const map = withModel ? searchRowsByModelStatements : searchRowsStatements;
|
|
231
|
+
let stmt = map.get(db);
|
|
232
|
+
if (!stmt) {
|
|
233
|
+
stmt = db.prepare(`SELECT e.compartment_id AS compartmentId,
|
|
234
|
+
e.session_id AS sessionId,
|
|
235
|
+
c.title AS title,
|
|
236
|
+
c.start_message AS compartmentStart,
|
|
237
|
+
c.end_message AS compartmentEnd,
|
|
238
|
+
e.window_index AS windowIndex,
|
|
239
|
+
e.start_ordinal AS windowStart,
|
|
240
|
+
e.end_ordinal AS windowEnd,
|
|
241
|
+
e.chunk_hash AS chunkHash,
|
|
242
|
+
e.model_id AS modelId,
|
|
243
|
+
e.dims AS dims,
|
|
244
|
+
e.vector AS vector
|
|
245
|
+
FROM compartment_chunk_embeddings e
|
|
246
|
+
JOIN compartments c ON c.id = e.compartment_id
|
|
247
|
+
WHERE e.session_id = ?
|
|
248
|
+
AND e.project_path = ?
|
|
249
|
+
${withModel ? "AND e.model_id = ?" : ""}
|
|
250
|
+
ORDER BY e.compartment_id ASC, e.window_index ASC`);
|
|
251
|
+
map.set(db, stmt);
|
|
252
|
+
}
|
|
253
|
+
return stmt;
|
|
254
|
+
}
|
|
255
|
+
function getDatedSearchRowsByModelStatement(db) {
|
|
256
|
+
let statement = datedSearchRowsByModelStatements.get(db);
|
|
257
|
+
if (!statement) {
|
|
258
|
+
statement = db.prepare(`SELECT e.compartment_id AS compartmentId,
|
|
259
|
+
e.session_id AS sessionId,
|
|
260
|
+
c.title AS title,
|
|
261
|
+
c.start_message AS compartmentStart,
|
|
262
|
+
c.end_message AS compartmentEnd,
|
|
263
|
+
e.window_index AS windowIndex,
|
|
264
|
+
e.start_ordinal AS windowStart,
|
|
265
|
+
e.end_ordinal AS windowEnd,
|
|
266
|
+
e.chunk_hash AS chunkHash,
|
|
267
|
+
e.model_id AS modelId,
|
|
268
|
+
e.dims AS dims,
|
|
269
|
+
e.vector AS vector
|
|
270
|
+
FROM compartment_chunk_embeddings e
|
|
271
|
+
JOIN compartments c ON c.id = e.compartment_id
|
|
272
|
+
JOIN message_fts_rowid_map AS start_map
|
|
273
|
+
ON start_map.session_id = c.session_id
|
|
274
|
+
AND start_map.message_ordinal = c.start_message
|
|
275
|
+
JOIN message_fts_rowid_map AS end_map
|
|
276
|
+
ON end_map.session_id = c.session_id
|
|
277
|
+
AND end_map.message_ordinal = c.end_message
|
|
278
|
+
WHERE e.session_id = ?
|
|
279
|
+
AND e.project_path = ?
|
|
280
|
+
AND e.model_id = ?
|
|
281
|
+
AND start_map.message_time_ms <= ?
|
|
282
|
+
AND end_map.message_time_ms >= ?
|
|
283
|
+
ORDER BY e.compartment_id ASC, e.window_index ASC`);
|
|
284
|
+
datedSearchRowsByModelStatements.set(db, statement);
|
|
285
|
+
}
|
|
286
|
+
return statement;
|
|
287
|
+
}
|
|
288
|
+
function getBackfillCandidateStatement(db) {
|
|
289
|
+
let stmt = backfillCandidateStatements.get(db);
|
|
290
|
+
if (!stmt) {
|
|
291
|
+
stmt = db.prepare(`SELECT c.id AS id,
|
|
292
|
+
c.session_id AS sessionId,
|
|
293
|
+
c.start_message AS startMessage,
|
|
294
|
+
c.end_message AS endMessage,
|
|
295
|
+
c.title AS title
|
|
296
|
+
FROM compartments c
|
|
297
|
+
JOIN session_projects sp
|
|
298
|
+
ON sp.session_id = c.session_id
|
|
299
|
+
AND sp.harness = c.harness
|
|
300
|
+
AND sp.project_path = ?
|
|
301
|
+
WHERE c.start_message IS NOT NULL
|
|
302
|
+
AND c.end_message IS NOT NULL
|
|
303
|
+
ORDER BY c.created_at DESC, c.id DESC`);
|
|
304
|
+
backfillCandidateStatements.set(db, stmt);
|
|
305
|
+
}
|
|
306
|
+
return stmt;
|
|
307
|
+
}
|
|
308
|
+
function getShadowBackfillCandidateStatement(db) {
|
|
309
|
+
let stmt = shadowBackfillCandidateStatements.get(db);
|
|
310
|
+
if (!stmt) {
|
|
311
|
+
stmt = db.prepare(`SELECT c.id AS id,
|
|
312
|
+
c.session_id AS sessionId,
|
|
313
|
+
c.start_message AS startMessage,
|
|
314
|
+
c.end_message AS endMessage,
|
|
315
|
+
c.title AS title
|
|
316
|
+
FROM compartments c
|
|
317
|
+
JOIN session_projects sp
|
|
318
|
+
ON sp.session_id = c.session_id
|
|
319
|
+
AND sp.harness = c.harness
|
|
320
|
+
AND sp.project_path = ?
|
|
321
|
+
WHERE c.start_message IS NOT NULL
|
|
322
|
+
AND c.end_message IS NOT NULL
|
|
323
|
+
AND EXISTS (
|
|
324
|
+
SELECT 1
|
|
325
|
+
FROM compartment_chunk_embeddings primary_chunks
|
|
326
|
+
WHERE primary_chunks.compartment_id = c.id
|
|
327
|
+
AND primary_chunks.project_path = ?
|
|
328
|
+
AND primary_chunks.model_id = ?
|
|
329
|
+
)
|
|
330
|
+
ORDER BY c.created_at DESC, c.id DESC`);
|
|
331
|
+
shadowBackfillCandidateStatements.set(db, stmt);
|
|
332
|
+
}
|
|
333
|
+
return stmt;
|
|
334
|
+
}
|
|
335
|
+
function searchPoolKey(sessionId, projectPath, modelId) {
|
|
336
|
+
return JSON.stringify([sessionId, projectPath, modelId]);
|
|
337
|
+
}
|
|
338
|
+
function getDecodedSearchPool(db) {
|
|
339
|
+
let pool = decodedSearchPools.get(db);
|
|
340
|
+
if (!pool) {
|
|
341
|
+
pool = new Map;
|
|
342
|
+
decodedSearchPools.set(db, pool);
|
|
343
|
+
}
|
|
344
|
+
return pool;
|
|
345
|
+
}
|
|
346
|
+
function removeDecodedSearchPoolEntry(entry) {
|
|
347
|
+
if (entry.pool.get(entry.key) === entry) {
|
|
348
|
+
entry.pool.delete(entry.key);
|
|
349
|
+
}
|
|
350
|
+
if (decodedSearchPoolLru.delete(entry)) {
|
|
351
|
+
decodedSearchPoolBytes -= entry.byteSize;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function touchDecodedSearchPoolEntry(entry) {
|
|
355
|
+
decodedSearchPoolLru.delete(entry);
|
|
356
|
+
decodedSearchPoolLru.set(entry, true);
|
|
357
|
+
}
|
|
358
|
+
function estimateDecodedSearchPoolBytes(rows) {
|
|
359
|
+
let bytes = 0;
|
|
360
|
+
for (const row of rows) {
|
|
361
|
+
bytes += row.vector.byteLength + 256 + 2 * (row.sessionId.length + row.title.length + row.chunkHash.length + row.modelId.length);
|
|
362
|
+
}
|
|
363
|
+
return bytes;
|
|
364
|
+
}
|
|
365
|
+
function cacheDecodedSearchPool(pool, key, rowCount, maxRowId, rows) {
|
|
366
|
+
const existing = pool.get(key);
|
|
367
|
+
if (existing)
|
|
368
|
+
removeDecodedSearchPoolEntry(existing);
|
|
369
|
+
const entry = {
|
|
370
|
+
pool,
|
|
371
|
+
key,
|
|
372
|
+
rowCount,
|
|
373
|
+
maxRowId,
|
|
374
|
+
rows,
|
|
375
|
+
byteSize: estimateDecodedSearchPoolBytes(rows)
|
|
376
|
+
};
|
|
377
|
+
pool.set(key, entry);
|
|
378
|
+
decodedSearchPoolLru.set(entry, true);
|
|
379
|
+
decodedSearchPoolBytes += entry.byteSize;
|
|
380
|
+
while (decodedSearchPoolBytes > DECODED_SEARCH_POOL_CACHE_MAX_BYTES) {
|
|
381
|
+
const oldest = decodedSearchPoolLru.keys().next().value;
|
|
382
|
+
if (!oldest)
|
|
383
|
+
break;
|
|
384
|
+
removeDecodedSearchPoolEntry(oldest);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
function invalidateDecodedSearchPools(db, predicate) {
|
|
388
|
+
const pool = decodedSearchPools.get(db);
|
|
389
|
+
if (!pool)
|
|
390
|
+
return;
|
|
391
|
+
for (const [key, entry] of [...pool.entries()]) {
|
|
392
|
+
const parsed = JSON.parse(key);
|
|
393
|
+
if (predicate(parsed))
|
|
394
|
+
removeDecodedSearchPoolEntry(entry);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function isFinitePositiveInteger(value) {
|
|
398
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
399
|
+
}
|
|
400
|
+
function normalizeCompartmentChunkMaxInputTokens(value) {
|
|
401
|
+
if (!isFinitePositiveInteger(value)) {
|
|
402
|
+
return DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS;
|
|
403
|
+
}
|
|
404
|
+
return Math.max(1, Math.floor(value));
|
|
405
|
+
}
|
|
406
|
+
function normalizeContent(text) {
|
|
407
|
+
return text.replace(/\s+/g, " ").trim();
|
|
408
|
+
}
|
|
409
|
+
function formatOrdinalRange(start, end) {
|
|
410
|
+
return start === end ? `[${start}]` : `[${start}-${end}]`;
|
|
411
|
+
}
|
|
412
|
+
function rolePrefix(role) {
|
|
413
|
+
if (role === "user")
|
|
414
|
+
return "U";
|
|
415
|
+
if (role === "assistant")
|
|
416
|
+
return "A";
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
function parseOrdinal(value) {
|
|
420
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
421
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
422
|
+
}
|
|
423
|
+
function parseCanonicalLineRange(line) {
|
|
424
|
+
const match = /^\[(\d+)(?:-(\d+))?\]\s+[UA]:/.exec(line.trim());
|
|
425
|
+
if (!match)
|
|
426
|
+
return null;
|
|
427
|
+
const start = Number.parseInt(match[1], 10);
|
|
428
|
+
const end = match[2] ? Number.parseInt(match[2], 10) : start;
|
|
429
|
+
if (!Number.isFinite(start) || !Number.isFinite(end))
|
|
430
|
+
return null;
|
|
431
|
+
return { start, end };
|
|
432
|
+
}
|
|
433
|
+
function assertOrdinalRangeWithinCompartment(rangeStart, rangeEnd, compartmentStart, compartmentEnd) {
|
|
434
|
+
if (rangeStart < compartmentStart || rangeEnd > compartmentEnd || rangeEnd < rangeStart) {
|
|
435
|
+
throw new RangeError(`Canonical chunk range ${rangeStart}-${rangeEnd} lies outside compartment ${compartmentStart}-${compartmentEnd}`);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function hashChunkText(text) {
|
|
439
|
+
return createHash("sha256").update(text).digest("hex");
|
|
440
|
+
}
|
|
441
|
+
function vectorBlob(vector) {
|
|
442
|
+
return new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength);
|
|
443
|
+
}
|
|
444
|
+
function toFloat32Array(blob) {
|
|
445
|
+
if (blob instanceof Uint8Array) {
|
|
446
|
+
const buffer = blob.buffer.slice(blob.byteOffset, blob.byteOffset + blob.byteLength);
|
|
447
|
+
return new Float32Array(buffer);
|
|
448
|
+
}
|
|
449
|
+
return new Float32Array(blob.slice(0));
|
|
450
|
+
}
|
|
451
|
+
function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal) {
|
|
452
|
+
if (endOrdinal < startOrdinal)
|
|
453
|
+
return "";
|
|
454
|
+
if (!messageFtsOrdinalRangeIsMapped(db, sessionId, startOrdinal, endOrdinal))
|
|
455
|
+
return null;
|
|
456
|
+
const rows = getLoadFtsRowsStatement(db).all(sessionId, startOrdinal, endOrdinal).map((row) => row);
|
|
457
|
+
const lines = [];
|
|
458
|
+
let current = null;
|
|
459
|
+
const flush = () => {
|
|
460
|
+
if (!current || current.parts.length === 0)
|
|
461
|
+
return;
|
|
462
|
+
lines.push(`${formatOrdinalRange(current.start, current.end)} ${current.role}: ${current.parts.join(" / ")}`);
|
|
463
|
+
current = null;
|
|
464
|
+
};
|
|
465
|
+
for (const row of rows) {
|
|
466
|
+
const ordinal = parseOrdinal(row.messageOrdinal);
|
|
467
|
+
const prefix = rolePrefix(row.role);
|
|
468
|
+
const content = typeof row.content === "string" ? normalizeContent(row.content) : "";
|
|
469
|
+
if (ordinal === null || prefix === null || content.length === 0)
|
|
470
|
+
continue;
|
|
471
|
+
if (current && current.role === prefix) {
|
|
472
|
+
current.end = ordinal;
|
|
473
|
+
current.parts.push(content);
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
flush();
|
|
477
|
+
current = { role: prefix, start: ordinal, end: ordinal, parts: [content] };
|
|
478
|
+
}
|
|
479
|
+
flush();
|
|
480
|
+
return lines.join(`
|
|
481
|
+
`);
|
|
482
|
+
}
|
|
483
|
+
function buildCompartmentSummaryFallbackText(db, compartmentId) {
|
|
484
|
+
const row = db.prepare("SELECT title, p1, content FROM compartments WHERE id = ?").get(compartmentId);
|
|
485
|
+
if (!row)
|
|
486
|
+
return "";
|
|
487
|
+
const title = typeof row.title === "string" ? row.title.trim() : "";
|
|
488
|
+
const p1 = typeof row.p1 === "string" ? row.p1.trim() : "";
|
|
489
|
+
const body = p1.length > 0 ? p1 : typeof row.content === "string" ? row.content.trim() : "";
|
|
490
|
+
return [title, body].filter((s) => s.length > 0).join(`
|
|
491
|
+
`);
|
|
492
|
+
}
|
|
493
|
+
function canonicalizeInMemoryChunkTextForEmbedding(chunkText, startOrdinal, endOrdinal) {
|
|
494
|
+
const lines = [];
|
|
495
|
+
for (const rawLine of chunkText.split(/\r?\n/)) {
|
|
496
|
+
const line = rawLine.trim();
|
|
497
|
+
const match = /^(\[(\d+)(?:-(\d+))?\]\s+[UA]:)\s*(.*)$/.exec(line);
|
|
498
|
+
if (!match)
|
|
499
|
+
continue;
|
|
500
|
+
const lineStart = Number.parseInt(match[2], 10);
|
|
501
|
+
const lineEnd = match[3] ? Number.parseInt(match[3], 10) : lineStart;
|
|
502
|
+
if (startOrdinal != null && lineEnd < startOrdinal)
|
|
503
|
+
continue;
|
|
504
|
+
if (endOrdinal != null && lineStart > endOrdinal)
|
|
505
|
+
continue;
|
|
506
|
+
const rawParts = match[4].split(" / ").map((part) => normalizeContent(part)).filter((part) => part.length > 0);
|
|
507
|
+
const ordinalSpan = lineEnd - lineStart + 1;
|
|
508
|
+
const roleLabel = match[1].slice(match[1].indexOf("]") + 2);
|
|
509
|
+
if (ordinalSpan === rawParts.length) {
|
|
510
|
+
const retained = rawParts.map((part, index) => ({ ordinal: lineStart + index, part })).filter(({ ordinal, part }) => {
|
|
511
|
+
if (part.startsWith("TC:"))
|
|
512
|
+
return false;
|
|
513
|
+
if (startOrdinal != null && ordinal < startOrdinal)
|
|
514
|
+
return false;
|
|
515
|
+
if (endOrdinal != null && ordinal > endOrdinal)
|
|
516
|
+
return false;
|
|
517
|
+
return true;
|
|
518
|
+
});
|
|
519
|
+
if (retained.length === 0)
|
|
520
|
+
continue;
|
|
521
|
+
const retainedStart = retained[0].ordinal;
|
|
522
|
+
const retainedEnd = retained[retained.length - 1].ordinal;
|
|
523
|
+
lines.push(`${formatOrdinalRange(retainedStart, retainedEnd)} ${roleLabel} ${retained.map(({ part }) => part).join(" / ")}`);
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
const clipsRequestedRange = startOrdinal != null && lineStart < startOrdinal || endOrdinal != null && lineEnd > endOrdinal;
|
|
527
|
+
if (clipsRequestedRange) {
|
|
528
|
+
return "";
|
|
529
|
+
}
|
|
530
|
+
const parts = rawParts.filter((part) => !part.startsWith("TC:"));
|
|
531
|
+
if (parts.length === 0)
|
|
532
|
+
continue;
|
|
533
|
+
lines.push(`${match[1]} ${parts.join(" / ")}`);
|
|
534
|
+
}
|
|
535
|
+
return lines.join(`
|
|
536
|
+
`);
|
|
537
|
+
}
|
|
538
|
+
function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTokens) {
|
|
539
|
+
const lines = canonicalText.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
540
|
+
if (lines.length === 0 || endOrdinal < startOrdinal)
|
|
541
|
+
return [];
|
|
542
|
+
for (const line of lines) {
|
|
543
|
+
const range = parseCanonicalLineRange(line);
|
|
544
|
+
if (range) {
|
|
545
|
+
assertOrdinalRangeWithinCompartment(range.start, range.end, startOrdinal, endOrdinal);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
const normalizedMax = normalizeCompartmentChunkMaxInputTokens(maxInputTokens);
|
|
549
|
+
const effectiveMax = Math.max(1, Math.floor(normalizedMax * CHUNK_WINDOW_SAFETY_RATIO));
|
|
550
|
+
const fullText = lines.join(`
|
|
551
|
+
`);
|
|
552
|
+
if (estimateTokens(fullText) <= effectiveMax) {
|
|
553
|
+
return [
|
|
554
|
+
{
|
|
555
|
+
windowIndex: 0,
|
|
556
|
+
startOrdinal,
|
|
557
|
+
endOrdinal,
|
|
558
|
+
text: fullText,
|
|
559
|
+
chunkHash: hashChunkText(fullText)
|
|
560
|
+
}
|
|
561
|
+
];
|
|
562
|
+
}
|
|
563
|
+
const windows = [];
|
|
564
|
+
let currentLines = [];
|
|
565
|
+
let currentStart = null;
|
|
566
|
+
let currentEnd = null;
|
|
567
|
+
let currentTokens = 0;
|
|
568
|
+
const flush = () => {
|
|
569
|
+
if (currentLines.length === 0 || currentStart === null || currentEnd === null)
|
|
570
|
+
return;
|
|
571
|
+
const text = currentLines.join(`
|
|
572
|
+
`);
|
|
573
|
+
assertOrdinalRangeWithinCompartment(currentStart, currentEnd, startOrdinal, endOrdinal);
|
|
574
|
+
windows.push({
|
|
575
|
+
windowIndex: windows.length,
|
|
576
|
+
startOrdinal: currentStart,
|
|
577
|
+
endOrdinal: currentEnd,
|
|
578
|
+
text,
|
|
579
|
+
chunkHash: hashChunkText(text)
|
|
580
|
+
});
|
|
581
|
+
currentLines = [];
|
|
582
|
+
currentStart = null;
|
|
583
|
+
currentEnd = null;
|
|
584
|
+
currentTokens = 0;
|
|
585
|
+
};
|
|
586
|
+
for (const line of lines) {
|
|
587
|
+
const range = parseCanonicalLineRange(line);
|
|
588
|
+
const lineStart = range?.start ?? startOrdinal;
|
|
589
|
+
const lineEnd = range?.end ?? lineStart;
|
|
590
|
+
const lineTokens = estimateTokens(line);
|
|
591
|
+
if (lineTokens > effectiveMax) {
|
|
592
|
+
flush();
|
|
593
|
+
for (const slice of splitOversizedLine(line, effectiveMax)) {
|
|
594
|
+
assertOrdinalRangeWithinCompartment(lineStart, lineEnd, startOrdinal, endOrdinal);
|
|
595
|
+
windows.push({
|
|
596
|
+
windowIndex: windows.length,
|
|
597
|
+
startOrdinal: lineStart,
|
|
598
|
+
endOrdinal: lineEnd,
|
|
599
|
+
text: slice,
|
|
600
|
+
chunkHash: hashChunkText(slice)
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
605
|
+
if (currentLines.length > 0 && currentTokens + lineTokens > effectiveMax) {
|
|
606
|
+
flush();
|
|
607
|
+
}
|
|
608
|
+
if (currentLines.length === 0) {
|
|
609
|
+
currentStart = lineStart;
|
|
610
|
+
}
|
|
611
|
+
currentLines.push(line);
|
|
612
|
+
currentEnd = lineEnd;
|
|
613
|
+
currentTokens += lineTokens;
|
|
614
|
+
}
|
|
615
|
+
flush();
|
|
616
|
+
return windows;
|
|
617
|
+
}
|
|
618
|
+
function splitOversizedLine(line, effectiveMax) {
|
|
619
|
+
let slices = [];
|
|
620
|
+
try {
|
|
621
|
+
slices = recursiveCharacterSplit(line, {
|
|
622
|
+
chunkSize: effectiveMax,
|
|
623
|
+
lengthFunction: estimateTokens
|
|
624
|
+
});
|
|
625
|
+
} catch (error) {
|
|
626
|
+
log2("[magic-context] recursiveCharacterSplit failed; using char-budget fallback:", error);
|
|
627
|
+
slices = [];
|
|
628
|
+
}
|
|
629
|
+
if (slices.length === 0) {
|
|
630
|
+
slices = charBudgetSplit(line, effectiveMax);
|
|
631
|
+
}
|
|
632
|
+
const safe = [];
|
|
633
|
+
const pushChecked = (slice) => {
|
|
634
|
+
if (estimateTokens(slice) > effectiveMax && slice.length > 1) {
|
|
635
|
+
safe.push(...charBudgetSplit(slice, effectiveMax));
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
safe.push(slice);
|
|
639
|
+
};
|
|
640
|
+
for (const slice of slices) {
|
|
641
|
+
if (estimateTokens(slice) <= effectiveMax) {
|
|
642
|
+
safe.push(slice);
|
|
643
|
+
} else {
|
|
644
|
+
for (const sub of charBudgetSplit(slice, effectiveMax))
|
|
645
|
+
pushChecked(sub);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return safe.filter((s) => s.length > 0);
|
|
649
|
+
}
|
|
650
|
+
function charBudgetSplit(text, effectiveMax) {
|
|
651
|
+
const totalTokens = Math.max(1, estimateTokens(text));
|
|
652
|
+
const charsPerToken = Math.max(1, Math.floor(text.length / totalTokens));
|
|
653
|
+
const sliceChars = Math.max(1, effectiveMax * charsPerToken);
|
|
654
|
+
const out = [];
|
|
655
|
+
let pos = 0;
|
|
656
|
+
while (pos < text.length) {
|
|
657
|
+
let end = Math.min(text.length, pos + sliceChars);
|
|
658
|
+
let slice = text.slice(pos, end);
|
|
659
|
+
while (slice.length > 1 && estimateTokens(slice) > effectiveMax) {
|
|
660
|
+
end = pos + Math.max(1, Math.floor((end - pos) / 2));
|
|
661
|
+
slice = text.slice(pos, end);
|
|
662
|
+
}
|
|
663
|
+
out.push(slice);
|
|
664
|
+
pos = end;
|
|
665
|
+
}
|
|
666
|
+
return out;
|
|
667
|
+
}
|
|
668
|
+
function getExistingChunkHashes(db, compartmentId, modelId, projectPath) {
|
|
669
|
+
const scoped = typeof projectPath === "string" && projectPath.length > 0;
|
|
670
|
+
const rows = scoped ? getExistingHashStatement(db, true).all(compartmentId, modelId, projectPath) : getExistingHashStatement(db, false).all(compartmentId, modelId);
|
|
671
|
+
return new Map(rows.filter((row) => typeof row.windowIndex === "number" && typeof row.chunkHash === "string").map((row) => [row.windowIndex, row.chunkHash]));
|
|
672
|
+
}
|
|
673
|
+
function chunkEmbeddingWindowsAreCurrent(db, compartmentId, modelId, windows, projectPath) {
|
|
674
|
+
const existing = getExistingChunkHashes(db, compartmentId, modelId, projectPath);
|
|
675
|
+
if (existing.size !== windows.length)
|
|
676
|
+
return false;
|
|
677
|
+
return windows.every((window) => existing.get(window.windowIndex) === window.chunkHash);
|
|
678
|
+
}
|
|
679
|
+
function replaceCompartmentChunkEmbeddings(db, rows, windowSourceKey) {
|
|
680
|
+
if (rows.length === 0 || rows.some((row) => isSynapseEmbeddingTruncated(row.vector)))
|
|
681
|
+
return;
|
|
682
|
+
const compartmentId = rows[0].compartmentId;
|
|
683
|
+
const modelId = rows[0].modelId;
|
|
684
|
+
const now = Date.now();
|
|
685
|
+
db.transaction(() => {
|
|
686
|
+
getDeleteByCompartmentStatement(db).run(compartmentId, modelId);
|
|
687
|
+
const insert = getInsertEmbeddingStatement(db);
|
|
688
|
+
for (const row of rows) {
|
|
689
|
+
insert.run(row.compartmentId, row.sessionId, row.projectPath, getHarness2(), row.window.windowIndex, row.window.startOrdinal, row.window.endOrdinal, row.window.chunkHash, row.modelId, row.vector.length, vectorBlob(row.vector), row.createdAt ?? now);
|
|
690
|
+
}
|
|
691
|
+
if (windowSourceKey) {
|
|
692
|
+
recordChunkWindowSource(db, compartmentId, windowSourceKey, rows.map((row) => [row.window.windowIndex, row.window.chunkHash]));
|
|
693
|
+
}
|
|
694
|
+
}).immediate();
|
|
695
|
+
invalidateDecodedSearchPools(db, ([sessionId, projectPath, cachedModelId]) => sessionId === rows[0].sessionId && projectPath === rows[0].projectPath && cachedModelId === modelId);
|
|
696
|
+
}
|
|
697
|
+
function loadCompartmentChunkEmbeddingsForSearch(db, sessionId, projectPath, modelId, dateRange = null) {
|
|
698
|
+
if (!modelId) {
|
|
699
|
+
throw new Error("loadCompartmentChunkEmbeddingsForSearch requires a current model id");
|
|
700
|
+
}
|
|
701
|
+
if (dateRange !== null) {
|
|
702
|
+
const rows = getDatedSearchRowsByModelStatement(db).all(sessionId, projectPath, modelId, dateRange.to, dateRange.from);
|
|
703
|
+
return rows.filter((row) => typeof row.compartmentId === "number" && typeof row.sessionId === "string" && typeof row.title === "string" && typeof row.compartmentStart === "number" && typeof row.compartmentEnd === "number" && typeof row.windowIndex === "number" && typeof row.windowStart === "number" && typeof row.windowEnd === "number" && typeof row.chunkHash === "string" && typeof row.modelId === "string" && typeof row.dims === "number" && (row.vector instanceof Uint8Array || row.vector instanceof ArrayBuffer)).map((row) => ({
|
|
704
|
+
compartmentId: row.compartmentId,
|
|
705
|
+
sessionId: row.sessionId,
|
|
706
|
+
title: row.title,
|
|
707
|
+
startOrdinal: row.compartmentStart,
|
|
708
|
+
endOrdinal: row.compartmentEnd,
|
|
709
|
+
windowIndex: row.windowIndex,
|
|
710
|
+
windowStartOrdinal: row.windowStart,
|
|
711
|
+
windowEndOrdinal: row.windowEnd,
|
|
712
|
+
chunkHash: row.chunkHash,
|
|
713
|
+
modelId: row.modelId,
|
|
714
|
+
dims: row.dims,
|
|
715
|
+
vector: toFloat32Array(row.vector)
|
|
716
|
+
}));
|
|
717
|
+
}
|
|
718
|
+
const key = searchPoolKey(sessionId, projectPath, modelId);
|
|
719
|
+
const pool = getDecodedSearchPool(db);
|
|
720
|
+
const probe = getSearchPoolProbeStatement(db).get(sessionId, projectPath, modelId);
|
|
721
|
+
const rowCount = typeof probe?.rowCount === "number" ? probe.rowCount : 0;
|
|
722
|
+
const maxRowId = typeof probe?.maxRowId === "number" ? probe.maxRowId : 0;
|
|
723
|
+
const cached = pool.get(key);
|
|
724
|
+
if (cached && cached.rowCount === rowCount && cached.maxRowId === maxRowId) {
|
|
725
|
+
touchDecodedSearchPoolEntry(cached);
|
|
726
|
+
return refreshPoolCompartmentFields(db, sessionId, projectPath, modelId, cached.rows);
|
|
727
|
+
}
|
|
728
|
+
if (cached)
|
|
729
|
+
removeDecodedSearchPoolEntry(cached);
|
|
730
|
+
const rows = getSearchRowsStatement(db, true).all(sessionId, projectPath, modelId);
|
|
731
|
+
const decodedRows = rows.filter((row) => typeof row.compartmentId === "number" && typeof row.sessionId === "string" && typeof row.title === "string" && typeof row.compartmentStart === "number" && typeof row.compartmentEnd === "number" && typeof row.windowIndex === "number" && typeof row.windowStart === "number" && typeof row.windowEnd === "number" && typeof row.chunkHash === "string" && typeof row.modelId === "string" && typeof row.dims === "number" && (row.vector instanceof Uint8Array || row.vector instanceof ArrayBuffer)).map((row) => ({
|
|
732
|
+
compartmentId: row.compartmentId,
|
|
733
|
+
sessionId: row.sessionId,
|
|
734
|
+
title: row.title,
|
|
735
|
+
startOrdinal: row.compartmentStart,
|
|
736
|
+
endOrdinal: row.compartmentEnd,
|
|
737
|
+
windowIndex: row.windowIndex,
|
|
738
|
+
windowStartOrdinal: row.windowStart,
|
|
739
|
+
windowEndOrdinal: row.windowEnd,
|
|
740
|
+
chunkHash: row.chunkHash,
|
|
741
|
+
modelId: row.modelId,
|
|
742
|
+
dims: row.dims,
|
|
743
|
+
vector: toFloat32Array(row.vector)
|
|
744
|
+
}));
|
|
745
|
+
cacheDecodedSearchPool(pool, key, rowCount, maxRowId, decodedRows);
|
|
746
|
+
return decodedRows;
|
|
747
|
+
}
|
|
748
|
+
function loadUnembeddedShadowChunkCandidates(db, projectPath, primaryModelId, shadowModelId, limit, shadowMaxInputTokens) {
|
|
749
|
+
const rows = getShadowBackfillCandidateStatement(db).all(projectPath, projectPath, primaryModelId);
|
|
750
|
+
return selectHashIncompleteChunkCandidates(db, projectPath, shadowModelId, mapBackfillCandidateRows(rows), Math.max(1, limit), shadowMaxInputTokens);
|
|
751
|
+
}
|
|
752
|
+
async function loadUnembeddedCompartmentChunkCandidatesPolite(db, projectPath, modelId, limit, maxInputTokens = DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS, leaseHeldRenumber = false) {
|
|
753
|
+
const rows = getBackfillCandidateStatement(db).all(projectPath);
|
|
754
|
+
const candidates = mapBackfillCandidateRows(rows);
|
|
755
|
+
const missing = [];
|
|
756
|
+
const stale = [];
|
|
757
|
+
let sliceStarted = performance.now();
|
|
758
|
+
for (const candidate of candidates) {
|
|
759
|
+
const classification = classifyChunkCoverageDefect(db, projectPath, modelId, candidate, maxInputTokens);
|
|
760
|
+
if (classification.defect === "missing")
|
|
761
|
+
missing.push(candidate);
|
|
762
|
+
else if (classification.defect === "stale")
|
|
763
|
+
stale.push(candidate);
|
|
764
|
+
else if (leaseHeldRenumber) {
|
|
765
|
+
applyLeaseHeldCoverageRepair(db, candidate, projectPath, modelId, classification);
|
|
766
|
+
}
|
|
767
|
+
sliceStarted = await yieldCoverageSlice(sliceStarted);
|
|
768
|
+
}
|
|
769
|
+
return [...missing, ...stale].slice(0, Math.max(1, limit));
|
|
770
|
+
}
|
|
771
|
+
function mapBackfillCandidateRows(rows) {
|
|
772
|
+
return rows.filter((row) => {
|
|
773
|
+
if (row === null || typeof row !== "object")
|
|
774
|
+
return false;
|
|
775
|
+
const candidate = row;
|
|
776
|
+
return typeof candidate.id === "number" && typeof candidate.sessionId === "string" && typeof candidate.startMessage === "number" && typeof candidate.endMessage === "number" && typeof candidate.title === "string";
|
|
777
|
+
}).map((row) => ({
|
|
778
|
+
id: row.id,
|
|
779
|
+
sessionId: row.sessionId,
|
|
780
|
+
startMessage: row.startMessage,
|
|
781
|
+
endMessage: row.endMessage,
|
|
782
|
+
title: row.title
|
|
783
|
+
}));
|
|
784
|
+
}
|
|
785
|
+
var CHUNKER_VERSION = 1;
|
|
786
|
+
var BACKOFF_PREFIX = "chunk_embed_backoff:";
|
|
787
|
+
function backoffKey(compartmentId) {
|
|
788
|
+
return `${BACKOFF_PREFIX}${compartmentId}`;
|
|
789
|
+
}
|
|
790
|
+
function deleteChunkEmbedBackoffForSession(db, sessionId) {
|
|
791
|
+
db.prepare(`DELETE FROM schema_migrations_meta WHERE key IN (
|
|
792
|
+
SELECT ? || id FROM compartments WHERE session_id = ?
|
|
793
|
+
UNION ALL
|
|
794
|
+
SELECT ? || id FROM compartments WHERE session_id = ?
|
|
795
|
+
)`).run(BACKOFF_PREFIX, sessionId, WINDOW_SOURCE_PREFIX, sessionId);
|
|
796
|
+
}
|
|
797
|
+
function recordChunkEmbedBackoff(db, candidate, projectPath, modelId) {
|
|
798
|
+
const mapped = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
|
|
799
|
+
if (mapped === null)
|
|
800
|
+
return;
|
|
801
|
+
const text = mapped || buildCompartmentSummaryFallbackText(db, candidate.id);
|
|
802
|
+
const hash = createHash("sha256").update(text).digest("hex");
|
|
803
|
+
const key = backoffKey(candidate.id);
|
|
804
|
+
const prior = db.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(key);
|
|
805
|
+
let retries = 0;
|
|
806
|
+
try {
|
|
807
|
+
const value = JSON.parse(prior?.value ?? "null");
|
|
808
|
+
if (value?.hash === hash && value.project === projectPath && value.model === modelId) {
|
|
809
|
+
retries = Math.max(0, Math.min(12, value.retries ?? 0));
|
|
810
|
+
}
|
|
811
|
+
} catch {}
|
|
812
|
+
db.prepare(`INSERT INTO schema_migrations_meta (key, value) VALUES (?, ?)
|
|
813
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(key, JSON.stringify({
|
|
814
|
+
hash,
|
|
815
|
+
project: projectPath,
|
|
816
|
+
model: modelId,
|
|
817
|
+
retries: retries + 1,
|
|
818
|
+
retryAt: Date.now() + Math.min(86400000, 60000 * 2 ** retries)
|
|
819
|
+
}));
|
|
820
|
+
}
|
|
821
|
+
function chunkEmbedBackoffActive(db, candidate, projectPath, modelId, text) {
|
|
822
|
+
const row = db.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(backoffKey(candidate.id));
|
|
823
|
+
if (!row)
|
|
824
|
+
return false;
|
|
825
|
+
try {
|
|
826
|
+
const value = JSON.parse(row.value);
|
|
827
|
+
return value.project === projectPath && value.model === modelId && value.hash === createHash("sha256").update(text).digest("hex") && value.retryAt > Date.now();
|
|
828
|
+
} catch {
|
|
829
|
+
return false;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
var WINDOW_SOURCE_PREFIX = "chunk_embed_windows:";
|
|
833
|
+
var WINDOW_SOURCE_RECORD_LIMIT = 4;
|
|
834
|
+
var windowSourceReadStatements = new WeakMap;
|
|
835
|
+
var windowSourceWriteStatements = new WeakMap;
|
|
836
|
+
function windowSourceMetaKey(compartmentId) {
|
|
837
|
+
return `${WINDOW_SOURCE_PREFIX}${compartmentId}`;
|
|
838
|
+
}
|
|
839
|
+
function windowSourceKeyFromTextHash(textHash, startOrdinal, endOrdinal, maxInputTokens) {
|
|
840
|
+
return hashChunkText(JSON.stringify([
|
|
841
|
+
CHUNKER_VERSION,
|
|
842
|
+
getTokenEstimatorFingerprint(),
|
|
843
|
+
normalizeCompartmentChunkMaxInputTokens(maxInputTokens),
|
|
844
|
+
startOrdinal,
|
|
845
|
+
endOrdinal,
|
|
846
|
+
textHash
|
|
847
|
+
]));
|
|
848
|
+
}
|
|
849
|
+
function chunkWindowSourceKey(canonicalText, startOrdinal, endOrdinal, maxInputTokens) {
|
|
850
|
+
return windowSourceKeyFromTextHash(hashChunkText(canonicalText), startOrdinal, endOrdinal, maxInputTokens);
|
|
851
|
+
}
|
|
852
|
+
function windowSetDigest(windows) {
|
|
853
|
+
const sorted = [...windows].sort((a, b) => a[0] - b[0]);
|
|
854
|
+
return hashChunkText(sorted.map(([index, hash]) => `${index}:${hash}`).join(`
|
|
855
|
+
`));
|
|
856
|
+
}
|
|
857
|
+
function readChunkWindowSources(db, compartmentId) {
|
|
858
|
+
let stmt = windowSourceReadStatements.get(db);
|
|
859
|
+
if (!stmt) {
|
|
860
|
+
stmt = db.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?");
|
|
861
|
+
windowSourceReadStatements.set(db, stmt);
|
|
862
|
+
}
|
|
863
|
+
const row = stmt.get(windowSourceMetaKey(compartmentId));
|
|
864
|
+
if (typeof row?.value !== "string")
|
|
865
|
+
return [];
|
|
866
|
+
try {
|
|
867
|
+
const parsed = JSON.parse(row.value);
|
|
868
|
+
if (!Array.isArray(parsed))
|
|
869
|
+
return [];
|
|
870
|
+
return parsed.filter((entry) => entry !== null && typeof entry === "object" && typeof entry.source === "string" && typeof entry.windows === "string");
|
|
871
|
+
} catch {
|
|
872
|
+
return [];
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
function recordChunkWindowSource(db, compartmentId, sourceKey, windows) {
|
|
876
|
+
const record = {
|
|
877
|
+
source: sourceKey,
|
|
878
|
+
windows: windowSetDigest(windows)
|
|
879
|
+
};
|
|
880
|
+
const kept = readChunkWindowSources(db, compartmentId).filter((entry) => entry.source !== sourceKey);
|
|
881
|
+
let stmt = windowSourceWriteStatements.get(db);
|
|
882
|
+
if (!stmt) {
|
|
883
|
+
stmt = db.prepare(`INSERT INTO schema_migrations_meta (key, value) VALUES (?, ?)
|
|
884
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value`);
|
|
885
|
+
windowSourceWriteStatements.set(db, stmt);
|
|
886
|
+
}
|
|
887
|
+
stmt.run(windowSourceMetaKey(compartmentId), JSON.stringify([record, ...kept].slice(0, WINDOW_SOURCE_RECORD_LIMIT)));
|
|
888
|
+
}
|
|
889
|
+
function storedWindowsMatchRecordedSource(db, compartmentId, sourceKey, existing) {
|
|
890
|
+
const record = readChunkWindowSources(db, compartmentId).find((entry) => entry.source === sourceKey);
|
|
891
|
+
return record !== undefined && record.windows === windowSetDigest(existing);
|
|
892
|
+
}
|
|
893
|
+
var COVERAGE_MEMO_LIMIT = 2048;
|
|
894
|
+
var cachedCoverageWindows = new Map;
|
|
895
|
+
function memoizedCoverageWindows(candidate, canonicalText, sourceKey, modelId, maxInputTokens) {
|
|
896
|
+
const key = JSON.stringify([candidate.id, sourceKey, modelId]);
|
|
897
|
+
const cached = cachedCoverageWindows.get(key);
|
|
898
|
+
if (cached) {
|
|
899
|
+
cachedCoverageWindows.delete(key);
|
|
900
|
+
cachedCoverageWindows.set(key, cached);
|
|
901
|
+
return cached;
|
|
902
|
+
}
|
|
903
|
+
const windows = chunkCanonicalText(canonicalText, candidate.startMessage, candidate.endMessage, maxInputTokens);
|
|
904
|
+
cachedCoverageWindows.set(key, windows);
|
|
905
|
+
if (cachedCoverageWindows.size > COVERAGE_MEMO_LIMIT) {
|
|
906
|
+
const oldest = cachedCoverageWindows.keys().next().value;
|
|
907
|
+
if (oldest !== undefined)
|
|
908
|
+
cachedCoverageWindows.delete(oldest);
|
|
909
|
+
}
|
|
910
|
+
return windows;
|
|
911
|
+
}
|
|
912
|
+
async function yieldCoverageSlice(started) {
|
|
913
|
+
if (performance.now() - started < 35)
|
|
914
|
+
return started;
|
|
915
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
916
|
+
return performance.now();
|
|
917
|
+
}
|
|
918
|
+
function renumberOneBasedChunkWindows(db, candidate, projectPath, modelId, windows, sourceKey) {
|
|
919
|
+
const update = getRenumberEmbeddingWindowStatement(db);
|
|
920
|
+
db.transaction(() => {
|
|
921
|
+
for (const window of windows) {
|
|
922
|
+
const result = update.run(window.windowIndex, candidate.id, modelId, projectPath, window.windowIndex + 1);
|
|
923
|
+
if (result.changes !== 1) {
|
|
924
|
+
throw new Error(`Failed to renumber compartment ${candidate.id} window ${window.windowIndex + 1}`);
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
if (sourceKey) {
|
|
928
|
+
recordChunkWindowSource(db, candidate.id, sourceKey, windows.map((window) => [window.windowIndex, window.chunkHash]));
|
|
929
|
+
}
|
|
930
|
+
}).immediate();
|
|
931
|
+
invalidateDecodedSearchPools(db, ([sessionId, cachedProjectPath, cachedModelId]) => sessionId === candidate.sessionId && cachedProjectPath === projectPath && cachedModelId === modelId);
|
|
932
|
+
}
|
|
933
|
+
function classifyChunkCoverageDefect(db, projectPath, modelId, candidate, maxInputTokens) {
|
|
934
|
+
const mappedText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
|
|
935
|
+
if (mappedText === null)
|
|
936
|
+
return { defect: "deferred", windows: [] };
|
|
937
|
+
const canonicalText = mappedText || buildCompartmentSummaryFallbackText(db, candidate.id);
|
|
938
|
+
if (!canonicalText || chunkEmbedBackoffActive(db, candidate, projectPath, modelId, canonicalText)) {
|
|
939
|
+
return { defect: "deferred", windows: [] };
|
|
940
|
+
}
|
|
941
|
+
const sourceKey = chunkWindowSourceKey(canonicalText, candidate.startMessage, candidate.endMessage, maxInputTokens);
|
|
942
|
+
const existing = getExistingChunkHashes(db, candidate.id, modelId, projectPath);
|
|
943
|
+
if (storedWindowsMatchRecordedSource(db, candidate.id, sourceKey, existing)) {
|
|
944
|
+
return { defect: null, windows: [], sourceKey, confirmedByRecord: true };
|
|
945
|
+
}
|
|
946
|
+
const windows = memoizedCoverageWindows(candidate, canonicalText, sourceKey, modelId, maxInputTokens);
|
|
947
|
+
const isMatchingOneBasedSet = windows.length > 0 && existing.size === windows.length && windows.every((window) => existing.get(window.windowIndex + 1) === window.chunkHash);
|
|
948
|
+
if (isMatchingOneBasedSet)
|
|
949
|
+
return { defect: "renumber", windows, sourceKey };
|
|
950
|
+
const expectedWindowIndexes = new Set(windows.map((window) => window.windowIndex));
|
|
951
|
+
if ([...existing.keys()].some((windowIndex) => !expectedWindowIndexes.has(windowIndex))) {
|
|
952
|
+
return { defect: "stale", windows, sourceKey };
|
|
953
|
+
}
|
|
954
|
+
if (windows.some((window) => !existing.has(window.windowIndex))) {
|
|
955
|
+
return { defect: "missing", windows, sourceKey };
|
|
956
|
+
}
|
|
957
|
+
if (existing.size !== windows.length || windows.some((window) => existing.get(window.windowIndex) !== window.chunkHash)) {
|
|
958
|
+
return { defect: "stale", windows, sourceKey };
|
|
959
|
+
}
|
|
960
|
+
return { defect: null, windows, sourceKey };
|
|
961
|
+
}
|
|
962
|
+
function applyLeaseHeldCoverageRepair(db, candidate, projectPath, modelId, classification) {
|
|
963
|
+
const { defect, windows, sourceKey, confirmedByRecord } = classification;
|
|
964
|
+
if (defect === "renumber") {
|
|
965
|
+
renumberOneBasedChunkWindows(db, candidate, projectPath, modelId, windows, sourceKey);
|
|
966
|
+
} else if (defect === null && !confirmedByRecord && sourceKey) {
|
|
967
|
+
db.transaction(() => {
|
|
968
|
+
recordChunkWindowSource(db, candidate.id, sourceKey, windows.map((window) => [window.windowIndex, window.chunkHash]));
|
|
969
|
+
}).immediate();
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
function selectHashIncompleteChunkCandidates(db, projectPath, modelId, candidates, limit, maxInputTokens, leaseHeldRenumber = false) {
|
|
973
|
+
const missing = [];
|
|
974
|
+
const stale = [];
|
|
975
|
+
for (const candidate of candidates) {
|
|
976
|
+
const classification = classifyChunkCoverageDefect(db, projectPath, modelId, candidate, maxInputTokens);
|
|
977
|
+
if (classification.defect === "missing")
|
|
978
|
+
missing.push(candidate);
|
|
979
|
+
else if (classification.defect === "stale")
|
|
980
|
+
stale.push(candidate);
|
|
981
|
+
else if (leaseHeldRenumber) {
|
|
982
|
+
applyLeaseHeldCoverageRepair(db, candidate, projectPath, modelId, classification);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
return [...missing, ...stale].slice(0, limit);
|
|
986
|
+
}
|
|
987
|
+
var sessionBackfillCandidateStatements = new WeakMap;
|
|
988
|
+
async function loadUnembeddedSessionChunkCandidatesPolite(db, projectPath, sessionId, modelId, limit, excludeIds = [], maxInputTokens = DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS, leaseHeldRenumber = false) {
|
|
989
|
+
const excluded = new Set(excludeIds);
|
|
990
|
+
const missing = [];
|
|
991
|
+
const stale = [];
|
|
992
|
+
let started = performance.now();
|
|
993
|
+
for (const candidate of getSessionBackfillRows(db, projectPath, sessionId)) {
|
|
994
|
+
if (excluded.has(candidate.id))
|
|
995
|
+
continue;
|
|
996
|
+
const classification = classifyChunkCoverageDefect(db, projectPath, modelId, candidate, maxInputTokens);
|
|
997
|
+
if (classification.defect === "missing")
|
|
998
|
+
missing.push(candidate);
|
|
999
|
+
else if (classification.defect === "stale")
|
|
1000
|
+
stale.push(candidate);
|
|
1001
|
+
else if (leaseHeldRenumber) {
|
|
1002
|
+
applyLeaseHeldCoverageRepair(db, candidate, projectPath, modelId, classification);
|
|
1003
|
+
}
|
|
1004
|
+
started = await yieldCoverageSlice(started);
|
|
1005
|
+
}
|
|
1006
|
+
return [...missing, ...stale].slice(0, Math.max(1, limit));
|
|
1007
|
+
}
|
|
1008
|
+
function countSessionCompartmentEmbedCoverage(db, projectPath, sessionId, modelId, maxInputTokens = DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS) {
|
|
1009
|
+
const candidates = getSessionBackfillRows(db, projectPath, sessionId);
|
|
1010
|
+
let embedded = 0;
|
|
1011
|
+
for (const candidate of candidates) {
|
|
1012
|
+
const { defect } = classifyChunkCoverageDefect(db, projectPath, modelId, candidate, maxInputTokens);
|
|
1013
|
+
if (defect === null || defect === "renumber")
|
|
1014
|
+
embedded += 1;
|
|
1015
|
+
}
|
|
1016
|
+
return { embedded, total: candidates.length };
|
|
1017
|
+
}
|
|
1018
|
+
function getSessionBackfillRows(db, projectPath, sessionId) {
|
|
1019
|
+
const rows = db.prepare(`SELECT c.id AS id,
|
|
1020
|
+
c.session_id AS sessionId,
|
|
1021
|
+
c.start_message AS startMessage,
|
|
1022
|
+
c.end_message AS endMessage,
|
|
1023
|
+
c.title AS title
|
|
1024
|
+
FROM compartments c
|
|
1025
|
+
JOIN session_projects sp
|
|
1026
|
+
ON sp.session_id = c.session_id
|
|
1027
|
+
AND sp.harness = c.harness
|
|
1028
|
+
AND sp.project_path = ?
|
|
1029
|
+
WHERE c.session_id = ?
|
|
1030
|
+
AND c.start_message IS NOT NULL
|
|
1031
|
+
AND c.end_message IS NOT NULL
|
|
1032
|
+
ORDER BY c.start_message ASC, c.id ASC`).all(projectPath, sessionId);
|
|
1033
|
+
return mapBackfillCandidateRows(rows);
|
|
1034
|
+
}
|
|
1035
|
+
async function countSessionCompartmentEmbedCoveragePolite(db, projectPath, sessionId, modelId, maxInputTokens = DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS) {
|
|
1036
|
+
const candidates = getSessionBackfillRows(db, projectPath, sessionId);
|
|
1037
|
+
let embedded = 0;
|
|
1038
|
+
let started = performance.now();
|
|
1039
|
+
for (const candidate of candidates) {
|
|
1040
|
+
const { defect } = classifyChunkCoverageDefect(db, projectPath, modelId, candidate, maxInputTokens);
|
|
1041
|
+
if (defect === null || defect === "renumber")
|
|
1042
|
+
embedded++;
|
|
1043
|
+
started = await yieldCoverageSlice(started);
|
|
1044
|
+
}
|
|
1045
|
+
return { embedded, total: candidates.length };
|
|
1046
|
+
}
|
|
1047
|
+
async function countUnembeddedSessionCompartmentsPolite(db, projectPath, sessionId, modelId, maxInputTokens = DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS) {
|
|
1048
|
+
const candidates = getSessionBackfillRows(db, projectPath, sessionId);
|
|
1049
|
+
let count = 0;
|
|
1050
|
+
let started = performance.now();
|
|
1051
|
+
for (const candidate of candidates) {
|
|
1052
|
+
const { defect } = classifyChunkCoverageDefect(db, projectPath, modelId, candidate, maxInputTokens);
|
|
1053
|
+
if (defect === "missing" || defect === "stale")
|
|
1054
|
+
count++;
|
|
1055
|
+
started = await yieldCoverageSlice(started);
|
|
1056
|
+
}
|
|
1057
|
+
return count;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
export { CHUNK_WINDOW_SAFETY_RATIO, normalizeCompartmentChunkMaxInputTokens, buildCanonicalChunkTextFromFts, buildCompartmentSummaryFallbackText, canonicalizeInMemoryChunkTextForEmbedding, chunkCanonicalText, chunkEmbeddingWindowsAreCurrent, replaceCompartmentChunkEmbeddings, loadCompartmentChunkEmbeddingsForSearch, loadUnembeddedShadowChunkCandidates, loadUnembeddedCompartmentChunkCandidatesPolite, deleteChunkEmbedBackoffForSession, recordChunkEmbedBackoff, chunkWindowSourceKey, loadUnembeddedSessionChunkCandidatesPolite, countSessionCompartmentEmbedCoverage, countSessionCompartmentEmbedCoveragePolite, countUnembeddedSessionCompartmentsPolite };
|