Skip to content

Commit fedb4f8

Browse files
committed
docs(readme): real quickstart, EmbeddingRequestError, CONTRIBUTING (CL-9089)
The quickstart embeds two strings with a literal config and prints the count and width; no env loader, spread, or manual deps. Errors document EmbeddingRequestError, the internal transport section is gone, the @intx/inference paragraph appears once under Using with Interchange, and Versioning/Development move to CONTRIBUTING.md. Also closes CL-9093, CL-9090, CL-9098.
1 parent ff0c099 commit fedb4f8

2 files changed

Lines changed: 35 additions & 70 deletions

File tree

‎CONTRIBUTING.md‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Contributing
2+
3+
## Development
4+
5+
```bash
6+
bun install
7+
bun run typecheck
8+
bun run lint
9+
bun run test
10+
```
11+
12+
`bun run test` includes a live `/v1/embeddings` round trip that runs when
13+
`EMBEDDING_E2E_BASE_URL` (default `http://localhost:11434/v1`) is reachable
14+
and skips otherwise. `EMBEDDING_E2E_MODEL` defaults to `nomic-embed-text`.
15+
16+
## Versioning
17+
18+
Semver. Releases run `bun run build && npm publish` with green CI.

‎README.md‎

Lines changed: 17 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ OpenAI, Ollama, TEI, vLLM, and Jina all serve the same wire shape. This package
88
- `encodingFormat` — `float` (default) or compact `base64`.
99
- `batchSize` — inputs per request (default 32). Tune it to provider caps and per-request token ceilings.
1010

11-
Transport, error classification, and retry build on `@intx/inference`: requests go through the shared `deps.fetch` path, failures classify into `InferenceError` just like chat calls, and `createDefaultRetryPolicy` guides backoff. A 429 from an embeddings endpoint behaves like one from a chat endpoint, and credential failures short-circuit.
12-
1311
## Install
1412

1513
```bash
@@ -20,85 +18,34 @@ Runs on Bun >= 1.2 or Node >= 24. The built `dist/` entry is the default import.
2018

2119
## Quickstart
2220

23-
This package never touches credential storage or config sources — it takes an
24-
already-built `EmbedConfig`. Where that config comes from is the host's
25-
choice; `@corbits/memory`, for example, reads it straight from
26-
`EMBED_BASE_URL`/`EMBED_MODEL`/`EMBED_API_KEY` env vars, all-or-nothing on the
27-
first two. A host wraps `embedTexts` in a function of its own that builds the
28-
config once (at startup, or per call) and probes dimensionality up front so a
29-
later model swap is caught as a migration, not a silent width mismatch.
30-
3121
```ts
32-
import { createDefaultScheduler } from "@intx/inference";
33-
import {
34-
embedTexts,
35-
probeEmbedDims,
36-
type EmbedConfig,
37-
} from "@corbits/embedding";
38-
39-
export function loadEmbedConfig(): EmbedConfig | undefined {
40-
const baseURL = process.env["EMBED_BASE_URL"];
41-
const model = process.env["EMBED_MODEL"];
42-
if (baseURL === undefined || model === undefined) return undefined;
43-
44-
const apiKey = process.env["EMBED_API_KEY"];
45-
return { baseURL, model, ...(apiKey !== undefined ? { apiKey } : {}) };
46-
}
47-
48-
export async function embed(
49-
texts: readonly string[],
50-
config: EmbedConfig,
51-
): Promise<number[][]> {
52-
const deps = { fetch, scheduler: createDefaultScheduler() };
53-
return embedTexts(texts, config, { deps });
54-
}
55-
56-
// At startup: fail fast if the configured model's width doesn't match
57-
// what's already stored.
58-
const config = loadEmbedConfig();
59-
if (config !== undefined) {
60-
const deps = { fetch, scheduler: createDefaultScheduler() };
61-
const dims = await probeEmbedDims(config, { deps });
62-
}
22+
import { embedTexts } from "@corbits/embedding";
23+
24+
const config = {
25+
baseURL: "http://localhost:11434/v1",
26+
model: "nomic-embed-text",
27+
};
28+
29+
const vectors = await embedTexts(["a", "b"], config);
30+
console.log(vectors.length, vectors[0]?.length); // 2 768
6331
```
6432

65-
`embedTexts(texts, config, options)` batches sequentially, posts each batch to
66-
`{baseURL}/embeddings`, and returns vectors in input order. `options` carries
67-
`deps` (a host's real `fetch` plus `createDefaultScheduler()`, the production
68-
scheduler), with optional `retryPolicy`, `extractRetryAfterMs`, and `signal`.
33+
`embedTexts(texts, config, options?)` batches sequentially, posts each batch to
34+
`{baseURL}/embeddings`, and returns vectors in input order. `options` is
35+
optional: `deps` (defaults to global `fetch` and `createDefaultScheduler()`),
36+
`retryPolicy`, `extractRetryAfterMs`, and `signal`.
6937

7038
## Dimensionality
7139

72-
`probeEmbedDims(config, { deps })` embeds one probe string and reports the length received. Dimensionality follows the provider and the `dimensions` setting, so callers that persist vectors discover it at startup and treat a model swap as a migration. Representative widths: 1536 for OpenAI `text-embedding-3-small`, 768 for `nomic-embed-text`, 384 for `bge-small-en-v1.5`.
40+
`probeEmbedDims(config)` embeds one probe string and reports the length received. Dimensionality follows the provider and the `dimensions` setting, so callers that persist vectors discover it at startup and treat a model swap as a migration. Representative widths: 1536 for OpenAI `text-embedding-3-small`, 768 for `nomic-embed-text`, 384 for `bge-small-en-v1.5`.
7341

7442
## Errors
7543

76-
Every failure mode — transport, HTTP status, or a 200 with an unexpected body — raises `ModelRequestError`, carrying the classified `InferenceError` as `reason` plus the request URL. The embedding and reranking packages each carry their own copy of this class while the shared transport is upstreamed, so code catching both discriminates on `error.name === "ModelRequestError"`.
77-
78-
## Lower-level: transport
79-
80-
The barrel also re-exports the one-shot JSON transport `embedTexts` is built on, for sibling clients that want the same classified, retried request path:
81-
82-
- `runJSONRequest` — one JSON POST with error classification and retry.
83-
- `extractRetryAfterMs` — default `Retry-After` reader, overridable per call.
84-
- `ModelRequestError` — error for every failure mode, with `reason` and URL.
85-
- Types `RunRequestOptions` and `RetryAfterExtractor`.
44+
Every failure — transport, HTTP status, or a 200 with an unexpected body — throws `EmbeddingRequestError` (`extends Error`), carrying the classified `InferenceError` as `reason` and the request `url`. A config that fails `EmbedConfigSchema` throws before any request.
8645

87-
## Interchange
46+
## Using with Interchange
8847

89-
Built on the shared `@intx/inference` transport, so an embeddings call fails and retries the same way a chat call does: same `deps.fetch` path, same `InferenceError` classification, same `createDefaultRetryPolicy` backoff. A retrieval pipeline typically pairs `probeEmbedDims` at startup with `embedTexts` batches at ingest and query time, as described above.
90-
91-
## Versioning
92-
93-
Semver. Releases run `bun run build && npm publish` with green CI.
94-
95-
## Development
96-
97-
```bash
98-
bun install
99-
bun test ./src
100-
bunx tsc --noEmit
101-
```
48+
Transport, error classification, and retry build on `@intx/inference`: requests go through `deps.fetch`, failures classify into `InferenceError` just like chat calls, and `createDefaultRetryPolicy` guides backoff. A 429 from an embeddings endpoint behaves like one from a chat endpoint, and credential failures short-circuit. `@intx/inference` and `@intx/types` are peer dependencies, so the host's Interchange version is the one used.
10249

10350
## License
10451

0 commit comments

Comments
 (0)