@equationalapplications/core-llm-wiki 7.4.0 → 7.5.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 +41 -0
- package/dist/{chunk-G5OR2VWD.mjs → chunk-3P7FAKJA.mjs} +141 -9
- package/dist/chunk-3P7FAKJA.mjs.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +139 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/{testing-Dmh1kfkd.d.mts → testing-ClpOUiLI.d.mts} +66 -1
- package/dist/{testing-Dmh1kfkd.d.ts → testing-ClpOUiLI.d.ts} +66 -1
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +139 -7
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-G5OR2VWD.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-
|
|
2
|
-
export { C as ChunkFailure, D as DegradedRecord,
|
|
1
|
+
import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-ClpOUiLI.mjs';
|
|
2
|
+
export { C as ChunkFailure, d as ClassifierAnswer, e as ClassifierQuestion, f as ClassifyRequest, g as ClassifyResponse, D as DegradedRecord, h as DraftPage, E as EmbedFactResult, i as EmbedFailureKind, j as EmbeddingMarkerKind, k as EntityStatus, l as ExtractedFact, m as ExtractedFactEdge, n as ExtractedFactWithOntology, o as ExtractedTask, p as GraphTraversalOptions, H as HEAL_BATCH_SIZE, q as HEAL_RECHECK_MS, r as HOOK_TIMEOUT_MARKER, s as HealResult, I as IngestDocumentResult, L as LLMProvider, O as ONTOLOGY_BACKFILL_BATCH_SIZE, t as ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, u as ONTOLOGY_BACKFILL_RECHECK_MS, v as OntologyBackfillResult, w as OntologyConfig, x as OntologyEdgeType, y as OntologyManifest, z as OntologyMode, A as OntologyNodeType, B as OntologyPromptContext, J as OntologyUpdates, P as PromptOverrides, K as PromptService, N as PrunePartialFailureError, Q as ReembedResult, V as VectorRanker, T as VectorRankerFallback, U as VectorRankerRankArgs, X as VectorRankerSemanticResult, Y as WikiBusyError, Z as WikiBusyOperation, _ as WikiCheckpoint, $ as WikiConfig, a0 as WikiDiagnostic, a1 as WikiDiagnosticCode, a2 as WikiDiagnosticDetail, a3 as WikiDiagnosticOperation, a4 as WikiDiagnosticSeverity, a5 as WikiDiagnosticTrigger, a6 as WikiDraftNotFound, a7 as WikiDuplicateHashError, a8 as WikiEdge, a9 as WikiEvent, aa as WikiFact, ab as WikiGraphNodeOwnershipConflict, ac as WikiIngestEmptyError, ad as WikiInvalidReadOptions, ae as WikiMemoryTestAccess, af as WikiOutboxEvent, ag as WikiParseError, ah as WikiSourceRefHashCollision, ai as WikiStrictOntologyViolation, aj as WikiTask, ak as WikiTransactionError, al as validateManifest } from './testing-ClpOUiLI.mjs';
|
|
3
3
|
import { OkfFile } from '@equationalapplications/core-okf';
|
|
4
4
|
import 'minisearch';
|
|
5
5
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-
|
|
2
|
-
export { C as ChunkFailure, D as DegradedRecord,
|
|
1
|
+
import { M as MemoryBundle, F as FormatContextOptions, G as GraphNeighborhood, a as MemoryDump, b as FormattedMemoryDump, R as ReadOptions, S as SQLiteAdapter, W as WikiOptions, c as WikiMemory } from './testing-ClpOUiLI.js';
|
|
2
|
+
export { C as ChunkFailure, d as ClassifierAnswer, e as ClassifierQuestion, f as ClassifyRequest, g as ClassifyResponse, D as DegradedRecord, h as DraftPage, E as EmbedFactResult, i as EmbedFailureKind, j as EmbeddingMarkerKind, k as EntityStatus, l as ExtractedFact, m as ExtractedFactEdge, n as ExtractedFactWithOntology, o as ExtractedTask, p as GraphTraversalOptions, H as HEAL_BATCH_SIZE, q as HEAL_RECHECK_MS, r as HOOK_TIMEOUT_MARKER, s as HealResult, I as IngestDocumentResult, L as LLMProvider, O as ONTOLOGY_BACKFILL_BATCH_SIZE, t as ONTOLOGY_BACKFILL_MAX_PROMPT_CHARS, u as ONTOLOGY_BACKFILL_RECHECK_MS, v as OntologyBackfillResult, w as OntologyConfig, x as OntologyEdgeType, y as OntologyManifest, z as OntologyMode, A as OntologyNodeType, B as OntologyPromptContext, J as OntologyUpdates, P as PromptOverrides, K as PromptService, N as PrunePartialFailureError, Q as ReembedResult, V as VectorRanker, T as VectorRankerFallback, U as VectorRankerRankArgs, X as VectorRankerSemanticResult, Y as WikiBusyError, Z as WikiBusyOperation, _ as WikiCheckpoint, $ as WikiConfig, a0 as WikiDiagnostic, a1 as WikiDiagnosticCode, a2 as WikiDiagnosticDetail, a3 as WikiDiagnosticOperation, a4 as WikiDiagnosticSeverity, a5 as WikiDiagnosticTrigger, a6 as WikiDraftNotFound, a7 as WikiDuplicateHashError, a8 as WikiEdge, a9 as WikiEvent, aa as WikiFact, ab as WikiGraphNodeOwnershipConflict, ac as WikiIngestEmptyError, ad as WikiInvalidReadOptions, ae as WikiMemoryTestAccess, af as WikiOutboxEvent, ag as WikiParseError, ah as WikiSourceRefHashCollision, ai as WikiStrictOntologyViolation, aj as WikiTask, ak as WikiTransactionError, al as validateManifest } from './testing-ClpOUiLI.js';
|
|
3
3
|
import { OkfFile } from '@equationalapplications/core-okf';
|
|
4
4
|
import 'minisearch';
|
|
5
5
|
|
package/dist/index.js
CHANGED
|
@@ -5112,6 +5112,51 @@ var IngestionService = class {
|
|
|
5112
5112
|
}
|
|
5113
5113
|
};
|
|
5114
5114
|
|
|
5115
|
+
// src/utils/classifier.ts
|
|
5116
|
+
var isUnit = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 && v <= 1;
|
|
5117
|
+
function validateClassifierAnswer(response, key, question) {
|
|
5118
|
+
try {
|
|
5119
|
+
if (response === null || typeof response !== "object") return { ok: false, reason: "malformed" };
|
|
5120
|
+
const answers = response.answers;
|
|
5121
|
+
if (answers === null || typeof answers !== "object") return { ok: false, reason: "missing_answer" };
|
|
5122
|
+
if (!Object.prototype.hasOwnProperty.call(answers, key)) return { ok: false, reason: "missing_answer" };
|
|
5123
|
+
const raw = answers[key];
|
|
5124
|
+
if (raw === null || typeof raw !== "object") return { ok: false, reason: "missing_answer" };
|
|
5125
|
+
const a = raw;
|
|
5126
|
+
if (a.kind !== question.kind) return { ok: false, reason: "kind_mismatch" };
|
|
5127
|
+
if (question.kind === "choice") {
|
|
5128
|
+
if (typeof a.choice !== "string" || !question.options.includes(a.choice)) return { ok: false, reason: "choice_not_offered" };
|
|
5129
|
+
if (!isUnit(a.confidence)) return { ok: false, reason: "invalid_probability" };
|
|
5130
|
+
const probs = a.probabilities;
|
|
5131
|
+
if (probs === null || typeof probs !== "object" || Array.isArray(probs)) return { ok: false, reason: "invalid_probability" };
|
|
5132
|
+
const probabilities = {};
|
|
5133
|
+
for (const [k, v] of Object.entries(probs)) {
|
|
5134
|
+
if (!isUnit(v)) return { ok: false, reason: "invalid_probability" };
|
|
5135
|
+
probabilities[k] = v;
|
|
5136
|
+
}
|
|
5137
|
+
return { ok: true, answer: { kind: "choice", choice: a.choice, confidence: a.confidence, probabilities } };
|
|
5138
|
+
}
|
|
5139
|
+
if (question.kind === "binary") {
|
|
5140
|
+
if (!isUnit(a.probability)) return { ok: false, reason: "invalid_probability" };
|
|
5141
|
+
return { ok: true, answer: { kind: "binary", probability: a.probability } };
|
|
5142
|
+
}
|
|
5143
|
+
const maxScore = question.levels.length - 1;
|
|
5144
|
+
if (typeof a.score !== "number" || !Number.isFinite(a.score) || a.score < 0 || a.score > maxScore) {
|
|
5145
|
+
return { ok: false, reason: "score_out_of_range" };
|
|
5146
|
+
}
|
|
5147
|
+
if (!isUnit(a.confidence)) return { ok: false, reason: "invalid_probability" };
|
|
5148
|
+
if (!Array.isArray(a.probabilities) || !a.probabilities.every(isUnit)) return { ok: false, reason: "invalid_probability" };
|
|
5149
|
+
return { ok: true, answer: { kind: "score", score: a.score, confidence: a.confidence, probabilities: a.probabilities.slice() } };
|
|
5150
|
+
} catch {
|
|
5151
|
+
return { ok: false, reason: "malformed" };
|
|
5152
|
+
}
|
|
5153
|
+
}
|
|
5154
|
+
function classifierStateForFact(fact) {
|
|
5155
|
+
const parts = [fact.title, fact.body];
|
|
5156
|
+
if (Array.isArray(fact.tags) && fact.tags.length > 0) parts.push(`Tags: ${fact.tags.join(", ")}`);
|
|
5157
|
+
return parts.join("\n\n");
|
|
5158
|
+
}
|
|
5159
|
+
|
|
5115
5160
|
// src/services/BoundedLlmCall.ts
|
|
5116
5161
|
var DEFAULT_BATCH_SIZE = 10;
|
|
5117
5162
|
var ESTIMATED_OUTPUT_TOKENS_PER_ITEM = 150;
|
|
@@ -5994,7 +6039,7 @@ var MaintenanceService = class {
|
|
|
5994
6039
|
if (!ontologyService) {
|
|
5995
6040
|
return { ...zeroed, remaining: 0, deferred: 0 };
|
|
5996
6041
|
}
|
|
5997
|
-
const { mode } = await ontologyService.getEffectiveState(entityId);
|
|
6042
|
+
const { mode, manifest: effectiveManifest } = await ontologyService.getEffectiveState(entityId);
|
|
5998
6043
|
if (mode === "off") {
|
|
5999
6044
|
const counts2 = await this.entryRepo.countUntypedByEntityId(entityId, recheckCutoff);
|
|
6000
6045
|
return { ...zeroed, remaining: 0, deferred: counts2.deferred };
|
|
@@ -6004,6 +6049,14 @@ var MaintenanceService = class {
|
|
|
6004
6049
|
const counts2 = await this.entryRepo.countUntypedByEntityId(entityId, recheckCutoff);
|
|
6005
6050
|
return { ...zeroed, remaining: counts2.eligible, deferred: counts2.deferred };
|
|
6006
6051
|
}
|
|
6052
|
+
const classifierMode = options?.classifier ?? this.options.config?.ontology?.backfillClassifier ?? "llm";
|
|
6053
|
+
const classify = this.options.llmProvider.classify;
|
|
6054
|
+
if (classifierMode === "auto" && typeof classify === "function") {
|
|
6055
|
+
const slugs = effectiveManifest.node_types.map((n) => n.type);
|
|
6056
|
+
if (slugs.length > 0 && slugs.length <= 255) {
|
|
6057
|
+
return this._runClassifierBackfill(entityId, candidates, effectiveManifest, now, recheckCutoff);
|
|
6058
|
+
}
|
|
6059
|
+
}
|
|
6007
6060
|
const ontologyContext = await ontologyService.buildPromptContext(entityId);
|
|
6008
6061
|
const toPromptShape = (f) => ({ id: f.id, title: f.title, body: f.body, tags: f.tags });
|
|
6009
6062
|
const buildPrompt = (facts) => this.promptService.buildOntologyBackfillPrompt(
|
|
@@ -6082,6 +6135,87 @@ var MaintenanceService = class {
|
|
|
6082
6135
|
deferred: counts.deferred
|
|
6083
6136
|
};
|
|
6084
6137
|
}
|
|
6138
|
+
/**
|
|
6139
|
+
* Classifier-mode backfill (spec §7.3): one `choice` question per untyped
|
|
6140
|
+
* fact over the effective manifest's node-type slugs. Accepted answers go
|
|
6141
|
+
* through `_applyOntologyBackfillBatch` exactly like LLM classifications.
|
|
6142
|
+
* No edges are proposed.
|
|
6143
|
+
*/
|
|
6144
|
+
async _runClassifierBackfill(entityId, candidates, manifest, now, recheckCutoff) {
|
|
6145
|
+
const provider = this.options.llmProvider;
|
|
6146
|
+
const rawMin = this.options.config?.ontology?.classifyMinConfidence;
|
|
6147
|
+
const minConfidence = typeof rawMin === "number" && Number.isFinite(rawMin) && rawMin >= 0 && rawMin <= 1 ? rawMin : 0.5;
|
|
6148
|
+
const rawConcurrency = this.options.config?.chunkConcurrency ?? 1;
|
|
6149
|
+
const concurrency = Number.isFinite(rawConcurrency) && rawConcurrency >= 1 ? Math.floor(rawConcurrency) : 1;
|
|
6150
|
+
const question = {
|
|
6151
|
+
kind: "choice",
|
|
6152
|
+
options: manifest.node_types.map((n) => n.type),
|
|
6153
|
+
instructions: "Choose the ontology node type that best describes this fact.\n" + manifest.node_types.map((n) => `- ${n.type}: ${n.description}`).join("\n")
|
|
6154
|
+
};
|
|
6155
|
+
const outcomes = await withConcurrency(
|
|
6156
|
+
candidates.map((fact) => async () => {
|
|
6157
|
+
let response;
|
|
6158
|
+
try {
|
|
6159
|
+
response = await provider.classify({ state: classifierStateForFact(fact), questions: { okf_type: question } });
|
|
6160
|
+
} catch {
|
|
6161
|
+
return { fact, kind: "threw" };
|
|
6162
|
+
}
|
|
6163
|
+
const checked = validateClassifierAnswer(response, "okf_type", question);
|
|
6164
|
+
if (!checked.ok) return { fact, kind: "invalid", reason: checked.reason };
|
|
6165
|
+
if (checked.answer.kind !== "choice") return { fact, kind: "invalid", reason: "kind_mismatch" };
|
|
6166
|
+
if (checked.answer.confidence < minConfidence) return { fact, kind: "low_confidence" };
|
|
6167
|
+
return { fact, kind: "accepted", okfType: checked.answer.choice };
|
|
6168
|
+
}),
|
|
6169
|
+
concurrency
|
|
6170
|
+
);
|
|
6171
|
+
const attempted = outcomes.filter((o) => o.kind !== "threw").map((o) => o.fact);
|
|
6172
|
+
const skipped = outcomes.length - attempted.length;
|
|
6173
|
+
const classifications = outcomes.filter((o) => o.kind === "accepted").map((o) => ({ id: o.fact.id, okf_type: o.okfType }));
|
|
6174
|
+
const invalidCount = outcomes.filter((o) => o.kind === "invalid").length;
|
|
6175
|
+
let typed = 0;
|
|
6176
|
+
let failedValidation = 0;
|
|
6177
|
+
let edgesAdded = 0;
|
|
6178
|
+
let aborted = false;
|
|
6179
|
+
if (attempted.length > 0) {
|
|
6180
|
+
const applied = await this._applyOntologyBackfillBatch(
|
|
6181
|
+
entityId,
|
|
6182
|
+
{ batch: attempted, classifications, ontologyUpdates: void 0 },
|
|
6183
|
+
now
|
|
6184
|
+
);
|
|
6185
|
+
aborted = applied.abortedOntologyOff;
|
|
6186
|
+
if (!aborted) {
|
|
6187
|
+
typed = applied.typed;
|
|
6188
|
+
failedValidation = invalidCount + applied.failedValidation;
|
|
6189
|
+
edgesAdded = applied.edgesAdded;
|
|
6190
|
+
}
|
|
6191
|
+
}
|
|
6192
|
+
const diagBuffer = new DiagnosticBuffer();
|
|
6193
|
+
const diagBase = { entityId, operation: "ontologyBackfill", trigger: "call" };
|
|
6194
|
+
for (const o of outcomes) {
|
|
6195
|
+
if (o.kind === "low_confidence") {
|
|
6196
|
+
diagBuffer.push({ ...diagBase, code: "classification_low_confidence", detail: { factId: o.fact.id, reason: "below_threshold" } });
|
|
6197
|
+
} else if (o.kind === "invalid") {
|
|
6198
|
+
diagBuffer.push({ ...diagBase, code: "classification_invalid", detail: { factId: o.fact.id, reason: o.reason } });
|
|
6199
|
+
} else if (o.kind === "threw") {
|
|
6200
|
+
diagBuffer.push({ ...diagBase, code: "classification_invalid", detail: { factId: o.fact.id, reason: "classify_threw" } });
|
|
6201
|
+
}
|
|
6202
|
+
}
|
|
6203
|
+
diagBuffer.flush(this.options);
|
|
6204
|
+
const counts = await this.entryRepo.countUntypedByEntityId(entityId, recheckCutoff);
|
|
6205
|
+
if (aborted) {
|
|
6206
|
+
return { scanned: 0, typed: 0, failedValidation: 0, edgesAdded: 0, skipped, remaining: 0, deferred: counts.deferred };
|
|
6207
|
+
}
|
|
6208
|
+
this.searchService.evictCache(entityId);
|
|
6209
|
+
return {
|
|
6210
|
+
scanned: candidates.length,
|
|
6211
|
+
typed,
|
|
6212
|
+
failedValidation,
|
|
6213
|
+
edgesAdded,
|
|
6214
|
+
skipped,
|
|
6215
|
+
remaining: counts.eligible,
|
|
6216
|
+
deferred: counts.deferred
|
|
6217
|
+
};
|
|
6218
|
+
}
|
|
6085
6219
|
/**
|
|
6086
6220
|
* Applies one parsed backfill batch in its own transaction. Per-batch rather
|
|
6087
6221
|
* than one transaction for the pass, so mergeEmergentUpdates semantics and
|
|
@@ -6785,8 +6919,7 @@ var EmbeddingService = class {
|
|
|
6785
6919
|
}
|
|
6786
6920
|
}
|
|
6787
6921
|
async tryEmbedFact(fact, ctx) {
|
|
6788
|
-
|
|
6789
|
-
if (typeof embedFn !== "function") return { ok: false, kind: "no_provider" };
|
|
6922
|
+
if (typeof this.options.llmProvider.embed !== "function") return { ok: false, kind: "no_provider" };
|
|
6790
6923
|
let tagsStr;
|
|
6791
6924
|
if (Array.isArray(fact.tags)) {
|
|
6792
6925
|
tagsStr = fact.tags.join(" ");
|
|
@@ -6803,7 +6936,7 @@ var EmbeddingService = class {
|
|
|
6803
6936
|
const text = clip(`${fact.title} ${fact.body} ${tagsStr}`.trim(), maxEmbedChars);
|
|
6804
6937
|
let float32Vector;
|
|
6805
6938
|
try {
|
|
6806
|
-
const vector = await
|
|
6939
|
+
const vector = await this.options.llmProvider.embed(text);
|
|
6807
6940
|
if (vector.length === 0 || !vector.every((v) => typeof v === "number" && isFinite(v))) {
|
|
6808
6941
|
console.warn(`[WikiMemory] embedFact: embed() returned an invalid vector for ${fact.id}; skipping.`);
|
|
6809
6942
|
this.reportEmbed(ctx, fact, "embedding_failed", "invalid_vector");
|
|
@@ -7062,7 +7195,6 @@ var RetrievalService = class {
|
|
|
7062
7195
|
const hybridWeight = options?.hybridWeight ?? config?.hybridWeight;
|
|
7063
7196
|
const weight = hybridWeight !== void 0 && !Number.isNaN(hybridWeight) ? Math.max(0, Math.min(1, hybridWeight)) : void 0;
|
|
7064
7197
|
const skipEmbed = weight === 0;
|
|
7065
|
-
const embedFn = this.options.llmProvider.embed;
|
|
7066
7198
|
let facts = [];
|
|
7067
7199
|
let scoreByFactId;
|
|
7068
7200
|
if (maxResults === 0) ; else if (trimmedQuery) {
|
|
@@ -7073,11 +7205,11 @@ var RetrievalService = class {
|
|
|
7073
7205
|
const padLimit = (n) => n >= Number.MAX_SAFE_INTEGER ? n : n + draftPad;
|
|
7074
7206
|
if (scoredEntityIds.length === 0) {
|
|
7075
7207
|
usedEmbed = true;
|
|
7076
|
-
} else if (!skipEmbed &&
|
|
7208
|
+
} else if (!skipEmbed && typeof this.options.llmProvider.embed === "function") {
|
|
7077
7209
|
let rankerShouldRethrow = false;
|
|
7078
7210
|
let pendingRankerFallbackError;
|
|
7079
7211
|
try {
|
|
7080
|
-
const queryVec = await
|
|
7212
|
+
const queryVec = await this.options.llmProvider.embed(trimmedQuery);
|
|
7081
7213
|
if (queryVec.length === 0 || !queryVec.every((v) => typeof v === "number" && isFinite(v))) {
|
|
7082
7214
|
throw new Error(
|
|
7083
7215
|
"embed() returned an empty or non-finite vector. Falling back to keyword search."
|