@autorag/librarian 2.8.0 → 2.9.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/NOTICE +4 -4
- package/README.md +65 -24
- package/dist/agent/agent.d.ts +126 -63
- package/dist/agent/citations.d.ts +23 -0
- package/dist/agent/datasource-skill.d.ts +30 -16
- package/dist/agent/emit-results-tool.d.ts +37 -2
- package/dist/agent/evidence-judgment.d.ts +58 -0
- package/dist/agent/evidence-ledger.d.ts +59 -0
- package/dist/agent/evidence-origins.d.ts +49 -0
- package/dist/agent/fast-answer-tool.d.ts +16 -6
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/jikji-find-tool.d.ts +2 -1
- package/dist/agent/pi-session.d.ts +8 -1
- package/dist/agent/query-peer-tool.d.ts +3 -0
- package/dist/agent/query-routing.d.ts +71 -10
- package/dist/agent/search-all-tool.d.ts +5 -5
- package/dist/agent/search-documents.d.ts +3 -11
- package/dist/agent/search-minsync-tool.d.ts +5 -5
- package/dist/agent/search-single-datasource-tool.d.ts +9 -8
- package/dist/agent/self-config.d.ts +40 -0
- package/dist/agent/system-prompt.d.ts +2 -3
- package/dist/agent/web-fetch-tool.d.ts +2 -1
- package/dist/agent/web-search-tool.d.ts +2 -1
- package/dist/cli/commands/evidence.d.ts +2 -2
- package/dist/cli/commands/memory.d.ts +1 -1
- package/dist/cli/commands/report.d.ts +1 -1
- package/dist/cli/config.d.ts +16 -8
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +10450 -9902
- package/dist/cli/output.d.ts +2 -6
- package/dist/config/home.d.ts +6 -0
- package/dist/core.d.ts +8 -16
- package/dist/core.js +16465 -15823
- package/dist/datasource/chunk-store.d.ts +2 -6
- package/dist/datasource/connector-skill.d.ts +2 -3
- package/dist/datasource/index.d.ts +2 -4
- package/dist/datasource/registry.d.ts +11 -13
- package/dist/datasource/scope.d.ts +19 -0
- package/dist/datasource/skills/github-gist/index.d.ts +1 -1
- package/dist/datasource/skills/github-gist/semantic.d.ts +3 -44
- package/dist/datasource/skills/github-gist/skill.d.ts +3 -3
- package/dist/datasource/types.d.ts +14 -28
- package/dist/embedding-runtime/gateway-embedder.d.ts +41 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14767 -14173
- package/dist/language.d.ts +2 -1
- package/dist/mcp/index.js +14797 -14204
- package/dist/memory/check-memory-tool.d.ts +8 -4
- package/dist/memory/context.d.ts +51 -0
- package/dist/memory/index.d.ts +8 -1
- package/dist/memory/judged-evidence.d.ts +32 -0
- package/dist/memory/memory.d.ts +36 -120
- package/dist/memory/renderer.d.ts +16 -7
- package/dist/memory/similar-queries.d.ts +40 -0
- package/dist/minsync/errors.d.ts +14 -0
- package/dist/minsync/index.d.ts +1 -0
- package/dist/minsync/method.d.ts +3 -3
- package/dist/mirror/sync.d.ts +5 -2
- package/dist/parser/defaults.d.ts +16 -5
- package/dist/parser/index.d.ts +1 -1
- package/dist/parser/kordoc.d.ts +8 -1
- package/dist/parser/ocr-engines.d.ts +19 -0
- package/dist/retrieval/bm25.d.ts +19 -0
- package/dist/retrieval/engine.d.ts +17 -58
- package/dist/retrieval/index.d.ts +2 -1
- package/dist/retrieval/merger.d.ts +6 -0
- package/dist/retrieval/rerank.d.ts +2 -2
- package/dist/retrieval/selection.d.ts +33 -41
- package/dist/retrieval/types.d.ts +1 -3
- package/dist/web/search/format.d.ts +5 -2
- package/dist/web/search/index.d.ts +7 -1
- package/package.json +5 -5
- package/skills/autorag/SKILL.md +21 -22
- package/skills/autorag-doctor/SKILL.md +20 -15
- package/skills/autorag-lite-setup/SKILL.md +21 -18
- package/skills/autorag-setup/SKILL.md +33 -20
- package/dist/cli/commands/feedback.d.ts +0 -8
- package/dist/datasource/access-context.d.ts +0 -43
- package/dist/datasource/result-filter.d.ts +0 -64
- package/dist/parser/ocr.d.ts +0 -31
package/NOTICE
CHANGED
|
@@ -6,16 +6,16 @@ legacy/ package license: Apache-2.0
|
|
|
6
6
|
|
|
7
7
|
Third-party production dependencies:
|
|
8
8
|
|
|
9
|
-
@earendil-works/pi-agent-core@
|
|
9
|
+
@earendil-works/pi-agent-core@1.1.0
|
|
10
10
|
License: MIT
|
|
11
11
|
|
|
12
|
-
@earendil-works/pi-ai@
|
|
12
|
+
@earendil-works/pi-ai@1.1.0
|
|
13
13
|
License: MIT
|
|
14
14
|
|
|
15
|
-
@earendil-works/pi-coding-agent@
|
|
15
|
+
@earendil-works/pi-coding-agent@1.1.0
|
|
16
16
|
License: MIT
|
|
17
17
|
|
|
18
|
-
@earendil-works/pi-tui@
|
|
18
|
+
@earendil-works/pi-tui@1.1.0
|
|
19
19
|
License: MIT
|
|
20
20
|
|
|
21
21
|
@modelcontextprotocol/server@2.3.0
|
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ Three principles drive every design decision in AutoRAG Agent:
|
|
|
61
61
|
|
|
62
62
|
AutoRAG Agent orchestrates five integrated subsystems:
|
|
63
63
|
|
|
64
|
-
1. **
|
|
64
|
+
1. **Retrieval Memory (`check_memory`):** After each answer, cited evidence Jev judges to genuinely support it is stored in `~/.autorag/memory.json`. Later searches receive this conversation's evidence, similar past questions, and long-term insights as **advisory reference** — it never reorders results or overrides current evidence. See [docs/retrieval-memory.md](docs/retrieval-memory.md).
|
|
65
65
|
2. **Pluggable Multi-Method Retrieval:**
|
|
66
66
|
- **BM25 Lexical Search:** Fast keyword ranking via MinSync over parsed markdown mirrors.
|
|
67
67
|
- **Semantic Vector Search:** Dense vector retrieval over CDC chunks via the built-in embedding gateway.
|
|
@@ -69,14 +69,14 @@ AutoRAG Agent orchestrates five integrated subsystems:
|
|
|
69
69
|
- **Jikji Find-First Discovery:** Local CLI-backed fast discovery answer packs.
|
|
70
70
|
- **Everything File-Name Search (Windows):** The bundled [voidtools Everything](https://www.voidtools.com/) indexes file and folder names under your search roots so the agent finds files by name, extension, path, size, or date instantly (`everything_search`).
|
|
71
71
|
- **FSearch File-Name Search (macOS/Linux):** [fsearch-cli](https://github.com/NomaDamas/fsearch-mac) (FSearch) keeps a live, per-workspace name index of your search roots so the agent finds files by name, extension, path, size, or date instantly (`fsearch_search`); without fsearch-cli installed it degrades to a slow filesystem walk.
|
|
72
|
-
- **Datasource Skills:**
|
|
73
|
-
3. **Result Merger &
|
|
72
|
+
- **Datasource Skills:** Federated retrieval across every configured external datasource.
|
|
73
|
+
3. **Result Merger & Scope Narrowing:** Cross-method deduplication, score normalization, and ordinary query-scope narrowing.
|
|
74
74
|
4. **Direct Evidence Reading (`bash`):** The agent directly opens and inspects promising files with `cat`, `grep`, or `find` to verify facts against ground truth.
|
|
75
|
-
5. **Curation
|
|
75
|
+
5. **Curation:** Structured findings are returned via `emit_autorag_results`; cited evidence that Jev judges to genuinely support the answer is remembered as reference context for later searches ([docs/retrieval-memory.md](docs/retrieval-memory.md)).
|
|
76
76
|
|
|
77
77
|
### Pi host boundary
|
|
78
78
|
|
|
79
|
-
AutoRAG uses `@earendil-works/pi-coding-agent` as the runtime host for model sessions. Pi owns provider credentials and OAuth storage, model-runtime dispatch, session JSONL persistence/resume, extension loading, lifecycle events, and the built-in `read`/`bash`/`edit`/`write`/`grep`/`find`/`ls` tools. AutoRAG registers only its domain tools and keeps orchestration outside the host: datasource
|
|
79
|
+
AutoRAG uses `@earendil-works/pi-coding-agent` as the runtime host for model sessions. Pi owns provider credentials and OAuth storage, model-runtime dispatch, session JSONL persistence/resume, extension loading, lifecycle events, and the built-in `read`/`bash`/`edit`/`write`/`grep`/`find`/`ls` tools. AutoRAG registers only its domain tools and keeps orchestration outside the host: datasource orchestration, MinSync/Jikji preparation, memory hints, fast-to-verification two-phase search, structured result emission, and remote-session filtering.
|
|
80
80
|
|
|
81
81
|
The CLI TUI (`autorag tui`) is Pi's interactive mode hosted on the AutoRAG librarian: there is no separate AutoRAG renderer. Pi owns the terminal UI and its native in-session commands — `/login`/`/logout`, `/model`, `/resume`, `/new`, `/tree`, `/compact`, and `/settings` — so provider sign-in and model selection work on first launch even when no AutoRAG model is configured. AutoRAG registers its retrieval tools and streams progress, preliminary answers, and final results into the same Pi session, so resume and two-phase search keep working together.
|
|
82
82
|
|
|
@@ -118,8 +118,8 @@ cp -R "$AUTORAG_SKILLS/autorag-lite-setup" .claude/skills/
|
|
|
118
118
|
Run the setup skill once to register the stdio server with the host. Reload the
|
|
119
119
|
agent, then discover the actual tool names and schemas with MCP `tools/list`.
|
|
120
120
|
The normal Lite path is `autorag.status` → `autorag.refresh` when needed →
|
|
121
|
-
`autorag.search`; use `autorag.report
|
|
122
|
-
|
|
121
|
+
`autorag.search`; use `autorag.report` and `autorag.evidence` for the optional
|
|
122
|
+
curation lifecycle. Copy `skills/autorag`
|
|
123
123
|
and `skills/autorag-setup` only when the agent should also drive the
|
|
124
124
|
model-backed librarian, and `skills/autorag-doctor` for diagnostics. Other
|
|
125
125
|
agents read their own skill directories; copy the same setup folder there and
|
|
@@ -166,10 +166,9 @@ hard-code a tool count.
|
|
|
166
166
|
|
|
167
167
|
Core Lite tools include `autorag.status`, `autorag.search`,
|
|
168
168
|
`autorag.search.files`, `autorag.datasources.list`, `autorag.datasources.get`,
|
|
169
|
-
`autorag.refresh`, `autorag.report`, `autorag.evidence
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
and feedback.
|
|
169
|
+
`autorag.refresh`, `autorag.report`, and `autorag.evidence`. Configured
|
|
170
|
+
integrated datasources expose additional scoped search tools. Read-only MCP
|
|
171
|
+
mode omits mutating tools such as refresh and report.
|
|
173
172
|
|
|
174
173
|
## ⚡ AutoRAG Lite: Model-Free Retrieval Engine
|
|
175
174
|
|
|
@@ -277,15 +276,59 @@ falling back to `["ko", "en"]`. Supported tags: `ko`, `en`, `ja`, `zh-hans`,
|
|
|
277
276
|
| `.pptx` | built-in PPTX reader |
|
|
278
277
|
| `.eml` | built-in mail reader |
|
|
279
278
|
| `.txt` `.text` `.md` `.markdown` | plain text (CP949/EUC-KR aware) |
|
|
280
|
-
| `.png` `.jpg` `.jpeg` `.
|
|
279
|
+
| `.png` `.jpg` `.jpeg` `.webp` | `kordoc` image OCR (only when `parserOptions.ocr.enabled` is `true`) |
|
|
281
280
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
281
|
+
`.bmp` and `.tiff` are not parsed: kordoc rejects both as unsupported.
|
|
282
|
+
|
|
283
|
+
### Making photos and scans searchable
|
|
284
|
+
|
|
285
|
+
Image files and scanned PDF pages become searchable through one switch,
|
|
286
|
+
`parserOptions.ocr.enabled` (default `false`). It is off by default so indexing
|
|
287
|
+
downloads no recognition model and never runs OCR over a photo library. With it
|
|
288
|
+
off, image files are not parsed at all and scanned pages stay unrecognized.
|
|
289
|
+
|
|
290
|
+
```json
|
|
291
|
+
{ "languages": ["ko", "en"], "parserOptions": { "ocr": { "enabled": true } } }
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`kordoc` owns both inputs. The configured `languages` pick the engine:
|
|
295
|
+
|
|
296
|
+
| `languages` | Engine | First-use download |
|
|
297
|
+
|---|---|---|
|
|
298
|
+
| only `ko` and/or `en` | kordoc built-in PP-OCRv5 (local CPU) | ~18 MB from Hugging Face, cached in `~/.cache/kordoc/models` |
|
|
299
|
+
| any other tag (`ja`, `zh-hans`, `fr`, `de`, …) | Tesseract, all configured languages at once (`kor+jpn`) | traineddata per language from the jsDelivr CDN, cached in `<workspace>/.autorag/models/tessdata` |
|
|
300
|
+
|
|
301
|
+
The built-in model has no kana, han, Cyrillic, Thai, Arabic or Devanagari
|
|
302
|
+
characters and drops diacritics in accented Latin text, so those languages need
|
|
303
|
+
Tesseract. Set `parserOptions.ocr.cachePath` to store the Tesseract models
|
|
304
|
+
elsewhere, or `KORDOC_OFFLINE=1` to block the built-in model download. An
|
|
305
|
+
explicit `parserOptions.kordoc.ocr` overrides the language-based choice.
|
|
306
|
+
|
|
307
|
+
Photos and videos are also reachable through two other paths that are not part
|
|
308
|
+
of this switch: the `clawgallery` datasource (captions and visual search over its
|
|
309
|
+
own folders) and Jikji's media index (`jikji.enableMediaIndex`, file facts such as
|
|
310
|
+
pixel size and format only, no content). Video content is not searchable yet.
|
|
286
311
|
|
|
287
312
|
### 2. Search from CLI
|
|
288
313
|
|
|
314
|
+
`autorag search` needs one chat model. `autorag init` does not pick one, so on
|
|
315
|
+
first run either sign in and choose a model inside the TUI:
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
autorag tui # then /login (OAuth or API key) and /model
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
or add the `model` entry to your existing AutoRAG config, preserving its other
|
|
322
|
+
settings. Find provider/model ids with `autorag models list --available`:
|
|
323
|
+
|
|
324
|
+
```json
|
|
325
|
+
"model": { "provider": "<provider>", "id": "<id>" }
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Then run `autorag health`. Do not re-run `autorag init --force` just to select
|
|
329
|
+
a model: it replaces the existing config, including datasource and parser settings.
|
|
330
|
+
Configure the provider's credentials through `/login` or its supported environment variables.
|
|
331
|
+
|
|
289
332
|
```bash
|
|
290
333
|
# Perform a curated search (uses your configured reasoning model)
|
|
291
334
|
autorag search "What are our primary Q3 deliverables?"
|
|
@@ -312,9 +355,6 @@ for (const result of response.results) {
|
|
|
312
355
|
console.log(`[${result.number}] ${result.title} (${result.source})`);
|
|
313
356
|
console.log(` ${result.summary}`);
|
|
314
357
|
}
|
|
315
|
-
|
|
316
|
-
// Record feedback: Result [1] was useful, [2] was not
|
|
317
|
-
agent.recordFeedbackByNumbers(response.sessionId, [1], [2]);
|
|
318
358
|
```
|
|
319
359
|
|
|
320
360
|
---
|
|
@@ -333,7 +373,7 @@ agent.recordFeedbackByNumbers(response.sessionId, [1], [2]);
|
|
|
333
373
|
| `autorag tui` | Open Pi's interactive librarian TUI (`/login`, `/model`, `/resume`, …) |
|
|
334
374
|
| `autorag duplicates [DIR]` | Read-only scan for exact and near-duplicate document families with `dupey` |
|
|
335
375
|
| `autorag lite ...` | CLI bootstrap, indexing repair, terminal maintenance, and fallback interface; agents use MCP for normal Lite operation |
|
|
336
|
-
| `autorag
|
|
376
|
+
| `autorag memory inspect` | Render a read-only, path-opaque snapshot of retrieval memory (judged evidence, curated results, evidence chunks, insights); model-free |
|
|
337
377
|
| `autorag evidence <session>` | Inspect persisted evidence behind numbered results; MCP clients normally use `autorag.evidence`, and the CLI stays available for terminal maintenance |
|
|
338
378
|
| `autorag serve` | Start the P2P query server over SimpleX (opt-in) |
|
|
339
379
|
| `autorag p2p ...` | Manage peer trust, query approvals, and sharing policies |
|
|
@@ -347,7 +387,7 @@ Deep dive into AutoRAG Agent's architecture, security, and integration guides:
|
|
|
347
387
|
- **[MinSync Setup & Embedding QA](docs/minsync-setup.md):** Automatic binary installation, CDC chunking, and EmbeddingGemma verification.
|
|
348
388
|
- **[Local Embedding Runtime & Gateway](docs/embedding-runtime.md):** AutoRAG-owned local gateway, model prefetching, and zero-egress semantic search. Model cards: [`qwen3-embedding-0.6b`](docs/model-cards/qwen3-embedding-0.6b.md), [`embeddinggemma-300m`](docs/model-cards/embeddinggemma-300m.md).
|
|
349
389
|
- **[Datasource Skills Reference](docs/datasource-skills.md):** Full configuration contracts, connection aliases, and connector options.
|
|
350
|
-
- **[Jev Decisions](docs/jev-decisions.md):** Jev query pipeline, **on by default** via OpenRouter: it routes each question to local search
|
|
390
|
+
- **[Jev Decisions](docs/jev-decisions.md):** Jev query pipeline, **on by default** via OpenRouter: it routes each question to a direct answer (intrinsic knowledge) or local search (everything needing more information; web search is left to the agent after the fast answer), splits multi-part questions into up to five parallel searches (`openrouter/qwen/qwen3.7-flash`), picks which registered datasources to search before the fast answer, and ends the run after the fast answer when that answer is complete. Also covers the `jev` judgment tool, backends (OpenRouter, TypeSafe, Vercel AI Gateway), and how to opt out.
|
|
351
391
|
- **[Manual QA & Datasource Test Harnesses](docs/manual-qa-datasources.md):** Real-world testing guides for Discord, KakaoTalk, Slack, Notion, and email.
|
|
352
392
|
- **[P2P SimpleX Sharing & Path Standard](docs/p2p-path-standard.md):** Decentralized peer query sharing with SimpleX, PII redaction, and approval queues.
|
|
353
393
|
- **[Supply Chain Security & License Audits](docs/supply-chain.md):** Software bill of materials (SBOM) and dependency gate policies.
|
|
@@ -400,7 +440,7 @@ itself through the connected Lite MCP server:
|
|
|
400
440
|
autorag.status {}
|
|
401
441
|
autorag.refresh {}
|
|
402
442
|
autorag.search {"query":"a word that certainly appears","topK":3}
|
|
403
|
-
autorag.search {"query":"recent topic","
|
|
443
|
+
autorag.search {"query":"recent topic","scope":"/discord/local/**","topK":3}
|
|
404
444
|
```
|
|
405
445
|
|
|
406
446
|
The CLI equivalents remain available for terminal repair, but do not use them
|
|
@@ -413,9 +453,10 @@ Common failures and their fix:
|
|
|
413
453
|
| Results are missing recent files | `stale-index` | `autorag refresh --method parsed,minsync --json` |
|
|
414
454
|
| Semantic search returns nothing after changing the embedder | `embedding-identity-mismatch` | `autorag index rebuild --method minsync` |
|
|
415
455
|
| Gateway will not start, a previous run was killed | `lock-conflict` | `autorag gateway stop`, then retry |
|
|
416
|
-
| A datasource is healthy in its own CLI but absent from results | — |
|
|
456
|
+
| A datasource is healthy in its own CLI but absent from results | — | confirm it is configured under `datasources` and connected through its native CLI |
|
|
417
457
|
| A datasource errors during refresh | `datasource-index-failed` | run that CLI's own `doctor` |
|
|
418
|
-
| MinSync
|
|
458
|
+
| MinSync binary missing (search and refresh fail with `MinSync is required ...`) | — | `cargo install minsync`, or leave `minSync.autoInstall` on and re-run refresh |
|
|
459
|
+
| Jikji missing | `jikji-unavailable` | check the Rust toolchain, re-run refresh |
|
|
419
460
|
| Windows file-name search fails during refresh | `everything-index-failed` | read the ES exit code and stderr in the message, then `autorag refresh --method everything --json` |
|
|
420
461
|
| Every search does a full local search and verification, even for small talk | `query-route-fallback` | set `OPENROUTER_API_KEY` (Jev routing and decomposition are on by default) |
|
|
421
462
|
|
package/dist/agent/agent.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import type { Agent, AgentTool
|
|
1
|
+
import type { Agent, AgentTool } from "@earendil-works/pi-agent-core";
|
|
2
2
|
import type { Api, Model } from "@earendil-works/pi-ai";
|
|
3
|
-
import { type DatasourceAccessContextOptions } from "../datasource/access-context.js";
|
|
4
3
|
import type { DatasourceIndexResult, DatasourceSkill } from "../datasource/types.js";
|
|
5
4
|
import { type DupeyCliOptions } from "../dupey/index.js";
|
|
5
|
+
import { type Embedder } from "../embedding-runtime/gateway-embedder.js";
|
|
6
6
|
import { type EverythingClientOptions, type EverythingSearchRequest, type EverythingSearchResult } from "../everything/index.js";
|
|
7
7
|
import { type FSearchClientOptions, type FSearchFailureReason, type FSearchSearchRequest, type FSearchSearchResult } from "../fsearch/index.js";
|
|
8
8
|
import { type JikjiFailureReason, type JikjiOptions } from "../jikji/index.js";
|
|
9
9
|
import { type LanguageTag } from "../language.js";
|
|
10
|
-
import type { ResultFeedback } from "../memory/memory.js";
|
|
11
10
|
import { type MinSyncSyncResult, type MinSyncVectorMethodOptions } from "../minsync/index.js";
|
|
12
11
|
import { type ParsedMirrorSyncResult } from "../mirror/sync.js";
|
|
13
12
|
import type { PolicyResolver } from "../p2p/policy-filter.js";
|
|
@@ -19,14 +18,15 @@ import { RetrievalEngine } from "../retrieval/engine.js";
|
|
|
19
18
|
import { RetrievalMethodRegistry } from "../retrieval/registry.js";
|
|
20
19
|
import type { DatasourceCatalogEntry } from "../retrieval/selection.js";
|
|
21
20
|
import type { CuratedResult, RetrievalDiagnostic, RetrievalOptions, RetrievalResult } from "../retrieval/types.js";
|
|
21
|
+
import { type DatasourceAgentSkill } from "./datasource-skill.js";
|
|
22
22
|
import { type ScanDuplicateDocumentsDetails } from "./dupey-tool.js";
|
|
23
23
|
import { type AutoRAGFastAnswerDetails } from "./fast-answer-tool.js";
|
|
24
24
|
import { type JevToolOptions } from "./jev-extension.js";
|
|
25
25
|
import { type JikjiFindProviderResult } from "./jikji-find-tool.js";
|
|
26
26
|
import { type AutoRAGPiInteractiveRuntime, type AutoRAGPiSession } from "./pi-session.js";
|
|
27
|
-
import { type QueryRoute } from "./query-routing.js";
|
|
28
27
|
import { type RefreshProgressCounts, type RefreshProgressPhase } from "./refresh-progress.js";
|
|
29
28
|
import { type SearchDocumentDiagnostic, type SearchDocumentsResponse, type SearchDocumentsStreamEvent } from "./search-documents.js";
|
|
29
|
+
import { type SelfConfigOptions } from "./self-config.js";
|
|
30
30
|
import { type WatcherFactory, type WatchRefreshHandle } from "./watch-refresh.js";
|
|
31
31
|
import { type WebFetchToolOptions } from "./web-fetch-tool.js";
|
|
32
32
|
import { type WebSearchToolOptions } from "./web-search-tool.js";
|
|
@@ -190,7 +190,7 @@ export interface AutoRAGAgentOptions {
|
|
|
190
190
|
memoryPath?: string;
|
|
191
191
|
workspacePath?: string;
|
|
192
192
|
tools?: AgentTool[];
|
|
193
|
-
minSync?: Omit<MinSyncVectorMethodOptions, "root"
|
|
193
|
+
minSync?: Omit<MinSyncVectorMethodOptions, "root">;
|
|
194
194
|
jikji?: JikjiOptions | false;
|
|
195
195
|
/**
|
|
196
196
|
* Windows-only instant file/folder name search through the bundled
|
|
@@ -237,8 +237,8 @@ export interface AutoRAGAgentOptions {
|
|
|
237
237
|
/**
|
|
238
238
|
* Jev (TypeSafe's judgment model: typed questions in, calibrated
|
|
239
239
|
* probabilities out). When set, the two-phase search asks Jev before the
|
|
240
|
-
* fast answer whether the question
|
|
241
|
-
* direct answer, and whether to decompose it; after the fast answer, whether
|
|
240
|
+
* fast answer whether the question is answerable from intrinsic knowledge
|
|
241
|
+
* (direct answer) or needs local search, and whether to decompose it; after the fast answer, whether
|
|
242
242
|
* verification is needed. It also exposes the `jev` tool. Always omitted for
|
|
243
243
|
* remote P2P sessions.
|
|
244
244
|
*
|
|
@@ -247,6 +247,20 @@ export interface AutoRAGAgentOptions {
|
|
|
247
247
|
* off, so library callers never make paid network calls they did not ask for.
|
|
248
248
|
*/
|
|
249
249
|
jev?: JevToolOptions | false;
|
|
250
|
+
/**
|
|
251
|
+
* Embedder used to find similar past questions in memory (semantic half of
|
|
252
|
+
* the hybrid search). Defaults to the local embedding gateway; `false` keeps
|
|
253
|
+
* memory search keyword-only.
|
|
254
|
+
*/
|
|
255
|
+
memoryEmbedder?: Embedder | false;
|
|
256
|
+
/**
|
|
257
|
+
* Agent self-configuration. When set (and Jev is on), Jev gains a `config`
|
|
258
|
+
* branch for questions about AutoRAG's own settings: the turn skips
|
|
259
|
+
* `emit_fast_answer`, receives the full `autorag-setup` skill, edits
|
|
260
|
+
* `configPath` with the pi tools, and reports through
|
|
261
|
+
* `emit_autorag_results`. Always omitted for remote P2P sessions.
|
|
262
|
+
*/
|
|
263
|
+
selfConfig?: SelfConfigOptions;
|
|
250
264
|
/**
|
|
251
265
|
* Question decomposition used by the Jev query pipeline. `model` (with its
|
|
252
266
|
* `apiKey`) is the LLM that splits one question into at most five search
|
|
@@ -266,7 +280,6 @@ export interface AutoRAGAgentOptions {
|
|
|
266
280
|
*/
|
|
267
281
|
limits?: AutoRAGRetrievalLimits;
|
|
268
282
|
datasourceSkills?: readonly DatasourceSkill[];
|
|
269
|
-
datasourceAccess?: DatasourceAccessContextOptions;
|
|
270
283
|
/** Non-fatal diagnostics from config/agent construction (e.g. skipped unknown datasources). */
|
|
271
284
|
startupDiagnostics?: readonly SearchDocumentDiagnostic[];
|
|
272
285
|
/** Maximum time a model/tool search may run before it is aborted. */
|
|
@@ -349,6 +362,8 @@ export declare class AutoRAGAgent {
|
|
|
349
362
|
private interactiveFastAnswerCallback;
|
|
350
363
|
private modelNativeSearchAuth;
|
|
351
364
|
private retrievalTrace;
|
|
365
|
+
/** Evidence every retrieval tool returned this run; emit tools resolve model-cited ids against it. */
|
|
366
|
+
private readonly evidenceLedger;
|
|
352
367
|
private preliminaryCallback;
|
|
353
368
|
/** Per-phase thinking levels of the two-phase search. */
|
|
354
369
|
private readonly fastThinkingLevel;
|
|
@@ -367,13 +382,11 @@ export declare class AutoRAGAgent {
|
|
|
367
382
|
private readonly merger;
|
|
368
383
|
private readonly reranker;
|
|
369
384
|
private readonly rerankTopN;
|
|
370
|
-
private readonly datasourceFilter;
|
|
371
385
|
private readonly minSyncMethod;
|
|
372
386
|
private readonly jikjiClient;
|
|
373
387
|
private readonly everythingClient;
|
|
374
388
|
private readonly fsearchClient;
|
|
375
389
|
private readonly datasourceSkills;
|
|
376
|
-
private readonly datasourceAccessOptions;
|
|
377
390
|
private readonly startupDiagnostics;
|
|
378
391
|
private readonly datasourceAgentSkills;
|
|
379
392
|
private readonly parserOptions;
|
|
@@ -382,8 +395,10 @@ export declare class AutoRAGAgent {
|
|
|
382
395
|
private readonly jevExtension;
|
|
383
396
|
/** Jev judge shared by the `jev` tool and the query router; undefined when disabled. */
|
|
384
397
|
private readonly jevJudge;
|
|
398
|
+
/** Self-configuration, enabled only with Jev on a local session. */
|
|
399
|
+
private readonly selfConfig;
|
|
385
400
|
private readonly queryDecompositionModel;
|
|
386
|
-
/** Web search
|
|
401
|
+
/** Web search options for the agent's `web_search` / `web_fetch` tools; undefined when web tools are off. */
|
|
387
402
|
private readonly webSearchOptions;
|
|
388
403
|
/** Routing diagnostics for the in-flight search; reset per run. */
|
|
389
404
|
private routingDiagnostics;
|
|
@@ -398,6 +413,17 @@ export declare class AutoRAGAgent {
|
|
|
398
413
|
private readonly persistPiSessions;
|
|
399
414
|
private readonly updateNotice;
|
|
400
415
|
private boundPiRuntime;
|
|
416
|
+
/** Embeds past questions for similar-question search; undefined keeps memory search keyword-only. */
|
|
417
|
+
private readonly memoryEmbedder;
|
|
418
|
+
private readonly memoryVectorPath;
|
|
419
|
+
/** Every retrieval result of the in-flight run with the query/method that surfaced it. */
|
|
420
|
+
private readonly evidenceOrigins;
|
|
421
|
+
/** Search-tool queries by tool call id, read back when the call ends. */
|
|
422
|
+
private readonly searchToolQueries;
|
|
423
|
+
/** Identifies this agent's conversation: everything judged in it is "current" memory. */
|
|
424
|
+
private readonly conversationId;
|
|
425
|
+
/** The memory context loaded for the in-flight run; cleared whenever a run starts. */
|
|
426
|
+
private memoryContextCache;
|
|
401
427
|
/** True when this agent was constructed for an untrusted remote peer. */
|
|
402
428
|
readonly remoteSession: boolean;
|
|
403
429
|
private activeRetrievalOptions;
|
|
@@ -405,7 +431,42 @@ export declare class AutoRAGAgent {
|
|
|
405
431
|
private readonly limits;
|
|
406
432
|
constructor(options: AutoRAGAgentOptions);
|
|
407
433
|
scanDuplicateDocuments(): Promise<ScanDuplicateDocumentsDetails>;
|
|
434
|
+
/**
|
|
435
|
+
* Reference memory for the current question: everything judged earlier in
|
|
436
|
+
* this conversation, up to 25 similar past questions, and matching
|
|
437
|
+
* long-term insights. Computed once per run (the datasource check and every
|
|
438
|
+
* model turn share it) so the similar-question search and its embedder call
|
|
439
|
+
* are not repeated and a fallback is reported once. Remote peers never read it.
|
|
440
|
+
*/
|
|
441
|
+
private loadMemoryContextFor;
|
|
408
442
|
private withMemoryContext;
|
|
443
|
+
/**
|
|
444
|
+
* Where evidence came from, or undefined when this run may not see it.
|
|
445
|
+
* Datasource chunks carry a virtual path rooted at the skill name
|
|
446
|
+
* (`/kakao/default/...`), but the model sometimes maps a datasource hit to a
|
|
447
|
+
* bare chunk id. The evidence method then still names the datasource
|
|
448
|
+
* (`search_datasource_kakao_work`, `datasource:kakao`, `kakao-work-lexical`):
|
|
449
|
+
* both sides collapse every non-alphanumeric to `_` exactly like generated
|
|
450
|
+
* tool names, and a datasource id that appears as a whole token attributes
|
|
451
|
+
* it; longer ids are checked first so `kakao-work` wins over `kakao`.
|
|
452
|
+
* Indexed files are absolute paths under a search path; web evidence is a URL.
|
|
453
|
+
* Memory is global (shared across workspaces and configs), so evidence from
|
|
454
|
+
* an unconfigured datasource, and evidence with no recognizable origin, is
|
|
455
|
+
* never attributed.
|
|
456
|
+
*/
|
|
457
|
+
private evidenceAttribution;
|
|
458
|
+
/** Options shared by the prompt injection and the `check_memory` tool; rebuilt on every call because datasource configuration follows live settings. */
|
|
459
|
+
private memoryContextOptions;
|
|
460
|
+
/** Remember which query and method surfaced each retrieval result, so cited evidence can be traced back. */
|
|
461
|
+
private rememberEvidenceOrigins;
|
|
462
|
+
/**
|
|
463
|
+
* After the final answer: map every cited evidence back to the search query
|
|
464
|
+
* and method that found it, ask Jev (one batched call, evidence judged in
|
|
465
|
+
* parallel) whether it really supports the answer sentence it backs, and
|
|
466
|
+
* keep only what clears the threshold. Remote peers and runs without Jev
|
|
467
|
+
* store nothing; a failed judgment stores nothing and says why.
|
|
468
|
+
*/
|
|
469
|
+
private recordJudgedEvidence;
|
|
409
470
|
private resolveSessionModel;
|
|
410
471
|
private createSearchSession;
|
|
411
472
|
private configureSearchSession;
|
|
@@ -425,10 +486,6 @@ export declare class AutoRAGAgent {
|
|
|
425
486
|
}): void;
|
|
426
487
|
stopAutoRefresh(): void;
|
|
427
488
|
private runAutoRefreshTick;
|
|
428
|
-
submitFeedback(sessionId: string | undefined, satisfied: boolean): void;
|
|
429
|
-
recordResultFeedback(feedback: ResultFeedback[]): void;
|
|
430
|
-
recordFeedbackByNumbers(sessionId: string, usefulNumbers: number[], notUsefulNumbers?: number[]): void;
|
|
431
|
-
recordFeedbackByIds(usefulFeedbackIds: readonly string[], notUsefulFeedbackIds?: readonly string[]): void;
|
|
432
489
|
getResultRegistry(sessionId?: string): ReadonlyMap<number, CuratedResult>;
|
|
433
490
|
searchDocuments(query: string, options?: RetrievalOptions): Promise<SearchDocumentsResponse>;
|
|
434
491
|
/**
|
|
@@ -438,43 +495,36 @@ export declare class AutoRAGAgent {
|
|
|
438
495
|
* stop by calling {@link abort}.
|
|
439
496
|
*/
|
|
440
497
|
searchDocumentsStream(query: string, options?: RetrievalOptions): AsyncGenerator<SearchDocumentsStreamEvent, void, void>;
|
|
441
|
-
private datasourceAccessContext;
|
|
442
498
|
/**
|
|
443
|
-
* Build the Pi agent-skill list for
|
|
444
|
-
*
|
|
445
|
-
* model
|
|
499
|
+
* Build the Pi agent-skill list for every configured datasource skill. All
|
|
500
|
+
* configured skills are model-visible; a connection is removed from the
|
|
501
|
+
* model surface by removing it from the config, not by a permission layer.
|
|
446
502
|
*/
|
|
447
|
-
private
|
|
503
|
+
private buildDatasourceAgentSkills;
|
|
448
504
|
/**
|
|
449
505
|
* Per-connection tool specs for the generated `search_datasource_<id>`
|
|
450
|
-
* tools,
|
|
451
|
-
*
|
|
452
|
-
* datasource skill; duplicate ids collapse to the first registration.
|
|
506
|
+
* tools, one per configured datasource skill; duplicate ids collapse to the
|
|
507
|
+
* first registration.
|
|
453
508
|
*/
|
|
454
509
|
private singleDatasourceToolSpecs;
|
|
455
510
|
/**
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
* entry carries only identity, capability tags, and authorized source scope
|
|
462
|
-
* strings (never credentials, config paths, or raw instance metadata).
|
|
463
|
-
* Duplicate datasource ids collapse to the first registration.
|
|
511
|
+
* Configured datasource descriptors for catalog/listing surfaces: every
|
|
512
|
+
* configured datasource is listed — including ones that expose no retrieval
|
|
513
|
+
* methods — and each entry carries only identity, capability tags, and
|
|
514
|
+
* source scope strings (never credentials, config paths, or raw instance
|
|
515
|
+
* metadata). Duplicate datasource ids collapse to the first registration.
|
|
464
516
|
*/
|
|
465
517
|
listDatasources(): DatasourceCatalogEntry[];
|
|
466
518
|
/**
|
|
467
|
-
* Opaque source scope strings for one datasource
|
|
468
|
-
*
|
|
469
|
-
* sources unfiltered (they are gated only at the tag level).
|
|
519
|
+
* Opaque source scope strings for one datasource. Sources containing a `#`
|
|
520
|
+
* fragment are invalid and skipped.
|
|
470
521
|
*/
|
|
471
|
-
private
|
|
522
|
+
private datasourceSourceScopes;
|
|
472
523
|
/**
|
|
473
|
-
* Resolve
|
|
474
|
-
* `load_datasource_skill` tool. Returns `undefined` for unknown
|
|
475
|
-
* unauthorized names — model/tool input can never widen authorization.
|
|
524
|
+
* Resolve a configured datasource agent skill by model-visible name for the
|
|
525
|
+
* `load_datasource_skill` tool. Returns `undefined` for unknown names.
|
|
476
526
|
*/
|
|
477
|
-
loadDatasourceSkill(name: string):
|
|
527
|
+
loadDatasourceSkill(name: string): DatasourceAgentSkill | undefined;
|
|
478
528
|
private indexDatasources;
|
|
479
529
|
/** Path-opaque component diagnostics for the search response. */
|
|
480
530
|
private collectComponentDiagnostics;
|
|
@@ -487,30 +537,39 @@ export declare class AutoRAGAgent {
|
|
|
487
537
|
private shouldFollowUp;
|
|
488
538
|
/**
|
|
489
539
|
* Jev query pipeline, run before the fast answer. Jev picks the branch
|
|
490
|
-
* (
|
|
540
|
+
* (direct answer or local search) and whether the question
|
|
491
541
|
* needs decomposition; a "yes" splits it into at most five search queries
|
|
492
|
-
* with the configured decomposition model (default: the session model).
|
|
493
|
-
*
|
|
494
|
-
*
|
|
542
|
+
* with the configured decomposition model (default: the session model). On
|
|
543
|
+
* the local branch, Jev also judges, per registered datasource, whether it
|
|
544
|
+
* must be searched (in parallel with decomposition). Without Jev, and on any
|
|
545
|
+
* routing failure, this is today's single local search for the original
|
|
546
|
+
* question with no datasource search.
|
|
495
547
|
*/
|
|
496
548
|
private planQuery;
|
|
497
549
|
/**
|
|
498
|
-
*
|
|
499
|
-
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
550
|
+
* Jev datasource check for the local branch: one `noul` per configured
|
|
551
|
+
* datasource that has retrieval methods, with where similar past questions
|
|
552
|
+
* were answered (from retrieval memory) in the state. Returns the ids to
|
|
553
|
+
* search with every query before the rerank; a failed check searches none.
|
|
554
|
+
*/
|
|
555
|
+
private selectSearchDatasources;
|
|
556
|
+
/**
|
|
557
|
+
* Baseline local evidence for the fast answer. Jikji, MinSync, and every
|
|
558
|
+
* Jev-selected datasource run for every search query in parallel (MinSync
|
|
559
|
+
* itself queues per workspace), the per-query hits are interleaved and
|
|
560
|
+
* deduplicated into one pool, and that pool is reranked against the
|
|
561
|
+
* original question.
|
|
502
562
|
*/
|
|
503
563
|
private prefetchInitialRetrievalContext;
|
|
504
|
-
/** Baseline web evidence for the fast answer: one web search per query, all in parallel. */
|
|
505
|
-
private prefetchWebContext;
|
|
506
564
|
/**
|
|
507
|
-
* Rerank the pre-fast-answer baseline pool — Jikji answer paths
|
|
508
|
-
* chunks — down to the configured
|
|
509
|
-
* merges every search query's
|
|
510
|
-
* per-source sizes as a single query
|
|
511
|
-
* with the query count. Returns
|
|
512
|
-
* disabled/unavailable or the pool is empty,
|
|
513
|
-
* unranked sections; a rerank failure never blocks
|
|
565
|
+
* Rerank the pre-fast-answer baseline pool — Jikji answer paths, MinSync
|
|
566
|
+
* chunks, and Jev-selected datasource chunks — down to the configured
|
|
567
|
+
* `rerank.topN`. With decomposition the pool merges every search query's
|
|
568
|
+
* hits (interleaved), capped at the same per-source sizes as a single query
|
|
569
|
+
* so the rerank request does not grow with the query count. Returns
|
|
570
|
+
* `undefined` when reranking is disabled/unavailable or the pool is empty,
|
|
571
|
+
* so the caller keeps the unranked sections; a rerank failure never blocks
|
|
572
|
+
* the fast answer.
|
|
514
573
|
*/
|
|
515
574
|
private rerankPrefetchPool;
|
|
516
575
|
/**
|
|
@@ -527,13 +586,19 @@ export declare class AutoRAGAgent {
|
|
|
527
586
|
buildDirectAnswerPrompt(query: string): string;
|
|
528
587
|
/** Discovery-tool hint naming only the registered discovery tools; empty when none. */
|
|
529
588
|
private discoveryHint;
|
|
589
|
+
/**
|
|
590
|
+
* Verification-phase nudge toward the internet. Jev no longer routes to web
|
|
591
|
+
* search, so the agent decides after the fast answer: when local evidence is
|
|
592
|
+
* missing, thin, or possibly stale, it searches the web. Empty when web tools are off.
|
|
593
|
+
*/
|
|
594
|
+
private webFallbackHint;
|
|
530
595
|
/**
|
|
531
596
|
* Verification-phase prompt for two-phase searches. The fast answer, when a
|
|
532
597
|
* consumer already received it, is embedded verbatim so the model can diff
|
|
533
598
|
* against it; the model then verifies with thinking on and finalizes with
|
|
534
599
|
* emit_autorag_results exactly once, returning only the delta.
|
|
535
600
|
*/
|
|
536
|
-
buildRefinementPrompt(query: string, options: RetrievalOptions, fastAnswer: AutoRAGFastAnswerDetails | undefined, fastAnswerDelivered: boolean
|
|
601
|
+
buildRefinementPrompt(query: string, options: RetrievalOptions, fastAnswer: AutoRAGFastAnswerDetails | undefined, fastAnswerDelivered: boolean): string;
|
|
537
602
|
buildSearchPrompt(query: string, options: RetrievalOptions, initialRetrievalContext?: string): string;
|
|
538
603
|
refresh(force?: boolean, opts?: AutoRAGRefreshOptions): Promise<AutoRAGRefreshResult>;
|
|
539
604
|
/**
|
|
@@ -571,7 +636,7 @@ export declare class AutoRAGAgent {
|
|
|
571
636
|
*/
|
|
572
637
|
private scanMirrorStaleness;
|
|
573
638
|
private exactDuplicateExclusions;
|
|
574
|
-
syncMinSync(force?: boolean): Promise<MinSyncSyncResult
|
|
639
|
+
syncMinSync(force?: boolean): Promise<MinSyncSyncResult>;
|
|
575
640
|
/** Provider for the Windows-only everything_search tool. */
|
|
576
641
|
searchEverything(request: EverythingSearchRequest): Promise<EverythingSearchResult>;
|
|
577
642
|
/**
|
|
@@ -660,10 +725,9 @@ export declare class AutoRAGAgent {
|
|
|
660
725
|
* Search one datasource connection only. Only the target connection's
|
|
661
726
|
* retrieval methods are registered with the retriever, so no other
|
|
662
727
|
* datasource CLI is spawned at all and only that connection's hits are
|
|
663
|
-
* returned.
|
|
664
|
-
* unknown or unauthorized `datasourceId` yields an empty result set.
|
|
728
|
+
* returned. An unknown `datasourceId` yields an empty result set.
|
|
665
729
|
*
|
|
666
|
-
* This backs the generated `search_datasource_<id>` tools; every
|
|
730
|
+
* This backs the generated `search_datasource_<id>` tools; every configured
|
|
667
731
|
* connection has one. Cross-datasource fan-out is
|
|
668
732
|
* {@link searchAllDocuments}, which spans every retrieval method.
|
|
669
733
|
*/
|
|
@@ -679,7 +743,7 @@ export declare class AutoRAGAgent {
|
|
|
679
743
|
/**
|
|
680
744
|
* The standalone retrieval engine for this agent's method pipeline.
|
|
681
745
|
* Built on first access using the agent's registered methods and configured
|
|
682
|
-
* datasource
|
|
746
|
+
* datasource catalog. Model-free — no agent state required.
|
|
683
747
|
*/
|
|
684
748
|
private retrievalEngine;
|
|
685
749
|
getRetrievalEngine(): RetrievalEngine;
|
|
@@ -690,7 +754,6 @@ export declare class AutoRAGAgent {
|
|
|
690
754
|
* the merged order is preserved — a reranker outage never hides evidence.
|
|
691
755
|
*/
|
|
692
756
|
private applyRerank;
|
|
693
|
-
private rerankWithMemory;
|
|
694
757
|
private remoteFilteredRetrievalMethod;
|
|
695
758
|
private normalizeRetrievalOptions;
|
|
696
759
|
private resolveRetrievalScope;
|
|
@@ -10,6 +10,29 @@ export declare function stripUnresolvedCitations(answer: string, results: readon
|
|
|
10
10
|
readonly unresolved: readonly number[];
|
|
11
11
|
};
|
|
12
12
|
export declare function formatCitationList(numbers: readonly number[]): string;
|
|
13
|
+
/**
|
|
14
|
+
* Throw a corrective error when two results share a number. A repeated number
|
|
15
|
+
* collapses into one registry entry and one feedback id, so the other result's
|
|
16
|
+
* evidence would be lost. Emit tools call this at tool time so the model sees
|
|
17
|
+
* the error and re-emits.
|
|
18
|
+
*/
|
|
19
|
+
export declare function assertUniqueResultNumbers(label: string, results: readonly {
|
|
20
|
+
readonly number: number;
|
|
21
|
+
}[]): void;
|
|
22
|
+
/**
|
|
23
|
+
* Throw a corrective error unless `results` and `mapping` carry the same
|
|
24
|
+
* numbers, exactly one entry each. Duplicates are rejected even when both
|
|
25
|
+
* sides repeat them: a repeated number collapses into a single registry entry,
|
|
26
|
+
* so the other entry's evidence would be lost.
|
|
27
|
+
* Emit tools call this at tool time (issue #1807) so the model sees the error
|
|
28
|
+
* and re-emits; checking only after the run ended failed the whole search and
|
|
29
|
+
* discarded an already-delivered answer.
|
|
30
|
+
*/
|
|
31
|
+
export declare function assertResultsMappingOneToOne(label: string, results: readonly {
|
|
32
|
+
readonly number: number;
|
|
33
|
+
}[], mapping: readonly {
|
|
34
|
+
readonly number: number;
|
|
35
|
+
}[]): void;
|
|
13
36
|
/**
|
|
14
37
|
* Throw a corrective error when `answer` cites numbers absent from `results`.
|
|
15
38
|
* Emit tools surface the message to the model as a tool error so it re-emits
|