@autorag/librarian 2.9.0 → 2.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/LICENSE +195 -21
  2. package/NOTICE +17 -21
  3. package/README.md +372 -143
  4. package/dist/agent/agent.d.ts +93 -22
  5. package/dist/agent/answer-citations.d.ts +22 -0
  6. package/dist/agent/answer-guidelines.d.ts +9 -9
  7. package/dist/agent/citations.d.ts +35 -23
  8. package/dist/agent/context-token-guard.d.ts +23 -0
  9. package/dist/agent/evidence-ledger.d.ts +7 -12
  10. package/dist/agent/index.d.ts +2 -2
  11. package/dist/agent/jev-extension.d.ts +5 -4
  12. package/dist/agent/jikji-find-tool.d.ts +1 -0
  13. package/dist/agent/pi-session.d.ts +35 -2
  14. package/dist/agent/request-limits.d.ts +20 -0
  15. package/dist/agent/{emit-results-tool.d.ts → results.d.ts} +5 -40
  16. package/dist/agent/search-all-tool.d.ts +1 -0
  17. package/dist/agent/search-documents.d.ts +14 -19
  18. package/dist/agent/search-single-datasource-tool.d.ts +1 -0
  19. package/dist/agent/self-config.d.ts +1 -1
  20. package/dist/cli/commands/report.d.ts +1 -1
  21. package/dist/cli/commands/tui.d.ts +3 -2
  22. package/dist/cli/config.d.ts +13 -11
  23. package/dist/cli/index.js +3939 -1684
  24. package/dist/cloud/authorize.d.ts +12 -0
  25. package/dist/cloud/callback-server.d.ts +33 -0
  26. package/dist/cloud/callback.d.ts +23 -0
  27. package/dist/cloud/config.d.ts +41 -0
  28. package/dist/cloud/errors.d.ts +46 -0
  29. package/dist/cloud/index.d.ts +12 -0
  30. package/dist/cloud/jev-backend.d.ts +90 -0
  31. package/dist/cloud/models.d.ts +32 -0
  32. package/dist/cloud/oauth-login.d.ts +22 -0
  33. package/dist/cloud/pkce.d.ts +20 -0
  34. package/dist/cloud/provider.d.ts +40 -0
  35. package/dist/cloud/token.d.ts +22 -0
  36. package/dist/core.d.ts +2 -5
  37. package/dist/core.js +3803 -1613
  38. package/dist/datasource/crawler-skill.d.ts +17 -0
  39. package/dist/datasource/sidecar/config.d.ts +26 -0
  40. package/dist/datasource/sidecar/descriptors.d.ts +67 -0
  41. package/dist/datasource/sidecar/fusion.d.ts +25 -0
  42. package/dist/datasource/sidecar/index.d.ts +131 -0
  43. package/dist/datasource/sidecar/methods.d.ts +27 -0
  44. package/dist/datasource/types.d.ts +3 -1
  45. package/dist/embedding-runtime/index.d.ts +6 -6
  46. package/dist/embedding-runtime/manifest.d.ts +0 -12
  47. package/dist/embedding-runtime/types.d.ts +1 -1
  48. package/dist/index.d.ts +2 -1
  49. package/dist/index.js +3982 -1676
  50. package/dist/mcp/index.js +3908 -1662
  51. package/dist/minsync/client.d.ts +3 -3
  52. package/dist/minsync/installer.d.ts +1 -1
  53. package/dist/minsync/process.d.ts +1 -0
  54. package/dist/minsync/types.d.ts +1 -1
  55. package/dist/observability/run-log.d.ts +1 -1
  56. package/dist/parser/defaults.d.ts +6 -4
  57. package/dist/parser/ocr-engines.d.ts +6 -0
  58. package/dist/retrieval/index.d.ts +2 -2
  59. package/dist/retrieval/rerank.d.ts +20 -3
  60. package/dist/retrieval/types.d.ts +0 -23
  61. package/licenses/embedding-assets.json +0 -35
  62. package/package.json +24 -27
  63. package/skills/autorag/SKILL.md +1 -1
  64. package/skills/autorag-doctor/SKILL.md +1 -1
  65. package/skills/autorag-lite-setup/SKILL.md +2 -2
  66. package/skills/autorag-setup/SKILL.md +3 -3
  67. package/dist/agent/fast-answer-tool.d.ts +0 -56
  68. package/licenses/gemma-notice.txt +0 -24
  69. package/licenses/gemma-section-3.2-flow-down.txt +0 -9
  70. package/licenses/gemma-terms-of-use.html +0 -4750
  71. package/licenses/gemma-terms-of-use.txt +0 -158
@@ -1,5 +1,5 @@
1
1
  import type { Agent, AgentTool } from "@earendil-works/pi-agent-core";
2
- import type { Api, Model } from "@earendil-works/pi-ai";
2
+ import type { Api, ImageContent, Model } from "@earendil-works/pi-ai";
3
3
  import type { DatasourceIndexResult, DatasourceSkill } from "../datasource/types.js";
4
4
  import { type DupeyCliOptions } from "../dupey/index.js";
5
5
  import { type Embedder } from "../embedding-runtime/gateway-embedder.js";
@@ -17,10 +17,9 @@ import { type DefaultParserRegistryOptions } from "../parser/index.js";
17
17
  import { RetrievalEngine } from "../retrieval/engine.js";
18
18
  import { RetrievalMethodRegistry } from "../retrieval/registry.js";
19
19
  import type { DatasourceCatalogEntry } from "../retrieval/selection.js";
20
- import type { CuratedResult, RetrievalDiagnostic, RetrievalOptions, RetrievalResult } from "../retrieval/types.js";
20
+ import type { RetrievalDiagnostic, RetrievalOptions, RetrievalResult } from "../retrieval/types.js";
21
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";
@@ -255,10 +254,10 @@ export interface AutoRAGAgentOptions {
255
254
  memoryEmbedder?: Embedder | false;
256
255
  /**
257
256
  * 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.
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.
262
261
  */
263
262
  selfConfig?: SelfConfigOptions;
264
263
  /**
@@ -356,13 +355,20 @@ export declare class AutoRAGAgent {
356
355
  private readonly runLogger;
357
356
  private lastQuery;
358
357
  private lastSessionId;
359
- private readonly sessions;
360
358
  private activeRun;
361
- private resultCapture;
362
- private interactiveFastAnswerCallback;
359
+ /**
360
+ * Steering state of the running search. A TUI query runs detached from pi's
361
+ * input loop (pi reads the next input only after its input handler returns),
362
+ * so input typed meanwhile steers this run (Enter) or waits behind it
363
+ * (Alt+Enter), the way pi steers its own turns. {@link steer} feeds the same
364
+ * state for `searchDocuments()` / `searchDocumentsStream()` callers.
365
+ */
366
+ private readonly interactive;
367
+ /** Aborted by {@link abort} and by the run's timeout: gates publishing and the run's own requests. */
368
+ private activeRunAbort;
363
369
  private modelNativeSearchAuth;
364
370
  private retrievalTrace;
365
- /** Evidence every retrieval tool returned this run; emit tools resolve model-cited ids against it. */
371
+ /** Evidence every retrieval tool returned this run; the answer's inline `[eN]` citations resolve against it. */
366
372
  private readonly evidenceLedger;
367
373
  private preliminaryCallback;
368
374
  /** Per-phase thinking levels of the two-phase search. */
@@ -474,8 +480,69 @@ export declare class AutoRAGAgent {
474
480
  private currentSystemPromptConfig;
475
481
  subscribe(listener: Parameters<Agent["subscribe"]>[0]): () => void;
476
482
  createPiInteractiveRuntime(): Promise<AutoRAGPiInteractiveRuntime>;
483
+ /**
484
+ * The session's custom tools, with retrieval and web reads interruptible by a
485
+ * steer: stopping them loses no side effect. bash and the file tools are pi
486
+ * built-ins and never pass through here.
487
+ */
488
+ private steerableTools;
489
+ /**
490
+ * Lets a steer cut a retrieval tool short, like an interruptible wait in pi:
491
+ * the tool's signal also aborts on the steer, and the call resolves at once
492
+ * with a skipped result telling the model to retry if the search still
493
+ * matters, so the steer reaches the model before the next request.
494
+ */
495
+ private interruptibleBySteer;
496
+ /** Resolve the model's inline `[eN]` citations against this run's evidence and derive the structured results. */
497
+ private deriveAnswer;
498
+ /**
499
+ * Routes one TUI input the way pi routes typed input for its own turns. With
500
+ * no search running it starts one. During a search, Enter steers it (the
501
+ * user is correcting a search that is going wrong) and Alt+Enter queues a
502
+ * follow-up question that runs once this search answers.
503
+ */
504
+ private routeInteractiveInput;
505
+ /**
506
+ * Esc and Alt+Enter during a search. pi handles both itself while a turn
507
+ * streams (abort, queue follow-up); between phases it ignores Esc and submits
508
+ * Alt+Enter like Enter, so AutoRAG acts on them there.
509
+ */
510
+ private handleInteractiveKey;
511
+ /** Runs one TUI query detached from pi's input loop, then any follow-ups queued behind it. */
512
+ private startInteractiveQuery;
513
+ /**
514
+ * Drives one TUI query through the two-phase search. The model's own
515
+ * assistant messages (progress notes before a tool call, the fast answer,
516
+ * the final answer) are already recorded and rendered by the bound pi
517
+ * session, so nothing is re-sent here: a second copy would show every answer
518
+ * twice and put it in the model's context twice.
519
+ */
477
520
  private runInteractivePiQuery;
521
+ /** Resolves once the TUI search and every follow-up queued behind it finished. */
522
+ waitForIdle(): Promise<void>;
523
+ /**
524
+ * Steers the running `searchDocuments()` / `searchDocumentsStream()` search,
525
+ * the way Enter steers a TUI search: `text` is a correction of the search in
526
+ * progress, not a new question. It reaches the search's next model request
527
+ * (also between phases, where no turn streams), cuts in-flight retrieval and
528
+ * the baseline prefetch short so it lands promptly, and forces the
529
+ * verification phase, whose prompt restates it. A steer that lands after
530
+ * verification's last request gets one more verification turn in the same
531
+ * search. The final answer stays the answer to the original question.
532
+ *
533
+ * Returns false, and does nothing, when no search is running, the search was
534
+ * stopped, or it is past its last model request; the caller should then ask
535
+ * the text as a new question.
536
+ */
537
+ steer(text: string, images?: readonly ImageContent[]): boolean;
538
+ /**
539
+ * Stops the running search as a whole: the streaming model turn, the
540
+ * baseline prefetch, in-flight retrieval, and every later phase. The search
541
+ * then resolves without a verified answer.
542
+ */
478
543
  abort(): void;
544
+ /** The next model request took the queued steers into the transcript; later retrieval runs uninterrupted until the next steer. */
545
+ private steersReachedModel;
479
546
  /**
480
547
  * Periodically re-runs the incremental {@link refresh} so parsed mirrors and
481
548
  * indexes stay current. Re-parsing is incremental (mtime/size) via the
@@ -486,13 +553,14 @@ export declare class AutoRAGAgent {
486
553
  }): void;
487
554
  stopAutoRefresh(): void;
488
555
  private runAutoRefreshTick;
489
- getResultRegistry(sessionId?: string): ReadonlyMap<number, CuratedResult>;
490
556
  searchDocuments(query: string, options?: RetrievalOptions): Promise<SearchDocumentsResponse>;
491
557
  /**
492
558
  * Stream bounded progress updates while retaining the stable
493
- * {@link searchDocuments} promise API. Progress is sourced from model text
494
- * deltas, so callers can render it in a TUI, CLI, or parent agent and can
495
- * stop by calling {@link abort}.
559
+ * {@link searchDocuments} promise API. Progress is the text an assistant
560
+ * message wrote before calling a tool (`stopReason: "toolUse"`); a message
561
+ * that ends its turn is an answer, delivered as `preliminary` or
562
+ * `complete`, never as progress. Callers can render it in a TUI, CLI, or
563
+ * parent agent and can stop by calling {@link abort}.
496
564
  */
497
565
  searchDocumentsStream(query: string, options?: RetrievalOptions): AsyncGenerator<SearchDocumentsStreamEvent, void, void>;
498
566
  /**
@@ -529,7 +597,7 @@ export declare class AutoRAGAgent {
529
597
  /** Path-opaque component diagnostics for the search response. */
530
598
  private collectComponentDiagnostics;
531
599
  /**
532
- * Jev check run after emit_fast_answer: does the answer need correction,
600
+ * Jev check run after the fast answer: does the answer need correction,
533
601
  * clarification, or further research? "No" ends the run with the fast
534
602
  * answer as the final answer. Without Jev, or when the check fails, the run
535
603
  * always continues into verification.
@@ -574,14 +642,14 @@ export declare class AutoRAGAgent {
574
642
  private rerankPrefetchPool;
575
643
  /**
576
644
  * Fast-phase prompt for two-phase searches. The baseline retrieval context
577
- * is already gathered, so the model answers immediately with thinking off
578
- * via emit_fast_answer, without any further tool calls.
645
+ * is already gathered, so the model answers immediately with thinking off,
646
+ * as plain text, without any further tool calls.
579
647
  */
580
648
  buildFastAnswerPrompt(query: string, options: RetrievalOptions, baseline: string): string;
581
649
  /**
582
650
  * Prompt for a question Jev routed to a direct answer: general knowledge or
583
651
  * small talk. No retrieval ran and no verification phase follows, so the
584
- * answer emitted here is final.
652
+ * reply is the final answer.
585
653
  */
586
654
  buildDirectAnswerPrompt(query: string): string;
587
655
  /** Discovery-tool hint naming only the registered discovery tools; empty when none. */
@@ -595,10 +663,10 @@ export declare class AutoRAGAgent {
595
663
  /**
596
664
  * Verification-phase prompt for two-phase searches. The fast answer, when a
597
665
  * consumer already received it, is embedded verbatim so the model can diff
598
- * against it; the model then verifies with thinking on and finalizes with
599
- * emit_autorag_results exactly once, returning only the delta.
666
+ * against it; the model then verifies with thinking on and ends with the
667
+ * final answer as a plain reply, returning only the delta.
600
668
  */
601
- buildRefinementPrompt(query: string, options: RetrievalOptions, fastAnswer: AutoRAGFastAnswerDetails | undefined, fastAnswerDelivered: boolean): string;
669
+ buildRefinementPrompt(query: string, options: RetrievalOptions, fastAnswer: string | undefined, fastAnswerDelivered: boolean, steers?: readonly string[]): string;
602
670
  buildSearchPrompt(query: string, options: RetrievalOptions, initialRetrievalContext?: string): string;
603
671
  refresh(force?: boolean, opts?: AutoRAGRefreshOptions): Promise<AutoRAGRefreshResult>;
604
672
  /**
@@ -673,6 +741,7 @@ export declare class AutoRAGAgent {
673
741
  findJikji(query: string, opts?: {
674
742
  readonly topK?: number;
675
743
  readonly first?: boolean;
744
+ readonly signal?: AbortSignal;
676
745
  }): Promise<JikjiFindProviderResult>;
677
746
  /**
678
747
  * Merge per-root answer packs into one. Concatenates answer_paths/candidates
@@ -717,6 +786,7 @@ export declare class AutoRAGAgent {
717
786
  searchAllDocuments(query: string, options?: {
718
787
  readonly topK?: number;
719
788
  readonly scope?: string;
789
+ readonly signal?: AbortSignal;
720
790
  }): Promise<{
721
791
  results: RetrievalResult[];
722
792
  diagnostics: RetrievalDiagnostic[];
@@ -734,6 +804,7 @@ export declare class AutoRAGAgent {
734
804
  searchSingleDatasourceDocuments(datasourceId: string, query: string, options?: {
735
805
  readonly topK?: number;
736
806
  readonly scope?: string;
807
+ readonly signal?: AbortSignal;
737
808
  }): Promise<{
738
809
  results: RetrievalResult[];
739
810
  diagnostics: RetrievalDiagnostic[];
@@ -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;
@@ -10,34 +42,14 @@ export declare function stripUnresolvedCitations(answer: string, results: readon
10
42
  readonly unresolved: readonly number[];
11
43
  };
12
44
  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
45
  /**
23
46
  * Throw a corrective error unless `results` and `mapping` carry the same
24
47
  * numbers, exactly one entry each. Duplicates are rejected even when both
25
48
  * sides repeat them: a repeated number collapses into a single registry entry,
26
49
  * 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
50
  */
31
51
  export declare function assertResultsMappingOneToOne(label: string, results: readonly {
32
52
  readonly number: number;
33
53
  }[], mapping: readonly {
34
54
  readonly number: number;
35
55
  }[]): void;
36
- /**
37
- * Throw a corrective error when `answer` cites numbers absent from `results`.
38
- * Emit tools surface the message to the model as a tool error so it re-emits
39
- * with one consistent numbering.
40
- */
41
- export declare function assertCitationsResolve(label: string, answer: string, results: readonly {
42
- readonly number: number;
43
- }[]): void;
@@ -0,0 +1,23 @@
1
+ import type { AgentMessage } from "@earendil-works/pi-agent-core";
2
+ import type { Model } from "@earendil-works/pi-ai";
3
+ type ContextTokenGuardModel = Model<any> | (() => Model<any> | undefined) | undefined;
4
+ /**
5
+ * Compose an optional context transform with the aggregate token guard. The
6
+ * guard runs on the final transcript immediately before each provider request,
7
+ * so it sees the system prompt, tool declarations, user query, memory context,
8
+ * and every prior tool result.
9
+ */
10
+ export declare function createContextTokenGuardedTransform(model: ContextTokenGuardModel, base?: (messages: AgentMessage[]) => Promise<AgentMessage[]>, fixedOverheadTokens?: () => number): (messages: AgentMessage[]) => Promise<AgentMessage[]>;
11
+ /**
12
+ * Keep complete retrieval candidates while the assembled request fits the
13
+ * model budget. Removing a per-chunk cut is only safe because this drops whole
14
+ * lower-ranked candidates (with an explicit marker) instead of hiding text.
15
+ */
16
+ export declare function guardAgentContextMessages(model: Model<any> | undefined, messages: AgentMessage[], useReportedUsage?: boolean, fixedOverheadTokens?: number): AgentMessage[];
17
+ /**
18
+ * Estimate the current transcript with pi-coding-agent's conservative chars/4
19
+ * counter. `useReportedUsage` adds the last assistant turn's provider-reported
20
+ * usage for the settled prefix; pass false when the messages were just edited.
21
+ */
22
+ export declare function estimateContextMessageTokens(messages: readonly AgentMessage[], useReportedUsage?: boolean): number;
23
+ export {};
@@ -1,5 +1,5 @@
1
1
  import type { RetrievalResult } from "../retrieval/types.js";
2
- import type { AutoRAGEvidenceRef } from "./emit-results-tool.js";
2
+ import type { AutoRAGEvidenceRef } from "./results.js";
3
3
  export interface LedgerEvidenceInput {
4
4
  readonly method: string;
5
5
  readonly source: string;
@@ -13,16 +13,11 @@ export interface LedgerEvidenceInput {
13
13
  readonly evidenceType?: string;
14
14
  readonly evidenceLocation?: string;
15
15
  }
16
- export interface ResolveEvidenceOptions {
17
- /** Tool name used to prefix corrective errors. */
18
- readonly label: string;
19
- /** Result number the refs belong to; named in corrective errors. */
20
- readonly number: number;
21
- /** Excerpt recorded for a local file the model opened itself (no search returned it). */
22
- readonly fallbackContent: string;
16
+ export interface LookupEvidenceOptions {
23
17
  /** False in remote sessions: only evidence a tool returned this run may be cited. */
24
18
  readonly allowLocalFiles: boolean;
25
19
  }
20
+ export declare function isRegularFile(path: string): boolean;
26
21
  /**
27
22
  * Per-run record of every piece of evidence a retrieval tool returned.
28
23
  *
@@ -47,13 +42,13 @@ export declare class EvidenceLedger {
47
42
  /** Record one retrieval result as returned by `tool`; backend metadata is carried over. */
48
43
  registerResult(tool: string, result: RetrievalResult): string;
49
44
  /**
50
- * Resolve model-supplied refs to recorded evidence. A ref is an evidence id
45
+ * Resolve one cited reference to recorded evidence. A ref is an evidence id
51
46
  * (`e3` or `[e3]`), the exact source a tool returned (a URL, a datasource
52
47
  * id, a path), or the absolute path of a real local file the model opened
53
- * itself. Anything else throws a corrective error naming the result.
48
+ * itself. Returns an empty list when nothing matches: the caller drops the
49
+ * citation instead of failing the run.
54
50
  */
55
- resolve(refs: readonly string[], options: ResolveEvidenceOptions): AutoRAGEvidenceRef[];
51
+ lookup(raw: string, options: LookupEvidenceOptions): AutoRAGEvidenceRef[];
56
52
  /** Forget every recorded entry. Ids are never reissued, so a previous run's id stays unresolvable. */
57
53
  clear(): void;
58
- private unresolvedMessage;
59
54
  }
@@ -2,11 +2,11 @@ export type { AutoRAGAgentOptions, AutoRefreshOptions, PeerQueryOptions } from "
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
4
  export { createScanDuplicateDocumentsTool, SCAN_DUPLICATE_DOCUMENTS_TOOL_NAME, type ScanDuplicateDocumentsDetails, type ScanDuplicateDocumentsProvider, } from "./dupey-tool.js";
5
- export type { AutoRAGEmittedResult, AutoRAGMappingEntry, AutoRAGResultsDetails, } from "./emit-results-tool.js";
6
- export { createEmitResultsTool, EMIT_AUTORAG_RESULTS_TOOL_NAME, emitResultsSchema, reportSchema, } from "./emit-results-tool.js";
7
5
  export { createJevExtension, JEV_TOOL_NAME, type JevBackendName, type JevToolOptions, } from "./jev-extension.js";
8
6
  export { createJikjiFindTool, JIKJI_FIND_TOOL_NAME, type JikjiFindDetails, type JikjiFindPerRootPolicy, type JikjiFindProvider, type JikjiFindProviderResult, type MergedJikjiPolicy, } from "./jikji-find-tool.js";
9
7
  export { createQueryPeerAgentTool, QUERY_PEER_AGENT_TOOL_NAME, type QueryPeerAgentDetails, type QueryPeerAgentResult, type QueryPeerAgentToolOptions, } from "./query-peer-tool.js";
8
+ export type { AutoRAGEmittedResult, AutoRAGMappingEntry, AutoRAGResultsDetails, } from "./results.js";
9
+ export { reportSchema } from "./results.js";
10
10
  export { createSearchAllDocumentsTool, SEARCH_ALL_DOCUMENTS_TOOL_NAME, type SearchAllDocumentsDetails, type SearchAllDocumentsProvider, type SearchAllDocumentsResult, } from "./search-all-tool.js";
11
11
  export type { SearchDocumentDiagnostic, SearchDocumentDiagnosticCode, SearchDocumentDiagnosticSeverity, SearchDocumentEvidence, SearchDocumentResult, SearchDocumentsResponse, SearchDocumentsStreamEvent, SearchDocumentWarning, } from "./search-documents.js";
12
12
  export { createSearchMinSyncDocumentsTool, SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME, type SearchMinSyncDocumentsDetails, } from "./search-minsync-tool.js";
@@ -4,9 +4,10 @@ import { type JevBackend, type Judgment, type Question, type State } from "jev-u
4
4
  export declare const JEV_TOOL_NAME = "jev";
5
5
  /**
6
6
  * Jev backends the `jev-use` engine resolves from the environment, in
7
- * auto-select order: TypeSafe -> OpenRouter -> Vercel AI Gateway.
7
+ * auto-select order: TypeSafe -> OpenRouter -> Vercel AI Gateway. `autorag` is
8
+ * the hosted AutoRAG (Dazzi) plan, built here rather than resolved by jev-use.
8
9
  */
9
- export type JevBackendName = "typesafe" | "openrouter" | "vercel";
10
+ export type JevBackendName = "typesafe" | "openrouter" | "vercel" | "autorag";
10
11
  /**
11
12
  * OpenRouter's live Jev model id. `jev-use` 0.8.0 ships `typesafe/jev-latest`,
12
13
  * which OpenRouter rejects with HTTP 400 ("Model ... does not exist"), so the
@@ -51,8 +52,8 @@ export type JevJudge = (state: State, questions: Question[], options?: {
51
52
  /**
52
53
  * Builds the Jev judge shared by the `jev` tool and the query router. The
53
54
  * `jev-use` client is created lazily on the first call, so no credential
54
- * resolves at construction time, and the OpenRouter model pin applies to
55
- * every caller.
55
+ * resolves at construction time, and the per-backend model default (the
56
+ * OpenRouter pin, or `jev-1.13` on the hosted plan) applies to every caller.
56
57
  */
57
58
  export declare function createJevJudge(options?: JevJudgeOptions): JevJudge;
58
59
  /**
@@ -44,6 +44,7 @@ export interface JikjiFindProvider {
44
44
  findJikji(query: string, opts?: {
45
45
  readonly topK?: number;
46
46
  readonly first?: boolean;
47
+ readonly signal?: AbortSignal;
47
48
  }): Promise<JikjiFindProviderResult>;
48
49
  }
49
50
  export interface JikjiFindDetails {
@@ -1,5 +1,5 @@
1
1
  import type { AgentMessage, AgentTool } from "@earendil-works/pi-agent-core";
2
- import type { Api, Model } from "@earendil-works/pi-ai";
2
+ import type { Api, ImageContent, Model } from "@earendil-works/pi-ai";
3
3
  import { type AgentSession, type AgentSessionRuntime, type ExtensionAPI, type ExtensionFactory, SettingsManager, type ToolDefinition, type TuiMode } from "@earendil-works/pi-coding-agent";
4
4
  export declare const PI_BUILTIN_TOOL_NAMES: readonly ["read", "bash", "edit", "write", "grep", "find", "ls"];
5
5
  /**
@@ -34,10 +34,43 @@ export interface AutoRAGPiSessionOptions {
34
34
  readonly remoteSession?: boolean;
35
35
  readonly contextTransform?: (messages: AgentMessage[]) => Promise<AgentMessage[]>;
36
36
  }
37
+ /**
38
+ * How AutoRAG takes one interactive input. `steer` while a pi turn streams
39
+ * returns the text pi should queue as steering (pi delivers it before the
40
+ * turn's next model request); every other outcome is fully handled by AutoRAG.
41
+ */
42
+ export type AutoRAGInputDisposition = {
43
+ readonly kind: "handled";
44
+ } | {
45
+ readonly kind: "steer";
46
+ readonly text: string;
47
+ };
48
+ export interface AutoRAGInteractiveInput {
49
+ readonly text: string;
50
+ readonly images: readonly ImageContent[] | undefined;
51
+ /** pi's delivery for input typed while a turn streams; undefined when no turn streams. */
52
+ readonly streamingBehavior: "steer" | "followUp" | undefined;
53
+ }
54
+ /** A TUI key AutoRAG acts on itself while a search runs, even when no pi turn streams. */
55
+ export type AutoRAGInteractiveKey = "interrupt" | "followUp";
37
56
  export interface AutoRAGPiInteractiveRuntimeOptions extends Omit<AutoRAGPiSessionOptions, "model"> {
38
57
  readonly model?: Model<Api>;
39
58
  readonly inactiveToolNames?: readonly string[];
40
- readonly onQuery: (query: string, pi: ExtensionAPI) => void | Promise<void>;
59
+ /**
60
+ * Routes one interactive input: a new query, a steer of the running search,
61
+ * or a follow-up queued behind it. Must not wait for a search to finish:
62
+ * pi's TUI reads the next input only after this returns.
63
+ */
64
+ readonly onInput: (input: AutoRAGInteractiveInput, pi: ExtensionAPI) => AutoRAGInputDisposition;
65
+ /** Whether a search is running: while it is, every interactive input belongs to it. */
66
+ readonly isSearchRunning?: () => boolean;
67
+ /**
68
+ * Called for pi's interrupt (Esc) and follow-up (Alt+Enter) keys while a
69
+ * search runs. pi acts on them only while a turn streams, but a search also
70
+ * spends time between turns (routing, prefetch, checks). Return true to
71
+ * consume the key; pi then never sees it.
72
+ */
73
+ readonly onKey?: (key: AutoRAGInteractiveKey) => boolean;
41
74
  /**
42
75
  * Optional best-effort provider for a startup update notice. Resolves to the
43
76
  * notice text, or `undefined` when there is nothing to announce. Called once
@@ -0,0 +1,20 @@
1
+ import type { AgentMessage } from "@earendil-works/pi-agent-core";
2
+ import type { ModelInputLimits } from "@earendil-works/pi-ai";
3
+ /** Stands in for an image dropped from a model request by {@link fitRequestLimits}. */
4
+ export declare const IMAGE_OMITTED_NOTE = "[Image omitted from this request to stay within the model provider's request limits. Read the file again if you still need to see it.]";
5
+ /**
6
+ * Fits a model request into the provider's declared `inputLimits`.
7
+ *
8
+ * pi keeps every image a tool returned in the transcript and resends all of
9
+ * them on each later turn, but it never enforces `maxRequestBytes` or
10
+ * `images.maxPerRequest`. A search that reads a handful of photos therefore
11
+ * grows past a provider's body limit and the request fails outright (the hosted
12
+ * AutoRAG API answers HTTP 413). Images are what grows the body, so the oldest
13
+ * ones are replaced with {@link IMAGE_OMITTED_NOTE} until the request fits; the
14
+ * newest images, which the model is looking at, go last. Text is never touched.
15
+ *
16
+ * The size is the serialized transcript, a close lower bound of the provider
17
+ * body, so `maxRequestBytes` should keep headroom below the hard limit.
18
+ * Returns undefined when the request already fits; never mutates `messages`.
19
+ */
20
+ export declare function fitRequestLimits(messages: readonly AgentMessage[], limits: ModelInputLimits | undefined): AgentMessage[] | undefined;
@@ -1,33 +1,11 @@
1
- import type { AgentTool } from "@earendil-works/pi-agent-core";
2
1
  import { Type } from "typebox";
3
- import type { EvidenceLedger } from "./evidence-ledger.js";
4
- export declare const EMIT_AUTORAG_RESULTS_TOOL_NAME = "emit_autorag_results";
5
- /**
6
- * Model-facing schema of `emit_autorag_results`. The model cites evidence by
7
- * the short ids retrieval tools print next to each result (`refs`); the
8
- * harness resolves them to the recorded source, method, and chunk, so the
9
- * model never retypes a path or a chunk.
10
- */
11
- export declare const emitResultsSchema: Type.TObject<{
12
- answer: Type.TString;
13
- results: Type.TArray<Type.TObject<{
14
- number: Type.TInteger;
15
- title: Type.TString;
16
- summary: Type.TString;
17
- evidence: Type.TArray<Type.TObject<{
18
- excerpt: Type.TString;
19
- lineNumber: Type.TOptional<Type.TInteger>;
20
- }>>;
21
- confidence: Type.TNumber;
22
- refs: Type.TArray<Type.TString>;
23
- }>>;
24
- warnings: Type.TOptional<Type.TArray<Type.TString>>;
25
- }>;
26
2
  /**
27
3
  * Report schema with the explicit number -> source mapping. This is the
28
4
  * persisted/typed shape and the input contract of `autorag report` and the MCP
29
5
  * report tool, where an external agent curated the evidence and no harness
30
- * ledger exists.
6
+ * ledger exists. The librarian itself never produces this shape from the
7
+ * model: it writes a plain answer and the harness derives the results from the
8
+ * evidence ids the answer cites.
31
9
  */
32
10
  export declare const reportSchema: Type.TObject<{
33
11
  answer: Type.TString;
@@ -75,7 +53,8 @@ export interface AutoRAGEmittedResult {
75
53
  readonly title: string;
76
54
  readonly summary: string;
77
55
  readonly evidence: readonly AutoRAGEmittedEvidence[];
78
- readonly confidence: number;
56
+ /** Absent for results the harness derived from cited evidence: nothing measured a confidence. */
57
+ readonly confidence?: number;
79
58
  }
80
59
  export interface AutoRAGEvidenceRef {
81
60
  readonly method: string;
@@ -107,17 +86,3 @@ export interface AutoRAGResultsDetails {
107
86
  readonly mapping: readonly AutoRAGMappingEntry[];
108
87
  readonly warnings: readonly string[];
109
88
  }
110
- export interface EmitResultsToolOptions {
111
- /** Evidence the run's retrieval tools returned; `refs` resolve against it. */
112
- readonly ledger: EvidenceLedger;
113
- /** False in remote sessions: only evidence a tool returned this run may be cited. */
114
- readonly allowLocalFiles: boolean;
115
- }
116
- /**
117
- * Builds the terminating structured-result tool. The model calls this exactly
118
- * once as its final action; the typed `details` plus `terminate: true` end the
119
- * Pi Agent run and hand the curated results back through `capture` — no
120
- * assistant-text parsing involved. The number -> source mapping is built here
121
- * from the harness-held evidence the model cited by id, never from model text.
122
- */
123
- export declare function createEmitResultsTool(capture: (details: AutoRAGResultsDetails) => void, options: EmitResultsToolOptions): AgentTool<typeof emitResultsSchema, AutoRAGResultsDetails>;
@@ -18,6 +18,7 @@ export interface SearchAllDocumentsProvider {
18
18
  searchAllDocuments(query: string, options?: {
19
19
  readonly topK?: number;
20
20
  readonly scope?: string;
21
+ readonly signal?: AbortSignal;
21
22
  }): Promise<SearchAllDocumentsResult>;
22
23
  }
23
24
  export interface SearchAllDocumentsDetails {