claude-memory-layer 1.0.28 → 1.0.30

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-memory-layer",
3
- "version": "1.0.28",
3
+ "version": "1.0.30",
4
4
  "description": "Claude Code plugin that learns from conversations to provide personalized assistance",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -23,7 +23,8 @@
23
23
  "ops:health": "npm run ops:sync-gap:report && npm run ops:sync-gap:heal && npm run ops:review:resolve",
24
24
  "ops:projects:clean-unknown": "node scripts/delete-unknown-projects.js",
25
25
  "benchmark:replay": "tsx scripts/replay-retrieval-benchmark.ts",
26
- "benchmark:qrels": "tsx scripts/generate-session-qrels.ts"
26
+ "benchmark:qrels": "tsx scripts/generate-session-qrels.ts",
27
+ "postinstall": "node scripts/postinstall-embedding-backend.cjs"
27
28
  },
28
29
  "keywords": [
29
30
  "claude-code",
@@ -40,7 +41,6 @@
40
41
  },
41
42
  "dependencies": {
42
43
  "@hono/node-server": "^1.13.0",
43
- "@huggingface/transformers": "^3.8.1",
44
44
  "@lancedb/lancedb": "^0.5.0",
45
45
  "@modelcontextprotocol/sdk": "^1.29.0",
46
46
  "better-sqlite3": "^12.6.2",
@@ -49,6 +49,9 @@
49
49
  "mongodb": "^6.14.0",
50
50
  "zod": "^3.22.0"
51
51
  },
52
+ "optionalDependencies": {
53
+ "@huggingface/transformers": "^3.8.1"
54
+ },
52
55
  "devDependencies": {
53
56
  "@types/better-sqlite3": "^7.6.13",
54
57
  "@types/node": "^20.11.0",
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const { execFileSync, spawnSync } = require('node:child_process');
5
+ const path = require('node:path');
6
+ const { createRequire } = require('node:module');
7
+
8
+ const EMBEDDING_BACKEND_PACKAGE_NAME = '@huggingface/transformers';
9
+ const EMBEDDING_BACKEND_VERSION = '3.8.1';
10
+ const EMBEDDING_BACKEND_PACKAGE = `${EMBEDDING_BACKEND_PACKAGE_NAME}@${EMBEDDING_BACKEND_VERSION}`;
11
+ const REPAIR_GUARD_ENV = 'CLAUDE_MEMORY_LAYER_EMBEDDING_POSTINSTALL_REPAIR';
12
+ const SKIP_ENV = 'CLAUDE_MEMORY_LAYER_SKIP_EMBEDDING_POSTINSTALL';
13
+
14
+ function parseCudaMajor(output) {
15
+ const releaseMatch = String(output).match(/release\s+(\d+)(?:\.\d+)?/i);
16
+ if (releaseMatch) return Number(releaseMatch[1]);
17
+
18
+ const versionMatch = String(output).match(/\bV(\d+)\.\d+/i);
19
+ if (versionMatch) return Number(versionMatch[1]);
20
+
21
+ return null;
22
+ }
23
+
24
+ function parseCudaMajorFromEnv(env = process.env) {
25
+ const value = env.ONNXRUNTIME_NODE_INSTALL_CUDA || env.npm_config_onnxruntime_node_install_cuda;
26
+ if (!value) return null;
27
+ if (value === 'v11' || value === '11') return 11;
28
+ if (value === 'v12' || value === '12') return 12;
29
+ return null;
30
+ }
31
+
32
+ function detectCudaMajor({ env = process.env, execFileSyncImpl = execFileSync } = {}) {
33
+ const envMajor = parseCudaMajorFromEnv(env);
34
+ if (envMajor) return envMajor;
35
+
36
+ try {
37
+ return parseCudaMajor(execFileSyncImpl('nvcc', ['--version'], {
38
+ encoding: 'utf8',
39
+ stdio: ['ignore', 'pipe', 'ignore']
40
+ }));
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+
46
+ function isSkipRequested(env = process.env) {
47
+ if (env[SKIP_ENV] === '1' || env[REPAIR_GUARD_ENV] === '1') return true;
48
+ if (env.npm_config_optional === 'false') return true;
49
+ if (String(env.npm_config_omit || '').split(',').map((item) => item.trim()).includes('optional')) return true;
50
+ return false;
51
+ }
52
+
53
+ function isEmbeddingBackendAvailable(rootDir = process.cwd()) {
54
+ try {
55
+ const requireFromRoot = createRequire(path.join(rootDir, 'package.json'));
56
+ requireFromRoot.resolve(EMBEDDING_BACKEND_PACKAGE_NAME);
57
+ return true;
58
+ } catch {
59
+ return false;
60
+ }
61
+ }
62
+
63
+ function shouldAttemptAutoInstall({ platform, arch, transformersAvailable, skipRequested }) {
64
+ return platform === 'linux' &&
65
+ arch === 'x64' &&
66
+ !transformersAvailable &&
67
+ !skipRequested;
68
+ }
69
+
70
+ function createRepairEnv(env = process.env) {
71
+ return {
72
+ ...env,
73
+ ONNXRUNTIME_NODE_INSTALL_CUDA: 'skip',
74
+ [REPAIR_GUARD_ENV]: '1'
75
+ };
76
+ }
77
+
78
+ function createNpmInstallArgs() {
79
+ return [
80
+ 'install',
81
+ '--no-save',
82
+ '--no-package-lock',
83
+ '--omit=dev',
84
+ EMBEDDING_BACKEND_PACKAGE
85
+ ];
86
+ }
87
+
88
+ function runPostinstall({
89
+ rootDir = process.cwd(),
90
+ env = process.env,
91
+ platform = process.platform,
92
+ arch = process.arch,
93
+ execFileSyncImpl = execFileSync,
94
+ spawnSyncImpl = spawnSync,
95
+ log = console.log,
96
+ warn = console.warn
97
+ } = {}) {
98
+ const transformersAvailable = isEmbeddingBackendAvailable(rootDir);
99
+ const skipRequested = isSkipRequested(env);
100
+ const cudaMajor = detectCudaMajor({ env, execFileSyncImpl });
101
+
102
+ if (!shouldAttemptAutoInstall({ platform, arch, cudaMajor, transformersAvailable, skipRequested })) {
103
+ return { attempted: false, cudaMajor, transformersAvailable, skipRequested };
104
+ }
105
+
106
+ log('[claude-memory-layer] Optional embedding backend is missing on Linux x64. Installing CPU-only embedding backend...');
107
+
108
+ const npmCommand = platform === 'win32' ? 'npm.cmd' : 'npm';
109
+ const result = spawnSyncImpl(npmCommand, createNpmInstallArgs(), {
110
+ cwd: rootDir,
111
+ env: createRepairEnv(env),
112
+ stdio: 'inherit'
113
+ });
114
+
115
+ if (result.error || result.status !== 0) {
116
+ warn('[claude-memory-layer] Optional embedding backend repair failed. Claude Memory Layer is installed, but semantic/vector embeddings may be unavailable until you run:');
117
+ warn(` ONNXRUNTIME_NODE_INSTALL_CUDA=skip npm install -g claude-memory-layer@latest`);
118
+ if (result.error) warn(` ${result.error.message}`);
119
+ return { attempted: true, success: false, cudaMajor, transformersAvailable, skipRequested };
120
+ }
121
+
122
+ log('[claude-memory-layer] Optional embedding backend installed with CPU-only ONNX Runtime.');
123
+ return { attempted: true, success: true, cudaMajor, transformersAvailable, skipRequested };
124
+ }
125
+
126
+ if (require.main === module) {
127
+ runPostinstall();
128
+ }
129
+
130
+ module.exports = {
131
+ EMBEDDING_BACKEND_PACKAGE,
132
+ parseCudaMajor,
133
+ parseCudaMajorFromEnv,
134
+ detectCudaMajor,
135
+ isSkipRequested,
136
+ isEmbeddingBackendAvailable,
137
+ shouldAttemptAutoInstall,
138
+ createRepairEnv,
139
+ createNpmInstallArgs,
140
+ runPostinstall
141
+ };
@@ -59,6 +59,10 @@ import {
59
59
  renderExternalMarketContextReport,
60
60
  type ExternalMarketProvider
61
61
  } from '../../core/external-market-context.js';
62
+ import {
63
+ DEFAULT_EMBEDDING_FALLBACK_MODEL,
64
+ DEFAULT_EMBEDDING_MODEL
65
+ } from '../../extensions/vector/embedder.js';
62
66
 
63
67
  // ============================================================
64
68
  // Hook Installation Utilities
@@ -1025,7 +1029,7 @@ program
1025
1029
  .option('-l, --limit <number>', 'Limit messages per session')
1026
1030
  .option('--session-limit <number>', 'Limit recent matching sessions to import')
1027
1031
  .option('-f, --force', 'Force reimport: delete existing events and reimport with turn_id grouping')
1028
- .option('--embedding-model <name>', 'Embedding model override (default: jinaai/jina-embeddings-v5-text-nano-text-matching, or env CLAUDE_MEMORY_EMBEDDING_MODEL; fallback env: CLAUDE_MEMORY_EMBEDDING_FALLBACK_MODEL)')
1032
+ .option('--embedding-model <name>', `Embedding model override (default: ${DEFAULT_EMBEDDING_MODEL}, or env CLAUDE_MEMORY_EMBEDDING_MODEL; fallback: ${DEFAULT_EMBEDDING_FALLBACK_MODEL} or env CLAUDE_MEMORY_EMBEDDING_FALLBACK_MODEL)`)
1029
1033
  .option('-v, --verbose', 'Show detailed progress')
1030
1034
  .action(async (options) => {
1031
1035
  const startTime = Date.now();
package/src/core/types.ts CHANGED
@@ -152,8 +152,8 @@ export const ConfigSchema = z.object({
152
152
  }).default({}),
153
153
  embedding: z.object({
154
154
  provider: z.enum(['local', 'openai']).default('local'),
155
- model: z.string().default('jinaai/jina-embeddings-v5-text-nano-text-matching'),
156
- openaiModel: z.string().default('jinaai/jina-embeddings-v5-text-nano-text-matching'),
155
+ model: z.string().default('Xenova/multilingual-e5-small'),
156
+ openaiModel: z.string().default('Xenova/multilingual-e5-small'),
157
157
  batchSize: z.number().default(32)
158
158
  }).default({}),
159
159
  retrieval: z.object({
@@ -14,13 +14,16 @@ type FeatureExtractionPipelineFactory = (
14
14
  model: string
15
15
  ) => Promise<NonNullable<Embedder['pipeline']>>;
16
16
 
17
+ export const DEFAULT_EMBEDDING_MODEL = 'Xenova/multilingual-e5-small';
18
+ export const DEFAULT_EMBEDDING_FALLBACK_MODEL = 'intfloat/multilingual-e5-small';
19
+
17
20
  export class Embedder {
18
21
  private pipeline: ((input: string, options?: Record<string, unknown>) => Promise<{ data: Float32Array }>) | null = null;
19
22
  private readonly modelName: string;
20
23
  private activeModelName: string;
21
24
  private initialized = false;
22
25
 
23
- constructor(modelName: string = 'jinaai/jina-embeddings-v5-text-nano-text-matching') {
26
+ constructor(modelName: string = DEFAULT_EMBEDDING_MODEL) {
24
27
  this.modelName = modelName;
25
28
  this.activeModelName = modelName;
26
29
  }
@@ -31,7 +34,16 @@ export class Embedder {
31
34
  async initialize(): Promise<void> {
32
35
  if (this.initialized) return;
33
36
 
34
- const pipeline = await withSuppressedKnownTransformersWarnings(() => loadTransformersPipeline());
37
+ const pipeline = await withSuppressedKnownTransformersWarnings(async () => {
38
+ try {
39
+ return await loadTransformersPipeline();
40
+ } catch (error) {
41
+ if (isMissingTransformersDependencyError(error)) {
42
+ throw createEmbeddingBackendUnavailableError(error);
43
+ }
44
+ throw error;
45
+ }
46
+ });
35
47
 
36
48
  try {
37
49
  this.pipeline = await withSuppressedKnownTransformersWarnings(() => pipeline('feature-extraction', this.modelName));
@@ -39,7 +51,7 @@ export class Embedder {
39
51
  this.initialized = true;
40
52
  return;
41
53
  } catch (primaryError) {
42
- const fallbackModel = process.env.CLAUDE_MEMORY_EMBEDDING_FALLBACK_MODEL || 'onnx-community/embeddinggemma-300m-ONNX';
54
+ const fallbackModel = process.env.CLAUDE_MEMORY_EMBEDDING_FALLBACK_MODEL || DEFAULT_EMBEDDING_FALLBACK_MODEL;
43
55
  if (fallbackModel === this.modelName) {
44
56
  throw primaryError;
45
57
  }
@@ -186,6 +198,30 @@ export function isKnownBenignTransformersWarning(message: string): boolean {
186
198
  message.includes('dtype not specified for "model"');
187
199
  }
188
200
 
201
+ export function isMissingTransformersDependencyError(error: unknown): boolean {
202
+ const maybeError = error as { code?: unknown; message?: unknown } | null;
203
+ const message = typeof maybeError?.message === 'string' ? maybeError.message : '';
204
+ return maybeError?.code === 'ERR_MODULE_NOT_FOUND' &&
205
+ message.includes("@huggingface/transformers");
206
+ }
207
+
208
+ export function createEmbeddingBackendUnavailableError(cause: unknown): Error & { cause?: unknown } {
209
+ const error = new Error(
210
+ [
211
+ 'Optional embedding backend is not installed.',
212
+ '',
213
+ 'Claude Memory Layer can run embeddings on CPU-only ONNX Runtime; CUDA is not required.',
214
+ 'Reinstall globally with:',
215
+ ' ONNXRUNTIME_NODE_INSTALL_CUDA=skip npm install -g claude-memory-layer@latest',
216
+ '',
217
+ 'If you are inside a local checkout or package directory, repair only the backend with:',
218
+ ' ONNXRUNTIME_NODE_INSTALL_CUDA=skip npm install --no-save --no-package-lock --omit=dev @huggingface/transformers@3.8.1'
219
+ ].join('\n')
220
+ ) as Error & { cause?: unknown };
221
+ error.cause = cause;
222
+ return error;
223
+ }
224
+
189
225
  async function loadTransformersPipeline(): Promise<FeatureExtractionPipelineFactory> {
190
226
  // Keep @huggingface/transformers lazy so importing MemoryService or pure
191
227
  // adapter helpers does not eagerly dlopen onnxruntime native bindings.
@@ -0,0 +1,175 @@
1
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { createRequire } from 'node:module';
5
+
6
+ import { describe, expect, it } from 'vitest';
7
+
8
+ const require = createRequire(import.meta.url);
9
+
10
+ type SpawnCall = {
11
+ cmd: string;
12
+ args: string[];
13
+ env: NodeJS.ProcessEnv;
14
+ };
15
+
16
+ type PostinstallEmbeddingBackend = {
17
+ EMBEDDING_BACKEND_PACKAGE: string;
18
+ parseCudaMajor(output: string): number | null;
19
+ shouldAttemptAutoInstall(input: {
20
+ platform: NodeJS.Platform;
21
+ arch: string;
22
+ cudaMajor: number | null;
23
+ transformersAvailable: boolean;
24
+ skipRequested: boolean;
25
+ }): boolean;
26
+ createRepairEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
27
+ createNpmInstallArgs(): string[];
28
+ runPostinstall(input?: {
29
+ rootDir?: string;
30
+ env?: NodeJS.ProcessEnv;
31
+ platform?: NodeJS.Platform;
32
+ arch?: string;
33
+ execFileSyncImpl?: () => string;
34
+ spawnSyncImpl?: (cmd: string, args: string[], options: { env: NodeJS.ProcessEnv }) => { status: number };
35
+ log?: () => void;
36
+ warn?: () => void;
37
+ }): { attempted: boolean; success?: boolean; cudaMajor: number | null; transformersAvailable: boolean; skipRequested: boolean };
38
+ };
39
+
40
+ function loadPostinstallModule(): PostinstallEmbeddingBackend {
41
+ return require('../../scripts/postinstall-embedding-backend.cjs') as PostinstallEmbeddingBackend;
42
+ }
43
+
44
+ describe('embedding backend postinstall repair', () => {
45
+ it('keeps the install-time embedding backend optional and registers postinstall repair', () => {
46
+ const pkg = JSON.parse(readFileSync('package.json', 'utf-8')) as {
47
+ scripts: Record<string, string>;
48
+ dependencies?: Record<string, string>;
49
+ optionalDependencies?: Record<string, string>;
50
+ };
51
+
52
+ expect(pkg.dependencies).not.toHaveProperty('@huggingface/transformers');
53
+ expect(pkg.optionalDependencies).toMatchObject({
54
+ '@huggingface/transformers': '^3.8.1'
55
+ });
56
+ expect(pkg.scripts.postinstall).toBe('node scripts/postinstall-embedding-backend.cjs');
57
+ });
58
+
59
+ it('detects CUDA major version from nvcc output', () => {
60
+ const postinstall = loadPostinstallModule();
61
+
62
+ expect(postinstall.parseCudaMajor('Cuda compilation tools, release 11.8, V11.8.89')).toBe(11);
63
+ expect(postinstall.parseCudaMajor('Cuda compilation tools, release 12.4, V12.4.131')).toBe(12);
64
+ expect(postinstall.parseCudaMajor('nvcc: NVIDIA (R) Cuda compiler driver')).toBeNull();
65
+ });
66
+
67
+ it('auto-installs a missing embedding backend for Linux x64 even when CUDA cannot be detected', () => {
68
+ const postinstall = loadPostinstallModule();
69
+
70
+ expect(postinstall.shouldAttemptAutoInstall({
71
+ platform: 'linux',
72
+ arch: 'x64',
73
+ cudaMajor: 11,
74
+ transformersAvailable: false,
75
+ skipRequested: false
76
+ })).toBe(true);
77
+
78
+ expect(postinstall.shouldAttemptAutoInstall({
79
+ platform: 'linux',
80
+ arch: 'x64',
81
+ cudaMajor: null,
82
+ transformersAvailable: false,
83
+ skipRequested: false
84
+ })).toBe(true);
85
+
86
+ expect(postinstall.shouldAttemptAutoInstall({
87
+ platform: 'linux',
88
+ arch: 'x64',
89
+ cudaMajor: 12,
90
+ transformersAvailable: false,
91
+ skipRequested: false
92
+ })).toBe(true);
93
+
94
+ expect(postinstall.shouldAttemptAutoInstall({
95
+ platform: 'linux',
96
+ arch: 'x64',
97
+ cudaMajor: null,
98
+ transformersAvailable: true,
99
+ skipRequested: false
100
+ })).toBe(false);
101
+
102
+ expect(postinstall.shouldAttemptAutoInstall({
103
+ platform: 'linux',
104
+ arch: 'arm64',
105
+ cudaMajor: null,
106
+ transformersAvailable: false,
107
+ skipRequested: false
108
+ })).toBe(false);
109
+
110
+ expect(postinstall.shouldAttemptAutoInstall({
111
+ platform: 'darwin',
112
+ arch: 'x64',
113
+ cudaMajor: null,
114
+ transformersAvailable: false,
115
+ skipRequested: false
116
+ })).toBe(false);
117
+
118
+ expect(postinstall.shouldAttemptAutoInstall({
119
+ platform: 'linux',
120
+ arch: 'x64',
121
+ cudaMajor: null,
122
+ transformersAvailable: false,
123
+ skipRequested: true
124
+ })).toBe(false);
125
+ });
126
+
127
+ it('repairs missing transformers with CPU-only onnxruntime install settings', () => {
128
+ const postinstall = loadPostinstallModule();
129
+
130
+ expect(postinstall.createRepairEnv({})).toMatchObject({
131
+ ONNXRUNTIME_NODE_INSTALL_CUDA: 'skip',
132
+ CLAUDE_MEMORY_LAYER_EMBEDDING_POSTINSTALL_REPAIR: '1'
133
+ });
134
+ expect(postinstall.createNpmInstallArgs()).toEqual([
135
+ 'install',
136
+ '--no-save',
137
+ '--no-package-lock',
138
+ '--omit=dev',
139
+ postinstall.EMBEDDING_BACKEND_PACKAGE
140
+ ]);
141
+ });
142
+
143
+ it('runs the automatic repair command when Linux x64 skipped the optional backend without detectable CUDA', () => {
144
+ const postinstall = loadPostinstallModule();
145
+ const rootDir = mkdtempSync(join(tmpdir(), 'cml-postinstall-test-'));
146
+ const calls: SpawnCall[] = [];
147
+
148
+ try {
149
+ writeFileSync(join(rootDir, 'package.json'), JSON.stringify({ name: 'claude-memory-layer-install-root' }));
150
+
151
+ const result = postinstall.runPostinstall({
152
+ rootDir,
153
+ env: {},
154
+ platform: 'linux',
155
+ arch: 'x64',
156
+ execFileSyncImpl: () => '',
157
+ spawnSyncImpl: (cmd, args, options) => {
158
+ calls.push({ cmd, args, env: options.env });
159
+ return { status: 0 };
160
+ },
161
+ log: () => undefined,
162
+ warn: () => undefined
163
+ });
164
+
165
+ expect(result).toMatchObject({ attempted: true, success: true, cudaMajor: null, transformersAvailable: false });
166
+ expect(calls).toHaveLength(1);
167
+ expect(calls[0]?.cmd).toBe('npm');
168
+ expect(calls[0]?.args).toEqual(postinstall.createNpmInstallArgs());
169
+ expect(calls[0]?.env.ONNXRUNTIME_NODE_INSTALL_CUDA).toBe('skip');
170
+ expect(calls[0]?.env.CLAUDE_MEMORY_LAYER_EMBEDDING_POSTINSTALL_REPAIR).toBe('1');
171
+ } finally {
172
+ rmSync(rootDir, { recursive: true, force: true });
173
+ }
174
+ });
175
+ });
@@ -1,11 +1,41 @@
1
1
  import { describe, expect, it, vi } from 'vitest';
2
2
 
3
3
  import {
4
+ DEFAULT_EMBEDDING_MODEL,
5
+ Embedder,
6
+ createEmbeddingBackendUnavailableError,
4
7
  isKnownBenignTransformersWarning,
8
+ isMissingTransformersDependencyError,
5
9
  withSuppressedKnownTransformersWarnings
6
10
  } from '../../src/extensions/vector/embedder.js';
11
+ import { ConfigSchema } from '../../src/core/types.js';
7
12
 
8
13
  describe('Embedder warning suppression', () => {
14
+ it('uses a CPU-friendly multilingual Korean-capable default embedding model', () => {
15
+ expect(DEFAULT_EMBEDDING_MODEL).toBe('Xenova/multilingual-e5-small');
16
+ expect(new Embedder().getModelName()).toBe(DEFAULT_EMBEDDING_MODEL);
17
+
18
+ const parsedConfig = ConfigSchema.parse({});
19
+ expect(parsedConfig.embedding.model).toBe(DEFAULT_EMBEDDING_MODEL);
20
+ expect(parsedConfig.embedding.openaiModel).toBe(DEFAULT_EMBEDDING_MODEL);
21
+ });
22
+
23
+ it('turns missing optional @huggingface/transformers errors into actionable install guidance', () => {
24
+ const missingBackendError = Object.assign(
25
+ new Error("Cannot find package '@huggingface/transformers' imported from /tmp/dist/cli/index.js"),
26
+ { code: 'ERR_MODULE_NOT_FOUND' }
27
+ );
28
+
29
+ expect(isMissingTransformersDependencyError(missingBackendError)).toBe(true);
30
+ expect(isMissingTransformersDependencyError(new Error('network failure'))).toBe(false);
31
+
32
+ const friendly = createEmbeddingBackendUnavailableError(missingBackendError);
33
+ expect(friendly.message).toContain('Optional embedding backend is not installed');
34
+ expect(friendly.message).toContain('ONNXRUNTIME_NODE_INSTALL_CUDA=skip npm install -g claude-memory-layer@latest');
35
+ expect(friendly.message).toContain('ONNXRUNTIME_NODE_INSTALL_CUDA=skip npm install --no-save --no-package-lock --omit=dev @huggingface/transformers@3.8.1');
36
+ expect(friendly.cause).toBe(missingBackendError);
37
+ });
38
+
9
39
  it('recognizes known benign transformer warnings', () => {
10
40
  expect(isKnownBenignTransformersWarning('Unknown model class "eurobert", attempting to construct from base class.')).toBe(true);
11
41
  expect(isKnownBenignTransformersWarning('dtype not specified for "model". Using the default dtype (fp32).')).toBe(true);