@autorag/librarian 2.13.6 → 2.13.8

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 (52) hide show
  1. package/README.md +15 -0
  2. package/dist/agent/agent.d.ts +35 -5
  3. package/dist/agent/calculator-tool.d.ts +39 -0
  4. package/dist/agent/dupey-tool.d.ts +0 -2
  5. package/dist/agent/evidence-ledger.d.ts +11 -0
  6. package/dist/agent/index-schedule.d.ts +45 -0
  7. package/dist/agent/index.d.ts +1 -0
  8. package/dist/agent/pipelined-sync.d.ts +34 -0
  9. package/dist/agent/result-render.d.ts +43 -0
  10. package/dist/agent/search-all-tool.d.ts +2 -1
  11. package/dist/agent/search-documents.d.ts +1 -1
  12. package/dist/agent/search-minsync-tool.d.ts +2 -1
  13. package/dist/agent/search-single-datasource-tool.d.ts +2 -1
  14. package/dist/agent/watch-refresh.d.ts +2 -0
  15. package/dist/calculator/civil.d.ts +27 -0
  16. package/dist/calculator/decimal.d.ts +47 -0
  17. package/dist/calculator/errors.d.ts +4 -0
  18. package/dist/calculator/expression.d.ts +11 -0
  19. package/dist/calculator/index.d.ts +17 -0
  20. package/dist/calculator/operations.d.ts +36 -0
  21. package/dist/calculator/temporal.d.ts +18 -0
  22. package/dist/calculator/timezone.d.ts +19 -0
  23. package/dist/cli/commands/duplicates.d.ts +2 -3
  24. package/dist/cli/commands/index.d.ts +1 -1
  25. package/dist/cli/commands/lite-refresh.d.ts +1 -1
  26. package/dist/cli/commands/refresh.d.ts +4 -0
  27. package/dist/cli/commands/watch.d.ts +2 -1
  28. package/dist/cli/index.js +3617 -1480
  29. package/dist/cli/signal-abort.d.ts +21 -0
  30. package/dist/core.d.ts +2 -0
  31. package/dist/core.js +4144 -2097
  32. package/dist/datasource/skills/factory.d.ts +4 -1
  33. package/dist/dupey/filter.d.ts +0 -2
  34. package/dist/dupey/index.d.ts +0 -1
  35. package/dist/dupey/version.d.ts +17 -0
  36. package/dist/index.js +4183 -2144
  37. package/dist/mcp/index.js +4182 -2142
  38. package/dist/mcp/server.d.ts +0 -3
  39. package/dist/minsync/installer.d.ts +1 -1
  40. package/dist/minsync/method.d.ts +7 -0
  41. package/dist/minsync/version.d.ts +3 -2
  42. package/dist/mirror/cloud-fingerprints.d.ts +6 -5
  43. package/dist/mirror/cloud.d.ts +9 -6
  44. package/dist/mirror/sync.d.ts +28 -15
  45. package/dist/profiles.js +3463 -1421
  46. package/dist/retrieval/engine.d.ts +7 -0
  47. package/dist/retrieval/merger.d.ts +6 -0
  48. package/dist/retrieval/record-cut.d.ts +101 -0
  49. package/package.json +1 -1
  50. package/skills/autorag/SKILL.md +28 -0
  51. package/skills/autorag-setup/SKILL.md +39 -0
  52. package/dist/dupey/scan-plan.d.ts +0 -23
package/README.md CHANGED
@@ -207,6 +207,7 @@ AutoRAG Agent orchestrates five integrated subsystems:
207
207
  - **Jikji Find-First Discovery:** Local CLI-backed fast discovery answer packs.
208
208
  - **Everything File-Name Search (Windows):** The bundled [voidtools Everything](https://www.voidtools.com/) indexes file and folder names under your search roots so the agent finds files by name, extension, path, size, or date instantly (`everything_search`).
209
209
  - **FSearch File-Name Search (macOS/Linux):** [fsearch-cli](https://github.com/NomaDamas/fsearch-mac) (FSearch) keeps a live, per-workspace name index of your search roots so the agent finds files by name, extension, path, size, or date instantly (`fsearch_search`); without fsearch-cli installed it degrades to a slow filesystem walk.
210
+ - **Calculator:** Exact decimal arithmetic (40 significant digits, no floating-point drift) plus calendar and clock math — days between dates, date offsets with month-end clamping, weekdays, ISO weeks, business days with holidays, the current time, and DST-aware time zone conversion — through the `calculator` tool. The system prompt, including the fast-answer phase, orders the model to compute every number and date with it instead of in its head. It runs in-process, reads no files, and needs no configuration.
210
211
  - **Datasource Skills:** Federated retrieval across every configured external datasource.
211
212
  3. **Result Merger & Scope Narrowing:** Cross-method deduplication, score normalization, and ordinary query-scope narrowing.
212
213
  4. **Direct Evidence Reading (`bash`):** The agent directly opens and inspects promising files with `cat`, `grep`, or `find` to verify facts against ground truth.
@@ -286,6 +287,20 @@ autorag refresh
286
287
  autorag status
287
288
  ```
288
289
 
290
+ ### Indexing only when you want it (power and time schedule)
291
+
292
+ Background indexing (`autorag watch`, auto-refresh, the fs watcher) can be limited by power source and local time. An explicit `autorag refresh` is never gated.
293
+
294
+ ```jsonc
295
+ // ~/.autorag/config.json
296
+ { "refresh": { "schedule": { "power": "ac", "windows": ["22:00-07:00"], "days": ["mon","tue","wed","thu","fri"] } } }
297
+ ```
298
+
299
+ - `power`: `any` (default) or `ac` (index only while plugged in; pauses on battery). An unknown power source (desktop, probe failure) counts as plugged in.
300
+ - `windows`: local `HH:MM-HH:MM`, start inclusive, end exclusive; `22:00-07:00` wraps midnight and belongs to the day it starts on.
301
+ - `days`: `sun`..`sat`. Omit for every day.
302
+ - `autorag watch --power ac --window 22:00-07:00 --days mon,tue` overrides the config. `--once` while closed prints `skipped` and exits 0; a long-running watcher defers changes and indexes once the schedule opens.
303
+
289
304
  ### Excluding files and folders
290
305
 
291
306
  Leave generated workspaces or archives out when initializing:
@@ -14,12 +14,14 @@ import { type MinSyncSyncProgress, type MinSyncSyncResult, type MinSyncVectorMet
14
14
  import { type ParsedMirrorSyncOptions, type ParsedMirrorSyncResult } from "../mirror/sync.js";
15
15
  import { type DefaultParserRegistryOptions } from "../parser/index.js";
16
16
  import { RetrievalEngine } from "../retrieval/engine.js";
17
+ import { type RecordCutOptions } from "../retrieval/record-cut.js";
17
18
  import { RetrievalMethodRegistry } from "../retrieval/registry.js";
18
19
  import type { DatasourceCatalogEntry } from "../retrieval/selection.js";
19
20
  import type { RetrievalDiagnostic, RetrievalOptions, RetrievalResult } from "../retrieval/types.js";
20
21
  import { type ConvertFilesDetails } from "./convert-tool.js";
21
22
  import { type DatasourceAgentSkill } from "./datasource-skill.js";
22
23
  import { type ScanDuplicateDocumentsDetails } from "./dupey-tool.js";
24
+ import { type IndexSchedule, type ScheduleDecision } from "./index-schedule.js";
23
25
  import { type JevToolOptions } from "./jev-extension.js";
24
26
  import { type JikjiFindProviderResult } from "./jikji-find-tool.js";
25
27
  import { type PackagedAgentSkill } from "./packaged-skill.js";
@@ -50,12 +52,12 @@ export interface AutoRAGRefreshLimits {
50
52
  /** Retries for a transient per-file I/O error (EMFILE/EBUSY/EIO/ETIMEDOUT) before the file is skipped. Default 3. */
51
53
  readonly transientRetries?: number;
52
54
  /**
53
- * Most cloud-file placeholders (files whose data is not on disk) one refresh may download.
54
- * Reading a placeholder downloads it, so this bounds disk and network use per refresh; the rest wait
55
- * for the next one. Default 200.
55
+ * Most cloud-file placeholders (files whose data is not on disk) one refresh batch may download.
56
+ * Reading a placeholder downloads it; the next one over the budget starts a new batch, so every
57
+ * placeholder is still read in the same refresh. Default 200.
56
58
  */
57
59
  readonly cloudMaxFiles?: number;
58
- /** Most placeholder bytes one refresh may download; the first file is always allowed. Default 536870912 (512 MiB). */
60
+ /** Most placeholder bytes one refresh batch may download; a batch's first file is always allowed. Default 536870912 (512 MiB). */
59
61
  readonly cloudMaxBytes?: number;
60
62
  /** Release a downloaded cloud file again once it is parsed and indexed. Default true. */
61
63
  readonly cloudEvictAfterParse?: boolean;
@@ -65,6 +67,12 @@ export interface AutoRAGRefreshLimits {
65
67
  * disk and `cloud-evict-failed` is reported. `0` tries once. Default 3.
66
68
  */
67
69
  readonly cloudEvictRetries?: number;
70
+ /**
71
+ * When background indexing (auto-refresh, fs watch, `autorag watch`) may run: power (`any`/`ac`),
72
+ * local-time `windows` (`HH:MM-HH:MM`) and weekdays. Omitted = always.
73
+ * An explicit `refresh()` call is never gated. See {@link IndexSchedule}.
74
+ */
75
+ readonly schedule?: IndexSchedule;
68
76
  }
69
77
  /**
70
78
  * Hard caps on retrieval, baseline prefetch, and the candidate lists handed to
@@ -99,6 +107,13 @@ export interface AutoRAGRetrievalLimits {
99
107
  /** Max results rendered per baseline section. Default 100. */
100
108
  readonly sectionLimit?: number;
101
109
  };
110
+ /**
111
+ * Spread each search's hits across documents instead of cutting by chunk, so one long document cannot take
112
+ * every slot (PipesHub's FUSION_RECORD_CUT). Off unless `enabled` is true: when on, MinSync and the merger ask
113
+ * for `depth` x the requested count, a chunk shown earlier in the run is not resent, and each search result
114
+ * is held to `resultChars` with the budget split fairly across its chunks.
115
+ */
116
+ readonly recordCut?: RecordCutOptions;
102
117
  }
103
118
  export interface AutoRefreshOptions {
104
119
  readonly intervalMs: number;
@@ -215,6 +230,10 @@ export interface AutoRAGWatchRefreshOptions {
215
230
  readonly debounceMs?: number;
216
231
  readonly force?: boolean;
217
232
  readonly maxWatchers?: number;
233
+ /** Replaces the configured `refresh.schedule` for this watcher. */
234
+ readonly schedule?: IndexSchedule;
235
+ /** How often a watcher with a closed schedule re-checks it (default 60000). */
236
+ readonly scheduleRecheckMs?: number;
218
237
  /** Injectable watcher factory (defaults to a recursive fs.watch). Primarily for tests. */
219
238
  readonly watcherFactory?: WatcherFactory;
220
239
  }
@@ -727,6 +746,11 @@ export declare class AutoRAGAgent {
727
746
  immediate?: boolean;
728
747
  }): void;
729
748
  stopAutoRefresh(): void;
749
+ /**
750
+ * Whether the configured index schedule lets a background refresh run now. `override` replaces the
751
+ * configured schedule (CLI flags). Probes the power source only when the policy depends on it.
752
+ */
753
+ indexScheduleDecision(override?: IndexSchedule, now?: Date): Promise<ScheduleDecision>;
730
754
  private runAutoRefreshTick;
731
755
  searchDocuments(query: string, options?: RetrievalOptions): Promise<SearchDocumentsResponse>;
732
756
  /**
@@ -954,10 +978,16 @@ export declare class AutoRAGAgent {
954
978
  private defaultWatcherFactory;
955
979
  syncParsedMirrors(force?: boolean, options?: Pick<ParsedMirrorSyncOptions, "signal" | "onProgress" | "retrySkipped" | "onBatch" | "batchSize">): Promise<ParsedMirrorSyncResult>;
956
980
  /**
957
- * Lightweight stat-only staleness scan used when `refresh` is called with
981
+ * Lightweight stat-only staleness scan used by status and when `refresh` is called with
958
982
  * methods that exclude parsed mirrors (e.g. only `datasources` or `jikji`).
959
983
  * Returns a zero-count `ParsedMirrorSyncResult` carrying fresh diagnostics
960
984
  * so the refresh result and status remain consistent.
985
+ *
986
+ * It never runs a duplicate scan: that reads every file under every root and costs seconds
987
+ * on a large corpus. It reuses the exclusions the last refresh recorded instead, so it
988
+ * differs from a fresh scan in two narrow ways: an indexed file that has since become an
989
+ * older exact duplicate is not reported (the next refresh drops it), and a newly added file
990
+ * that is already a duplicate is reported stale until the next refresh excludes it.
961
991
  */
962
992
  private scanMirrorStaleness;
963
993
  /** The machine's non-physical roots, resolved once; a probe failure reads as no roots, never an error. */
@@ -0,0 +1,39 @@
1
+ import type { AgentTool } from "@earendil-works/pi-agent-core";
2
+ import { Type } from "typebox";
3
+ export declare const CALCULATOR_TOOL_NAME = "calculator";
4
+ /** The standing order every prompt repeats: calculations belong to the tool, never to the model. */
5
+ export declare const CALCULATOR_PROMPT_RULE = "Never do arithmetic, date, time, or time zone math yourself: use calculator for every sum, percentage, average, unit conversion, day count, date offset, weekday, and \"what time is it in\u2026\", and copy its result unchanged. The current date in your instructions is a starting point, not a substitute for the tool.";
6
+ /** The fast phase forbids tools; this carves out the one that reads no sources and cannot slow the answer down. */
7
+ export declare const CALCULATOR_FAST_PHASE_RULE = "calculator is allowed: Never do arithmetic, date, time, or time zone math yourself: use calculator for every sum, percentage, average, unit conversion, day count, date offset, weekday, and \"what time is it in\u2026\", and copy its result unchanged. The current date in your instructions is a starting point, not a substitute for the tool.";
8
+ export interface CalculatorToolOptions {
9
+ /** The instant "now" and "today" mean. Tests pin it; the default reads the system clock on every call. */
10
+ readonly now?: () => Date;
11
+ /** Zone used when a call names none. Defaults to the host's zone. */
12
+ readonly hostTimeZone?: string;
13
+ }
14
+ declare const calculatorSchema: Type.TObject<{
15
+ operation: Type.TEnum<["evaluate", "now", "date_diff", "date_add", "date_info", "convert_timezone", "business_days_between", "add_business_days"]>;
16
+ expression: Type.TOptional<Type.TString>;
17
+ timeZone: Type.TOptional<Type.TString>;
18
+ toTimeZone: Type.TOptional<Type.TString>;
19
+ date: Type.TOptional<Type.TString>;
20
+ datetime: Type.TOptional<Type.TString>;
21
+ from: Type.TOptional<Type.TString>;
22
+ to: Type.TOptional<Type.TString>;
23
+ years: Type.TOptional<Type.TInteger>;
24
+ months: Type.TOptional<Type.TInteger>;
25
+ weeks: Type.TOptional<Type.TInteger>;
26
+ days: Type.TOptional<Type.TInteger>;
27
+ hours: Type.TOptional<Type.TInteger>;
28
+ minutes: Type.TOptional<Type.TInteger>;
29
+ seconds: Type.TOptional<Type.TInteger>;
30
+ holidays: Type.TOptional<Type.TArray<Type.TString>>;
31
+ inclusive: Type.TOptional<Type.TBoolean>;
32
+ }>;
33
+ export type CalculatorDetails = Record<string, string | number | boolean>;
34
+ /**
35
+ * The model's calculator: exact decimal arithmetic and calendar/clock math. Language models miscount days,
36
+ * drop digits and forget daylight saving, so every numeric or date answer comes from this tool, not from the model.
37
+ */
38
+ export declare function createCalculatorTool(options?: CalculatorToolOptions): AgentTool<typeof calculatorSchema, CalculatorDetails>;
39
+ export {};
@@ -4,8 +4,6 @@ import type { DupeyScanResult } from "../dupey/index.js";
4
4
  export declare const SCAN_DUPLICATE_DOCUMENTS_TOOL_NAME = "scan_duplicate_documents";
5
5
  export interface ScanDuplicateDocumentsDetails {
6
6
  readonly scans: readonly DupeyScanResult[];
7
- /** Roots inside a cloud or network folder: `dupey scan` opens file contents, so they were not scanned. */
8
- readonly skippedRoots: readonly string[];
9
7
  readonly familyCount: number;
10
8
  readonly exactDuplicateCount: number;
11
9
  }
@@ -77,6 +77,17 @@ export declare class EvidenceLedger {
77
77
  * at e1 would let a stale id silently resolve to a different chunk.
78
78
  */
79
79
  private lastOrdinal;
80
+ /** Ids whose text a search tool already put in front of the model during the current run. */
81
+ private readonly shown;
82
+ /** Whether a search already showed this evidence's text in the current run. */
83
+ hasShown(id: string): boolean;
84
+ /** Record that this evidence's text reached the model; returns whether it had already. */
85
+ markShown(id: string): boolean;
86
+ /**
87
+ * Start a run: nothing has been shown yet. A new question may follow a compaction that dropped the
88
+ * earlier tool output, so a repeat is only ever "already shown" within one run.
89
+ */
90
+ beginRun(): void;
80
91
  /** Record evidence and return its id. The same chunk always gets the same id. */
81
92
  register(input: LedgerEvidenceInput): string;
82
93
  /** Record one retrieval result as returned by `tool`; backend metadata is carried over. */
@@ -0,0 +1,45 @@
1
+ export type PowerPolicy = "any" | "ac";
2
+ export type PowerSource = "ac" | "battery" | "unknown";
3
+ export type ScheduleDay = "sun" | "mon" | "tue" | "wed" | "thu" | "fri" | "sat";
4
+ export interface IndexSchedule {
5
+ /** `any` (default) ignores power; `ac` pauses while on battery and runs only when plugged in. */
6
+ readonly power?: PowerPolicy;
7
+ /** Local-time windows `HH:MM-HH:MM`; indexing is allowed inside any of them. Omitted = all day. */
8
+ readonly windows?: readonly string[];
9
+ /** Local weekdays indexing is allowed on. Omitted = every day. */
10
+ readonly days?: readonly ScheduleDay[];
11
+ }
12
+ export type ScheduleDenyReason = "battery" | "outside-window" | "outside-day";
13
+ export type ScheduleDecision = {
14
+ readonly allowed: true;
15
+ } | {
16
+ readonly allowed: false;
17
+ readonly reason: ScheduleDenyReason;
18
+ };
19
+ /** Validate and normalize a raw `refresh.schedule` value. Throws a plain Error naming the field. */
20
+ export declare function validateIndexSchedule(raw: unknown): IndexSchedule;
21
+ /** Decide whether a background refresh may run at `now` given the detected `source`. */
22
+ export declare function evaluateIndexSchedule(schedule: IndexSchedule | undefined, now: Date, source: PowerSource): ScheduleDecision;
23
+ /** Map raw probe output to a power source. Returns `unknown` for anything unrecognized. */
24
+ export declare function parsePowerSourceOutput(platform: string, output: string): PowerSource;
25
+ export interface PowerProbeDeps {
26
+ readonly platform?: NodeJS.Platform;
27
+ /** Run a command and return stdout. */
28
+ readonly run?: (command: string, args: readonly string[]) => Promise<string>;
29
+ readonly read?: (path: string) => Promise<string>;
30
+ readonly list?: (dir: string) => Promise<string[]>;
31
+ }
32
+ /** Detect the current power source. Never throws: any probe failure yields `unknown`. */
33
+ export declare function detectPowerSource(deps?: PowerProbeDeps): Promise<PowerSource>;
34
+ export interface CheckIndexScheduleOptions {
35
+ readonly now?: Date;
36
+ /** Replaces the platform power probe (tests). */
37
+ readonly detect?: () => Promise<PowerSource>;
38
+ }
39
+ /**
40
+ * Decide from a raw config object (`refresh.schedule`) whether a background refresh may run now. For hosts
41
+ * that run their own scheduler, such as the desktop app's OS job. Probes the power source only when the policy
42
+ * asks for AC. A malformed schedule fails open: a bad edit must not silently stop indexing, and the config
43
+ * loader already rejects it loudly where the user can see it.
44
+ */
45
+ export declare function checkIndexSchedule(rawConfig: Record<string, unknown>, options?: CheckIndexScheduleOptions): Promise<ScheduleDecision>;
@@ -1,5 +1,6 @@
1
1
  export type { AutoRAGAgentOptions, AutoRefreshOptions } from "./agent.js";
2
2
  export { AutoRAGAgent } from "./agent.js";
3
+ export { CALCULATOR_FAST_PHASE_RULE, CALCULATOR_PROMPT_RULE, CALCULATOR_TOOL_NAME, type CalculatorDetails, type CalculatorToolOptions, createCalculatorTool, } from "./calculator-tool.js";
3
4
  export { CONVERT_FILES_TOOL_NAME, type ConvertFilesDetails, createConvertFilesTool, createListFileConversionsTool, type FileConversionProvider, LIST_FILE_CONVERSIONS_TOOL_NAME, } from "./convert-tool.js";
4
5
  export { buildDatasourceSkillsPrompt, createLoadDatasourceSkillTool, type DatasourceSkillProvider, datasourceSkillLocation, formatDatasourceSkillInvocation, LOAD_DATASOURCE_SKILL_TOOL_NAME, type LoadDatasourceSkillDetails, toDatasourceAgentSkill, } from "./datasource-skill.js";
5
6
  export { DECISION_PROVIDER_DEFAULT_MODELS, type DecisionModelRuntime, PiDecisionBackend, type PiDecisionBackendOptions, } from "./decision-backends.js";
@@ -0,0 +1,34 @@
1
+ import type { ParsedMirrorBatch, ParsedMirrorBatchOutcome } from "../mirror/sync.js";
2
+ /** One sync run: the 1-based run number and the sources of every batch committed since the previous run began. */
3
+ export interface PipelinedSyncRun {
4
+ readonly index: number;
5
+ readonly virtualPaths: readonly string[];
6
+ }
7
+ export interface PipelinedSyncOptions {
8
+ /**
9
+ * Index everything committed so far. Resolving with `stop` ends the pipeline (a held lock means another
10
+ * process owns the index, so every further run would fail the same way); a rejection is raised from the
11
+ * next {@link PipelinedSync.batch} call.
12
+ */
13
+ readonly sync: (run: PipelinedSyncRun) => Promise<ParsedMirrorBatchOutcome | undefined>;
14
+ }
15
+ /**
16
+ * Runs index syncs alongside the parse loop instead of between its batches.
17
+ *
18
+ * A sync only sees what is committed when it starts, and the indexer batches and commits on its own, so the
19
+ * first batch starts a sync right away while parsing carries on. At most one sync is in flight; when it ends,
20
+ * the next one covers every batch committed meanwhile. A slow sync therefore turns into few large ones
21
+ * instead of one per parse batch, and each sync pays its start-up and end-of-run maintenance once.
22
+ */
23
+ export declare class PipelinedSync {
24
+ #private;
25
+ constructor(options: PipelinedSyncOptions);
26
+ /**
27
+ * Hand over a committed batch. Returns at once, except for the final batch: it waits until a sync that
28
+ * started after every batch was committed has finished, and always runs one, so a sync that failed
29
+ * earlier is retried even when nothing changed.
30
+ */
31
+ batch(batch: Pick<ParsedMirrorBatch, "virtualPaths" | "final">): Promise<ParsedMirrorBatchOutcome | undefined>;
32
+ /** Wait for the sync in flight, if any, and start no further one. Never rejects. */
33
+ settle(): Promise<void>;
34
+ }
@@ -0,0 +1,43 @@
1
+ import type { RecordCut } from "../retrieval/record-cut.js";
2
+ import type { RetrievalResult } from "../retrieval/types.js";
3
+ import type { EvidenceLedger } from "./evidence-ledger.js";
4
+ /** One retrieved chunk as a search tool shows it to the model. */
5
+ export interface EvidenceRow {
6
+ /** Ledger id, cited as `[eN]`. */
7
+ readonly id: string;
8
+ /** Everything after the id on the first line: source, score, location. */
9
+ readonly header: string;
10
+ readonly content: string;
11
+ /** A search earlier in this run already put this chunk's text in front of the model. */
12
+ readonly repeat: boolean;
13
+ }
14
+ export interface RenderedEvidence {
15
+ readonly text: string;
16
+ /** Ids whose text is in `text`; the caller marks these as shown so a later search does not resend them. */
17
+ readonly delivered: ReadonlySet<string>;
18
+ }
19
+ export declare const REPEAT_NOTE = "(already shown earlier in this run; text not repeated)";
20
+ export declare const NOT_READ_NOTE = "(not read: result budget used up; narrow the query to read it)";
21
+ /**
22
+ * Render search results for the model.
23
+ *
24
+ * Without a record cut every row is shown in full, exactly as before. With one,
25
+ * a chunk an earlier search of this run already showed is named without its
26
+ * text, and the rest share `recordCut.resultChars` max-min fairly: a long chunk
27
+ * is cut and says how much, a short one keeps all of it, and when the budget
28
+ * cannot give every chunk a useful share the lowest-ranked ones are listed as
29
+ * not read rather than every chunk being clipped to a stub.
30
+ */
31
+ export declare function renderEvidenceRows(rows: readonly EvidenceRow[], recordCut: RecordCut | undefined): RenderedEvidence;
32
+ /** Options a search tool takes for the record cut; absent means the legacy rendering. */
33
+ export interface RecordCutToolOptions {
34
+ readonly recordCut?: RecordCut;
35
+ }
36
+ /**
37
+ * Register `results` in the ledger and render them. With a record cut, a chunk an earlier search of this run
38
+ * already showed is not resent, and only chunks whose text reached the model are marked as shown.
39
+ */
40
+ export declare function registerAndRender(ledger: EvidenceLedger, tool: string, results: readonly RetrievalResult[], header: (result: RetrievalResult) => string, recordCut: RecordCut | undefined): {
41
+ readonly evidenceIds: string[];
42
+ readonly text: string;
43
+ };
@@ -2,6 +2,7 @@ import type { AgentTool } from "@earendil-works/pi-agent-core";
2
2
  import { Type } from "typebox";
3
3
  import type { RetrievalDiagnostic, RetrievalResult } from "../retrieval/types.js";
4
4
  import { EvidenceLedger } from "./evidence-ledger.js";
5
+ import { type RecordCutToolOptions } from "./result-render.js";
5
6
  import { type SearchDocumentRetrievalTraceResult } from "./search-documents.js";
6
7
  export declare const SEARCH_ALL_DOCUMENTS_TOOL_NAME = "search_all_documents";
7
8
  declare const searchAllSchema: Type.TObject<{
@@ -36,5 +37,5 @@ export interface SearchAllDocumentsDetails {
36
37
  * properties are not part of the schema and are never forwarded to the
37
38
  * provider — only `query`, `topK`, and `scope` are passed through.
38
39
  */
39
- export declare function createSearchAllDocumentsTool(provider: SearchAllDocumentsProvider, ledger?: EvidenceLedger): AgentTool<typeof searchAllSchema, SearchAllDocumentsDetails>;
40
+ export declare function createSearchAllDocumentsTool(provider: SearchAllDocumentsProvider, ledger?: EvidenceLedger, options?: RecordCutToolOptions): AgentTool<typeof searchAllSchema, SearchAllDocumentsDetails>;
40
41
  export {};
@@ -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" | "no-verified-results" | "unknown-warning" | "caller-tool-dropped" | "minsync-staging-excluded" | "minsync-file-skipped" | "minsync-sync-failed" | "minsync-lock-held" | "embedder-unavailable" | "embedding-identity-mismatch" | "parser-skipped" | "parser-failed" | "parser-crashed" | "source-changed" | "source-vanished" | "source-unreadable" | "source-read-failed" | "mirror-write-failed" | "parser-warning" | "duplicate-excluded" | "unsupported-file" | "stale-index" | "deleted-mirror" | "search-root-unavailable" | "mass-delete-suppressed" | "walk-truncated" | "directory-unreadable" | "cloud-download-deferred" | "cloud-placeholder-skipped" | "cloud-evict-failed" | "cloud-fingerprint-failed" | "pdf-extract-thin" | "retrieval-method-failed" | "rerank-failed" | "rerank-disabled" | "jikji-unavailable" | "jikji-prepare-failed" | "jikji-cloud-root-skipped" | "jikji-find-failed" | "jikji-discover-failed" | "jikji-unsupported-version" | "everything-index-failed" | "fsearch-index-failed" | "fsearch-binary-missing" | "refresh-failed" | "refresh-interrupted" | "watch-failed" | "watch-limited" | "unknown-datasource-skill" | "no-final-answer" | "model-request-failed" | "tool-call-burst" | "decision-model-checked" | "decision-model-fallback" | "query-routed" | "query-route-fallback" | "query-decomposition-failed" | "follow-up-skipped" | "follow-up-check-fallback" | "datasources-selected" | "datasource-selection-fallback" | "web-datasource-id-taken" | "web-search-failed" | "citation-without-result" | "line-reference-unverified" | "citation-irrelevant" | "citation-relevance-fallback" | "evidence-judged" | "evidence-judgment-fallback" | "memory-search-fallback" | "self-config-unavailable" | "self-config-rolled-back" | "organize-skill-unavailable" | "embedding-unavailable";
12
+ export type SearchDocumentDiagnosticCode = "empty-query" | "no-verified-results" | "unknown-warning" | "caller-tool-dropped" | "minsync-staging-excluded" | "minsync-file-skipped" | "minsync-sync-failed" | "minsync-lock-held" | "embedder-unavailable" | "embedding-identity-mismatch" | "parser-skipped" | "parser-failed" | "parser-crashed" | "source-changed" | "source-vanished" | "source-unreadable" | "source-read-failed" | "mirror-write-failed" | "parser-warning" | "duplicate-excluded" | "unsupported-file" | "stale-index" | "deleted-mirror" | "search-root-unavailable" | "mass-delete-suppressed" | "walk-truncated" | "directory-unreadable" | "cloud-placeholder-skipped" | "cloud-evict-failed" | "cloud-fingerprint-failed" | "pdf-extract-thin" | "retrieval-method-failed" | "rerank-failed" | "rerank-disabled" | "jikji-unavailable" | "jikji-prepare-failed" | "jikji-cloud-root-skipped" | "jikji-find-failed" | "jikji-discover-failed" | "jikji-unsupported-version" | "everything-index-failed" | "fsearch-index-failed" | "fsearch-binary-missing" | "refresh-failed" | "refresh-interrupted" | "watch-failed" | "watch-limited" | "unknown-datasource-skill" | "retired-datasource-skill" | "no-final-answer" | "model-request-failed" | "tool-call-burst" | "decision-model-checked" | "decision-model-fallback" | "query-routed" | "query-route-fallback" | "query-decomposition-failed" | "follow-up-skipped" | "follow-up-check-fallback" | "datasources-selected" | "datasource-selection-fallback" | "web-datasource-id-taken" | "web-search-failed" | "citation-without-result" | "line-reference-unverified" | "citation-irrelevant" | "citation-relevance-fallback" | "evidence-judged" | "evidence-judgment-fallback" | "memory-search-fallback" | "self-config-unavailable" | "self-config-rolled-back" | "organize-skill-unavailable" | "embedding-unavailable";
13
13
  export interface SearchDocumentDiagnostic {
14
14
  readonly code: SearchDocumentDiagnosticCode;
15
15
  readonly severity: SearchDocumentDiagnosticSeverity;
@@ -2,6 +2,7 @@ import type { AgentTool } from "@earendil-works/pi-agent-core";
2
2
  import { Type } from "typebox";
3
3
  import type { MinSyncVectorMethod } from "../minsync/method.js";
4
4
  import { EvidenceLedger } from "./evidence-ledger.js";
5
+ import { type RecordCutToolOptions } from "./result-render.js";
5
6
  import { type SearchDocumentRetrievalTraceResult } from "./search-documents.js";
6
7
  export declare const SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME = "semantic_search_local_docs";
7
8
  declare const searchMinSyncSchema: Type.TObject<{
@@ -23,5 +24,5 @@ export interface SearchMinSyncDocumentsDetails {
23
24
  * into an "unavailable" result: the error propagates with its own message and
24
25
  * the harness reports it as a failed tool call.
25
26
  */
26
- export declare function createSearchMinSyncDocumentsTool(getMethod: () => MinSyncVectorMethod, resolveScope?: (scope: string | undefined) => string | undefined, ledger?: EvidenceLedger): AgentTool<typeof searchMinSyncSchema, SearchMinSyncDocumentsDetails>;
27
+ export declare function createSearchMinSyncDocumentsTool(getMethod: () => MinSyncVectorMethod, resolveScope?: (scope: string | undefined) => string | undefined, ledger?: EvidenceLedger, options?: RecordCutToolOptions): AgentTool<typeof searchMinSyncSchema, SearchMinSyncDocumentsDetails>;
27
28
  export {};
@@ -2,6 +2,7 @@ import type { AgentTool } from "@earendil-works/pi-agent-core";
2
2
  import { Type } from "typebox";
3
3
  import type { RetrievalDiagnostic, RetrievalResult } from "../retrieval/types.js";
4
4
  import { EvidenceLedger } from "./evidence-ledger.js";
5
+ import { type RecordCutToolOptions } from "./result-render.js";
5
6
  import { type SearchDocumentRetrievalTraceResult } from "./search-documents.js";
6
7
  /**
7
8
  * Per-datasource search tools.
@@ -54,7 +55,7 @@ export interface SearchSingleDatasourceDetails {
54
55
  /** Top candidates in traceable shape (additive; used for the run's retrieval trace). */
55
56
  readonly results?: readonly SearchDocumentRetrievalTraceResult[];
56
57
  }
57
- export declare function createSingleDatasourceSearchTools(provider: SingleDatasourceSearchProvider, specs: readonly SingleDatasourceToolSpec[], ledger?: EvidenceLedger): AgentTool<typeof searchSingleDatasourceSchema, SearchSingleDatasourceDetails>[];
58
+ export declare function createSingleDatasourceSearchTools(provider: SingleDatasourceSearchProvider, specs: readonly SingleDatasourceToolSpec[], ledger?: EvidenceLedger, options?: RecordCutToolOptions): AgentTool<typeof searchSingleDatasourceSchema, SearchSingleDatasourceDetails>[];
58
59
  declare const searchSingleDatasourceSchema: Type.TObject<{
59
60
  query: Type.TString;
60
61
  topK: Type.TOptional<Type.TInteger>;
@@ -24,6 +24,8 @@ export interface WatchRefreshDeps {
24
24
  readonly onLimit?: () => void;
25
25
  }
26
26
  export interface WatchRefreshHandle {
27
+ /** Schedule a (debounced) refresh as if a change had been seen, e.g. for a deferred initial refresh. */
28
+ trigger(): void;
27
29
  stop(): void;
28
30
  }
29
31
  export declare function createWatchRefresh(deps: WatchRefreshDeps): WatchRefreshHandle;
@@ -0,0 +1,27 @@
1
+ /** Proleptic Gregorian calendar arithmetic on whole days since 1970-01-01. No time zones, no `Date`. */
2
+ export declare const MS_PER_DAY = 86400000;
3
+ export declare const MIN_YEAR = 1;
4
+ export declare const MAX_YEAR = 9999;
5
+ export declare const WEEKDAYS: readonly ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
6
+ export interface Civil {
7
+ readonly y: number;
8
+ readonly m: number;
9
+ readonly d: number;
10
+ }
11
+ export declare function pad(value: number, width?: number): string;
12
+ export declare function floorDiv(a: number, b: number): number;
13
+ export declare function mod(a: number, b: number): number;
14
+ export declare function isLeapYear(y: number): boolean;
15
+ export declare function daysInMonth(y: number, m: number): number;
16
+ export declare function isRealDate(y: number, m: number, d: number): boolean;
17
+ /** Days since 1970-01-01 (Howard Hinnant's days_from_civil). */
18
+ export declare function daysFromCivil(y: number, m: number, d: number): number;
19
+ export declare function civilFromDays(days: number): Civil;
20
+ /** 1 = Monday … 7 = Sunday. 1970-01-01 was a Thursday. */
21
+ export declare function isoWeekday(days: number): number;
22
+ export declare function dayOfYear(c: Civil): number;
23
+ /** ISO 8601 week date, e.g. `2026-W45-7`. */
24
+ export declare function isoWeekDate(days: number): string;
25
+ /** Adds calendar months, clamping the day to the end of a shorter month (Jan 31 + 1 month = Feb 28). */
26
+ export declare function addMonths(c: Civil, months: number): Civil;
27
+ export declare function formatDate(days: number): string;
@@ -0,0 +1,47 @@
1
+ /** Significant digits every intermediate result keeps. */
2
+ export declare const WORK_DIGITS = 60;
3
+ /** Significant digits a final result keeps. */
4
+ export declare const RESULT_DIGITS = 40;
5
+ export declare const MAX_INTEGER_EXPONENT = 10000;
6
+ /** `n × 10^e`. Normalized: no trailing zeros in `n`, and zero is `{0n, 0}`. */
7
+ export interface Dec {
8
+ readonly n: bigint;
9
+ readonly e: number;
10
+ }
11
+ /** Whether any step rounded or approximated, so the answer is not the exact mathematical value. */
12
+ export interface Precision {
13
+ inexact: boolean;
14
+ }
15
+ export declare const ZERO: Dec;
16
+ export declare const ONE: Dec;
17
+ export type RoundingMode = "half-away" | "floor" | "ceil" | "trunc";
18
+ export declare function digitCount(n: bigint): number;
19
+ export declare function normalize(n: bigint, e: number): Dec;
20
+ export declare function parseDecimal(text: string): Dec;
21
+ export declare function fromInteger(value: number): Dec;
22
+ /** A finite double rounded to 15 significant digits: transcendental results are only that accurate. */
23
+ export declare function fromDouble(value: number, precision: Precision, name: string): Dec;
24
+ export declare function toDouble(value: Dec): number;
25
+ export declare function sign(value: Dec): -1 | 0 | 1;
26
+ export declare function negate(value: Dec): Dec;
27
+ export declare function isInteger(value: Dec): boolean;
28
+ /** Drops every digit below `10^target`, rounding as `mode` says. */
29
+ export declare function roundAtExponent(value: Dec, target: number, mode: RoundingMode, precision: Precision): Dec;
30
+ /** Rounds to `digits` significant digits, half away from zero. */
31
+ export declare function roundSignificant(value: Dec, digits: number, precision: Precision): Dec;
32
+ export declare function compare(a: Dec, b: Dec): -1 | 0 | 1;
33
+ export declare function add(a: Dec, b: Dec, precision: Precision): Dec;
34
+ export declare function subtract(a: Dec, b: Dec, precision: Precision): Dec;
35
+ export declare function multiply(a: Dec, b: Dec, precision: Precision): Dec;
36
+ export declare function divide(a: Dec, b: Dec, precision: Precision): Dec;
37
+ /** `a mod b` with the sign of `a`, like JavaScript's `%` but exact. */
38
+ export declare function remainder(a: Dec, b: Dec, precision: Precision): Dec;
39
+ /** Exact total of every term; only the final result is rounded. */
40
+ export declare function sumExact(terms: readonly Dec[], precision: Precision): Dec;
41
+ /** Square root to WORK_DIGITS digits; exact when the root is a terminating decimal. */
42
+ export declare function squareRoot(value: Dec, precision: Precision): Dec;
43
+ export declare function cubeRoot(value: Dec, precision: Precision): Dec;
44
+ /** `base ^ exponent`. Integer exponents are exact up to WORK_DIGITS; fractional ones are double precision. */
45
+ export declare function power(base: Dec, exponent: Dec, precision: Precision): Dec;
46
+ /** Plain digits up to 10^40, scientific notation beyond (and below 1e-7), trailing zeros trimmed. */
47
+ export declare function formatDecimal(value: Dec): string;
@@ -0,0 +1,4 @@
1
+ /** A calculation the calculator refuses: bad input or a result it cannot give honestly. The message is for the model. */
2
+ export declare class CalculatorError extends Error {
3
+ constructor(message: string);
4
+ }
@@ -0,0 +1,11 @@
1
+ import { digitCount, normalize, ZERO } from "./decimal.js";
2
+ export declare const MAX_EXPRESSION_LENGTH = 4096;
3
+ export interface ExpressionResult {
4
+ readonly expression: string;
5
+ readonly value: string | string[];
6
+ /** False when any step rounded or approximated, so the digits are the best 40-digit answer rather than the exact one. */
7
+ readonly exact: boolean;
8
+ }
9
+ /** Evaluates one expression, or one flat `[a, b, …]` list of expressions, with exact decimal arithmetic. */
10
+ export declare function evaluateExpression(source: string): ExpressionResult;
11
+ export { digitCount, normalize, ZERO };
@@ -0,0 +1,17 @@
1
+ import { type CalculatorRequest, type Fields } from "./operations.js";
2
+ export { CalculatorError } from "./errors.js";
3
+ export { MAX_EXPRESSION_LENGTH } from "./expression.js";
4
+ export type { CalculatorRequest, Fields } from "./operations.js";
5
+ export declare const CALCULATOR_OPERATIONS: readonly ["evaluate", "now", "date_diff", "date_add", "date_info", "convert_timezone", "business_days_between", "add_business_days"];
6
+ export interface CalculatorOptions {
7
+ /** The instant "now" and "today" mean. Defaults to the system clock. */
8
+ readonly now?: Date;
9
+ /** Zone used when the request names none. Defaults to the host's zone. */
10
+ readonly hostTimeZone?: string;
11
+ }
12
+ export interface CalculatorOutput {
13
+ readonly fields: Fields;
14
+ /** One `name: value` line per field: the text the model reads. */
15
+ readonly text: string;
16
+ }
17
+ export declare function calculate(request: CalculatorRequest, options?: CalculatorOptions): CalculatorOutput;
@@ -0,0 +1,36 @@
1
+ import { type Zone } from "./timezone.js";
2
+ export type FieldValue = string | number | boolean;
3
+ export type Fields = Record<string, FieldValue>;
4
+ export interface CalculatorRequest {
5
+ readonly operation: string;
6
+ readonly expression?: string;
7
+ /** Zone a date or time is read in and shown in; for convert_timezone, the source zone. */
8
+ readonly timeZone?: string;
9
+ readonly toTimeZone?: string;
10
+ readonly date?: string;
11
+ readonly datetime?: string;
12
+ readonly from?: string;
13
+ readonly to?: string;
14
+ readonly years?: number;
15
+ readonly months?: number;
16
+ readonly weeks?: number;
17
+ readonly days?: number;
18
+ readonly hours?: number;
19
+ readonly minutes?: number;
20
+ readonly seconds?: number;
21
+ readonly holidays?: readonly string[];
22
+ readonly inclusive?: boolean;
23
+ }
24
+ export interface Clock {
25
+ readonly now: Date;
26
+ readonly zone: Zone;
27
+ readonly zoneSource: "requested" | "host default";
28
+ }
29
+ export declare function need<T>(operation: string, name: string, value: T | undefined): T;
30
+ export declare function now(clock: Clock): Fields;
31
+ export declare function dateDiff(request: CalculatorRequest, clock: Clock): Fields;
32
+ export declare function dateAdd(request: CalculatorRequest, clock: Clock): Fields;
33
+ export declare function convertTimeZone(request: CalculatorRequest, clock: Clock, sourceGiven: boolean): Fields;
34
+ export declare function dateInfo(request: CalculatorRequest, clock: Clock): Fields;
35
+ export declare function businessDaysBetween(request: CalculatorRequest, clock: Clock): Fields;
36
+ export declare function addBusinessDays(request: CalculatorRequest, clock: Clock): Fields;
@@ -0,0 +1,18 @@
1
+ import { type Zone } from "./timezone.js";
2
+ /** A date with no time of day, or one instant on the timeline. */
3
+ export type Temporal = {
4
+ readonly kind: "date";
5
+ readonly days: number;
6
+ }
7
+ /** `zoneless` marks a wall-clock time that was placed in the zone by assumption, not by its own offset. */
8
+ | {
9
+ readonly kind: "instant";
10
+ readonly epochMs: number;
11
+ readonly zoneless: boolean;
12
+ };
13
+ export declare function todayIn(zone: Zone, now: Date): number;
14
+ export declare function parseTemporal(input: string, zone: Zone, now: Date): Temporal;
15
+ /** Calendar day of a value: a date as is, an instant as the date on the wall clock in `zone`. */
16
+ export declare function dayOf(value: Temporal, zone: Zone): number;
17
+ /** The instant of a value: a date means midnight in `zone`. */
18
+ export declare function instantOf(value: Temporal, zone: Zone): number;
@@ -0,0 +1,19 @@
1
+ /** A UTC offset in force at every instant (`fixed`, seconds), or an IANA zone whose offset changes over time. */
2
+ export interface Zone {
3
+ readonly name: string;
4
+ readonly fixed?: number;
5
+ }
6
+ export declare function formatOffset(seconds: number): string;
7
+ export declare function fixedZone(offsetSeconds: number): Zone;
8
+ export declare function parseZone(input: string): Zone;
9
+ /** Seconds east of UTC in force at `epochMs`. */
10
+ export declare function offsetAt(zone: Zone, epochMs: number): number;
11
+ /** Wall-clock time in the zone, as milliseconds counted from 1970-01-01T00:00 with no zone attached. */
12
+ export declare function toNaive(zone: Zone, epochMs: number): number;
13
+ /**
14
+ * The instant a wall-clock time denotes. A time that occurs twice (clocks turn back) is its first
15
+ * occurrence; a time that never occurs (clocks jump ahead) moves forward by the length of the gap.
16
+ */
17
+ export declare function fromNaive(zone: Zone, naiveMs: number): number;
18
+ /** `YYYY-MM-DDTHH:MM:SS[.mmm]±HH:MM` for an instant in the zone. */
19
+ export declare function formatIso(zone: Zone, epochMs: number): string;
@@ -1,11 +1,10 @@
1
1
  import type { DupeyScanResult } from "../../dupey/index.js";
2
- import { type CloudFileProbe } from "../../filesystem/cloud-placeholder.js";
3
2
  import type { CommandContext } from "./types.js";
4
- export type DuplicateScanner = (path: string, excludeDirs: readonly string[]) => Promise<DupeyScanResult>;
3
+ export type DuplicateScanner = (path: string) => Promise<DupeyScanResult>;
5
4
  /**
6
5
  * `autorag duplicates` — scan configured roots for exact and near duplicate
7
6
  * document families. Never deletes or moves source files.
8
7
  *
9
8
  * Exit codes: 0 on success, 2 on config error, 1 on runtime error.
10
9
  */
11
- export declare function runDuplicates(ctx: CommandContext, scanner?: DuplicateScanner, cloudProbe?: CloudFileProbe | undefined): Promise<number>;
10
+ export declare function runDuplicates(ctx: CommandContext, scanner?: DuplicateScanner): Promise<number>;
@@ -4,6 +4,6 @@ import type { CommandContext } from "./types.js";
4
4
  * and MinSync indexes
5
5
  * (preserving `bin`, `datasources`, and the memory file). `rebuild` resets then re-runs a forced
6
6
  * refresh. Returns 0 on success, 2 for usage/decline errors, 1 for runtime
7
- * errors including path-escape guard violations.
7
+ * errors including path-escape guard violations, and 130/143 when a rebuild is stopped by SIGINT/SIGTERM.
8
8
  */
9
9
  export declare function runIndex(ctx: CommandContext): Promise<number>;