@cerebriline/core 4.100.240 → 4.100.241

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 (59) hide show
  1. package/assets/skills/README.md +14 -0
  2. package/assets/skills/build-project/SKILL.md +103 -0
  3. package/assets/skills/docker-compose-deploy/SKILL.md +239 -0
  4. package/assets/skills/librarian/SKILL.md +177 -0
  5. package/assets/skills/mandatory-qa-prompt-and-issue-resolution/SKILL.md +58 -0
  6. package/assets/skills/run-project/SKILL.md +103 -0
  7. package/assets/skills/sdd-discuss/SKILL.md +129 -0
  8. package/assets/skills/sdd-execute/SKILL.md +146 -0
  9. package/assets/skills/sdd-plan/SKILL.md +140 -0
  10. package/assets/skills/sdd-quick/SKILL.md +40 -0
  11. package/assets/skills/sdd-status/SKILL.md +75 -0
  12. package/assets/skills/sdd-verify/SKILL.md +122 -0
  13. package/assets/skills/sdd-wizard/SKILL.md +105 -0
  14. package/assets/skills/tdd-coverage/SKILL.md +88 -0
  15. package/assets/skills/tdd-gen/SKILL.md +82 -0
  16. package/assets/skills/tdd-test/SKILL.md +61 -0
  17. package/assets/skills/tdd-wizard/SKILL.md +162 -0
  18. package/dist/extensions/config/bundled-skills.d.ts +24 -0
  19. package/dist/extensions/config/index.d.ts +2 -1
  20. package/dist/extensions/config/unified-config-file-watcher.d.ts +15 -0
  21. package/dist/extensions/config/user-instruction-config-loader.d.ts +15 -0
  22. package/dist/extensions/tools/executors/document/ebook.d.ts +10 -0
  23. package/dist/extensions/tools/executors/document/formats.d.ts +25 -0
  24. package/dist/extensions/tools/executors/document/ocr.d.ts +3 -0
  25. package/dist/extensions/tools/executors/document/recognition.d.ts +16 -0
  26. package/dist/extensions/tools/executors/document-extract.d.ts +91 -0
  27. package/dist/extensions/tools/librarian-tools.d.ts +35 -0
  28. package/dist/extensions/tools/library-import-run.d.ts +79 -0
  29. package/dist/extensions/tools/library-tools.d.ts +88 -0
  30. package/dist/extensions/tools/memory-tools.d.ts +41 -0
  31. package/dist/extensions/tools/sdd-tool.d.ts +215 -0
  32. package/dist/extensions/tools/team/create-agent-tool.d.ts +5 -4
  33. package/dist/hub/daemon/entry.js +547 -545
  34. package/dist/hub/index.js +531 -529
  35. package/dist/index.d.ts +17 -1
  36. package/dist/index.js +1070 -689
  37. package/dist/services/global-settings.d.ts +9 -0
  38. package/dist/services/llms/provider-settings.d.ts +15 -15
  39. package/dist/services/retrieval/catalogue.d.ts +370 -0
  40. package/dist/services/retrieval/chunker.d.ts +44 -0
  41. package/dist/services/retrieval/embedding-client.d.ts +78 -0
  42. package/dist/services/retrieval/fingerprint.d.ts +21 -0
  43. package/dist/services/retrieval/firecrawl.d.ts +77 -0
  44. package/dist/services/retrieval/lancedb-runtime.d.ts +84 -0
  45. package/dist/services/retrieval/lancedb-runtime.manifest.d.ts +17 -0
  46. package/dist/services/retrieval/library-store.d.ts +148 -0
  47. package/dist/services/retrieval/library.d.ts +139 -0
  48. package/dist/services/retrieval/memory-recall.d.ts +97 -0
  49. package/dist/services/retrieval/memory.d.ts +184 -0
  50. package/dist/services/retrieval/retrieve.d.ts +85 -0
  51. package/dist/services/retrieval/tar-extract.d.ts +14 -0
  52. package/dist/services/retrieval/tar-write.d.ts +20 -0
  53. package/dist/services/retrieval/vector-index.d.ts +82 -0
  54. package/dist/services/sdd/sdd-engine.d.ts +248 -0
  55. package/dist/services/telemetry/index.js +1 -1
  56. package/dist/types/config.d.ts +7 -0
  57. package/dist/types/session.d.ts +2 -0
  58. package/package.json +4 -4
  59. package/dist/extensions/tools/code-intel.d.ts +0 -131
@@ -0,0 +1,77 @@
1
+ /**
2
+ * A Firecrawl endpoint, as the Library's scraper uses it: one page, a crawl
3
+ * from a page outwards, the links of a site, and a web search.
4
+ *
5
+ * Pages are asked for as HTML and turned into markdown here. Firecrawl's own
6
+ * markdown loses fenced code blocks, which is most of what a book made from
7
+ * documentation is for.
8
+ */
9
+ export interface ScrapeEndpoint {
10
+ /** The endpoint's address: `http://host:3002`. */
11
+ baseUrl: string;
12
+ apiKey?: string;
13
+ }
14
+ export interface ScrapedPage {
15
+ url: string;
16
+ title?: string;
17
+ description?: string;
18
+ language?: string;
19
+ markdown: string;
20
+ /** A hash of the markdown: whether the page changed since it was last read. */
21
+ sha256: string;
22
+ /** The links on the page, when they were asked for. */
23
+ links?: string[];
24
+ }
25
+ export interface ScrapeFailure {
26
+ url: string;
27
+ reason: string;
28
+ }
29
+ export interface CrawlOptions {
30
+ /** Pages read, at most. */
31
+ limit: number;
32
+ /** How many links deep from the starting page. */
33
+ depth: number;
34
+ /** Only paths matching these (regular expressions), when given. */
35
+ includePaths?: readonly string[];
36
+ excludePaths?: readonly string[];
37
+ signal?: AbortSignal;
38
+ fetch?: typeof fetch;
39
+ /** How long to wait for the crawl. @default 20 minutes */
40
+ timeoutMs?: number;
41
+ onProgress?: (done: number, total: number) => void;
42
+ }
43
+ export interface CrawlResult {
44
+ pages: ScrapedPage[];
45
+ failed: ScrapeFailure[];
46
+ /** Set when the crawl was still running at the time limit. */
47
+ unfinished?: boolean;
48
+ }
49
+ export interface WebSearchHit {
50
+ url: string;
51
+ title?: string;
52
+ description?: string;
53
+ }
54
+ interface RequestOptions {
55
+ signal?: AbortSignal;
56
+ fetch?: typeof fetch;
57
+ }
58
+ export declare class ScrapeError extends Error {
59
+ }
60
+ /** A page's HTML as markdown, with its code blocks fenced. */
61
+ export declare function htmlToMarkdown(html: string): Promise<string>;
62
+ /** Read one page. */
63
+ export declare function scrapePage(endpoint: ScrapeEndpoint, url: string, options?: RequestOptions & {
64
+ links?: boolean;
65
+ }): Promise<ScrapedPage>;
66
+ /** Read a page and the pages it links to, as deep and as many as `options` allow. */
67
+ export declare function crawlSite(endpoint: ScrapeEndpoint, url: string, options: CrawlOptions): Promise<CrawlResult>;
68
+ /** The pages of a site, by their links, without reading them. */
69
+ export declare function mapSite(endpoint: ScrapeEndpoint, url: string, options?: RequestOptions & {
70
+ limit?: number;
71
+ search?: string;
72
+ }): Promise<string[]>;
73
+ /** Search the web. Works when the endpoint has a search provider behind it. */
74
+ export declare function searchWeb(endpoint: ScrapeEndpoint, query: string, options?: RequestOptions & {
75
+ limit?: number;
76
+ }): Promise<WebSearchHit[]>;
77
+ export {};
@@ -0,0 +1,84 @@
1
+ /**
2
+ * LanceDB, fetched when it is first needed.
3
+ *
4
+ * The vector index of the Library is LanceDB, whose native library is 200 to
5
+ * 390 MB depending on the platform. That cannot ship in the extension, so it
6
+ * is downloaded once into the data folder, the way OCR languages are: the
7
+ * JavaScript packages and the one native package for this machine, straight
8
+ * from the npm registry, each checked against the integrity pinned in
9
+ * `lancedb-runtime.manifest.ts` before anything is used.
10
+ *
11
+ * Keyword search does not depend on any of this.
12
+ */
13
+ import { type LanceDbRuntimeManifest } from "./lancedb-runtime.manifest";
14
+ export interface LanceDbInstallProgress {
15
+ /** The package being fetched, and how many there are. */
16
+ packageIndex: number;
17
+ packageCount: number;
18
+ path: string;
19
+ /** Bytes of this package received so far, and its size when the server said. */
20
+ receivedBytes: number;
21
+ totalBytes?: number;
22
+ }
23
+ export interface LanceDbRuntimeOptions {
24
+ /** The folder runtimes are kept in, e.g. `<data>/runtimes/lancedb`. */
25
+ directory: string;
26
+ manifest?: LanceDbRuntimeManifest;
27
+ fetch?: typeof fetch;
28
+ onProgress?: (progress: LanceDbInstallProgress) => void;
29
+ signal?: AbortSignal;
30
+ /** For tests: the platform key to install for. */
31
+ platformKey?: string;
32
+ }
33
+ export interface LanceDbRuntime {
34
+ /** The `@lancedb/lancedb` module. */
35
+ lancedb: any;
36
+ /** The `apache-arrow` module LanceDB was installed with. */
37
+ arrow: any;
38
+ version: string;
39
+ root: string;
40
+ }
41
+ export declare class LanceDbUnavailableError extends Error {
42
+ constructor(message: string);
43
+ }
44
+ /** `linux-x64-gnu`, `win32-x64`, `darwin-arm64`: the key into the manifest. */
45
+ export declare function currentPlatformKey(): string;
46
+ export declare function lanceDbRuntimeRoot(options: Pick<LanceDbRuntimeOptions, "directory" | "manifest">): string;
47
+ export declare function isLanceDbInstalled(options: Pick<LanceDbRuntimeOptions, "directory" | "manifest">): boolean;
48
+ /** Why LanceDB cannot run here, or undefined when it can. */
49
+ export declare function lanceDbUnsupportedReason(options?: Pick<LanceDbRuntimeOptions, "manifest" | "platformKey">): string | undefined;
50
+ /** How much will be downloaded and unpacked for this platform, when known. */
51
+ export declare function lanceDbInstallBytes(options?: Pick<LanceDbRuntimeOptions, "manifest" | "platformKey">): number | undefined;
52
+ /**
53
+ * Download and unpack LanceDB for this machine, unless it is already there.
54
+ * Everything lands in a folder of its own first and is moved into place only
55
+ * when every package has been verified, so an interrupted or failed install
56
+ * leaves nothing that looks installed.
57
+ */
58
+ export declare function installLanceDb(options: LanceDbRuntimeOptions): Promise<string>;
59
+ /** Load an installed LanceDB. Throws `LanceDbUnavailableError` when it is not installed. */
60
+ export declare function loadLanceDb(options: Pick<LanceDbRuntimeOptions, "directory" | "manifest">): LanceDbRuntime;
61
+ /** Where LanceDB stands here: for a settings panel, and for a bug report. */
62
+ export interface LanceDbStatus {
63
+ /** The version this build installs. */
64
+ version: string;
65
+ platform: string;
66
+ installed: boolean;
67
+ /** Installed, and the native library loaded in this process. */
68
+ working: boolean;
69
+ /** Why it did not load, when it is installed and did not. */
70
+ error?: string;
71
+ /** Why it cannot run here at all. */
72
+ unsupported?: string;
73
+ /** What a download unpacks to, when known. */
74
+ installBytes?: number;
75
+ root: string;
76
+ }
77
+ /**
78
+ * Whether LanceDB is installed and actually loads. Loading is the part
79
+ * worth checking: the files being there says nothing about whether this
80
+ * process, with its Node and its C library, can open the native library.
81
+ */
82
+ export declare function lanceDbStatus(options: Pick<LanceDbRuntimeOptions, "directory" | "manifest">): LanceDbStatus;
83
+ /** Install if needed, then load. */
84
+ export declare function ensureLanceDb(options: LanceDbRuntimeOptions): Promise<LanceDbRuntime>;
@@ -0,0 +1,17 @@
1
+ export interface LanceDbRuntimePackage {
2
+ /** Where it is unpacked, relative to the runtime folder. */
3
+ path: string;
4
+ tarball: string;
5
+ /** `sha512-<base64>`, as npm records it. */
6
+ integrity: string;
7
+ unpackedBytes?: number;
8
+ }
9
+ export interface LanceDbRuntimeManifest {
10
+ version: string;
11
+ arrow: string;
12
+ /** The JavaScript packages, the same on every platform. */
13
+ packages: LanceDbRuntimePackage[];
14
+ /** The native library, by `<platform>-<arch>` with `-gnu`/`-musl` on Linux. */
15
+ platforms: Record<string, LanceDbRuntimePackage>;
16
+ }
17
+ export declare const LANCEDB_RUNTIME_MANIFEST: LanceDbRuntimeManifest;
@@ -0,0 +1,148 @@
1
+ /**
2
+ * The Library's text store: collections, their documents, and the chunks
3
+ * each document was cut into, in one SQLite file with a full-text index.
4
+ *
5
+ * This is the part of the Library that needs no model. Keyword search works
6
+ * from the moment a document is added; vectors, when an embedding model is
7
+ * set, are kept elsewhere and refer to a chunk by the id it has here.
8
+ *
9
+ * The index is FTS5's external-content form, so the text of a library of
10
+ * books is stored once, in `chunks`, and not a second time in the index.
11
+ */
12
+ import { type SqliteDb } from "@cerebriline/shared/db";
13
+ import type { TextChunk } from "./chunker";
14
+ export interface LibraryCollection {
15
+ id: number;
16
+ name: string;
17
+ createdAt: string;
18
+ documents: number;
19
+ chunks: number;
20
+ }
21
+ export interface LibraryDocumentInput {
22
+ /** Where it came from: a path or a URL. One document per source in a collection. */
23
+ source: string;
24
+ title?: string;
25
+ /** A hash of the content. A source added again with the same hash is left alone. */
26
+ contentHash: string;
27
+ bytes?: number;
28
+ /** Anything else worth keeping: author, language, pages. */
29
+ metadata?: Record<string, unknown>;
30
+ }
31
+ export interface LibraryDocument {
32
+ id: number;
33
+ collectionId: number;
34
+ source: string;
35
+ title?: string;
36
+ contentHash: string;
37
+ bytes?: number;
38
+ chunks: number;
39
+ addedAt: string;
40
+ metadata: Record<string, unknown>;
41
+ }
42
+ export interface AddDocumentResult {
43
+ document: LibraryDocument;
44
+ /** "unchanged" when the same content was already there and nothing was written. */
45
+ outcome: "added" | "replaced" | "unchanged";
46
+ /** The ids given to the chunks, in order. Empty for "unchanged". */
47
+ chunkIds: number[];
48
+ /**
49
+ * For "replaced": the id the document had before. Its chunks are gone, and
50
+ * whatever else was kept under that id (its vectors) is the caller's to remove.
51
+ */
52
+ replacedDocumentId?: number;
53
+ }
54
+ export interface KeywordSearchOptions {
55
+ /** Collections to search. All of them when left out. */
56
+ collectionIds?: readonly number[];
57
+ /** Hits returned. Default 10. */
58
+ limit?: number;
59
+ /**
60
+ * Also match the document's file name, title and section headers, at this
61
+ * weight against the text's 1. 0 searches the text alone. Default 0.5.
62
+ */
63
+ contextWeight?: number;
64
+ }
65
+ export interface LibraryHit {
66
+ chunkId: number;
67
+ documentId: number;
68
+ collectionId: number;
69
+ /** Higher is better. BM25 for keyword hits; not comparable across queries. */
70
+ score: number;
71
+ text: string;
72
+ start: number;
73
+ end: number;
74
+ headings: string[];
75
+ source: string;
76
+ title?: string;
77
+ }
78
+ /** The words of a query, as the index's tokenizer would see them. */
79
+ export declare function queryTerms(query: string): string[];
80
+ /** What the index also matches on for a chunk: file name, title, headers. */
81
+ export declare function chunkContext(document: Pick<LibraryDocumentInput, "source" | "title">, headings: readonly string[]): string;
82
+ export declare class LibraryStore {
83
+ private readonly db;
84
+ constructor(filePath: string);
85
+ close(): void;
86
+ /** The database itself, for the catalogue kept in the same file. */
87
+ get database(): SqliteDb;
88
+ transaction<T>(run: () => T): T;
89
+ /** The collection of that name, created if it is not there. */
90
+ ensureCollection(name: string): LibraryCollection;
91
+ /** Give a collection another name. The documents and vectors stay as they are. */
92
+ renameCollection(collectionId: number, name: string): void;
93
+ listCollections(): LibraryCollection[];
94
+ /** Removes the collection with its documents and chunks. */
95
+ deleteCollection(collectionId: number): void;
96
+ private toDocument;
97
+ listDocuments(collectionId: number): LibraryDocument[];
98
+ findDocument(collectionId: number, source: string): LibraryDocument | undefined;
99
+ /**
100
+ * Adds a document with its chunks, in one transaction. The same source
101
+ * with the same content is left as it is; with different content, the old
102
+ * chunks are replaced.
103
+ */
104
+ addDocument(collectionId: number, input: LibraryDocumentInput, chunks: readonly TextChunk[]): AddDocumentResult;
105
+ deleteDocument(documentId: number): void;
106
+ getDocument(documentId: number): LibraryDocument | undefined;
107
+ /** A document's chunks, in order: what is embedded. */
108
+ documentChunks(documentId: number): LibraryHit[];
109
+ /** Documents with chunks and no vectors yet for this model, oldest first. */
110
+ /**
111
+ * The documents with no vectors for this model at the size it returns
112
+ * now. The size is the one last seen (`noteDimension`) unless given; a
113
+ * model never seen has no size to hold a document to.
114
+ */
115
+ documentsWithoutEmbedding(model: string, collectionIds?: readonly number[], dimension?: number | undefined): LibraryDocument[];
116
+ /** Record the vector size a model returned. True when it differs from the last one seen. */
117
+ noteDimension(model: string, dimension: number): boolean;
118
+ knownDimension(model: string): number | undefined;
119
+ /** Every model and size documents are recorded as embedded with, and how many. */
120
+ embeddingSets(): {
121
+ model: string;
122
+ dimension: number;
123
+ documents: number;
124
+ }[];
125
+ /** Forget that documents were embedded with this model at this size: their vectors are gone. */
126
+ forgetEmbeddings(model: string, dimension: number): void;
127
+ markEmbedded(documentId: number, model: string, dimension: number): void;
128
+ /** Totals, and how many documents have vectors for this model. */
129
+ counts(model?: string, dimension?: number | undefined): {
130
+ collections: number;
131
+ documents: number;
132
+ chunks: number;
133
+ embeddedDocuments: number;
134
+ };
135
+ private toHit;
136
+ /** Chunks by id, in the order asked for. Unknown ids are left out. */
137
+ getChunks(chunkIds: readonly number[]): LibraryHit[];
138
+ /**
139
+ * The query's terms worth searching for: those that are not in a large
140
+ * share of all chunks. If that leaves none, all of them are kept.
141
+ */
142
+ private selectiveTerms;
143
+ /**
144
+ * Keyword search, ranked by BM25. A chunk matches when it holds any of
145
+ * the query's terms; the more of them and the rarer they are, the higher.
146
+ */
147
+ searchKeywords(query: string, options?: KeywordSearchOptions): LibraryHit[];
148
+ }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The Library: documents kept for retrieval.
3
+ *
4
+ * It ties the pieces together. Text goes in as chunks in SQLite, where it is
5
+ * searchable by keyword at once; vectors are a second pass that needs an
6
+ * embedding model and LanceDB, and can be run later, resumed, or never.
7
+ */
8
+ import { type LibrarySettings } from "@cerebriline/shared";
9
+ import { Catalogue } from "./catalogue";
10
+ import { type RetrievalEndpoint } from "./embedding-client";
11
+ import { type LanceDbInstallProgress } from "./lancedb-runtime";
12
+ import { type AddDocumentResult, type LibraryDocument, LibraryStore } from "./library-store";
13
+ import { type RetrieveResult } from "./retrieve";
14
+ import { VectorIndex } from "./vector-index";
15
+ export declare function resolveLibraryDirectory(): string;
16
+ export declare function resolveLanceDbRuntimeDirectory(): string;
17
+ export interface LibraryOptions {
18
+ /** Where the Library is kept. @default <data dir>/library */
19
+ directory?: string;
20
+ /** Where LanceDB is installed. @default <data dir>/runtimes/lancedb */
21
+ runtimeDirectory?: string;
22
+ fetch?: typeof fetch;
23
+ }
24
+ export interface LibraryDocumentText {
25
+ source: string;
26
+ title?: string;
27
+ /** The document as text or markdown. */
28
+ text: string;
29
+ bytes?: number;
30
+ metadata?: Record<string, unknown>;
31
+ }
32
+ export interface EmbedProgress {
33
+ document: LibraryDocument;
34
+ documentIndex: number;
35
+ documentCount: number;
36
+ chunksDone: number;
37
+ }
38
+ export interface EmbedPendingOptions {
39
+ embedding: RetrievalEndpoint;
40
+ settings?: LibrarySettings;
41
+ collectionIds?: readonly number[];
42
+ /**
43
+ * Download LanceDB when it is not installed. Off, a Library with no
44
+ * LanceDB embeds nothing and says why.
45
+ */
46
+ install?: boolean;
47
+ onInstallProgress?: (progress: LanceDbInstallProgress) => void;
48
+ onProgress?: (progress: EmbedProgress) => void;
49
+ /**
50
+ * Ask the model for one vector first, to learn the size it returns now.
51
+ * For a run the user asked for: without it, a model that changed size
52
+ * since everything was embedded looks finished until the next search.
53
+ */
54
+ probe?: boolean;
55
+ signal?: AbortSignal;
56
+ }
57
+ export interface EmbedPendingResult {
58
+ documents: number;
59
+ chunks: number;
60
+ dimension?: number;
61
+ /** Why nothing was embedded, when that is so. */
62
+ skipped?: string;
63
+ }
64
+ export interface LibraryVectorSet {
65
+ /** What `deleteVectorSet` takes. */
66
+ table: string;
67
+ model: string;
68
+ dimension: number;
69
+ vectors: number;
70
+ /** Documents recorded as embedded with it. */
71
+ documents: number;
72
+ bytes: number;
73
+ /** The set the embedding model now set writes to and searches. */
74
+ current: boolean;
75
+ }
76
+ export interface LibrarySearchOptions {
77
+ settings?: LibrarySettings;
78
+ collectionIds?: readonly number[];
79
+ embedding?: RetrievalEndpoint;
80
+ reranker?: RetrievalEndpoint;
81
+ signal?: AbortSignal;
82
+ }
83
+ export declare class Library {
84
+ readonly store: LibraryStore;
85
+ /** Where this Library is kept. */
86
+ readonly directory: string;
87
+ private readonly runtimeDirectory;
88
+ private readonly fetch?;
89
+ private index?;
90
+ private shelves?;
91
+ constructor(options?: LibraryOptions);
92
+ /**
93
+ * The sections, shelves and books. Made on first use: Memory keeps its
94
+ * notes in a store of the same kind and has no shelves.
95
+ */
96
+ get catalogue(): Catalogue;
97
+ /** Whether vectors can be used here now, and if not, why. */
98
+ vectorState(): {
99
+ installed: boolean;
100
+ unsupported?: string;
101
+ };
102
+ /** The vector index, when LanceDB is installed (or `install` asks for it). */
103
+ vectors(options?: {
104
+ install?: boolean;
105
+ onInstallProgress?: (progress: LanceDbInstallProgress) => void;
106
+ signal?: AbortSignal;
107
+ }): Promise<VectorIndex | undefined>;
108
+ /**
109
+ * Add a document's text to a collection. It is searchable by keyword as
110
+ * soon as this returns; `embedPending` gives it vectors.
111
+ */
112
+ addDocument(collection: string, document: LibraryDocumentText, settings?: LibrarySettings): Promise<AddDocumentResult>;
113
+ private dropVectors;
114
+ removeDocument(documentId: number): Promise<void>;
115
+ removeCollection(collectionId: number): Promise<void>;
116
+ /**
117
+ * Give vectors to every document that has none for this embedding model.
118
+ * A document is marked done only when all of its vectors are written, so
119
+ * a run that is stopped or fails is picked up where it left off.
120
+ */
121
+ embedPending(options: EmbedPendingOptions): Promise<EmbedPendingResult>;
122
+ /**
123
+ * The sets of vectors on disk: one per embedding model and vector size.
124
+ * A change of model starts a new set and keeps the old one, so going back
125
+ * costs nothing -- and so they add up until one is deleted.
126
+ */
127
+ vectorSets(current?: string): Promise<LibraryVectorSet[]>;
128
+ /** Delete one set of vectors, and forget that its documents were embedded with it. */
129
+ deleteVectorSet(table: string): Promise<boolean>;
130
+ search(query: string, options?: LibrarySearchOptions): Promise<RetrieveResult>;
131
+ close(): Promise<void>;
132
+ }
133
+ /**
134
+ * Closes every Library this process opened. For shutdown: the SQLite file is
135
+ * checkpointed and released, and the next `sharedLibrary()` opens it afresh.
136
+ */
137
+ export declare function closeSharedLibraries(): Promise<void>;
138
+ /** The one Library of a folder in this process: SQLite and LanceDB are opened once. */
139
+ export declare function sharedLibrary(options?: LibraryOptions): Library;
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Automatic recall: Memory searched for every message the user sends, and
3
+ * what is found put beside the message.
4
+ *
5
+ * The model has `recall`, and is told to call it at the start of a task. A
6
+ * model that does not ask does not get its notes, and small models mostly do
7
+ * not ask. So the host asks for it.
8
+ *
9
+ * The order of work is the one claude-hooks settled on after measuring it
10
+ * (https://github.com/mann1x/claude-hooks, docs/hyde.md):
11
+ *
12
+ * 1. Search with the user's own words. Always.
13
+ * 2. HyDE (Gao et al., "Precise Zero-Shot Dense Retrieval without Relevance
14
+ * Labels", 2022), when it is on and step 1 found something: a second model
15
+ * writes the note that would answer the message, given the notes just
16
+ * found, and Memory is searched again with that. Grounded, because a model
17
+ * asked to imagine a note about a project's own jargon invents one about
18
+ * something else. Skipped when Memory holds no note in reach, for the
19
+ * same reason: there is nothing to ground on, and nothing to find.
20
+ * 3. The two results are fused, the first search weighing as much as the
21
+ * second.
22
+ *
23
+ * One thing is added to that. A search always returns its best matches,
24
+ * however poor: by keyword, "the" and "project" match every note. Asked for
25
+ * by the model that is fine, it asked. Attached unasked to every message it
26
+ * is noise, so a note is attached only when something says it is about the
27
+ * message: the reranker passed it, or it is close by meaning, or it shares
28
+ * two meaningful words with what was searched for.
29
+ *
30
+ * Nothing here can fail a turn. A search that throws, an expander that times
31
+ * out, a server that is down: the message goes to the model without notes.
32
+ */
33
+ import { type MemoryToolsConfig } from "../../extensions/tools/memory-tools";
34
+ import { type Memory, type RecalledMemory } from "./memory";
35
+ /** A message shorter than this is "yes", "continue", "go on": nothing to search for. */
36
+ export declare const MEMORY_RECALL_MIN_PROMPT_CHARS = 12;
37
+ /** A pasted log is not a question. Both ends are kept: the ask is at one of them. */
38
+ export declare const MEMORY_RECALL_MAX_QUERY_CHARS = 2000;
39
+ /** Notes given to the expander to ground on, and how much of them. */
40
+ export declare const HYDE_GROUND_NOTES = 3;
41
+ export declare const HYDE_GROUND_MAX_CHARS = 1500;
42
+ /** The expander's time. Past it the first search stands alone. */
43
+ export declare const HYDE_TIMEOUT_MS = 20000;
44
+ /**
45
+ * How close by meaning a note has to be to be attached unasked. A starting
46
+ * point: it depends on the embedding model and is to be tuned.
47
+ */
48
+ export declare const AUTO_RECALL_MIN_SIMILARITY = 0.5;
49
+ /** Meaningful words a note has to share with the search to be attached unasked. */
50
+ export declare const AUTO_RECALL_MIN_SHARED_WORDS = 2;
51
+ export declare const HYDE_SYSTEM_PROMPT = "You are a memory recall assistant. You are given a user's message and a few related notes retrieved from a knowledge base. Using ONLY facts consistent with those notes, write the short note that would answer the message, as if it were itself a stored note. Prefer the terms and specifics of the notes given. Do not invent facts beyond them. Two or three sentences. State facts; do not explain, and do not address the user.";
52
+ export declare function buildHydeUserPrompt(question: string, notes: string[]): string;
53
+ /** Writes the hypothetical note. Undefined or empty: search without it. */
54
+ export type MemoryQueryExpander = (input: {
55
+ system: string;
56
+ prompt: string;
57
+ signal: AbortSignal;
58
+ }) => Promise<string | undefined>;
59
+ export interface MemoryRecallInput {
60
+ /** The user's message, as typed. */
61
+ prompt: string;
62
+ /** The workspace, which decides the memories that are searched. */
63
+ cwd: string;
64
+ /** Notes already given to a session are not given to it again. */
65
+ sessionId?: string;
66
+ }
67
+ export interface MemoryRecallResult {
68
+ /** The block to put after the user's message. Absent: nothing found. */
69
+ context?: string;
70
+ /** The notes in it. */
71
+ ids: string[];
72
+ /** Whether the expander's note was searched with. */
73
+ expanded: boolean;
74
+ /** One line for the user: what was recalled. */
75
+ summary?: string;
76
+ }
77
+ export type MemoryRecaller = (input: MemoryRecallInput) => Promise<MemoryRecallResult | undefined>;
78
+ export interface CreateMemoryRecallerOptions {
79
+ /** Read on every message. Undefined, or Memory off: no recall. */
80
+ getConfig: () => MemoryToolsConfig | undefined;
81
+ /** Read on every message, so a profile chosen mid-session is used. */
82
+ getExpander?: () => MemoryQueryExpander | undefined;
83
+ /** @default the shared Memory of the data folder */
84
+ memory?: Memory;
85
+ log?: (message: string) => void;
86
+ hydeTimeoutMs?: number;
87
+ }
88
+ /** The meaningful words of a text, stemmed. */
89
+ export declare function contentWords(text: string): Set<string>;
90
+ /** Whether a note found for a search is about it, and not merely the best of a poor lot. */
91
+ export declare function isAboutTheSearch(search: string, item: RecalledMemory): boolean;
92
+ /** Bound a query, keeping its head and its tail. */
93
+ export declare function clampRecallQuery(query: string, maxChars?: number): string;
94
+ /** Reciprocal-rank fusion of two orderings of notes, best first. */
95
+ export declare function fuseRecalls(first: RecalledMemory[], second: RecalledMemory[], limit: number): RecalledMemory[];
96
+ export declare function formatRecalledMemory(items: RecalledMemory[]): string;
97
+ export declare function createMemoryRecaller(options: CreateMemoryRecallerOptions): MemoryRecaller;