@tangle-network/agent-knowledge 22.0.18 → 23.0.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/CHANGELOG.md +10 -0
- package/README.md +7 -4
- package/dist/cli.js +1 -1
- package/dist/index-B2s20NlV.d.ts.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -9
- package/dist/index.js.map +1 -1
- package/dist/{inspect-tl0P7I7w.js → inspect-CKNcuqrY.js} +292 -212
- package/dist/inspect-CKNcuqrY.js.map +1 -0
- package/dist/memory-krApkeRS.js.map +1 -1
- package/docs/agent-tools.md +3 -1
- package/docs/compatibility.md +8 -8
- package/package.json +4 -4
- package/dist/inspect-tl0P7I7w.js.map +0 -1
|
@@ -194,7 +194,8 @@ async function listRegularFileMetadataWithinRoot(root, relativeDirectory) {
|
|
|
194
194
|
stat.size,
|
|
195
195
|
stat.mtimeNs,
|
|
196
196
|
stat.ctimeNs
|
|
197
|
-
].join(":")
|
|
197
|
+
].join(":"),
|
|
198
|
+
changedNs: stat.ctimeNs
|
|
198
199
|
});
|
|
199
200
|
}
|
|
200
201
|
}
|
|
@@ -1210,6 +1211,10 @@ var KnowledgeLockLostError = class extends Error {
|
|
|
1210
1211
|
function isKnowledgeMutationHeld(root) {
|
|
1211
1212
|
return activeRoots.getStore()?.get(resolve(root))?.active === true;
|
|
1212
1213
|
}
|
|
1214
|
+
/** Whether this context already reads or mutates `root`, so it must never wait on another reader. */
|
|
1215
|
+
function isKnowledgeRootHeld(root) {
|
|
1216
|
+
return isKnowledgeMutationHeld(root) || activeReadRoots.getStore()?.has(resolve(root)) === true;
|
|
1217
|
+
}
|
|
1213
1218
|
async function withKnowledgeMutation(root, mutate, options = {}) {
|
|
1214
1219
|
const resolvedRoot = resolve(root);
|
|
1215
1220
|
const existing = activeRoots.getStore()?.get(resolvedRoot);
|
|
@@ -2354,25 +2359,132 @@ async function initKnowledgeBaseUnlocked(root) {
|
|
|
2354
2359
|
return layout;
|
|
2355
2360
|
}
|
|
2356
2361
|
async function loadKnowledgePages(root, options = {}) {
|
|
2357
|
-
|
|
2362
|
+
const { views } = await readKnowledgePageViews([root], options);
|
|
2363
|
+
return views[0].pages.map((page) => structuredClone(page));
|
|
2358
2364
|
}
|
|
2359
|
-
|
|
2365
|
+
const MAX_CACHED_ROOTS = 8;
|
|
2366
|
+
const MAX_CACHED_SOURCE_BYTES = 67108864;
|
|
2367
|
+
const RACY_NS = 1000000000n;
|
|
2368
|
+
const cachedViews = /* @__PURE__ */ new Map();
|
|
2369
|
+
const refreshes = /* @__PURE__ */ new Map();
|
|
2370
|
+
/**
|
|
2371
|
+
* Internal. Each root's pages under one pages directory; a file is read and parsed again only when
|
|
2372
|
+
* its identity (device, inode, size, mtime, ctime) changed, so a read of an unchanged store reads
|
|
2373
|
+
* no page. `pagesRead` counts the files this call's refreshes read from disk. Roots read together
|
|
2374
|
+
* stay cached together; other roots are evicted beyond a root and byte bound, oldest first.
|
|
2375
|
+
*/
|
|
2376
|
+
async function readKnowledgePageViews(roots, options = {}) {
|
|
2360
2377
|
const pagesDirectory = normalizePagesDirectory(options.pagesDirectory);
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2378
|
+
const keys = roots.map((root) => JSON.stringify([resolve(root), pagesDirectory]));
|
|
2379
|
+
const loaded = await Promise.all(roots.map((root, index) => refreshView(keys[index], resolve(root), pagesDirectory)));
|
|
2380
|
+
let bytes = 0;
|
|
2381
|
+
for (const view of cachedViews.values()) bytes += view.bytes;
|
|
2382
|
+
for (const [key, view] of cachedViews) {
|
|
2383
|
+
if (cachedViews.size <= MAX_CACHED_ROOTS && bytes <= MAX_CACHED_SOURCE_BYTES) break;
|
|
2384
|
+
if (keys.includes(key)) continue;
|
|
2385
|
+
cachedViews.delete(key);
|
|
2386
|
+
bytes -= view.bytes;
|
|
2367
2387
|
}
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2388
|
+
return {
|
|
2389
|
+
views: loaded.map((item) => item.view),
|
|
2390
|
+
pagesRead: loaded.reduce((sum, item) => sum + item.pagesRead, 0)
|
|
2391
|
+
};
|
|
2392
|
+
}
|
|
2393
|
+
function refreshView(key, root, pagesDirectory) {
|
|
2394
|
+
const start = () => loadView(root, pagesDirectory, cachedViews.get(key)).then((loaded) => {
|
|
2395
|
+
cachedViews.delete(key);
|
|
2396
|
+
cachedViews.set(key, loaded.view);
|
|
2397
|
+
return loaded;
|
|
2398
|
+
});
|
|
2399
|
+
if (isKnowledgeRootHeld(root)) return start();
|
|
2400
|
+
const state = refreshes.get(key) ?? {};
|
|
2401
|
+
refreshes.set(key, state);
|
|
2402
|
+
state.next ??= (state.running ?? Promise.resolve()).catch(() => void 0).then(() => {
|
|
2403
|
+
state.next = void 0;
|
|
2404
|
+
const running = start().finally(() => {
|
|
2405
|
+
if (state.running === running) state.running = void 0;
|
|
2406
|
+
if (!state.running && !state.next) refreshes.delete(key);
|
|
2407
|
+
});
|
|
2408
|
+
state.running = running;
|
|
2409
|
+
return running;
|
|
2410
|
+
});
|
|
2411
|
+
return state.next;
|
|
2412
|
+
}
|
|
2413
|
+
function loadView(root, pagesDirectory, previous) {
|
|
2414
|
+
return withKnowledgeRead(root, async () => {
|
|
2415
|
+
const recent = BigInt(Date.now()) * 1000000n - RACY_NS;
|
|
2416
|
+
let listed;
|
|
2417
|
+
try {
|
|
2418
|
+
listed = await listRegularFileMetadataWithinRoot(root, pagesDirectory);
|
|
2419
|
+
} catch (error) {
|
|
2420
|
+
if (!isMissingFile(error)) throw error;
|
|
2421
|
+
listed = [];
|
|
2422
|
+
}
|
|
2423
|
+
const trusted = (file) => file.changedNs < recent ? file.generation : "";
|
|
2424
|
+
const generation = listed.every((file) => trusted(file) !== "") ? JSON.stringify(listed.map((file) => [file.path, file.generation])) : void 0;
|
|
2425
|
+
if (generation !== void 0 && previous?.generation === generation) return {
|
|
2426
|
+
view: previous,
|
|
2427
|
+
pagesRead: 0
|
|
2428
|
+
};
|
|
2429
|
+
const files = /* @__PURE__ */ new Map();
|
|
2430
|
+
const changed = [];
|
|
2431
|
+
for (const file of listed) {
|
|
2432
|
+
const known = previous?.files.get(file.path);
|
|
2433
|
+
if (known?.generation === file.generation) files.set(file.path, known);
|
|
2434
|
+
else if (isKnowledgePagePath(file.path)) changed.push(file);
|
|
2435
|
+
}
|
|
2436
|
+
const parse = (file, bytes) => {
|
|
2437
|
+
const page = knowledgePageFromMarkdown(file.path, bytes.toString("utf8"), pagesDirectory);
|
|
2438
|
+
const known = previous?.files.get(file.path)?.page;
|
|
2439
|
+
const same = known?.text === page.text && JSON.stringify(known.frontmatter) === JSON.stringify(page.frontmatter);
|
|
2440
|
+
files.set(file.path, {
|
|
2441
|
+
generation: trusted(file),
|
|
2442
|
+
page: same ? known : freezeView(page)
|
|
2443
|
+
});
|
|
2444
|
+
};
|
|
2445
|
+
let pagesRead = changed.length;
|
|
2446
|
+
if (changed.length > listed.length / 2) {
|
|
2447
|
+
const wanted = new Map(changed.map((file) => [file.path, file]));
|
|
2448
|
+
const walked = await listRegularFilesWithinRoot(root, pagesDirectory);
|
|
2449
|
+
for (const file of walked) {
|
|
2450
|
+
const listedFile = wanted.get(file.path);
|
|
2451
|
+
if (listedFile) parse(listedFile, file.bytes);
|
|
2452
|
+
}
|
|
2453
|
+
pagesRead = walked.length;
|
|
2454
|
+
} else await mapFileIo(changed, async (file) => {
|
|
2455
|
+
try {
|
|
2456
|
+
parse(file, (await readRegularFileWithinRoot(root, file.path)).bytes);
|
|
2457
|
+
} catch (error) {
|
|
2458
|
+
if (!isMissingFile(error)) throw error;
|
|
2459
|
+
}
|
|
2460
|
+
});
|
|
2461
|
+
const pages = [...files.values()].map((file) => file.page).sort((a, b) => a.path.localeCompare(b.path));
|
|
2462
|
+
const bytes = listed.reduce((sum, file) => sum + file.bytes, 0);
|
|
2463
|
+
if (previous?.pages.length === pages.length && pages.every((p, i) => p === previous.pages[i])) return {
|
|
2464
|
+
view: Object.assign(previous, {
|
|
2465
|
+
generation,
|
|
2466
|
+
bytes,
|
|
2467
|
+
files
|
|
2468
|
+
}),
|
|
2469
|
+
pagesRead
|
|
2470
|
+
};
|
|
2471
|
+
return {
|
|
2472
|
+
view: {
|
|
2473
|
+
pages: Object.freeze(pages),
|
|
2474
|
+
generation,
|
|
2475
|
+
bytes,
|
|
2476
|
+
files
|
|
2477
|
+
},
|
|
2478
|
+
pagesRead
|
|
2479
|
+
};
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
function freezeView(value) {
|
|
2483
|
+
if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
|
|
2484
|
+
for (const child of Object.values(value)) freezeView(child);
|
|
2485
|
+
Object.freeze(value);
|
|
2373
2486
|
}
|
|
2374
|
-
|
|
2375
|
-
return pages;
|
|
2487
|
+
return value;
|
|
2376
2488
|
}
|
|
2377
2489
|
/** True when a root-relative path names authored Markdown rather than scaffolding. */
|
|
2378
2490
|
function isKnowledgePagePath(path) {
|
|
@@ -4154,25 +4266,22 @@ function prepareKnowledgeValidation(index) {
|
|
|
4154
4266
|
* the same report on every run.
|
|
4155
4267
|
*/
|
|
4156
4268
|
function detectNearDuplicatePages(pages, options = {}) {
|
|
4157
|
-
const threshold =
|
|
4158
|
-
const minCharacters = nonNegativeInteger(options.minCharacters ?? 80, "minCharacters");
|
|
4159
|
-
const wordShingleSize = positiveInteger(options.wordShingleSize ?? 5, "wordShingleSize");
|
|
4160
|
-
const characterShingleSize = positiveInteger(options.characterShingleSize ?? 16, "characterShingleSize");
|
|
4161
|
-
const maxDocumentFrequency = positiveInteger(options.maxDocumentFrequency ?? 64, "maxDocumentFrequency");
|
|
4269
|
+
const { threshold, minCharacters, wordShingleSize, characterShingleSize, maxDocumentFrequency } = settings(options);
|
|
4162
4270
|
const maxCandidatePairs = positiveInteger(options.maxCandidatePairs ?? 25e4, "maxCandidatePairs");
|
|
4163
4271
|
const maxReportedPairs = nonNegativeInteger(options.maxReportedPairs ?? 1e3, "maxReportedPairs");
|
|
4164
4272
|
const prepared = pages.map((page) => preparePage(page, wordShingleSize, characterShingleSize)).filter((item) => item !== null && item.normalized.length >= minCharacters).sort((left, right) => left.page.path.localeCompare(right.page.path));
|
|
4165
4273
|
const candidateKeys = /* @__PURE__ */ new Set();
|
|
4166
4274
|
const exactGroups = /* @__PURE__ */ new Map();
|
|
4167
4275
|
const byShingle = /* @__PURE__ */ new Map();
|
|
4276
|
+
const group = (groups, key) => groups.get(key) ?? groups.set(key, []).get(key);
|
|
4168
4277
|
for (const [index, item] of prepared.entries()) {
|
|
4169
|
-
exactGroups
|
|
4170
|
-
for (const shingle of item.shingles) byShingle
|
|
4278
|
+
group(exactGroups, item.normalized).push(index);
|
|
4279
|
+
for (const shingle of item.shingles) group(byShingle, shingle).push(index);
|
|
4171
4280
|
}
|
|
4172
4281
|
let truncated = false;
|
|
4173
4282
|
const addPair = (left, right) => {
|
|
4174
4283
|
if (left === right) return true;
|
|
4175
|
-
const key =
|
|
4284
|
+
const key = Math.min(left, right) * prepared.length + Math.max(left, right);
|
|
4176
4285
|
if (candidateKeys.has(key)) return true;
|
|
4177
4286
|
if (candidateKeys.size >= maxCandidatePairs) {
|
|
4178
4287
|
truncated = true;
|
|
@@ -4191,8 +4300,9 @@ function detectNearDuplicatePages(pages, options = {}) {
|
|
|
4191
4300
|
const pairs = [];
|
|
4192
4301
|
let duplicatePairCount = 0;
|
|
4193
4302
|
let comparedPairCount = 0;
|
|
4194
|
-
for (const key of [...candidateKeys].sort(
|
|
4195
|
-
const
|
|
4303
|
+
for (const key of [...candidateKeys].sort((left, right) => left - right)) {
|
|
4304
|
+
const leftIndex = Math.floor(key / prepared.length);
|
|
4305
|
+
const rightIndex = key % prepared.length;
|
|
4196
4306
|
const left = prepared[leftIndex];
|
|
4197
4307
|
const right = prepared[rightIndex];
|
|
4198
4308
|
comparedPairCount += 1;
|
|
@@ -4232,6 +4342,94 @@ function detectNearDuplicatePages(pages, options = {}) {
|
|
|
4232
4342
|
pairs
|
|
4233
4343
|
};
|
|
4234
4344
|
}
|
|
4345
|
+
function settings(options) {
|
|
4346
|
+
return {
|
|
4347
|
+
threshold: finiteUnitInterval(options.threshold ?? .82, "threshold"),
|
|
4348
|
+
minCharacters: nonNegativeInteger(options.minCharacters ?? 80, "minCharacters"),
|
|
4349
|
+
wordShingleSize: positiveInteger(options.wordShingleSize ?? 5, "wordShingleSize"),
|
|
4350
|
+
characterShingleSize: positiveInteger(options.characterShingleSize ?? 16, "characterShingleSize"),
|
|
4351
|
+
maxDocumentFrequency: positiveInteger(options.maxDocumentFrequency ?? 64, "maxDocumentFrequency")
|
|
4352
|
+
};
|
|
4353
|
+
}
|
|
4354
|
+
const sketches = /* @__PURE__ */ new Map();
|
|
4355
|
+
/**
|
|
4356
|
+
* Every pair between a candidate and another page of `pages` (which holds the candidates) at or
|
|
4357
|
+
* above the threshold. A pair qualifies as in `detectNearDuplicatePages`, an exact normalized copy
|
|
4358
|
+
* or a shared shingle held by at most `maxDocumentFrequency` pages, but no pair cap applies: only
|
|
4359
|
+
* the candidates' shingles index the corpus, as sorted 32-bit shingle hashes kept per frozen page.
|
|
4360
|
+
*/
|
|
4361
|
+
function detectCandidateNearDuplicates(candidates, pages, options = {}) {
|
|
4362
|
+
const config = settings(options);
|
|
4363
|
+
const key = `${config.wordShingleSize}:${config.characterShingleSize}`;
|
|
4364
|
+
const cache = sketches.get(key) ?? sketches.set(key, /* @__PURE__ */ new WeakMap()).get(key);
|
|
4365
|
+
const sketchOf = (page) => {
|
|
4366
|
+
let sketch = cache.get(page);
|
|
4367
|
+
if (sketch === void 0) {
|
|
4368
|
+
const item = preparePage(page, config.wordShingleSize, config.characterShingleSize);
|
|
4369
|
+
const sorted = Uint32Array.from(item?.shingles ?? [], hash32).sort();
|
|
4370
|
+
sketch = item && {
|
|
4371
|
+
length: item.normalized.length,
|
|
4372
|
+
exact: hash32(item.normalized),
|
|
4373
|
+
hashes: sorted.filter((value, index) => index === 0 || sorted[index - 1] !== value)
|
|
4374
|
+
};
|
|
4375
|
+
if (Object.isFrozen(page)) cache.set(page, sketch);
|
|
4376
|
+
}
|
|
4377
|
+
return sketch && sketch.length >= config.minCharacters ? sketch : null;
|
|
4378
|
+
};
|
|
4379
|
+
const eligible = pages.flatMap((page) => {
|
|
4380
|
+
const sketch = sketchOf(page);
|
|
4381
|
+
return sketch ? [{
|
|
4382
|
+
page,
|
|
4383
|
+
sketch
|
|
4384
|
+
}] : [];
|
|
4385
|
+
}).sort((left, right) => left.page.path.localeCompare(right.page.path));
|
|
4386
|
+
const position = new Map(eligible.map((entry, index) => [entry.page, index]));
|
|
4387
|
+
const holders = /* @__PURE__ */ new Map();
|
|
4388
|
+
for (const candidate of candidates.filter((page) => position.has(page))) {
|
|
4389
|
+
const sketch = eligible[position.get(candidate)].sketch;
|
|
4390
|
+
for (const hash of [~sketch.exact, ...sketch.hashes]) holders.set(hash, []);
|
|
4391
|
+
}
|
|
4392
|
+
for (const [index, { sketch }] of eligible.entries()) {
|
|
4393
|
+
holders.get(~sketch.exact)?.push(index);
|
|
4394
|
+
for (const hash of sketch.hashes) {
|
|
4395
|
+
const group = holders.get(hash);
|
|
4396
|
+
if (group && group.length <= config.maxDocumentFrequency) group.push(index);
|
|
4397
|
+
}
|
|
4398
|
+
}
|
|
4399
|
+
const text = (page) => normalizePageText(`${page.title}\n${page.text}`);
|
|
4400
|
+
const pairs = candidates.flatMap((candidate) => {
|
|
4401
|
+
const self = position.get(candidate);
|
|
4402
|
+
if (self === void 0) return [];
|
|
4403
|
+
const { sketch } = eligible[self];
|
|
4404
|
+
const matches = new Set(holders.get(~sketch.exact));
|
|
4405
|
+
for (const hash of sketch.hashes) {
|
|
4406
|
+
const group = holders.get(hash);
|
|
4407
|
+
if (group.length <= config.maxDocumentFrequency) for (const index of group) matches.add(index);
|
|
4408
|
+
}
|
|
4409
|
+
return [...matches].flatMap((index) => {
|
|
4410
|
+
const matched = eligible[index];
|
|
4411
|
+
if (index === self || index < self && candidates.includes(matched.page)) return [];
|
|
4412
|
+
const exact = matched.sketch.exact === sketch.exact && text(matched.page) === text(candidate);
|
|
4413
|
+
const { similarity } = sortedJaccard(sketch.hashes, matched.sketch.hashes);
|
|
4414
|
+
if (!exact && similarity < config.threshold) return [];
|
|
4415
|
+
return [{
|
|
4416
|
+
candidate,
|
|
4417
|
+
matched: matched.page,
|
|
4418
|
+
similarity: exact ? 1 : round(similarity),
|
|
4419
|
+
exact
|
|
4420
|
+
}];
|
|
4421
|
+
});
|
|
4422
|
+
});
|
|
4423
|
+
return {
|
|
4424
|
+
threshold: config.threshold,
|
|
4425
|
+
pairs
|
|
4426
|
+
};
|
|
4427
|
+
}
|
|
4428
|
+
function hash32(value) {
|
|
4429
|
+
let hash = 2166136261;
|
|
4430
|
+
for (let index = 0; index < value.length; index += 1) hash = Math.imul(hash ^ value.charCodeAt(index), 16777619);
|
|
4431
|
+
return hash >>> 0;
|
|
4432
|
+
}
|
|
4235
4433
|
function preparePage(page, wordShingleSize, characterShingleSize) {
|
|
4236
4434
|
const normalized = normalizePageText(`${page.title}\n${page.text}`);
|
|
4237
4435
|
if (normalized.length === 0) return null;
|
|
@@ -4268,25 +4466,26 @@ function jaccard(left, right) {
|
|
|
4268
4466
|
const [small, large] = left.size <= right.size ? [left, right] : [right, left];
|
|
4269
4467
|
let intersectionSize = 0;
|
|
4270
4468
|
for (const item of small) if (large.has(item)) intersectionSize += 1;
|
|
4271
|
-
|
|
4469
|
+
return overlap(left.size, right.size, intersectionSize);
|
|
4470
|
+
}
|
|
4471
|
+
function sortedJaccard(left, right) {
|
|
4472
|
+
let shared = 0;
|
|
4473
|
+
for (let i = 0, j = 0; i < left.length && j < right.length;) {
|
|
4474
|
+
if (left[i] === right[j]) shared += 1;
|
|
4475
|
+
const step = left[i] - right[j];
|
|
4476
|
+
if (step <= 0) i += 1;
|
|
4477
|
+
if (step >= 0) j += 1;
|
|
4478
|
+
}
|
|
4479
|
+
return overlap(left.length, right.length, shared);
|
|
4480
|
+
}
|
|
4481
|
+
function overlap(left, right, intersectionSize) {
|
|
4482
|
+
const unionSize = left + right - intersectionSize;
|
|
4272
4483
|
return {
|
|
4273
4484
|
similarity: unionSize === 0 ? 1 : intersectionSize / unionSize,
|
|
4274
4485
|
intersectionSize,
|
|
4275
4486
|
unionSize
|
|
4276
4487
|
};
|
|
4277
4488
|
}
|
|
4278
|
-
function pairKey(left, right) {
|
|
4279
|
-
return `${left}:${right}`;
|
|
4280
|
-
}
|
|
4281
|
-
function parsePairKey(value) {
|
|
4282
|
-
const [left, right] = value.split(":");
|
|
4283
|
-
return [Number(left), Number(right)];
|
|
4284
|
-
}
|
|
4285
|
-
function pairKeyOrder(left, right) {
|
|
4286
|
-
const [leftA, leftB] = parsePairKey(left);
|
|
4287
|
-
const [rightA, rightB] = parsePairKey(right);
|
|
4288
|
-
return leftA - rightA || leftB - rightB;
|
|
4289
|
-
}
|
|
4290
4489
|
function finiteUnitInterval(value, name) {
|
|
4291
4490
|
if (!Number.isFinite(value) || value < 0 || value > 1) throw new Error(`${name} must be a finite number in [0, 1]`);
|
|
4292
4491
|
return value;
|
|
@@ -4573,11 +4772,12 @@ const toolViews = /* @__PURE__ */ new WeakSet();
|
|
|
4573
4772
|
function isKnowledgeToolChain(chain) {
|
|
4574
4773
|
return toolViews.has(chain);
|
|
4575
4774
|
}
|
|
4576
|
-
const MAX_CACHED_ROOTS = 8;
|
|
4577
|
-
const MAX_CACHED_SOURCE_BYTES = 67108864;
|
|
4578
4775
|
/** Internal tool path. Custom stores retain their existing loadChain contract. */
|
|
4579
|
-
function loadKnowledgeToolChain(stores, runId) {
|
|
4580
|
-
return toolViewLoaders.get(stores)?.(runId) ??
|
|
4776
|
+
async function loadKnowledgeToolChain(stores, runId) {
|
|
4777
|
+
return await toolViewLoaders.get(stores)?.(runId) ?? {
|
|
4778
|
+
chain: await stores.loadChain(runId),
|
|
4779
|
+
timing: {}
|
|
4780
|
+
};
|
|
4581
4781
|
}
|
|
4582
4782
|
function createRunScopedStores(options) {
|
|
4583
4783
|
if (!options || typeof options !== "object") throw new TypeError("createRunScopedStores options are required");
|
|
@@ -4629,118 +4829,14 @@ function createRunScopedStores(options) {
|
|
|
4629
4829
|
},
|
|
4630
4830
|
lineage: resolveLineage,
|
|
4631
4831
|
async loadChain(runId) {
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
pages = await loadKnowledgePages(root, { pagesDirectory });
|
|
4638
|
-
} catch (error) {
|
|
4639
|
-
if (isMissingFile(error)) return;
|
|
4640
|
-
throw error;
|
|
4641
|
-
}
|
|
4642
|
-
for (const page of pages) out.push({
|
|
4643
|
-
page,
|
|
4644
|
-
origin
|
|
4645
|
-
});
|
|
4646
|
-
};
|
|
4647
|
-
await readInto(storePath(runId), "here");
|
|
4648
|
-
for (const ancestor of await resolveLineage(runId)) await readInto(storePath(ancestor), `inherited:${ancestor}`);
|
|
4649
|
-
if (options.sharedRoot) await readInto(options.sharedRoot, "shared");
|
|
4650
|
-
return out;
|
|
4651
|
-
}
|
|
4652
|
-
};
|
|
4653
|
-
const roots = /* @__PURE__ */ new Map();
|
|
4654
|
-
let current;
|
|
4655
|
-
const loadRoot = (root, previous) => withKnowledgeRead(root, async () => {
|
|
4656
|
-
let listed;
|
|
4657
|
-
try {
|
|
4658
|
-
listed = await listRegularFileMetadataWithinRoot(root, pagesDirectory);
|
|
4659
|
-
} catch (error) {
|
|
4660
|
-
if (!isMissingFile(error)) throw error;
|
|
4661
|
-
listed = [];
|
|
4662
|
-
}
|
|
4663
|
-
const generation = JSON.stringify(listed.map((file) => [file.path, file.generation]));
|
|
4664
|
-
if (previous?.generation === generation) return previous;
|
|
4665
|
-
const files = /* @__PURE__ */ new Map();
|
|
4666
|
-
const changed = [];
|
|
4667
|
-
for (const file of listed) {
|
|
4668
|
-
const known = previous?.files.get(file.path);
|
|
4669
|
-
if (known?.generation === file.generation) files.set(file.path, known);
|
|
4670
|
-
else if (!isKnowledgePagePath(file.path)) files.set(file.path, {
|
|
4671
|
-
generation: file.generation,
|
|
4672
|
-
page: void 0
|
|
4673
|
-
});
|
|
4674
|
-
else changed.push(file);
|
|
4675
|
-
}
|
|
4676
|
-
const parse = (path, generation, bytes) => files.set(path, {
|
|
4677
|
-
generation,
|
|
4678
|
-
page: freezeView(knowledgePageFromMarkdown(path, bytes.toString("utf8"), pagesDirectory))
|
|
4679
|
-
});
|
|
4680
|
-
if (changed.length > 64) {
|
|
4681
|
-
const wanted = new Map(changed.map((file) => [file.path, file.generation]));
|
|
4682
|
-
for (const file of await listRegularFilesWithinRoot(root, pagesDirectory)) {
|
|
4683
|
-
const generation = wanted.get(file.path);
|
|
4684
|
-
if (generation !== void 0) parse(file.path, generation, file.bytes);
|
|
4685
|
-
}
|
|
4686
|
-
} else await Promise.all(changed.map(async (file) => {
|
|
4687
|
-
try {
|
|
4688
|
-
parse(file.path, file.generation, (await readRegularFileWithinRoot(root, file.path)).bytes);
|
|
4689
|
-
} catch (error) {
|
|
4690
|
-
if (!isMissingFile(error)) throw error;
|
|
4691
|
-
}
|
|
4692
|
-
}));
|
|
4693
|
-
const pages = Object.freeze([...files.values()].flatMap((file) => file.page ? [file.page] : []).sort((a, b) => a.path.localeCompare(b.path)));
|
|
4694
|
-
return {
|
|
4695
|
-
generation,
|
|
4696
|
-
bytes: listed.reduce((sum, file) => sum + file.bytes, 0),
|
|
4697
|
-
files,
|
|
4698
|
-
pages
|
|
4699
|
-
};
|
|
4700
|
-
});
|
|
4701
|
-
const refreshes = /* @__PURE__ */ new Map();
|
|
4702
|
-
const readRoot = (root) => {
|
|
4703
|
-
let state = refreshes.get(root);
|
|
4704
|
-
if (!state) {
|
|
4705
|
-
state = {};
|
|
4706
|
-
refreshes.set(root, state);
|
|
4832
|
+
const { scopes, views } = await readChain(runId);
|
|
4833
|
+
return views.flatMap((view, i) => view.pages.map((page) => ({
|
|
4834
|
+
page: structuredClone(page),
|
|
4835
|
+
origin: scopes[i].origin
|
|
4836
|
+
})));
|
|
4707
4837
|
}
|
|
4708
|
-
const slot = state;
|
|
4709
|
-
const start = () => {
|
|
4710
|
-
const running = loadRoot(root, roots.get(root)).then((loaded) => retain(root, loaded)).finally(() => {
|
|
4711
|
-
if (slot.running === running) slot.running = void 0;
|
|
4712
|
-
if (!slot.running && !slot.next && refreshes.get(root) === slot) refreshes.delete(root);
|
|
4713
|
-
});
|
|
4714
|
-
slot.running = running;
|
|
4715
|
-
return running;
|
|
4716
|
-
};
|
|
4717
|
-
if (slot.next) return slot.next;
|
|
4718
|
-
if (!slot.running) return start();
|
|
4719
|
-
const next = slot.running.catch(() => void 0).then(() => {
|
|
4720
|
-
slot.next = void 0;
|
|
4721
|
-
return start();
|
|
4722
|
-
});
|
|
4723
|
-
slot.next = next;
|
|
4724
|
-
return next;
|
|
4725
4838
|
};
|
|
4726
|
-
const
|
|
4727
|
-
const existing = roots.get(root);
|
|
4728
|
-
if (existing?.generation === loaded.generation) return existing;
|
|
4729
|
-
roots.delete(root);
|
|
4730
|
-
roots.set(root, loaded);
|
|
4731
|
-
const live = new Set(current?.identities.map((identity) => JSON.parse(identity)[0]));
|
|
4732
|
-
live.add(root);
|
|
4733
|
-
let bytes = 0;
|
|
4734
|
-
for (const part of roots.values()) bytes += part.bytes;
|
|
4735
|
-
for (const [candidate, part] of roots) {
|
|
4736
|
-
if (roots.size <= MAX_CACHED_ROOTS && bytes <= MAX_CACHED_SOURCE_BYTES) break;
|
|
4737
|
-
if (live.has(candidate)) continue;
|
|
4738
|
-
roots.delete(candidate);
|
|
4739
|
-
bytes -= part.bytes;
|
|
4740
|
-
}
|
|
4741
|
-
return loaded;
|
|
4742
|
-
};
|
|
4743
|
-
toolViewLoaders.set(stores, async (runId) => {
|
|
4839
|
+
const readChain = async (runId) => {
|
|
4744
4840
|
assertRunId(runId);
|
|
4745
4841
|
const scopes = [{
|
|
4746
4842
|
root: storePath(runId),
|
|
@@ -4754,31 +4850,35 @@ function createRunScopedStores(options) {
|
|
|
4754
4850
|
root: options.sharedRoot,
|
|
4755
4851
|
origin: "shared"
|
|
4756
4852
|
});
|
|
4757
|
-
|
|
4758
|
-
|
|
4853
|
+
return {
|
|
4854
|
+
scopes,
|
|
4855
|
+
...await readKnowledgePageViews(scopes.map((scope) => scope.root), { pagesDirectory })
|
|
4856
|
+
};
|
|
4857
|
+
};
|
|
4858
|
+
let current;
|
|
4859
|
+
toolViewLoaders.set(stores, async (runId) => {
|
|
4860
|
+
const { scopes, views: parts, pagesRead } = await readChain(runId);
|
|
4861
|
+
const origins = scopes.map((scope) => scope.origin);
|
|
4759
4862
|
const latest = current;
|
|
4760
|
-
if (latest
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4863
|
+
if (latest?.parts.length !== parts.length || parts.some((part, i) => part !== latest.parts[i] || origins[i] !== latest.origins[i])) {
|
|
4864
|
+
const chain = Object.freeze(parts.flatMap((part, i) => part.pages.map((page) => Object.freeze({
|
|
4865
|
+
page,
|
|
4866
|
+
origin: origins[i]
|
|
4867
|
+
}))));
|
|
4868
|
+
toolViews.add(chain);
|
|
4869
|
+
current = {
|
|
4870
|
+
origins,
|
|
4871
|
+
parts,
|
|
4872
|
+
chain
|
|
4873
|
+
};
|
|
4874
|
+
}
|
|
4875
|
+
return {
|
|
4876
|
+
chain: current.chain,
|
|
4877
|
+
timing: { pagesRead }
|
|
4770
4878
|
};
|
|
4771
|
-
return chain;
|
|
4772
4879
|
});
|
|
4773
4880
|
return stores;
|
|
4774
4881
|
}
|
|
4775
|
-
function freezeView(value) {
|
|
4776
|
-
if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
|
|
4777
|
-
for (const child of Object.values(value)) freezeView(child);
|
|
4778
|
-
Object.freeze(value);
|
|
4779
|
-
}
|
|
4780
|
-
return value;
|
|
4781
|
-
}
|
|
4782
4882
|
/** File-backed authority used when the product has no separate run manifest. */
|
|
4783
4883
|
function createFileRunLineageAuthority(runStorePath) {
|
|
4784
4884
|
if (typeof runStorePath !== "function") throw new TypeError("createFileRunLineageAuthority requires a runStorePath function");
|
|
@@ -4893,46 +4993,26 @@ function assertKnowledgeWriteIntake(candidates, options) {
|
|
|
4893
4993
|
page,
|
|
4894
4994
|
origin: "here"
|
|
4895
4995
|
}))];
|
|
4896
|
-
assertNoUnrelatedDuplicate(
|
|
4996
|
+
assertNoUnrelatedDuplicate(candidates, corpus, options.nearDuplicates ?? {});
|
|
4897
4997
|
if (options.citations === false) return Object.freeze([]);
|
|
4898
4998
|
return assertKnowledgeCitationsResolved(corpus, candidates.flatMap((candidate) => (candidate.cites ?? []).map((persisted) => parseKnowledgeCitationReference(persisted))));
|
|
4899
4999
|
}
|
|
4900
|
-
function assertNoUnrelatedDuplicate(
|
|
4901
|
-
|
|
4902
|
-
const
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
if (!leftIsCandidate && !candidatePaths.has(pair.rightPath)) continue;
|
|
4912
|
-
if (pair.leftPageId === pair.rightPageId) continue;
|
|
4913
|
-
const left = byIdentity.get(identityKey(pair.leftPath, pair.leftPageId));
|
|
4914
|
-
const right = byIdentity.get(identityKey(pair.rightPath, pair.rightPageId));
|
|
4915
|
-
if (declaresRelation(left, right.id) || declaresRelation(right, left.id)) continue;
|
|
4916
|
-
const candidate = leftIsCandidate ? left : right;
|
|
4917
|
-
const matched = leftIsCandidate ? right : left;
|
|
4918
|
-
offending.push({
|
|
4919
|
-
candidatePageId: candidate.id,
|
|
4920
|
-
candidatePath: candidate.path,
|
|
4921
|
-
matchedPageId: matched.id,
|
|
4922
|
-
matchedPath: matched.path,
|
|
4923
|
-
similarity: pair.similarity,
|
|
4924
|
-
exact: pair.exact
|
|
4925
|
-
});
|
|
4926
|
-
}
|
|
4927
|
-
if (offending.length > 0) throw new KnowledgeDuplicateIntakeError(offending, report.threshold);
|
|
4928
|
-
}
|
|
4929
|
-
function identityKey(path, id) {
|
|
4930
|
-
return `${path}\u0000${id}`;
|
|
5000
|
+
function assertNoUnrelatedDuplicate(candidates, corpus, nearDuplicates) {
|
|
5001
|
+
const { threshold, pairs } = detectCandidateNearDuplicates(candidates, corpus.map((entry) => entry.page), nearDuplicates);
|
|
5002
|
+
const offending = pairs.filter(({ candidate: c, matched: m }) => c.id !== m.id && !relates(c, m) && !relates(m, c)).map(({ candidate, matched, similarity, exact }) => ({
|
|
5003
|
+
candidatePageId: candidate.id,
|
|
5004
|
+
candidatePath: candidate.path,
|
|
5005
|
+
matchedPageId: matched.id,
|
|
5006
|
+
matchedPath: matched.path,
|
|
5007
|
+
similarity,
|
|
5008
|
+
exact
|
|
5009
|
+
}));
|
|
5010
|
+
if (offending.length > 0) throw new KnowledgeDuplicateIntakeError(offending, threshold);
|
|
4931
5011
|
}
|
|
4932
|
-
/** Whether `page` already relates itself to `
|
|
4933
|
-
function
|
|
4934
|
-
for (const persisted of page.cites ?? []) if (parseKnowledgeCitationReference(persisted).pageId ===
|
|
4935
|
-
return (page.contradicts ?? []).includes(
|
|
5012
|
+
/** Whether `page` already relates itself to `target` through `cites` or `contradicts`. */
|
|
5013
|
+
function relates(page, target) {
|
|
5014
|
+
for (const persisted of page.cites ?? []) if (parseKnowledgeCitationReference(persisted).pageId === target.id) return true;
|
|
5015
|
+
return (page.contradicts ?? []).includes(target.id);
|
|
4936
5016
|
}
|
|
4937
5017
|
// src/write-protocol.ts
|
|
4938
5018
|
const OPENER_LINE = /^---\s*FILE:\s*(.+?)\s*---\s*$/i;
|
|
@@ -5053,10 +5133,10 @@ async function applyKnowledgeWriteBlocks(root, proposalText, options = {}) {
|
|
|
5053
5133
|
}
|
|
5054
5134
|
if (intake) {
|
|
5055
5135
|
const { inheritedPages = [], ...settings } = intake;
|
|
5056
|
-
const
|
|
5136
|
+
const { views } = await readKnowledgePageViews([root], { pagesDirectory });
|
|
5057
5137
|
assertKnowledgeWriteIntake(mutations.filter((mutation) => isKnowledgePagePath(mutation.path)).map((mutation) => knowledgePageFromMarkdown(mutation.path, mutation.content, pagesDirectory)), {
|
|
5058
5138
|
...settings,
|
|
5059
|
-
visiblePages: [...originatedPages(
|
|
5139
|
+
visiblePages: [...originatedPages(views[0].pages), ...inheritedPages]
|
|
5060
5140
|
});
|
|
5061
5141
|
}
|
|
5062
5142
|
await commitKnowledgeFileMutations({
|
|
@@ -5157,4 +5237,4 @@ function explainKnowledgeTarget(index, target) {
|
|
|
5157
5237
|
}
|
|
5158
5238
|
export { loadSourceRegistry as $, writeFileDurableWithinRoot as $n, KNOWLEDGE_EVENT_TYPES as $t, validateKnowledgePage as A, finishKnowledgeFileTransaction as An, isScaffoldPath as At, CHECKABLE_RUNG_THRESHOLD as B, canonicalRelativeWithinRoot as Bn, KnowledgeEventSchema as Bt, immutablePageDigest as C, runInKnowledgeMutationScope as Cn, resolveKnowledgeCitation as Ct, normalizeVisibilityArtifact as D, applyKnowledgeFileTransaction as Dn, SCAFFOLD_PAGE_BASENAMES as Dt, nonEmpty as E, withKnowledgeRead as En, resolveRunScopedCitations as Et, detectNearDuplicatePages as F, recordLockOwner as Fn, WIKILINK_REGEX as Ft, gradeClaims as G, readRegularFileWithinRoot as Gn, KnowledgePageSchema as Gt, UncheckableClaimError as H, isMissingFile as Hn, KnowledgeGraphNodeSchema as Ht, normalizePageText as I, takeOverDeadHolder as In, extractWikilinks as It, verifyGradeableEvidence as J, renameDurable as Jn, ResearchClaimLedgerSchema as Jt, gradeFor as K, relativeWithinRoot as Kn, KnowledgeRelationSchema as Kt, prepareKnowledgeValidation as L, DEFAULT_PAGES_DIRECTORY as Ln, normalizeLinkTarget as Lt, verifyKnowledgeVisibilitySnapshot as M, prepareKnowledgeFileTransaction as Mn, layoutFor as Mt, visibilityIdentity as N, rollbackKnowledgeFileTransaction as Nn, loadKnowledgePages as Nt, normalizeVisibilityRef as O, assertKnowledgeMutationPath as On, initKnowledgeBase as Ot, visibilityIndexOf as P, RUN_LEASE as Pn, writeJson as Pt, addSourceText as Q, writeFileDurable as Qn, SourceRecordSchema as Qt, validateKnowledgeIndex as R, normalizePagesDirectory as Rn, DeepQuestionSchema as Rt, encodeKnowledgeVisibilitySnapshot as S, recoverPendingKnowledgeMutation as Sn, parseKnowledgeCitationReference as St, knowledgeVisibilityArtifactRef as T, withKnowledgeMutationLabel as Tn, resolveRunScopedCitation as Tt, assertGradeableEvidence as U, listRegularFilesWithinRoot as Un, KnowledgeIndexSchema as Ut, DEADLINE_EXIT_CODE as V, isKernelAnchoredPath as Vn, KnowledgeGraphEdgeSchema as Vt, claimCheckKey as W, readRegularFileNoFollow as Wn, KnowledgePageInvalidationSchema as Wt, writeKnowledgeIndex as X, withSafeDescendant as Xn, ResearchSourceVersionSchema as Xt, buildKnowledgeIndex as Y, syncDirectory as Yn, ResearchClaimRecordSchema as Yt, addSourcePath as Z, withSafeDirectory as Zn, SourceAnchorSchema as Zt, KNOWLEDGE_USE_RECEIPT_SCHEMA_VERSION as _, parseFrontmatter as _n, assertKnowledgeCitationsResolved as _t, applyKnowledgeWriteBlocksFile as a, claimEvidenceId as an, KB_CLAIM_LEDGER_DIR as at, decodeKnowledgeVisibilitySnapshot as b, isKnowledgeMutationHeld as bn, auditKnowledgeCitations as bt, KnowledgeDuplicateIntakeError as c, deepQuestionId as cn, KB_STORE_DIR as ct, createFileRunLineageAuthority as d, materializeRegisteredClaimEvidence as dn, buildKnowledgeGraph as dt, ClaimLedgerGoalConflictError as en, writeJsonDurable as er, snapshotSourceTextInput as et, createRunScopedStores as f, mergeClaimLedgers as fn, knowledgePageRelations as ft, KNOWLEDGE_RECEIPT_DIGEST_ALGORITHM as g, formatFrontmatter as gn, assertKnowledgeCitationAudit as gt, originatedPages as h, researchSourceVersionKey as hn, assertCurrentRunCitationsResolved as ht, applyKnowledgeWriteBlocks as i, assertTrackedClaimIntegrity as in, FileSystemKbStore as it, validateOrigin as j, knowledgeFileTransactionPlanHash as jn, knowledgePageFromMarkdown as jt, snapshotImmutableVisibility as k, commitKnowledgeFileMutations as kn, isKnowledgePagePath as kt, assertKnowledgeWriteIntake as l, emptyClaimLedger as ln, MemoryKbStore as lt, loadKnowledgeToolChain as m, normalizeClaimText as mn, KnowledgeCitationResolutionError as mt, inspectKnowledgeIndex as n, assertResearchClaimEvidenceIntegrity as nn, mediaTypeFor$1 as nr, writeSourceRegistry as nt, isSafeKnowledgePath as o, claimId as on, KB_EVENTS_PATH as ot, isKnowledgeToolChain as p, mergeTrackedClaims as pn, KnowledgeCitationAuditError as pt, verdictFor as q, removeDurable as qn, ResearchClaimEvidenceSchema as qt, stringMetadata as r, assertResearchClaimLedgerIntegrity as rn, textSourceAdapter as rr, ClaimLedgerMigrationRequiredError as rt, parseKnowledgeWriteBlocks as s, claimSourceHost as sn, KB_INDEX_PATH as st, explainKnowledgeTarget as t, assertDeepQuestionIntegrity as tn, writeJsonDurableWithinRoot as tr, sourceRegistryPath as tt, RUN_LINEAGE_BASENAME as u, linkClaimContradictions as un, assertClaimLedgerId as ut, assertSchemaVersion as v, acquireDurableFileLock as vn, assertRunScopedCitationsResolved as vt, knowledgePageDigest as w, withKnowledgeMutation as wn, resolveKnowledgeCitations as wt, digest as x, measureKnowledgeMutation as xn, formatKnowledgeCitationReference as xt, createKnowledgeVisibilitySnapshot as y, inspectPendingKnowledgeMutation as yn, auditCurrentRunCitations as yt, lintKnowledgeIndex as z, canonicalPathsEqual as zn, KnowledgeBaseCandidateSchema as zt };
|
|
5159
5239
|
|
|
5160
|
-
//# sourceMappingURL=inspect-
|
|
5240
|
+
//# sourceMappingURL=inspect-CKNcuqrY.js.map
|