@autorag/librarian 2.2.0 → 2.3.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.
Files changed (50) hide show
  1. package/README.md +84 -42
  2. package/dist/agent/agent.d.ts +16 -41
  3. package/dist/agent/bash-tool.d.ts +0 -11
  4. package/dist/agent/dupey-tool.d.ts +15 -0
  5. package/dist/agent/emit-results-tool.d.ts +14 -0
  6. package/dist/agent/index.d.ts +1 -0
  7. package/dist/agent/local-model.d.ts +12 -0
  8. package/dist/agent/search-documents.d.ts +1 -1
  9. package/dist/agent/system-prompt.d.ts +1 -2
  10. package/dist/cli/commands/duplicates.d.ts +4 -0
  11. package/dist/cli/commands/health.d.ts +9 -65
  12. package/dist/cli/commands/init.d.ts +1 -1
  13. package/dist/cli/commands/search.d.ts +2 -2
  14. package/dist/cli/config.d.ts +10 -14
  15. package/dist/cli/index.js +10383 -11845
  16. package/dist/datasource/aliased-skill.d.ts +28 -0
  17. package/dist/datasource/chunk-store.d.ts +2 -0
  18. package/dist/datasource/connector-skill.d.ts +3 -0
  19. package/dist/datasource/connector.d.ts +4 -0
  20. package/dist/datasource/crawler-skill.d.ts +6 -0
  21. package/dist/datasource/index.d.ts +2 -0
  22. package/dist/datasource/skills/cloud-drive/index.d.ts +1 -0
  23. package/dist/datasource/skills/cloud-drive/skill.d.ts +14 -0
  24. package/dist/datasource/skills/discrawl/skill.d.ts +3 -0
  25. package/dist/datasource/skills/factory.d.ts +7 -0
  26. package/dist/datasource/skills/gdrive/rclone-connector.d.ts +16 -24
  27. package/dist/datasource/skills/obsidian/skill.d.ts +1 -0
  28. package/dist/dupey/cli.d.ts +40 -0
  29. package/dist/dupey/filter.d.ts +8 -0
  30. package/dist/dupey/index.d.ts +2 -0
  31. package/dist/index.d.ts +1 -0
  32. package/dist/index.js +5063 -6881
  33. package/dist/memory/check-memory-tool.d.ts +1 -0
  34. package/dist/memory/index.d.ts +2 -2
  35. package/dist/memory/memory.d.ts +33 -3
  36. package/dist/memory/renderer.d.ts +2 -1
  37. package/dist/mirror/sync.d.ts +3 -1
  38. package/dist/observability/run-log.d.ts +1 -26
  39. package/dist/process/portable-spawn.d.ts +10 -0
  40. package/package.json +5 -4
  41. package/skills/autorag/SKILL.md +59 -96
  42. package/skills/autorag-setup/SKILL.md +144 -400
  43. package/dist/subagents/contracts.d.ts +0 -90
  44. package/dist/subagents/dispatch-templates.d.ts +0 -104
  45. package/dist/subagents/dispatch-validation.d.ts +0 -169
  46. package/dist/subagents/explorer-tools-extension.d.ts +0 -4
  47. package/dist/subagents/explorer-tools-extension.js +0 -130
  48. package/dist/subagents/local-models.d.ts +0 -14
  49. package/dist/subagents/model-policy.d.ts +0 -31
  50. package/dist/subagents/runtime.d.ts +0 -52
package/README.md CHANGED
@@ -10,7 +10,11 @@
10
10
 
11
11
  AutoRAG searches your PDFs, wikis, notes, research papers, and knowledge bases — then curates the results into clean, numbered knowledge units. No raw grep dumps. Just answers.
12
12
 
13
- AutoRAG is a customized [Pi](https://github.com/earendil-works/pi-mono) agent — the Pi agent loop configured into a librarian. Searches use a two-tier workflow: a parent orchestrator delegates exploration to explorer agents. The roles and providers are independently configured from the models available in the user's authenticated runtime; AutoRAG does not ship a private provider default.
13
+ AutoRAG is a customized [Pi](https://github.com/earendil-works/pi-mono) agent — the Pi agent loop configured into a librarian. The AutoRAG librarian retrieves candidates, reads source files directly, judges the evidence, and curates the structured answer. Its model and provider come from the user's authenticated runtime; AutoRAG does not ship a private provider default.
14
+
15
+ AutoRAG itself is the specialized search agent, not a coordinator for other
16
+ model roles. You configure one model, and that model owns the complete
17
+ retrieval, reading, judgment, and curation loop.
14
18
 
15
19
  ## Why AutoRAG
16
20
 
@@ -61,31 +65,19 @@ Different documents need different search strategies:
61
65
  | Legal documents, specifications | BM25 (keyword ranking) | Handles domain terminology well |
62
66
  | Mixed collections | Hybrid (vector + BM25) | Combines precision and recall |
63
67
 
64
- AutoRAG supports **pluggable retrieval methods**. It ships with lexical **BM25** and semantic **MinSync** methods wired through the `RetrievalMethodRegistry`, and the architecture is ready for additional vector and hybrid backends. The parent orchestrator owns process-bound retrieval tools and gives bounded seed packs to explorers; explorers use read-only `read`/`grep`/`find`/`ls` tools to inspect the underlying documents. The `ResultMerger` handles cross-method score normalization and deduplication — you get one unified result set regardless of how many methods contributed.
68
+ AutoRAG supports **pluggable retrieval methods**. It ships with lexical **BM25** and semantic **MinSync** methods wired through the `RetrievalMethodRegistry`, and the architecture is ready for additional vector and hybrid backends. The librarian invokes retrieval tools, reads the underlying documents directly through `bash`, and curates one unified result set after `ResultMerger` score normalization and deduplication.
65
69
 
66
70
  BM25 and MinSync are **enabled by default** — no explicit configuration is needed for standard lexical + semantic retrieval. Both can be disabled by setting `"bm25": false` or `"minSync": false` in the config file. MinSync uses a pre-installed binary (`autoInstall: false`); configure `minSync.embedder` via `autorag init --embedder-*` flags for remote embedding endpoints. AutoRAG never forces TEI or any external embedding service.
67
71
 
68
72
  ### Real directory access
69
73
 
70
- AutoRAG reads configured source directories through delegated explorer tasks. Each explorer is assigned exactly one normalized configured search root as its `cwd`; the top-level `subagent` invocation sets `agentScope: "user"` and `artifacts: false` exactly once for single, `tasks`, `chain`, or `parallel` dispatch, and nested explorer task items omit both fields. Project-local `.pi-subagents` debug artifacts are disabled. Explorers use read-only `read`/`grep`/`find`/`ls`; the parent orchestrator owns retrieval seed tools and must delegate document reading before curating. Curated answers are returned as a structured `SearchDocumentsResponse`; results carry their real source (file path or datasource id) in the internal mapping for feedback and curation. BM25 and MinSync index parsed markdown mirrors under `.autorag`.
71
-
72
- Each explorer `task` contains an Assignment V1 block — a sentinel-wrapped JSON body with `originalQuery` (the caller query verbatim), `method` (the selected retrieval path), and `queryVariants` (a nonempty array), followed by canonical role lines requiring `retrievedAt` and temporal metadata:
73
-
74
- ```text
75
- <<<AUTORAG_ASSIGNMENT_V1>>>
76
- {"originalQuery":"<caller query verbatim>","method":"<selected retrieval method>","queryVariants":["<variant 1>","<variant 2>"]}
77
- <<<END_AUTORAG_ASSIGNMENT_V1>>>
78
- Required handoff: include retrievedAt.
79
- Required handoff: include temporal metadata.
80
- ```
81
-
82
- A legacy labeled format (`Original query:`, `Selected retrieval method:`, `Query variants:`) is accepted for compatibility. Missing or null top-level `artifacts`, `agentScope`, and leaf `model` fields are safely autofilled before validation; explicit wrong values (`artifacts: true`, `agentScope: "project"`, a non-configured model) remain rejected. There is no single-agent fallback. See [docs/subagent-orchestration.md](docs/subagent-orchestration.md) for the full dispatch contract, templates, anti-examples, and stable coded dispatch errors.
74
+ AutoRAG reads configured source directories directly through its built-in `bash` tool. Retrieval tools can supply candidate paths, but the same agent opens the source material before curating. Answers are returned as a structured `SearchDocumentsResponse`; results carry their real source (file path or datasource id) in the internal mapping for feedback and curation. BM25 and MinSync index parsed markdown mirrors under `.autorag`.
83
75
 
84
76
  ### Optional Jikji discovery and indexing
85
77
 
86
78
  AutoRAG can opt into [Jikji](https://github.com/NomaDamas/jikji) as a local CLI-backed **find-first discovery and indexing** layer. Jikji is optional: AutoRAG does not vendor it, install it, or register it as a retrieval backend when enabled.
87
79
 
88
- When Jikji is configured, AutoRAG calls `jikji find ROOT "query" --json` via a policy-aware `jikji_find` tool as the first local-discovery action. The tool parses and validates the upstream answer-pack and honors its `handoff_action` (`direct_use` / `jikji_retry` / `raw_fallback_after_retry`), `tool_call_policy` (`stop_after_find`, `forbidden_tools`, `allowed_followups`), and `agent_should_not_rerank`. Explorer `read`/`grep`/`find`/`ls` discovery is the fallback only when the answer-pack permits raw fallback (`raw_fallback_after_retry`, after the required retry) or when Jikji is unavailable/unconfigured. `prepare`/`refresh` remain for indexing only and do not answer queries directly.
80
+ When Jikji is configured, AutoRAG calls `jikji find ROOT "query" --json` via the `jikji_find` tool. The tool parses and validates the upstream answer pack and exposes its `handoff_action`, `tool_call_policy`, and `agent_should_not_rerank` to the librarian. Direct file reading remains available for source verification. `prepare`/`refresh` remain for indexing only and do not answer queries directly.
89
81
 
90
82
  Programmatic use:
91
83
 
@@ -97,6 +89,35 @@ const agent = new AutoRAGAgent({
97
89
  await agent.prepareJikji();
98
90
  ```
99
91
 
92
+ ### Duplicate document management with dupey
93
+
94
+ AutoRAG can use the external [`dupey`](https://github.com/NomaDamas/dupey) CLI
95
+ to detect exact, near, and containment document families.
96
+
97
+ ```bash
98
+ autorag duplicates /path/to/documents
99
+ autorag duplicates --json
100
+ ```
101
+
102
+ The command is read-only: it reports exact duplicate groups and review
103
+ guidance, but never moves or deletes source files. The `scan_duplicate_documents`
104
+ Agent tool exposes the same read-only scan to the orchestrator.
105
+
106
+ Exact duplicate exclusion is enabled by default during parsed-mirror refresh.
107
+ For each exact canonical-text hash, the newest filesystem copy is indexed and
108
+ older copies are omitted. Disable it in `config.json` when both copies must be
109
+ searchable:
110
+
111
+ ```json
112
+ {
113
+ "dupey": { "enabled": true },
114
+ "excludeExactDuplicates": false
115
+ }
116
+ ```
117
+
118
+ If `dupey` is not installed or fails, refresh continues without exclusion and
119
+ reports no destructive action; install it with `cargo install dupey`.
120
+
100
121
  The same `.autorag/jikji.json` shape configures Jikji when present:
101
122
 
102
123
  ```json
@@ -122,6 +143,14 @@ The upstream Rust `PrepareArgs` defines reference defaults that AutoRAG does not
122
143
 
123
144
  Datasource skills let AutoRAG search external, server-configured data sources through the same retrieval pipeline as local documents. A skill describes what it indexes, how it should be refreshed, what source instances exist, and which permission tags/scopes bound access. Retrieval still flows through `RetrievalMethodRegistry` → `ParallelRetriever` → datasource result filtering → `ResultMerger`; datasource skills do not create a parallel search path.
124
145
 
146
+ Every datasource can be registered multiple times through a connection alias:
147
+ use the config key as the unique name and set `type` to the reusable backend
148
+ (`gmail`, `github`, `slack`, `discord`, `kakao`, `cloud-drive`, and so on).
149
+ Each alias becomes an independently loadable agent skill with its own source
150
+ scope and workspace namespace. Chat aliases search all channels by default;
151
+ trusted `channels.ids` / `channels.names` allowlists can expose a particular
152
+ channel or group chat as its own datasource.
153
+
125
154
  Security defaults are intentionally strict:
126
155
 
127
156
  - datasource access is default-deny unless trusted server/API configuration supplies `datasourceAccess.allowedTags` and `datasourceAccess.allowedScopes`;
@@ -139,7 +168,7 @@ Security defaults are intentionally strict:
139
168
  | Discord | `discord` | external [`discrawl`](https://github.com/openclaw/discrawl) CLI | guild/channel/thread/DM archive; FTS5 + semantic + hybrid retrieval, incremental sync |
140
169
  | Notion | `notion` | external [`notcrawl`](https://github.com/openclaw/notcrawl) CLI | local-first page/database/block archive + FTS5 search |
141
170
  | GitHub Issues/PRs | `github` | GitHub REST (token optional) | issues + PR bodies per `owner/repo`; public repos work unauthenticated |
142
- | Google Drive | `gdrive` | Drive REST v3, or **[`rclone`](https://rclone.org) CLI** (`backend: "rclone"`) | Docs/Sheets exported as text; the rclone backend also opens any of rclone's 70+ remotes |
171
+ | Cloud drives | `cloud-drive` | **[`rclone`](https://rclone.org) CLI** | Incremental Google Drive Tier-1; OneDrive/network remotes; iCloud experimental |
143
172
  | Gmail / IMAP | `gmail` | Gmail REST v1, or **[`himalaya`](https://pimalaya.org) CLI** (`backend: "himalaya"`) | the himalaya backend indexes any IMAP/Maildir account it has configured — no OAuth plumbing |
144
173
  | Local mail exports | `mail-export` | filesystem (`.mbox` / `.eml`) | classic `From_` splitting, mailparser-based; count-only warnings |
145
174
  | Obsidian vault | `obsidian` | external [`qmd`](https://github.com/tobi/qmd) CLI | incremental `qmd update`, BM25 `qmd search`, semantic `qmd vsearch`; vault path via `connector.vaultPath` |
@@ -158,13 +187,14 @@ Configure them in `config.json` (CLI) or pass `datasourceSkills` programmaticall
158
187
  "notion": { "connector": { "binaryPath": "notcrawl", "configPath": "/path/to/notcrawl.yaml" } },
159
188
  "github": { "connector": { "repos": ["owner/repo"] } },
160
189
  "gmail": { "connector": { "backend": "himalaya", "account": "gmail", "folder": "INBOX" } },
161
- "gdrive": { "connector": { "backend": "rclone", "remote": "gdrive:" } },
190
+ "personal-google-drive": { "type": "cloud-drive", "instanceId": "personal", "connector": { "provider": "google-drive", "remote": "personal-gdrive:", "include": ["**/*.md"] } },
191
+ "company-onedrive": { "type": "cloud-drive", "instanceId": "work", "connector": { "provider": "onedrive", "remote": "company-onedrive:Documents" } },
162
192
  "obsidian": { "connector": { "vaultPath": "/path/to/vault" } },
163
193
  "rss": { "connector": { "feeds": [{ "url": "https://example.com/feed.xml" }] } }
164
194
  },
165
195
  "datasourceAccess": {
166
- "allowedTags": ["whatsapp", "telegram", "slack", "notion", "github", "gmail", "gdrive", "obsidian", "rss"],
167
- "allowedScopes": ["/whatsapp/**", "/telegram/**", "/slack/**", "/notion/**", "/github/**", "/gmail/**", "/gdrive/**", "/obsidian/**", "/rss/**"]
196
+ "allowedTags": ["whatsapp", "telegram", "slack", "notion", "github", "gmail", "cloud-drive", "obsidian", "rss"],
197
+ "allowedScopes": ["/whatsapp/**", "/telegram/**", "/slack/**", "/notion/**", "/github/**", "/gmail/**", "/personal-google-drive/**", "/company-onedrive/**", "/obsidian/**", "/rss/**"]
168
198
  }
169
199
  }
170
200
  ```
@@ -177,6 +207,21 @@ Install slacrawl with `brew install openclaw/tap/slacrawl`. AutoRAG invokes `sla
177
207
 
178
208
  Install notcrawl with `brew install openclaw/tap/notcrawl`. AutoRAG invokes `notcrawl sync` during datasource refresh and `notcrawl search --json` during retrieval. Optional trusted connector fields are `binaryPath` and `configPath`. Notion credentials and workspace definitions remain in notcrawl's own configuration rather than AutoRAG.
179
209
 
210
+ Install and authenticate rclone separately (`brew install rclone && rclone
211
+ config` on macOS), then configure the provider-neutral `cloud-drive` skill.
212
+ `cloud-drive` is a reusable `type`: each datasource config key is a connection
213
+ alias and becomes a separate agent skill and scope. Multiple Google accounts,
214
+ or Google Drive plus OneDrive/iCloud, can therefore be loaded and searched
215
+ independently.
216
+ AutoRAG inventories with `rclone lsjson`, keeps a workspace-local manifest and
217
+ managed mirror, and downloads only added or changed indexable files. Google
218
+ Drive is Tier-1. OneDrive, Dropbox, SMB/SFTP/WebDAV, and mounted drives share
219
+ the same manifest contract. iCloud Drive is experimental because rclone marks
220
+ that backend Tier 4 and Apple ID/2FA sessions periodically require
221
+ reauthentication. See [docs/datasource-skills.md](docs/datasource-skills.md)
222
+ for filtering, size, concurrency, bandwidth, dry-run, and agent tool-calling
223
+ details.
224
+
180
225
  #### KakaoTalk (katok)
181
226
 
182
227
  KakaoTalk was the first datasource skill. It uses the external [`katok`](https://github.com/NomaDamas/katok) CLI only — AutoRAG never reads KakaoTalk databases directly. `katok` failures return diagnostics instead of throwing, and remote embedding egress configuration is rejected before the CLI is spawned.
@@ -260,7 +305,7 @@ A datasource skill should provide polling/cron metadata for routine indexing, so
260
305
 
261
306
  AutoRAG is built for **non-code document retrieval**: manuals, legal docs, internal wikis, meeting notes, research literature, knowledge bases, PDFs.
262
307
 
263
- Code repositories work too (the explorer's `grep` is useful), but AutoRAG's real value shows on unstructured text where simple pattern matching isn't enough.
308
+ Code repositories work too (direct `grep` is useful), but AutoRAG's real value shows on unstructured text where simple pattern matching isn't enough.
264
309
 
265
310
  ## Configuration and state
266
311
 
@@ -270,38 +315,39 @@ The default home state is kept outside the workspace:
270
315
  ~/.autorag/
271
316
  ├── config.json
272
317
  ├── memory.json
273
- ├── logs/
274
- │ └── runs.jsonl
275
- └── pi-agent/
276
- ├── auth.json
277
- ├── models.json
278
- ├── settings.json
279
- └── sessions/
318
+ └── logs/
319
+ └── runs.jsonl
280
320
  ```
281
321
 
282
- `config.json` selects sources, the workspace, memory path, retrieval settings, and the two agent models. Configure the roles independently with `agents.orchestrator` and `agents.explorer`. Provider and model IDs must refer to models available in the user's authenticated runtime:
322
+ `config.json` selects sources, the workspace, memory path, retrieval settings, and the agent model. Provider and model IDs must refer to a model available in the user's authenticated runtime:
283
323
 
284
324
  ```json
285
325
  {
286
326
  "searchPaths": ["/path/to/documents"],
287
327
  "workspacePath": "/path/to/workspace",
288
328
  "memoryPath": "/Users/you/.autorag/memory.json",
289
- "agents": {
290
- "orchestrator": { "provider": "provider-name", "id": "reasoning-model" },
291
- "explorer": { "provider": "provider-name", "id": "exploration-model" }
292
- }
329
+ "model": { "provider": "provider-name", "id": "reasoning-model" }
293
330
  }
294
331
  ```
295
332
 
296
- `autorag init` leaves `agents` unset when no role-model flags are supplied. At search time AutoRAG resolves an authenticated local provider when possible; otherwise configure both roles explicitly.
333
+ `autorag init` leaves `model` unset when no model flags are supplied. At search time AutoRAG resolves an authenticated local provider when possible; otherwise configure the model explicitly.
334
+
335
+ For fast interactive search, prefer a model with reliable tool calling, high
336
+ output TPS, and low first-token latency. A query can require several short
337
+ model turns while AutoRAG alternates between retrieval tools and direct source
338
+ reading, so model throughput has a visible effect on end-to-end response time.
339
+ It does not accelerate BM25, MinSync, Jikji, filesystem access, or indexing
340
+ itself. Larger reasoning models remain useful for difficult synthesis,
341
+ conflicting evidence, and specialized domain judgment, but they are not a
342
+ requirement for ordinary retrieval.
297
343
 
298
344
  Config path precedence is `--config` > `AUTORAG_CONFIG` > `~/.autorag/config.json`. When the home config is absent and `<cwd>/autorag.config.json` exists, AutoRAG copies the legacy file to `~/.autorag/config.json` without deleting or modifying the legacy file. The legacy cwd file is a migration source, not the default location.
299
345
 
300
- `memory.json` stores retrieval memory, `logs/runs.jsonl` records run events, and durable Pi models, settings, and sessions stay under `~/.autorag/pi-agent`. Corpus indexes remain workspace-local: refresh keeps parsed mirrors and BM25/MinSync indexes under `<workspace>/.autorag`.
346
+ `memory.json` stores retrieval memory and `logs/runs.jsonl` records run events. Model authentication remains with the user's configured provider or authenticated local runtime. Corpus indexes remain workspace-local: refresh keeps parsed mirrors and BM25/MinSync indexes under `<workspace>/.autorag`.
301
347
 
302
348
  `autorag refresh` and `autorag index reset|rebuild` accept `--method <csv>` (e.g. `--method bm25,minsync,parsed`) to scope which indexing methods run or which index directories are removed. When omitted, all methods run. `autorag init` accepts `--embedder-*` flags to configure the MinSync embedder endpoint in the config file.
303
349
 
304
- `autorag health` checks model/provider auth and explorer subagent setup before a search — it resolves both role models, verifies credential presence, and optionally probes a completion call per role. Use it to diagnose model, provider, auth, timeout, or subagent dispatch failures. `autorag status` remains the model-free index-health command (corpus freshness and BM25/MinSync readiness); it does not check models or subagent dispatch. When `autorag search` fails for a model/provider/subagent reason, the error output includes a hint pointing to `autorag health`.
350
+ `autorag health` checks model/provider auth before a search — it resolves the model, verifies credential presence, and optionally probes one completion call. Use it to diagnose model, provider, auth, or timeout failures. `autorag status` remains the model-free index-health command (corpus freshness and BM25/MinSync readiness). When `autorag search` fails for a model/provider reason, the error output includes a hint pointing to `autorag health`.
305
351
 
306
352
  ## Installation
307
353
 
@@ -345,15 +391,11 @@ agent.recordFeedbackByNumbers(response.sessionId, [1, 3], [2]);
345
391
  │
346
392
  ▼
347
393
  ┌──────────────┐
348
- │ Plan + seed │ ← parent check_memory, Jikji, and retrieval tools
349
- └──────┬───────┘
350
- ▼
351
- ┌──────────────┐
352
- │ Delegate │ ← pi-subagents → gpt-5.6-luna explorer
394
+ │ Plan + search│ ← check_memory, Jikji, and retrieval tools
353
395
  └──────┬───────┘
354
396
  ▼
355
397
  ┌──────────────┐
356
- │ Search + read│ ← explorer read/grep/find/ls
398
+ │ Direct read │ ← bash find/grep/cat
357
399
  └──────┬──────┘
358
400
  ▼
359
401
  ┌─────────────┐
@@ -2,6 +2,7 @@ import { Agent, type AgentTool, type Skill } from "@earendil-works/pi-agent-core
2
2
  import type { Api, Model } from "@earendil-works/pi-ai";
3
3
  import { type DatasourceAccessContextOptions } from "../datasource/access-context.js";
4
4
  import type { DatasourceIndexResult, DatasourceSkill } from "../datasource/types.js";
5
+ import { type DupeyCliOptions } from "../dupey/index.js";
5
6
  import { type JikjiFailureReason, type JikjiOptions } from "../jikji/index.js";
6
7
  import type { ResultFeedback } from "../memory/memory.js";
7
8
  import { type MinSyncSyncResult, type MinSyncVectorMethodOptions } from "../minsync/index.js";
@@ -10,7 +11,7 @@ import type { DefaultParserRegistryOptions } from "../parser/index.js";
10
11
  import { type BM25MethodOptions, type BM25SyncResult } from "../retrieval/methods/bm25.js";
11
12
  import { RetrievalMethodRegistry } from "../retrieval/registry.js";
12
13
  import type { CuratedResult, RetrievalDiagnostic, RetrievalOptions, RetrievalResult } from "../retrieval/types.js";
13
- import { type MandatorySubagentSessionOptions } from "../subagents/runtime.js";
14
+ import { type ScanDuplicateDocumentsDetails } from "./dupey-tool.js";
14
15
  import { type JikjiFindProviderResult } from "./jikji-find-tool.js";
15
16
  import { type SearchDocumentDiagnostic, type SearchDocumentsResponse } from "./search-documents.js";
16
17
  import { type WatcherFactory, type WatchRefreshHandle } from "./watch-refresh.js";
@@ -68,7 +69,6 @@ export interface AutoRAGWatchRefreshOptions {
68
69
  export type AutoRAGWatchRefreshHandle = WatchRefreshHandle;
69
70
  export interface AutoRAGAgentOptions {
70
71
  model?: Model<Api>;
71
- explorerModel?: Model<Api>;
72
72
  apiKey?: string;
73
73
  providerApiKeys?: Readonly<Record<string, string>>;
74
74
  searchPaths: string[];
@@ -81,9 +81,10 @@ export interface AutoRAGAgentOptions {
81
81
  jikji?: JikjiOptions;
82
82
  autoRefresh?: AutoRefreshOptions;
83
83
  parserOptions?: DefaultParserRegistryOptions;
84
+ dupey?: DupeyCliOptions | false;
85
+ excludeExactDuplicates?: boolean;
84
86
  datasourceSkills?: readonly DatasourceSkill[];
85
87
  datasourceAccess?: DatasourceAccessContextOptions;
86
- sessionFactory?: AutoRAGSessionFactory;
87
88
  }
88
89
  export interface AutoRAGSearchSession {
89
90
  readonly agent: Agent;
@@ -91,7 +92,6 @@ export interface AutoRAGSearchSession {
91
92
  abort(): Promise<void> | void;
92
93
  dispose(): void;
93
94
  }
94
- export type AutoRAGSessionFactory = (options: MandatorySubagentSessionOptions) => Promise<AutoRAGSearchSession>;
95
95
  export type AutoRAGJikjiPrepareResult = {
96
96
  readonly ok: true;
97
97
  readonly code: number;
@@ -106,17 +106,10 @@ export declare class AutoRAGAgent {
106
106
  private readonly innerAgent;
107
107
  private readonly tools;
108
108
  private readonly configuredModel;
109
- private readonly configuredExplorerModel;
110
109
  private readonly apiKey;
111
110
  private readonly providerApiKeys;
112
- private readonly sessionFactory;
113
111
  private readonly listeners;
114
112
  private activeSession;
115
- private readonly pendingSubagentCalls;
116
- private readonly dispatchSequenceBySession;
117
- private readonly dispatchArgsTracker;
118
- private dispatchSyntheticCounter;
119
- private successfulExplorerCalls;
120
113
  private readonly memory;
121
114
  private readonly runLogger;
122
115
  private lastQuery;
@@ -131,7 +124,6 @@ export declare class AutoRAGAgent {
131
124
  private readonly configuredSearchPaths;
132
125
  private retrievalScopeBindings;
133
126
  private readonly datasourceVirtualScopePrefixes;
134
- private readonly allowedExplorerRoots;
135
127
  private readonly workspaceProjectRoot;
136
128
  private readonly methodRegistry;
137
129
  private readonly retriever;
@@ -144,23 +136,17 @@ export declare class AutoRAGAgent {
144
136
  private readonly datasourceAccessOptions;
145
137
  private readonly datasourceAgentSkills;
146
138
  private readonly parserOptions;
139
+ private readonly dupeyOptions;
140
+ private readonly excludeExactDuplicates;
147
141
  private readonly baseSystemPromptConfig;
148
- /** Run-scoped merged Jikji policy, set during searchDocuments; cleared after. */
149
- private activeJikjiPolicy;
150
- private activeExplorerModel;
151
- /** Run-scoped jikji_find call count for the two-phase raw-fallback gate. */
152
- private jikjiFindCallCount;
153
142
  private readonly droppedCallerToolNames;
154
143
  constructor(options: AutoRAGAgentOptions);
144
+ scanDuplicateDocuments(): Promise<ScanDuplicateDocumentsDetails>;
155
145
  private withMemoryContext;
156
146
  private resolveSessionModel;
147
+ private createSearchSession;
157
148
  private configureSearchSession;
158
149
  private recordSearchToolEvent;
159
- private nextDispatchSequence;
160
- private resolveToolCallId;
161
- private emitDispatchAutofilled;
162
- private emitDispatchRejected;
163
- private emitDispatchRejectedFromRejection;
164
150
  private currentSystemPromptConfig;
165
151
  subscribe(listener: Parameters<Agent["subscribe"]>[0]): () => void;
166
152
  abort(): void;
@@ -177,6 +163,7 @@ export declare class AutoRAGAgent {
177
163
  submitFeedback(sessionId: string | undefined, satisfied: boolean): void;
178
164
  recordResultFeedback(feedback: ResultFeedback[]): void;
179
165
  recordFeedbackByNumbers(sessionId: string, usefulNumbers: number[], notUsefulNumbers?: number[]): void;
166
+ recordFeedbackByIds(usefulFeedbackIds: readonly string[], notUsefulFeedbackIds?: readonly string[]): void;
180
167
  getResultRegistry(sessionId?: string): ReadonlyMap<number, CuratedResult>;
181
168
  searchDocuments(query: string, options?: RetrievalOptions): Promise<SearchDocumentsResponse>;
182
169
  private datasourceAccessContext;
@@ -195,7 +182,7 @@ export declare class AutoRAGAgent {
195
182
  private indexDatasources;
196
183
  /** Path-opaque component diagnostics (e.g. BM25 readiness) for the search response. */
197
184
  private collectComponentDiagnostics;
198
- buildSearchPrompt(query: string, options: RetrievalOptions, explorerModel?: string): string;
185
+ buildSearchPrompt(query: string, options: RetrievalOptions): string;
199
186
  refresh(force?: boolean, opts?: AutoRAGRefreshOptions): Promise<AutoRAGRefreshResult>;
200
187
  /**
201
188
  * Path-opaque snapshot of corpus freshness and the last refresh outcome. Runs
@@ -221,6 +208,7 @@ export declare class AutoRAGAgent {
221
208
  * so the refresh result and status remain consistent.
222
209
  */
223
210
  private scanMirrorStaleness;
211
+ private exactDuplicateExclusions;
224
212
  syncBM25(): Promise<BM25SyncResult | undefined>;
225
213
  syncMinSync(): Promise<MinSyncSyncResult | undefined>;
226
214
  prepareJikji(): Promise<readonly AutoRAGJikjiPrepareResult[] | undefined>;
@@ -229,12 +217,9 @@ export declare class AutoRAGAgent {
229
217
  /**
230
218
  * Provider method for the jikji_find tool. Runs JikjiClient.find over all
231
219
  * configured search roots, normalizes answer paths against planned source
232
- * roots, merges per-root answer packs using least-privilege (restrictive-
233
- * wins) semantics, and sets the run-scoped activeJikjiPolicy. Only mutates
234
- * run state (activeJikjiPolicy / jikjiFindCallCount) when a searchDocuments
235
- * run is active; direct out-of-run calls compute and return the result
236
- * without persisting. When jikji is unavailable or all roots fail, returns
237
- * an unavailable result and leaves the policy undefined (bash is allowed).
220
+ * roots, and merges per-root answer packs using least-privilege
221
+ * (restrictive-wins) semantics. Jikji policy metadata remains visible to the
222
+ * model, but it does not gate the librarian's direct file-reading tools.
238
223
  */
239
224
  findJikji(query: string, opts?: {
240
225
  readonly topK?: number;
@@ -253,20 +238,9 @@ export declare class AutoRAGAgent {
253
238
  * - stopAfterFind: OR
254
239
  * - agentShouldNotRerank: OR
255
240
  * - handoffAction: MOST RESTRICTIVE (direct_use < jikji_retry < raw_fallback_after_retry)
256
- * - rawFallbackAllowed: handoffAction===raw_fallback_after_retry AND callCount>=2
241
+ * - rawFallbackAllowed: handoffAction===raw_fallback_after_retry
257
242
  */
258
243
  private mergePolicy;
259
- /**
260
- * Deny-by-default bash gate. When jikji is configured but no jikji_find has
261
- * run yet this run (count===0), bash is blocked so the agent discovers local
262
- * files via jikji_find first. After a find, the run-scoped activeJikjiPolicy
263
- * applies: when no policy is active, bash behaves exactly as before
264
- * (allowed). Under an active policy, bash is denied unless handoffAction is
265
- * raw_fallback_after_retry AND rawFallbackAllowed is true (after a second
266
- * jikji_find). When jikji is not configured, the find-first branch is
267
- * skipped entirely (bash unchanged).
268
- */
269
- private bashGate;
270
244
  /**
271
245
  * Programmatic retrieval across all registered methods, merged via min-max
272
246
  * normalization + source dedup. Activates the RetrievalMethodRegistry /
@@ -300,6 +274,7 @@ export declare class AutoRAGAgent {
300
274
  /** The retrieval method registry (posix active; vector/bm25/hybrid pluggable). */
301
275
  getMethodRegistry(): RetrievalMethodRegistry;
302
276
  getSystemPrompt(): string;
277
+ private rerankWithMemory;
303
278
  private normalizeRetrievalOptions;
304
279
  private resolveRetrievalScope;
305
280
  }
@@ -13,16 +13,6 @@ export interface BashToolOptions {
13
13
  readonly timeoutMs?: number;
14
14
  /** Maximum captured output bytes before truncation. */
15
15
  readonly maxOutputBytes?: number;
16
- /**
17
- * Optional deny-by-default gate. When present and returns
18
- * `{ allowed: false }`, the command is NOT spawned; the tool returns the
19
- * gate message with `blockedByJikjiPolicy: true`. Used by the Jikji policy
20
- * to enforce stop_after_find / direct_use / forbidden bash restrictions.
21
- */
22
- readonly gate?: () => {
23
- allowed: boolean;
24
- message: string;
25
- };
26
16
  }
27
17
  export interface BashToolDetails {
28
18
  readonly method: "bash";
@@ -30,7 +20,6 @@ export interface BashToolDetails {
30
20
  readonly exitCode: number | undefined;
31
21
  readonly timedOut: boolean;
32
22
  readonly truncated: boolean;
33
- readonly blockedByJikjiPolicy?: boolean;
34
23
  }
35
24
  /**
36
25
  * Real shell access for the librarian agent. AutoRAG navigates and reads the
@@ -0,0 +1,15 @@
1
+ import type { AgentTool } from "@earendil-works/pi-agent-core";
2
+ import { Type } from "typebox";
3
+ import type { DupeyScanResult } from "../dupey/index.js";
4
+ export declare const SCAN_DUPLICATE_DOCUMENTS_TOOL_NAME = "scan_duplicate_documents";
5
+ export interface ScanDuplicateDocumentsDetails {
6
+ readonly scans: readonly DupeyScanResult[];
7
+ readonly familyCount: number;
8
+ readonly exactDuplicateCount: number;
9
+ }
10
+ export interface ScanDuplicateDocumentsProvider {
11
+ scanDuplicateDocuments(): Promise<ScanDuplicateDocumentsDetails>;
12
+ }
13
+ declare const scanDuplicateDocumentsSchema: Type.TObject<{}>;
14
+ export declare function createScanDuplicateDocumentsTool(provider: ScanDuplicateDocumentsProvider): AgentTool<typeof scanDuplicateDocumentsSchema, ScanDuplicateDocumentsDetails>;
15
+ export {};
@@ -27,6 +27,13 @@ declare const emitResultsSchema: Type.TObject<{
27
27
  chunkIndex: Type.TOptional<Type.TInteger>;
28
28
  lineNumber: Type.TOptional<Type.TInteger>;
29
29
  stableEvidenceId: Type.TOptional<Type.TString>;
30
+ retrieverMix: Type.TOptional<Type.TArray<Type.TString>>;
31
+ parserType: Type.TOptional<Type.TString>;
32
+ documentType: Type.TOptional<Type.TString>;
33
+ documentArea: Type.TOptional<Type.TString>;
34
+ evidenceType: Type.TOptional<Type.TString>;
35
+ evidenceLocation: Type.TOptional<Type.TString>;
36
+ confidence: Type.TOptional<Type.TNumber>;
30
37
  }>>>;
31
38
  }>>;
32
39
  warnings: Type.TOptional<Type.TArray<Type.TString>>;
@@ -51,6 +58,13 @@ export interface AutoRAGEvidenceRef {
51
58
  readonly chunkIndex?: number;
52
59
  readonly lineNumber?: number;
53
60
  readonly stableEvidenceId?: string;
61
+ readonly retrieverMix?: readonly string[];
62
+ readonly parserType?: string;
63
+ readonly documentType?: string;
64
+ readonly documentArea?: string;
65
+ readonly evidenceType?: string;
66
+ readonly evidenceLocation?: string;
67
+ readonly confidence?: number;
54
68
  }
55
69
  export interface AutoRAGMappingEntry {
56
70
  readonly number: number;
@@ -1,6 +1,7 @@
1
1
  export type { AutoRAGAgentOptions, AutoRefreshOptions } from "./agent.js";
2
2
  export { AutoRAGAgent } from "./agent.js";
3
3
  export { buildDatasourceSkillsPrompt, createLoadDatasourceSkillTool, type DatasourceSkillProvider, datasourceSkillLocation, formatDatasourceSkillInvocation, LOAD_DATASOURCE_SKILL_TOOL_NAME, type LoadDatasourceSkillDetails, toDatasourceAgentSkill, } from "./datasource-skill.js";
4
+ export { createScanDuplicateDocumentsTool, SCAN_DUPLICATE_DOCUMENTS_TOOL_NAME, type ScanDuplicateDocumentsDetails, type ScanDuplicateDocumentsProvider, } from "./dupey-tool.js";
4
5
  export type { AutoRAGEmittedResult, AutoRAGMappingEntry, AutoRAGResultsDetails, } from "./emit-results-tool.js";
5
6
  export { createEmitResultsTool, EMIT_AUTORAG_RESULTS_TOOL_NAME } from "./emit-results-tool.js";
6
7
  export { createJikjiFindTool, JIKJI_FIND_TOOL_NAME, type JikjiFindDetails, type JikjiFindPerRootPolicy, type JikjiFindProvider, type JikjiFindProviderResult, type MergedJikjiPolicy, } from "./jikji-find-tool.js";
@@ -0,0 +1,12 @@
1
+ import type { Model } from "@earendil-works/pi-ai";
2
+ export interface LocalAutoRAGModel {
3
+ readonly provider: string;
4
+ readonly apiKey: string;
5
+ readonly model: Model<"openai-responses">;
6
+ }
7
+ export interface LoadLocalAutoRAGModelOptions {
8
+ readonly configPath?: string;
9
+ readonly env?: Readonly<Record<string, string | undefined>>;
10
+ readonly modelId?: string;
11
+ }
12
+ export declare function loadLocalAutoRAGModel(options?: LoadLocalAutoRAGModelOptions): LocalAutoRAGModel;
@@ -9,7 +9,7 @@ export type SearchDocumentDiagnosticSeverity = "info" | "warning" | "error";
9
9
  * (#21/#22) does not require another source-breaking type change; codes not yet
10
10
  * emitted are still valid members.
11
11
  */
12
- export type SearchDocumentDiagnosticCode = "empty-query" | "unknown-warning" | "caller-tool-dropped" | "bm25-unavailable" | "bm25-degraded-fallback" | "minsync-unavailable" | "parser-skipped" | "parser-failed" | "unsupported-file" | "stale-index" | "deleted-mirror" | "retrieval-method-failed" | "jikji-unavailable" | "jikji-prepare-failed" | "jikji-find-failed" | "refresh-failed" | "watch-failed" | "watch-limited";
12
+ export type SearchDocumentDiagnosticCode = "empty-query" | "unknown-warning" | "caller-tool-dropped" | "bm25-unavailable" | "bm25-degraded-fallback" | "minsync-unavailable" | "parser-skipped" | "parser-failed" | "duplicate-excluded" | "unsupported-file" | "stale-index" | "deleted-mirror" | "retrieval-method-failed" | "jikji-unavailable" | "jikji-prepare-failed" | "jikji-find-failed" | "refresh-failed" | "watch-failed" | "watch-limited";
13
13
  export interface SearchDocumentDiagnostic {
14
14
  readonly code: SearchDocumentDiagnosticCode;
15
15
  readonly severity: SearchDocumentDiagnosticSeverity;
@@ -2,8 +2,7 @@ import type { Skill } from "@earendil-works/pi-agent-core";
2
2
  import type { StoreManifest } from "../manifest/types.js";
3
3
  export interface SystemPromptConfig {
4
4
  toolNames: string[];
5
- orchestratorModelId?: string;
6
- explorerModelId?: string;
5
+ modelId?: string;
7
6
  memorySignalCount?: number;
8
7
  memoryEntries?: readonly unknown[];
9
8
  manifests: StoreManifest[];
@@ -0,0 +1,4 @@
1
+ import type { DupeyScanResult } from "../../dupey/index.js";
2
+ import type { CommandContext } from "./types.js";
3
+ export type DuplicateScanner = (path: string) => Promise<DupeyScanResult>;
4
+ export declare function runDuplicates(ctx: CommandContext, scanner?: DuplicateScanner): Promise<number>;