@tangle-network/agent-knowledge 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -32,126 +32,113 @@ import {
32
32
  parseKnowledgeWriteBlocks,
33
33
  reciprocalRankFusion,
34
34
  searchKnowledge,
35
- sha256,
36
- slugify,
37
35
  sourceRegistryPath,
38
- stableId,
39
36
  textSourceAdapter,
40
37
  tokenizeQuery,
41
38
  validateKnowledgeIndex,
42
39
  writeJson,
43
40
  writeKnowledgeIndex,
44
41
  writeSourceRegistry
45
- } from "./chunk-JLCQ6O7W.js";
42
+ } from "./chunk-HKYD765Q.js";
43
+ import {
44
+ IRS_DIMENSION_HINTS,
45
+ MAX_RESPONSE_BYTES,
46
+ MIN_REQUEST_GAP_MS,
47
+ POLITE_USER_AGENT,
48
+ __resetHttpThrottle,
49
+ createCornellLiiSource,
50
+ createIrsPublicationsSource,
51
+ createStateSosSource,
52
+ extractLinks,
53
+ firstMatch,
54
+ htmlToText,
55
+ innerHtmlById,
56
+ looksLikeBlockPage,
57
+ politeFetch
58
+ } from "./chunk-WCYW2GDA.js";
59
+ import {
60
+ sha256,
61
+ slugify,
62
+ stableId
63
+ } from "./chunk-YMKHCTS2.js";
46
64
 
47
- // src/events.ts
48
- function createKnowledgeEvent(input) {
49
- const createdAt = (input.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
65
+ // src/changes.ts
66
+ function detectChanges(prev, next, options = {}) {
67
+ const skipUnverifiable = options.skipUnverifiable ?? true;
68
+ const warnings = [];
69
+ const { map: prevMap, warnings: prevWarn } = indexFragments(prev, skipUnverifiable, "prev");
70
+ const { map: nextMap, warnings: nextWarn } = indexFragments(next, skipUnverifiable, "next");
71
+ warnings.push(...prevWarn, ...nextWarn);
72
+ const changes = [];
73
+ const seen = /* @__PURE__ */ new Set();
74
+ for (const [id, nextFragment] of nextMap) {
75
+ seen.add(id);
76
+ const prevFragment = prevMap.get(id);
77
+ if (!prevFragment) {
78
+ changes.push({
79
+ fragmentId: id,
80
+ kind: "added",
81
+ diff: { after: nextFragment.body },
82
+ affectedDimensions: dedup(nextFragment.dimensionHints),
83
+ url: nextFragment.provenance.url,
84
+ detectedAt: nextFragment.provenance.sourceUpdatedAt
85
+ });
86
+ continue;
87
+ }
88
+ if (prevFragment.bodyHash !== nextFragment.bodyHash) {
89
+ changes.push({
90
+ fragmentId: id,
91
+ kind: "modified",
92
+ diff: { before: prevFragment.body, after: nextFragment.body },
93
+ affectedDimensions: dedup([...prevFragment.dimensionHints, ...nextFragment.dimensionHints]),
94
+ url: nextFragment.provenance.url,
95
+ detectedAt: nextFragment.provenance.sourceUpdatedAt
96
+ });
97
+ }
98
+ }
99
+ for (const [id, prevFragment] of prevMap) {
100
+ if (seen.has(id)) continue;
101
+ changes.push({
102
+ fragmentId: id,
103
+ kind: "removed",
104
+ diff: { before: prevFragment.body },
105
+ affectedDimensions: dedup(prevFragment.dimensionHints),
106
+ url: prevFragment.provenance.url,
107
+ detectedAt: prevFragment.provenance.sourceUpdatedAt
108
+ });
109
+ }
110
+ const filtered = options.filterDimensions ? changes.filter((c) => c.affectedDimensions.some((d) => options.filterDimensions?.includes(d))) : changes;
50
111
  return {
51
- id: stableId("evt", `${input.type}:${input.target ?? ""}:${createdAt}:${JSON.stringify(input.metadata ?? {})}`),
52
- type: input.type,
53
- createdAt,
54
- actor: input.actor,
55
- target: input.target,
56
- metadata: input.metadata
112
+ changes: filtered,
113
+ summary: {
114
+ added: filtered.filter((c) => c.kind === "added").length,
115
+ removed: filtered.filter((c) => c.kind === "removed").length,
116
+ modified: filtered.filter((c) => c.kind === "modified").length
117
+ },
118
+ warnings
57
119
  };
58
120
  }
59
-
60
- // src/kb-store.ts
61
- import { mkdir, readFile, writeFile } from "fs/promises";
62
- import { dirname, join } from "path";
63
- var MemoryKbStore = class {
64
- sources = /* @__PURE__ */ new Map();
65
- pages = /* @__PURE__ */ new Map();
66
- events = [];
67
- index = null;
68
- async putSource(source) {
69
- this.sources.set(source.id, clone(source));
70
- }
71
- async getSource(id) {
72
- return clone(this.sources.get(id) ?? null);
73
- }
74
- async listSources() {
75
- return [...this.sources.values()].map(clone);
76
- }
77
- async putPage(page) {
78
- this.pages.set(page.id, clone(page));
79
- }
80
- async getPage(idOrPath) {
81
- return clone(this.pages.get(idOrPath) ?? [...this.pages.values()].find((page) => page.path === idOrPath) ?? null);
82
- }
83
- async listPages() {
84
- return [...this.pages.values()].map(clone);
85
- }
86
- async putIndex(index) {
87
- this.index = clone(index);
88
- }
89
- async getIndex() {
90
- if (this.index) return clone(this.index);
91
- const pages = await this.listPages();
92
- const sources = await this.listSources();
93
- return { root: "memory", generatedAt: (/* @__PURE__ */ new Date()).toISOString(), sources, pages, graph: buildKnowledgeGraph(pages) };
94
- }
95
- async putEvent(event) {
96
- this.events.push(clone(event));
97
- }
98
- async listEvents(query = {}) {
99
- let out = this.events;
100
- if (query.type) out = out.filter((event) => event.type === query.type);
101
- if (query.target) out = out.filter((event) => event.target === query.target);
102
- out = [...out].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
103
- return out.slice(-(query.limit ?? out.length)).map(clone);
104
- }
105
- };
106
- var FileSystemKbStore = class extends MemoryKbStore {
107
- constructor(dir) {
108
- super();
109
- this.dir = dir;
110
- }
111
- dir;
112
- async putIndex(index) {
113
- await super.putIndex(index);
114
- await writeJson2(join(this.dir, "index.json"), index);
115
- }
116
- async getIndex() {
117
- try {
118
- return JSON.parse(await readFile(join(this.dir, "index.json"), "utf8"));
119
- } catch {
120
- return await super.getIndex();
121
+ function indexFragments(fragments, skipUnverifiable, side) {
122
+ const map = /* @__PURE__ */ new Map();
123
+ const warnings = [];
124
+ let dropped = 0;
125
+ for (const fragment of fragments) {
126
+ if (skipUnverifiable && !fragment.provenance.verifiable) {
127
+ dropped += 1;
128
+ continue;
129
+ }
130
+ if (map.has(fragment.id)) {
131
+ warnings.push(`${side}: duplicate fragment id ${fragment.id} \u2014 keeping last`);
121
132
  }
133
+ map.set(fragment.id, fragment);
122
134
  }
123
- async putEvent(event) {
124
- await super.putEvent(event);
125
- const events = await this.listEvents();
126
- await writeJson2(join(this.dir, "events.json"), events);
135
+ if (dropped > 0) {
136
+ warnings.push(`${side}: dropped ${dropped} unverifiable fragment(s) before diff`);
127
137
  }
128
- };
129
- async function writeJson2(path, value) {
130
- await mkdir(dirname(path), { recursive: true });
131
- await writeFile(path, JSON.stringify(value, null, 2) + "\n", "utf8");
138
+ return { map, warnings };
132
139
  }
133
- function clone(value) {
134
- return value == null ? value : JSON.parse(JSON.stringify(value));
135
- }
136
-
137
- // src/discovery.ts
138
- function createLocalDiscoveryDispatcher(worker) {
139
- return {
140
- async dispatch(tasks, options = {}) {
141
- const concurrency = Math.max(1, options.concurrency ?? 4);
142
- const results = [];
143
- let cursor = 0;
144
- async function runNext() {
145
- while (cursor < tasks.length) {
146
- if (options.signal?.aborted) throw new Error("Discovery dispatch aborted");
147
- const task = tasks[cursor++];
148
- results.push(await worker.run(task, options.signal));
149
- }
150
- }
151
- await Promise.all(Array.from({ length: Math.min(concurrency, tasks.length) }, runNext));
152
- return results.sort((a, b) => tasks.findIndex((task) => task.id === a.taskId) - tasks.findIndex((task) => task.id === b.taskId));
153
- }
154
- };
140
+ function dedup(items) {
141
+ return [...new Set(items)];
155
142
  }
156
143
 
157
144
  // src/chunking.ts
@@ -198,12 +185,17 @@ function splitSections(body, bodyOffset) {
198
185
  const lines = body.split("\n");
199
186
  const sections = [];
200
187
  const headings = {};
201
- let current = { lines: [], start: bodyOffset, headingPath: "" };
188
+ let current = {
189
+ lines: [],
190
+ start: bodyOffset,
191
+ headingPath: ""
192
+ };
202
193
  let cursor = bodyOffset;
203
194
  let fence = null;
204
195
  const flush = () => {
205
196
  const text = current.lines.join("\n");
206
- if (text.trim() !== "") sections.push({ text, start: current.start, headingPath: current.headingPath });
197
+ if (text.trim() !== "")
198
+ sections.push({ text, start: current.start, headingPath: current.headingPath });
207
199
  };
208
200
  for (let i = 0; i < lines.length; i++) {
209
201
  const line = lines[i];
@@ -283,66 +275,25 @@ ${chunk.text}`;
283
275
  return out;
284
276
  }
285
277
 
286
- // src/optimization.ts
287
- import {
288
- runMultiShotOptimization
289
- } from "@tangle-network/agent-eval";
290
- async function runKnowledgeBaseOptimization(config) {
291
- return runMultiShotOptimization({
292
- ...config,
293
- target: config.target ?? "agent-knowledge-base"
294
- });
295
- }
296
- function knowledgeVariantFromCandidate(candidate, options = {}) {
278
+ // src/discovery.ts
279
+ function createLocalDiscoveryDispatcher(worker) {
297
280
  return {
298
- id: options.id ?? candidate.id,
299
- label: options.label ?? candidate.id,
300
- generation: options.generation ?? 0,
301
- payload: candidate
302
- };
303
- }
304
-
305
- // src/release.ts
306
- import {
307
- evaluateReleaseConfidence,
308
- releaseTraceEvidenceFromMultiShotTrials,
309
- validateRunRecord
310
- } from "@tangle-network/agent-eval";
311
- function knowledgeReleaseReportFromOptimization(result, options = {}) {
312
- const trials = result.evolution.generations.flatMap((generation) => generation.trials);
313
- const traceEvidence = releaseTraceEvidenceFromMultiShotTrials(trials);
314
- const runRecords = (options.runRecords ?? [
315
- ...result.gate?.candidateRuns ?? [],
316
- ...result.gate?.baselineRuns ?? []
317
- ]).map(validateRunRecord);
318
- const scorecard = evaluateReleaseConfidence({
319
- target: "agent-knowledge-base",
320
- candidateId: result.promotedVariant.id,
321
- baselineId: "baseline",
322
- traces: traceEvidence,
323
- runs: runRecords,
324
- gateDecision: result.gate?.decision ?? null,
325
- thresholds: {
326
- requireCorpus: false,
327
- requireHoldout: Boolean(result.gate),
328
- minHoldoutRuns: result.gate ? 1 : 0,
329
- minSearchRuns: 1,
330
- minMeanScore: options.minScore ?? 0.7
281
+ async dispatch(tasks, options = {}) {
282
+ const concurrency = Math.max(1, options.concurrency ?? 4);
283
+ const results = [];
284
+ let cursor = 0;
285
+ async function runNext() {
286
+ while (cursor < tasks.length) {
287
+ if (options.signal?.aborted) throw new Error("Discovery dispatch aborted");
288
+ const task = tasks[cursor++];
289
+ results.push(await worker.run(task, options.signal));
290
+ }
291
+ }
292
+ await Promise.all(Array.from({ length: Math.min(concurrency, tasks.length) }, runNext));
293
+ return results.sort(
294
+ (a, b) => tasks.findIndex((task) => task.id === a.taskId) - tasks.findIndex((task) => task.id === b.taskId)
295
+ );
331
296
  }
332
- });
333
- const release = {
334
- id: stableId("krel", `${result.promotedVariant.id}:${options.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()}`),
335
- candidateId: result.promotedVariant.id,
336
- createdAt: options.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
337
- promoted: scorecard.status !== "fail" && result.promotedVariant.id === result.searchBestVariant.id,
338
- scorecard,
339
- runRecordIds: runRecords.map((record) => record.runId)
340
- };
341
- return {
342
- release,
343
- scorecard,
344
- candidateRuns: result.gate?.candidateRuns ?? [],
345
- baselineRuns: result.gate?.baselineRuns ?? []
346
297
  };
347
298
  }
348
299
 
@@ -383,7 +334,11 @@ function buildEvalKnowledgeBundle(options) {
383
334
  userAnswers: options.userAnswers,
384
335
  evidenceIds: requirements.flatMap((requirement) => requirement.evidenceIds),
385
336
  claimIds: [],
386
- wikiPageIds: unique(requirements.flatMap((requirement) => pageIdsFromResults(searchResultsByRequirement[requirement.id] ?? []))),
337
+ wikiPageIds: unique(
338
+ requirements.flatMap(
339
+ (requirement) => pageIdsFromResults(searchResultsByRequirement[requirement.id] ?? [])
340
+ )
341
+ ),
387
342
  metadata: options.metadata
388
343
  });
389
344
  const questions = userQuestionsForKnowledgeGaps(report.blockingMissingRequirements);
@@ -440,7 +395,9 @@ function requirementFromSearch(index, spec, results, now) {
440
395
  }
441
396
  function sourceFreshness(sources, now) {
442
397
  if (sources.length === 0) return { score: 0, expiredSourceIds: [] };
443
- const validUntilValues = sources.map((source) => source.validUntil ?? stringMetadata(source.metadata, "validUntil") ?? stringMetadata(source.metadata, "expiresAt")).filter(isIsoDate);
398
+ const validUntilValues = sources.map(
399
+ (source) => source.validUntil ?? stringMetadata(source.metadata, "validUntil") ?? stringMetadata(source.metadata, "expiresAt")
400
+ ).filter(isIsoDate);
444
401
  const lastVerifiedValues = sources.map((source) => source.lastVerifiedAt ?? stringMetadata(source.metadata, "lastVerifiedAt")).filter(isIsoDate);
445
402
  const expiredSourceIds = sources.filter((source) => {
446
403
  const validUntil = source.validUntil ?? stringMetadata(source.metadata, "validUntil") ?? stringMetadata(source.metadata, "expiresAt");
@@ -476,6 +433,450 @@ function round(value) {
476
433
  return Math.round(value * 1e3) / 1e3;
477
434
  }
478
435
 
436
+ // src/events.ts
437
+ function createKnowledgeEvent(input) {
438
+ const createdAt = (input.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
439
+ return {
440
+ id: stableId(
441
+ "evt",
442
+ `${input.type}:${input.target ?? ""}:${createdAt}:${JSON.stringify(input.metadata ?? {})}`
443
+ ),
444
+ type: input.type,
445
+ createdAt,
446
+ actor: input.actor,
447
+ target: input.target,
448
+ metadata: input.metadata
449
+ };
450
+ }
451
+
452
+ // src/freshness.ts
453
+ import { mkdir, readFile, writeFile } from "fs/promises";
454
+ import { dirname, join } from "path";
455
+ function createFileSystemFreshnessStore(options) {
456
+ const path = join(options.root, ".agent-knowledge", "freshness.json");
457
+ let writeQueue = Promise.resolve();
458
+ const read = async () => {
459
+ try {
460
+ const text = await readFile(path, "utf8");
461
+ const parsed = JSON.parse(text);
462
+ return parsed.records ?? {};
463
+ } catch {
464
+ return {};
465
+ }
466
+ };
467
+ const write = async (records) => {
468
+ await mkdir(dirname(path), { recursive: true });
469
+ await writeFile(path, `${JSON.stringify({ records }, null, 2)}
470
+ `, "utf8");
471
+ };
472
+ return {
473
+ async last(key) {
474
+ const records = await read();
475
+ const record = records[buildKey(key)];
476
+ return record ? new Date(record.lastRefreshedAt) : null;
477
+ },
478
+ async mark(input) {
479
+ writeQueue = writeQueue.then(async () => {
480
+ const records = await read();
481
+ records[buildKey(input)] = {
482
+ workspaceId: input.workspaceId,
483
+ sourceId: input.sourceId,
484
+ lastRefreshedAt: input.when.toISOString(),
485
+ contentHash: input.contentHash
486
+ };
487
+ await write(records);
488
+ });
489
+ await writeQueue;
490
+ },
491
+ async stale(input) {
492
+ const last = await this.last(input);
493
+ if (!last) return true;
494
+ const now = input.now ?? /* @__PURE__ */ new Date();
495
+ return now.getTime() - last.getTime() > input.ttlMs;
496
+ },
497
+ async list(workspaceId) {
498
+ const records = await read();
499
+ return Object.values(records).filter((r) => r.workspaceId === workspaceId);
500
+ }
501
+ };
502
+ }
503
+ function createD1FreshnessStoreStub(adapter) {
504
+ return {
505
+ async last(key) {
506
+ const record = await adapter.get(key.workspaceId, key.sourceId);
507
+ return record ? new Date(record.lastRefreshedAt) : null;
508
+ },
509
+ async mark(input) {
510
+ await adapter.upsert({
511
+ workspaceId: input.workspaceId,
512
+ sourceId: input.sourceId,
513
+ lastRefreshedAt: input.when.toISOString(),
514
+ contentHash: input.contentHash
515
+ });
516
+ },
517
+ async stale(input) {
518
+ const last = await this.last(input);
519
+ if (!last) return true;
520
+ const now = input.now ?? /* @__PURE__ */ new Date();
521
+ return now.getTime() - last.getTime() > input.ttlMs;
522
+ },
523
+ async list(workspaceId) {
524
+ return adapter.listByWorkspace(workspaceId);
525
+ }
526
+ };
527
+ }
528
+ function buildKey(key) {
529
+ return `${key.workspaceId}::${key.sourceId}`;
530
+ }
531
+
532
+ // src/kb-store.ts
533
+ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
534
+ import { dirname as dirname2, join as join2 } from "path";
535
+ var MemoryKbStore = class {
536
+ sources = /* @__PURE__ */ new Map();
537
+ pages = /* @__PURE__ */ new Map();
538
+ events = [];
539
+ index = null;
540
+ async putSource(source) {
541
+ this.sources.set(source.id, clone(source));
542
+ }
543
+ async getSource(id) {
544
+ return clone(this.sources.get(id) ?? null);
545
+ }
546
+ async listSources() {
547
+ return [...this.sources.values()].map(clone);
548
+ }
549
+ async putPage(page) {
550
+ this.pages.set(page.id, clone(page));
551
+ }
552
+ async getPage(idOrPath) {
553
+ return clone(
554
+ this.pages.get(idOrPath) ?? [...this.pages.values()].find((page) => page.path === idOrPath) ?? null
555
+ );
556
+ }
557
+ async listPages() {
558
+ return [...this.pages.values()].map(clone);
559
+ }
560
+ async putIndex(index) {
561
+ this.index = clone(index);
562
+ }
563
+ async getIndex() {
564
+ if (this.index) return clone(this.index);
565
+ const pages = await this.listPages();
566
+ const sources = await this.listSources();
567
+ return {
568
+ root: "memory",
569
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
570
+ sources,
571
+ pages,
572
+ graph: buildKnowledgeGraph(pages)
573
+ };
574
+ }
575
+ async putEvent(event) {
576
+ this.events.push(clone(event));
577
+ }
578
+ async listEvents(query = {}) {
579
+ let out = this.events;
580
+ if (query.type) out = out.filter((event) => event.type === query.type);
581
+ if (query.target) out = out.filter((event) => event.target === query.target);
582
+ out = [...out].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
583
+ return out.slice(-(query.limit ?? out.length)).map(clone);
584
+ }
585
+ };
586
+ var FileSystemKbStore = class extends MemoryKbStore {
587
+ constructor(dir) {
588
+ super();
589
+ this.dir = dir;
590
+ }
591
+ dir;
592
+ async putIndex(index) {
593
+ await super.putIndex(index);
594
+ await writeJson2(join2(this.dir, "index.json"), index);
595
+ }
596
+ async getIndex() {
597
+ try {
598
+ return JSON.parse(await readFile2(join2(this.dir, "index.json"), "utf8"));
599
+ } catch {
600
+ return await super.getIndex();
601
+ }
602
+ }
603
+ async putEvent(event) {
604
+ await super.putEvent(event);
605
+ const events = await this.listEvents();
606
+ await writeJson2(join2(this.dir, "events.json"), events);
607
+ }
608
+ };
609
+ async function writeJson2(path, value) {
610
+ await mkdir2(dirname2(path), { recursive: true });
611
+ await writeFile2(path, `${JSON.stringify(value, null, 2)}
612
+ `, "utf8");
613
+ }
614
+ function clone(value) {
615
+ return value == null ? value : JSON.parse(JSON.stringify(value));
616
+ }
617
+
618
+ // src/optimization.ts
619
+ import {
620
+ runMultiShotOptimization
621
+ } from "@tangle-network/agent-eval";
622
+ async function runKnowledgeBaseOptimization(config) {
623
+ return runMultiShotOptimization({
624
+ ...config,
625
+ target: config.target ?? "agent-knowledge-base"
626
+ });
627
+ }
628
+ function knowledgeVariantFromCandidate(candidate, options = {}) {
629
+ return {
630
+ id: options.id ?? candidate.id,
631
+ label: options.label ?? candidate.id,
632
+ generation: options.generation ?? 0,
633
+ payload: candidate
634
+ };
635
+ }
636
+
637
+ // src/propose-from-finding.ts
638
+ var KnowledgeProposalParseError = class extends Error {
639
+ constructor(findingId, subject, message) {
640
+ super(`proposeFromFinding(${findingId}, subject=${subject}): ${message}`);
641
+ this.findingId = findingId;
642
+ this.subject = subject;
643
+ this.name = "KnowledgeProposalParseError";
644
+ }
645
+ findingId;
646
+ subject;
647
+ };
648
+ function proposeFromFinding(finding) {
649
+ if (!finding.subject) return null;
650
+ if (!finding.subject.startsWith("agent-knowledge:")) return null;
651
+ const rest = finding.subject.slice("agent-knowledge:".length);
652
+ const [kindPart, ...locusParts] = rest.split(":");
653
+ const locus = locusParts.join(":");
654
+ if (!kindPart || !locus) {
655
+ throw new KnowledgeProposalParseError(
656
+ finding.finding_id,
657
+ finding.subject,
658
+ "expected `agent-knowledge:<kind>:<locus>` shape"
659
+ );
660
+ }
661
+ const baseMeta = {
662
+ severity: finding.severity,
663
+ confidence: finding.confidence,
664
+ evidence_uri: finding.evidence_refs[0]?.uri,
665
+ analyst_id: finding.analyst_id
666
+ };
667
+ switch (kindPart) {
668
+ case "wiki":
669
+ return wikiProposal(finding, locus, baseMeta);
670
+ case "claim":
671
+ return claimProposal(finding, locus, baseMeta);
672
+ case "raw":
673
+ return liftRawProposal(finding, locus, baseMeta);
674
+ case "stale":
675
+ return markStaleProposal(finding, locus, baseMeta);
676
+ default:
677
+ throw new KnowledgeProposalParseError(
678
+ finding.finding_id,
679
+ finding.subject,
680
+ `unknown kind "${kindPart}" (expected one of: wiki | claim | raw | stale)`
681
+ );
682
+ }
683
+ }
684
+ function wikiProposal(finding, locus, metadata) {
685
+ const hashIdx = locus.indexOf("#");
686
+ const pageSlug = hashIdx >= 0 ? locus.slice(0, hashIdx) : locus;
687
+ const heading = hashIdx >= 0 ? locus.slice(hashIdx + 1) : null;
688
+ const path = `knowledge/${ensureSlug(pageSlug)}.md`;
689
+ const body = renderWikiBody(finding, pageSlug, heading);
690
+ return {
691
+ id: `prop-${finding.finding_id}`,
692
+ sourceFindingId: finding.finding_id,
693
+ kind: heading ? "append-section" : "create-page",
694
+ locus: pageSlug,
695
+ writeBlocks: [{ path, content: body }],
696
+ metadata
697
+ };
698
+ }
699
+ function claimProposal(finding, locus, metadata) {
700
+ const refs = finding.evidence_refs.filter((r) => r.uri).map((r) => ({
701
+ sourceId: `analyst-finding:${finding.finding_id}`,
702
+ anchorId: r.uri,
703
+ quote: r.excerpt
704
+ }));
705
+ const claim = {
706
+ id: `claim-${finding.finding_id}`,
707
+ text: finding.recommended_action ?? finding.claim,
708
+ refs,
709
+ confidence: finding.confidence,
710
+ status: "draft",
711
+ metadata: {
712
+ analyst_id: finding.analyst_id,
713
+ source_finding_id: finding.finding_id,
714
+ topic: locus
715
+ }
716
+ };
717
+ return {
718
+ id: `prop-${finding.finding_id}`,
719
+ sourceFindingId: finding.finding_id,
720
+ kind: "create-claim",
721
+ locus,
722
+ writeBlocks: [],
723
+ claim,
724
+ metadata
725
+ };
726
+ }
727
+ function liftRawProposal(finding, sourceId, metadata) {
728
+ const path = `knowledge/${ensureSlug(sourceId)}.md`;
729
+ const body = [
730
+ "---",
731
+ `title: ${sourceId}`,
732
+ `source: ${sourceId}`,
733
+ `status: draft`,
734
+ `lifted_from_finding: ${finding.finding_id}`,
735
+ "---",
736
+ "",
737
+ "## Why this page exists",
738
+ "",
739
+ finding.claim,
740
+ "",
741
+ ...finding.rationale ? ["## Rationale", "", finding.rationale, ""] : [],
742
+ ...finding.recommended_action ? ["## Recommended action", "", finding.recommended_action, ""] : []
743
+ ].join("\n");
744
+ return {
745
+ id: `prop-${finding.finding_id}`,
746
+ sourceFindingId: finding.finding_id,
747
+ kind: "lift-raw",
748
+ locus: sourceId,
749
+ writeBlocks: [{ path, content: body }],
750
+ metadata
751
+ };
752
+ }
753
+ function markStaleProposal(finding, pageSlug, metadata) {
754
+ const path = `knowledge/${ensureSlug(pageSlug)}.stale.md`;
755
+ const body = [
756
+ "---",
757
+ `title: ${pageSlug} (marked stale)`,
758
+ `status: superseded`,
759
+ `superseded_by_finding: ${finding.finding_id}`,
760
+ `confidence: ${finding.confidence}`,
761
+ "---",
762
+ "",
763
+ "## Why marked stale",
764
+ "",
765
+ finding.claim,
766
+ "",
767
+ ...finding.rationale ? ["## Evidence", "", finding.rationale, ""] : [],
768
+ ...finding.recommended_action ? ["## Action", "", finding.recommended_action, ""] : []
769
+ ].join("\n");
770
+ return {
771
+ id: `prop-${finding.finding_id}`,
772
+ sourceFindingId: finding.finding_id,
773
+ kind: "mark-stale",
774
+ locus: pageSlug,
775
+ writeBlocks: [{ path, content: body }],
776
+ metadata
777
+ };
778
+ }
779
+ function proposeFromFindings(findings) {
780
+ const proposals = [];
781
+ const errors = [];
782
+ let skipped = 0;
783
+ for (const f of findings) {
784
+ try {
785
+ const p = proposeFromFinding(f);
786
+ if (p) proposals.push(p);
787
+ else skipped += 1;
788
+ } catch (err) {
789
+ if (err instanceof KnowledgeProposalParseError) errors.push(err);
790
+ else throw err;
791
+ }
792
+ }
793
+ return { proposals, skipped, errors };
794
+ }
795
+ function ensureSlug(s) {
796
+ return s.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 200) || "untitled";
797
+ }
798
+ function renderWikiBody(finding, slug, heading) {
799
+ const title = humanize(slug);
800
+ if (heading) {
801
+ return [
802
+ `## ${heading}`,
803
+ "",
804
+ finding.claim,
805
+ "",
806
+ ...finding.rationale ? ["### Rationale", "", finding.rationale, ""] : [],
807
+ ...finding.recommended_action ? ["### Action", "", finding.recommended_action, ""] : [],
808
+ `_Drafted from finding ${finding.finding_id} (confidence ${finding.confidence.toFixed(2)})._`
809
+ ].join("\n");
810
+ }
811
+ return [
812
+ "---",
813
+ `title: ${title}`,
814
+ `status: draft`,
815
+ `drafted_from_finding: ${finding.finding_id}`,
816
+ `confidence: ${finding.confidence}`,
817
+ "---",
818
+ "",
819
+ `# ${title}`,
820
+ "",
821
+ finding.claim,
822
+ "",
823
+ ...finding.rationale ? ["## Rationale", "", finding.rationale, ""] : [],
824
+ ...finding.recommended_action ? ["## Recommended action", "", finding.recommended_action, ""] : []
825
+ ].join("\n");
826
+ }
827
+ function humanize(slug) {
828
+ return slug.split("-").filter(Boolean).map((w) => w[0]?.toUpperCase() + w.slice(1)).join(" ") || slug;
829
+ }
830
+
831
+ // src/release.ts
832
+ import {
833
+ evaluateReleaseConfidence,
834
+ releaseTraceEvidenceFromMultiShotTrials,
835
+ validateRunRecord
836
+ } from "@tangle-network/agent-eval";
837
+ function knowledgeReleaseReportFromOptimization(result, options = {}) {
838
+ const trials = result.evolution.generations.flatMap(
839
+ (generation) => generation.trials
840
+ );
841
+ const traceEvidence = releaseTraceEvidenceFromMultiShotTrials(trials);
842
+ const runRecords = (options.runRecords ?? [
843
+ ...result.gate?.candidateRuns ?? [],
844
+ ...result.gate?.baselineRuns ?? []
845
+ ]).map(validateRunRecord);
846
+ const scorecard = evaluateReleaseConfidence({
847
+ target: "agent-knowledge-base",
848
+ candidateId: result.promotedVariant.id,
849
+ baselineId: "baseline",
850
+ traces: traceEvidence,
851
+ runs: runRecords,
852
+ gateDecision: result.gate?.decision ?? null,
853
+ thresholds: {
854
+ requireCorpus: false,
855
+ requireHoldout: Boolean(result.gate),
856
+ minHoldoutRuns: result.gate ? 1 : 0,
857
+ minSearchRuns: 1,
858
+ minMeanScore: options.minScore ?? 0.7
859
+ }
860
+ });
861
+ const release = {
862
+ id: stableId(
863
+ "krel",
864
+ `${result.promotedVariant.id}:${options.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()}`
865
+ ),
866
+ candidateId: result.promotedVariant.id,
867
+ createdAt: options.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
868
+ promoted: scorecard.status !== "fail" && result.promotedVariant.id === result.searchBestVariant.id,
869
+ scorecard,
870
+ runRecordIds: runRecords.map((record) => record.runId)
871
+ };
872
+ return {
873
+ release,
874
+ scorecard,
875
+ candidateRuns: result.gate?.candidateRuns ?? [],
876
+ baselineRuns: result.gate?.baselineRuns ?? []
877
+ };
878
+ }
879
+
479
880
  // src/research-loop.ts
480
881
  import {
481
882
  blockingKnowledgeEval,
@@ -509,7 +910,9 @@ function createKnowledgeControlLoopAdapter(options) {
509
910
  };
510
911
  },
511
912
  validate({ state }) {
512
- const errorFindings = state.validation.findings.filter((finding) => finding.severity === "error");
913
+ const errorFindings = state.validation.findings.filter(
914
+ (finding) => finding.severity === "error"
915
+ );
513
916
  const evals = [
514
917
  objectiveEval({
515
918
  id: "knowledge-valid",
@@ -636,18 +1039,24 @@ function readinessFor(options, index) {
636
1039
  }
637
1040
  export {
638
1041
  FileSystemKbStore,
1042
+ IRS_DIMENSION_HINTS,
639
1043
  KnowledgeBaseCandidateSchema,
640
1044
  KnowledgeEventSchema,
641
1045
  KnowledgeGraphEdgeSchema,
642
1046
  KnowledgeGraphNodeSchema,
643
1047
  KnowledgeIndexSchema,
644
1048
  KnowledgePageSchema,
1049
+ KnowledgeProposalParseError,
1050
+ MAX_RESPONSE_BYTES,
1051
+ MIN_REQUEST_GAP_MS,
645
1052
  MemoryKbStore,
1053
+ POLITE_USER_AGENT,
646
1054
  READINESS_SPEC_DEFAULTS,
647
1055
  SCAFFOLD_PAGE_BASENAMES,
648
1056
  SourceAnchorSchema,
649
1057
  SourceRecordSchema,
650
1058
  WIKILINK_REGEX,
1059
+ __resetHttpThrottle,
651
1060
  addSourcePath,
652
1061
  addSourceText,
653
1062
  applyKnowledgeWriteBlocks,
@@ -656,14 +1065,24 @@ export {
656
1065
  buildKnowledgeGraph,
657
1066
  buildKnowledgeIndex,
658
1067
  chunkMarkdown,
1068
+ createCornellLiiSource,
1069
+ createD1FreshnessStoreStub,
1070
+ createFileSystemFreshnessStore,
1071
+ createIrsPublicationsSource,
659
1072
  createKnowledgeControlLoopAdapter,
660
1073
  createKnowledgeEvent,
661
1074
  createLocalDiscoveryDispatcher,
1075
+ createStateSosSource,
662
1076
  defineReadinessSpec,
1077
+ detectChanges,
663
1078
  explainKnowledgeTarget,
1079
+ extractLinks,
664
1080
  extractWikilinks,
1081
+ firstMatch,
665
1082
  formatFrontmatter,
1083
+ htmlToText,
666
1084
  initKnowledgeBase,
1085
+ innerHtmlById,
667
1086
  inspectKnowledgeIndex,
668
1087
  isSafeKnowledgePath,
669
1088
  isScaffoldPath,
@@ -673,10 +1092,14 @@ export {
673
1092
  lintKnowledgeIndex,
674
1093
  loadKnowledgePages,
675
1094
  loadSourceRegistry,
1095
+ looksLikeBlockPage,
676
1096
  mediaTypeFor,
677
1097
  normalizeLinkTarget,
678
1098
  parseFrontmatter,
679
1099
  parseKnowledgeWriteBlocks,
1100
+ politeFetch,
1101
+ proposeFromFinding,
1102
+ proposeFromFindings,
680
1103
  reciprocalRankFusion,
681
1104
  runKnowledgeBaseOptimization,
682
1105
  runKnowledgeResearchLoop,