Skip to content

chore(deps): migrate @xenova/transformers to @huggingface/transformers v4#1096

Open
aqeelat wants to merge 1 commit into
rohitg00:mainfrom
aqeelat:chore/migrate-xenova-to-hf-transformers
Open

chore(deps): migrate @xenova/transformers to @huggingface/transformers v4#1096
aqeelat wants to merge 1 commit into
rohitg00:mainfrom
aqeelat:chore/migrate-xenova-to-hf-transformers

Conversation

@aqeelat

@aqeelat aqeelat commented Jul 21, 2026

Copy link
Copy Markdown

Summary

@xenova/transformers@2.17.2 is deprecated and silently broken on Node 22+ (see #479). This swaps to @huggingface/transformers@^4.2.0 — the same project, renamed, with an actively maintained ONNX runtime backend and Node 22/24 support. Drop-in for our usage: pipeline, RawImage.fromBlob, tolist, and text-classification output shape are all unchanged.

Closes #1095. Fixes #479.

Changes

  • package.json: replace @xenova/transformers + direct onnxruntime-{node,web} optional deps with a single @huggingface/transformers@^4.2.0. The onnxruntime packages are now bundled as HF v4's hard deps; sharp, @huggingface/jinja, and @huggingface/tokenizers come along transitively.
  • src/xenova.d.tssrc/huggingface.d.ts: rename ambient module decl and add RawImage export so the cast in clip.ts is no longer needed.
  • src/providers/embedding/{local,clip}.ts, src/state/reranker.ts: swap import specifier + install error strings. Drop the as unknown as TransformersModule cast in clip.ts.
  • tsdown.config.ts: update neverBundle list.
  • test/reranker.test.ts: swap vi.mock specifier.
  • 16 docs: install commands + prose mentions across README.md, 11 READMEs/ translations, SECURITY.md, 2 benchmark docs, and the benchmark script. CHANGELOG.md historical entry left as-is.

Model IDs (Xenova/all-MiniLM-L6-v2, Xenova/clip-vit-base-patch32, Xenova/ms-marco-MiniLM-L-6-v2) deliberately kept — HF Hub repo names, still valid under v3/v4.

Verification

  • npm install — clean (273 packages added; transitive onnxruntime-node@1.24.3, sharp@0.34.5, @huggingface/jinja, @huggingface/tokenizers)
  • npm test1415/1415 passing
  • npm run build — clean
  • Runtime smoke: @huggingface/transformers@4.2.0 loads, exposes pipeline / RawImage.fromBlob / env.cacheDir
  • Pre-existing tsc --noEmit errors are baseline (cli.ts, slots.ts, api.ts) — none touch migrated files

License check

Package License
@huggingface/transformers 4.2.0 (new) Apache-2.0
@xenova/transformers 2.17.2 (removed) Apache-2.0
onnxruntime-node 1.14.0 → 1.24.3 MIT
onnxruntime-web 1.14.0 → 1.26.0-dev MIT
sharp 0.34.5 (new transitive) Apache-2.0
@huggingface/jinja (new transitive) MIT
@huggingface/tokenizers (new transitive) Apache-2.0

All permissive, all compatible with this repo's Apache-2.0. No NOTICE files required.

Follow-ups (deliberately out of scope)

Relates

Summary by CodeRabbit

  • Documentation
    • Updated local embedding setup, embedding-provider instructions, benchmarks, and security guidance across supported languages to use @huggingface/transformers.
    • Changed the recommended default local embedding model to Xenova/all-MiniLM-L6-v2.
  • Enhancements
    • Switched local embeddings, CLIP/image embeddings, and reranking to @huggingface/transformers for improved compatibility.
    • Updated pipeline configuration to match current Transformers behavior.
  • Tests
    • Updated reranker and embedding-provider tests to mock @huggingface/transformers and added coverage for successful pipeline usage.

@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

@aqeelat is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR migrates embedding and reranking integrations from @xenova/transformers to @huggingface/transformers, updates optional dependency and build configuration, adds provider and reranker tests, and synchronizes README and benchmark guidance.

Changes

Transformers package migration

Layer / File(s) Summary
Runtime dependency and type wiring
package.json, src/providers/embedding/local.ts, src/providers/embedding/clip.ts
Optional dependencies, dynamic imports, installation errors, CLIP typings, image handling, dtype options, and embedding conversions now target @huggingface/transformers.
Reranker pipeline integration
src/state/reranker.ts
Reranking loads the Hugging Face pipeline with the q8 dtype option.
Build configuration and provider validation
tsdown.config.ts, test/clip-embedding-provider.test.ts, test/local-embedding-provider.test.ts, test/reranker.test.ts
Build exclusions and unavailable/loaded pipeline tests cover the migrated embedding and reranking integrations.
Documentation and benchmark guidance
README.md, READMEs/README.*.md, SECURITY.md, benchmark/*
Installation commands, local model guidance, security examples, and benchmark messages now reference @huggingface/transformers.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: rohitg00

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly states the dependency migration and matches the main change set.
Linked Issues check ✅ Passed The PR implements the requested migration to @huggingface/transformers and updates tests, docs, and runtime wiring for the cited Node.js 22+ fix.
Out of Scope Changes check ✅ Passed All changes appear tied to the transformers migration; no unrelated feature or behavioral scope is introduced.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
package.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/huggingface.d.ts (1)

1-6: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid broad any/unknown declarations for the optional package.

@huggingface/transformers 4.2.0 ships TypeScript declarations, including a typed RawImage.fromBlob(): Promise<RawImage>. This ambient shim widens the APIs to any and unknown, allowing invalid pipeline options and image handling to compile. Keep only a narrow fallback interface if omitted optional dependencies must still type-check. (npmjs.com)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/huggingface.d.ts` around lines 1 - 6, Update the ambient module
declaration for `@huggingface/transformers` to avoid broad any and unknown types,
relying on the package’s shipped declarations when available and retaining only
a narrow fallback interface if needed for absent optional dependencies. Preserve
typed pipeline options and make RawImage.fromBlob return the declared RawImage
type.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Line 1267: Update the README description for EMBEDDING_PROVIDER=local to
identify Xenova/all-MiniLM-L6-v2 as the default on-device model instead of
BGE-small, keeping the existing local-embedding behavior and configuration
guidance unchanged.

In `@test/reranker.test.ts`:
- Around line 3-10: Add a second reranker test case with a successful mock of
the `@huggingface/transformers` pipeline, alongside the existing
unavailable-module test. Exercise rerank and assert the mocked pipeline is
invoked or produces a changed ranking, so the test verifies the intended module
is loaded and used.

---

Nitpick comments:
In `@src/huggingface.d.ts`:
- Around line 1-6: Update the ambient module declaration for
`@huggingface/transformers` to avoid broad any and unknown types, relying on the
package’s shipped declarations when available and retaining only a narrow
fallback interface if needed for absent optional dependencies. Preserve typed
pipeline options and make RawImage.fromBlob return the declared RawImage type.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 15cb4830-5d34-4022-87d3-edd1a031e265

📥 Commits

Reviewing files that changed from the base of the PR and between a8e7d19 and ee991ca.

📒 Files selected for processing (24)
  • README.md
  • READMEs/README.de-DE.md
  • READMEs/README.es-ES.md
  • READMEs/README.fr-FR.md
  • READMEs/README.hi-IN.md
  • READMEs/README.ja-JP.md
  • READMEs/README.ko-KR.md
  • READMEs/README.pt-BR.md
  • READMEs/README.ru-RU.md
  • READMEs/README.tr-TR.md
  • READMEs/README.zh-CN.md
  • READMEs/README.zh-TW.md
  • SECURITY.md
  • benchmark/LONGMEMEVAL.md
  • benchmark/REAL-EMBEDDINGS.md
  • benchmark/real-embeddings-eval.ts
  • package.json
  • src/huggingface.d.ts
  • src/providers/embedding/clip.ts
  • src/providers/embedding/local.ts
  • src/state/reranker.ts
  • src/xenova.d.ts
  • test/reranker.test.ts
  • tsdown.config.ts
💤 Files with no reviewable changes (1)
  • src/xenova.d.ts

Comment thread README.md Outdated
Comment thread test/reranker.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/reranker.test.ts`:
- Around line 106-107: Make the mock cleanup around the reranker tests
exception-safe by moving vi.doUnmock("`@huggingface/transformers`") into an
afterEach hook or a try/finally block. Keep vi.resetModules() as module-cache
cleanup, and ensure the unmock always runs even when a test assertion fails.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 056f358f-378b-4d83-b869-d6f9298d82ea

📥 Commits

Reviewing files that changed from the base of the PR and between ee991ca and b58a76d.

📒 Files selected for processing (4)
  • README.md
  • src/providers/embedding/clip.ts
  • src/state/reranker.ts
  • test/reranker.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/state/reranker.ts
  • src/providers/embedding/clip.ts

Comment thread test/reranker.test.ts Outdated
Comment on lines +106 to +107
vi.doUnmock("@huggingface/transformers");
vi.resetModules();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the test file and inspect the relevant section with line numbers.
git ls-files 'test/reranker.test.ts'
wc -l test/reranker.test.ts
sed -n '1,220p' test/reranker.test.ts

Repository: rohitg00/agentmemory

Length of output: 1926


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the surrounding test structure and any cleanup hooks.
sed -n '1,220p' test/reranker.test.ts | nl -ba | sed -n '1,220p'

Repository: rohitg00/agentmemory

Length of output: 1926


🌐 Web query:

Vitest vi.resetModules does not clear mock registry vi.doUnmock cleanup afterEach finally

💡 Result:

In Vitest, vi.resetModules is designed specifically to clear the module cache, not the mock registry [1][2][3]. By design, these two systems operate independently, and calling vi.resetModules will not remove mocks or reset their state [4][5]. If you are using vi.doMock and require the mock to be cleared or the module to be unmocked between tests, you must use vi.unmock or vi.doUnmock explicitly [1][3]. However, note that if a module is implicitly mocked (e.g., mocked without an explicit factory), there have been historical limitations where vi.unmock/vi.doUnmock might not behave as expected depending on the specific Vitest version [6]. To manage mock state between tests, use the following APIs depending on your goal: 1. To clear mock call history (but keep implementation): Use vi.clearAllMocks [5][7]. 2. To clear call history and reset implementation: Use vi.resetAllMocks [5][7]. 3. To restore original implementations: Use vi.restoreAllMocks [7]. For a clean state between tests, it is common practice to use these in an afterEach hook [8][7], or enable them globally in your configuration (e.g., clearMocks: true, resetMocks: true, or restoreMocks: true) [7]. If you are struggling with module-level state persistence across tests, combining vi.resetModules with vi.doMock and dynamic imports inside your tests is often the required pattern, as vi.mock is hoisted to the top of the file and cannot be dynamically toggled [1][9].

Citations:


Make mock cleanup exception-safe. Move the vi.doUnmock("@huggingface/transformers") cleanup into afterEach or try/finally; vi.resetModules() only clears the module cache, so a failing assertion can leave the mock registered for later tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/reranker.test.ts` around lines 106 - 107, Make the mock cleanup around
the reranker tests exception-safe by moving
vi.doUnmock("`@huggingface/transformers`") into an afterEach hook or a try/finally
block. Keep vi.resetModules() as module-cache cleanup, and ensure the unmock
always runs even when a test assertion fails.

@aqeelat
aqeelat marked this pull request as draft July 21, 2026 21:20
…s v4

@xenova/transformers@2.x is deprecated and silently broken on Node 22+
(see rohitg00#479). The project was renamed to @huggingface/transformers; same
Apache-2.0 license, same code. v4 ships onnxruntime-node/web and sharp
as hard deps, so they're dropped from our optionalDependencies.

Pipeline / RawImage.fromBlob / tolist / text-classification output
shape all unchanged. Three behavior-preserving adjustments needed:

- All 4 pipeline call sites pass { dtype: "q8" }. v4's default on Node
  is fp32 (DEFAULT_DEVICE_DTYPE = "fp32"); v2 defaulted to quantized=true.
  Without explicit dtype, all 4 sites silently regress (~3.5x larger
  download, slower inference). dtype "q8" maps to model_quantized.onnx
  per v4's DEFAULT_DTYPE_SUFFIX_MAPPING; file exists in all 3 Xenova
  models. This was the regression that prompted the test additions below.
- src/providers/embedding/local.ts: split import try/catch from
  pipeline() call so model-load errors (network, missing q8 variant,
  disk) propagate with their actual message, not masked as
  "Install @huggingface/transformers...".
- src/providers/embedding/{local,clip}.ts: type module from
  typeof import("@huggingface/transformers") so PretrainedModelOptions
  flows through; drop hand-rolled aliases and @ts-ignore. Cast at
  assignment sites (pipeline return union isn't structurally assignable
  to our narrow FeatureExtractor / ClipPipeline shapes).

Tests added where coverage was zero (would have caught the dtype
regression):

- test/local-embedding-provider.test.ts (3 tests): unavailable-path
  install hint; pipeline called with dtype:q8 + extractor options +
  mapped Float32Array result; embedBatch shape.
- test/clip-embedding-provider.test.ts (5 tests): unavailable-path;
  text pipeline dtype:q8 + result; embedBatch; embedImage with data:
  URL decode; custom model ID propagation.
- test/reranker.test.ts: positive-path using vi.doMock + resetModules.

Other:
- src/huggingface.d.ts deleted (package ships its own types).
- src/xenova.d.ts removed.
- src/providers/embedding/clip.ts: inline single-use DIMENSIONS constant.
- tsdown.config.ts: trim neverBundle list and comment.
- README.md L1267: BGE-small -> Xenova/all-MiniLM-L6-v2 (was always wrong).
- 16 docs: install commands + prose mentions across main README, 11
  translations, SECURITY.md, 2 benchmark docs, benchmark script.
- Model IDs (Xenova/all-MiniLM-L6-v2, Xenova/clip-vit-base-patch32,
  Xenova/ms-marco-MiniLM-L-6-v2) kept — HF Hub repo names, still valid.

Closes rohitg00#1095. Fixes rohitg00#479.

Verified: 1424/1424 tests pass, build clean, tsc clean on migrated files.
@aqeelat
aqeelat force-pushed the chore/migrate-xenova-to-hf-transformers branch from 8207bed to 826b8bf Compare July 22, 2026 19:59
@aqeelat
aqeelat marked this pull request as ready for review July 22, 2026 20:03

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/providers/embedding/clip.ts`:
- Around line 59-65: Update loadTransformers() to catch errors, replace only
missing-module ERR_MODULE_NOT_FOUND failures with an embedding-agnostic
`@huggingface/transformers` installation hint, and rethrow all other errors
unchanged. Also update the provider.embed("hello") expectation in the CLIP
embedding provider test to avoid asserting the image-specific message.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: db31cfcc-2707-47cd-bda0-5af3b848b9fc

📥 Commits

Reviewing files that changed from the base of the PR and between 8207bed and 826b8bf.

📒 Files selected for processing (25)
  • README.md
  • READMEs/README.de-DE.md
  • READMEs/README.es-ES.md
  • READMEs/README.fr-FR.md
  • READMEs/README.hi-IN.md
  • READMEs/README.ja-JP.md
  • READMEs/README.ko-KR.md
  • READMEs/README.pt-BR.md
  • READMEs/README.ru-RU.md
  • READMEs/README.tr-TR.md
  • READMEs/README.zh-CN.md
  • READMEs/README.zh-TW.md
  • SECURITY.md
  • benchmark/LONGMEMEVAL.md
  • benchmark/REAL-EMBEDDINGS.md
  • benchmark/real-embeddings-eval.ts
  • package.json
  • src/providers/embedding/clip.ts
  • src/providers/embedding/local.ts
  • src/state/reranker.ts
  • src/xenova.d.ts
  • test/clip-embedding-provider.test.ts
  • test/local-embedding-provider.test.ts
  • test/reranker.test.ts
  • tsdown.config.ts
💤 Files with no reviewable changes (1)
  • src/xenova.d.ts
🚧 Files skipped from review as they are similar to previous changes (18)
  • benchmark/REAL-EMBEDDINGS.md
  • READMEs/README.tr-TR.md
  • READMEs/README.ru-RU.md
  • SECURITY.md
  • src/state/reranker.ts
  • tsdown.config.ts
  • READMEs/README.zh-CN.md
  • test/reranker.test.ts
  • benchmark/LONGMEMEVAL.md
  • READMEs/README.ko-KR.md
  • READMEs/README.zh-TW.md
  • READMEs/README.es-ES.md
  • READMEs/README.hi-IN.md
  • READMEs/README.pt-BR.md
  • READMEs/README.de-DE.md
  • README.md
  • src/providers/embedding/local.ts
  • READMEs/README.fr-FR.md

Comment on lines +59 to +65
async function loadTransformers(): Promise<TransformersModule> {
return import("@huggingface/transformers").catch(() => {
throw new Error(
"Install @huggingface/transformers for CLIP image embeddings: npm install @huggingface/transformers",
);
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)clip\.ts$|embedding|CLIP|clip' || true

echo "== target file outline =="
ast-grep outline src/providers/embedding/clip.ts --view expanded || true

echo "== target file relevant lines =="
cat -n src/providers/embedding/clip.ts | sed -n '1,180p'

echo "== loadTransformers usages =="
rg -n "loadTransformers|TextEncoder|image|CLIP|text embeddings|CLIP image embeddings|`@huggingface/transformers`" src/providers/embedding/clip.ts src -g '*.ts' || true

Repository: rohitg00/agentmemory

Length of output: 24333


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== clip test relevant assertions =="
cat -n test/clip-embedding-provider.test.ts | sed -n '1,260p'

echo "== local transformers loadTransformers behavior =="
cat -n src/providers/embedding/local.ts | sed -n '1,80p'

echo "== dynamic import failure behavior probe =="
node - <<'JS'
async function preserve() {
  try {
    await import('./this-package-should-not-exist-but-should-exist-because-bundling-can-change-runtime-404.mjs');
  } catch (error) {
    console.log('error_name', error && error.name);
    console.log('error_message', error && error.message);
    throw error;
  }
}
async function rewrite() {
  try {
    await import('./this-package-should-not-exist-but-should-exist-because-bundling-can-change-runtime-404.mjs');
  } catch {
    throw new Error('Install `@huggingface/transformers` for CLIP image embeddings: npm install `@huggingface/transformers`');
  }
}
(async () => {
  try { await preserve() } catch (e) { console.log('preserve_thrown_name', e.name) }
  try { await rewrite() } catch (e) { console.log('rewrite_thrown_name', e.name) }
})();
JS

Repository: rohitg00/agentmemory

Length of output: 6152


Preserve import errors and use an embedding-agnostic install hint.

loadTransformers() is called from both text and image CLIP paths, but its blanket catch only throws install guidance and hard-codes “CLIP image embeddings,” so text failures are misleading and non-module initialization errors get lost. Only rethrow missing-module ERR_MODULE_NOT_FOUND with a CLIP-transformers install hint; rethrow everything else. Update the provider.embed("hello") expectation in test/clip-embedding-provider.test.ts to avoid depending on the image-specific message.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/providers/embedding/clip.ts` around lines 59 - 65, Update
loadTransformers() to catch errors, replace only missing-module
ERR_MODULE_NOT_FOUND failures with an embedding-agnostic
`@huggingface/transformers` installation hint, and rethrow all other errors
unchanged. Also update the provider.embed("hello") expectation in the CLIP
embedding provider test to avoid asserting the image-specific message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant