@autorag/librarian 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/NOTICE +4 -4
  2. package/README.md +120 -24
  3. package/dist/agent/agent.d.ts +147 -78
  4. package/dist/agent/answer-citations.d.ts +22 -0
  5. package/dist/agent/answer-guidelines.d.ts +9 -9
  6. package/dist/agent/citations.d.ts +42 -7
  7. package/dist/agent/datasource-skill.d.ts +30 -16
  8. package/dist/agent/evidence-judgment.d.ts +58 -0
  9. package/dist/agent/evidence-ledger.d.ts +54 -0
  10. package/dist/agent/evidence-origins.d.ts +49 -0
  11. package/dist/agent/index.d.ts +2 -2
  12. package/dist/agent/jikji-find-tool.d.ts +2 -1
  13. package/dist/agent/pi-session.d.ts +8 -1
  14. package/dist/agent/query-peer-tool.d.ts +3 -0
  15. package/dist/agent/query-routing.d.ts +71 -10
  16. package/dist/agent/{emit-results-tool.d.ts → results.d.ts} +11 -11
  17. package/dist/agent/search-all-tool.d.ts +5 -5
  18. package/dist/agent/search-documents.d.ts +14 -27
  19. package/dist/agent/search-minsync-tool.d.ts +5 -5
  20. package/dist/agent/search-single-datasource-tool.d.ts +9 -8
  21. package/dist/agent/self-config.d.ts +40 -0
  22. package/dist/agent/system-prompt.d.ts +2 -3
  23. package/dist/agent/web-fetch-tool.d.ts +2 -1
  24. package/dist/agent/web-search-tool.d.ts +2 -1
  25. package/dist/cli/commands/evidence.d.ts +2 -2
  26. package/dist/cli/commands/memory.d.ts +1 -1
  27. package/dist/cli/commands/report.d.ts +2 -2
  28. package/dist/cli/commands/tui.d.ts +3 -2
  29. package/dist/cli/config.d.ts +16 -8
  30. package/dist/cli/index.d.ts +1 -1
  31. package/dist/cli/index.js +11133 -10103
  32. package/dist/cli/output.d.ts +2 -6
  33. package/dist/cloud/authorize.d.ts +12 -0
  34. package/dist/cloud/callback-server.d.ts +33 -0
  35. package/dist/cloud/callback.d.ts +23 -0
  36. package/dist/cloud/config.d.ts +23 -0
  37. package/dist/cloud/errors.d.ts +46 -0
  38. package/dist/cloud/index.d.ts +12 -0
  39. package/dist/cloud/models.d.ts +32 -0
  40. package/dist/cloud/oauth-login.d.ts +22 -0
  41. package/dist/cloud/pkce.d.ts +20 -0
  42. package/dist/cloud/provider.d.ts +40 -0
  43. package/dist/cloud/token.d.ts +22 -0
  44. package/dist/config/home.d.ts +6 -0
  45. package/dist/core.d.ts +10 -21
  46. package/dist/core.js +15272 -14207
  47. package/dist/datasource/chunk-store.d.ts +2 -6
  48. package/dist/datasource/connector-skill.d.ts +2 -3
  49. package/dist/datasource/index.d.ts +2 -4
  50. package/dist/datasource/registry.d.ts +11 -13
  51. package/dist/datasource/scope.d.ts +19 -0
  52. package/dist/datasource/skills/github-gist/index.d.ts +1 -1
  53. package/dist/datasource/skills/github-gist/semantic.d.ts +3 -44
  54. package/dist/datasource/skills/github-gist/skill.d.ts +3 -3
  55. package/dist/datasource/types.d.ts +14 -28
  56. package/dist/embedding-runtime/gateway-embedder.d.ts +41 -0
  57. package/dist/index.d.ts +2 -1
  58. package/dist/index.js +15488 -14359
  59. package/dist/language.d.ts +2 -1
  60. package/dist/mcp/index.js +15413 -14341
  61. package/dist/memory/check-memory-tool.d.ts +8 -4
  62. package/dist/memory/context.d.ts +51 -0
  63. package/dist/memory/index.d.ts +8 -1
  64. package/dist/memory/judged-evidence.d.ts +32 -0
  65. package/dist/memory/memory.d.ts +36 -120
  66. package/dist/memory/renderer.d.ts +16 -7
  67. package/dist/memory/similar-queries.d.ts +40 -0
  68. package/dist/minsync/client.d.ts +1 -1
  69. package/dist/minsync/errors.d.ts +14 -0
  70. package/dist/minsync/index.d.ts +1 -0
  71. package/dist/minsync/installer.d.ts +1 -1
  72. package/dist/minsync/method.d.ts +3 -3
  73. package/dist/mirror/sync.d.ts +5 -2
  74. package/dist/observability/run-log.d.ts +1 -1
  75. package/dist/parser/defaults.d.ts +16 -5
  76. package/dist/parser/index.d.ts +1 -1
  77. package/dist/parser/kordoc.d.ts +8 -1
  78. package/dist/parser/ocr-engines.d.ts +19 -0
  79. package/dist/retrieval/bm25.d.ts +19 -0
  80. package/dist/retrieval/engine.d.ts +17 -58
  81. package/dist/retrieval/index.d.ts +3 -2
  82. package/dist/retrieval/merger.d.ts +6 -0
  83. package/dist/retrieval/rerank.d.ts +2 -2
  84. package/dist/retrieval/selection.d.ts +33 -41
  85. package/dist/retrieval/types.d.ts +1 -26
  86. package/dist/web/search/format.d.ts +5 -2
  87. package/dist/web/search/index.d.ts +7 -1
  88. package/package.json +5 -5
  89. package/skills/autorag/SKILL.md +21 -22
  90. package/skills/autorag-doctor/SKILL.md +20 -15
  91. package/skills/autorag-lite-setup/SKILL.md +22 -19
  92. package/skills/autorag-setup/SKILL.md +34 -21
  93. package/dist/agent/fast-answer-tool.d.ts +0 -46
  94. package/dist/cli/commands/feedback.d.ts +0 -8
  95. package/dist/datasource/access-context.d.ts +0 -43
  96. package/dist/datasource/result-filter.d.ts +0 -64
  97. package/dist/parser/ocr.d.ts +0 -31
@@ -1,13 +1,12 @@
1
- import type { Agent, AgentTool, Skill } from "@earendil-works/pi-agent-core";
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";
@@ -18,15 +17,15 @@ import { type DefaultParserRegistryOptions } from "../parser/index.js";
18
17
  import { RetrievalEngine } from "../retrieval/engine.js";
19
18
  import { RetrievalMethodRegistry } from "../retrieval/registry.js";
20
19
  import type { DatasourceCatalogEntry } from "../retrieval/selection.js";
21
- import type { CuratedResult, RetrievalDiagnostic, RetrievalOptions, RetrievalResult } from "../retrieval/types.js";
20
+ import type { 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
- import { type AutoRAGFastAnswerDetails } from "./fast-answer-tool.js";
24
23
  import { type JevToolOptions } from "./jev-extension.js";
25
24
  import { type JikjiFindProviderResult } from "./jikji-find-tool.js";
26
25
  import { type AutoRAGPiInteractiveRuntime, type AutoRAGPiSession } from "./pi-session.js";
27
- import { type QueryRoute } from "./query-routing.js";
28
26
  import { type RefreshProgressCounts, type RefreshProgressPhase } from "./refresh-progress.js";
29
27
  import { type SearchDocumentDiagnostic, type SearchDocumentsResponse, type SearchDocumentsStreamEvent } from "./search-documents.js";
28
+ import { type SelfConfigOptions } from "./self-config.js";
30
29
  import { type WatcherFactory, type WatchRefreshHandle } from "./watch-refresh.js";
31
30
  import { type WebFetchToolOptions } from "./web-fetch-tool.js";
32
31
  import { type WebSearchToolOptions } from "./web-search-tool.js";
@@ -190,7 +189,7 @@ export interface AutoRAGAgentOptions {
190
189
  memoryPath?: string;
191
190
  workspacePath?: string;
192
191
  tools?: AgentTool[];
193
- minSync?: Omit<MinSyncVectorMethodOptions, "root"> | false;
192
+ minSync?: Omit<MinSyncVectorMethodOptions, "root">;
194
193
  jikji?: JikjiOptions | false;
195
194
  /**
196
195
  * Windows-only instant file/folder name search through the bundled
@@ -237,8 +236,8 @@ export interface AutoRAGAgentOptions {
237
236
  /**
238
237
  * Jev (TypeSafe's judgment model: typed questions in, calibrated
239
238
  * probabilities out). When set, the two-phase search asks Jev before the
240
- * fast answer whether the question needs local search, web search, or a
241
- * direct answer, and whether to decompose it; after the fast answer, whether
239
+ * fast answer whether the question is answerable from intrinsic knowledge
240
+ * (direct answer) or needs local search, and whether to decompose it; after the fast answer, whether
242
241
  * verification is needed. It also exposes the `jev` tool. Always omitted for
243
242
  * remote P2P sessions.
244
243
  *
@@ -247,6 +246,20 @@ export interface AutoRAGAgentOptions {
247
246
  * off, so library callers never make paid network calls they did not ask for.
248
247
  */
249
248
  jev?: JevToolOptions | false;
249
+ /**
250
+ * Embedder used to find similar past questions in memory (semantic half of
251
+ * the hybrid search). Defaults to the local embedding gateway; `false` keeps
252
+ * memory search keyword-only.
253
+ */
254
+ memoryEmbedder?: Embedder | false;
255
+ /**
256
+ * Agent self-configuration. When set (and Jev is on), Jev gains a `config`
257
+ * branch for questions about AutoRAG's own settings: the turn skips the
258
+ * fast answer, receives the full `autorag-setup` skill, edits
259
+ * `configPath` with the pi tools, and reports what it changed as its final
260
+ * message. Always omitted for remote P2P sessions.
261
+ */
262
+ selfConfig?: SelfConfigOptions;
250
263
  /**
251
264
  * Question decomposition used by the Jev query pipeline. `model` (with its
252
265
  * `apiKey`) is the LLM that splits one question into at most five search
@@ -266,7 +279,6 @@ export interface AutoRAGAgentOptions {
266
279
  */
267
280
  limits?: AutoRAGRetrievalLimits;
268
281
  datasourceSkills?: readonly DatasourceSkill[];
269
- datasourceAccess?: DatasourceAccessContextOptions;
270
282
  /** Non-fatal diagnostics from config/agent construction (e.g. skipped unknown datasources). */
271
283
  startupDiagnostics?: readonly SearchDocumentDiagnostic[];
272
284
  /** Maximum time a model/tool search may run before it is aborted. */
@@ -343,12 +355,11 @@ export declare class AutoRAGAgent {
343
355
  private readonly runLogger;
344
356
  private lastQuery;
345
357
  private lastSessionId;
346
- private readonly sessions;
347
358
  private activeRun;
348
- private resultCapture;
349
- private interactiveFastAnswerCallback;
350
359
  private modelNativeSearchAuth;
351
360
  private retrievalTrace;
361
+ /** Evidence every retrieval tool returned this run; the answer's inline `[eN]` citations resolve against it. */
362
+ private readonly evidenceLedger;
352
363
  private preliminaryCallback;
353
364
  /** Per-phase thinking levels of the two-phase search. */
354
365
  private readonly fastThinkingLevel;
@@ -367,13 +378,11 @@ export declare class AutoRAGAgent {
367
378
  private readonly merger;
368
379
  private readonly reranker;
369
380
  private readonly rerankTopN;
370
- private readonly datasourceFilter;
371
381
  private readonly minSyncMethod;
372
382
  private readonly jikjiClient;
373
383
  private readonly everythingClient;
374
384
  private readonly fsearchClient;
375
385
  private readonly datasourceSkills;
376
- private readonly datasourceAccessOptions;
377
386
  private readonly startupDiagnostics;
378
387
  private readonly datasourceAgentSkills;
379
388
  private readonly parserOptions;
@@ -382,8 +391,10 @@ export declare class AutoRAGAgent {
382
391
  private readonly jevExtension;
383
392
  /** Jev judge shared by the `jev` tool and the query router; undefined when disabled. */
384
393
  private readonly jevJudge;
394
+ /** Self-configuration, enabled only with Jev on a local session. */
395
+ private readonly selfConfig;
385
396
  private readonly queryDecompositionModel;
386
- /** Web search routing for the pipeline's web branch; undefined when web tools are off. */
397
+ /** Web search options for the agent's `web_search` / `web_fetch` tools; undefined when web tools are off. */
387
398
  private readonly webSearchOptions;
388
399
  /** Routing diagnostics for the in-flight search; reset per run. */
389
400
  private routingDiagnostics;
@@ -398,6 +409,17 @@ export declare class AutoRAGAgent {
398
409
  private readonly persistPiSessions;
399
410
  private readonly updateNotice;
400
411
  private boundPiRuntime;
412
+ /** Embeds past questions for similar-question search; undefined keeps memory search keyword-only. */
413
+ private readonly memoryEmbedder;
414
+ private readonly memoryVectorPath;
415
+ /** Every retrieval result of the in-flight run with the query/method that surfaced it. */
416
+ private readonly evidenceOrigins;
417
+ /** Search-tool queries by tool call id, read back when the call ends. */
418
+ private readonly searchToolQueries;
419
+ /** Identifies this agent's conversation: everything judged in it is "current" memory. */
420
+ private readonly conversationId;
421
+ /** The memory context loaded for the in-flight run; cleared whenever a run starts. */
422
+ private memoryContextCache;
401
423
  /** True when this agent was constructed for an untrusted remote peer. */
402
424
  readonly remoteSession: boolean;
403
425
  private activeRetrievalOptions;
@@ -405,7 +427,42 @@ export declare class AutoRAGAgent {
405
427
  private readonly limits;
406
428
  constructor(options: AutoRAGAgentOptions);
407
429
  scanDuplicateDocuments(): Promise<ScanDuplicateDocumentsDetails>;
430
+ /**
431
+ * Reference memory for the current question: everything judged earlier in
432
+ * this conversation, up to 25 similar past questions, and matching
433
+ * long-term insights. Computed once per run (the datasource check and every
434
+ * model turn share it) so the similar-question search and its embedder call
435
+ * are not repeated and a fallback is reported once. Remote peers never read it.
436
+ */
437
+ private loadMemoryContextFor;
408
438
  private withMemoryContext;
439
+ /**
440
+ * Where evidence came from, or undefined when this run may not see it.
441
+ * Datasource chunks carry a virtual path rooted at the skill name
442
+ * (`/kakao/default/...`), but the model sometimes maps a datasource hit to a
443
+ * bare chunk id. The evidence method then still names the datasource
444
+ * (`search_datasource_kakao_work`, `datasource:kakao`, `kakao-work-lexical`):
445
+ * both sides collapse every non-alphanumeric to `_` exactly like generated
446
+ * tool names, and a datasource id that appears as a whole token attributes
447
+ * it; longer ids are checked first so `kakao-work` wins over `kakao`.
448
+ * Indexed files are absolute paths under a search path; web evidence is a URL.
449
+ * Memory is global (shared across workspaces and configs), so evidence from
450
+ * an unconfigured datasource, and evidence with no recognizable origin, is
451
+ * never attributed.
452
+ */
453
+ private evidenceAttribution;
454
+ /** Options shared by the prompt injection and the `check_memory` tool; rebuilt on every call because datasource configuration follows live settings. */
455
+ private memoryContextOptions;
456
+ /** Remember which query and method surfaced each retrieval result, so cited evidence can be traced back. */
457
+ private rememberEvidenceOrigins;
458
+ /**
459
+ * After the final answer: map every cited evidence back to the search query
460
+ * and method that found it, ask Jev (one batched call, evidence judged in
461
+ * parallel) whether it really supports the answer sentence it backs, and
462
+ * keep only what clears the threshold. Remote peers and runs without Jev
463
+ * store nothing; a failed judgment stores nothing and says why.
464
+ */
465
+ private recordJudgedEvidence;
409
466
  private resolveSessionModel;
410
467
  private createSearchSession;
411
468
  private configureSearchSession;
@@ -413,6 +470,15 @@ export declare class AutoRAGAgent {
413
470
  private currentSystemPromptConfig;
414
471
  subscribe(listener: Parameters<Agent["subscribe"]>[0]): () => void;
415
472
  createPiInteractiveRuntime(): Promise<AutoRAGPiInteractiveRuntime>;
473
+ /** Resolve the model's inline `[eN]` citations against this run's evidence and derive the structured results. */
474
+ private deriveAnswer;
475
+ /**
476
+ * Drives one TUI query through the two-phase search. The model's own
477
+ * assistant messages (progress notes before a tool call, the fast answer,
478
+ * the final answer) are already recorded and rendered by the bound pi
479
+ * session, so nothing is re-sent here: a second copy would show every answer
480
+ * twice and put it in the model's context twice.
481
+ */
416
482
  private runInteractivePiQuery;
417
483
  abort(): void;
418
484
  /**
@@ -425,61 +491,51 @@ export declare class AutoRAGAgent {
425
491
  }): void;
426
492
  stopAutoRefresh(): void;
427
493
  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
- getResultRegistry(sessionId?: string): ReadonlyMap<number, CuratedResult>;
433
494
  searchDocuments(query: string, options?: RetrievalOptions): Promise<SearchDocumentsResponse>;
434
495
  /**
435
496
  * Stream bounded progress updates while retaining the stable
436
- * {@link searchDocuments} promise API. Progress is sourced from model text
437
- * deltas, so callers can render it in a TUI, CLI, or parent agent and can
438
- * stop by calling {@link abort}.
497
+ * {@link searchDocuments} promise API. Progress is the text an assistant
498
+ * message wrote before calling a tool (`stopReason: "toolUse"`); a message
499
+ * that ends its turn is an answer, delivered as `preliminary` or
500
+ * `complete`, never as progress. Callers can render it in a TUI, CLI, or
501
+ * parent agent and can stop by calling {@link abort}.
439
502
  */
440
503
  searchDocumentsStream(query: string, options?: RetrievalOptions): AsyncGenerator<SearchDocumentsStreamEvent, void, void>;
441
- private datasourceAccessContext;
442
504
  /**
443
- * Build the Pi agent-skill list for datasource skills authorized by the
444
- * trusted, server-bound access context. Only authorized skills become
445
- * model-visible; unauthorized skills are omitted entirely (default-deny).
505
+ * Build the Pi agent-skill list for every configured datasource skill. All
506
+ * configured skills are model-visible; a connection is removed from the
507
+ * model surface by removing it from the config, not by a permission layer.
446
508
  */
447
- private buildAuthorizedDatasourceSkills;
509
+ private buildDatasourceAgentSkills;
448
510
  /**
449
511
  * Per-connection tool specs for the generated `search_datasource_<id>`
450
- * tools, built from the same trusted config and access context as
451
- * {@link buildAuthorizedDatasourceSkills}. One spec per authorized
452
- * datasource skill; duplicate ids collapse to the first registration.
512
+ * tools, one per configured datasource skill; duplicate ids collapse to the
513
+ * first registration.
453
514
  */
454
515
  private singleDatasourceToolSpecs;
455
516
  /**
456
- * Authorized configured datasource descriptors for catalog/listing surfaces.
457
- *
458
- * Built from the same trusted, server-bound access context as
459
- * {@link buildAuthorizedDatasourceSkills}: only tag-authorized datasources
460
- * are listed — including ones that expose no retrieval methods — and each
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.
517
+ * Configured datasource descriptors for catalog/listing surfaces: every
518
+ * configured datasource is listed — including ones that expose no retrieval
519
+ * methods — and each entry carries only identity, capability tags, and
520
+ * source scope strings (never credentials, config paths, or raw instance
521
+ * metadata). Duplicate datasource ids collapse to the first registration.
464
522
  */
465
523
  listDatasources(): DatasourceCatalogEntry[];
466
524
  /**
467
- * Opaque source scope strings for one datasource that the trusted context
468
- * authorizes. Datasources without the `scoped` capability expose their
469
- * sources unfiltered (they are gated only at the tag level).
525
+ * Opaque source scope strings for one datasource. Sources containing a `#`
526
+ * fragment are invalid and skipped.
470
527
  */
471
- private authorizedSourceScopes;
528
+ private datasourceSourceScopes;
472
529
  /**
473
- * Resolve an authorized datasource agent skill by model-visible name for the
474
- * `load_datasource_skill` tool. Returns `undefined` for unknown or
475
- * unauthorized names — model/tool input can never widen authorization.
530
+ * Resolve a configured datasource agent skill by model-visible name for the
531
+ * `load_datasource_skill` tool. Returns `undefined` for unknown names.
476
532
  */
477
- loadDatasourceSkill(name: string): Skill | undefined;
533
+ loadDatasourceSkill(name: string): DatasourceAgentSkill | undefined;
478
534
  private indexDatasources;
479
535
  /** Path-opaque component diagnostics for the search response. */
480
536
  private collectComponentDiagnostics;
481
537
  /**
482
- * Jev check run after emit_fast_answer: does the answer need correction,
538
+ * Jev check run after the fast answer: does the answer need correction,
483
539
  * clarification, or further research? "No" ends the run with the fast
484
540
  * answer as the final answer. Without Jev, or when the check fails, the run
485
541
  * always continues into verification.
@@ -487,53 +543,68 @@ export declare class AutoRAGAgent {
487
543
  private shouldFollowUp;
488
544
  /**
489
545
  * Jev query pipeline, run before the fast answer. Jev picks the branch
490
- * (local search, web search, or a direct answer) and whether the question
546
+ * (direct answer or local search) and whether the question
491
547
  * needs decomposition; a "yes" splits it into at most five search queries
492
- * with the configured decomposition model (default: the session model).
493
- * Without Jev, and on any routing failure, this is today's single local
494
- * search for the original question.
548
+ * with the configured decomposition model (default: the session model). On
549
+ * the local branch, Jev also judges, per registered datasource, whether it
550
+ * must be searched (in parallel with decomposition). Without Jev, and on any
551
+ * routing failure, this is today's single local search for the original
552
+ * question with no datasource search.
495
553
  */
496
554
  private planQuery;
497
555
  /**
498
- * Baseline local evidence for the fast answer. Jikji and MinSync run for
499
- * every search query in parallel (MinSync itself queues per workspace), the
500
- * per-query hits are interleaved and deduplicated into one pool, and that
501
- * pool is reranked against the original question.
556
+ * Jev datasource check for the local branch: one `noul` per configured
557
+ * datasource that has retrieval methods, with where similar past questions
558
+ * were answered (from retrieval memory) in the state. Returns the ids to
559
+ * search with every query before the rerank; a failed check searches none.
560
+ */
561
+ private selectSearchDatasources;
562
+ /**
563
+ * Baseline local evidence for the fast answer. Jikji, MinSync, and every
564
+ * Jev-selected datasource run for every search query in parallel (MinSync
565
+ * itself queues per workspace), the per-query hits are interleaved and
566
+ * deduplicated into one pool, and that pool is reranked against the
567
+ * original question.
502
568
  */
503
569
  private prefetchInitialRetrievalContext;
504
- /** Baseline web evidence for the fast answer: one web search per query, all in parallel. */
505
- private prefetchWebContext;
506
570
  /**
507
- * Rerank the pre-fast-answer baseline pool — Jikji answer paths plus MinSync
508
- * chunks — down to the configured `rerank.topN`. With decomposition the pool
509
- * merges every search query's hits (interleaved), capped at the same
510
- * per-source sizes as a single query so the rerank request does not grow
511
- * with the query count. Returns `undefined` when reranking is
512
- * disabled/unavailable or the pool is empty, so the caller keeps the
513
- * unranked sections; a rerank failure never blocks the fast answer.
571
+ * Rerank the pre-fast-answer baseline pool — Jikji answer paths, MinSync
572
+ * chunks, and Jev-selected datasource chunks — down to the configured
573
+ * `rerank.topN`. With decomposition the pool merges every search query's
574
+ * hits (interleaved), capped at the same per-source sizes as a single query
575
+ * so the rerank request does not grow with the query count. Returns
576
+ * `undefined` when reranking is disabled/unavailable or the pool is empty,
577
+ * so the caller keeps the unranked sections; a rerank failure never blocks
578
+ * the fast answer.
514
579
  */
515
580
  private rerankPrefetchPool;
516
581
  /**
517
582
  * Fast-phase prompt for two-phase searches. The baseline retrieval context
518
- * is already gathered, so the model answers immediately with thinking off
519
- * via emit_fast_answer, without any further tool calls.
583
+ * is already gathered, so the model answers immediately with thinking off,
584
+ * as plain text, without any further tool calls.
520
585
  */
521
586
  buildFastAnswerPrompt(query: string, options: RetrievalOptions, baseline: string): string;
522
587
  /**
523
588
  * Prompt for a question Jev routed to a direct answer: general knowledge or
524
589
  * small talk. No retrieval ran and no verification phase follows, so the
525
- * answer emitted here is final.
590
+ * reply is the final answer.
526
591
  */
527
592
  buildDirectAnswerPrompt(query: string): string;
528
593
  /** Discovery-tool hint naming only the registered discovery tools; empty when none. */
529
594
  private discoveryHint;
595
+ /**
596
+ * Verification-phase nudge toward the internet. Jev no longer routes to web
597
+ * search, so the agent decides after the fast answer: when local evidence is
598
+ * missing, thin, or possibly stale, it searches the web. Empty when web tools are off.
599
+ */
600
+ private webFallbackHint;
530
601
  /**
531
602
  * Verification-phase prompt for two-phase searches. The fast answer, when a
532
603
  * consumer already received it, is embedded verbatim so the model can diff
533
- * against it; the model then verifies with thinking on and finalizes with
534
- * emit_autorag_results exactly once, returning only the delta.
604
+ * against it; the model then verifies with thinking on and ends with the
605
+ * final answer as a plain reply, returning only the delta.
535
606
  */
536
- buildRefinementPrompt(query: string, options: RetrievalOptions, fastAnswer: AutoRAGFastAnswerDetails | undefined, fastAnswerDelivered: boolean, route?: QueryRoute): string;
607
+ buildRefinementPrompt(query: string, options: RetrievalOptions, fastAnswer: string | undefined, fastAnswerDelivered: boolean): string;
537
608
  buildSearchPrompt(query: string, options: RetrievalOptions, initialRetrievalContext?: string): string;
538
609
  refresh(force?: boolean, opts?: AutoRAGRefreshOptions): Promise<AutoRAGRefreshResult>;
539
610
  /**
@@ -571,7 +642,7 @@ export declare class AutoRAGAgent {
571
642
  */
572
643
  private scanMirrorStaleness;
573
644
  private exactDuplicateExclusions;
574
- syncMinSync(force?: boolean): Promise<MinSyncSyncResult | undefined>;
645
+ syncMinSync(force?: boolean): Promise<MinSyncSyncResult>;
575
646
  /** Provider for the Windows-only everything_search tool. */
576
647
  searchEverything(request: EverythingSearchRequest): Promise<EverythingSearchResult>;
577
648
  /**
@@ -660,10 +731,9 @@ export declare class AutoRAGAgent {
660
731
  * Search one datasource connection only. Only the target connection's
661
732
  * retrieval methods are registered with the retriever, so no other
662
733
  * datasource CLI is spawned at all and only that connection's hits are
663
- * returned. Access is still gated by the trusted datasource context: an
664
- * unknown or unauthorized `datasourceId` yields an empty result set.
734
+ * returned. An unknown `datasourceId` yields an empty result set.
665
735
  *
666
- * This backs the generated `search_datasource_<id>` tools; every authorized
736
+ * This backs the generated `search_datasource_<id>` tools; every configured
667
737
  * connection has one. Cross-datasource fan-out is
668
738
  * {@link searchAllDocuments}, which spans every retrieval method.
669
739
  */
@@ -679,7 +749,7 @@ export declare class AutoRAGAgent {
679
749
  /**
680
750
  * The standalone retrieval engine for this agent's method pipeline.
681
751
  * Built on first access using the agent's registered methods and configured
682
- * datasource access context. Model-free — no agent state required.
752
+ * datasource catalog. Model-free — no agent state required.
683
753
  */
684
754
  private retrievalEngine;
685
755
  getRetrievalEngine(): RetrievalEngine;
@@ -690,7 +760,6 @@ export declare class AutoRAGAgent {
690
760
  * the merged order is preserved — a reranker outage never hides evidence.
691
761
  */
692
762
  private applyRerank;
693
- private rerankWithMemory;
694
763
  private remoteFilteredRetrievalMethod;
695
764
  private normalizeRetrievalOptions;
696
765
  private resolveRetrievalScope;
@@ -0,0 +1,22 @@
1
+ import { type EvidenceLedger } from "./evidence-ledger.js";
2
+ import type { AutoRAGResultsDetails } from "./results.js";
3
+ import type { SearchDocumentDiagnostic } from "./search-documents.js";
4
+ export interface DerivedAnswer {
5
+ readonly details: AutoRAGResultsDetails;
6
+ readonly diagnostics: readonly SearchDocumentDiagnostic[];
7
+ }
8
+ /**
9
+ * Turn the model's plain answer into the structured results the rest of the
10
+ * harness consumes. The model cites with the evidence ids the retrieval tools
11
+ * printed (`[e3]`, `[e3, e7]`) or `[file:<abs path>]` for a file it opened
12
+ * itself. Each id is resolved against the run's evidence ledger, so a source,
13
+ * method, and chunk always come from recorded evidence, never from model text.
14
+ *
15
+ * Results are one per cited source, numbered by first appearance, and every
16
+ * marker in the returned answer is rewritten to its result number (`[1]`).
17
+ * A marker that matches no evidence, and any numeric marker the model wrote on
18
+ * its own, is dropped and reported: it can never point at the wrong result.
19
+ */
20
+ export declare function deriveResultsFromAnswer(text: string, ledger: EvidenceLedger, options: {
21
+ readonly allowLocalFiles: boolean;
22
+ }): DerivedAnswer;
@@ -1,19 +1,19 @@
1
1
  /**
2
2
  * The single file-path exception to the answer "no file paths" rule
3
- * (issue #1790). Every prompt and tool description that shapes `answer` uses
4
- * this exact wording so a caller that can render images receives a markdown
5
- * image embed whose path is a real result source, while the no-path rule
6
- * otherwise still stands.
3
+ * (issue #1790). Every prompt that shapes the answer uses this exact wording so
4
+ * a caller that can render images receives a markdown image embed whose path is
5
+ * a real evidence source, while the no-path rule otherwise still stands.
7
6
  */
8
- export declare const ANSWER_IMAGE_EMBED_RULE = "**Images**: when a retrieved result is itself an image file (png, jpg, jpeg, gif, webp, svg, bmp, avif, heic, tiff) and showing it answers the question, embed it in `answer` as a markdown image on its own line: `![short description](<absolute source path>)`, followed by its citation, e.g. `![Q3 revenue chart](</data/reports/q3 chart.png>) [2]`. Use only the real source path of a result in `results`/`mapping`. Never invent a path, use relative paths, or embed remote URLs. Apart from these image embeds, the no-file-paths rule stands.";
7
+ export declare const ANSWER_IMAGE_EMBED_RULE = "**Images**: when a retrieved result is itself an image file (png, jpg, jpeg, gif, webp, svg, bmp, avif, heic, tiff) and showing it answers the question, embed it in the answer as a markdown image on its own line: `![short description](<absolute source path>)`, followed by its citation, e.g. `![Q3 revenue chart](</data/reports/q3 chart.png>) [e2]`. Use only the real source path of retrieved evidence. Never invent a path, use relative paths, or embed remote URLs. Apart from these image embeds, the no-file-paths rule stands.";
9
8
  /**
10
9
  * Delta (verification) answers must not re-embed an image the first answer
11
10
  * already showed.
12
11
  */
13
12
  export declare const ANSWER_IMAGE_DELTA_RULE = "An image already embedded in the first answer must not be embedded again.";
14
13
  /**
15
- * One numbering space for citations (issue #1788): every `[n]` in `answer`
16
- * must be a `results[].number` emitted in the same call. Retrieval candidate
17
- * numbers and first-answer unit numbers are never citation numbers.
14
+ * Inline evidence citations. The model writes the id the retrieval tools print
15
+ * next to each result; the harness resolves it to the recorded source and
16
+ * renumbers the markers `[1]`, `[2]`, ... in order of first appearance, so the
17
+ * caller only ever sees numbered citations backed by recorded evidence.
18
18
  */
19
- export declare const ANSWER_CITATION_RULE = "**Citation numbers**: every bracketed citation [n] in `answer` must be the `number` of a result you emit in `results` of the same call. Numbers shown in retrieval candidates or in an earlier first answer are NOT citation numbers \u2014 renumber against your own `results`, and add a result for any evidence you cite.";
19
+ export declare const ANSWER_CITATION_RULE = "**Citations**: cite supporting evidence inline with the evidence id shown next to each retrieved result, in square brackets (e.g. [e3], or [e3][e7] for two). Copy ids exactly; never invent one. For a local file you opened yourself with `bash`, cite `[file:<absolute path>]`. Cite the evidence that backs a sentence at the end of that sentence. Do not cite numbers, paths, or anything else.";
@@ -1,7 +1,39 @@
1
- /** Sorted, de-duplicated citation numbers in `answer` with no matching result. */
2
- export declare function unresolvedCitations(answer: string, results: readonly {
1
+ /**
2
+ * Bracketed citations in an answer. Two grammars share one scanner:
3
+ *
4
+ * - **Final form** `[n]`: a number that must resolve to a `results[].number`
5
+ * of the same response (issue #1788).
6
+ * - **Model form** `[e3]`, `[e3, e7]`, `[file:/abs/path]`: the evidence ids the
7
+ * retrieval tools print next to each result, or a local file the model opened
8
+ * itself. The harness resolves them against the run's evidence ledger and
9
+ * rewrites them into the final form.
10
+ *
11
+ * A markdown image target `(<...>)` is skipped verbatim so a bracketed token
12
+ * inside a real file path is never mistaken for a citation; `[n](...)` is a
13
+ * markdown link, not a citation.
14
+ *
15
+ * `answer` is model- or caller-supplied, so this is a single linear scan rather
16
+ * than a regex: alternations like `\(<[^>]*>\)` / `[ \t]*\[` backtrack
17
+ * quadratically on inputs such as repeated `(<` or long whitespace runs.
18
+ */
19
+ export type AnswerMarker = {
20
+ readonly kind: "number";
21
+ readonly start: number;
22
+ readonly end: number;
3
23
  readonly number: number;
4
- }[]): number[];
24
+ } | {
25
+ readonly kind: "evidence";
26
+ readonly start: number;
27
+ readonly end: number;
28
+ readonly ids: readonly string[];
29
+ } | {
30
+ readonly kind: "file";
31
+ readonly start: number;
32
+ readonly end: number;
33
+ readonly path: string;
34
+ };
35
+ /** Every citation marker in `answer`, in order. `isFile` decides which `[file:...]` paths are real. */
36
+ export declare function answerMarkers(answer: string, isFile?: (path: string) => boolean): AnswerMarker[];
5
37
  /** Remove citation markers whose number has no matching result. */
6
38
  export declare function stripUnresolvedCitations(answer: string, results: readonly {
7
39
  readonly number: number;
@@ -11,10 +43,13 @@ export declare function stripUnresolvedCitations(answer: string, results: readon
11
43
  };
12
44
  export declare function formatCitationList(numbers: readonly number[]): string;
13
45
  /**
14
- * Throw a corrective error when `answer` cites numbers absent from `results`.
15
- * Emit tools surface the message to the model as a tool error so it re-emits
16
- * with one consistent numbering.
46
+ * Throw a corrective error unless `results` and `mapping` carry the same
47
+ * numbers, exactly one entry each. Duplicates are rejected even when both
48
+ * sides repeat them: a repeated number collapses into a single registry entry,
49
+ * so the other entry's evidence would be lost.
17
50
  */
18
- export declare function assertCitationsResolve(label: string, answer: string, results: readonly {
51
+ export declare function assertResultsMappingOneToOne(label: string, results: readonly {
52
+ readonly number: number;
53
+ }[], mapping: readonly {
19
54
  readonly number: number;
20
55
  }[]): void;
@@ -1,42 +1,56 @@
1
- import type { AgentTool, Skill } from "@earendil-works/pi-agent-core";
1
+ import type { AgentTool } from "@earendil-works/pi-agent-core";
2
2
  import { Type } from "typebox";
3
3
  import type { DatasourceSkillManifest } from "../datasource/types.js";
4
4
  export declare const LOAD_DATASOURCE_SKILL_TOOL_NAME = "load_datasource_skill";
5
5
  /**
6
- * Opaque, path-free location used as the Pi `Skill.filePath` for a datasource
7
- * skill. Datasource skills have no real backing file, and AutoRAG must never
6
+ * A datasource skill as the agent sees it: name and description for the
7
+ * system-prompt listing, full `content` loaded on demand, and an opaque
8
+ * `datasource://` location. pi's own `Skill` is file-backed (`baseDir`,
9
+ * `sourceInfo`) and has no `content`, so datasource skills, which have no
10
+ * backing file, use this shape instead.
11
+ */
12
+ export interface DatasourceAgentSkill {
13
+ readonly name: string;
14
+ readonly description: string;
15
+ /** Full skill instructions, returned by `load_datasource_skill`. */
16
+ readonly content: string;
17
+ /** Opaque `datasource://<name>` location; never a real filesystem path. */
18
+ readonly filePath: string;
19
+ }
20
+ /**
21
+ * Opaque, path-free location used as the `filePath` of a datasource skill.
22
+ * Datasource skills have no real backing file, and AutoRAG must never
8
23
  * expose real filesystem paths, so we use a `datasource://<name>` scheme.
9
24
  */
10
25
  export declare function datasourceSkillLocation(name: string): string;
11
26
  /**
12
- * Map a datasource skill manifest onto the Pi agent-skill layer. The resulting
13
- * `Skill` is injected into the system prompt (name/description/location) for
27
+ * Map a datasource skill manifest onto the agent-skill shape. The resulting
28
+ * skill is listed in the system prompt (name/description/location) for
14
29
  * progressive disclosure and its `content` is loaded on demand.
15
30
  */
16
- export declare function toDatasourceAgentSkill(manifest: DatasourceSkillManifest): Skill;
31
+ export declare function toDatasourceAgentSkill(manifest: DatasourceSkillManifest): DatasourceAgentSkill;
17
32
  /**
18
- * Render the Pi `<available_skills>` progressive-disclosure block for the
19
- * authorized datasource skills using Pi's own formatter, so datasource skills
20
- * sit on the exact same layer as file-backed agent skills.
33
+ * Render the `<available_skills>` progressive-disclosure block for the
34
+ * configured datasource skills, in the same format pi uses for file-backed
35
+ * agent skills, so datasource skills sit on the same layer.
21
36
  */
22
- export declare function buildDatasourceSkillsPrompt(skills: readonly Skill[]): string;
37
+ export declare function buildDatasourceSkillsPrompt(skills: readonly DatasourceAgentSkill[]): string;
23
38
  /**
24
- * Format the full instructions for a loaded datasource skill, matching Pi's
39
+ * Format the full instructions for a loaded datasource skill, matching pi's
25
40
  * `<skill …>` invocation shape but with a path-opaque location (no real
26
41
  * filesystem reference, so no "references are relative to …" line).
27
42
  */
28
- export declare function formatDatasourceSkillInvocation(skill: Skill): string;
43
+ export declare function formatDatasourceSkillInvocation(skill: DatasourceAgentSkill): string;
29
44
  export interface LoadDatasourceSkillDetails {
30
45
  readonly skill: string;
31
46
  readonly loaded: boolean;
32
47
  }
33
48
  export interface DatasourceSkillProvider {
34
49
  /**
35
- * Resolve an authorized datasource skill by model-visible name. Returns
36
- * `undefined` when the name is unknown or not authorized by the trusted,
37
- * server-bound access context (default-deny).
50
+ * Resolve a configured datasource skill by model-visible name. Returns
51
+ * `undefined` when the name is unknown or not configured.
38
52
  */
39
- loadDatasourceSkill(name: string): Skill | undefined;
53
+ loadDatasourceSkill(name: string): DatasourceAgentSkill | undefined;
40
54
  }
41
55
  declare const loadDatasourceSkillSchema: Type.TObject<{
42
56
  name: Type.TString;