@autorag/librarian 2.12.0 → 2.13.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 (55) hide show
  1. package/README.md +22 -4
  2. package/dist/agent/agent.d.ts +84 -44
  3. package/dist/agent/answer-guidelines.d.ts +19 -2
  4. package/dist/agent/current-date.d.ts +10 -0
  5. package/dist/agent/datasource-skill.d.ts +2 -2
  6. package/dist/agent/environment-prompt.d.ts +20 -0
  7. package/dist/agent/evidence-ledger.d.ts +4 -2
  8. package/dist/agent/location-claims.d.ts +14 -0
  9. package/dist/agent/packaged-skill.d.ts +19 -0
  10. package/dist/agent/query-routing.d.ts +80 -26
  11. package/dist/agent/results.d.ts +10 -2
  12. package/dist/agent/search-documents.d.ts +6 -1
  13. package/dist/agent/self-config.d.ts +4 -4
  14. package/dist/agent/skill-invocation.d.ts +17 -0
  15. package/dist/agent/user-requests.d.ts +2 -2
  16. package/dist/cli/commands/attachments.d.ts +13 -0
  17. package/dist/cli/commands/evidence.d.ts +2 -0
  18. package/dist/cli/index.d.ts +1 -1
  19. package/dist/cli/index.js +13923 -12387
  20. package/dist/cli/setup.d.ts +2 -0
  21. package/dist/core.js +22362 -21005
  22. package/dist/datasource/crawler-skill.d.ts +1 -0
  23. package/dist/datasource/index.d.ts +1 -1
  24. package/dist/datasource/sidecar/descriptors.d.ts +14 -1
  25. package/dist/datasource/sidecar/index.d.ts +4 -0
  26. package/dist/datasource/sidecar/methods.d.ts +12 -2
  27. package/dist/datasource/skills/clawgallery/skill.d.ts +4 -0
  28. package/dist/datasource/skills/discrawl/attachments.d.ts +139 -0
  29. package/dist/datasource/skills/discrawl/client.d.ts +11 -1
  30. package/dist/datasource/skills/discrawl/index.d.ts +2 -1
  31. package/dist/datasource/skills/discrawl/ranked-method.d.ts +19 -0
  32. package/dist/datasource/skills/discrawl/sidecar.d.ts +21 -0
  33. package/dist/datasource/skills/discrawl/skill.d.ts +23 -2
  34. package/dist/datasource/skills/discrawl/types.d.ts +41 -0
  35. package/dist/datasource/skills/factory.d.ts +17 -2
  36. package/dist/datasource/skills/lazykatok/index.d.ts +1 -1
  37. package/dist/datasource/skills/lazykatok/methods.d.ts +5 -5
  38. package/dist/datasource/skills/lazykatok/skill.d.ts +1 -0
  39. package/dist/datasource/skills/mailcrawl/skill.d.ts +1 -0
  40. package/dist/index.js +22454 -21046
  41. package/dist/mcp/index.js +22451 -21044
  42. package/dist/memory/memory.d.ts +4 -1
  43. package/dist/minsync/installer.d.ts +1 -1
  44. package/dist/mirror/atomic-write.d.ts +16 -1
  45. package/dist/mirror/sync.d.ts +2 -0
  46. package/dist/profiles.js +25935 -24578
  47. package/dist/retrieval/chunk-location.d.ts +28 -0
  48. package/dist/retrieval/fallback.d.ts +24 -0
  49. package/dist/retrieval/index.d.ts +1 -0
  50. package/dist/retrieval/types.d.ts +16 -0
  51. package/internal-skills/organize/SKILL.md +43 -0
  52. package/package.json +2 -1
  53. package/skills/autorag/SKILL.md +18 -7
  54. package/skills/autorag-lite-setup/SKILL.md +24 -0
  55. package/skills/autorag-setup/SKILL.md +31 -5
@@ -58,6 +58,7 @@ export declare class CrawlerDatasourceSkill implements DatasourceSkill {
58
58
  private syncSidecar;
59
59
  /** Release the sidecar's database handles. Safe to call repeatedly; later use reopens them. */
60
60
  close(): void;
61
+ /** One method: the sidecar's hybrid search (or BM25 without an embedder), with the CLI as the last fallback. */
61
62
  retrievalMethods(): readonly RetrievalMethod[];
62
63
  private cliMethod;
63
64
  describeSources(): readonly SourceDescription[];
@@ -13,7 +13,7 @@ export { GitHubConnector, type GitHubConnectorOptions, GitHubSkill, type GitHubS
13
13
  export { HISTER_SKILL_TYPE, HisterClient, type HisterClientOptions, HisterSkill, type HisterSkillOptions, } from "./skills/hister/index.js";
14
14
  export { LarkClient, type LarkClientOptions, LarkSkill, type LarkSkillOptions } from "./skills/lark/index.js";
15
15
  export type { LazykatokFailureReason, LazykatokHit, LazykatokOptions, LazykatokSearchMode, LazykatokSearchOptions, LazykatokSearchResult, LazykatokSkillClient, LazykatokSkillOptions, } from "./skills/lazykatok/index.js";
16
- export { LazykatokBm25Method, LazykatokClient, LazykatokSemanticMethod, LazykatokSkill, } from "./skills/lazykatok/index.js";
16
+ export { LazykatokBm25Method, LazykatokClient, LazykatokHybridMethod, LazykatokSkill, } from "./skills/lazykatok/index.js";
17
17
  export { MailExportConnector, type MailExportConnectorOptions, MailExportSkill, type MailExportSkillOptions, } from "./skills/mail-export/index.js";
18
18
  export { MAILCRAWL_MODES, MailcrawlClient, type MailcrawlFailure, type MailcrawlFailureReason, type MailcrawlIndexInfo, MailcrawlMethod, type MailcrawlOptions, type MailcrawlSearchHit, type MailcrawlSearchMode, type MailcrawlSearchResult, MailcrawlSkill, type MailcrawlSyncInfo, type MailcrawlSyncResult, } from "./skills/mailcrawl/index.js";
19
19
  export { NotcrawlClient, type NotcrawlOptions, NotionSkill, type NotionSkillOptions, } from "./skills/notion/index.js";
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Declarative description of a crawler's read-only SQLite schema. The sidecar
3
3
  * engine (index.ts) is crawler-agnostic: everything that differs between
4
- * slacrawl, telecrawl, wacrawl and notcrawl is expressed here as SQL fragments.
4
+ * slacrawl, telecrawl, wacrawl and discrawl is expressed here as SQL fragments.
5
5
  *
6
6
  * Every SQL fragment is a trusted constant authored in this file. User input
7
7
  * (the search query, workspace id) is only ever bound as a parameter.
@@ -44,6 +44,16 @@ export interface CrawlerDescriptor {
44
44
  readonly fts: {
45
45
  readonly table: string;
46
46
  readonly joinOn: string;
47
+ /**
48
+ * Optional tokenizer-specific FTS tables the crawler maintains alongside the base index
49
+ * (discrawl's `message_fts_<lang>`). Each table that exists in the attached archive is
50
+ * searched and reciprocal-rank fused with the base table, so rows only the language
51
+ * tokenizer can match still reach the lexical candidate list. Absent tables are ignored.
52
+ */
53
+ readonly extraTables?: readonly {
54
+ readonly table: string;
55
+ readonly joinOn: string;
56
+ }[];
47
57
  };
48
58
  /** Extra result columns mapped into hit metadata: a SQL expression and the metadata key it fills. */
49
59
  readonly metadata: readonly {
@@ -59,10 +69,13 @@ export interface CrawlerDescriptor {
59
69
  /** Path-opaque label for the hierarchy: ["workspaces", ws, "channels", name] etc. */
60
70
  readonly hierarchy: (metadata: Readonly<Record<string, unknown>>) => readonly string[];
61
71
  }
72
+ /** discrawl's FTS row refers to the stable Discord message id, independent of SQLite rowid. */
73
+ export declare const discordDescriptor: CrawlerDescriptor;
62
74
  export declare const CRAWLER_DESCRIPTORS: {
63
75
  readonly slack: CrawlerDescriptor;
64
76
  readonly telegram: CrawlerDescriptor;
65
77
  readonly whatsapp: CrawlerDescriptor;
78
+ readonly discord: CrawlerDescriptor;
66
79
  readonly kakao: CrawlerDescriptor;
67
80
  };
68
81
  export type SidecarCrawlerId = keyof typeof CRAWLER_DESCRIPTORS;
@@ -66,6 +66,8 @@ export declare class CrawlerSidecar {
66
66
  private opened;
67
67
  /** Identity of the attached crawler file; a crawler that replaces or deletes its archive forces a re-attach. */
68
68
  private attached;
69
+ /** Base FTS table plus any language-specific tables present in the attached archive. */
70
+ private ftsTables;
69
71
  /**
70
72
  * The last query's embedding and ranking. The semantic and hybrid methods of one search ask for the same
71
73
  * query, so they share one embedding call and one vector scan. Short-lived, and dropped on any write.
@@ -90,6 +92,8 @@ export declare class CrawlerSidecar {
90
92
  private whereParams;
91
93
  /** BM25-ranked lexical search. Natural-language queries are OR-ed term by term. */
92
94
  searchLexical(query: string, topK: number): SidecarHit[];
95
+ /** Descriptor-declared FTS tables that the attached archive actually defines. */
96
+ private presentExtraTables;
93
97
  /** Cosine search over embedded messages. Empty when there is no embedder or the query embedding fails. */
94
98
  searchSemantic(query: string, topK: number): Promise<SidecarHit[]>;
95
99
  /** Best `pool` stored vectors for `query`, reusing the previous ranking when it already covers `pool`. */
@@ -6,9 +6,10 @@
6
6
  import type { RetrievalMethod, RetrievalMethodDescriptor, RetrievalOptions, RetrievalResult } from "../../retrieval/types.js";
7
7
  import type { CrawlerDescriptor } from "./descriptors.js";
8
8
  import type { CrawlerSidecar } from "./index.js";
9
- export type SidecarMode = "bm25" | "semantic" | "hybrid";
9
+ export type SidecarMode = "bm25" | "hybrid";
10
10
  export interface SidecarMethodOptions {
11
- readonly sidecar: CrawlerSidecar;
11
+ /** Resolve lazily when the native CLI owns the archive location. */
12
+ readonly sidecar: CrawlerSidecar | ((signal?: AbortSignal) => Promise<CrawlerSidecar>);
12
13
  readonly descriptor: CrawlerDescriptor;
13
14
  readonly mode: SidecarMode;
14
15
  readonly datasourceId: string;
@@ -25,3 +26,12 @@ export declare class SidecarRetrievalMethod implements RetrievalMethod {
25
26
  retrieve(query: string, options: RetrievalOptions): Promise<RetrievalResult[]>;
26
27
  private toResult;
27
28
  }
29
+ /**
30
+ * The one method a sidecar-backed crawler registers. The sidecar's hybrid search leads when semantic
31
+ * search is enabled and its BM25 search leads otherwise. When the leader throws, the sidecar's own BM25
32
+ * answers next and the crawler's CLI search last, so the datasource still searches when the embedder or
33
+ * the sidecar index is down. A leader that answers with no hits is final.
34
+ */
35
+ export declare function sidecarFirstMethod(options: Omit<SidecarMethodOptions, "mode" | "sidecar"> & {
36
+ readonly sidecar: CrawlerSidecar;
37
+ }, cli: RetrievalMethod): RetrievalMethod;
@@ -29,6 +29,10 @@ export declare class ClawGallerySkill implements DatasourceSkill {
29
29
  describe(): DatasourceSkillDescriptor;
30
30
  polling(): PollingMetadata;
31
31
  index(options?: DatasourceIndexOptions): Promise<DatasourceIndexResult>;
32
+ /**
33
+ * Hybrid RRF-fuses every channel the index has, so it runs alone and keyword search stands in only
34
+ * when hybrid fails. A mode the operator pinned explicitly runs by itself with no fallback.
35
+ */
32
36
  retrievalMethods(): readonly RetrievalMethod[];
33
37
  describeSources(): readonly SourceDescription[];
34
38
  skillManifest(): DatasourceSkillManifest;
@@ -0,0 +1,139 @@
1
+ import type { DiscrawlAttachmentFetchResult, DiscrawlAttachmentListResult, DiscrawlStatusResult } from "./types.js";
2
+ /** Per-connection status file kept at the top of the attachments folder. */
3
+ export declare const DISCORD_ATTACHMENT_STATUS_FILENAME = "download-status.json";
4
+ /**
5
+ * Where a Discord connection's attachments are saved: `<AUTORAG_HOME>/attachments/discord/<connection>`.
6
+ * That is `~/.autorag/attachments/discord/<connection>` for every user on macOS, Linux, and Windows, unless
7
+ * `AUTORAG_HOME` moves the whole AutoRAG home.
8
+ */
9
+ export declare function discordAttachmentsRoot(connection: string, env?: NodeJS.ProcessEnv): string;
10
+ /**
11
+ * - `downloaded`: the saved file is still byte-identical to what Discord served.
12
+ * - `not-downloaded`: never saved.
13
+ * - `changed`: the saved file was edited. It stays as the user's own file; the original is fetched again.
14
+ * - `missing`: the saved file was deleted, moved, or renamed; the original is fetched again.
15
+ * - `failed`: the last download attempt failed (`error` says why).
16
+ * - `skipped`: discrawl refused the file (for example `too_large`) and it is not retried.
17
+ */
18
+ export type DiscordAttachmentState = "downloaded" | "not-downloaded" | "changed" | "missing" | "failed" | "skipped";
19
+ export interface DiscordAttachmentRecord {
20
+ readonly attachmentId: string;
21
+ readonly messageId: string;
22
+ readonly guildId: string;
23
+ readonly guildName?: string;
24
+ readonly channelId: string;
25
+ readonly channelName?: string;
26
+ readonly authorName?: string;
27
+ readonly createdAt?: string;
28
+ readonly filename: string;
29
+ readonly contentType?: string;
30
+ readonly size: number;
31
+ readonly state: DiscordAttachmentState;
32
+ /** True when the file is not saved intact and Discord's signed link still works. */
33
+ readonly downloadable: boolean;
34
+ /** When the signed link stops working (Discord signs attachment links for 24 hours). */
35
+ readonly linkExpiresAt?: string;
36
+ /** Saved file, relative to the attachments folder, with `/` separators. */
37
+ readonly path?: string;
38
+ readonly sha256?: string;
39
+ readonly bytes?: number;
40
+ readonly mtimeMs?: number;
41
+ readonly downloadedAt?: string;
42
+ readonly error?: string;
43
+ }
44
+ export interface DiscordAttachmentSummary {
45
+ readonly total: number;
46
+ readonly downloaded: number;
47
+ readonly notDownloaded: number;
48
+ readonly changed: number;
49
+ readonly missing: number;
50
+ readonly failed: number;
51
+ readonly skipped: number;
52
+ /** Not saved intact and still downloadable now. */
53
+ readonly downloadable: number;
54
+ /** Not saved intact and the link already expired: these can no longer be downloaded. */
55
+ readonly expired: number;
56
+ }
57
+ /** What one sync downloaded. */
58
+ export interface DiscordAttachmentRun {
59
+ readonly attempted: number;
60
+ readonly fetched: number;
61
+ readonly failed: number;
62
+ readonly skipped: number;
63
+ readonly bytes: number;
64
+ }
65
+ export interface DiscordAttachmentSyncOk {
66
+ readonly ok: true;
67
+ readonly root: string;
68
+ readonly statusPath: string;
69
+ readonly summary: DiscordAttachmentSummary;
70
+ readonly run: DiscordAttachmentRun;
71
+ readonly records: readonly DiscordAttachmentRecord[];
72
+ }
73
+ export interface DiscordAttachmentSyncFail {
74
+ readonly ok: false;
75
+ readonly reason: "busy" | "discrawl-failed";
76
+ readonly message: string;
77
+ }
78
+ export type DiscordAttachmentSyncResult = DiscordAttachmentSyncOk | DiscordAttachmentSyncFail;
79
+ export interface DiscordAttachmentSyncOptions {
80
+ /** Download every attachment that is not saved intact and whose link still works. */
81
+ readonly download: boolean;
82
+ readonly signal?: AbortSignal;
83
+ }
84
+ /** The discrawl calls the store needs; `DiscrawlClient` implements them. */
85
+ export interface DiscordAttachmentClient {
86
+ status(signal?: AbortSignal): Promise<DiscrawlStatusResult>;
87
+ listAttachments(configPath: string, guildId?: string, signal?: AbortSignal): Promise<DiscrawlAttachmentListResult>;
88
+ fetchAttachments(configPath: string, messageId: string, signal?: AbortSignal): Promise<DiscrawlAttachmentFetchResult>;
89
+ }
90
+ /** What the Discord skill calls after each import; `DiscordAttachmentStore` implements it. */
91
+ export interface DiscordAttachmentSyncer {
92
+ readonly root: string;
93
+ sync(options: DiscordAttachmentSyncOptions): Promise<DiscordAttachmentSyncResult>;
94
+ }
95
+ export interface DiscordAttachmentStoreOptions {
96
+ readonly client: DiscordAttachmentClient;
97
+ /** Attachments folder; see {@link discordAttachmentsRoot}. */
98
+ readonly root: string;
99
+ readonly guildId?: string;
100
+ readonly channelIds?: readonly string[];
101
+ readonly channelNames?: readonly string[];
102
+ readonly now?: () => number;
103
+ }
104
+ /**
105
+ * Saves Discord attachments into one folder and keeps `download-status.json` beside them.
106
+ *
107
+ * discrawl does the downloading; AutoRAG never talks to Discord itself. AutoRAG hands discrawl a private
108
+ * config whose `cache_dir` is `.discrawl/` inside the folder, asks it to fetch one message's attachments at a
109
+ * time, and then moves each file to `<server>/<channel>/<original name>`. A saved file is identified by its
110
+ * SHA-256: when the file at the recorded path is gone or its bytes differ, it no longer counts as the
111
+ * attachment. An edited file is left in place as the user's own and the original is saved again beside it
112
+ * under a free name, as long as Discord's signed link still works. Nothing in the folder is ever overwritten
113
+ * or deleted.
114
+ */
115
+ export declare class DiscordAttachmentStore implements DiscordAttachmentSyncer {
116
+ readonly root: string;
117
+ private readonly client;
118
+ private readonly guildId;
119
+ private readonly channelIds;
120
+ private readonly channelNames;
121
+ private readonly now;
122
+ constructor(options: DiscordAttachmentStoreOptions);
123
+ get statusPath(): string;
124
+ sync(options: DiscordAttachmentSyncOptions): Promise<DiscordAttachmentSyncResult>;
125
+ private syncLocked;
126
+ /** discrawl keeps reading the operator's archive but stores downloads in this folder's private cache. */
127
+ private writeDiscrawlConfig;
128
+ private channelAllowed;
129
+ private isDownloadable;
130
+ /** Re-checks a saved file. Unchanged size and mtime is trusted; anything else is hashed. */
131
+ private verify;
132
+ private download;
133
+ /** Puts a downloaded file at `<server>/<channel>/<name>`, never over an existing file. */
134
+ private place;
135
+ }
136
+ /** Discord signs attachment links with `ex=<hex unix seconds>`. */
137
+ export declare function signedLinkExpiry(url: string | undefined): string | undefined;
138
+ /** The original Discord file name, made safe for macOS, Linux, and Windows. */
139
+ export declare function safeFilename(name: string, attachmentId: string): string;
@@ -1,4 +1,4 @@
1
- import type { DiscrawlDoctorResult, DiscrawlEmbeddingConfigResult, DiscrawlEmbeddingRuntime, DiscrawlEmbedResult, DiscrawlMetadataResult, DiscrawlOptions, DiscrawlSearchMode, DiscrawlSearchOptions, DiscrawlSearchResult, DiscrawlStatusResult, DiscrawlSyncResult } from "./types.js";
1
+ import type { DiscrawlAttachmentFetchResult, DiscrawlAttachmentListResult, DiscrawlDoctorResult, DiscrawlEmbeddingConfigResult, DiscrawlEmbeddingRuntime, DiscrawlEmbedResult, DiscrawlMetadataResult, DiscrawlOptions, DiscrawlSearchMode, DiscrawlSearchOptions, DiscrawlSearchResult, DiscrawlStatusResult, DiscrawlSyncResult } from "./types.js";
2
2
  /**
3
3
  * Thin external `discrawl` CLI wrapper. Every method spawns the `discrawl`
4
4
  * binary as a child process, parses JSON from stdout, and returns a
@@ -27,8 +27,18 @@ export declare class DiscrawlClient {
27
27
  sync(signal?: AbortSignal): Promise<DiscrawlSyncResult>;
28
28
  embed(limit?: number, rebuild?: boolean, signal?: AbortSignal): Promise<DiscrawlEmbedResult>;
29
29
  search(mode: DiscrawlSearchMode, query: string, options?: DiscrawlSearchOptions): Promise<DiscrawlSearchResult>;
30
+ /**
31
+ * Lists every archived attachment with discrawl's fetch bookkeeping. `configPath` is the
32
+ * attachments-only config that points discrawl's `cache_dir` at AutoRAG's attachments folder; it
33
+ * replaces the operator/managed config for this call only.
34
+ */
35
+ listAttachments(configPath: string, guildId?: string, signal?: AbortSignal): Promise<DiscrawlAttachmentListResult>;
36
+ /** Downloads the attachments of one message into the config's `cache_dir` while their signed links live. */
37
+ fetchAttachments(configPath: string, messageId: string, signal?: AbortSignal): Promise<DiscrawlAttachmentFetchResult>;
30
38
  private runJson;
31
39
  private run;
40
+ /** Runs with an explicit `--config` and no embedding runtime: attachment commands never embed. */
41
+ private runWithConfig;
32
42
  }
33
43
  export declare function discrawlWorkspace(options: DiscrawlOptions): string | undefined;
34
44
  export declare function nativeGatewayBaseUrl(baseUrl: string): string;
@@ -1,5 +1,6 @@
1
+ export { DISCORD_ATTACHMENT_STATUS_FILENAME, type DiscordAttachmentClient, type DiscordAttachmentRecord, type DiscordAttachmentRun, type DiscordAttachmentState, DiscordAttachmentStore, type DiscordAttachmentStoreOptions, type DiscordAttachmentSummary, type DiscordAttachmentSyncer, type DiscordAttachmentSyncOptions, type DiscordAttachmentSyncResult, discordAttachmentsRoot, } from "./attachments.js";
1
2
  export { DiscrawlClient, discrawlWorkspace } from "./client.js";
2
3
  export { DiscrawlFtsMethod, DiscrawlHybridMethod, type DiscrawlMethodOptions, type DiscrawlSearchClient, DiscrawlSemanticMethod, } from "./methods.js";
3
4
  export { DISCRAWL_SOURCE_KIND, discrawlConfigPath, discrawlDatabasePath, discrawlDatasourceRoot, discrawlSourcePath, parseDiscrawlSourcePath, } from "./paths.js";
4
5
  export { DiscrawlSkill, type DiscrawlSkillClient, type DiscrawlSkillOptions } from "./skill.js";
5
- export { DEFAULT_DISCRAWL_BINARY, DEFAULT_DISCRAWL_EMBEDDING_MODEL, DEFAULT_DISCRAWL_EMBEDDING_PROVIDER, DEFAULT_DISCRAWL_MAX_BUFFER_BYTES, DEFAULT_DISCRAWL_MODE, DEFAULT_DISCRAWL_TIMEOUT_MS, type DiscrawlDoctorInfo, type DiscrawlDoctorResult, type DiscrawlEmbeddingConfigResult, type DiscrawlEmbeddingRuntime, type DiscrawlEmbedInfo, type DiscrawlEmbedResult, type DiscrawlFailure, type DiscrawlFailureReason, type DiscrawlMessage, type DiscrawlMetadataInfo, type DiscrawlMetadataResult, type DiscrawlOptions, type DiscrawlSearchHit, type DiscrawlSearchMode, type DiscrawlSearchOptions, type DiscrawlSearchResult, type DiscrawlStatusInfo, type DiscrawlStatusResult, type DiscrawlSyncInfo, type DiscrawlSyncResult, ENGLISH_ONLY_EMBEDDING_MODELS, } from "./types.js";
6
+ export { DEFAULT_DISCRAWL_BINARY, DEFAULT_DISCRAWL_EMBEDDING_MODEL, DEFAULT_DISCRAWL_EMBEDDING_PROVIDER, DEFAULT_DISCRAWL_MAX_BUFFER_BYTES, DEFAULT_DISCRAWL_MODE, DEFAULT_DISCRAWL_TIMEOUT_MS, type DiscrawlAttachmentFetchResult, type DiscrawlAttachmentFetchStats, type DiscrawlAttachmentListResult, type DiscrawlAttachmentRow, type DiscrawlDoctorInfo, type DiscrawlDoctorResult, type DiscrawlEmbeddingConfigResult, type DiscrawlEmbeddingRuntime, type DiscrawlEmbedInfo, type DiscrawlEmbedResult, type DiscrawlFailure, type DiscrawlFailureReason, type DiscrawlMessage, type DiscrawlMetadataInfo, type DiscrawlMetadataResult, type DiscrawlOptions, type DiscrawlSearchHit, type DiscrawlSearchMode, type DiscrawlSearchOptions, type DiscrawlSearchResult, type DiscrawlStatusInfo, type DiscrawlStatusResult, type DiscrawlSyncInfo, type DiscrawlSyncResult, ENGLISH_ONLY_EMBEDDING_MODELS, } from "./types.js";
@@ -0,0 +1,19 @@
1
+ import type { RetrievalMethod, RetrievalMethodDescriptor, RetrievalOptions, RetrievalResult } from "../../../retrieval/types.js";
2
+ import type { DiscrawlSearchMode } from "./types.js";
3
+ export interface DiscrawlRankedMethodOptions {
4
+ readonly mode: DiscrawlSearchMode;
5
+ readonly lexical: RetrievalMethod;
6
+ readonly nativeFts: RetrievalMethod;
7
+ readonly semantic: RetrievalMethod;
8
+ readonly workspaceId?: string;
9
+ readonly channelIds?: readonly string[];
10
+ readonly channelNames?: readonly string[];
11
+ }
12
+ /** One Discord ranking boundary: native FTS supplements BM25 rather than voting for the same messages again. */
13
+ export declare class DiscrawlRankedMethod implements RetrievalMethod {
14
+ private readonly options;
15
+ constructor(options: DiscrawlRankedMethodOptions);
16
+ describe(): RetrievalMethodDescriptor;
17
+ retrieve(query: string, options: RetrievalOptions): Promise<RetrievalResult[]>;
18
+ private matchesScope;
19
+ }
@@ -0,0 +1,21 @@
1
+ import { type ResolveSidecarInput } from "../../sidecar/config.js";
2
+ import { CrawlerSidecar, type CrawlerSidecarOptions } from "../../sidecar/index.js";
3
+ import type { DiscrawlStatusResult } from "./types.js";
4
+ export interface DiscrawlStatusClient {
5
+ status?(signal?: AbortSignal): Promise<DiscrawlStatusResult>;
6
+ }
7
+ export interface DiscrawlSidecarOptions extends Omit<CrawlerSidecarOptions, "crawlerDbPath" | "embedder"> {
8
+ /** Explicit archive path; omitted to discover it through the native client's status command. */
9
+ readonly crawlerDbPath?: string;
10
+ }
11
+ /** Discord reuses its native embeddings; its sidecar provides lexical ranking only. */
12
+ export declare function resolveDiscrawlSidecarOptions(input: Omit<ResolveSidecarInput, "descriptor" | "defaultCrawlerDb">): DiscrawlSidecarOptions | undefined;
13
+ /** Resolves the native archive on first search, without requiring indexing or a second vector store. */
14
+ export declare class DiscrawlSidecar {
15
+ private readonly options;
16
+ private readonly client;
17
+ private sidecar;
18
+ constructor(options: DiscrawlSidecarOptions, client: DiscrawlStatusClient);
19
+ get(signal?: AbortSignal): Promise<CrawlerSidecar>;
20
+ close(): void;
21
+ }
@@ -1,8 +1,10 @@
1
1
  import type { RetrievalMethod } from "../../../retrieval/types.js";
2
2
  import type { DatasourceIndexOptions, DatasourceIndexResult, DatasourceSkill, DatasourceSkillDescriptor, DatasourceSkillManifest, PollingMetadata, SourceDescription } from "../../types.js";
3
+ import type { DiscordAttachmentSyncer } from "./attachments.js";
3
4
  import { type DiscrawlSearchClient } from "./methods.js";
5
+ import { type DiscrawlSidecarOptions, type DiscrawlStatusClient } from "./sidecar.js";
4
6
  import type { DiscrawlDoctorResult, DiscrawlEmbedResult, DiscrawlSearchMode, DiscrawlSyncResult } from "./types.js";
5
- export interface DiscrawlSkillClient extends DiscrawlSearchClient {
7
+ export interface DiscrawlSkillClient extends DiscrawlSearchClient, DiscrawlStatusClient {
6
8
  doctor(signal?: AbortSignal): Promise<DiscrawlDoctorResult>;
7
9
  sync(signal?: AbortSignal): Promise<DiscrawlSyncResult>;
8
10
  embed(limit?: number, rebuild?: boolean, signal?: AbortSignal): Promise<DiscrawlEmbedResult>;
@@ -22,12 +24,19 @@ export interface DiscrawlSkillOptions {
22
24
  readonly embedLimit?: number;
23
25
  readonly channelIds?: readonly string[];
24
26
  readonly channelNames?: readonly string[];
27
+ /** Optional lexical-only sidecar. Its archive path is discovered through native status when omitted. */
28
+ readonly sidecar?: DiscrawlSidecarOptions;
29
+ /**
30
+ * Saves attachments right after each successful import, while Discord's 24-hour signed links still work.
31
+ * Built by default (`connector.downloadAttachments: false` disables it); absent means attachments are not downloaded.
32
+ */
33
+ readonly attachments?: DiscordAttachmentSyncer;
25
34
  }
26
35
  /**
27
36
  * Discord datasource skill backed by the external `discrawl` CLI.
28
37
  *
29
38
  * Mirrors the lazykatok model: the CLI owns the archive, the FTS5 index, and the
30
- * vector index; AutoRAG only spawns it and maps results. AutoRAG never calls
39
+ * vector index; an optional read-only sidecar adds BM25 lexical ranking. AutoRAG never calls
31
40
  * the Discord API itself and never reads the Discord Desktop cache directly.
32
41
  *
33
42
  * `index()` runs the CLI's two-phase pipeline — `sync` (incremental, cursor
@@ -43,14 +52,26 @@ export declare class DiscrawlSkill implements DatasourceSkill {
43
52
  private readonly embeddingModel;
44
53
  private readonly defaultMode;
45
54
  private readonly embedLimit;
55
+ private readonly sidecar;
56
+ private readonly retrievalScope;
57
+ private readonly attachments;
46
58
  private lastIndexedAt;
47
59
  constructor(options: DiscrawlSkillOptions);
48
60
  describe(): DatasourceSkillDescriptor;
49
61
  polling(): PollingMetadata;
50
62
  index(options?: DatasourceIndexOptions): Promise<DatasourceIndexResult>;
63
+ /**
64
+ * One method per query. Hybrid is the default and already degrades to FTS inside the single
65
+ * `discrawl search` call when embeddings are unavailable, so FTS and semantic are not registered
66
+ * beside it; an operator who pins `defaultMode` to `fts` or `semantic` gets exactly that mode.
67
+ */
51
68
  retrievalMethods(): readonly RetrievalMethod[];
69
+ /** Release the optional sidecar without changing the native archive. */
70
+ close(): void;
52
71
  describeSources(): readonly SourceDescription[];
53
72
  skillManifest(): DatasourceSkillManifest;
73
+ /** Best effort: a failed or expired download never fails the index, and messages stay searchable. */
74
+ private downloadAttachments;
54
75
  private runEmbed;
55
76
  /**
56
77
  * English-only embedders map non-English text into one narrow similarity
@@ -101,6 +101,11 @@ export interface DiscrawlOptions {
101
101
  * issue #1413.
102
102
  */
103
103
  readonly defaultMode?: DiscrawlSearchMode;
104
+ /**
105
+ * Spawn timeout for `discrawl attachments fetch`. Defaults to the shared connector sync budget, because a
106
+ * burst of attachments downloads far longer than one wiretap import.
107
+ */
108
+ readonly attachmentTimeoutMs?: number;
104
109
  /** Environment overrides merged on top of `process.env` for the child. */
105
110
  readonly env?: Readonly<Record<string, string | undefined>>;
106
111
  }
@@ -203,6 +208,42 @@ export type DiscrawlMetadataResult = DiscrawlOk<DiscrawlMetadataInfo> | Discrawl
203
208
  export type DiscrawlSyncResult = DiscrawlOk<DiscrawlSyncInfo> | DiscrawlFailure;
204
209
  export type DiscrawlEmbedResult = DiscrawlOk<DiscrawlEmbedInfo> | DiscrawlFailure;
205
210
  export type DiscrawlSearchResult = DiscrawlSearchOk | DiscrawlFailure;
211
+ /** One row of `discrawl --json attachments`: metadata plus discrawl's own fetch bookkeeping. */
212
+ export interface DiscrawlAttachmentRow {
213
+ readonly attachmentId: string;
214
+ readonly messageId: string;
215
+ readonly guildId: string;
216
+ readonly guildName?: string;
217
+ readonly channelId: string;
218
+ readonly channelName?: string;
219
+ readonly authorName?: string;
220
+ readonly filename: string;
221
+ readonly contentType?: string;
222
+ readonly size: number;
223
+ readonly url?: string;
224
+ readonly proxyUrl?: string;
225
+ /** Path relative to `<cache_dir>/media`, set once discrawl stored the file. */
226
+ readonly mediaPath?: string;
227
+ readonly contentSha256?: string;
228
+ readonly contentSize?: number;
229
+ /** `fetched`, `failed`, a skip reason such as `too_large`, or empty when never attempted. */
230
+ readonly fetchStatus?: string;
231
+ readonly fetchError?: string;
232
+ /** When discrawl last attempted the download (RFC 3339). */
233
+ readonly fetchedAt?: string;
234
+ readonly createdAt?: string;
235
+ }
236
+ /** Result of `discrawl --json attachments fetch`. */
237
+ export interface DiscrawlAttachmentFetchStats {
238
+ readonly attachments: number;
239
+ readonly fetched: number;
240
+ readonly reused: number;
241
+ readonly skipped: number;
242
+ readonly failed: number;
243
+ readonly bytes: number;
244
+ }
245
+ export type DiscrawlAttachmentListResult = DiscrawlOk<readonly DiscrawlAttachmentRow[]> | DiscrawlFailure;
246
+ export type DiscrawlAttachmentFetchResult = DiscrawlOk<DiscrawlAttachmentFetchStats> | DiscrawlFailure;
206
247
  /**
207
248
  * Search-specific options. Reuses the shared {@link RetrievalOptions} so the
208
249
  * retrieval methods can pass their options straight through.
@@ -10,7 +10,7 @@
10
10
  import type { Embedder } from "../../embedding/embedder.js";
11
11
  import type { EmbeddingEndpointSource } from "../embedding-env.js";
12
12
  import type { DatasourceSkill } from "../types.js";
13
- import { type DiscrawlEmbeddingRuntime } from "./discrawl/index.js";
13
+ import { DiscordAttachmentStore, type DiscrawlEmbeddingRuntime } from "./discrawl/index.js";
14
14
  import { type ObsidianMinSyncOptions } from "./obsidian/index.js";
15
15
  /** One configured datasource entry (the trusted `datasources.<name>` value). */
16
16
  export interface DatasourceSkillConfig {
@@ -50,7 +50,22 @@ export interface DatasourceEmbeddingOptions {
50
50
  /** MinSync binary, embedder and chunking shared with the local-file index; vault indexes run on it too. */
51
51
  readonly minSync?: ObsidianMinSyncOptions;
52
52
  }
53
- /** Skill names this factory can build. */
53
+ export interface DiscordAttachmentConnection {
54
+ readonly name: string;
55
+ /** Whether refreshes download automatically (`connector.downloadAttachments !== false`, default on). */
56
+ readonly autoDownload: boolean;
57
+ readonly store: DiscordAttachmentStore;
58
+ }
59
+ /**
60
+ * Every enabled Discord connection's attachments folder, built exactly as a refresh builds it, so
61
+ * `autorag attachments` and the refresh always agree on where files live.
62
+ */
63
+ export declare function discordAttachmentConnections(config: DatasourcesConfig | undefined, workspaceRoot?: string): readonly DiscordAttachmentConnection[];
64
+ /** Whether the skill's backend exists on `platform`. Names with no platform restriction are always supported. */
65
+ export declare function datasourceSkillSupported(name: string, platform?: NodeJS.Platform): boolean;
66
+ /** Skill names this factory can build on `platform`. */
67
+ export declare function builtinDatasourceSkillNames(platform?: NodeJS.Platform): readonly string[];
68
+ /** Skill names this factory can build on the running platform. */
54
69
  export declare const BUILTIN_DATASOURCE_SKILL_NAMES: readonly string[];
55
70
  /**
56
71
  * Build datasource skills from the trusted config section. `false` or
@@ -6,7 +6,7 @@
6
6
  * the form `/kakao/<instance-id>/chunks/<chunk-id>`.
7
7
  */
8
8
  export { LazykatokClient } from "./client.js";
9
- export { LazykatokBm25Method, type LazykatokMethodOptions, type LazykatokSearchClient, LazykatokSemanticMethod, } from "./methods.js";
9
+ export { LazykatokBm25Method, LazykatokHybridMethod, type LazykatokMethodOptions, type LazykatokSearchClient, } from "./methods.js";
10
10
  export { LazykatokSkill, type LazykatokSkillClient, type LazykatokSkillOptions } from "./skill.js";
11
11
  export type { LazykatokChunkResult, LazykatokDoctorResult, LazykatokFailureReason, LazykatokHit, LazykatokIndexResult, LazykatokOptions, LazykatokSearchMode, LazykatokSearchOptions, LazykatokSearchResult, LazykatokSyncResult, } from "./types.js";
12
12
  export { DEFAULT_LAZYKATOK_INDEX_TIMEOUT_MS, DEFAULT_LAZYKATOK_OPTIONS } from "./types.js";
@@ -27,12 +27,12 @@ export declare class LazykatokBm25Method implements RetrievalMethod {
27
27
  retrieve(query: string, options: RetrievalOptions): Promise<RetrievalResult[]>;
28
28
  }
29
29
  /**
30
- * Semantic (vector) retrieval over a KakaoTalk datasource via the external
31
- * `lazykatok` CLI in semantic mode. Lazykatok does not expose source scopes; access is
32
- * controlled at the datasource/tag level. All client failures collapse to an
33
- * empty result set; retrieval never throws.
30
+ * Hybrid retrieval over a KakaoTalk datasource via the external `lazykatok` CLI in hybrid mode
31
+ * (BM25 and semantic rankings fused by reciprocal rank fusion inside the CLI). Lazykatok does not
32
+ * expose source scopes; access is controlled at the datasource/tag level. Client failures reach the
33
+ * caller verbatim so the pipeline can fall back to {@link LazykatokBm25Method}.
34
34
  */
35
- export declare class LazykatokSemanticMethod implements RetrievalMethod {
35
+ export declare class LazykatokHybridMethod implements RetrievalMethod {
36
36
  private readonly client;
37
37
  private readonly instanceId;
38
38
  private readonly tags;
@@ -38,6 +38,7 @@ export declare class LazykatokSkill implements DatasourceSkill {
38
38
  index(options?: DatasourceIndexOptions): Promise<DatasourceIndexResult>;
39
39
  /** Release the sidecar's database handles. Safe to call repeatedly; later use reopens them. */
40
40
  close(): void;
41
+ /** One method: sidecar hybrid when a sidecar is configured, else the CLI's hybrid; BM25 is the fallback either way. */
41
42
  retrievalMethods(): readonly RetrievalMethod[];
42
43
  private syncSidecar;
43
44
  describeSources(): readonly SourceDescription[];
@@ -27,6 +27,7 @@ export declare class MailcrawlSkill implements DatasourceSkill {
27
27
  describe(): DatasourceSkillDescriptor;
28
28
  polling(): PollingMetadata;
29
29
  index(options?: DatasourceIndexOptions): Promise<DatasourceIndexResult>;
30
+ /** Hybrid search first; BM25 only when mailcrawl cannot run hybrid (for example, no usable semantic index). */
30
31
  retrievalMethods(): readonly RetrievalMethod[];
31
32
  describeSources(): readonly SourceDescription[];
32
33
  skillManifest(): DatasourceSkillManifest;