@loomwork/knowledge 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +72 -2
- package/dist/KnowledgeBase.d.ts +212 -0
- package/dist/KnowledgeBase.d.ts.map +1 -0
- package/dist/KnowledgeBase.js +394 -0
- package/dist/KnowledgeBase.js.map +1 -0
- package/dist/chunk.d.ts +18 -0
- package/dist/chunk.d.ts.map +1 -0
- package/dist/chunk.js +44 -0
- package/dist/chunk.js.map +1 -0
- package/dist/citations.d.ts +45 -0
- package/dist/citations.d.ts.map +1 -0
- package/dist/citations.js +76 -0
- package/dist/citations.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/prompt.d.ts +41 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +47 -0
- package/dist/prompt.js.map +1 -0
- package/dist/types.d.ts +94 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +57 -3
- package/src/KnowledgeBase.ts +489 -0
- package/src/chunk.ts +41 -0
- package/src/citations.ts +88 -0
- package/src/index.ts +16 -0
- package/src/prompt.ts +56 -0
- package/src/types.ts +97 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KnowledgeBase = void 0;
|
|
4
|
+
exports.openKnowledgeBase = openKnowledgeBase;
|
|
5
|
+
const classify_1 = require("@loomwork/classify");
|
|
6
|
+
const core_1 = require("@loomwork/core");
|
|
7
|
+
const memory_1 = require("@loomwork/memory");
|
|
8
|
+
const verify_1 = require("@loomwork/verify");
|
|
9
|
+
const chunk_1 = require("./chunk");
|
|
10
|
+
/**
|
|
11
|
+
* A document corpus over a memory tier: ingest, revise, delete, retrieve — with the
|
|
12
|
+
* provenance and the recorded retrieval that make the result usable in a prompt.
|
|
13
|
+
*
|
|
14
|
+
* ## What this is not
|
|
15
|
+
*
|
|
16
|
+
* It is not a construct, an SPI, or a retrieval engine. Ranking is the `MemoryStore`'s
|
|
17
|
+
* (FTS5, `tsvector`, cosine — whichever backend is configured), reproducibility is
|
|
18
|
+
* `ctx.decide`'s, safety is ADR 0085's, and the corpus is an ordinary `semantic` tier
|
|
19
|
+
* anyone can read with `recall`. What lives here is the one thing none of those provide:
|
|
20
|
+
* the mapping from a DOCUMENT — the unit a corpus is edited in — to the PASSAGES it is
|
|
21
|
+
* searched in, so that revising a document supersedes its old passages instead of
|
|
22
|
+
* duplicating them.
|
|
23
|
+
*
|
|
24
|
+
* ## The tier must not evict
|
|
25
|
+
*
|
|
26
|
+
* A corpus is kept until someone deletes it, so the tier it lives in must have no `ttlMs`
|
|
27
|
+
* and no `maxEntries`. Under eviction, the store would drop passages the manifest still
|
|
28
|
+
* counts, and a document would silently retrieve as a fragment of itself. `semantic` and
|
|
29
|
+
* `procedural` are unbounded by default, which is exactly why they are the tiers a corpus
|
|
30
|
+
* belongs in — and the constructor refuses a bounded one rather than letting it rot.
|
|
31
|
+
*
|
|
32
|
+
* ## Two scopes
|
|
33
|
+
*
|
|
34
|
+
* Passages live in `scope`; the manifest lives in `scope::docs`, one small row per
|
|
35
|
+
* document. They are separate because they are searched differently: a manifest row in
|
|
36
|
+
* the corpus would be an entry that matches queries and answers nothing.
|
|
37
|
+
*/
|
|
38
|
+
class KnowledgeBase {
|
|
39
|
+
memory;
|
|
40
|
+
tier;
|
|
41
|
+
scope;
|
|
42
|
+
manifestScope;
|
|
43
|
+
chunker;
|
|
44
|
+
origin;
|
|
45
|
+
constructor(config) {
|
|
46
|
+
this.memory = config.memory;
|
|
47
|
+
this.tier = config.tier ?? "semantic";
|
|
48
|
+
this.scope = config.scope;
|
|
49
|
+
this.manifestScope = `${config.scope}::docs`;
|
|
50
|
+
this.chunker = config.chunker ?? (0, chunk_1.packParagraphs)();
|
|
51
|
+
this.origin = config.origin ?? ((doc) => `knowledge:${config.scope}:${doc.id}`);
|
|
52
|
+
const policy = this.memory.tierPolicy(this.tier);
|
|
53
|
+
if (policy === undefined) {
|
|
54
|
+
throw new Error(`KnowledgeBase: unknown memory tier "${this.tier}" (have: ${this.memory.tierNames.join(", ")})`);
|
|
55
|
+
}
|
|
56
|
+
if (policy.ttlMs !== undefined || policy.maxEntries !== undefined) {
|
|
57
|
+
throw new Error(`KnowledgeBase: tier "${this.tier}" evicts (ttlMs/maxEntries), and a corpus must not. Eviction would drop passages the document manifest still counts, so a document would retrieve as a fragment of itself with nothing to detect it. Use an unbounded tier ("semantic"/"procedural" are unbounded by default).`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** `docId#index` — derived, never stored, so a document's passage ids are its count. */
|
|
61
|
+
passageId(docId, index) {
|
|
62
|
+
return `${docId}#${index}`;
|
|
63
|
+
}
|
|
64
|
+
fingerprint(doc) {
|
|
65
|
+
// canonicalJson + fnv1a64 are core's one canonicalization and one hash (ADR 0063).
|
|
66
|
+
// Over the WHOLE document, not just its text: a changed title or a changed `meta`
|
|
67
|
+
// reaches the prompt through every passage, so it is a revision like any other.
|
|
68
|
+
return (0, core_1.fnv1a64)((0, core_1.canonicalJson)({
|
|
69
|
+
title: doc.title,
|
|
70
|
+
text: doc.text,
|
|
71
|
+
meta: doc.meta,
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
toPassages(doc) {
|
|
75
|
+
const origin = this.origin(doc);
|
|
76
|
+
return this.chunker(doc).map((text, index) => ({
|
|
77
|
+
docId: doc.id,
|
|
78
|
+
...(doc.title !== undefined && { title: doc.title }),
|
|
79
|
+
index,
|
|
80
|
+
text: (0, classify_1.tainted)(text, origin),
|
|
81
|
+
...(doc.meta !== undefined && { meta: doc.meta }),
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* What is actually WRITTEN for a passage: its `text`, and its `title`/`meta` if any.
|
|
86
|
+
*
|
|
87
|
+
* `docId` and `index` are deliberately NOT stored, because a store indexes the string
|
|
88
|
+
* and number leaves of `content` — so storing them would make a document's own id a term
|
|
89
|
+
* matching all of its passages, and the chunk ordinal a term matching the first passage
|
|
90
|
+
* of every document in the corpus. That is the same widening that made a tainted value's
|
|
91
|
+
* `origin` unindexable (ADR 0090), and the same rule the SPI states for `MemoryEntry.id`.
|
|
92
|
+
*
|
|
93
|
+
* They are not lost: the entry id IS `docId#index`, ids are required to round-trip
|
|
94
|
+
* (SPI 2.0.0), and ids are not indexed. The requirement earns its keep twice.
|
|
95
|
+
*/
|
|
96
|
+
storedPassage(passage) {
|
|
97
|
+
return {
|
|
98
|
+
...(passage.title !== undefined && { title: passage.title }),
|
|
99
|
+
text: passage.text,
|
|
100
|
+
...(passage.meta !== undefined && { meta: passage.meta }),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The tiered memory the corpus lives in, for a caller that also wants to `recall` it,
|
|
105
|
+
* point a second corpus at the same store, or inspect it from ops code.
|
|
106
|
+
*/
|
|
107
|
+
get tieredMemory() {
|
|
108
|
+
return this.memory;
|
|
109
|
+
}
|
|
110
|
+
/** `docId#revision` — a manifest row's id. Rows are appended; the highest revision wins. */
|
|
111
|
+
rowId(docId, revision) {
|
|
112
|
+
return `${docId}#${revision}`;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* The manifest: the live record per document, plus every row id currently standing for
|
|
116
|
+
* it so superseded rows can be pruned.
|
|
117
|
+
*
|
|
118
|
+
* One read of a small scope — rows are ids, counts and hashes, never passage text — which
|
|
119
|
+
* is what keeps `sync` proportional to the number of DOCUMENTS rather than to the size of
|
|
120
|
+
* the corpus. Read order is append order (the SPI guarantees it), so the last row for a
|
|
121
|
+
* document is the live one.
|
|
122
|
+
*/
|
|
123
|
+
async manifest() {
|
|
124
|
+
const entries = await this.memory.recall(this.tier, this.manifestScope);
|
|
125
|
+
const slots = new Map();
|
|
126
|
+
for (const entry of entries) {
|
|
127
|
+
const record = entry.content;
|
|
128
|
+
const slot = slots.get(record.docId);
|
|
129
|
+
const rowId = this.rowId(record.docId, record.revision);
|
|
130
|
+
if (slot === undefined)
|
|
131
|
+
slots.set(record.docId, { record, rowIds: [rowId] });
|
|
132
|
+
else {
|
|
133
|
+
slot.rowIds.push(rowId);
|
|
134
|
+
slot.record = record;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return slots;
|
|
138
|
+
}
|
|
139
|
+
async appendRecord(record) {
|
|
140
|
+
await this.memory.remember(this.tier, this.manifestScope, {
|
|
141
|
+
id: this.rowId(record.docId, record.revision),
|
|
142
|
+
content: record,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Remove a document's passages, by the count the manifest holds. Idempotent — a document
|
|
147
|
+
* that is absent, or whose passages were already deleted, is a no-op.
|
|
148
|
+
*/
|
|
149
|
+
async removeDoc(docId) {
|
|
150
|
+
const slot = (await this.manifest()).get(docId);
|
|
151
|
+
if (slot === undefined)
|
|
152
|
+
return;
|
|
153
|
+
await this.removeRecordedPassages(slot.record);
|
|
154
|
+
await this.memory.forget(this.tier, this.manifestScope, slot.rowIds);
|
|
155
|
+
}
|
|
156
|
+
async removeRecordedPassages(record) {
|
|
157
|
+
const ids = Array.from({ length: record.chunkCount }, (_, i) => this.passageId(record.docId, i));
|
|
158
|
+
if (ids.length > 0)
|
|
159
|
+
await this.memory.forget(this.tier, this.scope, ids);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Ingest a document, superseding any previous revision of it. Returns the passages now
|
|
163
|
+
* stored for it (empty if the document chunked to nothing).
|
|
164
|
+
*
|
|
165
|
+
* UPSERT, not append. Ingesting the same document twice must not double it in the index
|
|
166
|
+
* — retrieval would then return the stale passage beside the current one, and a citation
|
|
167
|
+
* could not say which is live. That is the operation a `MemoryStore` alone cannot
|
|
168
|
+
* express, and the reason this class exists.
|
|
169
|
+
*
|
|
170
|
+
* The write order is the crash contract, and it is deliberate:
|
|
171
|
+
*
|
|
172
|
+
* 1. APPEND an uncommitted manifest row at the new count and fingerprint;
|
|
173
|
+
* 2. delete the previous revision's passages (by the count the old row holds);
|
|
174
|
+
* 3. append the new passages;
|
|
175
|
+
* 4. APPEND the committed manifest row, then prune the superseded rows.
|
|
176
|
+
*
|
|
177
|
+
* A crash before (4) leaves an uncommitted row, which {@link sync} and every later
|
|
178
|
+
* `putDoc` treat as changed no matter what the fingerprint says — so the document is
|
|
179
|
+
* rewritten rather than skipped.
|
|
180
|
+
*
|
|
181
|
+
* Two orderings look more natural and neither survives. Passages first: passages nothing
|
|
182
|
+
* counts are passages nothing can remove, and they stay retrievable forever. Manifest
|
|
183
|
+
* updated in place (delete the old row, write the new one): the crash window between
|
|
184
|
+
* them leaves the document with NO row, which is the same orphaning by a shorter path —
|
|
185
|
+
* which is why rows are appended and superseded ones are pruned only afterwards.
|
|
186
|
+
*/
|
|
187
|
+
async putDoc(doc, opts = {}) {
|
|
188
|
+
const slot = (await this.manifest()).get(doc.id);
|
|
189
|
+
// Only an EXISTING document has an owner. An absent one is unclaimed, so any writer
|
|
190
|
+
// may create it — the check is about not taking someone else's, not about permission.
|
|
191
|
+
if (slot !== undefined)
|
|
192
|
+
assertOwned(doc.id, slot.record.source, opts.source);
|
|
193
|
+
return this.write(doc, slot, opts.source);
|
|
194
|
+
}
|
|
195
|
+
async write(doc, slot, source) {
|
|
196
|
+
const passages = this.toPassages(doc);
|
|
197
|
+
const pending = {
|
|
198
|
+
docId: doc.id,
|
|
199
|
+
chunkCount: passages.length,
|
|
200
|
+
fingerprint: this.fingerprint(doc),
|
|
201
|
+
committed: false,
|
|
202
|
+
revision: (slot?.record.revision ?? -1) + 1,
|
|
203
|
+
...(source !== undefined && { source }),
|
|
204
|
+
};
|
|
205
|
+
await this.appendRecord(pending);
|
|
206
|
+
if (slot !== undefined)
|
|
207
|
+
await this.removeRecordedPassages(slot.record);
|
|
208
|
+
for (const passage of passages) {
|
|
209
|
+
await this.memory.remember(this.tier, this.scope, {
|
|
210
|
+
id: this.passageId(doc.id, passage.index),
|
|
211
|
+
content: this.storedPassage(passage),
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
const committed = { ...pending, committed: true, revision: pending.revision + 1 };
|
|
215
|
+
await this.appendRecord(committed);
|
|
216
|
+
// Prune only after the committed row is durable, and only rows this call has seen: a
|
|
217
|
+
// concurrent writer's row is not ours to delete.
|
|
218
|
+
const superseded = [...(slot?.rowIds ?? []), this.rowId(doc.id, pending.revision)];
|
|
219
|
+
await this.memory.forget(this.tier, this.manifestScope, superseded);
|
|
220
|
+
return passages;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Reconcile the corpus against the documents the source currently has: write what is new
|
|
224
|
+
* or changed, leave what is identical, remove what the source dropped.
|
|
225
|
+
*
|
|
226
|
+
* This is the operation a knowledge base is actually run with — a wiki export, a docs
|
|
227
|
+
* directory, a table of policies — and it is what makes deletion complete rather than
|
|
228
|
+
* best-effort. Without it, a document deleted upstream keeps answering questions.
|
|
229
|
+
*
|
|
230
|
+
* Cost is one manifest read (rows are ids and counts) plus writes for the documents that
|
|
231
|
+
* genuinely changed — NOT a rewrite of the corpus, which is the whole point of the
|
|
232
|
+
* fingerprint. Re-running it on an unchanged source writes nothing.
|
|
233
|
+
*
|
|
234
|
+
* `docs` is the COMPLETE set. Passing a subset removes everything not in it, which is
|
|
235
|
+
* the correct reading of "reconcile" and the wrong thing to do with a page of results.
|
|
236
|
+
*/
|
|
237
|
+
async sync(docs, opts = {}) {
|
|
238
|
+
const manifest = await this.manifest();
|
|
239
|
+
const plan = this.classify(docs, manifest, opts.source);
|
|
240
|
+
// Indexed once: `written` is O(docs) and a scan per entry would make a sync of a
|
|
241
|
+
// 10,000-document corpus quadratic in the size of the source, not of the change.
|
|
242
|
+
const byId = new Map(docs.map((doc) => [doc.id, doc]));
|
|
243
|
+
for (const docId of plan.written) {
|
|
244
|
+
// An UNCOMMITTED row is rewritten even when the fingerprint matches. That case is
|
|
245
|
+
// exactly the crash this design exists for, and treating it as unchanged is how a
|
|
246
|
+
// document disappears from a corpus that still lists it.
|
|
247
|
+
await this.write(byId.get(docId), manifest.get(docId), opts.source);
|
|
248
|
+
}
|
|
249
|
+
for (const docId of plan.removed) {
|
|
250
|
+
const slot = manifest.get(docId);
|
|
251
|
+
await this.removeRecordedPassages(slot.record);
|
|
252
|
+
await this.memory.forget(this.tier, this.manifestScope, slot.rowIds);
|
|
253
|
+
}
|
|
254
|
+
return plan;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* What {@link sync} WOULD do, without doing it. Read-only.
|
|
258
|
+
*
|
|
259
|
+
* Exists because a corpus sync is a destructive reconcile — `docs` is the complete set,
|
|
260
|
+
* so anything missing from it is deleted — and the operator command that runs it
|
|
261
|
+
* (`loom knowledge sync`) defaults to a dry run for that reason. A preview computed by a
|
|
262
|
+
* separate code path would be a preview of a different operation, so both go through the
|
|
263
|
+
* same classification and only `sync` writes.
|
|
264
|
+
*/
|
|
265
|
+
async planSync(docs, opts = {}) {
|
|
266
|
+
return this.classify(docs, await this.manifest(), opts.source);
|
|
267
|
+
}
|
|
268
|
+
/** Pure: which documents are new/changed, unchanged, or no longer in the source. */
|
|
269
|
+
classify(docs, manifest, source) {
|
|
270
|
+
const result = { written: [], unchanged: [], removed: [], retained: [] };
|
|
271
|
+
const seen = new Set();
|
|
272
|
+
for (const doc of docs) {
|
|
273
|
+
if (seen.has(doc.id)) {
|
|
274
|
+
throw new Error(`KnowledgeBase.sync: duplicate document id "${doc.id}". Ids identify a document across revisions, so two documents sharing one would each supersede the other on every sync.`);
|
|
275
|
+
}
|
|
276
|
+
seen.add(doc.id);
|
|
277
|
+
const slot = manifest.get(doc.id);
|
|
278
|
+
if (slot !== undefined)
|
|
279
|
+
assertOwned(doc.id, slot.record.source, source);
|
|
280
|
+
if (slot?.record.committed === true && slot.record.fingerprint === this.fingerprint(doc)) {
|
|
281
|
+
result.unchanged.push(doc.id);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
result.written.push(doc.id);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
for (const [docId, slot] of manifest) {
|
|
288
|
+
if (seen.has(docId))
|
|
289
|
+
continue;
|
|
290
|
+
// The whole point: a reconcile deletes only what it OWNS. Another writer's documents
|
|
291
|
+
// are not missing from this source — they were never this source's to list.
|
|
292
|
+
if (slot.record.source !== source)
|
|
293
|
+
result.retained.push(docId);
|
|
294
|
+
else
|
|
295
|
+
result.removed.push(docId);
|
|
296
|
+
}
|
|
297
|
+
return result;
|
|
298
|
+
}
|
|
299
|
+
/** The documents this corpus holds, in manifest order. Ids and counts — no passage text. */
|
|
300
|
+
async listDocs() {
|
|
301
|
+
return [...(await this.manifest()).values()].map((slot) => slot.record);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Retrieve the passages most relevant to a question, best first.
|
|
305
|
+
*
|
|
306
|
+
* `decide` is REQUIRED, and it is a type requirement rather than advice for the reason
|
|
307
|
+
* ADR 0090 gives: a corpus grows and is edited, so the passages a question retrieves
|
|
308
|
+
* genuinely differ between a run and its replay. Recorded, the retrieval is a fact and
|
|
309
|
+
* the replay rebuilds the prompt that actually ran; unrecorded, "reproducing" an
|
|
310
|
+
* incident quietly means asking today's corpus yesterday's question.
|
|
311
|
+
*
|
|
312
|
+
* What is recorded is the passage CONTENT, not passage ids — ids do not reconstruct a
|
|
313
|
+
* prompt once the document behind them has been revised.
|
|
314
|
+
*/
|
|
315
|
+
async retrieve(query, opts) {
|
|
316
|
+
const hits = await this.memory.recallRelevant(this.tier, this.scope, query, {
|
|
317
|
+
decide: opts.decide,
|
|
318
|
+
...(opts.limit !== undefined && { limit: opts.limit }),
|
|
319
|
+
...(opts.decisionKey !== undefined && { decisionKey: opts.decisionKey }),
|
|
320
|
+
});
|
|
321
|
+
return hits.map(toPassage);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
exports.KnowledgeBase = KnowledgeBase;
|
|
325
|
+
// L34 - declared reach (ADR 0086). `kb.retrieve(q, { decide: ctx.decide })` is one `ctx.decide`
|
|
326
|
+
// whose decider reads the memory store; it runs no tool (embedding, if any, is the store's own, not
|
|
327
|
+
// a ctx effect). Declared on the PROTOTYPE so both `verify.reach["kb.retrieve"]` and `verify.reach.kb`
|
|
328
|
+
// (the instance, which inherits it) and a method reference (`kb.retrieve`) resolve. Only `retrieve` is
|
|
329
|
+
// ever handed a ctx seam.
|
|
330
|
+
(0, verify_1.declareReach)(KnowledgeBase.prototype, { run: [], transient: [] });
|
|
331
|
+
(0, verify_1.declareReach)(KnowledgeBase.prototype.retrieve, { run: [], transient: [] });
|
|
332
|
+
/**
|
|
333
|
+
* Open a corpus over a `MemoryStore` directly — the two-line form of the four every
|
|
334
|
+
* consumer was writing by hand.
|
|
335
|
+
*
|
|
336
|
+
* A corpus needs exactly one memory tier and that tier must not evict, which is a fact
|
|
337
|
+
* about corpora and not a decision each application should be re-deriving. Both first
|
|
338
|
+
* consumers built the identical `new TieredMemory({ tiers: { semantic: {} }, store })`
|
|
339
|
+
* before they could construct anything, and an application wiring `defineConfig` cannot
|
|
340
|
+
* pass `app.memory` here at all — that is a {@link MemoryRuntime}, one layer below
|
|
341
|
+
* `TieredMemory` — so the boilerplate was mandatory rather than incidental.
|
|
342
|
+
*
|
|
343
|
+
* Reach for the constructor instead when the corpus shares a memory with something else
|
|
344
|
+
* (a conversation in `episodic`, say), which is exactly when the tier set is a decision.
|
|
345
|
+
*/
|
|
346
|
+
function openKnowledgeBase(store, opts) {
|
|
347
|
+
const tier = opts.tier ?? "semantic";
|
|
348
|
+
return new KnowledgeBase({
|
|
349
|
+
...opts,
|
|
350
|
+
memory: new memory_1.TieredMemory({ tiers: { [tier]: {} }, store }),
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Refuse a write to a document another writer owns.
|
|
355
|
+
*
|
|
356
|
+
* Loud rather than re-stamping, because silently taking ownership makes the two writers
|
|
357
|
+
* fight: each `sync` would claim the document and the other's next `sync` would delete it,
|
|
358
|
+
* so the corpus would flap between two revisions forever while every individual run looked
|
|
359
|
+
* correct. Two writers claiming one document is the ambiguity this field exists to remove.
|
|
360
|
+
*/
|
|
361
|
+
function assertOwned(docId, owner, writer) {
|
|
362
|
+
if (owner === writer)
|
|
363
|
+
return;
|
|
364
|
+
const name = (s) => s === undefined ? "the default writer" : `source "${s}"`;
|
|
365
|
+
throw new Error(`KnowledgeBase: document "${docId}" is managed by ${name(owner)}, and this call speaks for ${name(writer)}. One document, one writer — otherwise the two delete each other's revisions on alternate syncs. Use a different document id, or the owning source.`);
|
|
366
|
+
}
|
|
367
|
+
/** `docId#index` split at the LAST separator, so a document id may itself contain one. */
|
|
368
|
+
function splitPassageId(id) {
|
|
369
|
+
const cut = id.lastIndexOf("#");
|
|
370
|
+
const index = Number(id.slice(cut + 1));
|
|
371
|
+
if (cut < 1 || !Number.isInteger(index)) {
|
|
372
|
+
throw new Error(`KnowledgeBase: entry id "${id}" is not a passage id (expected "docId#index"). The corpus scope holds passages this KnowledgeBase wrote; something else appended to it.`);
|
|
373
|
+
}
|
|
374
|
+
return { docId: id.slice(0, cut), index };
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* A stored entry, as a passage: its identity from the entry id, the rest from `content`.
|
|
378
|
+
*
|
|
379
|
+
* The content half is a cast and not a parse, deliberately: on replay this value comes back
|
|
380
|
+
* out of a `DECISION_RECORDED` payload as plain JSON, and re-validating it would only be
|
|
381
|
+
* able to reject what the log already contains — the value IS what ran. The taint wrapper
|
|
382
|
+
* survives that round trip because it is plain JSON too, which is the property ADR 0085 was
|
|
383
|
+
* built on. The identity half is checked, because an unparseable id means the entry was not
|
|
384
|
+
* written by a KnowledgeBase and a `docId: undefined` would flow straight into a citation.
|
|
385
|
+
*/
|
|
386
|
+
function toPassage(entry) {
|
|
387
|
+
if (entry.id === undefined) {
|
|
388
|
+
throw new Error("KnowledgeBase: a corpus entry has no id, so the document it belongs to cannot be named. Either the backend does not round-trip `MemoryEntry.id` (REQUIRED since MemoryStore SPI 2.0.0 — run `runMemoryStoreConformance` against it), or something other than this KnowledgeBase appended to the corpus scope.");
|
|
389
|
+
}
|
|
390
|
+
const { docId, index } = splitPassageId(entry.id);
|
|
391
|
+
const stored = entry.content;
|
|
392
|
+
return { docId, index, ...stored };
|
|
393
|
+
}
|
|
394
|
+
//# sourceMappingURL=KnowledgeBase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KnowledgeBase.js","sourceRoot":"","sources":["../src/KnowledgeBase.ts"],"names":[],"mappings":";;;AAuaA,8CASC;AAhbD,iDAA6C;AAC7C,yCAAwD;AACxD,6CAAgD;AAEhD,6CAAgD;AAChD,mCAAyC;AAoDzC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAa,aAAa;IACP,MAAM,CAAe;IACrB,IAAI,CAAS;IACb,KAAK,CAAS;IACd,aAAa,CAAS;IACtB,OAAO,CAAU;IACjB,MAAM,CAAgC;IAEvD,YAAY,MAA2B;QACrC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC;QACtC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,aAAa,GAAG,GAAG,MAAM,CAAC,KAAK,QAAQ,CAAC;QAC7C,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,IAAA,sBAAc,GAAE,CAAC;QAClD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAEhF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,uCAAuC,IAAI,CAAC,IAAI,YAAY,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAChG,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAClE,MAAM,IAAI,KAAK,CACb,wBAAwB,IAAI,CAAC,IAAI,gRAAgR,CAClT,CAAC;QACJ,CAAC;IACH,CAAC;IAED,wFAAwF;IAChF,SAAS,CAAC,KAAa,EAAE,KAAa;QAC5C,OAAO,GAAG,KAAK,IAAI,KAAK,EAAE,CAAC;IAC7B,CAAC;IAEO,WAAW,CAAC,GAAiB;QACnC,mFAAmF;QACnF,kFAAkF;QAClF,gFAAgF;QAChF,OAAO,IAAA,cAAO,EACZ,IAAA,oBAAa,EAAC;YACZ,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,IAAI,EAAE,GAAG,CAAC,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;IAEO,UAAU,CAAC,GAAiB;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAC7C,KAAK,EAAE,GAAG,CAAC,EAAE;YACb,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;YACpD,KAAK;YACL,IAAI,EAAE,IAAA,kBAAO,EAAC,IAAI,EAAE,MAAM,CAAC;YAC3B,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC;SAClD,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;;;;;;;;;;OAWG;IACK,aAAa,CAAC,OAAgB;QACpC,OAAO;YACL,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;YAC5D,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;SAC1D,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,4FAA4F;IACpF,KAAK,CAAC,KAAa,EAAE,QAAgB;QAC3C,OAAO,GAAG,KAAK,IAAI,QAAQ,EAAE,CAAC;IAChC,CAAC;IAED;;;;;;;;OAQG;IACK,KAAK,CAAC,QAAQ;QACpB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QACxE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAwB,CAAC;QAC9C,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAG,KAAK,CAAC,OAAoB,CAAC;YAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACrC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YACxD,IAAI,IAAI,KAAK,SAAS;gBAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;iBACxE,CAAC;gBACJ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YACvB,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,MAAiB;QAC1C,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE;YACxD,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC;YAC7C,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,SAAS,CAAC,KAAa;QAC3B,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO;QAC/B,MAAM,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACvE,CAAC;IAEO,KAAK,CAAC,sBAAsB,CAAC,MAAiB;QACpD,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAC7D,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAChC,CAAC;QACF,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC3E,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,KAAK,CAAC,MAAM,CAAC,GAAiB,EAAE,OAAsB,EAAE;QACtD,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACjD,oFAAoF;QACpF,sFAAsF;QACtF,IAAI,IAAI,KAAK,SAAS;YAAE,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAC7E,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAEO,KAAK,CAAC,KAAK,CACjB,GAAiB,EACjB,IAA8B,EAC9B,MAA0B;QAE1B,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,OAAO,GAAc;YACzB,KAAK,EAAE,GAAG,CAAC,EAAE;YACb,UAAU,EAAE,QAAQ,CAAC,MAAM;YAC3B,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC;YAClC,SAAS,EAAE,KAAK;YAChB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;YAC3C,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC;SACxC,CAAC;QAEF,MAAM,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QACjC,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvE,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;gBAChD,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC;gBACzC,OAAO,EAAE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;aACrC,CAAC,CAAC;QACL,CAAC;QACD,MAAM,SAAS,GAAc,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC7F,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QACnC,qFAAqF;QACrF,iDAAiD;QACjD,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;QACnF,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;QACpE,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,IAAI,CAAC,IAA6B,EAAE,OAAsB,EAAE;QAChE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACxD,iFAAiF;QACjF,iFAAiF;QACjF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;QAEvD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,kFAAkF;YAClF,kFAAkF;YAClF,yDAAyD;YACzD,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAiB,EAAE,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACtF,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAiB,CAAC;YACjD,MAAM,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC/C,MAAM,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,QAAQ,CAAC,IAA6B,EAAE,OAAsB,EAAE;QACpE,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACjE,CAAC;IAED,oFAAoF;IAC5E,QAAQ,CACd,IAA6B,EAC7B,QAAmC,EACnC,MAA0B;QAE1B,MAAM,MAAM,GAAe,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACrF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CACb,8CAA8C,GAAG,CAAC,EAAE,yHAAyH,CAC9K,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACjB,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAClC,IAAI,IAAI,KAAK,SAAS;gBAAE,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YACxE,IAAI,IAAI,EAAE,MAAM,CAAC,SAAS,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzF,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC9B,CAAC;QACH,CAAC;QACD,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;YACrC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,SAAS;YAC9B,qFAAqF;YACrF,4EAA4E;YAC5E,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM;gBAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;;gBAC1D,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,4FAA4F;IAC5F,KAAK,CAAC,QAAQ;QACZ,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1E,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,QAAQ,CAAC,KAAa,EAAE,IAAqB;QACjD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE;YAC1E,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;YACtD,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;SACzE,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC7B,CAAC;CACF;AA1TD,sCA0TC;AAED,gGAAgG;AAChG,oGAAoG;AACpG,uGAAuG;AACvG,uGAAuG;AACvG,0BAA0B;AAC1B,IAAA,qBAAY,EAAC,aAAa,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;AAClE,IAAA,qBAAY,EAAC,aAAa,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;AAE3E;;;;;;;;;;;;;GAaG;AACH,SAAgB,iBAAiB,CAC/B,KAAkB,EAClB,IAAyC;IAEzC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,UAAU,CAAC;IACrC,OAAO,IAAI,aAAa,CAAC;QACvB,GAAG,IAAI;QACP,MAAM,EAAE,IAAI,qBAAY,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;KAC3D,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,WAAW,CAAC,KAAa,EAAE,KAAyB,EAAE,MAA0B;IACvF,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO;IAC7B,MAAM,IAAI,GAAG,CAAC,CAAqB,EAAU,EAAE,CAC7C,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC;IAC3D,MAAM,IAAI,KAAK,CACb,4BAA4B,KAAK,mBAAmB,IAAI,CAAC,KAAK,CAAC,8BAA8B,IAAI,CAAC,MAAM,CAAC,qJAAqJ,CAC/P,CAAC;AACJ,CAAC;AAED,0FAA0F;AAC1F,SAAS,cAAc,CAAC,EAAU;IAChC,MAAM,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACxC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,4BAA4B,EAAE,0IAA0I,CACzK,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,SAAS,CAAC,KAAkB;IACnC,IAAI,KAAK,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACb,+SAA+S,CAChT,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,KAAK,CAAC,OAA2C,CAAC;IACjE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,EAAE,CAAC;AACrC,CAAC"}
|
package/dist/chunk.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Chunker } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* The default {@link Chunker}: split on blank lines, then greedily pack paragraphs up to
|
|
4
|
+
* `maxChars` so a passage is a coherent unit of prose rather than a fixed window that cuts
|
|
5
|
+
* mid-sentence.
|
|
6
|
+
*
|
|
7
|
+
* It is a DEFAULT and not a recommendation. Chunking decides what retrieval can return —
|
|
8
|
+
* too small and a passage loses the context that makes it answer the question, too large
|
|
9
|
+
* and one irrelevant paragraph drags a whole page into the prompt — and the right split is
|
|
10
|
+
* a property of the corpus, not of the framework. Pass your own for anything structured.
|
|
11
|
+
*
|
|
12
|
+
* A paragraph longer than `maxChars` is emitted whole rather than cut: splitting mid-word
|
|
13
|
+
* to satisfy a soft bound produces two passages that each retrieve badly, and the bound is
|
|
14
|
+
* a packing target, not a storage limit. Oversized content belongs behind
|
|
15
|
+
* `claimCheckMiddleware` at the effect boundary, which is where size actually bites.
|
|
16
|
+
*/
|
|
17
|
+
export declare function packParagraphs(maxChars?: number): Chunker;
|
|
18
|
+
//# sourceMappingURL=chunk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk.d.ts","sourceRoot":"","sources":["../src/chunk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,SAAS,CAAC;AAErD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,QAAQ,SAAQ,GAAG,OAAO,CAuBxD"}
|
package/dist/chunk.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.packParagraphs = packParagraphs;
|
|
4
|
+
/**
|
|
5
|
+
* The default {@link Chunker}: split on blank lines, then greedily pack paragraphs up to
|
|
6
|
+
* `maxChars` so a passage is a coherent unit of prose rather than a fixed window that cuts
|
|
7
|
+
* mid-sentence.
|
|
8
|
+
*
|
|
9
|
+
* It is a DEFAULT and not a recommendation. Chunking decides what retrieval can return —
|
|
10
|
+
* too small and a passage loses the context that makes it answer the question, too large
|
|
11
|
+
* and one irrelevant paragraph drags a whole page into the prompt — and the right split is
|
|
12
|
+
* a property of the corpus, not of the framework. Pass your own for anything structured.
|
|
13
|
+
*
|
|
14
|
+
* A paragraph longer than `maxChars` is emitted whole rather than cut: splitting mid-word
|
|
15
|
+
* to satisfy a soft bound produces two passages that each retrieve badly, and the bound is
|
|
16
|
+
* a packing target, not a storage limit. Oversized content belongs behind
|
|
17
|
+
* `claimCheckMiddleware` at the effect boundary, which is where size actually bites.
|
|
18
|
+
*/
|
|
19
|
+
function packParagraphs(maxChars = 1_000) {
|
|
20
|
+
if (!Number.isFinite(maxChars) || maxChars < 1) {
|
|
21
|
+
throw new TypeError(`packParagraphs: maxChars must be a positive number (got ${maxChars})`);
|
|
22
|
+
}
|
|
23
|
+
return (doc) => {
|
|
24
|
+
const paragraphs = doc.text
|
|
25
|
+
.split(/\n\s*\n/)
|
|
26
|
+
.map((p) => p.replace(/\s+/g, " ").trim())
|
|
27
|
+
.filter((p) => p.length > 0);
|
|
28
|
+
const chunks = [];
|
|
29
|
+
let current = "";
|
|
30
|
+
for (const paragraph of paragraphs) {
|
|
31
|
+
if (current.length > 0 && current.length + paragraph.length + 1 > maxChars) {
|
|
32
|
+
chunks.push(current);
|
|
33
|
+
current = paragraph;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
current = current.length > 0 ? `${current} ${paragraph}` : paragraph;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (current.length > 0)
|
|
40
|
+
chunks.push(current);
|
|
41
|
+
return chunks;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=chunk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk.js","sourceRoot":"","sources":["../src/chunk.ts"],"names":[],"mappings":";;AAiBA,wCAuBC;AAtCD;;;;;;;;;;;;;;GAcG;AACH,SAAgB,cAAc,CAAC,QAAQ,GAAG,KAAK;IAC7C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,SAAS,CAAC,2DAA2D,QAAQ,GAAG,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,CAAC,GAAiB,EAAY,EAAE;QACrC,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI;aACxB,KAAK,CAAC,SAAS,CAAC;aAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;aACzC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE/B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,EAAE,CAAC;gBAC3E,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACrB,OAAO,GAAG,SAAS,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;YACvE,CAAC;QACH,CAAC;QACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7C,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Passage } from "./types";
|
|
2
|
+
export interface CitationCheck {
|
|
3
|
+
/** Claimed ids that were actually retrieved, deduplicated, in retrieval order. */
|
|
4
|
+
grounded: string[];
|
|
5
|
+
/**
|
|
6
|
+
* Claimed ids that were NOT retrieved — the model named a source it was never shown.
|
|
7
|
+
* Non-empty is a fabricated citation, not a near miss.
|
|
8
|
+
*/
|
|
9
|
+
ungrounded: string[];
|
|
10
|
+
/** Retrieved documents the answer did not cite. Not an error — evidence for tuning `limit`. */
|
|
11
|
+
unused: string[];
|
|
12
|
+
}
|
|
13
|
+
export declare class UngroundedCitationError extends Error {
|
|
14
|
+
readonly ungrounded: readonly string[];
|
|
15
|
+
readonly retrieved: readonly string[];
|
|
16
|
+
constructor(ungrounded: readonly string[], retrieved: readonly string[]);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Compare the documents an answer CLAIMS to cite against the ones actually retrieved.
|
|
20
|
+
*
|
|
21
|
+
* The check is nearly free and almost never written, because the number it needs is
|
|
22
|
+
* already in hand: the retrieval was recorded, so the set of documents the model could
|
|
23
|
+
* possibly have read is known exactly. A citation outside that set was not misread from a
|
|
24
|
+
* passage — there was no passage. It is the one hallucination in a RAG answer that can be
|
|
25
|
+
* detected with certainty rather than judged, which is what makes it mechanism and not a
|
|
26
|
+
* quality heuristic.
|
|
27
|
+
*
|
|
28
|
+
* What it does NOT check is whether the answer's CLAIMS follow from the cited passage.
|
|
29
|
+
* That needs a judge, it belongs to `@loomwork/learning`'s evaluation surface, and conflating
|
|
30
|
+
* the two would turn a decidable check into an approximate one.
|
|
31
|
+
*
|
|
32
|
+
* Ids are compared exactly: a corpus's document ids are its own keys, and normalizing
|
|
33
|
+
* case or punctuation here would be guessing at someone else's namespace.
|
|
34
|
+
*/
|
|
35
|
+
export declare function checkCitations(claimed: readonly string[], passages: readonly Passage[]): CitationCheck;
|
|
36
|
+
/**
|
|
37
|
+
* {@link checkCitations}, but a fabricated citation throws.
|
|
38
|
+
*
|
|
39
|
+
* Returns the grounded ids, so the caller's happy path is `cited: assertGrounded(...)`.
|
|
40
|
+
* Use it where an answer is about to be shown as sourced: the failure mode this prevents
|
|
41
|
+
* is an answer that reads as attributed, names a plausible document, and cannot be traced
|
|
42
|
+
* to anything — the citation making it MORE trusted than an uncited answer would be.
|
|
43
|
+
*/
|
|
44
|
+
export declare function assertGrounded(claimed: readonly string[], passages: readonly Passage[]): string[];
|
|
45
|
+
//# sourceMappingURL=citations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"citations.d.ts","sourceRoot":"","sources":["../src/citations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,WAAW,aAAa;IAC5B,kFAAkF;IAClF,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,+FAA+F;IAC/F,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAE9C,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE;IACtC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE;gBAD5B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,SAAS,EAAE,SAAS,MAAM,EAAE;CAOxC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,QAAQ,EAAE,SAAS,OAAO,EAAE,GAC3B,aAAa,CAyBf;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,MAAM,EAAE,CAMjG"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UngroundedCitationError = void 0;
|
|
4
|
+
exports.checkCitations = checkCitations;
|
|
5
|
+
exports.assertGrounded = assertGrounded;
|
|
6
|
+
class UngroundedCitationError extends Error {
|
|
7
|
+
ungrounded;
|
|
8
|
+
retrieved;
|
|
9
|
+
constructor(ungrounded, retrieved) {
|
|
10
|
+
super(`answer cites ${ungrounded.length} document(s) that were not retrieved: ${ungrounded.join(", ")} (retrieved: ${retrieved.join(", ") || "none"})`);
|
|
11
|
+
this.ungrounded = ungrounded;
|
|
12
|
+
this.retrieved = retrieved;
|
|
13
|
+
this.name = "UngroundedCitationError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.UngroundedCitationError = UngroundedCitationError;
|
|
17
|
+
/**
|
|
18
|
+
* Compare the documents an answer CLAIMS to cite against the ones actually retrieved.
|
|
19
|
+
*
|
|
20
|
+
* The check is nearly free and almost never written, because the number it needs is
|
|
21
|
+
* already in hand: the retrieval was recorded, so the set of documents the model could
|
|
22
|
+
* possibly have read is known exactly. A citation outside that set was not misread from a
|
|
23
|
+
* passage — there was no passage. It is the one hallucination in a RAG answer that can be
|
|
24
|
+
* detected with certainty rather than judged, which is what makes it mechanism and not a
|
|
25
|
+
* quality heuristic.
|
|
26
|
+
*
|
|
27
|
+
* What it does NOT check is whether the answer's CLAIMS follow from the cited passage.
|
|
28
|
+
* That needs a judge, it belongs to `@loomwork/learning`'s evaluation surface, and conflating
|
|
29
|
+
* the two would turn a decidable check into an approximate one.
|
|
30
|
+
*
|
|
31
|
+
* Ids are compared exactly: a corpus's document ids are its own keys, and normalizing
|
|
32
|
+
* case or punctuation here would be guessing at someone else's namespace.
|
|
33
|
+
*/
|
|
34
|
+
function checkCitations(claimed, passages) {
|
|
35
|
+
const retrieved = [];
|
|
36
|
+
const retrievedSet = new Set();
|
|
37
|
+
for (const passage of passages) {
|
|
38
|
+
if (retrievedSet.has(passage.docId))
|
|
39
|
+
continue;
|
|
40
|
+
retrievedSet.add(passage.docId);
|
|
41
|
+
retrieved.push(passage.docId);
|
|
42
|
+
}
|
|
43
|
+
const claimedSet = new Set(claimed);
|
|
44
|
+
const ungrounded = [];
|
|
45
|
+
const seen = new Set();
|
|
46
|
+
for (const id of claimed) {
|
|
47
|
+
if (seen.has(id))
|
|
48
|
+
continue;
|
|
49
|
+
seen.add(id);
|
|
50
|
+
if (!retrievedSet.has(id))
|
|
51
|
+
ungrounded.push(id);
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
// Retrieval order, not claim order: it is the order the app can explain (best first),
|
|
55
|
+
// and the model's ordering carries no meaning worth preserving.
|
|
56
|
+
grounded: retrieved.filter((id) => claimedSet.has(id)),
|
|
57
|
+
ungrounded,
|
|
58
|
+
unused: retrieved.filter((id) => !claimedSet.has(id)),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* {@link checkCitations}, but a fabricated citation throws.
|
|
63
|
+
*
|
|
64
|
+
* Returns the grounded ids, so the caller's happy path is `cited: assertGrounded(...)`.
|
|
65
|
+
* Use it where an answer is about to be shown as sourced: the failure mode this prevents
|
|
66
|
+
* is an answer that reads as attributed, names a plausible document, and cannot be traced
|
|
67
|
+
* to anything — the citation making it MORE trusted than an uncited answer would be.
|
|
68
|
+
*/
|
|
69
|
+
function assertGrounded(claimed, passages) {
|
|
70
|
+
const check = checkCitations(claimed, passages);
|
|
71
|
+
if (check.ungrounded.length > 0) {
|
|
72
|
+
throw new UngroundedCitationError(check.ungrounded, [...new Set(passages.map((p) => p.docId))]);
|
|
73
|
+
}
|
|
74
|
+
return check.grounded;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=citations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"citations.js","sourceRoot":"","sources":["../src/citations.ts"],"names":[],"mappings":";;;AA2CA,wCA4BC;AAUD,wCAMC;AAzED,MAAa,uBAAwB,SAAQ,KAAK;IAErC;IACA;IAFX,YACW,UAA6B,EAC7B,SAA4B;QAErC,KAAK,CACH,gBAAgB,UAAU,CAAC,MAAM,yCAAyC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,GAAG,CACjJ,CAAC;QALO,eAAU,GAAV,UAAU,CAAmB;QAC7B,cAAS,GAAT,SAAS,CAAmB;QAKrC,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAVD,0DAUC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,cAAc,CAC5B,OAA0B,EAC1B,QAA4B;IAE5B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IACvC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,SAAS;QAC9C,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAChC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IACpC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,OAAO;QACL,sFAAsF;QACtF,gEAAgE;QAChE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtD,UAAU;QACV,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;KACtD,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,cAAc,CAAC,OAA0B,EAAE,QAA4B;IACrF,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAChD,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,uBAAuB,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAClG,CAAC;IACD,OAAO,KAAK,CAAC,QAAQ,CAAC;AACxB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { KnowledgeBase, openKnowledgeBase } from "./KnowledgeBase";
|
|
2
|
+
export type { KnowledgeBaseConfig, RetrieveOptions, SourceOptions, SyncResult, } from "./KnowledgeBase";
|
|
3
|
+
export { packParagraphs } from "./chunk";
|
|
4
|
+
export { checkCitations, assertGrounded, UngroundedCitationError } from "./citations";
|
|
5
|
+
export type { CitationCheck } from "./citations";
|
|
6
|
+
export { groundedRequest, passageMessages } from "./prompt";
|
|
7
|
+
export type { GroundedRequestOptions } from "./prompt";
|
|
8
|
+
export type { Chunker, DocRecord, KnowledgeDoc, Passage } from "./types";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAInE,YAAY,EACV,mBAAmB,EACnB,eAAe,EACf,aAAa,EACb,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtF,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC5D,YAAY,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACvD,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.passageMessages = exports.groundedRequest = exports.UngroundedCitationError = exports.assertGrounded = exports.checkCitations = exports.packParagraphs = exports.openKnowledgeBase = exports.KnowledgeBase = void 0;
|
|
4
|
+
var KnowledgeBase_1 = require("./KnowledgeBase");
|
|
5
|
+
Object.defineProperty(exports, "KnowledgeBase", { enumerable: true, get: function () { return KnowledgeBase_1.KnowledgeBase; } });
|
|
6
|
+
Object.defineProperty(exports, "openKnowledgeBase", { enumerable: true, get: function () { return KnowledgeBase_1.openKnowledgeBase; } });
|
|
7
|
+
var chunk_1 = require("./chunk");
|
|
8
|
+
Object.defineProperty(exports, "packParagraphs", { enumerable: true, get: function () { return chunk_1.packParagraphs; } });
|
|
9
|
+
var citations_1 = require("./citations");
|
|
10
|
+
Object.defineProperty(exports, "checkCitations", { enumerable: true, get: function () { return citations_1.checkCitations; } });
|
|
11
|
+
Object.defineProperty(exports, "assertGrounded", { enumerable: true, get: function () { return citations_1.assertGrounded; } });
|
|
12
|
+
Object.defineProperty(exports, "UngroundedCitationError", { enumerable: true, get: function () { return citations_1.UngroundedCitationError; } });
|
|
13
|
+
var prompt_1 = require("./prompt");
|
|
14
|
+
Object.defineProperty(exports, "groundedRequest", { enumerable: true, get: function () { return prompt_1.groundedRequest; } });
|
|
15
|
+
Object.defineProperty(exports, "passageMessages", { enumerable: true, get: function () { return prompt_1.passageMessages; } });
|
|
16
|
+
//# sourceMappingURL=index.js.map
|