@ponraaj/dimple-sdk 0.0.0-alpha.3 → 0.0.0-alpha.4

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 CHANGED
@@ -19,8 +19,10 @@ npm install @ponraaj/dimple-sdk
19
19
  ```
20
20
 
21
21
  Runtime dependencies are the only things installed (Effect, libSQL,
22
- Transformers.js, drizzle) — the workspace internals are bundled into the
23
- package.
22
+ Transformers.js, drizzle) — the workspace internals (`@dimple/*`) are
23
+ bundled into the package, including fully **self-contained type
24
+ declarations** (the publish build vendors every internal d.ts and rewrites
25
+ the `@dimple/*` specifiers — plain consumers never need the workspace).
24
26
 
25
27
  ## Quickstart
26
28
 
@@ -80,7 +82,7 @@ Pass a config file path or an inline object:
80
82
 
81
83
  ```ts
82
84
  const dimple = await makeDimple({ config: "./dimple.jsonc" });
83
- // or
85
+ // or — the inline object mirrors the JSON config exactly (quoted keys):
84
86
  const dimple = await makeDimple({
85
87
  config: {
86
88
  storeUrl: "file:./.dimple/dimple.db",
@@ -116,8 +118,9 @@ const dimple = await makeDimple({
116
118
 
117
119
  ### Embedding models
118
120
 
119
- Config-swappable — any Transformers.js ONNX model (the only tested
120
- provider):
121
+ Two providers — **local** (Transformers.js ONNX, runs on your CPU, no
122
+ keys) and **hosted** (any OpenAI-compatible endpoint, plus native
123
+ provider families):
121
124
 
122
125
  ```jsonc
123
126
  "embedding": {
@@ -128,11 +131,32 @@ provider):
128
131
  { "id": "bge", "provider": "transformers",
129
132
  "model": "Xenova/bge-small-en-v1.5", "dimensions": 384 },
130
133
  { "id": "bge-base", "provider": "transformers",
131
- "model": "Xenova/bge-base-en-v1.5", "dimensions": 768 }
134
+ "model": "Xenova/bge-base-en-v1.5", "dimensions": 768 },
135
+ { "id": "gemini", "provider": "openai",
136
+ "model": "gemini-embedding-2", "dimensions": 3072, "apiKey": "…",
137
+ "baseURL": "https://generativelanguage.googleapis.com/v1beta/openai/" },
138
+ { "id": "openai", "provider": "openai",
139
+ "model": "text-embedding-3-small", "dimensions": 1536, "apiKey": "…" }
132
140
  ]
133
141
  }
134
142
  ```
135
143
 
144
+ **Hosted providers** — the config `provider` field selects the family:
145
+
146
+ | `provider` | Models | `baseURL` needed? |
147
+ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
148
+ | `openai` (default) | any OpenAI-compatible endpoint — OpenAI, vLLM, **ollama** (`http://localhost:11434/v1`), Ollama Cloud, LM Studio, Together, Fireworks, Groq, Mistral, … | optional (defaults to OpenAI) — set it for custom endpoints |
149
+ | `google` | `gemini-embedding-001`, `gemini-embedding-2`, `gemini-embedding-2-preview` (native provider) | ❌ no |
150
+ | `cohere` | `embed-english-v3.0`, `embed-multilingual-v3.0`, … (native provider) | ❌ no |
151
+ | `bedrock` | `amazon.titan-embed-text-v2:0`, `amazon.nova-embed-text-v2:0`, `cohere.embed-*` (native provider; AWS creds from env) | ❌ no |
152
+
153
+ `dimensions` is sent as a provider option where the API supports it
154
+ (openai-compatible/`outputDimensionality`/`outputDimension`/titan `dimensions`
155
+ and nova `embeddingDimension`) and ALWAYS enforced on the output.
156
+ Verified end-to-end against real `gemini-embedding-2` (3072-dim), local
157
+ ollama `Qwen3-Embedding-0.6B` (1024-dim), and the openai-compatible
158
+ contract.
159
+
136
160
  - `dimensions` must match the model's real output — a mismatch fails typed
137
161
  on first use
138
162
  - Multiple models coexist: each gets its own vector tables
@@ -326,6 +350,11 @@ query history, persisted asynchronously (never blocks the query).
326
350
  | Grammar WASMs | `~/.cache/dimple/tree-sitter/` (downloaded once, offline after) |
327
351
  | ONNX model | bun/npm cache (~90 MB, first use) |
328
352
 
353
+ ## Changelog
354
+
355
+ Every release creates a GitHub Release with the per-version changes (the
356
+ tag-based publish workflow): repo → **Releases** page.
357
+
329
358
  ## Notes
330
359
 
331
360
  - Determinism: same data + same config ⇒ same tree, same clusters, same
package/dist/index.js CHANGED
@@ -659,6 +659,7 @@ var EmbeddingModelConfig = Schema6.Struct({
659
659
  dimensions: Schema6.Number,
660
660
  vectorType: Schema6.optional(Schema6.String),
661
661
  apiKey: Schema6.optional(Schema6.String),
662
+ baseURL: Schema6.optional(Schema6.String),
662
663
  indexConfig: Schema6.optional(IndexConfig),
663
664
  device: Schema6.optional(Schema6.Literals([
664
665
  "auto",
@@ -6394,46 +6395,72 @@ var makeTransformersModel = (options = {}) => {
6394
6395
  embedSingle: impl.embedSingle
6395
6396
  };
6396
6397
  };
6397
- // ../embedder/src/openai.ts
6398
- import { Effect as Effect33 } from "effect";
6399
- var makeOpenAIModel = (options) => {
6400
- const embed = Effect33.fn("OpenAIEmbedding.embed")(function* (texts) {
6401
- const response = yield* Effect33.tryPromise({
6402
- try: () => fetch("https://api.openai.com/v1/embeddings", {
6403
- method: "POST",
6404
- headers: {
6405
- "Content-Type": "application/json",
6406
- Authorization: `Bearer ${options.apiKey}`
6407
- },
6408
- body: JSON.stringify({
6409
- input: texts,
6410
- model: options.model,
6411
- dimensions: options.dimensions
6412
- })
6413
- }).then((r) => {
6414
- if (!r.ok) {
6415
- return Promise.reject(new Error(`OpenAI API error: ${r.status} ${r.statusText}`));
6398
+ // ../embedder/src/registry.ts
6399
+ import { Effect as Effect33, Layer as Layer12 } from "effect";
6400
+ // ../core/src/hosted-embedding.ts
6401
+ import { embedMany } from "ai";
6402
+ import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
6403
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
6404
+ import { createCohere } from "@ai-sdk/cohere";
6405
+ import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock";
6406
+ import { Effect as Effect34 } from "effect";
6407
+ var makeHostedEmbeddingModel = (options) => {
6408
+ const provider = options.provider ?? "openai";
6409
+ const model = provider === "google" ? createGoogleGenerativeAI({
6410
+ apiKey: options.apiKey,
6411
+ ...options.baseURL !== undefined ? { baseURL: options.baseURL } : {}
6412
+ }).embedding(options.model) : provider === "cohere" ? createCohere({ apiKey: options.apiKey }).embedding(options.model) : provider === "bedrock" ? createAmazonBedrock({
6413
+ ...options.apiKey !== undefined ? { apiKey: options.apiKey } : {}
6414
+ }).embedding(options.model) : createOpenAICompatible({
6415
+ name: "openaiCompatible",
6416
+ baseURL: options.baseURL ?? "https://api.openai.com/v1",
6417
+ apiKey: options.apiKey
6418
+ }).embeddingModel(options.model);
6419
+ const providerOptions = (() => {
6420
+ switch (provider) {
6421
+ case "google":
6422
+ return { google: { outputDimensionality: options.dimensions } };
6423
+ case "bedrock":
6424
+ if (options.model.startsWith("amazon.nova")) {
6425
+ return { bedrock: { embeddingDimension: options.dimensions } };
6416
6426
  }
6417
- return r.json();
6418
- }),
6419
- catch: (cause) => new EmbeddingError({ message: `OpenAI embed: ${cause}` })
6427
+ if (options.model.startsWith("cohere.")) {
6428
+ return { bedrock: { inputType: "search_document" } };
6429
+ }
6430
+ return { bedrock: { dimensions: options.dimensions } };
6431
+ case "cohere":
6432
+ return [256, 512, 1024, 1536].includes(options.dimensions) ? { cohere: { inputType: "search_document", outputDimension: options.dimensions } } : { cohere: { inputType: "search_document" } };
6433
+ default:
6434
+ return { openaiCompatible: { dimensions: options.dimensions } };
6435
+ }
6436
+ })();
6437
+ const embed = Effect34.fn("HostedEmbedding.embed")(function* (texts) {
6438
+ const result = yield* Effect34.tryPromise({
6439
+ try: () => embedMany({ model, values: [...texts], providerOptions }),
6440
+ catch: (cause) => new EmbeddingError({ message: `hosted embedMany: ${cause}` })
6420
6441
  });
6421
- return response.data.map((d) => new Float32Array(d.embedding));
6442
+ for (const vector of result.embeddings) {
6443
+ if (vector.length !== options.dimensions) {
6444
+ return yield* new EmbeddingError({
6445
+ message: `hosted embedder dimension mismatch: endpoint returned ${vector.length} dims but config declares ${options.dimensions}`
6446
+ });
6447
+ }
6448
+ }
6449
+ return result.embeddings.map((e) => new Float32Array(e));
6422
6450
  });
6423
- const embedSingle = Effect33.fn("OpenAIEmbedding.embedSingle")(function* (text4) {
6451
+ const embedSingle = Effect34.fn("HostedEmbedding.embedSingle")(function* (text4) {
6424
6452
  const results = yield* embed([text4]);
6425
6453
  return results[0];
6426
6454
  });
6427
6455
  return {
6428
6456
  modelId: options.modelId,
6429
- provider: "openai",
6457
+ provider,
6430
6458
  dimensions: options.dimensions,
6431
6459
  embed,
6432
6460
  embedSingle
6433
6461
  };
6434
6462
  };
6435
- // ../embedder/src/registry.ts
6436
- import { Effect as Effect34, Layer as Layer12 } from "effect";
6463
+
6437
6464
  // ../retriever/src/hybrid.ts
6438
6465
  import { Context as Context10, Effect as Effect35, Layer as Layer13, Schema as Schema22 } from "effect";
6439
6466
 
@@ -6730,9 +6757,9 @@ ${schemaJson}`,
6730
6757
  return { generateText, generateObject };
6731
6758
  };
6732
6759
  // ../llm/src/provider.ts
6733
- import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
6760
+ import { createOpenAICompatible as createOpenAICompatible2 } from "@ai-sdk/openai-compatible";
6734
6761
  var openAICompatible = (options) => {
6735
- const provider = createOpenAICompatible({
6762
+ const provider = createOpenAICompatible2({
6736
6763
  baseURL: options.baseURL,
6737
6764
  apiKey: options.apiKey,
6738
6765
  name: options.name ?? "openai-compatible"
@@ -6835,11 +6862,13 @@ var embedderFromConfig = (model) => model.provider === "transformers" ? Effect39
6835
6862
  ...model.pooling !== undefined ? { pooling: model.pooling } : {},
6836
6863
  ...model.normalize !== undefined ? { normalize: model.normalize } : {},
6837
6864
  ...model.cacheDir !== undefined ? { cacheDir: model.cacheDir } : {}
6838
- })) : model.provider === "openai" ? model.apiKey === undefined ? Effect39.fail(new EmbeddingError({ message: `OpenAI model ${model.id} requires an apiKey` })) : Effect39.succeed(makeOpenAIModel({
6865
+ })) : model.provider === "openai" ? model.apiKey === undefined ? Effect39.fail(new EmbeddingError({ message: `OpenAI model ${model.id} requires an apiKey` })) : Effect39.succeed(makeHostedEmbeddingModel({
6839
6866
  modelId: model.id,
6840
6867
  model: model.model,
6841
6868
  dimensions: model.dimensions,
6842
- apiKey: model.apiKey
6869
+ apiKey: model.apiKey,
6870
+ ...model.provider !== "openai" ? { provider: model.provider } : {},
6871
+ ...model.baseURL !== undefined ? { baseURL: model.baseURL } : {}
6843
6872
  })) : Effect39.fail(new EmbeddingError({ message: `Unknown provider: ${model.provider}` }));
6844
6873
  var layer13 = (options) => {
6845
6874
  const topicConfig = Schema24.decodeUnknownSync(TopicConfig)(options.topics?.config ?? {});
@@ -13,6 +13,9 @@ export declare const EmbeddingModelConfig: Schema.Struct<{
13
13
  readonly dimensions: Schema.Number;
14
14
  readonly vectorType: Schema.optional<Schema.String>;
15
15
  readonly apiKey: Schema.optional<Schema.String>;
16
+ /** Hosted providers: OpenAI-compatible endpoint override (default
17
+ * `https://api.openai.com/v1`). */
18
+ readonly baseURL: Schema.optional<Schema.String>;
16
19
  readonly indexConfig: Schema.optional<Schema.Struct<{
17
20
  readonly compressNeighbors: Schema.optional<Schema.String>;
18
21
  readonly maxNeighbors: Schema.optional<Schema.Number>;
@@ -39,6 +42,9 @@ export declare const EmbeddingConfig: Schema.Struct<{
39
42
  readonly dimensions: Schema.Number;
40
43
  readonly vectorType: Schema.optional<Schema.String>;
41
44
  readonly apiKey: Schema.optional<Schema.String>;
45
+ /** Hosted providers: OpenAI-compatible endpoint override (default
46
+ * `https://api.openai.com/v1`). */
47
+ readonly baseURL: Schema.optional<Schema.String>;
42
48
  readonly indexConfig: Schema.optional<Schema.Struct<{
43
49
  readonly compressNeighbors: Schema.optional<Schema.String>;
44
50
  readonly maxNeighbors: Schema.optional<Schema.Number>;
@@ -128,6 +134,9 @@ export declare const DimpleConfig: Schema.Struct<{
128
134
  readonly dimensions: Schema.Number;
129
135
  readonly vectorType: Schema.optional<Schema.String>;
130
136
  readonly apiKey: Schema.optional<Schema.String>;
137
+ /** Hosted providers: OpenAI-compatible endpoint override (default
138
+ * `https://api.openai.com/v1`). */
139
+ readonly baseURL: Schema.optional<Schema.String>;
131
140
  readonly indexConfig: Schema.optional<Schema.Struct<{
132
141
  readonly compressNeighbors: Schema.optional<Schema.String>;
133
142
  readonly maxNeighbors: Schema.optional<Schema.Number>;
@@ -0,0 +1,33 @@
1
+ import { type EmbeddingModel } from "./internal/embedder/index.js";
2
+ export interface HostedEmbeddingOptions {
3
+ readonly modelId: string;
4
+ readonly model: string;
5
+ readonly dimensions: number;
6
+ readonly apiKey: string;
7
+ /** The AI SDK provider family — see
8
+ * https://ai-sdk.dev/providers for the full provider list. */
9
+ readonly provider?: "openai" | "google" | "cohere" | "bedrock";
10
+ /** OpenAI-compatible endpoint override — ONLY needed for custom
11
+ * endpoints (vLLM/ollama/…). The preconfigured providers have their
12
+ * base URL baked in. */
13
+ readonly baseURL?: string;
14
+ }
15
+ /**
16
+ * Hosted embeddings — the `ai` SDK IS the implementation (`embedMany`),
17
+ * this adapter only bridges it to the dimple `EmbeddingModel` interface.
18
+ *
19
+ * Provider mapping (config `provider` field):
20
+ * - `"openai"` — openai-compatible provider; `baseURL` defaults to
21
+ * `https://api.openai.com/v1`, override for any compatible endpoint
22
+ * - `"google"` — native `@ai-sdk/google` (gemini-embedding-*), no baseURL
23
+ * - `"cohere"` — native `@ai-sdk/cohere` (embed-*-v3.0), no baseURL
24
+ * - `"bedrock"` — native `@ai-sdk/amazon-bedrock` (titan/nova/cohere
25
+ * models), no baseURL — credentials come from AWS env (or the provider
26
+ * settings)
27
+ *
28
+ * `dimensions` is sent as a provider option where the API supports it
29
+ * (openaiCompatible.dimensions / google.outputDimensionality /
30
+ * cohere.outputDimension) and ALWAYS enforced on the output (some
31
+ * endpoints ignore the option).
32
+ */
33
+ export declare const makeHostedEmbeddingModel: (options: HostedEmbeddingOptions) => EmbeddingModel;
@@ -1,4 +1,3 @@
1
1
  export { Service as EmbeddingModelRegistry, type Interface as EmbeddingModelRegistryInterface, type EmbeddingModel, EmbeddingError, } from "./provider.ts";
2
2
  export { layer as transformersEmbeddingLayer, layerConfig as transformersEmbeddingLayerConfig, makeTransformersModel, } from "./transformers.ts";
3
- export { makeOpenAIModel } from "./openai.ts";
4
3
  export { layer as registryLayer, type ModelSpec } from "./registry.ts";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponraaj/dimple-sdk",
3
- "version": "0.0.0-alpha.3",
3
+ "version": "0.0.0-alpha.4",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist"
@@ -29,26 +29,19 @@
29
29
  "typecheck": "tsgo --noEmit"
30
30
  },
31
31
  "dependencies": {
32
- "@ai-sdk/openai-compatible": "^1.0.0",
32
+ "@ai-sdk/amazon-bedrock": "^5.0.46",
33
+ "@ai-sdk/cohere": "^3",
34
+ "@ai-sdk/google": "^2",
35
+ "@ai-sdk/openai-compatible": "^3.0.21",
33
36
  "@huggingface/transformers": "^4.2.0",
34
37
  "@libsql/client": "^0.17.4",
35
- "ai": "^5.0.0",
38
+ "ai": "^7.0.50",
36
39
  "drizzle-orm": "^1.0.0-rc.4",
37
40
  "effect": "4.0.0-beta.103",
38
41
  "jsonc-parser": "^3.3.1",
39
42
  "web-tree-sitter": "^0.26.9",
40
43
  "zod": "^4.4.3"
41
44
  },
42
- "devDependencies": {
43
- "@dimple/config": "0.0.0-alpha.1",
44
- "@dimple/core": "0.0.0-alpha.1",
45
- "@dimple/embedder": "0.0.0-alpha.1",
46
- "@dimple/extractor": "0.0.0-alpha.1",
47
- "@dimple/parser": "0.0.0-alpha.1",
48
- "@dimple/retriever": "0.0.0-alpha.1",
49
- "@dimple/store": "0.0.0-alpha.1",
50
- "@dimple/workflow": "0.0.0-alpha.1"
51
- },
52
45
  "peerDependencies": {
53
46
  "typescript": "^5"
54
47
  }
@@ -1,8 +0,0 @@
1
- import { type EmbeddingModel } from "./provider.ts";
2
- export interface OpenAIOptions {
3
- readonly modelId: string;
4
- readonly model: string;
5
- readonly dimensions: number;
6
- readonly apiKey: string;
7
- }
8
- export declare const makeOpenAIModel: (options: OpenAIOptions) => EmbeddingModel;