@mneme-ai/embeddings 0.8.3

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 ADDED
@@ -0,0 +1,25 @@
1
+ # @mneme-ai/embeddings
2
+
3
+ Embedding providers for [Mneme](https://github.com/patsa2561-art/mneme-ai). Three implementations of the same `EmbeddingProvider` interface.
4
+
5
+ ```ts
6
+ import { resolveEmbedder } from "@mneme-ai/embeddings";
7
+
8
+ // Auto: try Ollama → OpenAI → hash fallback
9
+ const embedder = await resolveEmbedder({ provider: "auto" });
10
+ const [vec] = await embedder.embed(["fix Stripe webhook crash on bigint"]);
11
+ ```
12
+
13
+ ## Providers
14
+
15
+ | Provider | Quality | Setup | Cost |
16
+ |---|---|---|---|
17
+ | `OllamaEmbedder` | ★★★★ | `ollama pull nomic-embed-text` | $0 |
18
+ | `OpenAIEmbedder` | ★★★★★ | `OPENAI_API_KEY=…` | ~$0.02/M tokens |
19
+ | `HashEmbedder` | ★★ | nothing | $0 |
20
+
21
+ The `HashEmbedder` is a deterministic FNV-1a hashing-trick fallback. Useful for tests, CI, and "I want to try mneme without installing anything." Not a substitute for a real embedder in production.
22
+
23
+ ## License
24
+
25
+ MIT.
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Enricher — LLM access for *generating text* (commit-note synthesis,
3
+ * incident summaries, future agentic flows).
4
+ *
5
+ * Sister contract to EmbeddingProvider but with a different shape:
6
+ * embedders return vectors, enrichers return strings.
7
+ *
8
+ * Both Ollama and OpenAI implementations are local-first compatible:
9
+ * - Ollama needs `ollama serve` + `ollama pull <model>`. Free.
10
+ * - OpenAI needs OPENAI_API_KEY. ~$0.10 to enrich a 1k-bad-commit repo.
11
+ */
12
+ export interface EnrichInput {
13
+ /** System-style instruction (rules + persona). */
14
+ system: string;
15
+ /** User-style request (the actual question/task). */
16
+ user: string;
17
+ /** Soft cap on output tokens. */
18
+ maxTokens?: number;
19
+ /** Sampling temperature; 0 = deterministic, 0.7 = creative. */
20
+ temperature?: number;
21
+ }
22
+ export interface EnrichResult {
23
+ text: string;
24
+ /** Provider name + model — for provenance tracking. */
25
+ source: string;
26
+ /** Input + output token counts when available. */
27
+ usage?: {
28
+ promptTokens?: number;
29
+ completionTokens?: number;
30
+ };
31
+ }
32
+ export interface EnricherProvider {
33
+ readonly name: string;
34
+ enrich(input: EnrichInput): Promise<EnrichResult>;
35
+ }
36
+ export interface OllamaEnricherOptions {
37
+ model?: string;
38
+ baseUrl?: string;
39
+ timeoutMs?: number;
40
+ }
41
+ export declare class OllamaEnricher implements EnricherProvider {
42
+ readonly name: string;
43
+ private readonly baseUrl;
44
+ private readonly model;
45
+ private readonly timeoutMs;
46
+ constructor(opts?: OllamaEnricherOptions);
47
+ enrich(input: EnrichInput): Promise<EnrichResult>;
48
+ ping(): Promise<boolean>;
49
+ }
50
+ export interface OpenAIEnricherOptions {
51
+ apiKey: string;
52
+ model?: string;
53
+ baseUrl?: string;
54
+ timeoutMs?: number;
55
+ }
56
+ export declare class OpenAIEnricher implements EnricherProvider {
57
+ readonly name: string;
58
+ private readonly apiKey;
59
+ private readonly model;
60
+ private readonly baseUrl;
61
+ private readonly timeoutMs;
62
+ constructor(opts: OpenAIEnricherOptions);
63
+ enrich(input: EnrichInput): Promise<EnrichResult>;
64
+ }
65
+ export interface ResolveEnricherOptions {
66
+ provider?: "auto" | "ollama" | "openai";
67
+ model?: string;
68
+ apiKey?: string;
69
+ baseUrl?: string;
70
+ }
71
+ export declare function resolveEnricher(opts?: ResolveEnricherOptions): Promise<EnricherProvider>;
72
+ //# sourceMappingURL=enrich.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrich.d.ts","sourceRoot":"","sources":["../src/enrich.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,KAAK,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACnD;AAID,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD,qBAAa,cAAe,YAAW,gBAAgB;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,IAAI,GAAE,qBAA0B;IAOtC,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA0CjD,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;CAQ/B;AAID,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD,qBAAa,cAAe,YAAW,gBAAgB;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,IAAI,EAAE,qBAAqB;IAQjC,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;CAwCxD;AAID,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,eAAe,CACnC,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,gBAAgB,CAAC,CAgB3B"}
package/dist/enrich.js ADDED
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Enricher — LLM access for *generating text* (commit-note synthesis,
3
+ * incident summaries, future agentic flows).
4
+ *
5
+ * Sister contract to EmbeddingProvider but with a different shape:
6
+ * embedders return vectors, enrichers return strings.
7
+ *
8
+ * Both Ollama and OpenAI implementations are local-first compatible:
9
+ * - Ollama needs `ollama serve` + `ollama pull <model>`. Free.
10
+ * - OpenAI needs OPENAI_API_KEY. ~$0.10 to enrich a 1k-bad-commit repo.
11
+ */
12
+ const OLLAMA_DEFAULT_MODEL = "llama3.2:1b";
13
+ const OLLAMA_DEFAULT_URL = "http://localhost:11434";
14
+ export class OllamaEnricher {
15
+ name;
16
+ baseUrl;
17
+ model;
18
+ timeoutMs;
19
+ constructor(opts = {}) {
20
+ this.model = opts.model ?? OLLAMA_DEFAULT_MODEL;
21
+ this.baseUrl = (opts.baseUrl ?? OLLAMA_DEFAULT_URL).replace(/\/$/, "");
22
+ this.timeoutMs = opts.timeoutMs ?? 60_000;
23
+ this.name = `ollama:${this.model}`;
24
+ }
25
+ async enrich(input) {
26
+ const ctrl = new AbortController();
27
+ const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
28
+ try {
29
+ const res = await fetch(`${this.baseUrl}/api/chat`, {
30
+ method: "POST",
31
+ headers: { "content-type": "application/json" },
32
+ body: JSON.stringify({
33
+ model: this.model,
34
+ messages: [
35
+ { role: "system", content: input.system },
36
+ { role: "user", content: input.user },
37
+ ],
38
+ stream: false,
39
+ options: {
40
+ temperature: input.temperature ?? 0.2,
41
+ num_predict: input.maxTokens ?? 256,
42
+ },
43
+ }),
44
+ signal: ctrl.signal,
45
+ });
46
+ if (!res.ok) {
47
+ throw new Error(`Ollama enrich failed (${res.status}): ${await res.text()}`);
48
+ }
49
+ const json = (await res.json());
50
+ return {
51
+ text: json.message?.content?.trim() ?? "",
52
+ source: this.name,
53
+ usage: {
54
+ promptTokens: json.prompt_eval_count,
55
+ completionTokens: json.eval_count,
56
+ },
57
+ };
58
+ }
59
+ finally {
60
+ clearTimeout(timer);
61
+ }
62
+ }
63
+ async ping() {
64
+ try {
65
+ const res = await fetch(`${this.baseUrl}/api/tags`);
66
+ return res.ok;
67
+ }
68
+ catch {
69
+ return false;
70
+ }
71
+ }
72
+ }
73
+ const OPENAI_DEFAULT_MODEL = "gpt-4o-mini";
74
+ const OPENAI_DEFAULT_URL = "https://api.openai.com/v1";
75
+ export class OpenAIEnricher {
76
+ name;
77
+ apiKey;
78
+ model;
79
+ baseUrl;
80
+ timeoutMs;
81
+ constructor(opts) {
82
+ this.apiKey = opts.apiKey;
83
+ this.model = opts.model ?? OPENAI_DEFAULT_MODEL;
84
+ this.baseUrl = (opts.baseUrl ?? OPENAI_DEFAULT_URL).replace(/\/$/, "");
85
+ this.timeoutMs = opts.timeoutMs ?? 60_000;
86
+ this.name = `openai:${this.model}`;
87
+ }
88
+ async enrich(input) {
89
+ const ctrl = new AbortController();
90
+ const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
91
+ try {
92
+ const res = await fetch(`${this.baseUrl}/chat/completions`, {
93
+ method: "POST",
94
+ headers: {
95
+ "content-type": "application/json",
96
+ authorization: `Bearer ${this.apiKey}`,
97
+ },
98
+ body: JSON.stringify({
99
+ model: this.model,
100
+ messages: [
101
+ { role: "system", content: input.system },
102
+ { role: "user", content: input.user },
103
+ ],
104
+ temperature: input.temperature ?? 0.2,
105
+ max_tokens: input.maxTokens ?? 256,
106
+ }),
107
+ signal: ctrl.signal,
108
+ });
109
+ if (!res.ok) {
110
+ throw new Error(`OpenAI enrich failed (${res.status}): ${await res.text()}`);
111
+ }
112
+ const json = (await res.json());
113
+ return {
114
+ text: json.choices?.[0]?.message?.content?.trim() ?? "",
115
+ source: this.name,
116
+ usage: {
117
+ promptTokens: json.usage?.prompt_tokens,
118
+ completionTokens: json.usage?.completion_tokens,
119
+ },
120
+ };
121
+ }
122
+ finally {
123
+ clearTimeout(timer);
124
+ }
125
+ }
126
+ }
127
+ export async function resolveEnricher(opts = {}) {
128
+ const provider = opts.provider ?? "auto";
129
+ if (provider === "ollama" || provider === "auto") {
130
+ const ollama = new OllamaEnricher({ model: opts.model, baseUrl: opts.baseUrl });
131
+ if (await ollama.ping())
132
+ return ollama;
133
+ if (provider === "ollama") {
134
+ throw new Error("Ollama not reachable. Start it: ollama serve");
135
+ }
136
+ }
137
+ const apiKey = opts.apiKey ?? process.env["OPENAI_API_KEY"];
138
+ if ((provider === "openai" || provider === "auto") && apiKey) {
139
+ return new OpenAIEnricher({ apiKey, model: opts.model, baseUrl: opts.baseUrl });
140
+ }
141
+ throw new Error("No enricher available. Install Ollama (recommended) or set OPENAI_API_KEY.");
142
+ }
143
+ //# sourceMappingURL=enrich.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrich.js","sourceRoot":"","sources":["../src/enrich.ts"],"names":[],"mappings":"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"}
package/dist/hash.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import type { EmbeddingProvider } from "@mneme-ai/core";
2
+ /**
3
+ * Deterministic hashing-trick embedder. Zero dependencies, zero infrastructure.
4
+ * Useful for: testing, CI, "I just want to try mneme right now without installing Ollama".
5
+ *
6
+ * Quality is much lower than nomic-embed, but the architecture downstream is identical
7
+ * so users can upgrade by changing one line.
8
+ */
9
+ export declare class HashEmbedder implements EmbeddingProvider {
10
+ readonly name = "hash:fnv-256";
11
+ readonly dimensions: number;
12
+ constructor(dimensions?: number);
13
+ embed(texts: string[]): Promise<Float32Array[]>;
14
+ private embedOne;
15
+ }
16
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD;;;;;;GAMG;AACH,qBAAa,YAAa,YAAW,iBAAiB;IACpD,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAEhB,UAAU,SAAM;IAItB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAIrD,OAAO,CAAC,QAAQ;CAejB"}
package/dist/hash.js ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Deterministic hashing-trick embedder. Zero dependencies, zero infrastructure.
3
+ * Useful for: testing, CI, "I just want to try mneme right now without installing Ollama".
4
+ *
5
+ * Quality is much lower than nomic-embed, but the architecture downstream is identical
6
+ * so users can upgrade by changing one line.
7
+ */
8
+ export class HashEmbedder {
9
+ name = "hash:fnv-256";
10
+ dimensions;
11
+ constructor(dimensions = 256) {
12
+ this.dimensions = dimensions;
13
+ }
14
+ async embed(texts) {
15
+ return texts.map((t) => this.embedOne(t));
16
+ }
17
+ embedOne(text) {
18
+ const vec = new Float32Array(this.dimensions);
19
+ const tokens = tokenize(text);
20
+ for (const tok of tokens) {
21
+ const h1 = fnv1a(tok) % this.dimensions;
22
+ const h2 = fnv1a(`#${tok}`) % this.dimensions;
23
+ vec[h1] += 1;
24
+ vec[h2] += 0.5;
25
+ }
26
+ let n = 0;
27
+ for (let i = 0; i < vec.length; i++)
28
+ n += vec[i] * vec[i];
29
+ const norm = Math.sqrt(n) || 1;
30
+ for (let i = 0; i < vec.length; i++)
31
+ vec[i] /= norm;
32
+ return vec;
33
+ }
34
+ }
35
+ function tokenize(s) {
36
+ return s
37
+ .toLowerCase()
38
+ .replace(/[^a-z0-9_]+/g, " ")
39
+ .split(/\s+/)
40
+ .filter((t) => t.length >= 2);
41
+ }
42
+ function fnv1a(s) {
43
+ let h = 0x811c9dc5;
44
+ for (let i = 0; i < s.length; i++) {
45
+ h ^= s.charCodeAt(i);
46
+ h = Math.imul(h, 0x01000193);
47
+ }
48
+ return h >>> 0;
49
+ }
50
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,OAAO,YAAY;IACd,IAAI,GAAG,cAAc,CAAC;IACtB,UAAU,CAAS;IAE5B,YAAY,UAAU,GAAG,GAAG;QAC1B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAe;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IAEO,QAAQ,CAAC,IAAY;QAC3B,MAAM,GAAG,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC9B,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YACzB,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YACxC,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC;YAC9C,GAAG,CAAC,EAAE,CAAE,IAAI,CAAC,CAAC;YACd,GAAG,CAAC,EAAE,CAAE,IAAI,GAAG,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;YAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAE,GAAG,GAAG,CAAC,CAAC,CAAE,CAAC;QAC5D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;YAAE,GAAG,CAAC,CAAC,CAAE,IAAI,IAAI,CAAC;QACrD,OAAO,GAAG,CAAC;IACb,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,CAAS;IACzB,OAAO,CAAC;SACL,WAAW,EAAE;SACb,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;SAC5B,KAAK,CAAC,KAAK,CAAC;SACZ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,KAAK,CAAC,CAAS;IACtB,IAAI,CAAC,GAAG,UAAU,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACrB,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,CAAC;AACjB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=hash.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.test.d.ts","sourceRoot":"","sources":["../src/hash.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,43 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { HashEmbedder } from "./hash.js";
3
+ describe("HashEmbedder", () => {
4
+ const embedder = new HashEmbedder(64);
5
+ it("produces vectors of the configured dimension", async () => {
6
+ const [v] = await embedder.embed(["hello world"]);
7
+ expect(v).toBeInstanceOf(Float32Array);
8
+ expect(v.length).toBe(64);
9
+ });
10
+ it("is deterministic — same input → same output", async () => {
11
+ const [a] = await embedder.embed(["fix stripe webhook"]);
12
+ const [b] = await embedder.embed(["fix stripe webhook"]);
13
+ expect(Array.from(a)).toEqual(Array.from(b));
14
+ });
15
+ it("normalizes vectors to unit length", async () => {
16
+ const [v] = await embedder.embed(["arbitrary text content"]);
17
+ let norm = 0;
18
+ for (let i = 0; i < v.length; i++)
19
+ norm += v[i] * v[i];
20
+ expect(Math.sqrt(norm)).toBeCloseTo(1, 5);
21
+ });
22
+ it("handles empty input gracefully", async () => {
23
+ const [v] = await embedder.embed([""]);
24
+ expect(v).toBeInstanceOf(Float32Array);
25
+ });
26
+ it("similar inputs are more similar than dissimilar", async () => {
27
+ const big = new HashEmbedder(512);
28
+ const [a] = await big.embed(["fix stripe webhook crash on bigint amount"]);
29
+ const [b] = await big.embed(["fix stripe webhook bug for bigint"]);
30
+ const [c] = await big.embed(["unrelated documentation update for readme"]);
31
+ const sim = (x, y) => {
32
+ let d = 0;
33
+ for (let i = 0; i < x.length; i++)
34
+ d += x[i] * y[i];
35
+ return d;
36
+ };
37
+ expect(sim(a, b)).toBeGreaterThan(sim(a, c));
38
+ });
39
+ it("reports a stable name", () => {
40
+ expect(embedder.name).toBe("hash:fnv-256");
41
+ });
42
+ });
43
+ //# sourceMappingURL=hash.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.test.js","sourceRoot":"","sources":["../src/hash.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export * from "./ollama.js";
2
+ export * from "./openai.js";
3
+ export * from "./hash.js";
4
+ export * from "./resolve.js";
5
+ export * from "./enrich.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from "./ollama.js";
2
+ export * from "./openai.js";
3
+ export * from "./hash.js";
4
+ export * from "./resolve.js";
5
+ export * from "./enrich.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { EmbeddingProvider } from "@mneme-ai/core";
2
+ export interface OllamaOptions {
3
+ model?: string;
4
+ baseUrl?: string;
5
+ dimensions?: number;
6
+ }
7
+ export declare class OllamaEmbedder implements EmbeddingProvider {
8
+ readonly name: string;
9
+ readonly dimensions: number;
10
+ private readonly baseUrl;
11
+ private readonly model;
12
+ constructor(opts?: OllamaOptions);
13
+ embed(texts: string[]): Promise<Float32Array[]>;
14
+ ping(): Promise<boolean>;
15
+ }
16
+ //# sourceMappingURL=ollama.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../src/ollama.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,qBAAa,cAAe,YAAW,iBAAiB;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAEnB,IAAI,GAAE,aAAkB;IAO9B,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAkB/C,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;CAQ/B"}
package/dist/ollama.js ADDED
@@ -0,0 +1,43 @@
1
+ const DEFAULT_MODEL = "nomic-embed-text";
2
+ const DEFAULT_DIMS = 768;
3
+ const DEFAULT_URL = "http://localhost:11434";
4
+ export class OllamaEmbedder {
5
+ name;
6
+ dimensions;
7
+ baseUrl;
8
+ model;
9
+ constructor(opts = {}) {
10
+ this.model = opts.model ?? DEFAULT_MODEL;
11
+ this.baseUrl = (opts.baseUrl ?? DEFAULT_URL).replace(/\/$/, "");
12
+ this.dimensions = opts.dimensions ?? DEFAULT_DIMS;
13
+ this.name = `ollama:${this.model}`;
14
+ }
15
+ async embed(texts) {
16
+ const out = [];
17
+ for (const text of texts) {
18
+ const res = await fetch(`${this.baseUrl}/api/embeddings`, {
19
+ method: "POST",
20
+ headers: { "content-type": "application/json" },
21
+ body: JSON.stringify({ model: this.model, prompt: text }),
22
+ });
23
+ if (!res.ok) {
24
+ throw new Error(`Ollama embed failed (${res.status}): ${await res.text()}`);
25
+ }
26
+ const json = (await res.json());
27
+ if (!json.embedding)
28
+ throw new Error("Ollama returned no embedding");
29
+ out.push(Float32Array.from(json.embedding));
30
+ }
31
+ return out;
32
+ }
33
+ async ping() {
34
+ try {
35
+ const res = await fetch(`${this.baseUrl}/api/tags`);
36
+ return res.ok;
37
+ }
38
+ catch {
39
+ return false;
40
+ }
41
+ }
42
+ }
43
+ //# sourceMappingURL=ollama.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama.js","sourceRoot":"","sources":["../src/ollama.ts"],"names":[],"mappings":"AAQA,MAAM,aAAa,GAAG,kBAAkB,CAAC;AACzC,MAAM,YAAY,GAAG,GAAG,CAAC;AACzB,MAAM,WAAW,GAAG,wBAAwB,CAAC;AAE7C,MAAM,OAAO,cAAc;IAChB,IAAI,CAAS;IACb,UAAU,CAAS;IACX,OAAO,CAAS;IAChB,KAAK,CAAS;IAE/B,YAAY,OAAsB,EAAE;QAClC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC;QACzC,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,WAAW,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,YAAY,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAe;QACzB,MAAM,GAAG,GAAmB,EAAE,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,iBAAiB,EAAE;gBACxD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;aAC1D,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,CAAC,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC9E,CAAC;YACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA4B,CAAC;YAC3D,IAAI,CAAC,IAAI,CAAC,SAAS;gBAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;YACrE,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,WAAW,CAAC,CAAC;YACpD,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ import type { EmbeddingProvider } from "@mneme-ai/core";
2
+ export interface OpenAIOptions {
3
+ apiKey: string;
4
+ model?: string;
5
+ baseUrl?: string;
6
+ dimensions?: number;
7
+ }
8
+ export declare class OpenAIEmbedder implements EmbeddingProvider {
9
+ readonly name: string;
10
+ readonly dimensions: number;
11
+ private readonly apiKey;
12
+ private readonly model;
13
+ private readonly baseUrl;
14
+ constructor(opts: OpenAIOptions);
15
+ embed(texts: string[]): Promise<Float32Array[]>;
16
+ }
17
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../src/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,qBAAa,cAAe,YAAW,iBAAiB;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,IAAI,EAAE,aAAa;IAQzB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAmBtD"}
package/dist/openai.js ADDED
@@ -0,0 +1,36 @@
1
+ const DEFAULT_MODEL = "text-embedding-3-small";
2
+ const DEFAULT_DIMS = 1536;
3
+ const DEFAULT_URL = "https://api.openai.com/v1";
4
+ export class OpenAIEmbedder {
5
+ name;
6
+ dimensions;
7
+ apiKey;
8
+ model;
9
+ baseUrl;
10
+ constructor(opts) {
11
+ this.apiKey = opts.apiKey;
12
+ this.model = opts.model ?? DEFAULT_MODEL;
13
+ this.baseUrl = (opts.baseUrl ?? DEFAULT_URL).replace(/\/$/, "");
14
+ this.dimensions = opts.dimensions ?? DEFAULT_DIMS;
15
+ this.name = `openai:${this.model}`;
16
+ }
17
+ async embed(texts) {
18
+ if (!texts.length)
19
+ return [];
20
+ const res = await fetch(`${this.baseUrl}/embeddings`, {
21
+ method: "POST",
22
+ headers: {
23
+ "content-type": "application/json",
24
+ authorization: `Bearer ${this.apiKey}`,
25
+ },
26
+ body: JSON.stringify({ model: this.model, input: texts }),
27
+ });
28
+ if (!res.ok) {
29
+ throw new Error(`OpenAI embed failed (${res.status}): ${await res.text()}`);
30
+ }
31
+ const json = (await res.json());
32
+ json.data.sort((a, b) => a.index - b.index);
33
+ return json.data.map((d) => Float32Array.from(d.embedding));
34
+ }
35
+ }
36
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../src/openai.ts"],"names":[],"mappings":"AASA,MAAM,aAAa,GAAG,wBAAwB,CAAC;AAC/C,MAAM,YAAY,GAAG,IAAI,CAAC;AAC1B,MAAM,WAAW,GAAG,2BAA2B,CAAC;AAEhD,MAAM,OAAO,cAAc;IAChB,IAAI,CAAS;IACb,UAAU,CAAS;IACX,MAAM,CAAS;IACf,KAAK,CAAS;IACd,OAAO,CAAS;IAEjC,YAAY,IAAmB;QAC7B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC;QACzC,IAAI,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,WAAW,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,YAAY,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,KAAe;QACzB,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,aAAa,EAAE;YACpD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;aACvC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;SAC1D,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,wBAAwB,GAAG,CAAC,MAAM,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC9E,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAE7B,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IAC9D,CAAC;CACF"}
@@ -0,0 +1,15 @@
1
+ import type { EmbeddingProvider } from "@mneme-ai/core";
2
+ export interface ResolveOptions {
3
+ provider?: "auto" | "ollama" | "openai" | "hash";
4
+ model?: string;
5
+ apiKey?: string;
6
+ baseUrl?: string;
7
+ }
8
+ /**
9
+ * Auto-select an embedder.
10
+ *
11
+ * auto: prefer Ollama → OpenAI (if key) → hash fallback
12
+ * ollama / openai / hash: explicit
13
+ */
14
+ export declare function resolveEmbedder(opts?: ResolveOptions): Promise<EmbeddingProvider>;
15
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAKxD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuB3F"}
@@ -0,0 +1,29 @@
1
+ import { OllamaEmbedder } from "./ollama.js";
2
+ import { OpenAIEmbedder } from "./openai.js";
3
+ import { HashEmbedder } from "./hash.js";
4
+ /**
5
+ * Auto-select an embedder.
6
+ *
7
+ * auto: prefer Ollama → OpenAI (if key) → hash fallback
8
+ * ollama / openai / hash: explicit
9
+ */
10
+ export async function resolveEmbedder(opts = {}) {
11
+ const provider = opts.provider ?? "auto";
12
+ if (provider === "ollama" || provider === "auto") {
13
+ const ollama = new OllamaEmbedder({ model: opts.model, baseUrl: opts.baseUrl });
14
+ if (await ollama.ping())
15
+ return ollama;
16
+ if (provider === "ollama") {
17
+ throw new Error(`Ollama not reachable at ${opts.baseUrl ?? "http://localhost:11434"}. Start it with: ollama serve`);
18
+ }
19
+ }
20
+ const apiKey = opts.apiKey ?? process.env["OPENAI_API_KEY"];
21
+ if ((provider === "openai" || provider === "auto") && apiKey) {
22
+ return new OpenAIEmbedder({ apiKey, model: opts.model, baseUrl: opts.baseUrl });
23
+ }
24
+ if (provider === "openai") {
25
+ throw new Error("No OpenAI API key. Set OPENAI_API_KEY or pass --api-key.");
26
+ }
27
+ return new HashEmbedder();
28
+ }
29
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../src/resolve.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AASzC;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAuB,EAAE;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC;IAEzC,IAAI,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACjD,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAChF,IAAI,MAAM,MAAM,CAAC,IAAI,EAAE;YAAE,OAAO,MAAM,CAAC;QACvC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,2BAA2B,IAAI,CAAC,OAAO,IAAI,wBAAwB,+BAA+B,CACnG,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC5D,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QAC7D,OAAO,IAAI,cAAc,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC9E,CAAC;IAED,OAAO,IAAI,YAAY,EAAE,CAAC;AAC5B,CAAC"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@mneme-ai/embeddings",
3
+ "version": "0.8.3",
4
+ "description": "Embedding providers (Ollama, OpenAI, hash-fallback) for Mneme",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/patsa2561-art/mneme-ai.git",
17
+ "directory": "packages/embeddings"
18
+ },
19
+ "homepage": "https://github.com/patsa2561-art/mneme-ai#readme",
20
+ "bugs": {
21
+ "url": "https://github.com/patsa2561-art/mneme-ai/issues"
22
+ },
23
+ "license": "MIT",
24
+ "files": ["dist", "README.md"],
25
+ "scripts": {
26
+ "build": "tsc -b",
27
+ "clean": "tsc -b --clean"
28
+ },
29
+ "dependencies": {
30
+ "@mneme-ai/core": "0.8.3"
31
+ }
32
+ }