@tangle-network/agent-knowledge 1.8.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/index.d.ts +739 -321
- package/dist/index.js +653 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/index.d.ts +1 -1
- package/dist/{types-BEDGlXB-.d.ts → types-C17sAROL.d.ts} +1 -1
- package/dist/viz/index.d.ts +1 -1
- package/docs/results/adaptive.md +120 -0
- package/docs/results/claim-grounding.md +97 -0
- package/docs/results/cost-quality.md +27 -0
- package/docs/supervisor-profiles.md +295 -0
- package/docs/two-agent-research-ab.md +428 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { S as SourceRecord, c as KnowledgeIndex, d as KnowledgeSearchResult, e as
|
|
2
|
-
export { C as ClaimRef, n as KnowledgeBaseCandidate, K as KnowledgeGraphEdge, a as KnowledgeGraphNode, o as KnowledgeId, p as KnowledgePolicy, q as KnowledgeRelation, r as KnowledgeUnit, s as SourceAnchor } from './types-
|
|
1
|
+
import { S as SourceRecord, c as KnowledgeIndex, d as KnowledgeSearchResult, e as SourceRegistry, f as KnowledgeEvent, g as KnowledgeEventType, h as KnowledgePage, b as KnowledgeGraph, i as KnowledgeLintFinding, j as KnowledgeWriteBlock, k as KnowledgeClaim, l as KnowledgeRelease, m as KnowledgeWriteParseResult } from './types-C17sAROL.js';
|
|
2
|
+
export { C as ClaimRef, n as KnowledgeBaseCandidate, K as KnowledgeGraphEdge, a as KnowledgeGraphNode, o as KnowledgeId, p as KnowledgePolicy, q as KnowledgeRelation, r as KnowledgeUnit, s as SourceAnchor } from './types-C17sAROL.js';
|
|
3
|
+
import { KnowledgeRequirementCategory, KnowledgeAcquisitionMode, KnowledgeImportance, KnowledgeFreshness, KnowledgeSensitivity, KnowledgeRequirement, KnowledgeBundle, KnowledgeReadinessReport, UserQuestion, DataAcquisitionPlan, AnalystSeverity, AnalystFinding, RunRecord, ReleaseTraceEvidence, GateDecision, ReleaseConfidenceScorecard, ControlRuntimeConfig, ControlEvalResult } from '@tangle-network/agent-eval';
|
|
3
4
|
import { KnowledgeFragment } from './sources/index.js';
|
|
4
5
|
export { CornellLiiSelector, CornellLiiSourceOptions, FetchOpts, FragmentProvenance, IRS_DIMENSION_HINTS, IrsPublicationsSourceOptions, KnowledgeSource, MAX_RESPONSE_BYTES, MIN_REQUEST_GAP_MS, POLITE_USER_AGENT, PoliteFetchOptions, PoliteFetchResult, StateSosEntity, StateSosSourceConfig, __resetHttpThrottle, createCornellLiiSource, createIrsPublicationsSource, createStateSosSource, extractLinks, firstMatch, htmlToText, innerHtmlById, looksLikeBlockPage, politeFetch } from './sources/index.js';
|
|
5
|
-
import { KnowledgeRequirementCategory, KnowledgeAcquisitionMode, KnowledgeImportance, KnowledgeFreshness, KnowledgeSensitivity, KnowledgeRequirement, KnowledgeBundle, KnowledgeReadinessReport, UserQuestion, DataAcquisitionPlan, AnalystSeverity, AnalystFinding, RunRecord, ReleaseTraceEvidence, GateDecision, ReleaseConfidenceScorecard, ControlRuntimeConfig, ControlEvalResult } from '@tangle-network/agent-eval';
|
|
6
6
|
export { AgentMemoryAdapter, AgentMemoryContext, AgentMemoryHit, AgentMemoryHitSchema, AgentMemoryKind, AgentMemoryKindSchema, AgentMemoryScope, AgentMemoryScopeSchema, AgentMemorySearchOptions, AgentMemoryWriteInput, AgentMemoryWriteInputSchema, AgentMemoryWriteResult, Neo4jAgentMemoryAdapterOptions, createNeo4jAgentMemoryAdapter, defaultGetMemoryContext, memoryHitToSourceRecord, memoryWriteResultToSourceRecord, renderMemoryContext } from './memory/index.js';
|
|
7
7
|
import { Budget, ExecutorConfig, SuperviseOptions, DeliverableSpec, SupervisedResult } from '@tangle-network/agent-runtime/loops';
|
|
8
8
|
import { z } from 'zod';
|
|
@@ -28,6 +28,588 @@ interface SourceAdapter {
|
|
|
28
28
|
declare const textSourceAdapter: SourceAdapter;
|
|
29
29
|
declare function mediaTypeFor(uri: string): string;
|
|
30
30
|
|
|
31
|
+
interface KnowledgeReadinessSpec {
|
|
32
|
+
id: string;
|
|
33
|
+
description: string;
|
|
34
|
+
query: string;
|
|
35
|
+
requiredFor: string[];
|
|
36
|
+
category: KnowledgeRequirementCategory;
|
|
37
|
+
acquisitionMode: KnowledgeAcquisitionMode;
|
|
38
|
+
importance: KnowledgeImportance;
|
|
39
|
+
freshness: KnowledgeFreshness;
|
|
40
|
+
sensitivity: KnowledgeSensitivity;
|
|
41
|
+
confidenceNeeded: number;
|
|
42
|
+
fallbackPolicy?: KnowledgeRequirement['fallbackPolicy'];
|
|
43
|
+
minSources?: number;
|
|
44
|
+
minHits?: number;
|
|
45
|
+
metadata?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Defaults applied by `defineReadinessSpec` when the caller omits the field.
|
|
49
|
+
*
|
|
50
|
+
* These are deliberately conservative: a domain-specific topic that an agent
|
|
51
|
+
* needs grounded to a high-confidence threshold from at least one authoritative
|
|
52
|
+
* source. Override any field to specialise (e.g. `freshness: 'daily'` for a
|
|
53
|
+
* topic that must reflect today's regulatory state).
|
|
54
|
+
*/
|
|
55
|
+
declare const READINESS_SPEC_DEFAULTS: {
|
|
56
|
+
readonly category: "domain_specific";
|
|
57
|
+
readonly acquisitionMode: "search_web";
|
|
58
|
+
readonly importance: "high";
|
|
59
|
+
readonly freshness: "monthly";
|
|
60
|
+
readonly sensitivity: "public";
|
|
61
|
+
readonly confidenceNeeded: 0.7;
|
|
62
|
+
readonly minSources: 1;
|
|
63
|
+
readonly minHits: 2;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Inputs accepted by `defineReadinessSpec`. The four fields the caller cannot
|
|
67
|
+
* sanely default (id, description, query, requiredFor) are required; everything
|
|
68
|
+
* else is optional and pulls from `READINESS_SPEC_DEFAULTS`.
|
|
69
|
+
*/
|
|
70
|
+
type DefineReadinessSpecInput = Pick<KnowledgeReadinessSpec, 'id' | 'description' | 'query' | 'requiredFor'> & Partial<Omit<KnowledgeReadinessSpec, 'id' | 'description' | 'query' | 'requiredFor'>>;
|
|
71
|
+
/**
|
|
72
|
+
* Builder that returns a fully-typed `KnowledgeReadinessSpec` from a slim input.
|
|
73
|
+
*
|
|
74
|
+
* Motivation: `KnowledgeReadinessSpec` has eleven required fields. Most of them
|
|
75
|
+
* (category, acquisition mode, importance, freshness, sensitivity, confidence
|
|
76
|
+
* threshold, source/hit minima) have a clear default for domain-specific KB
|
|
77
|
+
* topics — agents end up copy-pasting the same boilerplate across every spec.
|
|
78
|
+
* This helper collapses that boilerplate while keeping every field overridable.
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* defineReadinessSpec({
|
|
82
|
+
* id: 'coop/intent-grounding',
|
|
83
|
+
* description: 'Required grounding for coop pack intent stage',
|
|
84
|
+
* query: 'flock size space ventilation predator',
|
|
85
|
+
* requiredFor: ['IntentIntakeAgent', 'requirements'],
|
|
86
|
+
* })
|
|
87
|
+
*
|
|
88
|
+
* @example // override defaults where the topic demands it
|
|
89
|
+
* defineReadinessSpec({
|
|
90
|
+
* id: 'medical/dosing',
|
|
91
|
+
* description: 'Dosing guidance for compounding pharmacy',
|
|
92
|
+
* query: 'compounding dose schedule',
|
|
93
|
+
* requiredFor: ['DosingAgent'],
|
|
94
|
+
* importance: 'blocking',
|
|
95
|
+
* freshness: 'daily',
|
|
96
|
+
* sensitivity: 'private',
|
|
97
|
+
* confidenceNeeded: 0.95,
|
|
98
|
+
* minSources: 3,
|
|
99
|
+
* })
|
|
100
|
+
*/
|
|
101
|
+
declare function defineReadinessSpec(input: DefineReadinessSpecInput): KnowledgeReadinessSpec;
|
|
102
|
+
interface BuildEvalKnowledgeBundleOptions {
|
|
103
|
+
taskId: string;
|
|
104
|
+
index: KnowledgeIndex;
|
|
105
|
+
specs: KnowledgeReadinessSpec[];
|
|
106
|
+
userAnswers?: Record<string, string>;
|
|
107
|
+
searchLimit?: number;
|
|
108
|
+
metadata?: Record<string, unknown>;
|
|
109
|
+
now?: Date;
|
|
110
|
+
}
|
|
111
|
+
interface EvalKnowledgeBundleBuildResult {
|
|
112
|
+
bundle: KnowledgeBundle;
|
|
113
|
+
report: KnowledgeReadinessReport;
|
|
114
|
+
requirements: KnowledgeRequirement[];
|
|
115
|
+
searchResultsByRequirement: Record<string, KnowledgeSearchResult[]>;
|
|
116
|
+
questions: UserQuestion[];
|
|
117
|
+
acquisitionPlans: DataAcquisitionPlan[];
|
|
118
|
+
}
|
|
119
|
+
declare function buildEvalKnowledgeBundle(options: BuildEvalKnowledgeBundleOptions): EvalKnowledgeBundleBuildResult;
|
|
120
|
+
|
|
121
|
+
interface AddSourceOptions {
|
|
122
|
+
copyIntoRaw?: boolean;
|
|
123
|
+
adapters?: SourceAdapter[];
|
|
124
|
+
now?: () => Date;
|
|
125
|
+
}
|
|
126
|
+
interface AddSourceTextInput {
|
|
127
|
+
uri: string;
|
|
128
|
+
text: string;
|
|
129
|
+
title?: string;
|
|
130
|
+
mediaType?: string;
|
|
131
|
+
validUntil?: string;
|
|
132
|
+
lastVerifiedAt?: string;
|
|
133
|
+
metadata?: Record<string, unknown>;
|
|
134
|
+
}
|
|
135
|
+
declare function loadSourceRegistry(root: string): Promise<SourceRegistry>;
|
|
136
|
+
declare function writeSourceRegistry(root: string, registry: SourceRegistry): Promise<void>;
|
|
137
|
+
declare function addSourcePath(root: string, sourcePath: string, options?: AddSourceOptions): Promise<SourceRecord[]>;
|
|
138
|
+
declare function addSourceText(root: string, input: AddSourceTextInput, options?: Pick<AddSourceOptions, 'adapters' | 'now'>): Promise<SourceRecord>;
|
|
139
|
+
declare function sourceRegistryPath(root: string): string;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* A knowledge gap the loop surfaces from `scoreKnowledgeReadiness`. The worker
|
|
143
|
+
* targets these; the driver folds the unfilled remainder into the worker's next
|
|
144
|
+
* prompt and runs its own gap-fill pass over them.
|
|
145
|
+
*/
|
|
146
|
+
interface KnowledgeGap {
|
|
147
|
+
/** Readiness-spec id this gap belongs to. */
|
|
148
|
+
id: string;
|
|
149
|
+
/** Human-readable description of what's missing. */
|
|
150
|
+
description: string;
|
|
151
|
+
/** The search query the readiness check ran for this requirement. */
|
|
152
|
+
query: string;
|
|
153
|
+
/** True when the gap blocks readiness (vs. a soft, non-blocking gap). */
|
|
154
|
+
blocking: boolean;
|
|
155
|
+
}
|
|
156
|
+
/** A new source the worker (or driver) discovered and wants to add to the KB. */
|
|
157
|
+
type ResearchSourceProposal = AddSourceTextInput;
|
|
158
|
+
/**
|
|
159
|
+
* What a research agent contributes in one round. Both the worker and (when
|
|
160
|
+
* `driverResearches` is on) the driver produce this shape — the worker ADDS
|
|
161
|
+
* primary findings, the driver gap-FILLS the ones the worker missed.
|
|
162
|
+
*
|
|
163
|
+
* `proposalText` is the safe write-protocol text (`---FILE: knowledge/...---`
|
|
164
|
+
* blocks). The loop only applies it AFTER the driver has verified the round's
|
|
165
|
+
* sources, so a rejected source never reaches the curated pages.
|
|
166
|
+
*/
|
|
167
|
+
interface ResearchContribution {
|
|
168
|
+
/** Immutable sources to register (the raw evidence). */
|
|
169
|
+
sources?: ResearchSourceProposal[];
|
|
170
|
+
/** Safe write-protocol text producing curated `knowledge/*.md` pages. */
|
|
171
|
+
proposalText?: string;
|
|
172
|
+
/**
|
|
173
|
+
* Build the page write-protocol text FROM the sources the driver accepted —
|
|
174
|
+
* the curated, citing pages the readiness gate searches. Receives the
|
|
175
|
+
* registered `SourceRecord`s (with their assigned ids, so a page's frontmatter
|
|
176
|
+
* `sources:` can cite them). Returns `---FILE: knowledge/...---` block text or
|
|
177
|
+
* `undefined`. Runs after verification, so a page never cites a rejected
|
|
178
|
+
* source. Concatenated after any static `proposalText`.
|
|
179
|
+
*/
|
|
180
|
+
buildPages?: (acceptedSources: SourceRecord[]) => string | undefined;
|
|
181
|
+
/** Free-form research transcript — products can persist this. */
|
|
182
|
+
notes?: string;
|
|
183
|
+
metadata?: Record<string, unknown>;
|
|
184
|
+
}
|
|
185
|
+
/** Context handed to the worker each round. */
|
|
186
|
+
interface WorkerResearchContext {
|
|
187
|
+
root: string;
|
|
188
|
+
goal: string;
|
|
189
|
+
round: number;
|
|
190
|
+
index: KnowledgeIndex;
|
|
191
|
+
/** Gaps the readiness gate currently reports — what the worker should close. */
|
|
192
|
+
gaps: KnowledgeGap[];
|
|
193
|
+
/** Steer text the driver folded in from the previous round's remaining gaps. */
|
|
194
|
+
steer?: string;
|
|
195
|
+
readiness: EvalKnowledgeBundleBuildResult;
|
|
196
|
+
signal?: AbortSignal;
|
|
197
|
+
}
|
|
198
|
+
/** Context handed to the driver's verifier for one candidate source. */
|
|
199
|
+
interface SourceVerificationContext {
|
|
200
|
+
root: string;
|
|
201
|
+
goal: string;
|
|
202
|
+
round: number;
|
|
203
|
+
index: KnowledgeIndex;
|
|
204
|
+
gaps: KnowledgeGap[];
|
|
205
|
+
/** Sources already accepted earlier THIS round (in-round dedup). */
|
|
206
|
+
acceptedThisRound: ResearchSourceProposal[];
|
|
207
|
+
signal?: AbortSignal;
|
|
208
|
+
}
|
|
209
|
+
/** A single rejected source plus the reason the driver gave. */
|
|
210
|
+
interface RejectedSource {
|
|
211
|
+
source: ResearchSourceProposal;
|
|
212
|
+
reason: string;
|
|
213
|
+
}
|
|
214
|
+
/** Context handed to the driver's gap-fill pass (only when `driverResearches`). */
|
|
215
|
+
interface DriverResearchContext {
|
|
216
|
+
root: string;
|
|
217
|
+
goal: string;
|
|
218
|
+
round: number;
|
|
219
|
+
index: KnowledgeIndex;
|
|
220
|
+
/** Gaps STILL open after the worker's accepted contribution applied. */
|
|
221
|
+
remainingGaps: KnowledgeGap[];
|
|
222
|
+
readiness: EvalKnowledgeBundleBuildResult;
|
|
223
|
+
signal?: AbortSignal;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* The differentiated driver role.
|
|
227
|
+
*
|
|
228
|
+
* - `verifySource` — the gate the worker's additions pass before they commit.
|
|
229
|
+
* Return `{ accept: true }` to keep a source or `{ accept: false, reason }`
|
|
230
|
+
* to reject it (not real / not relevant / duplicate). The loop dedups exact
|
|
231
|
+
* duplicates (same `uri` already in the KB or accepted this round) BEFORE
|
|
232
|
+
* calling this, so the verifier only sees genuinely-new candidates.
|
|
233
|
+
* - `research` — the driver's OWN gap-fill pass over the gaps the worker left
|
|
234
|
+
* open. Only invoked when `driverResearches` is true.
|
|
235
|
+
* - `foldGaps` — turn the remaining gaps into a steer string for the worker's
|
|
236
|
+
* next prompt. Defaults to a compact bulleted list when omitted.
|
|
237
|
+
*/
|
|
238
|
+
interface ResearchDriver {
|
|
239
|
+
verifySource(source: ResearchSourceProposal, ctx: SourceVerificationContext): Promise<SourceVerdict> | SourceVerdict;
|
|
240
|
+
research?(ctx: DriverResearchContext): Promise<ResearchContribution> | ResearchContribution;
|
|
241
|
+
foldGaps?(gaps: KnowledgeGap[]): string;
|
|
242
|
+
}
|
|
243
|
+
type SourceVerdict = {
|
|
244
|
+
accept: true;
|
|
245
|
+
} | {
|
|
246
|
+
accept: false;
|
|
247
|
+
reason: string;
|
|
248
|
+
};
|
|
249
|
+
/** The worker: primary research targeting the round's gaps. */
|
|
250
|
+
type ResearchWorker = (ctx: WorkerResearchContext) => Promise<ResearchContribution> | ResearchContribution;
|
|
251
|
+
interface TwoAgentResearchLoopOptions {
|
|
252
|
+
root: string;
|
|
253
|
+
goal: string;
|
|
254
|
+
worker: ResearchWorker;
|
|
255
|
+
driver: ResearchDriver;
|
|
256
|
+
/**
|
|
257
|
+
* When false (default), the driver ONLY verifies + gates — a pure coordinator
|
|
258
|
+
* that contributes no research of its own (the "doesn't participate in the
|
|
259
|
+
* work" mode). When true, the driver also runs its `research` gap-fill pass
|
|
260
|
+
* each round over the gaps the worker left open.
|
|
261
|
+
*/
|
|
262
|
+
driverResearches?: boolean;
|
|
263
|
+
maxRounds?: number;
|
|
264
|
+
actor?: string;
|
|
265
|
+
/** Readiness specs define the gate; an empty list means the loop never gates. */
|
|
266
|
+
readinessSpecs?: KnowledgeReadinessSpec[];
|
|
267
|
+
readinessTaskId?: string;
|
|
268
|
+
readiness?: Omit<BuildEvalKnowledgeBundleOptions, 'taskId' | 'index' | 'specs'>;
|
|
269
|
+
sourceOptions?: Pick<AddSourceOptions, 'adapters' | 'now'>;
|
|
270
|
+
signal?: AbortSignal;
|
|
271
|
+
onRound?: (round: TwoAgentResearchRound) => Promise<void> | void;
|
|
272
|
+
}
|
|
273
|
+
interface TwoAgentResearchRound {
|
|
274
|
+
round: number;
|
|
275
|
+
/** Gaps reported at the START of the round (what the worker targeted). */
|
|
276
|
+
gaps: KnowledgeGap[];
|
|
277
|
+
/** Worker sources accepted by the driver and written to the KB. */
|
|
278
|
+
acceptedWorkerSources: SourceRecord[];
|
|
279
|
+
/** Worker sources the driver rejected (with reasons) — never written. */
|
|
280
|
+
rejectedWorkerSources: RejectedSource[];
|
|
281
|
+
/** Sources the driver itself added in its gap-fill pass. */
|
|
282
|
+
driverSources: SourceRecord[];
|
|
283
|
+
/** Curated pages written this round (worker proposal + driver proposal). */
|
|
284
|
+
writtenPages: string[];
|
|
285
|
+
readiness?: EvalKnowledgeBundleBuildResult;
|
|
286
|
+
/** True once the readiness gate reports no blocking gaps. */
|
|
287
|
+
ready: boolean;
|
|
288
|
+
event: KnowledgeEvent;
|
|
289
|
+
notes: {
|
|
290
|
+
worker?: string;
|
|
291
|
+
driver?: string;
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
interface TwoAgentResearchLoopResult {
|
|
295
|
+
root: string;
|
|
296
|
+
goal: string;
|
|
297
|
+
rounds: number;
|
|
298
|
+
ready: boolean;
|
|
299
|
+
index: KnowledgeIndex;
|
|
300
|
+
readiness?: EvalKnowledgeBundleBuildResult;
|
|
301
|
+
steps: TwoAgentResearchRound[];
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Two-agent (driver + worker) sibling of `runKnowledgeResearchLoop`.
|
|
305
|
+
*
|
|
306
|
+
* Both agents research to grow ONE knowledge base. The roles are differentiated:
|
|
307
|
+
*
|
|
308
|
+
* - **WORKER** = primary research. Each round it reads the open gaps, discovers
|
|
309
|
+
* new sources, and proposes additions (`sources` + `proposalText`). It ADDS.
|
|
310
|
+
* - **DRIVER** = the verifier / gap-filler / gate. It (1) VERIFIES the worker's
|
|
311
|
+
* sources before they commit — dedup against the KB, then `verifySource`
|
|
312
|
+
* rejects ones that aren't real/relevant; (2) GAP-FILLS the gaps the worker
|
|
313
|
+
* missed with its own research pass (when `driverResearches`); (3) folds the
|
|
314
|
+
* remaining gaps into the worker's next prompt; and (4) GATES on
|
|
315
|
+
* `scoreKnowledgeReadiness` — the loop stops as soon as there are no blocking
|
|
316
|
+
* gaps.
|
|
317
|
+
*
|
|
318
|
+
* Set `driverResearches: false` (default) for the pure-coordinator mode: the
|
|
319
|
+
* driver only verifies + gates and contributes no research itself.
|
|
320
|
+
*
|
|
321
|
+
* Composes existing atoms — `initKnowledgeBase`, `addSourceText`,
|
|
322
|
+
* `applyKnowledgeWriteBlocks`, `buildEvalKnowledgeBundle` (the readiness gate),
|
|
323
|
+
* and `searchKnowledge` — and reinvents none of them.
|
|
324
|
+
*/
|
|
325
|
+
declare function runTwoAgentResearchLoop(options: TwoAgentResearchLoopOptions): Promise<TwoAgentResearchLoopResult>;
|
|
326
|
+
/**
|
|
327
|
+
* Helper for verifiers: does the candidate source's text/title overlap any page
|
|
328
|
+
* the readiness search returns for a gap query? A cheap relevance heuristic the
|
|
329
|
+
* driver can compose into `verifySource` (real verifiers can do more).
|
|
330
|
+
*/
|
|
331
|
+
declare function sourceMatchesGaps(source: ResearchSourceProposal, index: KnowledgeIndex, gaps: KnowledgeGap[]): KnowledgeSearchResult[];
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Real web-research worker + verifying driver for `runTwoAgentResearchLoop`.
|
|
335
|
+
*
|
|
336
|
+
* This is the GENERAL, any-topic implementation behind the two-agent research
|
|
337
|
+
* loop's live arm. Given the open knowledge gaps the readiness gate surfaces,
|
|
338
|
+
* the worker:
|
|
339
|
+
*
|
|
340
|
+
* 1. asks an LLM (glm-5.2 by default) to turn each gap into focused web
|
|
341
|
+
* search queries,
|
|
342
|
+
* 2. runs a REAL web search over the Tangle router (`POST /v1/search` — the
|
|
343
|
+
* same endpoint `tcloud mcp`'s `web_search` tool forwards to), so there is
|
|
344
|
+
* no hardcoded corpus,
|
|
345
|
+
* 3. fetches the top results with the repo's polite, cached `politeFetch` and
|
|
346
|
+
* reduces each page to text with `htmlToText`,
|
|
347
|
+
* 4. proposes the readable, verifiable pages as `ResearchSourceProposal`s plus
|
|
348
|
+
* a `buildPages` that writes citing `knowledge/*.md` pages from the sources
|
|
349
|
+
* the driver accepts.
|
|
350
|
+
*
|
|
351
|
+
* The verifying DRIVER is the differentiated role from the two-agent loop: a
|
|
352
|
+
* second LLM pass that judges each fetched source's on-topic relevance to the
|
|
353
|
+
* goal + open gaps and rejects off-topic / spam / already-covered material. The
|
|
354
|
+
* worker ADDS; the driver GATES. Together they build a cleaner knowledge base
|
|
355
|
+
* than a single agent at the same compute budget.
|
|
356
|
+
*
|
|
357
|
+
* Dependency-free on purpose: it talks to the router over `fetch` directly with
|
|
358
|
+
* the published OpenAI-compatible chat shape and the `/v1/search` shape, so it
|
|
359
|
+
* works whether or not the `tcloud` CLI is installed. Point it at any router by
|
|
360
|
+
* passing `baseUrl`; supply the key via `apiKey` or `TANGLE_API_KEY`.
|
|
361
|
+
*/
|
|
362
|
+
|
|
363
|
+
/** One live web result, as the router's `/v1/search` returns it. */
|
|
364
|
+
interface WebSearchHit {
|
|
365
|
+
title: string;
|
|
366
|
+
url: string;
|
|
367
|
+
snippet?: string;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* The two router capabilities the worker/driver need. Injectable so tests can
|
|
371
|
+
* stub the network; the default talks to the live Tangle router over `fetch`.
|
|
372
|
+
*/
|
|
373
|
+
interface RouterClient {
|
|
374
|
+
/** Live web search — returns title/url/snippet hits. */
|
|
375
|
+
search(query: string, opts?: {
|
|
376
|
+
maxResults?: number;
|
|
377
|
+
}): Promise<WebSearchHit[]>;
|
|
378
|
+
/** Chat completion — returns the assistant message's visible text. */
|
|
379
|
+
chat(messages: {
|
|
380
|
+
role: 'system' | 'user';
|
|
381
|
+
content: string;
|
|
382
|
+
}[], maxTokens?: number): Promise<string>;
|
|
383
|
+
/** Cumulative cost (chat + search) since this client was created. */
|
|
384
|
+
usage(): RouterUsage;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Cumulative router cost — the per-arm signal the A/B reports ALONGSIDE quality,
|
|
388
|
+
* so "2.3 fewer sources" can be read against the token/$/latency it cost. A
|
|
389
|
+
* two-agent round is one worker pass plus N `verifySource` LLM calls; counting
|
|
390
|
+
* each call here is what surfaces that the two-agent loop spends more inference
|
|
391
|
+
* than its "equal passes" budget implies.
|
|
392
|
+
*/
|
|
393
|
+
interface RouterUsage {
|
|
394
|
+
chatCalls: number;
|
|
395
|
+
searchCalls: number;
|
|
396
|
+
promptTokens: number;
|
|
397
|
+
completionTokens: number;
|
|
398
|
+
usd: number;
|
|
399
|
+
wallMs: number;
|
|
400
|
+
}
|
|
401
|
+
interface TangleRouterOptions {
|
|
402
|
+
/** Router base URL. Defaults to `https://router.tangle.tools/v1`. */
|
|
403
|
+
baseUrl?: string;
|
|
404
|
+
/** Bearer key. Defaults to `process.env.TANGLE_API_KEY`. */
|
|
405
|
+
apiKey?: string;
|
|
406
|
+
/** Chat model id. Defaults to `glm-5.2`. */
|
|
407
|
+
model?: string;
|
|
408
|
+
/** Optional preferred search provider (exa | you | perplexity | …). */
|
|
409
|
+
searchProvider?: string;
|
|
410
|
+
signal?: AbortSignal;
|
|
411
|
+
}
|
|
412
|
+
/** A small error so a failed router call fails loud rather than returning junk. */
|
|
413
|
+
declare class RouterError extends Error {
|
|
414
|
+
readonly status: number;
|
|
415
|
+
constructor(status: number, message: string);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Build a dependency-free Tangle router client over `fetch`. This is the same
|
|
419
|
+
* wire surface the `tcloud` SDK + `tcloud mcp` use (`/v1/search` for web search,
|
|
420
|
+
* `/v1/chat/completions` for chat) so it needs no CLI installed.
|
|
421
|
+
*/
|
|
422
|
+
declare function createTangleRouterClient(options?: TangleRouterOptions): RouterClient;
|
|
423
|
+
interface WebResearchWorkerOptions {
|
|
424
|
+
/** Router client. Defaults to a live Tangle router client from env creds. */
|
|
425
|
+
router?: RouterClient;
|
|
426
|
+
router_options?: TangleRouterOptions;
|
|
427
|
+
/** Max search queries the LLM may form per gap. Default 2. */
|
|
428
|
+
queriesPerGap?: number;
|
|
429
|
+
/** Max web results fetched per query. Default 3. */
|
|
430
|
+
resultsPerQuery?: number;
|
|
431
|
+
/** Hard cap on sources proposed per round (across all gaps). Default 6. */
|
|
432
|
+
maxSourcesPerRound?: number;
|
|
433
|
+
/** Disk cache dir for `politeFetch`. Optional; speeds repeat runs. */
|
|
434
|
+
cacheDir?: string;
|
|
435
|
+
/** Minimum readable text length to keep a fetched page. Default 200. */
|
|
436
|
+
minTextChars?: number;
|
|
437
|
+
/** Max chars of page text stored per source (keeps pages bounded). Default 4000. */
|
|
438
|
+
maxTextChars?: number;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* The real web-research worker. Conforms to the loop's `ResearchWorker`
|
|
442
|
+
* contract: given the open gaps, it returns the sources it found plus a
|
|
443
|
+
* `buildPages` that emits citing pages from the sources the driver accepted.
|
|
444
|
+
*/
|
|
445
|
+
declare function createWebResearchWorker(options?: WebResearchWorkerOptions): ResearchWorker;
|
|
446
|
+
interface VerifyingDriverOptions {
|
|
447
|
+
router?: RouterClient;
|
|
448
|
+
router_options?: TangleRouterOptions;
|
|
449
|
+
/**
|
|
450
|
+
* When the LLM verdict can't be parsed, default to REJECT (fail-closed) so a
|
|
451
|
+
* model hiccup never poisons the KB with an unverified source. Set `true` to
|
|
452
|
+
* accept-on-parse-failure only if you have a reason to. Default false.
|
|
453
|
+
*/
|
|
454
|
+
acceptOnParseFailure?: boolean;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* The verifying driver: a real LLM pass that judges each candidate source's
|
|
458
|
+
* on-topic relevance to the goal + open gaps and whether it duplicates material
|
|
459
|
+
* already accepted this round. This is the differentiated coordinator role — it
|
|
460
|
+
* GATES the worker's additions; it adds nothing itself.
|
|
461
|
+
*
|
|
462
|
+
* The loop already dedups exact-uri duplicates and only calls this on genuinely
|
|
463
|
+
* new candidates, so the verifier focuses on relevance + near-duplicate
|
|
464
|
+
* judgement, not bookkeeping.
|
|
465
|
+
*/
|
|
466
|
+
declare function createVerifyingResearchDriver(options?: VerifyingDriverOptions): ResearchDriver;
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Adaptive verifier mode for `runTwoAgentResearchLoop`.
|
|
470
|
+
*
|
|
471
|
+
* The cost/quality A/B (`docs/results/cost-quality.md`) found the LLM relevance
|
|
472
|
+
* verifier's cleanliness win is dominated by DE-DUPLICATION — which a
|
|
473
|
+
* deterministic content-hash / canonical-URL check captures at ~none of the LLM
|
|
474
|
+
* premium — and that an LLM check only earns its dollar on the off-scope tail.
|
|
475
|
+
* The honest production move it names is: do the cheap deterministic work first,
|
|
476
|
+
* spend the LLM only where it pays. This module is that driver.
|
|
477
|
+
*
|
|
478
|
+
* Per candidate source the adaptive driver runs THREE stages, cheapest first,
|
|
479
|
+
* and stops at the first that decides:
|
|
480
|
+
*
|
|
481
|
+
* 1. DEDUP ($0, no LLM). Reject a source whose CONTENT (normalized-text hash)
|
|
482
|
+
* or whose CANONICAL URL matches one already accepted this round or already
|
|
483
|
+
* in the knowledge base. This is the de-dup the relevance judge was being
|
|
484
|
+
* paid to do; doing it deterministically is free and exact.
|
|
485
|
+
*
|
|
486
|
+
* 2. HEURISTIC TRIAGE ($0, no LLM). For a unique survivor, a cheap host /
|
|
487
|
+
* title / length signal classifies it as clearly-keep, clearly-drop, or
|
|
488
|
+
* AMBIGUOUS. Clear cases are resolved without a model: an authoritative host
|
|
489
|
+
* (arxiv, *.edu, *.gov, official docs) with a substantial readable body is
|
|
490
|
+
* kept; an obvious spam/listicle/marketing title or a too-thin body is
|
|
491
|
+
* dropped. Only genuinely ambiguous survivors fall through.
|
|
492
|
+
*
|
|
493
|
+
* 3. LLM ESCALATION ($, one call). ONLY the ambiguous survivors reach the LLM
|
|
494
|
+
* `verifySource` — the shipped `createVerifyingResearchDriver` relevance
|
|
495
|
+
* judge. This is where the verifier earns its premium: the off-scope tail a
|
|
496
|
+
* cheap rule can't adjudicate.
|
|
497
|
+
*
|
|
498
|
+
* The result is the cost/quality frontier point the doc predicted: most of the
|
|
499
|
+
* cleanliness (dedup + clear drops) at a fraction of the LLM $/calls (only the
|
|
500
|
+
* ambiguous tail pays). It is a real `ResearchDriver` — same contract the
|
|
501
|
+
* two-agent loop already gates on — and reuses `sha256`, the relevance verifier,
|
|
502
|
+
* and the index; it reinvents none of them.
|
|
503
|
+
*/
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Canonicalize a URL for duplicate detection: lowercase host, strip a leading
|
|
507
|
+
* `www.`, drop the scheme, the fragment, a trailing slash, and tracking query
|
|
508
|
+
* params (`utm_*`, `ref`, `fbclid`, `gclid`, …). Two URLs that differ only by
|
|
509
|
+
* those decorations canonicalize to the same key, so the dedup stage treats them
|
|
510
|
+
* as the same source. Falls back to the lowercased raw string when the input is
|
|
511
|
+
* not a parseable absolute URL (so non-http identifiers still dedup by equality).
|
|
512
|
+
*/
|
|
513
|
+
declare function canonicalizeUrl(uri: string): string;
|
|
514
|
+
/**
|
|
515
|
+
* A stable content key for a fetched page: the sha256 of its normalized text
|
|
516
|
+
* (lowercased, punctuation/whitespace collapsed). Two pages whose readable body
|
|
517
|
+
* is the same modulo formatting collide here, so the dedup stage rejects a
|
|
518
|
+
* mirror/syndication of an already-accepted source even when the URL differs.
|
|
519
|
+
*/
|
|
520
|
+
declare function contentKey(text: string): string;
|
|
521
|
+
/** Why the deterministic dedup stage rejected a candidate (for audit/notes). */
|
|
522
|
+
type DedupReason = 'duplicate-url' | 'duplicate-content';
|
|
523
|
+
/** The cheap-triage classification of a unique survivor. */
|
|
524
|
+
type TriageClass = 'keep' | 'drop' | 'ambiguous';
|
|
525
|
+
/** One source's adaptive routing decision, for instrumentation and the doc. */
|
|
526
|
+
interface AdaptiveDecision {
|
|
527
|
+
uri: string;
|
|
528
|
+
/** The stage that decided this source: dedup | heuristic | llm. */
|
|
529
|
+
stage: 'dedup' | 'heuristic' | 'llm';
|
|
530
|
+
accepted: boolean;
|
|
531
|
+
/** The triage class assigned (set once past dedup). */
|
|
532
|
+
triage?: TriageClass;
|
|
533
|
+
reason?: string;
|
|
534
|
+
}
|
|
535
|
+
/** Running tally of where the adaptive driver spent its decisions. */
|
|
536
|
+
interface AdaptiveStats {
|
|
537
|
+
total: number;
|
|
538
|
+
/** Rejected by deterministic dedup (URL or content). $0. */
|
|
539
|
+
dedupRejected: number;
|
|
540
|
+
/** Kept by the cheap heuristic without an LLM call. $0. */
|
|
541
|
+
heuristicKept: number;
|
|
542
|
+
/** Dropped by the cheap heuristic without an LLM call. $0. */
|
|
543
|
+
heuristicDropped: number;
|
|
544
|
+
/** Escalated to the LLM relevance verifier ($ — the only paid stage). */
|
|
545
|
+
llmCalls: number;
|
|
546
|
+
/** Of the escalations, how many the LLM accepted. */
|
|
547
|
+
llmAccepted: number;
|
|
548
|
+
decisions: AdaptiveDecision[];
|
|
549
|
+
}
|
|
550
|
+
interface AdaptiveDriverOptions {
|
|
551
|
+
/** Router client for the LLM escalation. Defaults to a live client from env. */
|
|
552
|
+
router?: RouterClient;
|
|
553
|
+
router_options?: TangleRouterOptions;
|
|
554
|
+
/** Passed through to the escalation relevance verifier. */
|
|
555
|
+
verifying?: Pick<VerifyingDriverOptions, 'acceptOnParseFailure'>;
|
|
556
|
+
/**
|
|
557
|
+
* Hosts an authoritative source lives on. A unique survivor on one of these,
|
|
558
|
+
* with a substantial body, is KEPT deterministically (no LLM). Suffix-matched
|
|
559
|
+
* against the canonical host, so `arxiv.org` matches `export.arxiv.org`. The
|
|
560
|
+
* defaults cover papers, official docs, and standards bodies.
|
|
561
|
+
*/
|
|
562
|
+
authoritativeHosts?: string[];
|
|
563
|
+
/**
|
|
564
|
+
* Title/snippet patterns that mark obvious spam / listicle / marketing — a
|
|
565
|
+
* unique survivor matching one is DROPPED deterministically (no LLM).
|
|
566
|
+
*/
|
|
567
|
+
spamPatterns?: RegExp[];
|
|
568
|
+
/**
|
|
569
|
+
* Below this many readable chars a survivor is too thin to be a real reference
|
|
570
|
+
* and is dropped deterministically. Default 400.
|
|
571
|
+
*/
|
|
572
|
+
minBodyChars?: number;
|
|
573
|
+
/**
|
|
574
|
+
* A survivor whose body is at or above this many chars AND on an authoritative
|
|
575
|
+
* host is kept without an LLM call. Default 600.
|
|
576
|
+
*/
|
|
577
|
+
substantialBodyChars?: number;
|
|
578
|
+
/** Receives each routing decision as it is made (for live instrumentation). */
|
|
579
|
+
onDecision?: (decision: AdaptiveDecision) => void;
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Classify a UNIQUE survivor (already past dedup) with cheap host/title/length
|
|
583
|
+
* signals only — no LLM. Returns `keep`, `drop`, or `ambiguous`. `ambiguous` is
|
|
584
|
+
* the residue the LLM is reserved for: on-topic-looking pages on unknown hosts
|
|
585
|
+
* with a plausible body, which a host/title rule cannot adjudicate.
|
|
586
|
+
*/
|
|
587
|
+
declare function triageSource(source: ResearchSourceProposal, options: {
|
|
588
|
+
authoritativeHosts: string[];
|
|
589
|
+
spamPatterns: RegExp[];
|
|
590
|
+
minBodyChars: number;
|
|
591
|
+
substantialBodyChars: number;
|
|
592
|
+
}): {
|
|
593
|
+
triage: TriageClass;
|
|
594
|
+
reason: string;
|
|
595
|
+
};
|
|
596
|
+
interface AdaptiveResearchDriver {
|
|
597
|
+
verifySource(source: ResearchSourceProposal, ctx: SourceVerificationContext): Promise<SourceVerdict>;
|
|
598
|
+
/** Live tally of where decisions were spent — the cost/quality instrumentation. */
|
|
599
|
+
stats(): AdaptiveStats;
|
|
600
|
+
}
|
|
601
|
+
/**
|
|
602
|
+
* Build the adaptive verifier. The deterministic stages (dedup + heuristic
|
|
603
|
+
* triage) cost $0; only AMBIGUOUS survivors escalate to the LLM relevance
|
|
604
|
+
* verifier. `stats()` exposes where every decision was spent so the A/B can read
|
|
605
|
+
* the LLM $/calls the adaptive driver saved against the cleanliness it kept.
|
|
606
|
+
*
|
|
607
|
+
* Dedup state is kept on the driver instance: it tracks the canonical URLs and
|
|
608
|
+
* content hashes it has ACCEPTED, plus those it sees in the verification
|
|
609
|
+
* context's `acceptedThisRound` and the KB index. Use one driver per loop run.
|
|
610
|
+
*/
|
|
611
|
+
declare function createAdaptiveResearchDriver(options?: AdaptiveDriverOptions): AdaptiveResearchDriver;
|
|
612
|
+
|
|
31
613
|
/**
|
|
32
614
|
* Change detection across snapshots of one source's fragments.
|
|
33
615
|
*
|
|
@@ -132,125 +714,173 @@ declare function stripFrontmatter(content: string): {
|
|
|
132
714
|
bodyOffset: number;
|
|
133
715
|
};
|
|
134
716
|
|
|
135
|
-
interface DiscoveryTask {
|
|
136
|
-
id: string;
|
|
137
|
-
goal: string;
|
|
138
|
-
query?: string;
|
|
139
|
-
sourceHints?: string[];
|
|
140
|
-
metadata?: Record<string, unknown>;
|
|
141
|
-
}
|
|
142
|
-
interface DiscoveryResult {
|
|
143
|
-
taskId: string;
|
|
144
|
-
summary: string;
|
|
145
|
-
sourceUris?: string[];
|
|
146
|
-
claims?: Array<{
|
|
147
|
-
text: string;
|
|
148
|
-
sourceUri?: string;
|
|
149
|
-
confidence?: number;
|
|
150
|
-
}>;
|
|
151
|
-
followUpTasks?: DiscoveryTask[];
|
|
152
|
-
metadata?: Record<string, unknown>;
|
|
153
|
-
}
|
|
154
|
-
interface KnowledgeDiscoveryWorker {
|
|
155
|
-
run(task: DiscoveryTask, signal?: AbortSignal): Promise<DiscoveryResult> | DiscoveryResult;
|
|
156
|
-
}
|
|
157
|
-
interface KnowledgeDiscoveryDispatcher {
|
|
158
|
-
dispatch(tasks: DiscoveryTask[], options?: {
|
|
159
|
-
concurrency?: number;
|
|
160
|
-
signal?: AbortSignal;
|
|
161
|
-
}): Promise<DiscoveryResult[]>;
|
|
162
|
-
}
|
|
163
|
-
declare function createLocalDiscoveryDispatcher(worker: KnowledgeDiscoveryWorker): KnowledgeDiscoveryDispatcher;
|
|
164
|
-
|
|
165
|
-
interface KnowledgeReadinessSpec {
|
|
166
|
-
id: string;
|
|
167
|
-
description: string;
|
|
168
|
-
query: string;
|
|
169
|
-
requiredFor: string[];
|
|
170
|
-
category: KnowledgeRequirementCategory;
|
|
171
|
-
acquisitionMode: KnowledgeAcquisitionMode;
|
|
172
|
-
importance: KnowledgeImportance;
|
|
173
|
-
freshness: KnowledgeFreshness;
|
|
174
|
-
sensitivity: KnowledgeSensitivity;
|
|
175
|
-
confidenceNeeded: number;
|
|
176
|
-
fallbackPolicy?: KnowledgeRequirement['fallbackPolicy'];
|
|
177
|
-
minSources?: number;
|
|
178
|
-
minHits?: number;
|
|
179
|
-
metadata?: Record<string, unknown>;
|
|
180
|
-
}
|
|
181
717
|
/**
|
|
182
|
-
*
|
|
718
|
+
* Claim-grounding mode for `runTwoAgentResearchLoop`.
|
|
183
719
|
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
720
|
+
* The two-agent loop's existing verifier judges a source's on-topic RELEVANCE
|
|
721
|
+
* (is this page about the goal?). On the topic sets we have measured, its
|
|
722
|
+
* cleanliness win is dominated by DE-DUPLICATION — which a deterministic
|
|
723
|
+
* content-hash / canonical-URL check captures at ~none of the LLM premium (see
|
|
724
|
+
* `docs/results/cost-quality.md`). That makes the LLM verifier look expensive
|
|
725
|
+
* for what a cheap rule already does.
|
|
726
|
+
*
|
|
727
|
+
* Claim-grounding targets a DIFFERENT, harder error band: a citation that is
|
|
728
|
+
* relevant and unique but **misattributed** — the page is on-topic, the URL is
|
|
729
|
+
* real, yet the specific CLAIM the source is cited for does NOT actually appear
|
|
730
|
+
* in the page. This is the citation-fabrication failure mode of LLM research:
|
|
731
|
+
* the model writes a plausible sentence and hangs a real URL off it that never
|
|
732
|
+
* says any such thing. Neither de-dup nor a relevance judge catches it (both can
|
|
733
|
+
* pass a misattributed-but-on-topic page); only checking the claim against the
|
|
734
|
+
* fetched text does.
|
|
735
|
+
*
|
|
736
|
+
* The check is EXECUTABLE GROUND TRUTH, not another LLM opinion: the worker
|
|
737
|
+
* attaches the specific claim it is citing the source for, and the verifier
|
|
738
|
+
* tests whether that claim is PRESENT (verbatim, normalized, or as a sufficient
|
|
739
|
+
* content-word overlap / close paraphrase) in the `htmlToText` output of the
|
|
740
|
+
* page the worker actually fetched. A claim that is not grounded is rejected as
|
|
741
|
+
* misattributed. Because the oracle is deterministic text presence — not a model
|
|
742
|
+
* call — it is a deployable, non-oracle verifier: it can run in production with
|
|
743
|
+
* zero inference cost, OR be composed with the LLM relevance verifier so the
|
|
744
|
+
* loop rejects BOTH off-topic AND misattributed sources.
|
|
745
|
+
*
|
|
746
|
+
* This module is content-free and any-topic: it adds (1) a way for a proposal to
|
|
747
|
+
* carry the claim it is cited for, (2) the `groundClaimInText` oracle, and (3) a
|
|
748
|
+
* `ResearchDriver` that gates on grounding. It composes the existing
|
|
749
|
+
* `ResearchDriver` / `ResearchSourceProposal` contracts and the shipped
|
|
750
|
+
* `htmlToText`; it reinvents none of them.
|
|
188
751
|
*/
|
|
189
|
-
|
|
190
|
-
readonly category: "domain_specific";
|
|
191
|
-
readonly acquisitionMode: "search_web";
|
|
192
|
-
readonly importance: "high";
|
|
193
|
-
readonly freshness: "monthly";
|
|
194
|
-
readonly sensitivity: "public";
|
|
195
|
-
readonly confidenceNeeded: 0.7;
|
|
196
|
-
readonly minSources: 1;
|
|
197
|
-
readonly minHits: 2;
|
|
198
|
-
};
|
|
752
|
+
|
|
199
753
|
/**
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
754
|
+
* Metadata key under which a proposal carries the specific claim it is cited
|
|
755
|
+
* for. The worker sets `metadata[citedClaimKey] = '<the claim>'`; the
|
|
756
|
+
* claim-grounding driver reads it and checks it against the fetched page text.
|
|
203
757
|
*/
|
|
204
|
-
|
|
758
|
+
declare const citedClaimKey = "citedClaim";
|
|
759
|
+
/** Read the cited claim a proposal carries, if any. */
|
|
760
|
+
declare function citedClaimOf(source: ResearchSourceProposal): string | undefined;
|
|
761
|
+
/** Attach a cited claim to a proposal (immutably returns a new proposal). */
|
|
762
|
+
declare function withCitedClaim(source: ResearchSourceProposal, claim: string): ResearchSourceProposal;
|
|
763
|
+
interface GroundingResult {
|
|
764
|
+
/** True when the claim is sufficiently present in the page text. */
|
|
765
|
+
grounded: boolean;
|
|
766
|
+
/** How the claim matched (or why it didn't). For audit/notes. */
|
|
767
|
+
mode: 'verbatim' | 'normalized' | 'overlap' | 'absent' | 'empty-claim' | 'empty-text';
|
|
768
|
+
/**
|
|
769
|
+
* Fraction of the claim's content words found in the page text. 1 for a
|
|
770
|
+
* verbatim/normalized hit; the measured overlap otherwise.
|
|
771
|
+
*/
|
|
772
|
+
overlap: number;
|
|
773
|
+
/** Content words present in the claim but NOT in the page text. */
|
|
774
|
+
missingWords: string[];
|
|
775
|
+
}
|
|
776
|
+
interface GroundClaimOptions {
|
|
777
|
+
/**
|
|
778
|
+
* Minimum fraction of the claim's content words that must appear in the page
|
|
779
|
+
* text to count as a close paraphrase when there is no verbatim/normalized
|
|
780
|
+
* hit. Default 0.7 — a high bar, because a misattribution is exactly a claim
|
|
781
|
+
* whose specific words the page does not contain.
|
|
782
|
+
*/
|
|
783
|
+
minOverlap?: number;
|
|
784
|
+
/**
|
|
785
|
+
* Content words shorter than this are ignored (drops "the", "of", "is", …)
|
|
786
|
+
* and never count toward overlap. Default 3.
|
|
787
|
+
*/
|
|
788
|
+
minWordLength?: number;
|
|
789
|
+
}
|
|
205
790
|
/**
|
|
206
|
-
*
|
|
791
|
+
* THE ORACLE. Is `claim` grounded in `pageText` (the `htmlToText` output of the
|
|
792
|
+
* page the worker fetched)? Deterministic, no model call:
|
|
207
793
|
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
*
|
|
212
|
-
*
|
|
794
|
+
* 1. verbatim — the claim string appears as-is (case-insensitive).
|
|
795
|
+
* 2. normalized — the claim appears after collapsing punctuation/whitespace
|
|
796
|
+
* on both sides (so "5.4x" vs "5.4 x", smart quotes, etc. still match).
|
|
797
|
+
* 3. overlap — a close paraphrase: at least `minOverlap` of the claim's
|
|
798
|
+
* substantive content words appear in the page text. A misattributed page
|
|
799
|
+
* fails here because the SPECIFIC words the claim asserts are absent.
|
|
213
800
|
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
801
|
+
* Returns the match mode, the measured overlap, and the missing content words —
|
|
802
|
+
* enough for the driver to give a precise rejection reason and for a test/doc to
|
|
803
|
+
* audit WHY a claim grounded or didn't.
|
|
804
|
+
*/
|
|
805
|
+
declare function groundClaimInText(claim: string, pageText: string, options?: GroundClaimOptions): GroundingResult;
|
|
806
|
+
interface ClaimGroundingDriverOptions extends GroundClaimOptions {
|
|
807
|
+
/**
|
|
808
|
+
* Optional second verifier to compose AFTER grounding passes. When set, a
|
|
809
|
+
* source must BOTH ground its claim AND pass this verifier (e.g. the LLM
|
|
810
|
+
* relevance driver's `verifySource`). Lets the loop reject off-topic AND
|
|
811
|
+
* misattributed sources in one driver. Omit for the pure, zero-inference
|
|
812
|
+
* grounding gate.
|
|
813
|
+
*/
|
|
814
|
+
relevanceVerifier?: (source: ResearchSourceProposal, ctx: SourceVerificationContext) => Promise<SourceVerdict> | SourceVerdict;
|
|
815
|
+
/**
|
|
816
|
+
* What to do when a proposal carries NO cited claim. `'reject'` (default) is
|
|
817
|
+
* fail-closed: in claim-grounding mode every source must declare what it is
|
|
818
|
+
* cited for, so an un-annotated source is treated as ungrounded. `'accept'`
|
|
819
|
+
* lets un-annotated sources through to the relevance verifier (if any) —
|
|
820
|
+
* useful when mixing annotated and legacy proposals.
|
|
821
|
+
*/
|
|
822
|
+
onMissingClaim?: 'reject' | 'accept';
|
|
823
|
+
}
|
|
824
|
+
/**
|
|
825
|
+
* A `ResearchDriver`-shaped verifier (just the `verifySource` arm) that gates on
|
|
826
|
+
* CLAIM GROUNDING: it rejects a source whose cited claim is not present in its
|
|
827
|
+
* fetched page text — a misattributed / fabricated citation — and (optionally)
|
|
828
|
+
* composes a relevance verifier after grounding passes.
|
|
221
829
|
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
*
|
|
830
|
+
* The returned function matches `ResearchDriver['verifySource']`, so it drops
|
|
831
|
+
* straight into `runTwoAgentResearchLoop` as `{ verifySource: createClaimGroundingVerifier(...) }`.
|
|
832
|
+
*/
|
|
833
|
+
declare function createClaimGroundingVerifier(options?: ClaimGroundingDriverOptions): (source: ResearchSourceProposal, ctx: SourceVerificationContext) => Promise<SourceVerdict>;
|
|
834
|
+
interface WorkerClaimDecorationOptions {
|
|
835
|
+
router?: RouterClient;
|
|
836
|
+
router_options?: TangleRouterOptions;
|
|
837
|
+
/** Max output tokens for the claim-extraction call. Default 1200 (glm floor). */
|
|
838
|
+
maxTokens?: number;
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Ask an LLM to state, for one source, the single specific factual claim a
|
|
842
|
+
* researcher would cite THIS page for toward the goal. Used to DECORATE the
|
|
843
|
+
* sources a relevance-only worker produced with the claim a citation would make,
|
|
844
|
+
* so the claim-grounding verifier has something executable to check. The model
|
|
845
|
+
* is told to ground the claim in the provided excerpt; the verifier then checks
|
|
846
|
+
* it against the FULL page text independently — the model does not get to mark
|
|
847
|
+
* its own homework.
|
|
848
|
+
*
|
|
849
|
+
* Returns the proposal annotated via `withCitedClaim`, or the original proposal
|
|
850
|
+
* unchanged if the model returns nothing parseable (the verifier's
|
|
851
|
+
* `onMissingClaim` policy then decides).
|
|
234
852
|
*/
|
|
235
|
-
declare function
|
|
236
|
-
|
|
853
|
+
declare function createClaimDecorator(options?: WorkerClaimDecorationOptions): (source: ResearchSourceProposal, goal: string) => Promise<ResearchSourceProposal>;
|
|
854
|
+
|
|
855
|
+
interface DiscoveryTask {
|
|
856
|
+
id: string;
|
|
857
|
+
goal: string;
|
|
858
|
+
query?: string;
|
|
859
|
+
sourceHints?: string[];
|
|
860
|
+
metadata?: Record<string, unknown>;
|
|
861
|
+
}
|
|
862
|
+
interface DiscoveryResult {
|
|
237
863
|
taskId: string;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
864
|
+
summary: string;
|
|
865
|
+
sourceUris?: string[];
|
|
866
|
+
claims?: Array<{
|
|
867
|
+
text: string;
|
|
868
|
+
sourceUri?: string;
|
|
869
|
+
confidence?: number;
|
|
870
|
+
}>;
|
|
871
|
+
followUpTasks?: DiscoveryTask[];
|
|
242
872
|
metadata?: Record<string, unknown>;
|
|
243
|
-
now?: Date;
|
|
244
873
|
}
|
|
245
|
-
interface
|
|
246
|
-
|
|
247
|
-
report: KnowledgeReadinessReport;
|
|
248
|
-
requirements: KnowledgeRequirement[];
|
|
249
|
-
searchResultsByRequirement: Record<string, KnowledgeSearchResult[]>;
|
|
250
|
-
questions: UserQuestion[];
|
|
251
|
-
acquisitionPlans: DataAcquisitionPlan[];
|
|
874
|
+
interface KnowledgeDiscoveryWorker {
|
|
875
|
+
run(task: DiscoveryTask, signal?: AbortSignal): Promise<DiscoveryResult> | DiscoveryResult;
|
|
252
876
|
}
|
|
253
|
-
|
|
877
|
+
interface KnowledgeDiscoveryDispatcher {
|
|
878
|
+
dispatch(tasks: DiscoveryTask[], options?: {
|
|
879
|
+
concurrency?: number;
|
|
880
|
+
signal?: AbortSignal;
|
|
881
|
+
}): Promise<DiscoveryResult[]>;
|
|
882
|
+
}
|
|
883
|
+
declare function createLocalDiscoveryDispatcher(worker: KnowledgeDiscoveryWorker): KnowledgeDiscoveryDispatcher;
|
|
254
884
|
|
|
255
885
|
interface KnowledgeEventQuery {
|
|
256
886
|
type?: KnowledgeEventType;
|
|
@@ -604,26 +1234,6 @@ interface KnowledgeReleaseInput {
|
|
|
604
1234
|
}
|
|
605
1235
|
declare function knowledgeReleaseReport(input: KnowledgeReleaseInput): KnowledgeReleaseReport;
|
|
606
1236
|
|
|
607
|
-
interface AddSourceOptions {
|
|
608
|
-
copyIntoRaw?: boolean;
|
|
609
|
-
adapters?: SourceAdapter[];
|
|
610
|
-
now?: () => Date;
|
|
611
|
-
}
|
|
612
|
-
interface AddSourceTextInput {
|
|
613
|
-
uri: string;
|
|
614
|
-
text: string;
|
|
615
|
-
title?: string;
|
|
616
|
-
mediaType?: string;
|
|
617
|
-
validUntil?: string;
|
|
618
|
-
lastVerifiedAt?: string;
|
|
619
|
-
metadata?: Record<string, unknown>;
|
|
620
|
-
}
|
|
621
|
-
declare function loadSourceRegistry(root: string): Promise<SourceRegistry>;
|
|
622
|
-
declare function writeSourceRegistry(root: string, registry: SourceRegistry): Promise<void>;
|
|
623
|
-
declare function addSourcePath(root: string, sourcePath: string, options?: AddSourceOptions): Promise<SourceRecord[]>;
|
|
624
|
-
declare function addSourceText(root: string, input: AddSourceTextInput, options?: Pick<AddSourceOptions, 'adapters' | 'now'>): Promise<SourceRecord>;
|
|
625
|
-
declare function sourceRegistryPath(root: string): string;
|
|
626
|
-
|
|
627
1237
|
interface ValidateKnowledgeOptions {
|
|
628
1238
|
strict?: boolean;
|
|
629
1239
|
}
|
|
@@ -996,198 +1606,6 @@ declare function initKnowledgeBase(root: string): Promise<KnowledgeLayout>;
|
|
|
996
1606
|
declare function loadKnowledgePages(root: string): Promise<KnowledgePage[]>;
|
|
997
1607
|
declare function writeJson(path: string, value: unknown): Promise<void>;
|
|
998
1608
|
|
|
999
|
-
/**
|
|
1000
|
-
* A knowledge gap the loop surfaces from `scoreKnowledgeReadiness`. The worker
|
|
1001
|
-
* targets these; the driver folds the unfilled remainder into the worker's next
|
|
1002
|
-
* prompt and runs its own gap-fill pass over them.
|
|
1003
|
-
*/
|
|
1004
|
-
interface KnowledgeGap {
|
|
1005
|
-
/** Readiness-spec id this gap belongs to. */
|
|
1006
|
-
id: string;
|
|
1007
|
-
/** Human-readable description of what's missing. */
|
|
1008
|
-
description: string;
|
|
1009
|
-
/** The search query the readiness check ran for this requirement. */
|
|
1010
|
-
query: string;
|
|
1011
|
-
/** True when the gap blocks readiness (vs. a soft, non-blocking gap). */
|
|
1012
|
-
blocking: boolean;
|
|
1013
|
-
}
|
|
1014
|
-
/** A new source the worker (or driver) discovered and wants to add to the KB. */
|
|
1015
|
-
type ResearchSourceProposal = AddSourceTextInput;
|
|
1016
|
-
/**
|
|
1017
|
-
* What a research agent contributes in one round. Both the worker and (when
|
|
1018
|
-
* `driverResearches` is on) the driver produce this shape — the worker ADDS
|
|
1019
|
-
* primary findings, the driver gap-FILLS the ones the worker missed.
|
|
1020
|
-
*
|
|
1021
|
-
* `proposalText` is the safe write-protocol text (`---FILE: knowledge/...---`
|
|
1022
|
-
* blocks). The loop only applies it AFTER the driver has verified the round's
|
|
1023
|
-
* sources, so a rejected source never reaches the curated pages.
|
|
1024
|
-
*/
|
|
1025
|
-
interface ResearchContribution {
|
|
1026
|
-
/** Immutable sources to register (the raw evidence). */
|
|
1027
|
-
sources?: ResearchSourceProposal[];
|
|
1028
|
-
/** Safe write-protocol text producing curated `knowledge/*.md` pages. */
|
|
1029
|
-
proposalText?: string;
|
|
1030
|
-
/**
|
|
1031
|
-
* Build the page write-protocol text FROM the sources the driver accepted —
|
|
1032
|
-
* the curated, citing pages the readiness gate searches. Receives the
|
|
1033
|
-
* registered `SourceRecord`s (with their assigned ids, so a page's frontmatter
|
|
1034
|
-
* `sources:` can cite them). Returns `---FILE: knowledge/...---` block text or
|
|
1035
|
-
* `undefined`. Runs after verification, so a page never cites a rejected
|
|
1036
|
-
* source. Concatenated after any static `proposalText`.
|
|
1037
|
-
*/
|
|
1038
|
-
buildPages?: (acceptedSources: SourceRecord[]) => string | undefined;
|
|
1039
|
-
/** Free-form research transcript — products can persist this. */
|
|
1040
|
-
notes?: string;
|
|
1041
|
-
metadata?: Record<string, unknown>;
|
|
1042
|
-
}
|
|
1043
|
-
/** Context handed to the worker each round. */
|
|
1044
|
-
interface WorkerResearchContext {
|
|
1045
|
-
root: string;
|
|
1046
|
-
goal: string;
|
|
1047
|
-
round: number;
|
|
1048
|
-
index: KnowledgeIndex;
|
|
1049
|
-
/** Gaps the readiness gate currently reports — what the worker should close. */
|
|
1050
|
-
gaps: KnowledgeGap[];
|
|
1051
|
-
/** Steer text the driver folded in from the previous round's remaining gaps. */
|
|
1052
|
-
steer?: string;
|
|
1053
|
-
readiness: EvalKnowledgeBundleBuildResult;
|
|
1054
|
-
signal?: AbortSignal;
|
|
1055
|
-
}
|
|
1056
|
-
/** Context handed to the driver's verifier for one candidate source. */
|
|
1057
|
-
interface SourceVerificationContext {
|
|
1058
|
-
root: string;
|
|
1059
|
-
goal: string;
|
|
1060
|
-
round: number;
|
|
1061
|
-
index: KnowledgeIndex;
|
|
1062
|
-
gaps: KnowledgeGap[];
|
|
1063
|
-
/** Sources already accepted earlier THIS round (in-round dedup). */
|
|
1064
|
-
acceptedThisRound: ResearchSourceProposal[];
|
|
1065
|
-
signal?: AbortSignal;
|
|
1066
|
-
}
|
|
1067
|
-
/** A single rejected source plus the reason the driver gave. */
|
|
1068
|
-
interface RejectedSource {
|
|
1069
|
-
source: ResearchSourceProposal;
|
|
1070
|
-
reason: string;
|
|
1071
|
-
}
|
|
1072
|
-
/** Context handed to the driver's gap-fill pass (only when `driverResearches`). */
|
|
1073
|
-
interface DriverResearchContext {
|
|
1074
|
-
root: string;
|
|
1075
|
-
goal: string;
|
|
1076
|
-
round: number;
|
|
1077
|
-
index: KnowledgeIndex;
|
|
1078
|
-
/** Gaps STILL open after the worker's accepted contribution applied. */
|
|
1079
|
-
remainingGaps: KnowledgeGap[];
|
|
1080
|
-
readiness: EvalKnowledgeBundleBuildResult;
|
|
1081
|
-
signal?: AbortSignal;
|
|
1082
|
-
}
|
|
1083
|
-
/**
|
|
1084
|
-
* The differentiated driver role.
|
|
1085
|
-
*
|
|
1086
|
-
* - `verifySource` — the gate the worker's additions pass before they commit.
|
|
1087
|
-
* Return `{ accept: true }` to keep a source or `{ accept: false, reason }`
|
|
1088
|
-
* to reject it (not real / not relevant / duplicate). The loop dedups exact
|
|
1089
|
-
* duplicates (same `uri` already in the KB or accepted this round) BEFORE
|
|
1090
|
-
* calling this, so the verifier only sees genuinely-new candidates.
|
|
1091
|
-
* - `research` — the driver's OWN gap-fill pass over the gaps the worker left
|
|
1092
|
-
* open. Only invoked when `driverResearches` is true.
|
|
1093
|
-
* - `foldGaps` — turn the remaining gaps into a steer string for the worker's
|
|
1094
|
-
* next prompt. Defaults to a compact bulleted list when omitted.
|
|
1095
|
-
*/
|
|
1096
|
-
interface ResearchDriver {
|
|
1097
|
-
verifySource(source: ResearchSourceProposal, ctx: SourceVerificationContext): Promise<SourceVerdict> | SourceVerdict;
|
|
1098
|
-
research?(ctx: DriverResearchContext): Promise<ResearchContribution> | ResearchContribution;
|
|
1099
|
-
foldGaps?(gaps: KnowledgeGap[]): string;
|
|
1100
|
-
}
|
|
1101
|
-
type SourceVerdict = {
|
|
1102
|
-
accept: true;
|
|
1103
|
-
} | {
|
|
1104
|
-
accept: false;
|
|
1105
|
-
reason: string;
|
|
1106
|
-
};
|
|
1107
|
-
/** The worker: primary research targeting the round's gaps. */
|
|
1108
|
-
type ResearchWorker = (ctx: WorkerResearchContext) => Promise<ResearchContribution> | ResearchContribution;
|
|
1109
|
-
interface TwoAgentResearchLoopOptions {
|
|
1110
|
-
root: string;
|
|
1111
|
-
goal: string;
|
|
1112
|
-
worker: ResearchWorker;
|
|
1113
|
-
driver: ResearchDriver;
|
|
1114
|
-
/**
|
|
1115
|
-
* When false (default), the driver ONLY verifies + gates — a pure coordinator
|
|
1116
|
-
* that contributes no research of its own (the "doesn't participate in the
|
|
1117
|
-
* work" mode). When true, the driver also runs its `research` gap-fill pass
|
|
1118
|
-
* each round over the gaps the worker left open.
|
|
1119
|
-
*/
|
|
1120
|
-
driverResearches?: boolean;
|
|
1121
|
-
maxRounds?: number;
|
|
1122
|
-
actor?: string;
|
|
1123
|
-
/** Readiness specs define the gate; an empty list means the loop never gates. */
|
|
1124
|
-
readinessSpecs?: KnowledgeReadinessSpec[];
|
|
1125
|
-
readinessTaskId?: string;
|
|
1126
|
-
readiness?: Omit<BuildEvalKnowledgeBundleOptions, 'taskId' | 'index' | 'specs'>;
|
|
1127
|
-
sourceOptions?: Pick<AddSourceOptions, 'adapters' | 'now'>;
|
|
1128
|
-
signal?: AbortSignal;
|
|
1129
|
-
onRound?: (round: TwoAgentResearchRound) => Promise<void> | void;
|
|
1130
|
-
}
|
|
1131
|
-
interface TwoAgentResearchRound {
|
|
1132
|
-
round: number;
|
|
1133
|
-
/** Gaps reported at the START of the round (what the worker targeted). */
|
|
1134
|
-
gaps: KnowledgeGap[];
|
|
1135
|
-
/** Worker sources accepted by the driver and written to the KB. */
|
|
1136
|
-
acceptedWorkerSources: SourceRecord[];
|
|
1137
|
-
/** Worker sources the driver rejected (with reasons) — never written. */
|
|
1138
|
-
rejectedWorkerSources: RejectedSource[];
|
|
1139
|
-
/** Sources the driver itself added in its gap-fill pass. */
|
|
1140
|
-
driverSources: SourceRecord[];
|
|
1141
|
-
/** Curated pages written this round (worker proposal + driver proposal). */
|
|
1142
|
-
writtenPages: string[];
|
|
1143
|
-
readiness?: EvalKnowledgeBundleBuildResult;
|
|
1144
|
-
/** True once the readiness gate reports no blocking gaps. */
|
|
1145
|
-
ready: boolean;
|
|
1146
|
-
event: KnowledgeEvent;
|
|
1147
|
-
notes: {
|
|
1148
|
-
worker?: string;
|
|
1149
|
-
driver?: string;
|
|
1150
|
-
};
|
|
1151
|
-
}
|
|
1152
|
-
interface TwoAgentResearchLoopResult {
|
|
1153
|
-
root: string;
|
|
1154
|
-
goal: string;
|
|
1155
|
-
rounds: number;
|
|
1156
|
-
ready: boolean;
|
|
1157
|
-
index: KnowledgeIndex;
|
|
1158
|
-
readiness?: EvalKnowledgeBundleBuildResult;
|
|
1159
|
-
steps: TwoAgentResearchRound[];
|
|
1160
|
-
}
|
|
1161
|
-
/**
|
|
1162
|
-
* Two-agent (driver + worker) sibling of `runKnowledgeResearchLoop`.
|
|
1163
|
-
*
|
|
1164
|
-
* Both agents research to grow ONE knowledge base. The roles are differentiated:
|
|
1165
|
-
*
|
|
1166
|
-
* - **WORKER** = primary research. Each round it reads the open gaps, discovers
|
|
1167
|
-
* new sources, and proposes additions (`sources` + `proposalText`). It ADDS.
|
|
1168
|
-
* - **DRIVER** = the verifier / gap-filler / gate. It (1) VERIFIES the worker's
|
|
1169
|
-
* sources before they commit — dedup against the KB, then `verifySource`
|
|
1170
|
-
* rejects ones that aren't real/relevant; (2) GAP-FILLS the gaps the worker
|
|
1171
|
-
* missed with its own research pass (when `driverResearches`); (3) folds the
|
|
1172
|
-
* remaining gaps into the worker's next prompt; and (4) GATES on
|
|
1173
|
-
* `scoreKnowledgeReadiness` — the loop stops as soon as there are no blocking
|
|
1174
|
-
* gaps.
|
|
1175
|
-
*
|
|
1176
|
-
* Set `driverResearches: false` (default) for the pure-coordinator mode: the
|
|
1177
|
-
* driver only verifies + gates and contributes no research itself.
|
|
1178
|
-
*
|
|
1179
|
-
* Composes existing atoms — `initKnowledgeBase`, `addSourceText`,
|
|
1180
|
-
* `applyKnowledgeWriteBlocks`, `buildEvalKnowledgeBundle` (the readiness gate),
|
|
1181
|
-
* and `searchKnowledge` — and reinvents none of them.
|
|
1182
|
-
*/
|
|
1183
|
-
declare function runTwoAgentResearchLoop(options: TwoAgentResearchLoopOptions): Promise<TwoAgentResearchLoopResult>;
|
|
1184
|
-
/**
|
|
1185
|
-
* Helper for verifiers: does the candidate source's text/title overlap any page
|
|
1186
|
-
* the readiness search returns for a gap query? A cheap relevance heuristic the
|
|
1187
|
-
* driver can compose into `verifySource` (real verifiers can do more).
|
|
1188
|
-
*/
|
|
1189
|
-
declare function sourceMatchesGaps(source: ResearchSourceProposal, index: KnowledgeIndex, gaps: KnowledgeGap[]): KnowledgeSearchResult[];
|
|
1190
|
-
|
|
1191
1609
|
declare const WIKILINK_REGEX: RegExp;
|
|
1192
1610
|
declare function extractWikilinks(content: string): string[];
|
|
1193
1611
|
declare function normalizeLinkTarget(target: string): string;
|
|
@@ -1195,4 +1613,4 @@ declare function normalizeLinkTarget(target: string): string;
|
|
|
1195
1613
|
declare function isSafeKnowledgePath(path: string, allowedPrefixes?: string[]): boolean;
|
|
1196
1614
|
declare function parseKnowledgeWriteBlocks(text: string, allowedPrefixes?: string[]): KnowledgeWriteParseResult;
|
|
1197
1615
|
|
|
1198
|
-
export { type AddSourceOptions, type AddSourceTextInput, type ApplyWriteBlocksResult, type BuildEvalKnowledgeBundleOptions, type ChunkingOptions, type D1Adapter, type DefineReadinessSpecInput, type DetectChangesOptions, type DetectChangesResult, type DiscoveryResult, type DiscoveryTask, type DriverResearchContext, type EvalKnowledgeBundleBuildResult, type FileSystemFreshnessStoreOptions, FileSystemKbStore, type FreshnessKey, type FreshnessMark, type FreshnessRecord, type FreshnessTtl, type KbStore, KnowledgeBaseCandidateSchema, type KnowledgeChange, type KnowledgeChangeKind, type KnowledgeChunk, KnowledgeClaim, type KnowledgeControlLoopAction, type KnowledgeControlLoopActionResult, type KnowledgeControlLoopAdapter, type KnowledgeControlLoopAdapterOptions, type KnowledgeControlLoopState, type KnowledgeDiscoveryDispatcher, type KnowledgeDiscoveryWorker, KnowledgeEvent, type KnowledgeEventQuery, KnowledgeEventSchema, KnowledgeEventType, type KnowledgeExplanation, KnowledgeFragment, type KnowledgeFreshnessStore, type KnowledgeGap, KnowledgeGraph, KnowledgeGraphEdgeSchema, KnowledgeGraphNodeSchema, KnowledgeIndex, KnowledgeIndexSchema, type KnowledgeInspection, type KnowledgeLayout, KnowledgeLintFinding, KnowledgePage, KnowledgePageSchema, type KnowledgeProposal, KnowledgeProposalParseError, type KnowledgeReadinessSpec, KnowledgeRelease, type KnowledgeReleaseInput, type KnowledgeReleaseReport, type KnowledgeResearchLoopContext, type KnowledgeResearchLoopDecision, type KnowledgeResearchLoopResult, type KnowledgeResearchLoopStep, KnowledgeSearchResult, KnowledgeWriteBlock, KnowledgeWriteParseResult, MemoryKbStore, type ParsedFrontmatter, type ProposeFromFindingsResult, READINESS_SPEC_DEFAULTS, RESEARCH_SUPERVISOR_SYSTEM_PROMPT, type RejectedSource, type ResearchContribution, type ResearchDriver, type ResearchSourceProposal, type ResearchSupervisorOptions, type ResearchWorker, type RunKnowledgeResearchLoopOptions, SCAFFOLD_PAGE_BASENAMES, type SourceAdapter, type SourceAdapterInput, type SourceAdapterOutput, SourceAnchorSchema, type SourceFreshnessInspection, SourceRecord, SourceRecordSchema, SourceRegistry, type SourceVerdict, type SourceVerificationContext, type TwoAgentResearchLoopOptions, type TwoAgentResearchLoopResult, type TwoAgentResearchRound, type ValidateKnowledgeOptions, type ValidateKnowledgeResult, WIKILINK_REGEX, type WorkerResearchContext, addSourcePath, addSourceText, applyKnowledgeWriteBlocks, applyKnowledgeWriteBlocksFile, buildEvalKnowledgeBundle, buildKnowledgeGraph, buildKnowledgeIndex, chunkMarkdown, createD1FreshnessStoreStub, createFileSystemFreshnessStore, createKnowledgeControlLoopAdapter, createKnowledgeEvent, createLocalDiscoveryDispatcher, defineReadinessSpec, detectChanges, explainKnowledgeTarget, extractWikilinks, formatFrontmatter, initKnowledgeBase, inspectKnowledgeIndex, isSafeKnowledgePath, isScaffoldPath, knowledgeReadinessDeliverable, knowledgeReleaseReport, layoutFor, lintKnowledgeIndex, loadKnowledgePages, loadSourceRegistry, mediaTypeFor, normalizeLinkTarget, parseFrontmatter, parseKnowledgeWriteBlocks, proposeFromFinding, proposeFromFindings, reciprocalRankFusion, runKnowledgeResearchLoop, runResearchSupervisor, runTwoAgentResearchLoop, searchKnowledge, sha256, slugify, sourceMatchesGaps, sourceRegistryPath, stableId, stripFrontmatter, textSourceAdapter, tokenizeQuery, validateKnowledgeIndex, writeJson, writeKnowledgeIndex, writeSourceRegistry };
|
|
1616
|
+
export { type AdaptiveDecision, type AdaptiveDriverOptions, type AdaptiveResearchDriver, type AdaptiveStats, type AddSourceOptions, type AddSourceTextInput, type ApplyWriteBlocksResult, type BuildEvalKnowledgeBundleOptions, type ChunkingOptions, type ClaimGroundingDriverOptions, type D1Adapter, type DedupReason, type DefineReadinessSpecInput, type DetectChangesOptions, type DetectChangesResult, type DiscoveryResult, type DiscoveryTask, type DriverResearchContext, type EvalKnowledgeBundleBuildResult, type FileSystemFreshnessStoreOptions, FileSystemKbStore, type FreshnessKey, type FreshnessMark, type FreshnessRecord, type FreshnessTtl, type GroundClaimOptions, type GroundingResult, type KbStore, KnowledgeBaseCandidateSchema, type KnowledgeChange, type KnowledgeChangeKind, type KnowledgeChunk, KnowledgeClaim, type KnowledgeControlLoopAction, type KnowledgeControlLoopActionResult, type KnowledgeControlLoopAdapter, type KnowledgeControlLoopAdapterOptions, type KnowledgeControlLoopState, type KnowledgeDiscoveryDispatcher, type KnowledgeDiscoveryWorker, KnowledgeEvent, type KnowledgeEventQuery, KnowledgeEventSchema, KnowledgeEventType, type KnowledgeExplanation, KnowledgeFragment, type KnowledgeFreshnessStore, type KnowledgeGap, KnowledgeGraph, KnowledgeGraphEdgeSchema, KnowledgeGraphNodeSchema, KnowledgeIndex, KnowledgeIndexSchema, type KnowledgeInspection, type KnowledgeLayout, KnowledgeLintFinding, KnowledgePage, KnowledgePageSchema, type KnowledgeProposal, KnowledgeProposalParseError, type KnowledgeReadinessSpec, KnowledgeRelease, type KnowledgeReleaseInput, type KnowledgeReleaseReport, type KnowledgeResearchLoopContext, type KnowledgeResearchLoopDecision, type KnowledgeResearchLoopResult, type KnowledgeResearchLoopStep, KnowledgeSearchResult, KnowledgeWriteBlock, KnowledgeWriteParseResult, MemoryKbStore, type ParsedFrontmatter, type ProposeFromFindingsResult, READINESS_SPEC_DEFAULTS, RESEARCH_SUPERVISOR_SYSTEM_PROMPT, type RejectedSource, type ResearchContribution, type ResearchDriver, type ResearchSourceProposal, type ResearchSupervisorOptions, type ResearchWorker, type RouterClient, RouterError, type RouterUsage, type RunKnowledgeResearchLoopOptions, SCAFFOLD_PAGE_BASENAMES, type SourceAdapter, type SourceAdapterInput, type SourceAdapterOutput, SourceAnchorSchema, type SourceFreshnessInspection, SourceRecord, SourceRecordSchema, SourceRegistry, type SourceVerdict, type SourceVerificationContext, type TangleRouterOptions, type TriageClass, type TwoAgentResearchLoopOptions, type TwoAgentResearchLoopResult, type TwoAgentResearchRound, type ValidateKnowledgeOptions, type ValidateKnowledgeResult, type VerifyingDriverOptions, WIKILINK_REGEX, type WebResearchWorkerOptions, type WebSearchHit, type WorkerClaimDecorationOptions, type WorkerResearchContext, addSourcePath, addSourceText, applyKnowledgeWriteBlocks, applyKnowledgeWriteBlocksFile, buildEvalKnowledgeBundle, buildKnowledgeGraph, buildKnowledgeIndex, canonicalizeUrl, chunkMarkdown, citedClaimKey, citedClaimOf, contentKey, createAdaptiveResearchDriver, createClaimDecorator, createClaimGroundingVerifier, createD1FreshnessStoreStub, createFileSystemFreshnessStore, createKnowledgeControlLoopAdapter, createKnowledgeEvent, createLocalDiscoveryDispatcher, createTangleRouterClient, createVerifyingResearchDriver, createWebResearchWorker, defineReadinessSpec, detectChanges, explainKnowledgeTarget, extractWikilinks, formatFrontmatter, groundClaimInText, initKnowledgeBase, inspectKnowledgeIndex, isSafeKnowledgePath, isScaffoldPath, knowledgeReadinessDeliverable, knowledgeReleaseReport, layoutFor, lintKnowledgeIndex, loadKnowledgePages, loadSourceRegistry, mediaTypeFor, normalizeLinkTarget, parseFrontmatter, parseKnowledgeWriteBlocks, proposeFromFinding, proposeFromFindings, reciprocalRankFusion, runKnowledgeResearchLoop, runResearchSupervisor, runTwoAgentResearchLoop, searchKnowledge, sha256, slugify, sourceMatchesGaps, sourceRegistryPath, stableId, stripFrontmatter, textSourceAdapter, tokenizeQuery, triageSource, validateKnowledgeIndex, withCitedClaim, writeJson, writeKnowledgeIndex, writeSourceRegistry };
|