@totalreclaw/totalreclaw 3.3.1-rc.14 → 3.3.1-rc.15

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/CHANGELOG.md CHANGED
@@ -4,6 +4,47 @@ All notable changes to `@totalreclaw/totalreclaw` (the OpenClaw plugin) are docu
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [3.3.1-rc.15] — 2026-04-24
8
+
9
+ Install-time unblock for bandwidth-constrained hosts. Lazy-loads the ONNX
10
+ runtime instead of forcing a ~216MB download during `openclaw plugins
11
+ install`.
12
+
13
+ ### Lazy-loaded ONNX / `@huggingface/transformers`
14
+
15
+ `openclaw plugins install @totalreclaw/totalreclaw` on slow hosts (VPNs,
16
+ CI containers with limited bandwidth, metered connections) was exceeding
17
+ the plugin-install timeout mid-download and getting SIGTERM'd, leaving
18
+ the plugin partially installed. Root cause: `@huggingface/transformers`
19
+ was a direct `dependency`, which transitively pulled
20
+ `onnxruntime-node`'s postinstall binary fetch (~216MB from GitHub
21
+ Releases).
22
+
23
+ - `@huggingface/transformers` and `onnxruntime-node` moved from
24
+ `dependencies` to optional `peerDependencies`
25
+ (`peerDependenciesMeta.<name>.optional: true`). npm v7+ and the
26
+ OpenClaw install path (`--legacy-peer-deps`) both skip these by
27
+ default — plugin install is now lean.
28
+ - `embedding.ts` converts the static
29
+ `import { AutoTokenizer, AutoModel, pipeline } from
30
+ '@huggingface/transformers'` into a dynamic `await import(...)` on
31
+ the first `generateEmbedding` call. If the optional peer is missing,
32
+ the error surfaces a clear install hint:
33
+ `npm install @huggingface/transformers`.
34
+ - New regression test `lazy-load-embedding.test.ts` asserts the
35
+ invariants (no top-level static runtime import; heavy packages not in
36
+ `dependencies`; peer-dep `optional` flag set) so a future refactor
37
+ can't silently reintroduce the install-time block.
38
+
39
+ **User impact:** users on constrained hosts can now install the plugin
40
+ without the 216MB download. Users who want semantic memory (recall /
41
+ search over encrypted facts) install `@huggingface/transformers`
42
+ separately — one-time, resumable if it times out.
43
+
44
+ Fixes [issue #92][i92] (QA bug 6 of 10, split from #84).
45
+
46
+ [i92]: https://github.com/p-diogo/totalreclaw-internal/issues/92
47
+
7
48
  ## [3.3.1-rc.14] — 2026-04-24
8
49
 
9
50
  Coordinated version bump with Python `2.3.1rc14`. Two narrow bug fixes
package/embedding.ts CHANGED
@@ -8,11 +8,44 @@
8
8
  * embedding model breaks search across an existing vault, so the
9
9
  * `TOTALRECLAW_EMBEDDING_MODEL` user-facing env var was removed in v1.
10
10
  *
11
- * Dependencies: @huggingface/transformers
11
+ * Dependencies: @huggingface/transformers is declared as an optional peer
12
+ * dependency. It is lazy-loaded on the first `generateEmbedding` call so
13
+ * `openclaw plugins install @totalreclaw/totalreclaw` does not block on the
14
+ * ~216MB onnxruntime-node native-binary download. Install it separately to
15
+ * enable semantic search: `npm install @huggingface/transformers`.
12
16
  */
13
17
 
18
+ // Type-only import — erased at compile time, no runtime dep on the package.
14
19
  // @ts-ignore - @huggingface/transformers types may not be perfect
15
- import { AutoTokenizer, AutoModel, pipeline, type FeatureExtractionPipeline } from '@huggingface/transformers';
20
+ import type { FeatureExtractionPipeline } from '@huggingface/transformers';
21
+
22
+ type HFTransformers = typeof import('@huggingface/transformers');
23
+
24
+ /** Cached module handle after first successful dynamic import. */
25
+ let transformersModule: HFTransformers | null = null;
26
+
27
+ /**
28
+ * Lazily import @huggingface/transformers. The package is declared as an
29
+ * optional peer dependency so the plugin installs on bandwidth-constrained
30
+ * hosts without pulling the onnxruntime-node native binary (~216MB). On first
31
+ * use, try to load it; if the user never installed it, surface a clear
32
+ * actionable error with the install command.
33
+ */
34
+ async function loadTransformers(): Promise<HFTransformers> {
35
+ if (transformersModule) return transformersModule;
36
+ try {
37
+ // @ts-ignore - dynamic import target is the optional peer dep
38
+ transformersModule = (await import('@huggingface/transformers')) as HFTransformers;
39
+ return transformersModule;
40
+ } catch (err) {
41
+ const hint =
42
+ '[TotalReclaw] @huggingface/transformers is not installed. ' +
43
+ 'Semantic memory requires it (one-time ~216MB download of ONNX runtime + model). ' +
44
+ 'Install with: npm install @huggingface/transformers';
45
+ const detail = err instanceof Error ? err.message : String(err);
46
+ throw new Error(`${hint}\nUnderlying load error: ${detail}`);
47
+ }
48
+ }
16
49
 
17
50
  interface ModelConfig {
18
51
  id: string;
@@ -45,14 +78,17 @@ let activeModel: ModelConfig | null = null;
45
78
  /**
46
79
  * Generate an embedding vector for the given text.
47
80
  *
48
- * On first call, downloads and loads the ONNX model (cached after download).
49
- * Subsequent calls reuse the loaded model and run in ~100ms.
81
+ * On first call, dynamically imports @huggingface/transformers (requires it
82
+ * to be installed see module docstring) and downloads the ONNX model
83
+ * (cached after download). Subsequent calls reuse the loaded module + model
84
+ * and run in ~100ms.
50
85
  */
51
86
  export async function generateEmbedding(
52
87
  text: string,
53
88
  options?: { isQuery?: boolean },
54
89
  ): Promise<number[]> {
55
90
  if (!activeModel) {
91
+ const { AutoTokenizer, AutoModel, pipeline } = await loadTransformers();
56
92
  activeModel = getModelConfig();
57
93
  console.error(`[TotalReclaw] Downloading embedding model (${activeModel.size}, one-time setup)...`);
58
94
  console.error('[TotalReclaw] This enables semantic search across your encrypted memories.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@totalreclaw/totalreclaw",
3
- "version": "3.3.1-rc.14",
3
+ "version": "3.3.1-rc.15",
4
4
  "description": "End-to-end encrypted, agent-portable memory for OpenClaw and any LLM-agent runtime. XChaCha20-Poly1305 with protobuf v4 + on-chain Memory Taxonomy v1 (claim / preference / directive / commitment / episode / summary).",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -31,16 +31,26 @@
31
31
  "author": "TotalReclaw Team",
32
32
  "license": "MIT",
33
33
  "dependencies": {
34
- "@huggingface/transformers": "^4.0.1",
35
34
  "@totalreclaw/client": "^1.2.0",
36
35
  "@totalreclaw/core": "^2.1.1",
37
36
  "@types/qrcode": "^1.5.6",
38
37
  "@types/ws": "^8.5.12",
39
- "onnxruntime-node": "^1.24.0",
40
38
  "qrcode": "^1.5.4",
41
39
  "qrcode-terminal": "^0.12.0",
42
40
  "ws": "^8.18.3"
43
41
  },
42
+ "peerDependencies": {
43
+ "@huggingface/transformers": "^4.0.1",
44
+ "onnxruntime-node": "^1.24.0"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "@huggingface/transformers": {
48
+ "optional": true
49
+ },
50
+ "onnxruntime-node": {
51
+ "optional": true
52
+ }
53
+ },
44
54
  "files": [
45
55
  "*.ts",
46
56
  "import-adapters/",
@@ -54,7 +64,7 @@
54
64
  "skill.json"
55
65
  ],
56
66
  "scripts": {
57
- "test": "npx tsx manifest-shape.test.ts && npx tsx config-schema.test.ts && npx tsx llm-profile-reader.test.ts && npx tsx llm-client.test.ts && npx tsx llm-client-retry.test.ts && npx tsx gateway-url.test.ts && npx tsx retype-setscope.test.ts && npx tsx tool-gating.test.ts && npx tsx onboarding-noninteractive.test.ts && npx tsx pair-cli-json.test.ts && npx tsx pair-qr.test.ts && npx tsx pair-remote-client.test.ts && npx tsx qa-bug-report.test.ts && npx tsx nonce-serialization.test.ts && npx tsx phrase-safety-registry.test.ts",
67
+ "test": "npx tsx manifest-shape.test.ts && npx tsx config-schema.test.ts && npx tsx llm-profile-reader.test.ts && npx tsx llm-client.test.ts && npx tsx llm-client-retry.test.ts && npx tsx gateway-url.test.ts && npx tsx retype-setscope.test.ts && npx tsx tool-gating.test.ts && npx tsx onboarding-noninteractive.test.ts && npx tsx pair-cli-json.test.ts && npx tsx pair-qr.test.ts && npx tsx pair-remote-client.test.ts && npx tsx qa-bug-report.test.ts && npx tsx nonce-serialization.test.ts && npx tsx phrase-safety-registry.test.ts && npx tsx lazy-load-embedding.test.ts",
58
68
  "check-scanner": "node ../scripts/check-scanner.mjs",
59
69
  "prepublishOnly": "node ../scripts/check-scanner.mjs"
60
70
  },