@equationalapplications/core-llm-wiki 5.5.0 → 6.0.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 +136 -31
- package/dist/{chunk-QVY5DFJV.mjs → chunk-HREQ6F6Z.mjs} +241 -45
- package/dist/chunk-HREQ6F6Z.mjs.map +1 -0
- package/dist/index.d.mts +18 -3
- package/dist/index.d.ts +18 -3
- package/dist/index.js +241 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/{testing-D0RnZjyW.d.mts → testing-DgqVB29I.d.mts} +72 -6
- package/dist/{testing-D0RnZjyW.d.ts → testing-DgqVB29I.d.ts} +72 -6
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +238 -42
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-QVY5DFJV.mjs.map +0 -1
|
@@ -1220,7 +1220,12 @@ function extractParsePosition(err) {
|
|
|
1220
1220
|
return match ? Number(match[1]) : null;
|
|
1221
1221
|
}
|
|
1222
1222
|
function safeErrorToString(e) {
|
|
1223
|
-
|
|
1223
|
+
let isErrorLike = false;
|
|
1224
|
+
try {
|
|
1225
|
+
isErrorLike = e instanceof Error;
|
|
1226
|
+
} catch {
|
|
1227
|
+
}
|
|
1228
|
+
if (isErrorLike) {
|
|
1224
1229
|
const msg = readErrorField(e, "message");
|
|
1225
1230
|
if (typeof msg === "string" && msg.length > 0) return msg;
|
|
1226
1231
|
const name = readErrorField(e, "name");
|
|
@@ -1245,16 +1250,54 @@ function readErrorField(e, key) {
|
|
|
1245
1250
|
}
|
|
1246
1251
|
}
|
|
1247
1252
|
function sanitizeRankerError(err, sanitizeRankerErrors) {
|
|
1253
|
+
let isErrorLike = false;
|
|
1254
|
+
try {
|
|
1255
|
+
isErrorLike = err instanceof Error;
|
|
1256
|
+
} catch {
|
|
1257
|
+
}
|
|
1248
1258
|
if (sanitizeRankerErrors === false) {
|
|
1249
|
-
return
|
|
1259
|
+
return isErrorLike ? err : new Error(safeErrorToString(err));
|
|
1260
|
+
}
|
|
1261
|
+
let errLike = null;
|
|
1262
|
+
if (isErrorLike) errLike = err;
|
|
1263
|
+
let typeName;
|
|
1264
|
+
try {
|
|
1265
|
+
if (errLike) {
|
|
1266
|
+
const rawName = errLike.constructor?.name;
|
|
1267
|
+
typeName = typeof rawName === "string" ? rawName : "Error";
|
|
1268
|
+
} else {
|
|
1269
|
+
typeName = typeof err;
|
|
1270
|
+
}
|
|
1271
|
+
} catch {
|
|
1272
|
+
typeName = isErrorLike ? "Error" : typeof err;
|
|
1273
|
+
}
|
|
1274
|
+
let innerCause;
|
|
1275
|
+
if (errLike) {
|
|
1276
|
+
let cause;
|
|
1277
|
+
try {
|
|
1278
|
+
cause = errLike.cause;
|
|
1279
|
+
} catch {
|
|
1280
|
+
cause = void 0;
|
|
1281
|
+
}
|
|
1282
|
+
if (cause !== void 0) {
|
|
1283
|
+
let causeName;
|
|
1284
|
+
try {
|
|
1285
|
+
const rawCauseName = cause?.constructor?.name;
|
|
1286
|
+
causeName = typeof rawCauseName === "string" ? rawCauseName : typeof cause;
|
|
1287
|
+
} catch {
|
|
1288
|
+
causeName = typeof cause;
|
|
1289
|
+
}
|
|
1290
|
+
innerCause = new Error(`Caused by: ${causeName}`);
|
|
1291
|
+
}
|
|
1250
1292
|
}
|
|
1251
|
-
const typeName = err instanceof Error ? err.constructor?.name ?? "Error" : typeof err;
|
|
1252
|
-
const innerCause = err instanceof Error && err.cause !== void 0 ? new Error(`Caused by: ${err.cause?.constructor?.name ?? typeof err.cause}`) : void 0;
|
|
1253
1293
|
const sanitized = new Error(
|
|
1254
1294
|
`VectorRanker ${typeName} (message scrubbed for security)`,
|
|
1255
1295
|
innerCause ? { cause: innerCause } : void 0
|
|
1256
1296
|
);
|
|
1257
|
-
|
|
1297
|
+
try {
|
|
1298
|
+
sanitized.name = typeName;
|
|
1299
|
+
} catch {
|
|
1300
|
+
}
|
|
1258
1301
|
return sanitized;
|
|
1259
1302
|
}
|
|
1260
1303
|
function safeSlice(value, start, end) {
|
|
@@ -1438,6 +1481,12 @@ Return ONLY a valid JSON object matching this schema:
|
|
|
1438
1481
|
If no manifest type fits a fact, omit that fact from "classifications" entirely \u2014 do not guess.
|
|
1439
1482
|
When echoing an existing fact's title verbatim into "target_title", preserve every JSON escape sequence (\\", \\n, \\\\, \\/) exactly as it appeared in the input body \u2014 do not strip backslashes, do not add unescaped quotes. Do not return markdown, just raw JSON.`;
|
|
1440
1483
|
|
|
1484
|
+
// src/utils/healConstants.ts
|
|
1485
|
+
var HEAL_MAX_ANCHORS = 50;
|
|
1486
|
+
var HEAL_ANCHORS_PER_CANDIDATE = 4;
|
|
1487
|
+
var HEAL_MAX_FACT_BODY_CHARS_L3 = 4e3;
|
|
1488
|
+
var HEAL_MAX_TASKS = 50;
|
|
1489
|
+
|
|
1441
1490
|
// src/services/PromptService.ts
|
|
1442
1491
|
var PromptService = class {
|
|
1443
1492
|
constructor(globalOverrides) {
|
|
@@ -1505,25 +1554,67 @@ Current Facts:
|
|
|
1505
1554
|
${JSON.stringify(currentFacts, null, 2)}`
|
|
1506
1555
|
};
|
|
1507
1556
|
}
|
|
1508
|
-
|
|
1557
|
+
/**
|
|
1558
|
+
* Heal-prompt level interpretation for the `attemptLevel` ladder.
|
|
1559
|
+
*
|
|
1560
|
+
* Caller contract: `documentAnchors` may be a slice sized for `batch.length`
|
|
1561
|
+
* or a larger set (e.g. a cache hit from `_selectHealAnchors`). This function
|
|
1562
|
+
* applies the prompt-side anchor cap `min(HEAL_MAX_ANCHORS=50, batch.length
|
|
1563
|
+
* * HEAL_ANCHORS_PER_CANDIDATE=4)` so the rendered prompt is bounded
|
|
1564
|
+
* regardless of caller input. `HEAL_MAX_ANCHORS` and
|
|
1565
|
+
* `HEAL_ANCHORS_PER_CANDIDATE` live here too — keeping the formula
|
|
1566
|
+
* co-located with its application avoids a "MaintenanceService policy"
|
|
1567
|
+
* import cycle (`PromptService` is constructed before `MaintenanceService`
|
|
1568
|
+
* exists) and makes the cap testable without a `MaintenanceService`
|
|
1569
|
+
* instance. Task 3 exports the same two constants from `MaintenanceService`
|
|
1570
|
+
* for caller-side overfetch sizing; the values must match.
|
|
1571
|
+
*
|
|
1572
|
+
* Level semantics:
|
|
1573
|
+
* - L0: allTasks + recentEvents + full candidate bodies; anchors re-capped
|
|
1574
|
+
* - L1: drop allTasks; recentEvents present; candidate bodies full
|
|
1575
|
+
* - L2: drop allTasks and recentEvents; candidate bodies full
|
|
1576
|
+
* - L3: drop allTasks and recentEvents; truncate each candidate body to
|
|
1577
|
+
* `bodyTruncationChars` and emit a `degraded` record per truncated fact
|
|
1578
|
+
*/
|
|
1579
|
+
buildHealPrompt(healCandidates, documentAnchors, allTasks, recentEvents, runtimeOverride, attemptLevel, bodyTruncationChars = HEAL_MAX_FACT_BODY_CHARS_L3) {
|
|
1580
|
+
const effectiveTasks = attemptLevel >= 1 ? [] : allTasks;
|
|
1581
|
+
const effectiveEvents = attemptLevel >= 2 ? [] : recentEvents;
|
|
1582
|
+
const maxAnchors = Math.max(1, Math.min(HEAL_MAX_ANCHORS, healCandidates.length * HEAL_ANCHORS_PER_CANDIDATE));
|
|
1583
|
+
const effectiveAnchors = documentAnchors.slice(0, maxAnchors);
|
|
1584
|
+
const { shapedCandidates, degraded } = applyBodyTruncation(
|
|
1585
|
+
healCandidates,
|
|
1586
|
+
attemptLevel,
|
|
1587
|
+
bodyTruncationChars
|
|
1588
|
+
);
|
|
1509
1589
|
const template = runtimeOverride ?? this.globalOverrides?.healSystemPrompt ?? HEAL_SYSTEM_PROMPT;
|
|
1510
1590
|
if (/\{\{\s*healCandidates\s*\}\}/.test(template) || /\{\{\s*documentAnchors\s*\}\}/.test(template) || /\{\{\s*allTasks\s*\}\}/.test(template) || /\{\{\s*recentEvents\s*\}\}/.test(template)) {
|
|
1511
1591
|
return {
|
|
1512
|
-
|
|
1513
|
-
|
|
1592
|
+
prompts: {
|
|
1593
|
+
systemPrompt: this.hydrate(template, {
|
|
1594
|
+
healCandidates: shapedCandidates,
|
|
1595
|
+
documentAnchors: effectiveAnchors,
|
|
1596
|
+
allTasks: effectiveTasks,
|
|
1597
|
+
recentEvents: effectiveEvents
|
|
1598
|
+
}),
|
|
1599
|
+
userPrompt: "Please heal the memory graph."
|
|
1600
|
+
},
|
|
1601
|
+
degraded
|
|
1514
1602
|
};
|
|
1515
1603
|
}
|
|
1516
1604
|
return {
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1605
|
+
prompts: {
|
|
1606
|
+
systemPrompt: template,
|
|
1607
|
+
userPrompt: `Heal Candidates:
|
|
1608
|
+
${JSON.stringify(shapedCandidates, null, 2)}
|
|
1520
1609
|
Document Anchors (DO NOT MODIFY OR DELETE):
|
|
1521
|
-
${JSON.stringify(
|
|
1610
|
+
${JSON.stringify(effectiveAnchors, null, 2)}
|
|
1522
1611
|
All Tasks:
|
|
1523
|
-
${JSON.stringify(
|
|
1612
|
+
${JSON.stringify(effectiveTasks, null, 2)}
|
|
1524
1613
|
Recent Events:
|
|
1525
|
-
${JSON.stringify(
|
|
1614
|
+
${JSON.stringify(effectiveEvents, null, 2)}
|
|
1526
1615
|
The following document anchors are provided for contradiction detection only. Do not include them in \`downgraded\`, \`deleted\`, or \`newFacts\`.`
|
|
1616
|
+
},
|
|
1617
|
+
degraded
|
|
1527
1618
|
};
|
|
1528
1619
|
}
|
|
1529
1620
|
buildOntologyBackfillPrompt(facts, runtimeOverride, ontologyContext) {
|
|
@@ -1543,6 +1634,36 @@ ${JSON.stringify(facts, null, 2)}`
|
|
|
1543
1634
|
};
|
|
1544
1635
|
}
|
|
1545
1636
|
};
|
|
1637
|
+
function applyBodyTruncation(candidates, attemptLevel, bodyTruncationChars) {
|
|
1638
|
+
if (attemptLevel < 3) {
|
|
1639
|
+
return { shapedCandidates: candidates, degraded: [] };
|
|
1640
|
+
}
|
|
1641
|
+
const shapedCandidates = [];
|
|
1642
|
+
const degraded = [];
|
|
1643
|
+
for (const c of candidates) {
|
|
1644
|
+
if (typeof c !== "object" || c === null) {
|
|
1645
|
+
shapedCandidates.push(c);
|
|
1646
|
+
continue;
|
|
1647
|
+
}
|
|
1648
|
+
const fact = c;
|
|
1649
|
+
const body = typeof fact.body === "string" ? fact.body : "";
|
|
1650
|
+
if (body.length <= bodyTruncationChars) {
|
|
1651
|
+
shapedCandidates.push(c);
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
if (typeof fact.id !== "string") {
|
|
1655
|
+
shapedCandidates.push(c);
|
|
1656
|
+
continue;
|
|
1657
|
+
}
|
|
1658
|
+
const originalBodyChars = body.length;
|
|
1659
|
+
const prefix = safeSlice(body, 0, bodyTruncationChars);
|
|
1660
|
+
const truncatedBodyChars = prefix.length;
|
|
1661
|
+
const truncated = `${prefix}\u2026[truncated at ${truncatedBodyChars} chars, original was ${originalBodyChars}]`;
|
|
1662
|
+
shapedCandidates.push({ ...fact, body: truncated });
|
|
1663
|
+
degraded.push({ id: fact.id, originalBodyChars, truncatedBodyChars });
|
|
1664
|
+
}
|
|
1665
|
+
return { shapedCandidates, degraded };
|
|
1666
|
+
}
|
|
1546
1667
|
|
|
1547
1668
|
// src/utils/chunkingDefaults.ts
|
|
1548
1669
|
var DEFAULT_MAX_CHUNK_LENGTH = 12e3;
|
|
@@ -2197,11 +2318,24 @@ var TRUNCATION_PATTERNS = [
|
|
|
2197
2318
|
/finish[_ ]?reason/i
|
|
2198
2319
|
];
|
|
2199
2320
|
var EXCEEDS_LIMIT_PATTERN = /exceed[a-z]*[^.]{0,40}\b(model|context)?[ _-]?limit/i;
|
|
2321
|
+
function getErrorMessage(err) {
|
|
2322
|
+
try {
|
|
2323
|
+
return err instanceof Error ? err.message : String(err ?? "");
|
|
2324
|
+
} catch {
|
|
2325
|
+
return void 0;
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2200
2328
|
function isTruncationError(err) {
|
|
2201
|
-
const message =
|
|
2329
|
+
const message = getErrorMessage(err);
|
|
2330
|
+
if (message === void 0) return false;
|
|
2202
2331
|
if (EXCEEDS_LIMIT_PATTERN.test(message)) return false;
|
|
2203
2332
|
return TRUNCATION_PATTERNS.some((pattern) => pattern.test(message));
|
|
2204
2333
|
}
|
|
2334
|
+
function isConfigError(err) {
|
|
2335
|
+
const message = getErrorMessage(err);
|
|
2336
|
+
if (message === void 0) return false;
|
|
2337
|
+
return EXCEEDS_LIMIT_PATTERN.test(message);
|
|
2338
|
+
}
|
|
2205
2339
|
function initialBatchSize(maxOutputTokens) {
|
|
2206
2340
|
if (!maxOutputTokens || !Number.isFinite(maxOutputTokens) || maxOutputTokens <= 0) {
|
|
2207
2341
|
return DEFAULT_BATCH_SIZE;
|
|
@@ -2243,14 +2377,18 @@ async function runBatched(args) {
|
|
|
2243
2377
|
const single = candidate.slice(0, 1);
|
|
2244
2378
|
return { batch: single, prompts: await buildPrompt(single) };
|
|
2245
2379
|
};
|
|
2246
|
-
const onFailure = async (batch, err) => {
|
|
2247
|
-
if (batch.length
|
|
2248
|
-
if (
|
|
2249
|
-
|
|
2380
|
+
const onFailure = async (batch, err, attemptLevel, fromCall) => {
|
|
2381
|
+
if (batch.length === 1) {
|
|
2382
|
+
if (fromCall && isTruncationError(err) && attemptLevel < 3) {
|
|
2383
|
+
await attempt(batch, void 0, attemptLevel + 1);
|
|
2384
|
+
} else {
|
|
2385
|
+
const reason = fromCall && !isTruncationError(err) && !isConfigError(err) ? "call_error" : "non_convergent";
|
|
2386
|
+
skipped.push({ item: batch[0], reason });
|
|
2250
2387
|
onSkip?.(batch[0], err);
|
|
2251
2388
|
}
|
|
2252
2389
|
return;
|
|
2253
2390
|
}
|
|
2391
|
+
if (fromCall && !isTruncationError(err)) throw err;
|
|
2254
2392
|
const mid = Math.ceil(batch.length / 2);
|
|
2255
2393
|
if (mid < batchSize) batchSize = mid;
|
|
2256
2394
|
let i = 0;
|
|
@@ -2261,23 +2399,22 @@ async function runBatched(args) {
|
|
|
2261
2399
|
i += trimmed.batch.length;
|
|
2262
2400
|
}
|
|
2263
2401
|
};
|
|
2264
|
-
const attempt = async (batch, prebuilt) => {
|
|
2402
|
+
const attempt = async (batch, prebuilt, attemptLevel = 0) => {
|
|
2265
2403
|
if (batch.length === 0) return;
|
|
2266
|
-
const prompts = prebuilt
|
|
2404
|
+
const prompts = prebuilt && attemptLevel === 0 ? prebuilt : await buildPrompt(batch, attemptLevel);
|
|
2267
2405
|
batches++;
|
|
2268
2406
|
let responseText;
|
|
2269
2407
|
try {
|
|
2270
2408
|
responseText = await call(prompts);
|
|
2271
2409
|
} catch (err) {
|
|
2272
|
-
|
|
2273
|
-
await onFailure(batch, err);
|
|
2410
|
+
await onFailure(batch, err, attemptLevel, true);
|
|
2274
2411
|
return;
|
|
2275
2412
|
}
|
|
2276
2413
|
let result;
|
|
2277
2414
|
try {
|
|
2278
2415
|
result = parse(responseText, batch);
|
|
2279
2416
|
} catch (err) {
|
|
2280
|
-
await onFailure(batch, err);
|
|
2417
|
+
await onFailure(batch, err, attemptLevel, false);
|
|
2281
2418
|
return;
|
|
2282
2419
|
}
|
|
2283
2420
|
results.push(result);
|
|
@@ -2286,7 +2423,7 @@ async function runBatched(args) {
|
|
|
2286
2423
|
while (index < items.length) {
|
|
2287
2424
|
const { batch, prompts } = await trim(items.slice(index, index + batchSize));
|
|
2288
2425
|
index += batch.length;
|
|
2289
|
-
await attempt(batch, prompts);
|
|
2426
|
+
await attempt(batch, prompts, 0);
|
|
2290
2427
|
}
|
|
2291
2428
|
return { results, skipped, batches };
|
|
2292
2429
|
}
|
|
@@ -2297,7 +2434,6 @@ var MIN_TOKENS_TO_QUALIFY = 3;
|
|
|
2297
2434
|
var ONTOLOGY_BACKFILL_BATCH_SIZE = 25;
|
|
2298
2435
|
var ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS = 4e4;
|
|
2299
2436
|
var ONTOLOGY_BACKFILL_RECHECK_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
2300
|
-
var HEAL_MAX_ANCHORS = 50;
|
|
2301
2437
|
var HEAL_ANCHOR_SEARCH_OVERFETCH = 4;
|
|
2302
2438
|
var HEAL_MAX_PROMPT_CHARS = 4e4;
|
|
2303
2439
|
var HEAL_BATCH_SIZE = 25;
|
|
@@ -2305,7 +2441,12 @@ var HEAL_RECHECK_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
2305
2441
|
var SKIP_ERROR_LOG_CHARS = 4096;
|
|
2306
2442
|
var formatSkipError = (err) => {
|
|
2307
2443
|
let base;
|
|
2308
|
-
|
|
2444
|
+
let isErrorLike = false;
|
|
2445
|
+
try {
|
|
2446
|
+
isErrorLike = err instanceof Error;
|
|
2447
|
+
} catch {
|
|
2448
|
+
}
|
|
2449
|
+
if (isErrorLike || typeof err !== "object" && typeof err !== "function") {
|
|
2309
2450
|
base = safeErrorToString(err);
|
|
2310
2451
|
} else {
|
|
2311
2452
|
try {
|
|
@@ -2723,6 +2864,10 @@ var MaintenanceService = class {
|
|
|
2723
2864
|
if (!Number.isInteger(batchSize) || batchSize < 1) {
|
|
2724
2865
|
throw new Error("Invalid batchSize: must be an integer >= 1");
|
|
2725
2866
|
}
|
|
2867
|
+
const bodyTruncationChars = options?.bodyTruncationChars ?? HEAL_MAX_FACT_BODY_CHARS_L3;
|
|
2868
|
+
if (!Number.isInteger(bodyTruncationChars) || bodyTruncationChars < 1) {
|
|
2869
|
+
throw new Error("Invalid bodyTruncationChars: must be an integer >= 1");
|
|
2870
|
+
}
|
|
2726
2871
|
const now = Date.now();
|
|
2727
2872
|
const recheckCutoff = now - HEAL_RECHECK_MS;
|
|
2728
2873
|
const orphanAfterDays = this.options.config?.orphanAfterDays !== void 0 ? this.options.config?.orphanAfterDays : 30;
|
|
@@ -2763,29 +2908,44 @@ var MaintenanceService = class {
|
|
|
2763
2908
|
downgraded: staleDowngradedIds.length,
|
|
2764
2909
|
deleted: orphanedIds.length,
|
|
2765
2910
|
newFactsCreated: 0,
|
|
2766
|
-
skipped:
|
|
2911
|
+
skipped: [],
|
|
2912
|
+
degraded: [],
|
|
2767
2913
|
remaining: counts2.eligible,
|
|
2768
2914
|
deferred: counts2.deferred
|
|
2769
2915
|
};
|
|
2770
2916
|
}
|
|
2771
|
-
const allTasks = await this.taskRepo.findAllPending([entityId]);
|
|
2917
|
+
const allTasks = await this.taskRepo.findAllPending([entityId], HEAL_MAX_TASKS);
|
|
2772
2918
|
const recentEvents = await this.eventRepo.getRecent(entityId, 20);
|
|
2773
2919
|
const toPromptShape = (f) => {
|
|
2774
2920
|
const { embedding: _embedding, embedding_blob: _blob, ...rest } = f;
|
|
2775
2921
|
return { ...rest, tags: typeof rest.tags === "string" ? JSON.parse(rest.tags) : rest.tags };
|
|
2776
2922
|
};
|
|
2777
2923
|
const anchorCache = /* @__PURE__ */ new Map();
|
|
2924
|
+
const degraded = [];
|
|
2778
2925
|
const outcome = await runBatched({
|
|
2779
2926
|
items: healCandidates,
|
|
2780
|
-
buildPrompt: async (batch) => {
|
|
2781
|
-
const documentAnchors = await this._selectHealAnchors(
|
|
2782
|
-
|
|
2927
|
+
buildPrompt: async (batch, attemptLevel = 0) => {
|
|
2928
|
+
const documentAnchors = await this._selectHealAnchors(
|
|
2929
|
+
entityId,
|
|
2930
|
+
batch,
|
|
2931
|
+
// Per-batch anchor cap: `batch.length * HEAL_ANCHORS_PER_CANDIDATE` (capped at
|
|
2932
|
+
// HEAL_MAX_ANCHORS) right-sizes the anchor lookup so a 1-fact batch does
|
|
2933
|
+
// not overfetch the same 200 keyword hits a 25-fact batch once did.
|
|
2934
|
+
// buildHealPrompt applies the matching cap on its side — values must match.
|
|
2935
|
+
Math.min(HEAL_MAX_ANCHORS, batch.length * HEAL_ANCHORS_PER_CANDIDATE),
|
|
2936
|
+
anchorCache
|
|
2937
|
+
);
|
|
2938
|
+
const { prompts, degraded: batchDegraded } = await this.promptService.buildHealPrompt(
|
|
2783
2939
|
batch.map(toPromptShape),
|
|
2784
2940
|
documentAnchors,
|
|
2785
2941
|
allTasks,
|
|
2786
2942
|
recentEvents,
|
|
2787
|
-
promptOverride
|
|
2943
|
+
promptOverride,
|
|
2944
|
+
attemptLevel,
|
|
2945
|
+
bodyTruncationChars
|
|
2788
2946
|
);
|
|
2947
|
+
degraded.push(...batchDegraded);
|
|
2948
|
+
return prompts;
|
|
2789
2949
|
},
|
|
2790
2950
|
call: (prompts) => this.options.llmProvider.generateText(prompts),
|
|
2791
2951
|
parse: (responseText, batch) => {
|
|
@@ -2859,8 +3019,14 @@ var MaintenanceService = class {
|
|
|
2859
3019
|
insertedFacts.push({ id, entity_id: entityId, title: fact.title, body: fact.body, tags: JSON.stringify(fact.tags) });
|
|
2860
3020
|
healFactsForDedupe.push({ id, title: fact.title });
|
|
2861
3021
|
}
|
|
3022
|
+
const callErrorIds = new Set(
|
|
3023
|
+
outcome.skipped.filter((s) => s.reason === "call_error").map((s) => s.item.id)
|
|
3024
|
+
);
|
|
2862
3025
|
await this.entryRepo.markHealChecked(
|
|
2863
|
-
[
|
|
3026
|
+
[
|
|
3027
|
+
...healCandidates.map((f) => f.id).filter((id) => !callErrorIds.has(id)),
|
|
3028
|
+
...insertedFacts.map((f) => f.id)
|
|
3029
|
+
],
|
|
2864
3030
|
entityId,
|
|
2865
3031
|
now,
|
|
2866
3032
|
tx
|
|
@@ -2878,6 +3044,13 @@ var MaintenanceService = class {
|
|
|
2878
3044
|
await this.embeddingService.embedFact(fact);
|
|
2879
3045
|
}
|
|
2880
3046
|
this.searchService.evictCache(entityId);
|
|
3047
|
+
const skippedIds = new Set(outcome.skipped.map(({ item }) => item.id));
|
|
3048
|
+
const healedDegraded = degraded.filter((d) => !skippedIds.has(d.id));
|
|
3049
|
+
for (const d of healedDegraded) {
|
|
3050
|
+
console.warn(
|
|
3051
|
+
`[WikiMemory] heal healed under degraded context ${entityId}/${d.id}: body truncated from ${d.originalBodyChars} to ${d.truncatedBodyChars} chars`
|
|
3052
|
+
);
|
|
3053
|
+
}
|
|
2881
3054
|
let scanned = outcome.skipped.length;
|
|
2882
3055
|
for (const batchResult of outcome.results) scanned += batchResult.batch.length;
|
|
2883
3056
|
const allDowngraded = /* @__PURE__ */ new Set([...staleDowngradedIds, ...safeDowngraded]);
|
|
@@ -2888,7 +3061,8 @@ var MaintenanceService = class {
|
|
|
2888
3061
|
downgraded: allDowngraded.size,
|
|
2889
3062
|
deleted: allDeleted.size,
|
|
2890
3063
|
newFactsCreated: insertedFacts.length,
|
|
2891
|
-
skipped: outcome.skipped.
|
|
3064
|
+
skipped: outcome.skipped.map(({ item, reason }) => ({ id: item.id, reason })),
|
|
3065
|
+
degraded: healedDegraded,
|
|
2892
3066
|
remaining: counts.eligible,
|
|
2893
3067
|
deferred: counts.deferred
|
|
2894
3068
|
};
|
|
@@ -2972,7 +3146,15 @@ var MaintenanceService = class {
|
|
|
2972
3146
|
};
|
|
2973
3147
|
}
|
|
2974
3148
|
if (outcome.skipped.length > 0) {
|
|
2975
|
-
|
|
3149
|
+
const callErrorIds = new Set(
|
|
3150
|
+
outcome.skipped.filter((s) => s.reason === "call_error").map((s) => s.item.id)
|
|
3151
|
+
);
|
|
3152
|
+
await this.entryRepo.markOntologyChecked(
|
|
3153
|
+
outcome.skipped.filter(({ item }) => !callErrorIds.has(item.id)).map(({ item }) => item.id),
|
|
3154
|
+
entityId,
|
|
3155
|
+
now,
|
|
3156
|
+
this.db
|
|
3157
|
+
);
|
|
2976
3158
|
}
|
|
2977
3159
|
this.searchService.evictCache(entityId);
|
|
2978
3160
|
const counts = await this.entryRepo.countUntypedByEntityId(entityId, recheckCutoff);
|
|
@@ -3088,7 +3270,7 @@ var MaintenanceService = class {
|
|
|
3088
3270
|
* batches that reduce to the same query share one lookup. Caller-owned and
|
|
3089
3271
|
* per-pass — see the call site in doRunHeal.
|
|
3090
3272
|
*/
|
|
3091
|
-
async _selectHealAnchors(entityId, batch, cache) {
|
|
3273
|
+
async _selectHealAnchors(entityId, batch, cap = HEAL_MAX_ANCHORS, cache) {
|
|
3092
3274
|
const query = batch.map((f) => f.title).join(" ").trim();
|
|
3093
3275
|
if (!query) return [];
|
|
3094
3276
|
const cached = cache?.get(query);
|
|
@@ -3096,7 +3278,7 @@ var MaintenanceService = class {
|
|
|
3096
3278
|
const hits = this.searchService.searchKeyword(
|
|
3097
3279
|
query,
|
|
3098
3280
|
[entityId],
|
|
3099
|
-
|
|
3281
|
+
cap * HEAL_ANCHOR_SEARCH_OVERFETCH
|
|
3100
3282
|
);
|
|
3101
3283
|
const hitIds = hits.map((h) => h.id);
|
|
3102
3284
|
const anchors = [];
|
|
@@ -3107,7 +3289,7 @@ var MaintenanceService = class {
|
|
|
3107
3289
|
const row = byId.get(id);
|
|
3108
3290
|
if (!row) continue;
|
|
3109
3291
|
anchors.push(row);
|
|
3110
|
-
if (anchors.length >=
|
|
3292
|
+
if (anchors.length >= cap) break;
|
|
3111
3293
|
}
|
|
3112
3294
|
}
|
|
3113
3295
|
cache?.set(query, anchors);
|
|
@@ -3997,7 +4179,12 @@ var RetrievalService = class {
|
|
|
3997
4179
|
}
|
|
3998
4180
|
}
|
|
3999
4181
|
} catch (rankerErr) {
|
|
4000
|
-
|
|
4182
|
+
let isErrorLike = false;
|
|
4183
|
+
try {
|
|
4184
|
+
isErrorLike = rankerErr instanceof Error;
|
|
4185
|
+
} catch {
|
|
4186
|
+
}
|
|
4187
|
+
const rankerError = isErrorLike ? rankerErr : new Error(safeErrorToString(rankerErr));
|
|
4001
4188
|
const policy = this.options.vectorRankerFallback ?? "js-cosine";
|
|
4002
4189
|
this.options.onVectorRankerFallback?.({
|
|
4003
4190
|
error: this._sanitizeRankerError(rankerError),
|
|
@@ -4109,12 +4296,21 @@ var RetrievalService = class {
|
|
|
4109
4296
|
}
|
|
4110
4297
|
}
|
|
4111
4298
|
} catch (err) {
|
|
4112
|
-
|
|
4299
|
+
let isErrorLike = false;
|
|
4300
|
+
try {
|
|
4301
|
+
isErrorLike = err instanceof Error;
|
|
4302
|
+
} catch {
|
|
4303
|
+
}
|
|
4304
|
+
const error = isErrorLike ? err : new Error(safeErrorToString(err));
|
|
4113
4305
|
if (rankerShouldRethrow) {
|
|
4114
4306
|
throw error;
|
|
4115
4307
|
}
|
|
4116
4308
|
if (pendingRankerFallbackError) {
|
|
4117
|
-
|
|
4309
|
+
try {
|
|
4310
|
+
error.cause = pendingRankerFallbackError;
|
|
4311
|
+
} catch {
|
|
4312
|
+
this.options.onRetrievalFallback?.(pendingRankerFallbackError);
|
|
4313
|
+
}
|
|
4118
4314
|
pendingRankerFallbackError = void 0;
|
|
4119
4315
|
}
|
|
4120
4316
|
this.options.onRetrievalFallback?.(error);
|
|
@@ -4370,6 +4566,6 @@ var WriteService = class {
|
|
|
4370
4566
|
}
|
|
4371
4567
|
};
|
|
4372
4568
|
|
|
4373
|
-
export { BaseRepository, DEFAULT_CHUNK_OVERLAP, DEFAULT_MAX_CHUNK_LENGTH, EmbeddingService, HEAL_BATCH_SIZE, HEAL_RECHECK_MS, HOOK_TIMEOUT_MARKER, ImportExportService, IngestionService, JobManager, MaintenanceService, MetadataRepository, ONTOLOGY_BACKFILL_BATCH_SIZE, ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, ONTOLOGY_BACKFILL_RECHECK_MS, ONTOLOGY_BACKFILL_SYSTEM_PROMPT, PromptService, PrunePartialFailureError, RetrievalService, SearchService, WikiBusyError, WikiDuplicateHashError, WikiIngestEmptyError, WikiParseError, WikiSourceRefHashCollision, WikiStrictOntologyViolation, WikiTransactionError, WriteService, __privateAdd, __privateGet, __privateSet, chunkText, configureRandomSource, emptyManifest, entitySummaryMetaKey, extractSqliteCode, generateId, normalizeSourceHash, normalizeSourceRef, normalizeTitleKey, parseEmbedding, resolveEdgeDefinitions, resolveNodeType, safeSlice, validateInlineEdges, validateManifest };
|
|
4374
|
-
//# sourceMappingURL=chunk-
|
|
4375
|
-
//# sourceMappingURL=chunk-
|
|
4569
|
+
export { BaseRepository, DEFAULT_CHUNK_OVERLAP, DEFAULT_MAX_CHUNK_LENGTH, EmbeddingService, HEAL_ANCHORS_PER_CANDIDATE, HEAL_BATCH_SIZE, HEAL_MAX_FACT_BODY_CHARS_L3, HEAL_MAX_TASKS, HEAL_RECHECK_MS, HOOK_TIMEOUT_MARKER, ImportExportService, IngestionService, JobManager, MaintenanceService, MetadataRepository, ONTOLOGY_BACKFILL_BATCH_SIZE, ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, ONTOLOGY_BACKFILL_RECHECK_MS, ONTOLOGY_BACKFILL_SYSTEM_PROMPT, PromptService, PrunePartialFailureError, RetrievalService, SearchService, WikiBusyError, WikiDuplicateHashError, WikiIngestEmptyError, WikiParseError, WikiSourceRefHashCollision, WikiStrictOntologyViolation, WikiTransactionError, WriteService, __privateAdd, __privateGet, __privateSet, chunkText, configureRandomSource, emptyManifest, entitySummaryMetaKey, extractSqliteCode, generateId, normalizeSourceHash, normalizeSourceRef, normalizeTitleKey, parseEmbedding, resolveEdgeDefinitions, resolveNodeType, safeSlice, validateInlineEdges, validateManifest };
|
|
4570
|
+
//# sourceMappingURL=chunk-HREQ6F6Z.mjs.map
|
|
4571
|
+
//# sourceMappingURL=chunk-HREQ6F6Z.mjs.map
|