@tangle-network/agent-knowledge 1.10.0 → 1.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +250 -74
  2. package/dist/benchmarks/index.d.ts +5 -0
  3. package/dist/benchmarks/index.js +52 -0
  4. package/dist/chunk-DQ3PDMDP.js +115 -0
  5. package/dist/chunk-DQ3PDMDP.js.map +1 -0
  6. package/dist/chunk-ULXZI235.js +1855 -0
  7. package/dist/chunk-ULXZI235.js.map +1 -0
  8. package/dist/{chunk-U6KQ4FS3.js → chunk-VN2OGUUP.js} +306 -40
  9. package/dist/chunk-VN2OGUUP.js.map +1 -0
  10. package/dist/{chunk-WWY5FTKQ.js → chunk-W6VWYTNH.js} +10 -115
  11. package/dist/chunk-W6VWYTNH.js.map +1 -0
  12. package/dist/chunk-XVU5FFQA.js +49 -0
  13. package/dist/chunk-XVU5FFQA.js.map +1 -0
  14. package/dist/cli.js +4 -2
  15. package/dist/cli.js.map +1 -1
  16. package/dist/index-Cj5jRXOz.d.ts +426 -0
  17. package/dist/index.d.ts +1036 -169
  18. package/dist/index.js +3372 -558
  19. package/dist/index.js.map +1 -1
  20. package/dist/memory/index.d.ts +5 -70
  21. package/dist/memory/index.js +20 -4
  22. package/dist/types-CjqPcTTK.d.ts +319 -0
  23. package/docs/architecture.md +7 -5
  24. package/docs/eval/investment-material-facts.md +252 -0
  25. package/docs/eval/rag-eval-roadmap.md +119 -0
  26. package/docs/results/investment-thesis.md +306 -0
  27. package/docs/results/research-driving.md +265 -0
  28. package/docs/two-agent-research-ab.md +121 -10
  29. package/package.json +8 -9
  30. package/dist/chunk-MU5CEOGE.js +0 -387
  31. package/dist/chunk-MU5CEOGE.js.map +0 -1
  32. package/dist/chunk-U6KQ4FS3.js.map +0 -1
  33. package/dist/chunk-WWY5FTKQ.js.map +0 -1
  34. package/dist/profiles/index.d.ts +0 -194
  35. package/dist/profiles/index.js +0 -11
  36. package/docs/recursive-research-leaf.md +0 -86
  37. package/docs/supervisor-profiles.md +0 -295
  38. /package/dist/{profiles → benchmarks}/index.js.map +0 -0
package/README.md CHANGED
@@ -10,10 +10,11 @@ This package turns raw sources and generated markdown knowledge into a versionab
10
10
  - [Start here](#start-here) — pick CLI vs programmatic
11
11
  - [CLI](#cli) — `init` → `source-add` → `index` → `search` → `lint`
12
12
  - [Design](#design) — the invariants (immutable sources, cited claims, deterministic graph)
13
- - [Agent-Eval integration](#agent-eval-integration) — readiness bundles + release reports
13
+ - [Benchmark harness](#benchmark-harness) — BEIR/MTEB/qrels, RAG answer, hallucination, KB-improvement cases
14
+ - [Agent-Eval integration](#agent-eval-integration) — retrieval eval + readiness bundles + release reports
14
15
  - [Memory adapters](#memory-adapters) — generic memory contract + Neo4j Agent Memory bridge
15
16
  - [Research loop](#research-loop) — `runKnowledgeResearchLoop` + control-loop adapter
16
- - [Researcher profile](#researcher-profile) — sandbox `AgentProfile` for `runLoop`
17
+ - [Runtime integration](#runtime-integration) — how agent runners plug into the pure KB loop
17
18
  - [Pluggable knowledge sources](#pluggable-knowledge-sources) — live authorities → eval re-runs
18
19
 
19
20
  ## Install
@@ -29,8 +30,15 @@ Two ways in, depending on what you're doing:
29
30
  - **Author / inspect a KB by hand** → the [CLI](#cli) (`init` → `source-add` → `index` → `search` → `lint`). Fastest way to see the shape on disk.
30
31
  - **Drive it from an agent** → pick the primitive by intent:
31
32
  - *"Does the agent have enough context to run?"* → [`buildEvalKnowledgeBundle`](#agent-eval-integration) (block / ask / acquire before execution).
32
- - *"Grow the KB as a researcher"* → [`runKnowledgeResearchLoop`](#research-loop) (deterministic mechanics; your agent owns judgment), [`runTwoAgentResearchLoop`](#two-agent-research-loop) (researcher proposes, verifier checks + fills gaps, offline), or the sandbox [researcher profile](#researcher-profile) for `runLoop`.
33
- - *"Spawn one researcher per sub-topic and stop when the KB is ready"* → [`runResearchSupervisor`](#research-supervisor) (a supervisor brain sizes the topology over a `Scope`; LIVE, needs creds).
33
+ - *"Grow the KB as a researcher"* → [`runKnowledgeResearchLoop`](#research-loop) (deterministic mechanics; your agent owns judgment) or [`runTwoAgentResearchLoop`](#two-agent-research-loop) (researcher proposes, verifier checks + fills gaps).
34
+ - *"Spawn live agents to improve a KB"* → pass an `updateKnowledge` callback to `improveKnowledgeBase`; runtime-backed supervisors live in `@tangle-network/agent-runtime`.
35
+ - *"Tune retrieval for a knowledge base"* → `runRetrievalImprovementLoop` in the [Agent-Eval integration](#agent-eval-integration) section.
36
+ - *"Run an operator-grade KB improvement cycle"* → `improveKnowledgeBase` in the [Agent-Eval integration](#agent-eval-integration) section.
37
+ It creates a candidate KB, lets agents or deterministic hooks improve it, runs configured evals, can be resumed, and promotes only when the live KB has not changed underneath it.
38
+ - *"Expose the lower-level RAG lifecycle phases"* → `runRagKnowledgeImprovementLoop` in the [Agent-Eval integration](#agent-eval-integration) section.
39
+ It exposes retrieval tuning, gap diagnosis, knowledge acquisition/update, answer-quality checks, and promotion as one typed lifecycle.
40
+ - *"Evaluate RAG answers or a wiki/KB"* → `ragAnswerQualityJudge`, `createRagAnswerQualityHook`, and `scoreKnowledgeBaseIndex` in the [Agent-Eval integration](#agent-eval-integration) section.
41
+ - *"Run standard RAG/KB benchmarks"* → `runKnowledgeBenchmarkSuite` in the [Benchmark harness](#benchmark-harness) section.
34
42
  - *"Does this candidate KB actually improve task success?"* → run an [agent-eval improvement loop](#agent-eval-integration) over KB variants, then `knowledgeReleaseReport` for the promotion decision.
35
43
  - *"Keep live authorities fresh"* → [pluggable sources](#pluggable-knowledge-sources) + `detectChanges` → eval re-runs.
36
44
 
@@ -91,6 +99,23 @@ from `@tangle-network/agent-knowledge`.
91
99
  - `createKnowledgeControlLoopAdapter()` maps those mechanics into
92
100
  `agent-eval`'s `runAgentControlLoop()` so products can plug in their own
93
101
  proposer, reviewer, and driver policies.
102
+ - `runRagKnowledgeImprovementLoop()` coordinates the whole RAG improvement
103
+ lifecycle. Retrieval tuning, diagnosis, acquisition, KB update,
104
+ answer-quality eval, and promotion are separate typed phases so products can
105
+ plug in browser agents, coding agents, connectors, or deterministic policies
106
+ without this package hardcoding an agent runner.
107
+ - `improveKnowledgeBase()` wraps that lifecycle with durable candidate state,
108
+ a per-run lock, resume support, isolated candidate workspaces, KB quality
109
+ scoring, and conflict-safe promotion.
110
+ Use it when running agents in loops against a real KB rather than only
111
+ exposing phase hooks.
112
+ - `evaluateKnowledgeBaseReadiness()` checks one KB root without running an
113
+ improvement loop: it rebuilds the index, validates/lints it, scores KB
114
+ quality, and evaluates configured readiness specs.
115
+ - RAG answer evaluation follows the common open-source shape used by Ragas,
116
+ DeepEval, TruLens, and RAGChecker: context quality, answer relevance,
117
+ support/faithfulness, citations, abstention, and failure diagnosis.
118
+ External tools stay pluggable via score normalization and row exporters.
94
119
  - Zod schemas define the stable wire shape.
95
120
  - Graph/search/lint are deterministic and fast.
96
121
  - `searchKnowledge` returns hits with three score fields. `score` and
@@ -101,6 +126,7 @@ from `@tangle-network/agent-knowledge`.
101
126
  when comparing against natural confidence thresholds. The normalization is
102
127
  within-set ranking, not a cross-query absolute confidence.
103
128
  - Release confidence uses `@tangle-network/agent-eval` release gates (`evaluateReleaseConfidence`) instead of reimplementing them.
129
+ - Retrieval eval turns retrieval/RAG configs into `agent-eval` surfaces, auto-searches candidate configs, and scores them against page, source, source-anchor, or source-span targets.
104
130
  - `buildEvalKnowledgeBundle()` maps wiki/search evidence into
105
131
  `agent-eval` `KnowledgeRequirement`, `KnowledgeBundle`, and
106
132
  `KnowledgeReadinessReport` contracts so control loops can block, ask, or
@@ -112,8 +138,214 @@ The `/memory` subpath exports an optional memory adapter contract. Use it to
112
138
  bridge episodic or graph-native memory systems into the same source-grounded
113
139
  readiness/eval machinery without making `agent-knowledge` own the database.
114
140
 
141
+ ## Benchmark Harness
142
+
143
+ Use `runKnowledgeBenchmarkSuite()` when the product goal is to run a fixed RAG/KB benchmark pack and get one report across retrieval, answer quality, hallucination, and candidate-KB improvement cases.
144
+ The module also exports `INDUSTRY_RAG_BENCHMARKS`, a compact manifest for BEIR, MTEB retrieval, MS MARCO, TREC DL, MIRACL, LoTTE, BRIGHT, CRAG, HotpotQA, KILT, RAGTruth, FaithBench, and first-party KB-improvement tasks.
145
+
146
+ ```ts
147
+ import {
148
+ buildFirstPartyMemoryLifecycleBenchmarkCases,
149
+ buildIndustryMemoryBenchmarkSmokeCases,
150
+ buildIndustryRagBenchmarkSmokeCases,
151
+ buildRetrievalBenchmarkCasesFromQrels,
152
+ createInMemoryBenchmarkAdapter,
153
+ createNoopMemoryBenchmarkAdapter,
154
+ isKnowledgeMemoryBenchmarkCase,
155
+ parseKnowledgeBenchmarkQrels,
156
+ respondToIndustryMemoryBenchmarkSmokeCase,
157
+ respondToIndustryRagBenchmarkSmokeCase,
158
+ runMemoryAdapterBenchmark,
159
+ runKnowledgeBenchmarkSuite,
160
+ } from '@tangle-network/agent-knowledge/benchmarks'
161
+ import { createNeo4jAgentMemoryAdapter } from '@tangle-network/agent-knowledge/memory'
162
+
163
+ await runKnowledgeBenchmarkSuite({
164
+ cases: buildIndustryRagBenchmarkSmokeCases(),
165
+ runDir: '.agent-knowledge/benchmark-runs/industry-smoke',
166
+ respond: respondToIndustryRagBenchmarkSmokeCase,
167
+ })
168
+
169
+ await runKnowledgeBenchmarkSuite({
170
+ cases: buildIndustryMemoryBenchmarkSmokeCases(),
171
+ runDir: '.agent-knowledge/benchmark-runs/memory-smoke',
172
+ respond: ({ case: testCase }) => {
173
+ if (!isKnowledgeMemoryBenchmarkCase(testCase)) return { answer: '' }
174
+ return respondToIndustryMemoryBenchmarkSmokeCase({ case: testCase })
175
+ },
176
+ })
177
+
178
+ const memoryRanking = await runMemoryAdapterBenchmark({
179
+ cases: buildFirstPartyMemoryLifecycleBenchmarkCases(),
180
+ runDir: '.agent-knowledge/benchmark-runs/memory-ranking',
181
+ candidates: [
182
+ { id: 'no-memory', createAdapter: () => createNoopMemoryBenchmarkAdapter() },
183
+ {
184
+ id: 'in-memory',
185
+ createAdapter: () => createInMemoryBenchmarkAdapter(),
186
+ searchLimit: 1,
187
+ },
188
+ {
189
+ id: 'neo4j-agent-memory',
190
+ createAdapter: () => createNeo4jAgentMemoryAdapter({ client: neo4jMemoryClient }),
191
+ searchLimit: 5,
192
+ },
193
+ ],
194
+ })
195
+
196
+ console.log(memoryRanking.rows)
197
+
198
+ const cases = buildRetrievalBenchmarkCasesFromQrels({
199
+ benchmarkId: 'beir/nfcorpus',
200
+ family: 'beir',
201
+ queries: [{ id: 'q1', text: 'aspirin heart attack prevention', split: 'holdout' }],
202
+ qrels: parseKnowledgeBenchmarkQrels('q1 0 src-aspirin 1'),
203
+ targetKind: 'source',
204
+ k: 10,
205
+ })
206
+
207
+ const result = await runKnowledgeBenchmarkSuite({
208
+ cases,
209
+ runDir: '.agent-knowledge/benchmark-runs/beir-nfcorpus-smoke',
210
+ respond: async ({ case: testCase }) => {
211
+ if (testCase.taskKind !== 'retrieval') return { hits: [] }
212
+ const hits = await retrieveFromYourKb(testCase.query)
213
+ return { hits, costUsd: 0.001 }
214
+ },
215
+ })
216
+
217
+ console.log(result.report.score.mean)
218
+ ```
219
+
220
+ Use `buildRetrievalBenchmarkCasesFromQrels()` for qrels-backed retrieval datasets.
221
+ The smoke pack proves that every declared benchmark family is wired through the runner; full BEIR, MTEB, MS MARCO, TREC DL, MIRACL, LoTTE, BRIGHT, CRAG, HotpotQA, KILT, RAGTruth, and FaithBench runs should pass real dataset rows through the same case shapes.
222
+ Use `KnowledgeAnswerBenchmarkCase` for CRAG/HotpotQA/KILT-style answer checks and RAGTruth/FaithBench-style hallucination checks by encoding required claims, forbidden claims, and expected source IDs.
223
+ Use `taskKind: 'kb-improvement'` when the artifact is candidate KB text produced by `improveKnowledgeBase()`.
224
+ Use `KnowledgeMemoryBenchmarkCase` for memory systems.
225
+ Memory cases carry ordered events plus current required facts, stale forbidden facts, expected event IDs, and expected actor IDs.
226
+ The built-in memory scorer reports current fact recall, stale-memory safety, event recall, and actor recall, which maps to LoCoMo, LongMemEval, Memora, MemoryAgentBench, MemoryBank-style personalization, GroupMemBench, and first-party memory lifecycle checks.
227
+ Use `runMemoryAdapterBenchmark()` to rank real memory systems that implement `AgentMemoryAdapter`.
228
+ This is the path for Neo4j Agent Memory, Mem0, Zep, Letta, Graphiti, a vector store, or a product-owned memory backend.
229
+
115
230
  ## Agent-Eval Integration
116
231
 
232
+ Use `ragAnswerQualityJudge` or `createRagAnswerQualityHook` when the product already has answer traces and needs SOTA-style RAG scoring without rebuilding metrics.
233
+ The built-in checks are deterministic and general; pass external scores from Ragas, DeepEval, TruLens, RAGChecker, or a custom evaluator when you want model-based judging.
234
+
235
+ ```ts
236
+ import {
237
+ createRagAnswerQualityHook,
238
+ scoreKnowledgeBaseIndex,
239
+ } from '@tangle-network/agent-knowledge'
240
+
241
+ const evaluateAnswers = createRagAnswerQualityHook({
242
+ scenarios: answerScenarios,
243
+ run: async (scenario) => runRagAnswerTrace(scenario),
244
+ externalEvaluator: async ({ scenario, artifact }) => runRagasOrDeepEval({
245
+ input: scenario.query,
246
+ output: artifact.answer,
247
+ contexts: artifact.contexts,
248
+ }),
249
+ })
250
+
251
+ const answerQuality = await evaluateAnswers()
252
+ const kbQuality = scoreKnowledgeBaseIndex(index, {
253
+ strict: true,
254
+ minCitationRate: 0.8,
255
+ maxStaleSourceRate: 0.02,
256
+ })
257
+ ```
258
+
259
+ Use `runRagKnowledgeImprovementLoop` when the product question is broader than retrieval:
260
+ can the system find the gaps, gather or update knowledge, prove generated answers still behave, and decide whether to promote?
261
+ `agent-knowledge` owns the knowledge/eval contract; the caller supplies the research, coding, connector, and answer-eval hooks.
262
+
263
+ ```ts
264
+ import { runRagKnowledgeImprovementLoop } from '@tangle-network/agent-knowledge'
265
+
266
+ const result = await runRagKnowledgeImprovementLoop({
267
+ goal: 'Improve the support RAG KB',
268
+ retrieval: {
269
+ baseline: { k: 5, hybrid: false },
270
+ scenarios: trainRetrievalScenarios,
271
+ holdoutScenarios,
272
+ index,
273
+ searchSpace: { k: [5, 10, 20], hybrid: [false, true] },
274
+ targetRecall: 0.9,
275
+ },
276
+ diagnose: async ({ retrieval }) => diagnoseRagGaps(retrieval),
277
+ acquireKnowledge: async ({ findings }) => researchMissingSources(findings),
278
+ knowledgeResearch: { root: './kb' },
279
+ evaluateAnswers,
280
+ promote: async ({ retrieval, answerQuality }) =>
281
+ decidePromotion({ retrieval, answerQuality }),
282
+ requiredPhases: ['retrieval-tuning', 'knowledge-update', 'answer-quality', 'promotion'],
283
+ })
284
+
285
+ console.log(result.promotion)
286
+ ```
287
+
288
+ Use `improveKnowledgeBase` when a program should own the candidate workspace and promotion mechanics.
289
+ The wrapper composes the same RAG lifecycle, but adds resumable state under `.agent-knowledge/improvements/<runId>/`, a lock lease for parallel operators, and a base-hash check before copying the candidate over the live KB.
290
+
291
+ ```ts
292
+ import { improveKnowledgeBase } from '@tangle-network/agent-knowledge'
293
+
294
+ const result = await improveKnowledgeBase({
295
+ root: './kb',
296
+ goal: 'Improve support refund-policy knowledge',
297
+ readinessSpecs,
298
+ retrieval: {
299
+ baseline: { k: 5 },
300
+ scenarios: trainRetrievalScenarios,
301
+ holdoutScenarios,
302
+ searchSpace: { k: [5, 10, 20] },
303
+ targetRecall: 0.9,
304
+ },
305
+ step: async ({ readiness }) => runResearchAgent({ missing: readiness?.report }),
306
+ evaluateAnswers,
307
+ requiredPhases: ['knowledge-update', 'retrieval-tuning', 'answer-quality'],
308
+ })
309
+
310
+ console.log(result.promoted, result.candidate?.evaluation)
311
+ ```
312
+
313
+ Pass `promote: false` to leave the candidate workspace open for another agent or a human edit.
314
+ Calling `improveKnowledgeBase` again with the same `runId` re-evaluates that candidate and promotes it only if the original live KB hash still matches.
315
+
316
+ If a required phase is missing its hook, the loop throws.
317
+ That keeps the public API from reporting a fake “RAG improved” result when the caller only wired retrieval or only wired a researcher.
318
+
319
+ Use retrieval eval when the question is whether a retrieval/RAG config can find the right knowledge before an agent reasons over it.
320
+ The labels should name stable pages, source records, anchors, or source spans, not ephemeral chunk IDs.
321
+ The completion roadmap is in [`docs/eval/rag-eval-roadmap.md`](docs/eval/rag-eval-roadmap.md).
322
+
323
+ ```ts
324
+ import { runRetrievalImprovementLoop } from '@tangle-network/agent-knowledge'
325
+
326
+ const result = await runRetrievalImprovementLoop({
327
+ baseline: { k: 5, hybrid: false, reranker: null },
328
+ scenarios: trainRetrievalScenarios,
329
+ holdoutScenarios: holdoutRetrievalScenarios,
330
+ index,
331
+ searchSpace: {
332
+ k: [5, 10, 20],
333
+ hybrid: [false, true],
334
+ reranker: [null, 'bge-reranker'],
335
+ },
336
+ targetRecall: 0.9,
337
+ deltaThreshold: 0.02,
338
+ costCeiling: 15,
339
+ runDir: '.agent-knowledge/retrieval-runs',
340
+ })
341
+
342
+ console.log(result.winnerConfig)
343
+ ```
344
+
345
+ Pass a custom `retrieve` function to `buildRetrievalEvalDispatch` when the config controls an external vector store, reranker, hybrid search service, or chunker.
346
+ The built-in fallback uses `searchKnowledge` over the local deterministic index.
347
+ Use `buildRetrievalEvalDispatch`, `retrievalRecallJudge`, and `retrievalParameterSweepProposer` directly only when you need custom `agent-eval` wiring.
348
+
117
349
  To answer whether a candidate knowledge base actually improves agent task success, run an `@tangle-network/agent-eval` improvement loop (`runImprovementLoop`) over your KB variants on a real task corpus; each run is scored into a `RunRecord`.
118
350
 
119
351
  Use `knowledgeReleaseReport()` before promotion: pass the candidate and baseline `RunRecord[]` (plus optional `ReleaseTraceEvidence` and the gate decision) and it folds them into a `ReleaseConfidenceScorecard` and a `KnowledgeRelease` using `agent-eval`'s release gates and `RunRecord` validation.
@@ -308,86 +540,30 @@ await runTwoAgentResearchLoop({
308
540
  })
309
541
  ```
310
542
 
311
- ## Research supervisor
543
+ ## Runtime integration
312
544
 
313
- `runResearchSupervisor()` is the LIVE counterpart: a supervisor brain creates the
314
- topology dynamically one researcher worker per sub-topic over a `Scope` — and
315
- stops when the knowledge base is ready. It is a thin wrapper over `supervise()`
316
- from `@tangle-network/agent-runtime/loops`; it builds nothing new. The worker
317
- shape is the [researcher profile](#researcher-profile), and the completion oracle
318
- is `knowledgeReadinessDeliverable` (re-reads the KB from disk and runs the
319
- readiness gate, so it stops on the real grounded state, not a worker's
320
- self-report). Needs creds: a supervisor router brain plus a worker backend.
545
+ `agent-knowledge` owns knowledge state and measurement.
546
+ It deliberately does not own an agent runner.
547
+ Live agent orchestration belongs in `@tangle-network/agent-runtime`, which can call `improveKnowledgeBase` by passing an `updateKnowledge` callback:
321
548
 
322
549
  ```ts
323
- import { defineReadinessSpec, runResearchSupervisor } from '@tangle-network/agent-knowledge'
550
+ import { improveKnowledgeBase } from '@tangle-network/agent-knowledge'
324
551
 
325
- await runResearchSupervisor({
552
+ await improveKnowledgeBase({
326
553
  root: './kb',
327
554
  goal: 'Build a grounded onboarding wiki for billing support',
328
- readinessSpecs: [defineReadinessSpec({
329
- id: 'refund-policy',
330
- description: 'Refund policy grounding',
331
- query: 'refund policy customer request',
332
- requiredFor: ['support-agent'],
333
- })],
334
- budget: { maxIterations: 12, maxTokens: 200_000, maxUsd: 5 },
335
- // WHERE researcher workers run — the real backend seam.
336
- backend: {
337
- backend: 'router', // or 'sandbox' / 'cli' / 'bridge'
338
- routerBaseUrl: process.env.ROUTER_BASE_URL!,
339
- routerKey: process.env.ROUTER_KEY!,
340
- model: 'your-worker-model',
341
- },
342
- })
343
- ```
344
-
345
- ## Researcher profile
346
-
347
- `@tangle-network/agent-knowledge/profiles` ships a sandbox-SDK
348
- `AgentProfile` preset for source-grounded research agents. Pairs with
349
- `runLoop` from `@tangle-network/agent-runtime/loops` — the profile owns
350
- the prompt + output adapter + validator; the kernel owns iteration,
351
- concurrency, cost, and trace emission.
352
-
353
- ```ts
354
- import { runLoop } from '@tangle-network/agent-runtime/loops'
355
- import { multiHarnessResearcherFanout } from '@tangle-network/agent-knowledge/profiles'
356
-
357
- const research = multiHarnessResearcherFanout({
358
- harnesses: ['opencode/zai-coding-plan/glm-5.1', 'claude-code', 'codex'],
359
- })
360
-
361
- const result = await runLoop({
362
- driver: research.driver,
363
- agentRuns: research.agentRuns,
364
- output: research.output,
365
- validator: research.validator,
366
- task: {
367
- question: 'What content does cpg-founder ICP engage with on Twitter?',
368
- knowledgeNamespace: 'cust_42',
369
- sources: ['twitter', 'web'],
370
- maxItems: 20,
371
- minConfidence: 0.6,
555
+ readinessSpecs,
556
+ updateKnowledge: async ({ goal, findings }) => {
557
+ // Call your agent runner here, then apply source-backed write blocks.
558
+ return {
559
+ applied: true,
560
+ summary: `updated KB for ${goal} with ${findings.length} finding(s)`,
561
+ }
372
562
  },
373
- ctx: { sandboxClient },
374
563
  })
375
-
376
- if (result.winner?.verdict?.valid) {
377
- // result.winner.output.proposedWrites: KnowledgeUpdate[]
378
- // The profile does NOT materialize. Decide whether to apply.
379
- for (const write of result.winner.output.proposedWrites) {
380
- // route through applyKnowledgeWriteBlocks / a KbStore put when ready
381
- }
382
- }
383
564
  ```
384
565
 
385
- Three invariants are enforced by the validator:
386
-
387
- - **Namespace isolation** — every `KnowledgeItem` + `KnowledgeUpdate`
388
- must carry `task.knowledgeNamespace`. Cross-tenant writes hard-fail.
389
- - **Provenance** — every item carries at least one evidence entry.
390
- - **Citation density** — quotes-with-source / items >= 0.7 by default.
566
+ This keeps the dependency graph acyclic: `agent-knowledge` depends on `agent-eval`; agent runners depend on `agent-knowledge`, not the reverse.
391
567
 
392
568
  Validator scoring (default; overridable):
393
569
 
@@ -0,0 +1,5 @@
1
+ import '@tangle-network/agent-eval/campaign';
2
+ import '../types-CjqPcTTK.js';
3
+ export { B as BuildRetrievalBenchmarkCasesFromQrelsOptions, I as INDUSTRY_MEMORY_BENCHMARKS, e as INDUSTRY_RAG_BENCHMARKS, K as KnowledgeAnswerBenchmarkCase, f as KnowledgeAnswerBenchmarkTaskKind, g as KnowledgeBenchmarkArtifact, h as KnowledgeBenchmarkCase, i as KnowledgeBenchmarkCaseBase, j as KnowledgeBenchmarkDistribution, k as KnowledgeBenchmarkEvaluation, l as KnowledgeBenchmarkFamily, m as KnowledgeBenchmarkReport, n as KnowledgeBenchmarkResponder, o as KnowledgeBenchmarkScenario, p as KnowledgeBenchmarkSliceSummary, q as KnowledgeBenchmarkSource, r as KnowledgeBenchmarkSpec, s as KnowledgeBenchmarkSplit, t as KnowledgeBenchmarkTaskKind, u as KnowledgeClaimMatcher, v as KnowledgeMemoryBenchmarkCase, w as KnowledgeMemoryBenchmarkTaskKind, x as KnowledgeMemoryEvent, y as KnowledgeMemoryFactMatcher, z as KnowledgeRetrievalBenchmarkCase, A as KnowledgeRetrievalBenchmarkQrel, C as KnowledgeRetrievalBenchmarkQuery, M as MemoryAdapterBenchmarkCandidate, D as MemoryAdapterBenchmarkRankingRow, V as RunKnowledgeBenchmarkSuiteOptions, W as RunKnowledgeBenchmarkSuiteResult, X as RunMemoryAdapterBenchmarkOptions, Y as RunMemoryAdapterBenchmarkResult, Z as buildFirstPartyMemoryLifecycleBenchmarkCases, _ as buildIndustryMemoryBenchmarkSmokeCases, $ as buildIndustryRagBenchmarkSmokeCases, a0 as buildKnowledgeBenchmarkScenarios, a1 as buildRetrievalBenchmarkCasesFromQrels, a4 as createInMemoryBenchmarkAdapter, a5 as createMemoryAdapterBenchmarkResponder, a6 as createNoopMemoryBenchmarkAdapter, a7 as isKnowledgeMemoryBenchmarkCase, a8 as knowledgeBenchmarkJudge, a9 as parseKnowledgeBenchmarkJsonl, aa as parseKnowledgeBenchmarkQrels, ab as renderKnowledgeBenchmarkReportMarkdown, ac as respondToIndustryMemoryBenchmarkSmokeCase, ad as respondToIndustryRagBenchmarkSmokeCase, ai as runKnowledgeBenchmarkSuite, aj as runMemoryAdapterBenchmark, al as scoreKnowledgeBenchmarkArtifact, am as scoreMemoryBenchmarkArtifact, ao as summarizeKnowledgeBenchmarkCampaign } from '../index-Cj5jRXOz.js';
4
+ import '../types-C17sAROL.js';
5
+ import '@tangle-network/agent-eval/rl';
@@ -0,0 +1,52 @@
1
+ import {
2
+ INDUSTRY_MEMORY_BENCHMARKS,
3
+ INDUSTRY_RAG_BENCHMARKS,
4
+ buildFirstPartyMemoryLifecycleBenchmarkCases,
5
+ buildIndustryMemoryBenchmarkSmokeCases,
6
+ buildIndustryRagBenchmarkSmokeCases,
7
+ buildKnowledgeBenchmarkScenarios,
8
+ buildRetrievalBenchmarkCasesFromQrels,
9
+ createInMemoryBenchmarkAdapter,
10
+ createMemoryAdapterBenchmarkResponder,
11
+ createNoopMemoryBenchmarkAdapter,
12
+ isKnowledgeMemoryBenchmarkCase,
13
+ knowledgeBenchmarkJudge,
14
+ parseKnowledgeBenchmarkJsonl,
15
+ parseKnowledgeBenchmarkQrels,
16
+ renderKnowledgeBenchmarkReportMarkdown,
17
+ respondToIndustryMemoryBenchmarkSmokeCase,
18
+ respondToIndustryRagBenchmarkSmokeCase,
19
+ runKnowledgeBenchmarkSuite,
20
+ runMemoryAdapterBenchmark,
21
+ scoreKnowledgeBenchmarkArtifact,
22
+ scoreMemoryBenchmarkArtifact,
23
+ summarizeKnowledgeBenchmarkCampaign
24
+ } from "../chunk-ULXZI235.js";
25
+ import "../chunk-DQ3PDMDP.js";
26
+ import "../chunk-XVU5FFQA.js";
27
+ import "../chunk-YMKHCTS2.js";
28
+ export {
29
+ INDUSTRY_MEMORY_BENCHMARKS,
30
+ INDUSTRY_RAG_BENCHMARKS,
31
+ buildFirstPartyMemoryLifecycleBenchmarkCases,
32
+ buildIndustryMemoryBenchmarkSmokeCases,
33
+ buildIndustryRagBenchmarkSmokeCases,
34
+ buildKnowledgeBenchmarkScenarios,
35
+ buildRetrievalBenchmarkCasesFromQrels,
36
+ createInMemoryBenchmarkAdapter,
37
+ createMemoryAdapterBenchmarkResponder,
38
+ createNoopMemoryBenchmarkAdapter,
39
+ isKnowledgeMemoryBenchmarkCase,
40
+ knowledgeBenchmarkJudge,
41
+ parseKnowledgeBenchmarkJsonl,
42
+ parseKnowledgeBenchmarkQrels,
43
+ renderKnowledgeBenchmarkReportMarkdown,
44
+ respondToIndustryMemoryBenchmarkSmokeCase,
45
+ respondToIndustryRagBenchmarkSmokeCase,
46
+ runKnowledgeBenchmarkSuite,
47
+ runMemoryAdapterBenchmark,
48
+ scoreKnowledgeBenchmarkArtifact,
49
+ scoreMemoryBenchmarkArtifact,
50
+ summarizeKnowledgeBenchmarkCampaign
51
+ };
52
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,115 @@
1
+ // src/search.ts
2
+ var RRF_K = 60;
3
+ var STOP_WORDS = /* @__PURE__ */ new Set([
4
+ "the",
5
+ "is",
6
+ "a",
7
+ "an",
8
+ "what",
9
+ "how",
10
+ "are",
11
+ "was",
12
+ "were",
13
+ "to",
14
+ "for",
15
+ "of",
16
+ "with",
17
+ "by",
18
+ "in",
19
+ "on",
20
+ "and"
21
+ ]);
22
+ function searchKnowledge(index, query, limit = 10) {
23
+ const trimmed = query.trim();
24
+ if (trimmed === "") return [];
25
+ const tokenRanked = rankByTokens(index.pages, trimmed);
26
+ const graphRanked = rankByGraph(index.pages, tokenRanked);
27
+ const scores = reciprocalRankFusion([tokenRanked.map((p) => p.id), graphRanked.map((p) => p.id)]);
28
+ const byId = new Map(index.pages.map((page) => [page.id, page]));
29
+ const ranked = [...scores.entries()].map(([id, score]) => ({ page: byId.get(id), score })).filter((item) => Boolean(item.page)).sort((a, b) => b.score - a.score || a.page.path.localeCompare(b.page.path)).slice(0, limit);
30
+ const topScore = ranked[0]?.score ?? 0;
31
+ return ranked.map((item, i) => ({
32
+ page: item.page,
33
+ score: item.score,
34
+ rrfScore: item.score,
35
+ normalizedScore: topScore > 0 ? item.score / topScore : 0,
36
+ rank: i + 1,
37
+ snippet: buildSnippet(item.page.text, trimmed),
38
+ reasons: reasonsFor(item.page, trimmed)
39
+ }));
40
+ }
41
+ function tokenizeQuery(query) {
42
+ const raw = query.toLowerCase().split(/[\s,,。!?、;:""''()()\-_/\\·~~…]+/).filter((token) => token.length > 1 && !STOP_WORDS.has(token));
43
+ const tokens = [];
44
+ for (const token of raw) {
45
+ if (/[\u4e00-\u9fff\u3400-\u4dbf]/.test(token) && token.length > 2) {
46
+ const chars = [...token];
47
+ for (let i = 0; i < chars.length - 1; i++) tokens.push(chars[i] + chars[i + 1]);
48
+ tokens.push(...chars);
49
+ }
50
+ tokens.push(token);
51
+ }
52
+ return [...new Set(tokens)];
53
+ }
54
+ function reciprocalRankFusion(rankLists, k = RRF_K) {
55
+ const scores = /* @__PURE__ */ new Map();
56
+ for (const list of rankLists) {
57
+ list.forEach((id, idx) => {
58
+ scores.set(id, (scores.get(id) ?? 0) + 1 / (k + idx + 1));
59
+ });
60
+ }
61
+ return scores;
62
+ }
63
+ function rankByTokens(pages, query) {
64
+ const tokens = tokenizeQuery(query);
65
+ const effective = tokens.length > 0 ? tokens : [query.toLowerCase()];
66
+ return pages.map((page) => ({ page, score: tokenScore(page, query, effective) })).filter((item) => item.score > 0).sort((a, b) => b.score - a.score || a.page.path.localeCompare(b.page.path)).map((item) => item.page);
67
+ }
68
+ function rankByGraph(pages, tokenRanked) {
69
+ if (tokenRanked.length === 0) return [];
70
+ const seeds = new Set(tokenRanked.slice(0, 5).map((page) => page.id));
71
+ return pages.map((page) => ({
72
+ page,
73
+ score: page.outLinks.filter((link) => seeds.has(link)).length + page.sourceIds.filter(
74
+ (source) => tokenRanked.some((seed) => seed.sourceIds.includes(source))
75
+ ).length
76
+ })).filter((item) => item.score > 0).sort((a, b) => b.score - a.score || a.page.path.localeCompare(b.page.path)).map((item) => item.page);
77
+ }
78
+ function tokenScore(page, query, tokens) {
79
+ const title = page.title.toLowerCase();
80
+ const path = page.path.toLowerCase();
81
+ const body = page.text.toLowerCase();
82
+ const phrase = query.toLowerCase();
83
+ let score = 0;
84
+ if (path.endsWith(`${phrase}.md`) || title === phrase) score += 200;
85
+ if (title.includes(phrase)) score += 50;
86
+ if (body.includes(phrase)) score += 20;
87
+ for (const token of tokens) {
88
+ if (title.includes(token)) score += 5;
89
+ if (body.includes(token)) score += 1;
90
+ if (path.includes(token)) score += 3;
91
+ }
92
+ return score;
93
+ }
94
+ function buildSnippet(text, query) {
95
+ const compact = text.replace(/\s+/g, " ").trim();
96
+ const idx = compact.toLowerCase().indexOf(query.toLowerCase());
97
+ if (idx < 0) return compact.slice(0, 180);
98
+ return compact.slice(Math.max(0, idx - 80), Math.min(compact.length, idx + query.length + 100));
99
+ }
100
+ function reasonsFor(page, query) {
101
+ const lower = `${page.title}
102
+ ${page.text}`.toLowerCase();
103
+ const reasons = [];
104
+ if (lower.includes(query.toLowerCase())) reasons.push("phrase");
105
+ if (page.sourceIds.length > 0) reasons.push("sourced");
106
+ if (page.outLinks.length > 0) reasons.push("linked");
107
+ return reasons;
108
+ }
109
+
110
+ export {
111
+ searchKnowledge,
112
+ tokenizeQuery,
113
+ reciprocalRankFusion
114
+ };
115
+ //# sourceMappingURL=chunk-DQ3PDMDP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/search.ts"],"sourcesContent":["import type { KnowledgeIndex, KnowledgePage, KnowledgeSearchResult } from './types'\n\nconst RRF_K = 60\nconst STOP_WORDS = new Set([\n 'the',\n 'is',\n 'a',\n 'an',\n 'what',\n 'how',\n 'are',\n 'was',\n 'were',\n 'to',\n 'for',\n 'of',\n 'with',\n 'by',\n 'in',\n 'on',\n 'and',\n])\n\nexport function searchKnowledge(\n index: KnowledgeIndex,\n query: string,\n limit = 10,\n): KnowledgeSearchResult[] {\n const trimmed = query.trim()\n if (trimmed === '') return []\n const tokenRanked = rankByTokens(index.pages, trimmed)\n const graphRanked = rankByGraph(index.pages, tokenRanked)\n const scores = reciprocalRankFusion([tokenRanked.map((p) => p.id), graphRanked.map((p) => p.id)])\n const byId = new Map(index.pages.map((page) => [page.id, page]))\n\n const ranked = [...scores.entries()]\n .map(([id, score]) => ({ page: byId.get(id), score }))\n .filter((item): item is { page: KnowledgePage; score: number } => Boolean(item.page))\n .sort((a, b) => b.score - a.score || a.page.path.localeCompare(b.page.path))\n .slice(0, limit)\n\n // Normalize against the top hit so callers can compare against natural\n // [0, 1] thresholds. Raw RRF values are typically ~0.016, which reads as\n // \"no relevance\" to humans even when the result is the best available.\n // The top hit becomes 1 by definition; lower-ranked hits scale linearly.\n const topScore = ranked[0]?.score ?? 0\n\n return ranked.map((item, i) => ({\n page: item.page,\n score: item.score,\n rrfScore: item.score,\n normalizedScore: topScore > 0 ? item.score / topScore : 0,\n rank: i + 1,\n snippet: buildSnippet(item.page.text, trimmed),\n reasons: reasonsFor(item.page, trimmed),\n }))\n}\n\nexport function tokenizeQuery(query: string): string[] {\n const raw = query\n .toLowerCase()\n .split(/[\\s,,。!?、;:\"\"''()()\\-_/\\\\·~~…]+/)\n .filter((token) => token.length > 1 && !STOP_WORDS.has(token))\n const tokens: string[] = []\n for (const token of raw) {\n if (/[\\u4e00-\\u9fff\\u3400-\\u4dbf]/.test(token) && token.length > 2) {\n const chars = [...token]\n for (let i = 0; i < chars.length - 1; i++) tokens.push(chars[i]! + chars[i + 1]!)\n tokens.push(...chars)\n }\n tokens.push(token)\n }\n return [...new Set(tokens)]\n}\n\nexport function reciprocalRankFusion(rankLists: string[][], k = RRF_K): Map<string, number> {\n const scores = new Map<string, number>()\n for (const list of rankLists) {\n list.forEach((id, idx) => {\n scores.set(id, (scores.get(id) ?? 0) + 1 / (k + idx + 1))\n })\n }\n return scores\n}\n\nfunction rankByTokens(pages: KnowledgePage[], query: string): KnowledgePage[] {\n const tokens = tokenizeQuery(query)\n const effective = tokens.length > 0 ? tokens : [query.toLowerCase()]\n return pages\n .map((page) => ({ page, score: tokenScore(page, query, effective) }))\n .filter((item) => item.score > 0)\n .sort((a, b) => b.score - a.score || a.page.path.localeCompare(b.page.path))\n .map((item) => item.page)\n}\n\nfunction rankByGraph(pages: KnowledgePage[], tokenRanked: KnowledgePage[]): KnowledgePage[] {\n if (tokenRanked.length === 0) return []\n const seeds = new Set(tokenRanked.slice(0, 5).map((page) => page.id))\n return pages\n .map((page) => ({\n page,\n score:\n page.outLinks.filter((link) => seeds.has(link)).length +\n page.sourceIds.filter((source) =>\n tokenRanked.some((seed) => seed.sourceIds.includes(source)),\n ).length,\n }))\n .filter((item) => item.score > 0)\n .sort((a, b) => b.score - a.score || a.page.path.localeCompare(b.page.path))\n .map((item) => item.page)\n}\n\nfunction tokenScore(page: KnowledgePage, query: string, tokens: string[]): number {\n const title = page.title.toLowerCase()\n const path = page.path.toLowerCase()\n const body = page.text.toLowerCase()\n const phrase = query.toLowerCase()\n let score = 0\n if (path.endsWith(`${phrase}.md`) || title === phrase) score += 200\n if (title.includes(phrase)) score += 50\n if (body.includes(phrase)) score += 20\n for (const token of tokens) {\n if (title.includes(token)) score += 5\n if (body.includes(token)) score += 1\n if (path.includes(token)) score += 3\n }\n return score\n}\n\nfunction buildSnippet(text: string, query: string): string {\n const compact = text.replace(/\\s+/g, ' ').trim()\n const idx = compact.toLowerCase().indexOf(query.toLowerCase())\n if (idx < 0) return compact.slice(0, 180)\n return compact.slice(Math.max(0, idx - 80), Math.min(compact.length, idx + query.length + 100))\n}\n\nfunction reasonsFor(page: KnowledgePage, query: string): string[] {\n const lower = `${page.title}\\n${page.text}`.toLowerCase()\n const reasons: string[] = []\n if (lower.includes(query.toLowerCase())) reasons.push('phrase')\n if (page.sourceIds.length > 0) reasons.push('sourced')\n if (page.outLinks.length > 0) reasons.push('linked')\n return reasons\n}\n"],"mappings":"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","names":[]}