libsql-search 0.6.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 -47
- package/dist/index.cjs +160 -131
- package/dist/index.d.ts +6 -2
- package/dist/index.esm.js +160 -131
- package/docs/API.md +125 -96
- package/docs/INDEXING.md +12 -25
- package/docs/INTEGRATIONS.md +221 -29
- package/docs/MIGRATIONS.md +174 -0
- package/docs/PROVIDERS.md +112 -175
- package/docs/README.md +7 -9
- package/docs/TESTING.md +138 -0
- package/package.json +1 -1
package/docs/PROVIDERS.md
CHANGED
|
@@ -1,25 +1,35 @@
|
|
|
1
1
|
# Embedding Providers
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use this page to choose an embedding provider, confirm the table width it needs, and understand what crosses a network boundary.
|
|
4
|
+
|
|
5
|
+
`libsql-search` supports these provider values:
|
|
4
6
|
|
|
5
7
|
- `local`
|
|
6
8
|
- `cloudflare`
|
|
7
9
|
- `mistral`
|
|
8
10
|
- `gemini`
|
|
9
11
|
- `openai`
|
|
12
|
+
- `openai-compatible`
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
between stored vectors and query vectors will break search quality or fail at
|
|
13
|
-
query time.
|
|
14
|
+
## Shared Behavior
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
All providers share the same `EmbeddingOptions` surface:
|
|
16
17
|
|
|
17
18
|
```ts
|
|
18
19
|
interface EmbeddingOptions {
|
|
19
|
-
provider?:
|
|
20
|
+
provider?:
|
|
21
|
+
| "local"
|
|
22
|
+
| "cloudflare"
|
|
23
|
+
| "mistral"
|
|
24
|
+
| "gemini"
|
|
25
|
+
| "openai"
|
|
26
|
+
| "openai-compatible";
|
|
20
27
|
apiKey?: string;
|
|
21
28
|
accountId?: string;
|
|
22
29
|
apiToken?: string;
|
|
30
|
+
baseUrl?: string;
|
|
31
|
+
model?: string;
|
|
32
|
+
batchSize?: number;
|
|
23
33
|
dimensions?: number;
|
|
24
34
|
maxLength?: number;
|
|
25
35
|
intent?: "document" | "query";
|
|
@@ -28,79 +38,37 @@ interface EmbeddingOptions {
|
|
|
28
38
|
}
|
|
29
39
|
```
|
|
30
40
|
|
|
31
|
-
|
|
32
|
-
- `dimensions` defaults to `384` for the library's default local provider.
|
|
33
|
-
Provider-specific defaults can differ; Cloudflare and Mistral use `1024`,
|
|
34
|
-
and Gemini defaults to `3072`.
|
|
35
|
-
- `maxLength` defaults to `8000`
|
|
36
|
-
- `intent` can be `"document"` or `"query"`; indexing defaults to
|
|
37
|
-
`"document"` and search defaults to `"query"` unless explicitly set
|
|
38
|
-
- `timeoutMs` defaults to `30000`
|
|
39
|
-
- `apiKey` is used by Mistral, Gemini, and OpenAI and falls back to
|
|
40
|
-
`MISTRAL_API_KEY`, `GEMINI_API_KEY`, or `OPENAI_API_KEY`
|
|
41
|
-
- `accountId` and `apiToken` are used by Cloudflare and fall back to
|
|
42
|
-
`CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_API_TOKEN`
|
|
43
|
-
|
|
44
|
-
## Provider Contract
|
|
45
|
-
|
|
46
|
-
Each provider exposes immutable metadata:
|
|
47
|
-
|
|
48
|
-
```ts
|
|
49
|
-
interface EmbeddingProviderMetadata {
|
|
50
|
-
name: "local" | "cloudflare" | "mistral" | "gemini" | "openai";
|
|
51
|
-
model: string;
|
|
52
|
-
dimensions: number;
|
|
53
|
-
batch: {
|
|
54
|
-
mode: "native" | "sequential";
|
|
55
|
-
maxSize?: number;
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
```
|
|
41
|
+
Shared defaults and rules:
|
|
59
42
|
|
|
60
|
-
|
|
61
|
-
`
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
- `"native"` means the upstream provider accepts the batch in one request
|
|
68
|
-
- `"sequential"` means the library accepts a batch and processes items one at a
|
|
69
|
-
time
|
|
70
|
-
- when `maxSize` is present, it is a hard maximum enforced before provider or
|
|
71
|
-
network work
|
|
72
|
-
|
|
73
|
-
`generateEmbeddings(texts, options)` returns vectors in the same order as the
|
|
74
|
-
input texts. Provider responses are validated before database writes:
|
|
75
|
-
|
|
76
|
-
- result count must match input count
|
|
77
|
-
- each vector must match the provider's effective dimensions
|
|
78
|
-
- every vector value must be a finite number
|
|
79
|
-
- indexed batch responses must contain unique contiguous indices and are
|
|
80
|
-
reordered before being returned
|
|
43
|
+
- `provider` defaults to `local`
|
|
44
|
+
- `maxLength` defaults to `8000` code units
|
|
45
|
+
- `timeoutMs` defaults to `30000`
|
|
46
|
+
- `indexContent()` defaults to `intent: "document"`
|
|
47
|
+
- `search()` defaults to `intent: "query"`
|
|
48
|
+
- `getEmbeddingProviderMetadata()` reports the effective provider, model, dimensions, and batch mode without making a hosted call
|
|
49
|
+
- use one embedding space per table: if provider, dimensions, model selection, endpoint, or formatting contract changes, build a new table and reindex
|
|
81
50
|
|
|
82
|
-
|
|
83
|
-
or making network calls.
|
|
51
|
+
Intent behavior is intentionally narrow today:
|
|
84
52
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
`generateEmbedding()` and `generateEmbeddings()` return only arrays.
|
|
53
|
+
- only the current Gemini adapter changes the formatted payload for `"document"` versus `"query"`
|
|
54
|
+
- all other providers still carry `intent` metadata through the API, but they embed the same text string either way
|
|
88
55
|
|
|
89
|
-
|
|
90
|
-
options. They are not cached globally across different credentials or
|
|
91
|
-
configurations. The local Hugging Face Transformers pipeline is loaded lazily
|
|
92
|
-
and cached by model name.
|
|
56
|
+
The `model` option is only used by `openai-compatible`.
|
|
93
57
|
|
|
94
|
-
|
|
95
|
-
context and without raw upstream bodies, credentials, Authorization headers, or
|
|
96
|
-
full URLs with query strings.
|
|
58
|
+
## Provider Matrix
|
|
97
59
|
|
|
98
|
-
|
|
60
|
+
| Provider | Literal | Upstream model used by this adapter | Dimensions | Credentials | Batching | Network and privacy boundary | Cost and table planning |
|
|
61
|
+
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
62
|
+
| Local | `local` | `Xenova/all-MiniLM-L6-v2` | Fixed `384` | None | Sequential in-process | No hosted API call. First use may download model artifacts and cache them locally. | No hosted API bill. Table must be `F32_BLOB(384)`. |
|
|
63
|
+
| Cloudflare Workers AI | `cloudflare` | `@cf/baai/bge-m3` | Fixed `1024` | `accountId` and `apiToken`, or `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_API_TOKEN` | Native batch in one request | Indexed and queried text is sent to Cloudflare. | Check Cloudflare pricing before large rebuilds. Table must be `F32_BLOB(1024)`. |
|
|
64
|
+
| Mistral | `mistral` | `mistral-embed` | Fixed `1024` | `apiKey`, or `MISTRAL_API_KEY` | Native batch in one request | Indexed and queried text is sent to Mistral. | Check Mistral pricing before rebuilds. Table must be `F32_BLOB(1024)`. |
|
|
65
|
+
| Gemini | `gemini` | `gemini-embedding-2` | Default `3072`; allowed integers `128-3072` | `apiKey`, or `GEMINI_API_KEY` | Sequential SDK request per input | Indexed and queried text is sent to Google. The adapter currently rewrites payload text by intent. | Check Gemini pricing before rebuilds. Table width must match the chosen dimension count exactly. |
|
|
66
|
+
| OpenAI | `openai` | `text-embedding-3-small` when `dimensions <= 1536`, otherwise `text-embedding-3-large` | Default `768`; any positive integer accepted locally and forwarded as `dimensions` | `apiKey`, or `OPENAI_API_KEY` | Native batch in one request, max `2048` inputs | Indexed and queried text is sent to OpenAI. | Check OpenAI pricing before rebuilds. Table width must match the chosen dimension count exactly. |
|
|
67
|
+
| OpenAI-compatible | `openai-compatible` | Your configured `model` | Required positive integer; no default | `baseUrl`, `model`, and `dimensions` are required. `apiKey` is optional and never falls back to env. | Metadata reports `native`; outbound requests are chunked sequentially at `batchSize`, default `32` | Boundary depends on the operator behind `baseUrl`. Treat `baseUrl` as a trusted server-side setting and review HTTPS, SSRF, logging, and retention controls yourself. | Table width must match the configured `dimensions`. Any endpoint or model change should use a new table plus full reindex. |
|
|
99
68
|
|
|
100
|
-
Provider
|
|
69
|
+
## Provider Notes
|
|
101
70
|
|
|
102
|
-
|
|
103
|
-
`@huggingface/transformers`.
|
|
71
|
+
### Local
|
|
104
72
|
|
|
105
73
|
```ts
|
|
106
74
|
embeddingOptions: {
|
|
@@ -108,26 +76,16 @@ embeddingOptions: {
|
|
|
108
76
|
}
|
|
109
77
|
```
|
|
110
78
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
-
|
|
114
|
-
384 finite numbers
|
|
115
|
-
- `dimensions: 384` is accepted explicitly; any other local dimension is
|
|
116
|
-
rejected before the runtime is imported or loaded
|
|
117
|
-
- metadata reports 384 dimensions
|
|
118
|
-
- batch metadata is `{ mode: "sequential" }`
|
|
119
|
-
- the first run downloads and caches the model and can take longer on a fresh
|
|
120
|
-
machine
|
|
121
|
-
- no API key is required
|
|
122
|
-
- this remains the default provider for offline use
|
|
79
|
+
- fixed at `384` dimensions
|
|
80
|
+
- rejects any other `dimensions` value before loading the runtime
|
|
81
|
+
- uses `@huggingface/transformers` lazily and caches the local pipeline by model name
|
|
123
82
|
|
|
124
|
-
|
|
83
|
+
References:
|
|
125
84
|
|
|
126
|
-
|
|
85
|
+
- [Transformers.js in Node.js](https://huggingface.co/docs/transformers.js/en/tutorials/node)
|
|
86
|
+
- [Transformers.js environment and cache controls](https://huggingface.co/docs/transformers.js/en/api/env)
|
|
127
87
|
|
|
128
|
-
Cloudflare
|
|
129
|
-
It uses Workers AI `@cf/baai/bge-m3` through Cloudflare's OpenAI-compatible
|
|
130
|
-
embeddings endpoint.
|
|
88
|
+
### Cloudflare Workers AI
|
|
131
89
|
|
|
132
90
|
```ts
|
|
133
91
|
embeddingOptions: {
|
|
@@ -137,25 +95,16 @@ embeddingOptions: {
|
|
|
137
95
|
}
|
|
138
96
|
```
|
|
139
97
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
-
|
|
143
|
-
- if `apiToken` is omitted, the library reads `CLOUDFLARE_API_TOKEN`
|
|
144
|
-
- blank Cloudflare credentials are treated as missing
|
|
145
|
-
- `@cf/baai/bge-m3` returns 1024 dimensions
|
|
146
|
-
- metadata reports `@cf/baai/bge-m3` and 1024 dimensions without requiring
|
|
147
|
-
credentials
|
|
148
|
-
- batch metadata is `{ mode: "native" }`
|
|
149
|
-
- response items are reordered by provider-supplied index before being returned
|
|
150
|
-
- Cloudflare does not accept custom dimensions in this provider; use
|
|
151
|
-
`createTable(client, "articles", 1024)` for Cloudflare-backed indexes
|
|
98
|
+
- fixed at `1024` dimensions
|
|
99
|
+
- uses the account-scoped Workers AI embeddings endpoint
|
|
100
|
+
- blank credentials are treated as missing
|
|
152
101
|
|
|
153
|
-
|
|
102
|
+
References:
|
|
154
103
|
|
|
155
|
-
|
|
104
|
+
- [Cloudflare `@cf/baai/bge-m3`](https://developers.cloudflare.com/workers-ai/models/bge-m3/)
|
|
105
|
+
- [Cloudflare Workers AI pricing](https://developers.cloudflare.com/workers-ai/platform/pricing/)
|
|
156
106
|
|
|
157
|
-
Mistral
|
|
158
|
-
`https://api.mistral.ai/v1/embeddings`.
|
|
107
|
+
### Mistral
|
|
159
108
|
|
|
160
109
|
```ts
|
|
161
110
|
embeddingOptions: {
|
|
@@ -164,24 +113,17 @@ embeddingOptions: {
|
|
|
164
113
|
}
|
|
165
114
|
```
|
|
166
115
|
|
|
167
|
-
|
|
116
|
+
- fixed at `1024` dimensions
|
|
117
|
+
- sends `encoding_format: "float"`
|
|
118
|
+
- expects indexed upstream responses
|
|
168
119
|
|
|
169
|
-
|
|
170
|
-
- blank Mistral credentials are treated as missing
|
|
171
|
-
- `mistral-embed` returns 1024 dimensions
|
|
172
|
-
- metadata reports `mistral-embed` and 1024 dimensions without requiring
|
|
173
|
-
credentials
|
|
174
|
-
- batch metadata is `{ mode: "native" }`
|
|
175
|
-
- request bodies send `encoding_format: "float"`
|
|
176
|
-
- response items are reordered by provider-supplied index before being returned
|
|
177
|
-
- Mistral does not accept custom dimensions in this provider; use
|
|
178
|
-
`createTable(client, "articles", 1024)` for Mistral-backed indexes
|
|
120
|
+
References:
|
|
179
121
|
|
|
180
|
-
|
|
122
|
+
- [Mistral embeddings guide](https://docs.mistral.ai/studio/knowledge-rag/embeddings/text_embeddings)
|
|
123
|
+
- [Mistral embeddings API reference](https://docs.mistral.ai/api/endpoint/embeddings)
|
|
124
|
+
- [Mistral model overview for `mistral-embed`](https://docs.mistral.ai/models/mistral-embed-23-12)
|
|
181
125
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
Gemini uses Google `gemini-embedding-2` through `@google/genai`.
|
|
126
|
+
### Gemini
|
|
185
127
|
|
|
186
128
|
```ts
|
|
187
129
|
embeddingOptions: {
|
|
@@ -191,26 +133,18 @@ embeddingOptions: {
|
|
|
191
133
|
}
|
|
192
134
|
```
|
|
193
135
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
-
|
|
197
|
-
-
|
|
198
|
-
-
|
|
199
|
-
- explicit Gemini dimensions must be integers from 128 through 3072
|
|
200
|
-
- 768, 1536, and 3072 are recommended practical sizes
|
|
201
|
-
- metadata reports `gemini-embedding-2` and the effective dimensions
|
|
202
|
-
- batch metadata is `{ mode: "sequential" }`
|
|
203
|
-
- the library sends one SDK request per input and verifies one vector per input
|
|
204
|
-
- document inputs are formatted as `title: none | text: ...`
|
|
205
|
-
- query inputs are formatted as `task: search result | query: ...`
|
|
206
|
-
- the current implementation does not expose custom model selection
|
|
136
|
+
- defaults to `3072` dimensions
|
|
137
|
+
- accepts only integer dimensions from `128` through `3072`
|
|
138
|
+
- currently formats document inputs as `title: none | text: ...`
|
|
139
|
+
- currently formats query inputs as `task: search result | query: ...`
|
|
140
|
+
- sends one SDK request per input, even when you call `generateEmbeddings()`
|
|
207
141
|
|
|
208
|
-
|
|
142
|
+
References:
|
|
209
143
|
|
|
210
|
-
|
|
144
|
+
- [Gemini embeddings guide](https://ai.google.dev/gemini-api/docs/embeddings)
|
|
145
|
+
- [Gemini pricing](https://ai.google.dev/gemini-api/docs/pricing)
|
|
211
146
|
|
|
212
|
-
OpenAI
|
|
213
|
-
`text-embedding-3-large` when `dimensions > 1536`.
|
|
147
|
+
### OpenAI
|
|
214
148
|
|
|
215
149
|
```ts
|
|
216
150
|
embeddingOptions: {
|
|
@@ -220,42 +154,45 @@ embeddingOptions: {
|
|
|
220
154
|
}
|
|
221
155
|
```
|
|
222
156
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
-
|
|
226
|
-
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
-
|
|
235
|
-
|
|
236
|
-
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
`
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
157
|
+
- defaults to `768` dimensions
|
|
158
|
+
- uses `text-embedding-3-small` through `1536`
|
|
159
|
+
- uses `text-embedding-3-large` above `1536`
|
|
160
|
+
- rejects batches above `2048` inputs before any network request
|
|
161
|
+
|
|
162
|
+
References:
|
|
163
|
+
|
|
164
|
+
- [OpenAI embeddings guide](https://developers.openai.com/api/docs/guides/embeddings)
|
|
165
|
+
- [OpenAI embeddings API reference](https://developers.openai.com/api/reference/resources/embeddings/methods/create/)
|
|
166
|
+
- [OpenAI data controls](https://developers.openai.com/api/docs/guides/your-data#default-usage-policies-by-endpoint)
|
|
167
|
+
- [OpenAI models overview](https://developers.openai.com/api/docs/models)
|
|
168
|
+
- [OpenAI API pricing](https://openai.com/api/pricing/)
|
|
169
|
+
|
|
170
|
+
### OpenAI-compatible
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
embeddingOptions: {
|
|
174
|
+
provider: "openai-compatible",
|
|
175
|
+
baseUrl: process.env.EMBEDDING_BASE_URL,
|
|
176
|
+
model: process.env.EMBEDDING_MODEL,
|
|
177
|
+
dimensions: Number(process.env.EMBEDDING_DIMENSIONS),
|
|
178
|
+
apiKey: process.env.EMBEDDING_API_KEY,
|
|
179
|
+
batchSize: 32,
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- `baseUrl`, `model`, and `dimensions` are required
|
|
184
|
+
- `baseUrl` must be an absolute `http` or `https` URL without URL credentials, query strings, or fragments
|
|
185
|
+
- the library normalizes `baseUrl` to an `/embeddings` endpoint
|
|
186
|
+
- `batchSize` defaults to `32` and controls outbound chunking
|
|
187
|
+
- `apiKey` is optional and never falls back to `OPENAI_API_KEY`
|
|
188
|
+
|
|
189
|
+
References:
|
|
190
|
+
|
|
191
|
+
- [Text Embeddings Inference quick tour](https://huggingface.co/docs/text-embeddings-inference/quick_tour)
|
|
192
|
+
- [Text Embeddings Inference CLI arguments](https://huggingface.co/docs/text-embeddings-inference/cli_arguments)
|
|
193
|
+
|
|
194
|
+
## Next Steps
|
|
195
|
+
|
|
196
|
+
- [Integration examples](./INTEGRATIONS.md) for end-to-end configuration flows
|
|
197
|
+
- [Migration guide](./MIGRATIONS.md) before changing widths, models, or endpoints
|
|
198
|
+
- [Testing guide](./TESTING.md) for CI-safe provider coverage
|
package/docs/README.md
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
# Documentation
|
|
2
2
|
|
|
3
3
|
This directory holds the longer-form reference material for `libsql-search`.
|
|
4
|
-
Start with the page that matches the job you are doing:
|
|
5
4
|
|
|
6
|
-
- [Provider
|
|
7
|
-
|
|
5
|
+
- [Provider selection and configuration](./PROVIDERS.md): compare local, hosted, and custom embedding providers before you build an index
|
|
6
|
+
- [Integration examples](./INTEGRATIONS.md): reusable provider flow plus Astro and Next.js examples
|
|
7
|
+
- [Migration and reindexing guide](./MIGRATIONS.md): table-width changes, provider/model swaps, and safe cutovers
|
|
8
8
|
- [API reference](./API.md): exported functions, option shapes, and result data
|
|
9
|
-
- [
|
|
10
|
-
- [
|
|
11
|
-
|
|
12
|
-
- [Troubleshooting](./TROUBLESHOOTING.md): known install/runtime issues
|
|
9
|
+
- [Indexing and operations](./INDEXING.md): content layout, rebuild behavior, and search quality notes
|
|
10
|
+
- [Testing guidance](./TESTING.md): CI-safe mocks and no-live-call policy
|
|
11
|
+
- [Troubleshooting](./TROUBLESHOOTING.md): known install and runtime issues
|
|
13
12
|
- [Releasing](./RELEASING.md): maintainer release workflow
|
|
14
13
|
|
|
15
|
-
For the shortest first-use path, go back to the repository
|
|
16
|
-
[README](../README.md).
|
|
14
|
+
For the shortest first-use path, go back to the repository [README](../README.md).
|
package/docs/TESTING.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Testing Guidance
|
|
2
|
+
|
|
3
|
+
Routine unit tests and CI should not make live embedding-provider calls and should not require real provider credentials.
|
|
4
|
+
|
|
5
|
+
## Repository Policy
|
|
6
|
+
|
|
7
|
+
- no live provider keys in unit tests or CI
|
|
8
|
+
- no routine network calls to hosted embedding providers in CI
|
|
9
|
+
- validate option handling and response parsing with mocks first
|
|
10
|
+
- assert failures happen before network calls when configuration is invalid
|
|
11
|
+
|
|
12
|
+
The current test suite follows that pattern in `tests/embeddings.test.ts` and [`tests/huggingface-transformers.mock.ts`](../tests/huggingface-transformers.mock.ts).
|
|
13
|
+
|
|
14
|
+
## Local Provider Mocks
|
|
15
|
+
|
|
16
|
+
The local provider should use a lightweight Transformers.js mock instead of downloading the real model during routine tests.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import {
|
|
20
|
+
huggingFaceTransformersMock,
|
|
21
|
+
resetHuggingFaceTransformersMock,
|
|
22
|
+
} from "./huggingface-transformers.mock.js";
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
resetHuggingFaceTransformersMock();
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The repository source file is `huggingface-transformers.mock.ts`. The example keeps the `.js` import suffix because this repo's ESM TypeScript source uses explicit `.js` relative imports that resolve after compilation.
|
|
30
|
+
|
|
31
|
+
Test the contract you care about:
|
|
32
|
+
|
|
33
|
+
- the library requests `Xenova/all-MiniLM-L6-v2`
|
|
34
|
+
- the call uses `pooling: "mean"` and `normalize: true`
|
|
35
|
+
- non-`384` local dimensions fail before runtime loading
|
|
36
|
+
|
|
37
|
+
## HTTP Provider Mocks
|
|
38
|
+
|
|
39
|
+
Cloudflare, Mistral, OpenAI, and `openai-compatible` should use `fetch` mocks.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { vi } from "vitest";
|
|
43
|
+
|
|
44
|
+
const fetchMock = vi.fn().mockResolvedValue({
|
|
45
|
+
ok: true,
|
|
46
|
+
headers: new Headers(),
|
|
47
|
+
json: async () => ({
|
|
48
|
+
data: [
|
|
49
|
+
{ index: 0, embedding: [1, 2] },
|
|
50
|
+
{ index: 1, embedding: [3, 4] },
|
|
51
|
+
],
|
|
52
|
+
}),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Useful assertions:
|
|
59
|
+
|
|
60
|
+
- request body includes the expected `model`
|
|
61
|
+
- OpenAI includes `dimensions`
|
|
62
|
+
- Mistral and `openai-compatible` include `encoding_format: "float"`
|
|
63
|
+
- `openai-compatible` chunking honors `batchSize`
|
|
64
|
+
- Cloudflare and Mistral reorder indexed responses correctly
|
|
65
|
+
- invalid config fails before `fetch` is called
|
|
66
|
+
|
|
67
|
+
## Gemini SDK Mocks
|
|
68
|
+
|
|
69
|
+
Gemini uses the `@google/genai` SDK, so routine tests should mock the SDK client rather than calling Google.
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
vi.mock("@google/genai", () => ({
|
|
73
|
+
GoogleGenAI: class {
|
|
74
|
+
readonly models = {
|
|
75
|
+
embedContent: vi.fn(async () => ({
|
|
76
|
+
embeddings: [{ values: [1, 2, 3] }],
|
|
77
|
+
})),
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
}));
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Useful assertions:
|
|
84
|
+
|
|
85
|
+
- the adapter sends `gemini-embedding-2`
|
|
86
|
+
- document intent formats text as `title: none | text: ...`
|
|
87
|
+
- query intent formats text as `task: search result | query: ...`
|
|
88
|
+
- explicit dimensions are forwarded as `outputDimensionality`
|
|
89
|
+
- invalid dimensions fail before SDK work
|
|
90
|
+
|
|
91
|
+
## Environment Cleanup
|
|
92
|
+
|
|
93
|
+
Tests that touch provider credentials should save and restore environment variables so one case cannot leak into another:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
let originalOpenAIKey: string | undefined;
|
|
97
|
+
|
|
98
|
+
beforeEach(() => {
|
|
99
|
+
originalOpenAIKey = process.env.OPENAI_API_KEY;
|
|
100
|
+
delete process.env.OPENAI_API_KEY;
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
afterEach(() => {
|
|
104
|
+
if (originalOpenAIKey === undefined) {
|
|
105
|
+
delete process.env.OPENAI_API_KEY;
|
|
106
|
+
} else {
|
|
107
|
+
process.env.OPENAI_API_KEY = originalOpenAIKey;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Apply the same pattern to `GEMINI_API_KEY`, `MISTRAL_API_KEY`, `CLOUDFLARE_ACCOUNT_ID`, and `CLOUDFLARE_API_TOKEN`.
|
|
113
|
+
|
|
114
|
+
## Validation-before-network Coverage
|
|
115
|
+
|
|
116
|
+
Prefer tests that prove bad inputs fail locally:
|
|
117
|
+
|
|
118
|
+
- unknown provider
|
|
119
|
+
- missing provider credentials
|
|
120
|
+
- blank credentials where trimming is expected
|
|
121
|
+
- invalid local dimensions
|
|
122
|
+
- invalid Gemini dimensions
|
|
123
|
+
- invalid `openai-compatible` `baseUrl`
|
|
124
|
+
- invalid `openai-compatible` `batchSize`
|
|
125
|
+
- OpenAI batches above `2048`
|
|
126
|
+
|
|
127
|
+
These checks keep CI fast and prove the library rejects bad inputs before it ships them to a provider.
|
|
128
|
+
|
|
129
|
+
## Optional Live Smoke Tests
|
|
130
|
+
|
|
131
|
+
If you want live provider smoke coverage, keep it outside routine CI:
|
|
132
|
+
|
|
133
|
+
- run it only when a developer explicitly opts in
|
|
134
|
+
- use dedicated throwaway credentials and test content
|
|
135
|
+
- isolate it from unit-test jobs
|
|
136
|
+
- expect provider cost and external data transfer
|
|
137
|
+
|
|
138
|
+
This repository does not require or expect live provider smoke tests for normal pull-request validation.
|