@mneme-ai/embeddings 0.21.1 → 0.22.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/dist/enrich.d.ts CHANGED
@@ -63,10 +63,112 @@ export declare class OpenAIEnricher implements EnricherProvider {
63
63
  enrich(input: EnrichInput): Promise<EnrichResult>;
64
64
  }
65
65
  export interface ResolveEnricherOptions {
66
- provider?: "auto" | "ollama" | "openai";
66
+ provider?: "auto" | "ollama" | "openai" | "groq" | "together" | "openrouter";
67
67
  model?: string;
68
68
  apiKey?: string;
69
69
  baseUrl?: string;
70
70
  }
71
+ /**
72
+ * Provider catalog — every entry uses an OpenAI-compatible /chat/completions
73
+ * endpoint, so they all share `OpenAIEnricher`. New providers = one row here.
74
+ *
75
+ * Ordered by free-tier-friendliness:
76
+ * ollama (local, totally free)
77
+ * groq — generous free tier, fast (500 tok/s), signup required
78
+ * together — modest free tier
79
+ * openrouter — pay-per-token but exposes free models too
80
+ * openai — paid, premium quality
81
+ */
82
+ export interface ProviderEntry {
83
+ id: "groq" | "together" | "openrouter" | "openai";
84
+ envKey: string;
85
+ baseUrl: string;
86
+ defaultModel: string;
87
+ /** Other free models the user can opt into (Qwen / Gemma / Llama family). */
88
+ freeModels: string[];
89
+ freeTier: boolean;
90
+ signupUrl: string;
91
+ }
92
+ declare const PROVIDERS: ProviderEntry[];
93
+ /**
94
+ * Recommended local Ollama models for the chat path. Order: balance of
95
+ * size / quality / speed. User picks one in the setup wizard or just runs
96
+ * `ollama pull <name>` manually.
97
+ */
98
+ export declare const OLLAMA_FREE_CHAT_MODELS: Array<{
99
+ name: string;
100
+ size: string;
101
+ note: string;
102
+ }>;
71
103
  export declare function resolveEnricher(opts?: ResolveEnricherOptions): Promise<EnricherProvider>;
104
+ /**
105
+ * Sentinel error for the "no LLM available" case. The CLI catches this
106
+ * specifically and switches `ask` to retrieval-only mode instead of
107
+ * showing a hard error.
108
+ */
109
+ export declare class NoEnricherAvailableError extends Error {
110
+ constructor();
111
+ }
112
+ /** Catalog exposed for `mneme setup-free` and CLI hints. */
113
+ export declare function listProviders(): typeof PROVIDERS;
114
+ /**
115
+ * Classify a thrown error into a category that determines retry behavior.
116
+ * Used by ResilientEnricher to set per-provider cooldown durations: a 429
117
+ * (quota exhausted) merits a longer cooldown than a transient 503.
118
+ */
119
+ export type FailureKind = "timeout" | "network" | "rate-limit" | "server" | "auth" | "model-missing" | "empty" | "unknown";
120
+ export declare function classifyFailure(err: unknown): FailureKind;
121
+ interface ProviderHealth {
122
+ lastFailure?: {
123
+ kind: FailureKind;
124
+ at: number;
125
+ reason: string;
126
+ };
127
+ lastSuccess?: number;
128
+ cooldownUntil?: number;
129
+ }
130
+ /**
131
+ * Self-healing enricher. Wraps an ordered list of providers and:
132
+ *
133
+ * 1. Tracks per-provider health state (lastSuccess / lastFailure / cooldownUntil)
134
+ * 2. Skips providers in cooldown — different durations per failure type
135
+ * 3. On call: tries providers in order, returns first success
136
+ * 4. On every failure: classifies + sets cooldown so the next call avoids
137
+ * the bad provider without thrashing
138
+ * 5. Surfaces switches via onSwitch() so the CLI can show "Ollama timed
139
+ * out (cooldown 30s), trying Groq..."
140
+ *
141
+ * The key UX win: a flaky cloud call NEVER kills `mneme ask`. The user
142
+ * always gets an answer (or a final extractive fallback) — Mneme silently
143
+ * adapts.
144
+ */
145
+ export declare class ResilientEnricher implements EnricherProvider {
146
+ readonly name: string;
147
+ private readonly chain;
148
+ private readonly health;
149
+ private readonly onSwitch?;
150
+ constructor(chain: EnricherProvider[], onSwitch?: (event: {
151
+ from: string;
152
+ to: string;
153
+ reason: string;
154
+ kind: FailureKind;
155
+ }) => void);
156
+ /** Inspect health for testing / debugging. */
157
+ inspectHealth(): Record<string, ProviderHealth>;
158
+ enrich(input: EnrichInput): Promise<EnrichResult>;
159
+ }
160
+ export declare class AllProvidersFailedError extends Error {
161
+ constructor(msg: string);
162
+ }
163
+ /**
164
+ * Build the FULL ladder of enrichers available to this user, in
165
+ * preference order. Used by callers that want runtime fallback (e.g.
166
+ * `mneme ask`) — try Ollama first, fall back to Groq, fall back to
167
+ * OpenRouter, etc., on EVERY call rather than just at startup.
168
+ *
169
+ * Returns [] if the user has nothing configured. Caller decides what
170
+ * to do (typically: degrade to extractive answer).
171
+ */
172
+ export declare function resolveAllEnrichers(opts?: ResolveEnricherOptions): Promise<EnricherProvider[]>;
173
+ export {};
72
174
  //# sourceMappingURL=enrich.d.ts.map
@@ -1 +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;AAOD,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;IAStC,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"}
1
+ {"version":3,"file":"enrich.d.ts","sourceRoot":"","sources":["../src/enrich.ts"],"names":[],"mappings":"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"}
package/dist/enrich.js CHANGED
@@ -128,20 +128,310 @@ export class OpenAIEnricher {
128
128
  }
129
129
  }
130
130
  }
131
+ const PROVIDERS = [
132
+ {
133
+ id: "groq",
134
+ envKey: "GROQ_API_KEY",
135
+ baseUrl: "https://api.groq.com/openai/v1",
136
+ defaultModel: "llama-3.3-70b-versatile",
137
+ freeModels: [
138
+ "llama-3.3-70b-versatile",
139
+ "qwen-qwq-32b",
140
+ "gemma2-9b-it",
141
+ "llama-3.1-8b-instant",
142
+ ],
143
+ freeTier: true,
144
+ signupUrl: "https://console.groq.com/keys",
145
+ },
146
+ {
147
+ id: "together",
148
+ envKey: "TOGETHER_API_KEY",
149
+ baseUrl: "https://api.together.xyz/v1",
150
+ defaultModel: "meta-llama/Llama-3.3-70B-Instruct-Turbo",
151
+ freeModels: [
152
+ "meta-llama/Llama-3.3-70B-Instruct-Turbo",
153
+ "Qwen/Qwen2.5-72B-Instruct-Turbo",
154
+ "google/gemma-2-9b-it",
155
+ ],
156
+ freeTier: true,
157
+ signupUrl: "https://api.together.xyz/settings/api-keys",
158
+ },
159
+ {
160
+ id: "openrouter",
161
+ envKey: "OPENROUTER_API_KEY",
162
+ baseUrl: "https://openrouter.ai/api/v1",
163
+ defaultModel: "meta-llama/llama-3.3-70b-instruct:free",
164
+ freeModels: [
165
+ "meta-llama/llama-3.3-70b-instruct:free",
166
+ "qwen/qwen-2.5-72b-instruct:free",
167
+ "google/gemma-2-9b-it:free",
168
+ "qwen/qwq-32b:free",
169
+ ],
170
+ freeTier: true,
171
+ signupUrl: "https://openrouter.ai/keys",
172
+ },
173
+ {
174
+ id: "openai",
175
+ envKey: "OPENAI_API_KEY",
176
+ baseUrl: "https://api.openai.com/v1",
177
+ defaultModel: "gpt-4o-mini",
178
+ freeModels: [], // no free models on OpenAI
179
+ freeTier: false,
180
+ signupUrl: "https://platform.openai.com/api-keys",
181
+ },
182
+ ];
183
+ /**
184
+ * Recommended local Ollama models for the chat path. Order: balance of
185
+ * size / quality / speed. User picks one in the setup wizard or just runs
186
+ * `ollama pull <name>` manually.
187
+ */
188
+ export const OLLAMA_FREE_CHAT_MODELS = [
189
+ { name: "qwen2.5:3b", size: "1.9GB", note: "best small/quality balance — recommended default" },
190
+ { name: "gemma2:2b", size: "1.6GB", note: "Google Gemma 2 — fastest tiny" },
191
+ { name: "llama3.2:1b", size: "1.3GB", note: "smallest, decent for short answers" },
192
+ { name: "qwen2.5:7b", size: "4.7GB", note: "much smarter — needs ~6GB free RAM" },
193
+ { name: "gemma2:9b", size: "5.4GB", note: "Gemma 2 mid — strong reasoning" },
194
+ ];
131
195
  export async function resolveEnricher(opts = {}) {
132
196
  const provider = opts.provider ?? "auto";
133
- if (provider === "ollama" || provider === "auto") {
197
+ // Explicit picks
198
+ if (provider === "ollama") {
134
199
  const ollama = new OllamaEnricher({ model: opts.model, baseUrl: opts.baseUrl });
135
200
  if (await ollama.ping())
136
201
  return ollama;
137
- if (provider === "ollama") {
138
- throw new Error("Ollama not reachable. Start it: ollama serve");
202
+ throw new Error("Ollama not reachable at " +
203
+ (opts.baseUrl ?? "http://127.0.0.1:11434") +
204
+ ". Start it: ollama serve\nThen pull a chat model: ollama pull llama3.2:1b");
205
+ }
206
+ if (provider === "openai" || provider === "groq" || provider === "together" || provider === "openrouter") {
207
+ const cfg = PROVIDERS.find((p) => p.id === provider);
208
+ const key = opts.apiKey ?? process.env[cfg.envKey];
209
+ if (!key) {
210
+ throw new Error(`No ${provider} key found. Set ${cfg.envKey} or pass --api-key.\n` +
211
+ `Sign up (free tier): ${cfg.signupUrl}`);
212
+ }
213
+ return new OpenAIEnricher({
214
+ apiKey: key,
215
+ model: opts.model ?? cfg.defaultModel,
216
+ baseUrl: opts.baseUrl ?? cfg.baseUrl,
217
+ });
218
+ }
219
+ // auto: privacy-first ladder. Ollama local first (free + private), then any
220
+ // free-tier cloud provider whose key is in the env, then OpenAI as last resort.
221
+ const ollama = new OllamaEnricher({ model: opts.model, baseUrl: opts.baseUrl });
222
+ if (await ollama.ping())
223
+ return ollama;
224
+ // Try env-var providers in order
225
+ for (const cfg of PROVIDERS) {
226
+ const key = process.env[cfg.envKey];
227
+ if (key) {
228
+ return new OpenAIEnricher({
229
+ apiKey: key,
230
+ model: opts.model ?? cfg.defaultModel,
231
+ baseUrl: opts.baseUrl ?? cfg.baseUrl,
232
+ });
233
+ }
234
+ }
235
+ throw new NoEnricherAvailableError();
236
+ }
237
+ /**
238
+ * Sentinel error for the "no LLM available" case. The CLI catches this
239
+ * specifically and switches `ask` to retrieval-only mode instead of
240
+ * showing a hard error.
241
+ */
242
+ export class NoEnricherAvailableError extends Error {
243
+ constructor() {
244
+ super("No LLM available — set up the free path:\n" +
245
+ " Local + private (recommended): ollama pull llama3.2:1b\n" +
246
+ " Free cloud (fastest): Get a free Groq key at https://console.groq.com/keys, then export GROQ_API_KEY=...\n" +
247
+ " Or run 'mneme setup-free' for a guided 30-second setup.");
248
+ this.name = "NoEnricherAvailableError";
249
+ }
250
+ }
251
+ /** Catalog exposed for `mneme setup-free` and CLI hints. */
252
+ export function listProviders() {
253
+ return PROVIDERS;
254
+ }
255
+ export function classifyFailure(err) {
256
+ const msg = err?.message ?? String(err);
257
+ if (/no\s+such\s+model|model.+(not\s+found|not\s+pulled)|404/i.test(msg))
258
+ return "model-missing";
259
+ if (/401|403|invalid.*key|unauthor|forbidden/i.test(msg))
260
+ return "auth";
261
+ if (/429|rate.?limit|quota|too\s+many/i.test(msg))
262
+ return "rate-limit";
263
+ if (/5\d\d|server\s+error|unavailable|bad\s+gateway/i.test(msg))
264
+ return "server";
265
+ if (/timeout|aborted|ETIMEDOUT/i.test(msg))
266
+ return "timeout";
267
+ if (/ECONNREFUSED|ENOTFOUND|EAI_AGAIN|fetch\s+failed|socket\s+hang/i.test(msg))
268
+ return "network";
269
+ return "unknown";
270
+ }
271
+ /** Cooldown in ms per failure kind. Tuned so a flaky provider self-heals
272
+ * without thrashing, but a permanently-broken one is skipped for hours. */
273
+ const COOLDOWN_MS = {
274
+ timeout: 30_000,
275
+ network: 30_000,
276
+ "rate-limit": 5 * 60_000,
277
+ server: 60_000,
278
+ auth: 60 * 60_000, // 1 hr — auth issues require user fix
279
+ "model-missing": 60 * 60_000,
280
+ empty: 5_000,
281
+ unknown: 30_000,
282
+ };
283
+ /**
284
+ * Self-healing enricher. Wraps an ordered list of providers and:
285
+ *
286
+ * 1. Tracks per-provider health state (lastSuccess / lastFailure / cooldownUntil)
287
+ * 2. Skips providers in cooldown — different durations per failure type
288
+ * 3. On call: tries providers in order, returns first success
289
+ * 4. On every failure: classifies + sets cooldown so the next call avoids
290
+ * the bad provider without thrashing
291
+ * 5. Surfaces switches via onSwitch() so the CLI can show "Ollama timed
292
+ * out (cooldown 30s), trying Groq..."
293
+ *
294
+ * The key UX win: a flaky cloud call NEVER kills `mneme ask`. The user
295
+ * always gets an answer (or a final extractive fallback) — Mneme silently
296
+ * adapts.
297
+ */
298
+ export class ResilientEnricher {
299
+ name;
300
+ chain;
301
+ health = new Map();
302
+ onSwitch;
303
+ constructor(chain, onSwitch) {
304
+ if (chain.length === 0)
305
+ throw new Error("ResilientEnricher requires at least one provider");
306
+ this.chain = chain;
307
+ this.onSwitch = onSwitch;
308
+ this.name = `resilient:[${chain.map((p) => p.name).join(", ")}]`;
309
+ }
310
+ /** Inspect health for testing / debugging. */
311
+ inspectHealth() {
312
+ return Object.fromEntries(this.health);
313
+ }
314
+ async enrich(input) {
315
+ const now = Date.now();
316
+ const errors = [];
317
+ let lastTried = -1;
318
+ for (let i = 0; i < this.chain.length; i++) {
319
+ const p = this.chain[i];
320
+ const h = this.health.get(p.name) ?? {};
321
+ // Skip if in cooldown
322
+ if (h.cooldownUntil && h.cooldownUntil > now) {
323
+ errors.push({
324
+ name: p.name,
325
+ kind: h.lastFailure?.kind ?? "unknown",
326
+ reason: `in cooldown for ${Math.ceil((h.cooldownUntil - now) / 1000)}s (${h.lastFailure?.reason ?? "?"})`,
327
+ });
328
+ continue;
329
+ }
330
+ // Notify CLI if we're switching
331
+ if (lastTried >= 0 && this.onSwitch) {
332
+ const prev = errors[errors.length - 1];
333
+ this.onSwitch({ from: this.chain[lastTried].name, to: p.name, reason: prev.reason, kind: prev.kind });
334
+ }
335
+ lastTried = i;
336
+ try {
337
+ const result = await p.enrich(input);
338
+ if (!result.text || result.text.trim().length === 0) {
339
+ // Empty answer = soft failure → short cooldown, try next
340
+ this.health.set(p.name, {
341
+ ...h,
342
+ lastFailure: { kind: "empty", at: now, reason: "empty answer" },
343
+ cooldownUntil: now + COOLDOWN_MS.empty,
344
+ });
345
+ errors.push({ name: p.name, kind: "empty", reason: "empty answer" });
346
+ continue;
347
+ }
348
+ // Success — clear cooldown, record timestamp
349
+ this.health.set(p.name, { ...h, lastSuccess: now, cooldownUntil: undefined });
350
+ return result;
351
+ }
352
+ catch (err) {
353
+ const kind = classifyFailure(err);
354
+ const msg = err.message ?? String(err);
355
+ this.health.set(p.name, {
356
+ ...h,
357
+ lastFailure: { kind, at: now, reason: msg.slice(0, 200) },
358
+ cooldownUntil: now + COOLDOWN_MS[kind],
359
+ });
360
+ errors.push({ name: p.name, kind, reason: msg.slice(0, 120) });
361
+ }
362
+ }
363
+ // Every provider failed (or all in cooldown). Throw a descriptive error
364
+ // so the caller can fall back to extractive synthesis.
365
+ const summary = errors
366
+ .map((e) => ` • ${e.name} (${e.kind}): ${e.reason}`)
367
+ .join("\n");
368
+ throw new AllProvidersFailedError(`All ${this.chain.length} provider(s) failed or in cooldown:\n${summary}\n` +
369
+ `→ Run \`mneme setup-free\` if no providers are configured.`);
370
+ }
371
+ }
372
+ export class AllProvidersFailedError extends Error {
373
+ constructor(msg) {
374
+ super(msg);
375
+ this.name = "AllProvidersFailedError";
376
+ }
377
+ }
378
+ /**
379
+ * Build the FULL ladder of enrichers available to this user, in
380
+ * preference order. Used by callers that want runtime fallback (e.g.
381
+ * `mneme ask`) — try Ollama first, fall back to Groq, fall back to
382
+ * OpenRouter, etc., on EVERY call rather than just at startup.
383
+ *
384
+ * Returns [] if the user has nothing configured. Caller decides what
385
+ * to do (typically: degrade to extractive answer).
386
+ */
387
+ export async function resolveAllEnrichers(opts = {}) {
388
+ const out = [];
389
+ // 1. Local Ollama — only add if reachable, AND auto-pick the first
390
+ // available chat model so we don't pass a wrong/embedder name.
391
+ const ollama = new OllamaEnricher({ model: opts.model, baseUrl: opts.baseUrl });
392
+ if (await ollama.ping()) {
393
+ const chatModel = opts.model ?? (await pickOllamaChatModel(ollama));
394
+ if (chatModel) {
395
+ out.push(new OllamaEnricher({ model: chatModel, baseUrl: opts.baseUrl }));
396
+ }
397
+ }
398
+ // 2. Free-tier cloud providers (env-var detection)
399
+ for (const cfg of PROVIDERS) {
400
+ const key = process.env[cfg.envKey];
401
+ if (key) {
402
+ out.push(new OpenAIEnricher({
403
+ apiKey: key,
404
+ model: opts.model ?? cfg.defaultModel,
405
+ baseUrl: opts.baseUrl ?? cfg.baseUrl,
406
+ }));
407
+ }
408
+ }
409
+ return out;
410
+ }
411
+ /** Probe Ollama's installed models and pick the first viable chat model.
412
+ * Skips embedders (nomic-embed-*, bge-*, e5-*, minilm-*). */
413
+ async function pickOllamaChatModel(probe) {
414
+ try {
415
+ const res = await fetch(`${probe.baseUrl}/api/tags`, {
416
+ signal: AbortSignal.timeout(2000),
417
+ });
418
+ if (!res.ok)
419
+ return undefined;
420
+ const data = (await res.json());
421
+ const names = (data.models ?? []).map((m) => m.name);
422
+ // Filter out embedding-only models that would crash chat API
423
+ const chatModels = names.filter((n) => !/^(nomic-embed|bge-|e5-|all-minilm|paraphrase-|gte-|jina-)/i.test(n));
424
+ // Prefer modern small models in this order
425
+ const preferred = ["qwen2.5:3b", "gemma2:2b", "llama3.2:1b", "llama3.2:3b", "qwen2.5:7b"];
426
+ for (const want of preferred) {
427
+ const hit = chatModels.find((n) => n === want || n.startsWith(want.split(":")[0] + ":"));
428
+ if (hit)
429
+ return hit;
139
430
  }
431
+ return chatModels[0];
140
432
  }
141
- const apiKey = opts.apiKey ?? process.env["OPENAI_API_KEY"];
142
- if ((provider === "openai" || provider === "auto") && apiKey) {
143
- return new OpenAIEnricher({ apiKey, model: opts.model, baseUrl: opts.baseUrl });
433
+ catch {
434
+ return undefined;
144
435
  }
145
- throw new Error("No enricher available. Install Ollama (recommended) or set OPENAI_API_KEY.");
146
436
  }
147
437
  //# sourceMappingURL=enrich.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"enrich.js","sourceRoot":"","sources":["../src/enrich.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"enrich.js","sourceRoot":"","sources":["../src/enrich.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=enrich.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrich.test.d.ts","sourceRoot":"","sources":["../src/enrich.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Tests for ResilientEnricher's self-healing fallback chain.
3
+ *
4
+ * Strategy: mock providers that throw classified errors and verify:
5
+ * - chain order is honored
6
+ * - successful provider returns immediately
7
+ * - failures cool the provider down for the right duration
8
+ * - subsequent calls skip cooled-down providers
9
+ * - all-fail throws AllProvidersFailedError (so caller can degrade)
10
+ * - empty answers count as soft failures + try the next provider
11
+ */
12
+ import { describe, it, expect, vi } from "vitest";
13
+ import { ResilientEnricher, AllProvidersFailedError, classifyFailure, } from "./enrich.js";
14
+ function mockProvider(name, responses) {
15
+ let i = 0;
16
+ return {
17
+ name,
18
+ enrich: vi.fn().mockImplementation(async () => {
19
+ const r = responses[Math.min(i++, responses.length - 1)];
20
+ if (r instanceof Error)
21
+ throw r;
22
+ return { text: r, source: name };
23
+ }),
24
+ };
25
+ }
26
+ const INPUT = { system: "s", user: "u" };
27
+ describe("classifyFailure — error category detection", () => {
28
+ it("recognizes rate-limit phrases as rate-limit (long cooldown)", () => {
29
+ expect(classifyFailure(new Error("HTTP 429: too many requests"))).toBe("rate-limit");
30
+ expect(classifyFailure(new Error("daily quota exhausted"))).toBe("rate-limit");
31
+ });
32
+ it("recognizes 5xx as server (medium cooldown)", () => {
33
+ expect(classifyFailure(new Error("503 service unavailable"))).toBe("server");
34
+ expect(classifyFailure(new Error("Internal server error"))).toBe("server");
35
+ });
36
+ it("recognizes auth failures (long cooldown — needs user fix)", () => {
37
+ expect(classifyFailure(new Error("401 invalid API key"))).toBe("auth");
38
+ expect(classifyFailure(new Error("Forbidden"))).toBe("auth");
39
+ });
40
+ it("recognizes model-missing (skip until next env change)", () => {
41
+ expect(classifyFailure(new Error("model not found"))).toBe("model-missing");
42
+ expect(classifyFailure(new Error("no such model: qwen2.5"))).toBe("model-missing");
43
+ });
44
+ it("recognizes timeout / network errors", () => {
45
+ expect(classifyFailure(new Error("aborted"))).toBe("timeout");
46
+ expect(classifyFailure(new Error("ECONNREFUSED"))).toBe("network");
47
+ expect(classifyFailure(new Error("fetch failed"))).toBe("network");
48
+ });
49
+ });
50
+ describe("ResilientEnricher — fallback chain behavior", () => {
51
+ it("returns immediately when first provider succeeds", async () => {
52
+ const a = mockProvider("a", ["A answer"]);
53
+ const b = mockProvider("b", ["B answer"]);
54
+ const r = new ResilientEnricher([a, b]);
55
+ const out = await r.enrich(INPUT);
56
+ expect(out.text).toBe("A answer");
57
+ expect(b.enrich).not.toHaveBeenCalled();
58
+ });
59
+ it("falls back to next provider on hard failure", async () => {
60
+ const a = mockProvider("a", [new Error("503 unavailable")]);
61
+ const b = mockProvider("b", ["B answer"]);
62
+ const r = new ResilientEnricher([a, b]);
63
+ const out = await r.enrich(INPUT);
64
+ expect(out.text).toBe("B answer");
65
+ });
66
+ it("treats empty answer as soft failure → tries next provider", async () => {
67
+ const a = mockProvider("a", [" "]); // whitespace-only = empty
68
+ const b = mockProvider("b", ["B answer"]);
69
+ const r = new ResilientEnricher([a, b]);
70
+ const out = await r.enrich(INPUT);
71
+ expect(out.text).toBe("B answer");
72
+ });
73
+ it("throws AllProvidersFailedError when every provider fails", async () => {
74
+ const a = mockProvider("a", [new Error("503 unavailable")]);
75
+ const b = mockProvider("b", [new Error("ECONNREFUSED")]);
76
+ const r = new ResilientEnricher([a, b]);
77
+ await expect(r.enrich(INPUT)).rejects.toThrow(AllProvidersFailedError);
78
+ });
79
+ it("skips a provider while it's in cooldown (5xx → 60s default)", async () => {
80
+ // First call: a fails, b answers. a now in cooldown for 60s.
81
+ // Second call: a should be SKIPPED (still in cooldown), b answers again.
82
+ const a = mockProvider("a", [new Error("503"), "A would-recover"]);
83
+ const b = mockProvider("b", ["B1", "B2"]);
84
+ const r = new ResilientEnricher([a, b]);
85
+ const r1 = await r.enrich(INPUT);
86
+ expect(r1.text).toBe("B1");
87
+ expect(a.enrich).toHaveBeenCalledTimes(1);
88
+ const r2 = await r.enrich(INPUT);
89
+ expect(r2.text).toBe("B2");
90
+ // Critically, a should NOT have been retried — it's in cooldown
91
+ expect(a.enrich).toHaveBeenCalledTimes(1);
92
+ });
93
+ it("emits onSwitch event with reason when falling back", async () => {
94
+ const a = mockProvider("a", [new Error("aborted (timeout)")]);
95
+ const b = mockProvider("b", ["B answer"]);
96
+ const events = [];
97
+ const r = new ResilientEnricher([a, b], (ev) => events.push(ev));
98
+ await r.enrich(INPUT);
99
+ expect(events).toHaveLength(1);
100
+ expect(events[0].from).toBe("a");
101
+ expect(events[0].to).toBe("b");
102
+ expect(events[0].kind).toBe("timeout");
103
+ });
104
+ it("rate-limit failure cools down longer than server failure", async () => {
105
+ const aRate = mockProvider("aRate", [new Error("429 rate limit")]);
106
+ const aServer = mockProvider("aServer", [new Error("503")]);
107
+ const b = mockProvider("b", ["B"]);
108
+ const r1 = new ResilientEnricher([aRate, b]);
109
+ const r2 = new ResilientEnricher([aServer, b]);
110
+ await r1.enrich(INPUT);
111
+ await r2.enrich(INPUT);
112
+ const h1 = r1.inspectHealth().aRate?.cooldownUntil ?? 0;
113
+ const h2 = r2.inspectHealth().aServer?.cooldownUntil ?? 0;
114
+ expect(h1).toBeGreaterThan(h2); // rate-limit cooldown > server cooldown
115
+ });
116
+ it("constructor rejects empty chain (you must give SOMETHING)", () => {
117
+ expect(() => new ResilientEnricher([])).toThrow();
118
+ });
119
+ });
120
+ //# sourceMappingURL=enrich.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enrich.test.js","sourceRoot":"","sources":["../src/enrich.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mneme-ai/embeddings",
3
- "version": "0.21.1",
3
+ "version": "0.22.1",
4
4
  "description": "Embedding providers (OpenAI, Ollama, bundled-WASM, hash-fallback) for Mneme",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,7 +30,7 @@
30
30
  "clean": "tsc -b --clean"
31
31
  },
32
32
  "dependencies": {
33
- "@mneme-ai/core": "0.21.1",
33
+ "@mneme-ai/core": "0.22.1",
34
34
  "@xenova/transformers": "^2.17.2"
35
35
  }
36
36
  }