libsql-search 0.7.0 → 0.7.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.
- package/README.md +26 -48
- package/docs/API.md +114 -107
- package/docs/INDEXING.md +12 -25
- package/docs/INTEGRATIONS.md +220 -40
- package/docs/MIGRATIONS.md +174 -0
- package/docs/PROVIDERS.md +86 -245
- package/docs/README.md +7 -9
- package/docs/TESTING.md +138 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,27 +5,13 @@
|
|
|
5
5
|
[](https://github.com/llbbl/libsql-search/actions/workflows/ci.yml)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
-
`libsql-search` adds semantic search to Markdown-backed sites
|
|
9
|
-
It indexes frontmatter and content from files on disk, stores vectors in your
|
|
10
|
-
database, and lets you query by meaning instead of exact keywords.
|
|
8
|
+
`libsql-search` adds semantic search to Markdown-backed sites with a small TypeScript API. It indexes frontmatter and content from files on disk, stores vectors in libSQL/Turso, and lets you query by meaning instead of exact keywords.
|
|
11
9
|
|
|
12
10
|
Use it when you want:
|
|
13
11
|
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
- direct control over table names, dimensions, content shape, and deployment
|
|
18
|
-
|
|
19
|
-
## What It Supports
|
|
20
|
-
|
|
21
|
-
- Markdown indexing from local directories with frontmatter via `gray-matter`
|
|
22
|
-
- libSQL/Turso storage and vector search
|
|
23
|
-
- Embedding providers: local Hugging Face `Xenova/all-MiniLM-L6-v2`,
|
|
24
|
-
Cloudflare Workers AI `@cf/baai/bge-m3`, Mistral `mistral-embed`, Google Gemini
|
|
25
|
-
`gemini-embedding-2`, and OpenAI `text-embedding-3-small` /
|
|
26
|
-
`text-embedding-3-large`; self-hosted OpenAI-compatible endpoints are also
|
|
27
|
-
available for TEI and similar trusted deployments
|
|
28
|
-
- npm distribution plus JSR publishing
|
|
12
|
+
- one indexing/search API across local and hosted embedding providers
|
|
13
|
+
- direct control over vector dimensions, table names, and deployment shape
|
|
14
|
+
- a lightweight library instead of a hosted search product
|
|
29
15
|
|
|
30
16
|
## Install
|
|
31
17
|
|
|
@@ -44,18 +30,10 @@ deno add jsr:@logan/libsql-search npm:@libsql/client
|
|
|
44
30
|
```
|
|
45
31
|
|
|
46
32
|
For npm usage, the package requires Node `>=22.12.0`.
|
|
47
|
-
Node examples in this README import from `libsql-search` and `@libsql/client`.
|
|
48
|
-
In Deno, after `deno add`, import from `@logan/libsql-search` and
|
|
49
|
-
`@libsql/client`.
|
|
50
33
|
|
|
51
34
|
## Quick Start
|
|
52
35
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
1. create a libSQL client
|
|
56
|
-
2. create the search table
|
|
57
|
-
3. index a Markdown directory
|
|
58
|
-
4. query it with the same embedding provider and dimensions
|
|
36
|
+
This example uses the default local provider. Local embeddings run in-process after the initial model download and cache warmup; they are not automatically air-gapped.
|
|
59
37
|
|
|
60
38
|
```ts
|
|
61
39
|
import { createClient } from "@libsql/client";
|
|
@@ -66,11 +44,12 @@ const client = createClient({
|
|
|
66
44
|
authToken: "your-auth-token",
|
|
67
45
|
});
|
|
68
46
|
|
|
69
|
-
await createTable(client);
|
|
47
|
+
await createTable(client, "articles_local_384", 384);
|
|
70
48
|
|
|
71
49
|
await indexContent({
|
|
72
50
|
client,
|
|
73
51
|
contentPath: "./content",
|
|
52
|
+
tableName: "articles_local_384",
|
|
74
53
|
embeddingOptions: {
|
|
75
54
|
provider: "local",
|
|
76
55
|
},
|
|
@@ -79,6 +58,7 @@ await indexContent({
|
|
|
79
58
|
const results = await search({
|
|
80
59
|
client,
|
|
81
60
|
query: "how do I deploy my docs site",
|
|
61
|
+
tableName: "articles_local_384",
|
|
82
62
|
limit: 5,
|
|
83
63
|
embeddingOptions: {
|
|
84
64
|
provider: "local",
|
|
@@ -95,33 +75,31 @@ console.log(results.map((result) => ({
|
|
|
95
75
|
Important behavior:
|
|
96
76
|
|
|
97
77
|
- Call `createTable()` before indexing or searching.
|
|
98
|
-
- Keep
|
|
99
|
-
- `indexContent()` clears existing rows before rebuilding
|
|
100
|
-
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
- `
|
|
107
|
-
- `
|
|
108
|
-
- `
|
|
109
|
-
- `
|
|
110
|
-
- `
|
|
111
|
-
- `
|
|
112
|
-
- `getFolders(client, tableName?)`
|
|
113
|
-
- `generateEmbedding(text, options?)`
|
|
114
|
-
- `prepareTextForEmbedding(fields)`
|
|
78
|
+
- Keep table width, provider, and dimensions aligned across create/index/query.
|
|
79
|
+
- `indexContent()` clears existing rows before rebuilding and is not transactional.
|
|
80
|
+
- Hosted providers send indexed and queried text to external services and may incur provider charges.
|
|
81
|
+
|
|
82
|
+
## Providers
|
|
83
|
+
|
|
84
|
+
Built-in providers:
|
|
85
|
+
|
|
86
|
+
- `local` with `Xenova/all-MiniLM-L6-v2` at 384 dimensions
|
|
87
|
+
- `cloudflare` with `@cf/baai/bge-m3` at 1024 dimensions
|
|
88
|
+
- `mistral` with `mistral-embed` at 1024 dimensions
|
|
89
|
+
- `gemini` with `gemini-embedding-2` at 128-3072 dimensions, default 3072
|
|
90
|
+
- `openai` with `text-embedding-3-small` or `text-embedding-3-large`, default 768
|
|
91
|
+
- `openai-compatible` for trusted OpenAI-compatible endpoints such as TEI
|
|
115
92
|
|
|
116
93
|
## Docs
|
|
117
94
|
|
|
118
|
-
- [
|
|
119
|
-
- [Provider
|
|
95
|
+
- [Documentation index](./docs/README.md)
|
|
96
|
+
- [Provider selection and configuration](./docs/PROVIDERS.md)
|
|
120
97
|
- [API reference](./docs/API.md)
|
|
121
98
|
- [Integration examples](./docs/INTEGRATIONS.md)
|
|
99
|
+
- [Migration and reindexing guide](./docs/MIGRATIONS.md)
|
|
100
|
+
- [Testing guidance](./docs/TESTING.md)
|
|
122
101
|
- [Indexing and operations](./docs/INDEXING.md)
|
|
123
102
|
- [Troubleshooting](./docs/TROUBLESHOOTING.md)
|
|
124
|
-
- [Release workflow](./docs/RELEASING.md)
|
|
125
103
|
|
|
126
104
|
## License
|
|
127
105
|
|
package/docs/API.md
CHANGED
|
@@ -37,9 +37,16 @@ It also exports these types:
|
|
|
37
37
|
- `SearchOptions`
|
|
38
38
|
- `SearchResult`
|
|
39
39
|
|
|
40
|
+
## Navigation
|
|
41
|
+
|
|
42
|
+
- [Provider matrix and credential rules](./PROVIDERS.md)
|
|
43
|
+
- [Migration and reindexing guide](./MIGRATIONS.md)
|
|
44
|
+
- [Indexing and operational behavior](./INDEXING.md)
|
|
45
|
+
- [Testing guidance](./TESTING.md)
|
|
46
|
+
|
|
40
47
|
## `createTable(client, tableName?, dimensions?)`
|
|
41
48
|
|
|
42
|
-
Creates the table and supporting indexes
|
|
49
|
+
Creates the search table and supporting indexes.
|
|
43
50
|
|
|
44
51
|
```ts
|
|
45
52
|
await createTable(client);
|
|
@@ -50,10 +57,7 @@ Defaults:
|
|
|
50
57
|
- `tableName`: `"articles"`
|
|
51
58
|
- `dimensions`: `384`
|
|
52
59
|
|
|
53
|
-
`tableName` must be an ASCII SQLite identifier matching
|
|
54
|
-
`[A-Za-z_][A-Za-z0-9_]*`. Valid identifiers are quoted internally, so reserved
|
|
55
|
-
words such as `"select"` are safe to use. `dimensions` must be a positive
|
|
56
|
-
integer.
|
|
60
|
+
`tableName` must be an ASCII SQLite identifier matching `[A-Za-z_][A-Za-z0-9_]*`. Valid identifiers are quoted internally, so reserved words such as `"select"` are safe to use. `dimensions` must be a positive integer.
|
|
57
61
|
|
|
58
62
|
The created schema includes:
|
|
59
63
|
|
|
@@ -63,10 +67,12 @@ The created schema includes:
|
|
|
63
67
|
- `content`
|
|
64
68
|
- `folder`
|
|
65
69
|
- `tags`
|
|
66
|
-
- `embedding`
|
|
70
|
+
- `embedding F32_BLOB(dimensions)`
|
|
67
71
|
- `created_at`
|
|
68
72
|
- `updated_at`
|
|
69
73
|
|
|
74
|
+
`createTable()` uses `CREATE TABLE IF NOT EXISTS`, so it does not resize an existing vector column. See [Migration and reindexing guide](./MIGRATIONS.md) before changing widths or providers.
|
|
75
|
+
|
|
70
76
|
## `indexContent(options)`
|
|
71
77
|
|
|
72
78
|
Indexes Markdown files from a directory on disk.
|
|
@@ -89,8 +95,6 @@ Defaults:
|
|
|
89
95
|
- `exclude`: ["node_modules", ".git", "dist", "build"]
|
|
90
96
|
- `tableName`: `"articles"`
|
|
91
97
|
|
|
92
|
-
`tableName` follows the same identifier policy as `createTable()`.
|
|
93
|
-
|
|
94
98
|
Return shape:
|
|
95
99
|
|
|
96
100
|
```ts
|
|
@@ -104,10 +108,9 @@ Return shape:
|
|
|
104
108
|
Behavior notes:
|
|
105
109
|
|
|
106
110
|
- `indexContent()` deletes existing rows in the target table before rebuilding
|
|
107
|
-
-
|
|
108
|
-
|
|
109
|
-
- embeddings default to `intent: "document"` unless `embeddingOptions.intent`
|
|
110
|
-
is set explicitly
|
|
111
|
+
- rebuilds are not transactional
|
|
112
|
+
- frontmatter `title`, `description`, and `tags` are folded into the embedding text
|
|
113
|
+
- embeddings default to `intent: "document"` unless `embeddingOptions.intent` is set explicitly
|
|
111
114
|
- if a file has no frontmatter title, the filename becomes the title
|
|
112
115
|
|
|
113
116
|
## `search(options)`
|
|
@@ -129,9 +132,7 @@ Defaults:
|
|
|
129
132
|
- `limit`: `10`
|
|
130
133
|
- `tableName`: `"articles"`
|
|
131
134
|
|
|
132
|
-
`limit` must be an integer from `1` through `100`; invalid values are rejected
|
|
133
|
-
before query embedding generation. `tableName` follows the same identifier
|
|
134
|
-
policy as `createTable()`.
|
|
135
|
+
`limit` must be an integer from `1` through `100`; invalid values are rejected before query embedding generation.
|
|
135
136
|
|
|
136
137
|
Result shape:
|
|
137
138
|
|
|
@@ -150,8 +151,7 @@ interface SearchResult {
|
|
|
150
151
|
|
|
151
152
|
Lower `distance` values are better matches.
|
|
152
153
|
|
|
153
|
-
Search embeddings default to `intent: "query"` unless
|
|
154
|
-
`embeddingOptions.intent` is set explicitly.
|
|
154
|
+
Search embeddings default to `intent: "query"` unless `embeddingOptions.intent` is set explicitly.
|
|
155
155
|
|
|
156
156
|
## Article Retrieval Helpers
|
|
157
157
|
|
|
@@ -171,82 +171,106 @@ Returns articles in a specific folder.
|
|
|
171
171
|
|
|
172
172
|
Returns distinct folder names from the index.
|
|
173
173
|
|
|
174
|
-
All
|
|
174
|
+
All retrieval helpers validate `tableName` before executing SQL.
|
|
175
175
|
|
|
176
176
|
## Embedding Helpers
|
|
177
177
|
|
|
178
|
-
### `
|
|
178
|
+
### `EmbeddingOptions`
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
interface EmbeddingOptions {
|
|
182
|
+
provider?:
|
|
183
|
+
| "local"
|
|
184
|
+
| "cloudflare"
|
|
185
|
+
| "mistral"
|
|
186
|
+
| "gemini"
|
|
187
|
+
| "openai"
|
|
188
|
+
| "openai-compatible";
|
|
189
|
+
apiKey?: string;
|
|
190
|
+
accountId?: string;
|
|
191
|
+
apiToken?: string;
|
|
192
|
+
baseUrl?: string;
|
|
193
|
+
model?: string;
|
|
194
|
+
batchSize?: number;
|
|
195
|
+
dimensions?: number;
|
|
196
|
+
maxLength?: number;
|
|
197
|
+
intent?: "document" | "query";
|
|
198
|
+
timeoutMs?: number;
|
|
199
|
+
signal?: AbortSignal;
|
|
200
|
+
}
|
|
201
|
+
```
|
|
179
202
|
|
|
180
|
-
|
|
203
|
+
Important option rules:
|
|
181
204
|
|
|
182
|
-
|
|
205
|
+
- `provider` defaults to `local`
|
|
206
|
+
- `maxLength` defaults to `8000`
|
|
207
|
+
- `timeoutMs` defaults to `30000`
|
|
208
|
+
- `model` is only used by `openai-compatible`
|
|
209
|
+
- `baseUrl`, `model`, and `dimensions` are required for `openai-compatible`
|
|
210
|
+
- `batchSize` only applies to `openai-compatible` and defaults to `32`
|
|
211
|
+
- `openai-compatible` never reads `OPENAI_API_KEY`
|
|
212
|
+
- only the Gemini adapter currently changes payload formatting by `intent`
|
|
183
213
|
|
|
184
|
-
|
|
185
|
-
creating a hosted provider client or making a network request.
|
|
214
|
+
Dimension rules:
|
|
186
215
|
|
|
187
|
-
|
|
216
|
+
- local: fixed `384`
|
|
217
|
+
- Cloudflare: fixed `1024`
|
|
218
|
+
- Mistral: fixed `1024`
|
|
219
|
+
- Gemini: default `3072`, allowed integer range `128-3072`
|
|
220
|
+
- OpenAI: default `768`; `text-embedding-3-small` through `1536`, `text-embedding-3-large` above `1536`
|
|
221
|
+
- OpenAI-compatible: required positive integer, no default
|
|
188
222
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
223
|
+
See [Provider matrix and credential rules](./PROVIDERS.md) for the canonical provider table.
|
|
224
|
+
|
|
225
|
+
### `generateEmbedding(text, options?)`
|
|
226
|
+
|
|
227
|
+
Generates one embedding vector.
|
|
193
228
|
|
|
194
229
|
```ts
|
|
195
|
-
const
|
|
230
|
+
const embedding = await generateEmbedding("deploy docs", {
|
|
196
231
|
provider: "openai",
|
|
197
232
|
apiKey: process.env.OPENAI_API_KEY,
|
|
198
233
|
dimensions: 1536,
|
|
199
234
|
});
|
|
200
|
-
|
|
201
|
-
console.log(provider.metadata);
|
|
202
235
|
```
|
|
203
236
|
|
|
204
|
-
|
|
237
|
+
### `generateEmbeddings(texts, options?)`
|
|
205
238
|
|
|
206
|
-
|
|
207
|
-
- `model`
|
|
208
|
-
- `dimensions`
|
|
209
|
-
- `batch.mode`
|
|
210
|
-
- `batch.maxSize`, when the provider has a hard maximum
|
|
239
|
+
Generates an ordered batch of embeddings.
|
|
211
240
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
241
|
+
- empty batches return `[]` without loading the local model or making a hosted call
|
|
242
|
+
- OpenAI batches above `2048` inputs are rejected before network work
|
|
243
|
+
- `openai-compatible` batches are chunked sequentially according to `batchSize`
|
|
215
244
|
|
|
216
|
-
|
|
217
|
-
Gemini dimensions must be an integer from 128 through 3072.
|
|
245
|
+
### `createEmbeddingProvider(options?)`
|
|
218
246
|
|
|
219
|
-
|
|
220
|
-
`@huggingface/transformers` and are fixed at the model's native 384 dimensions.
|
|
221
|
-
Passing any other local dimension is rejected before the runtime is loaded.
|
|
247
|
+
Creates a provider client with immutable metadata and an `embed(texts, options?)` method.
|
|
222
248
|
|
|
223
|
-
|
|
249
|
+
```ts
|
|
250
|
+
const provider = createEmbeddingProvider({
|
|
251
|
+
provider: "openai-compatible",
|
|
252
|
+
baseUrl: "https://tei.example.internal/v1",
|
|
253
|
+
model: "bge-large-en-v1.5",
|
|
254
|
+
dimensions: 1024,
|
|
255
|
+
batchSize: 32,
|
|
256
|
+
});
|
|
224
257
|
|
|
225
|
-
|
|
226
|
-
|
|
258
|
+
console.log(provider.metadata);
|
|
259
|
+
```
|
|
227
260
|
|
|
228
|
-
Provider
|
|
261
|
+
Provider clients return a rich `EmbeddingBatchResult`; the compatibility helpers `generateEmbedding()` and `generateEmbeddings()` return only vectors.
|
|
229
262
|
|
|
230
|
-
|
|
231
|
-
type EmbeddingBatchMode = "native" | "sequential";
|
|
263
|
+
Hosted provider clients are scoped to their current options. The library does not reuse a Cloudflare, Mistral, Gemini, or OpenAI client across different credential sets or configurations.
|
|
232
264
|
|
|
233
|
-
|
|
234
|
-
mode: EmbeddingBatchMode;
|
|
235
|
-
maxSize?: number;
|
|
236
|
-
}
|
|
237
|
-
```
|
|
265
|
+
### `getEmbeddingProviderMetadata(options?)`
|
|
238
266
|
|
|
239
|
-
|
|
240
|
-
`"sequential"` means the library accepts an input batch but processes items one
|
|
241
|
-
at a time. If `maxSize` is present, the library enforces it before provider or
|
|
242
|
-
network work.
|
|
267
|
+
Returns the same metadata exposed by `createEmbeddingProvider(options).metadata` without resolving hosted-provider credentials.
|
|
243
268
|
|
|
244
|
-
|
|
269
|
+
Metadata shape:
|
|
245
270
|
|
|
246
271
|
```ts
|
|
247
|
-
interface
|
|
248
|
-
|
|
249
|
-
provider:
|
|
272
|
+
interface EmbeddingProviderMetadata {
|
|
273
|
+
name:
|
|
250
274
|
| "local"
|
|
251
275
|
| "cloudflare"
|
|
252
276
|
| "mistral"
|
|
@@ -255,69 +279,52 @@ interface EmbeddingBatchResult {
|
|
|
255
279
|
| "openai-compatible";
|
|
256
280
|
model: string;
|
|
257
281
|
dimensions: number;
|
|
258
|
-
|
|
282
|
+
batch: {
|
|
283
|
+
mode: "native" | "sequential";
|
|
284
|
+
maxSize?: number;
|
|
285
|
+
};
|
|
259
286
|
}
|
|
260
287
|
```
|
|
261
288
|
|
|
262
|
-
|
|
289
|
+
Batch interpretation:
|
|
263
290
|
|
|
264
|
-
|
|
265
|
-
|
|
291
|
+
- `"native"` means the provider accepts a batch request upstream
|
|
292
|
+
- `"sequential"` means the library accepts a batch but processes items one-by-one
|
|
293
|
+
- `batch.maxSize` is a hard client-side limit when present
|
|
266
294
|
|
|
267
|
-
`
|
|
295
|
+
`openai-compatible` metadata reports `batch.mode: "native"` because the remote endpoint is expected to accept batch inputs, even though the library may split large arrays into sequential outbound chunks at `batchSize`.
|
|
296
|
+
|
|
297
|
+
### `EmbeddingBatchResult`
|
|
268
298
|
|
|
269
299
|
```ts
|
|
270
|
-
interface
|
|
271
|
-
|
|
300
|
+
interface EmbeddingBatchResult {
|
|
301
|
+
embeddings: number[][];
|
|
302
|
+
provider:
|
|
272
303
|
| "local"
|
|
273
304
|
| "cloudflare"
|
|
274
305
|
| "mistral"
|
|
275
306
|
| "gemini"
|
|
276
307
|
| "openai"
|
|
277
308
|
| "openai-compatible";
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
baseUrl?: string;
|
|
282
|
-
model?: string;
|
|
283
|
-
batchSize?: number;
|
|
284
|
-
dimensions?: number;
|
|
285
|
-
maxLength?: number;
|
|
286
|
-
intent?: "document" | "query";
|
|
287
|
-
timeoutMs?: number;
|
|
288
|
-
signal?: AbortSignal;
|
|
309
|
+
model: string;
|
|
310
|
+
dimensions: number;
|
|
311
|
+
intent: "document" | "query";
|
|
289
312
|
}
|
|
290
313
|
```
|
|
291
314
|
|
|
292
|
-
`
|
|
293
|
-
`MISTRAL_API_KEY`, `GEMINI_API_KEY`, or `OPENAI_API_KEY` for those providers.
|
|
294
|
-
Cloudflare uses `accountId` and `apiToken`, which fall back to
|
|
295
|
-
`CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_API_TOKEN`.
|
|
315
|
+
### `validateEmbeddingBatch(items, expectedCount, expectedDimensions, provider)`
|
|
296
316
|
|
|
297
|
-
|
|
298
|
-
`dimensions`. `apiKey` is optional and is used only when explicitly provided;
|
|
299
|
-
the provider never reads `OPENAI_API_KEY`. `batchSize` controls the maximum
|
|
300
|
-
items per outbound request and defaults to `32`. The endpoint is treated as
|
|
301
|
-
trusted server-side configuration and should not be derived from untrusted
|
|
302
|
-
request input.
|
|
317
|
+
Validates provider responses before they reach the database:
|
|
303
318
|
|
|
304
|
-
|
|
319
|
+
- result count must match the requested input count
|
|
320
|
+
- vectors must match the effective dimensions
|
|
321
|
+
- values must be finite numbers
|
|
322
|
+
- indexed provider responses are reordered and checked for contiguous indices
|
|
305
323
|
|
|
306
|
-
|
|
324
|
+
### `padEmbedding(embedding, targetDimensions)`
|
|
307
325
|
|
|
308
|
-
This
|
|
309
|
-
provider does not use it; local vectors are validated at native 384 dimensions.
|
|
326
|
+
Pads or truncates a vector to the target width. This is exported for compatibility and migration workflows, but the current local provider uses its native `384` dimensions rather than padding by default.
|
|
310
327
|
|
|
311
328
|
### `prepareTextForEmbedding(fields)`
|
|
312
329
|
|
|
313
|
-
|
|
314
|
-
embedding model.
|
|
315
|
-
|
|
316
|
-
```ts
|
|
317
|
-
const text = prepareTextForEmbedding({
|
|
318
|
-
title: "My Article",
|
|
319
|
-
description: "How semantic search works",
|
|
320
|
-
tags: ["search", "turso"],
|
|
321
|
-
content: "# Content",
|
|
322
|
-
});
|
|
323
|
-
```
|
|
330
|
+
Builds the text that is embedded from title, description, content, and tags.
|
package/docs/INDEXING.md
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Content Shape
|
|
4
4
|
|
|
5
|
-
`indexContent()` walks a directory tree, reads Markdown files, parses
|
|
6
|
-
frontmatter with `gray-matter`, and stores:
|
|
5
|
+
`indexContent()` walks a directory tree, reads Markdown files, parses frontmatter with `gray-matter`, and stores:
|
|
7
6
|
|
|
8
7
|
- `slug`
|
|
9
8
|
- `title`
|
|
@@ -22,41 +21,32 @@ The slug is derived from the file path relative to `contentPath`.
|
|
|
22
21
|
await indexContent({
|
|
23
22
|
client,
|
|
24
23
|
contentPath: "./content",
|
|
25
|
-
tableName: "
|
|
24
|
+
tableName: "articles_local_384",
|
|
26
25
|
embeddingOptions: {
|
|
27
26
|
provider: "local",
|
|
28
27
|
},
|
|
29
28
|
});
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
That keeps the implementation simple, but it also means
|
|
33
|
-
leave the index partially repopulated.
|
|
31
|
+
That keeps the implementation simple, but it also means:
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
768-dimensional tables stored 384 model values followed by zero padding;
|
|
39
|
-
`indexContent()` clears rows but does not change the table's `F32_BLOB` width.
|
|
33
|
+
- failed rebuilds can leave the table partially repopulated
|
|
34
|
+
- provider or dimension changes should use a parallel table migration
|
|
35
|
+
- `createTable()` does not resize an existing vector column
|
|
40
36
|
|
|
41
|
-
|
|
42
|
-
model must be rebuilt for `gemini-embedding-2` even when staying at 768
|
|
43
|
-
dimensions, because the model and query/document formatting both changed. If
|
|
44
|
-
you adopt Gemini's 3072-dimensional default, recreate the vector table or build
|
|
45
|
-
into a separate table first; clearing rows with `indexContent()` does not change
|
|
46
|
-
the table's `F32_BLOB` width.
|
|
37
|
+
If provider, dimensions, model, endpoint, or embedding-space assumptions change, fully reindex into a new table. See the canonical [Migration and reindexing guide](./MIGRATIONS.md).
|
|
47
38
|
|
|
48
39
|
## Quality Guidelines
|
|
49
40
|
|
|
50
41
|
- include descriptive frontmatter titles
|
|
51
42
|
- add meaningful `tags` when they help retrieval
|
|
52
|
-
- use the same
|
|
43
|
+
- use the same provider and dimensions at index and query time
|
|
53
44
|
- keep `maxLength` intentional if your content is very large
|
|
54
45
|
- start with a smaller search `limit` and tune from real query behavior
|
|
55
46
|
|
|
56
47
|
## Build Integration
|
|
57
48
|
|
|
58
|
-
Many projects wire indexing into a dedicated script and call it before their
|
|
59
|
-
site build:
|
|
49
|
+
Many projects wire indexing into a dedicated script and call it before their site build:
|
|
60
50
|
|
|
61
51
|
```json
|
|
62
52
|
{
|
|
@@ -69,14 +59,11 @@ site build:
|
|
|
69
59
|
|
|
70
60
|
## Table Names
|
|
71
61
|
|
|
72
|
-
`tableName` must be an ASCII SQLite identifier matching
|
|
73
|
-
`[A-Za-z_][A-Za-z0-9_]*`. Valid names are quoted internally for table and index
|
|
74
|
-
SQL, so reserved words such as `"select"` work safely. Invalid names fail before
|
|
75
|
-
database calls or embedding generation.
|
|
62
|
+
`tableName` must be an ASCII SQLite identifier matching `[A-Za-z_][A-Za-z0-9_]*`. Valid names are quoted internally for table and index SQL, so reserved words such as `"select"` work safely. Invalid names fail before database calls or embedding generation.
|
|
76
63
|
|
|
77
64
|
## Runtime Notes
|
|
78
65
|
|
|
79
66
|
- local embeddings may download and cache a model on the first run
|
|
80
67
|
- Node users need `@libsql/client` installed alongside the package
|
|
81
|
-
-
|
|
82
|
-
|
|
68
|
+
- hosted providers send indexed or queried text to external services
|
|
69
|
+
- the repository validates package build and `deno check`, but indexing still depends on filesystem access
|