anyformer 0.4.4 → 0.4.8
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 +58 -0
- package/README.md +3 -3
- package/package.json +1 -1
- package/src/backends/kohra.js +33 -6
- package/src/backends/transformers.js +42 -0
- package/src/models.js +6 -0
- package/src/sources.js +7 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,63 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.8 — 2026-10-24
|
|
4
|
+
|
|
5
|
+
Skips 0.4.7 on npm: this release carries its Nemotron-Labs-Diffusion-3B entry too.
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- kohra pinned to v0.3.0 (85e01f0); kohra.js is identical to 0.4.7's pin, 14e430c.
|
|
9
|
+
- Nemotron-Labs-Diffusion-3B decodes with threshold 0.9 by default (Fast-dLLM: unmask every position at that
|
|
10
|
+
confidence per step); `generate(messages, { threshold: null })` runs fixed steps. kohra measured 34 forward passes
|
|
11
|
+
against 64 with the same answer.
|
|
12
|
+
|
|
13
|
+
### Verified
|
|
14
|
+
- Browser (Chrome, M4 Pro, GPU shared with another session): one page, the CPU prompt, 32 tokens, threshold
|
|
15
|
+
null / 0.9 / null / 0.9: identical text in every run; 7.1 s and 5.8 s at fixed steps, 4.9 s at 0.9. npm test 89/89.
|
|
16
|
+
|
|
17
|
+
## 0.4.7 — 2026-10-24
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- Nemotron-Labs-Diffusion-3B (`MODELS.chat.NEMOTRON_DIFFUSION_3B`, naklitechie/Nemotron-Labs-Diffusion-3B-ONNX) on
|
|
21
|
+
`kohra`: the q4f16 seeded block-KV graph (onnx/model_kv_q4f16.onnx, 2.73 GB with its two data files), mask id 100,
|
|
22
|
+
EOS 11, and Nemotron's chat template over the whole conversation (a system turn, an empty think block before each
|
|
23
|
+
assistant reply). Content blocks are joined as text.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
- kohra pinned to main 14e430c (after v0.2.1; kohra.js changed in afee5f4): seeded KV graphs, `chatFormat`, graphs
|
|
27
|
+
whose data is split into `_data`, `_data_1`.
|
|
28
|
+
|
|
29
|
+
### Verified
|
|
30
|
+
- Browser (Chrome, M4 Pro): `npm run test:browser -- kohra --query "repo=naklitechie/Nemotron-Labs-Diffusion-3B-ONNX"`
|
|
31
|
+
answered on topic (32 tokens, 5.0 tok/s, load 156 s with the download); `npm run test:browser -- kohra` (Qwen3-0.6B
|
|
32
|
+
MDLM) on the new pin answered on topic. npm test 89/89.
|
|
33
|
+
|
|
34
|
+
## 0.4.6 — 2026-10-24
|
|
35
|
+
|
|
36
|
+
Skips 0.4.5 on npm: this release carries its diskformer v0.6.8 pin too.
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
- Nemotron 3.5 Bolt E4B (`MODELS.chat.NEMOTRON_3_5_BOLT_E4B`) on `transformers` at a 5 GB budget:
|
|
40
|
+
danyalmalik/NVIDIA-Nemotron-3.5-Bolt-E4B-ONNX-WebGPU, a community q4f16 export (Bolt's weights in onnx-community's
|
|
41
|
+
Gemma 4 E4B graph), text only, 4.91 GB.
|
|
42
|
+
- `transformers`: a Gemma 4 repo in the multimodal layout with no vision or audio encoder loads through
|
|
43
|
+
`Gemma4ForCausalLM` and the tokenizer. Its `use_external_data_format` comes from the repo's `_data` files, because
|
|
44
|
+
that repo's config.json has no transformers.js_config (without it: "Module.MountedFiles is not available"). Image
|
|
45
|
+
and audio blocks are refused with `INVALID_ARGUMENT`.
|
|
46
|
+
|
|
47
|
+
### Verified
|
|
48
|
+
- Browser (Chrome, M4 Pro): `npm run test:browser -- transformers --query "repo=danyalmalik/NVIDIA-Nemotron-3.5-Bolt-E4B-ONNX-WebGPU&budget=5.3"`
|
|
49
|
+
answered on topic, 34.9 tok/s, load 231 s with the download. npm test 88/88.
|
|
50
|
+
|
|
51
|
+
## 0.4.5 — 2026-10-24
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
- diskformer pinned to v0.6.8 (3aad103). Its llama.cpp path (ggml/) reads past 2 GiB in a browser, adds head-512
|
|
55
|
+
attention and loads drafter GGUFs (`draft`). The hand engines (engines/, src/) are unchanged since v0.6.7.
|
|
56
|
+
|
|
57
|
+
### Verified
|
|
58
|
+
- `llama-gate` on Granite 4.0 H Tiny (Chrome, M4 Pro, v0.6.8 pin): 9/9 identical to diskformer's refs, chat path
|
|
59
|
+
equal, 19.1 tok/s median. npm test 87/87. Not rerun: the hand-engine gates, because engines/ did not change.
|
|
60
|
+
|
|
3
61
|
## 0.4.4 — 2026-10-24
|
|
4
62
|
|
|
5
63
|
### Changed
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ browser storage; no account, no server, no telemetry.
|
|
|
14
14
|
| How | Command |
|
|
15
15
|
|---|---|
|
|
16
16
|
| npm | `npm install anyformer` |
|
|
17
|
-
| CDN | `import { load } from 'https://cdn.jsdelivr.net/npm/anyformer@0.4.
|
|
17
|
+
| CDN | `import { load } from 'https://cdn.jsdelivr.net/npm/anyformer@0.4.8/+esm';` |
|
|
18
18
|
| Copy | `index.js` and `src/`; nothing else is needed |
|
|
19
19
|
|
|
20
20
|
```js
|
|
@@ -54,8 +54,8 @@ back end's answer: yes with an estimate (GPU bytes, disk bytes, tok/s when measu
|
|
|
54
54
|
|
|
55
55
|
| Back end | Runs | Models |
|
|
56
56
|
|---|---|---|
|
|
57
|
-
| `transformers` | transformers.js 4.3.1: text generation, image and audio chat (Gemma 4, Qwen3.5), embeddings, speech to text, detection, classification, depth, segmentation | ONNX repos in the onnx-community / Xenova layout |
|
|
58
|
-
| `kohra` | kohra, text-diffusion over onnxruntime-web | MDLM and BD3LM repos tagged `text-diffusion
|
|
57
|
+
| `transformers` | transformers.js 4.3.1: text generation (Nemotron 3.5 Bolt E4B among them), image and audio chat (Gemma 4, Qwen3.5), embeddings, speech to text, detection, classification, depth, segmentation | ONNX repos in the onnx-community / Xenova layout |
|
|
58
|
+
| `kohra` | kohra, text-diffusion over onnxruntime-web | MDLM and BD3LM repos tagged `text-diffusion`; Nemotron-Labs-Diffusion-3B |
|
|
59
59
|
| `localmind` | LocalMind's hand-written WebGPU kernels (shipped in diskformer), the whole model on the GPU | any LFM2 / LFM2.5 GGUF; Gemma 4 E2B / E4B QAT-mobile; Ternary Bonsai 2 |
|
|
60
60
|
| `wllama` | llama.cpp in WebAssembly: WebGPU when the budget holds the model, the CPU otherwise (no WebGPU needed) | any GGUF up to about 3.6 GB that no engine above covers; files over 2 GB are split into OPFS shards once |
|
|
61
61
|
| `diskformer` | diskformer engines: weights in OPFS, only what a step needs on the GPU | Gemma 4 26B-A4B (from 2.5 GB), Qwen3.6 35B-A3B (from 4 GB), Ling 3.0 Flash 124B (from 6.8 GB), MiniCPM-V 4.7 with images, Flint 40B, LFM2.5 24B (from 4 GB) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anyformer",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"description": "One call to run a model in a browser tab: anyformer reads the Hub repo, probes the browser, and picks the back end (transformers.js, LocalMind's WebGPU kernels, diskformer, kohra) that fits the model's format, architecture and your GPU budget.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
package/src/backends/kohra.js
CHANGED
|
@@ -9,8 +9,29 @@ const FP16 = 'onnx/model_fp16_fused.onnx';
|
|
|
9
9
|
const Q4 = 'onnx/model_q4f16_rtn_sym.onnx';
|
|
10
10
|
const Q4_ORT = '1.26.0-dev.20260416-b7804b056c';
|
|
11
11
|
|
|
12
|
+
// Models with their own graph and tokens, keyed by config.model_type (kohra index.html REGISTRY at the pinned commit).
|
|
13
|
+
// Nemotron-Labs-Diffusion-3B: a seeded block-KV graph (kohra.js finds its attention_mask input and denoises blocks
|
|
14
|
+
// from the prompt end), mask id 100, EOS 11, and Nemotron's template: a system turn, always, and an empty think block
|
|
15
|
+
// before each assistant reply.
|
|
16
|
+
const SPECIAL = {
|
|
17
|
+
nemotron_labs_diffusion: {
|
|
18
|
+
graph: 'onnx/model_kv_q4f16.onnx', opts: { kvCache: true, maskId: 100n, eosId: 11n }, blockCausal: false,
|
|
19
|
+
// Fast-dLLM decoding: unmask every position at confidence 0.9 or more per step. Same answer in 34 forward passes
|
|
20
|
+
// where fixed steps took 64 (kohra, primes prompt).
|
|
21
|
+
threshold: 0.9,
|
|
22
|
+
template: (messages) => {
|
|
23
|
+
const [system, rest] = messages[0]?.role === 'system' ? [messages[0].content, messages.slice(1)] : ['', messages];
|
|
24
|
+
return `<|im_start|>system\n${system}<|im_end|>\n` + rest.map((m) => (m.role === 'assistant'
|
|
25
|
+
? `<|im_start|>assistant\n<think></think>${m.content.trim()}<|im_end|>\n`
|
|
26
|
+
: `<|im_start|>${m.role}\n${m.content}<|im_end|>\n`)).join('') + '<|im_start|>assistant\n<think></think>';
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
12
31
|
const pickGraph = (model, caps) => {
|
|
13
32
|
const have = new Set(model.files.onnx.map((f) => f.name));
|
|
33
|
+
const special = SPECIAL[model.architecture];
|
|
34
|
+
if (special) return have.has(special.graph) ? special.graph : null;
|
|
14
35
|
return caps.f16 && have.has(FP16) ? FP16 : have.has(Q4) ? Q4 : null;
|
|
15
36
|
};
|
|
16
37
|
|
|
@@ -18,6 +39,9 @@ const pickGraph = (model, caps) => {
|
|
|
18
39
|
const chatml = (messages) =>
|
|
19
40
|
messages.map((m) => `<|im_start|>${m.role}\n${m.content}<|im_end|>\n`).join('') + '<|im_start|>assistant\n';
|
|
20
41
|
|
|
42
|
+
// Text blocks joined: kohra reads text only.
|
|
43
|
+
const text = (messages) => messages.map((m) => (typeof m.content === 'string' ? m : { ...m, content: m.content.map((b) => b.text ?? '').join('\n') }));
|
|
44
|
+
|
|
21
45
|
export const kohraBackend = {
|
|
22
46
|
id: 'kohra',
|
|
23
47
|
tasks: ['text-generation'],
|
|
@@ -28,7 +52,7 @@ export const kohraBackend = {
|
|
|
28
52
|
if (task && task !== 'text-generation') return { ok: false, code: 'task', reason: `task ${task}; kohra runs text-generation only` };
|
|
29
53
|
if (!caps.webgpu) return { ok: false, code: 'webgpu', reason: 'no WebGPU adapter' };
|
|
30
54
|
const graph = pickGraph(model, caps);
|
|
31
|
-
if (!graph) return { ok: false, code: 'format', reason: `no kohra graph (${FP16} or ${Q4}) in the repo` };
|
|
55
|
+
if (!graph) return { ok: false, code: 'format', reason: `no kohra graph (${SPECIAL[model.architecture]?.graph || `${FP16} or ${Q4}`}) in the repo` };
|
|
32
56
|
const bytes = graphBytes(model, graph);
|
|
33
57
|
return { ok: true, estimate: { gpuBytes: bytes, diskBytes: bytes, tokPerSec: null } };
|
|
34
58
|
},
|
|
@@ -38,18 +62,21 @@ export const kohraBackend = {
|
|
|
38
62
|
const { DiffusionLM } = await import(kohraBackend.source);
|
|
39
63
|
onProgress?.({ backend: 'kohra', status: 'loading', file: graph });
|
|
40
64
|
const base = `https://huggingface.co/${model.repo}/resolve/${model.revision || 'main'}`;
|
|
65
|
+
const special = SPECIAL[model.architecture];
|
|
41
66
|
const lm = await DiffusionLM.from_pretrained({
|
|
42
|
-
model: `${base}/${graph}`, tokenizer: model.repo, ...(graph === Q4 && { ortVersion: Q4_ORT }),
|
|
67
|
+
model: `${base}/${graph}`, tokenizer: model.repo, ...(graph === Q4 && { ortVersion: Q4_ORT }), ...special?.opts,
|
|
43
68
|
});
|
|
44
69
|
signal?.throwIfAborted();
|
|
45
|
-
const blockCausal = model.tags.includes('block-diffusion');
|
|
70
|
+
const blockCausal = special ? special.blockCausal : model.tags.includes('block-diffusion');
|
|
71
|
+
const prompt = special?.template || chatml;
|
|
46
72
|
return {
|
|
47
73
|
task: 'text-generation',
|
|
48
74
|
// Diffusion fills the whole block at once, so the reply arrives as one chunk.
|
|
49
|
-
|
|
75
|
+
// threshold: unmask every position at that confidence per step (Fast-dLLM); null runs fixed steps.
|
|
76
|
+
async *generate(messages, { maxNewTokens = 128, steps, threshold = special?.threshold ?? null, signal } = {}) {
|
|
50
77
|
signal?.throwIfAborted();
|
|
51
|
-
const out = await lm.generate(
|
|
52
|
-
maxNewTokens, steps: steps ?? maxNewTokens, blockCausal, chatTemplate: false, stripThink: true,
|
|
78
|
+
const out = await lm.generate(prompt(text(messages)), {
|
|
79
|
+
maxNewTokens, steps: steps ?? maxNewTokens, threshold, blockCausal, chatTemplate: false, stripThink: true,
|
|
53
80
|
});
|
|
54
81
|
yield { text: out.text, tokens: out.tokens, tokPerSec: out.tokensPerSecond };
|
|
55
82
|
},
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// importing anyformer costs nothing until this back end is chosen.
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
import { AnyformerError } from '../errors.js';
|
|
5
6
|
import { SOURCES } from '../sources.js';
|
|
6
7
|
|
|
7
8
|
// dtype → the ONNX file transformers.js reads for it (decoder-only repos keep one graph per dtype under onnx/).
|
|
@@ -31,6 +32,18 @@ function pickMmDtype(model, caps) {
|
|
|
31
32
|
return order.find((d) => have.has(`onnx/decoder_model_merged${MM_SUFFIX[d]}.onnx`)) || null;
|
|
32
33
|
}
|
|
33
34
|
const mmBytes = (model, dtype) => mmModules(model).reduce((n, m) => n + graphBytes(model, `onnx/${m}${MM_SUFFIX[dtype]}.onnx`), 0);
|
|
35
|
+
// A text-only export in the multimodal layout (embed_tokens + decoder_model_merged, no vision or audio encoder), e.g.
|
|
36
|
+
// danyalmalik/NVIDIA-Nemotron-3.5-Bolt-E4B-ONNX-WebGPU: loads through the causal-LM class and the tokenizer, as
|
|
37
|
+
// LocalMind does, since there is no processor.
|
|
38
|
+
const CAUSAL = { gemma4: 'Gemma4ForCausalLM' };
|
|
39
|
+
const textOnly = (model) => model.architecture in CAUSAL && !mmModules(model).some((m) => /^(vision|audio)_encoder$/.test(m));
|
|
40
|
+
// How many external-data files each graph has (<graph>_data, <graph>_data_1 …), keyed as transformers.js_config's
|
|
41
|
+
// use_external_data_format is: a repo whose config.json lacks that block fails to mount the data without it. The
|
|
42
|
+
// counts equal the config's in onnx-community's Gemma 4 E2B and Qwen3.5 4B repos.
|
|
43
|
+
const externalData = (model, dtype) => Object.fromEntries(mmModules(model).map((m) => {
|
|
44
|
+
const file = `onnx/${m}${MM_SUFFIX[dtype]}.onnx`;
|
|
45
|
+
return [file.slice(5), model.files.all.filter((f) => f.name.startsWith(`${file}_data`)).length];
|
|
46
|
+
}).filter(([, n]) => n > 0));
|
|
34
47
|
const isMultimodal = (model) => model.architecture in MULTIMODAL && model.files.onnx.some((f) => f.name.startsWith('onnx/decoder_model_merged'));
|
|
35
48
|
// The chat tasks a multimodal repo is tagged with on the Hub; all run here as chat.
|
|
36
49
|
const MM_TASKS = ['text-generation', 'image-text-to-text', 'any-to-any'];
|
|
@@ -100,6 +113,7 @@ export const transformersBackend = {
|
|
|
100
113
|
const want = task || model.task || 'text-generation';
|
|
101
114
|
const lib = await import(transformersBackend.source);
|
|
102
115
|
const progress_callback = onProgress && ((p) => onProgress({ backend: 'transformers', ...p }));
|
|
116
|
+
if (isMultimodal(model) && textOnly(model)) return loadCausal(lib, model, forced || pickMmDtype(model, caps), { progress_callback, signal });
|
|
103
117
|
if (isMultimodal(model)) return loadMultimodal(lib, model, forced || pickMmDtype(model, caps), { progress_callback, signal });
|
|
104
118
|
if (want !== 'text-generation') return loadPipeline(lib, model, want, { progress_callback, signal });
|
|
105
119
|
const dtype = forced || pickDtype(model, caps);
|
|
@@ -156,6 +170,34 @@ async function* stream(lib, tokenizer, signal, run) {
|
|
|
156
170
|
if (failed) throw failed;
|
|
157
171
|
}
|
|
158
172
|
|
|
173
|
+
// A text-only model in the multimodal layout: the causal-LM class over embed_tokens + decoder_model_merged.
|
|
174
|
+
async function loadCausal(lib, model, dtype, { progress_callback, signal }) {
|
|
175
|
+
const opts = { revision: model.revision || 'main', progress_callback };
|
|
176
|
+
const tokenizer = await lib.AutoTokenizer.from_pretrained(model.repo, opts);
|
|
177
|
+
const net = await lib[CAUSAL[model.architecture]].from_pretrained(model.repo, {
|
|
178
|
+
...opts, dtype, device: 'webgpu', use_external_data_format: externalData(model, dtype),
|
|
179
|
+
});
|
|
180
|
+
signal?.throwIfAborted();
|
|
181
|
+
return {
|
|
182
|
+
task: 'text-generation',
|
|
183
|
+
generate: (messages, { maxNewTokens = 256, repetitionPenalty, signal } = {}) => stream(lib, tokenizer, signal, (streamer, stopping_criteria) => {
|
|
184
|
+
const inputs = tokenizer.apply_chat_template(textMessages(messages), { add_generation_prompt: true, enable_thinking: false, return_dict: true });
|
|
185
|
+
return net.generate({ ...inputs, max_new_tokens: maxNewTokens, do_sample: false, ...(repetitionPenalty && { repetition_penalty: repetitionPenalty }), streamer, stopping_criteria });
|
|
186
|
+
}),
|
|
187
|
+
dispose: () => net.dispose?.(),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Text blocks joined; a text-only model refuses any other block.
|
|
192
|
+
function textMessages(messages) {
|
|
193
|
+
return messages.map((m) => {
|
|
194
|
+
if (typeof m.content === 'string') return m;
|
|
195
|
+
const other = m.content.find((b) => b.type !== 'text');
|
|
196
|
+
if (other) throw new AnyformerError('INVALID_ARGUMENT', `this model reads text only; got a ${other.type} block`);
|
|
197
|
+
return { ...m, content: m.content.map((b) => b.text).join('\n') };
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
159
201
|
// A multimodal chat model. Message content is a string or an array of blocks: { type: 'text', text },
|
|
160
202
|
// { type: 'image', image } (ImageData, RawImage or a URL) and, for Gemma 4, { type: 'audio', audio } (16 kHz
|
|
161
203
|
// Float32Array). The template sees placeholders; the processor gets the media, in order.
|
package/src/models.js
CHANGED
|
@@ -16,7 +16,9 @@ const GEMMA4_E2B_ONNX = M('onnx-community/gemma-4-E2B-it-ONNX', 'transformers',
|
|
|
16
16
|
const GEMMA4_E4B_ONNX = M('onnx-community/gemma-4-E4B-it-ONNX', 'transformers', 'text-generation', 'transformers', { budget: 5.3e9, downloadBytes: 5.18e9 });
|
|
17
17
|
const MINICPM5_2B = M('openbmb/MiniCPM5-2B-GGUF', 'wllama', 'text-generation', 'chat', { downloadBytes: 1.56e9 });
|
|
18
18
|
const QWEN3_0_6B_MDLM = M('naklitechie/Qwen3-0.6B-diffusion-mdlm-ONNX', 'kohra', 'text-generation', 'kohra', { downloadBytes: 1.54e9 });
|
|
19
|
+
const NEMOTRON_DIFFUSION_3B = M('naklitechie/Nemotron-Labs-Diffusion-3B-ONNX', 'kohra', 'text-generation', 'kohra', { downloadBytes: 2.77e9 });
|
|
19
20
|
const GEMMA4_26B_A4B = M('google/gemma-4-26B-A4B-it-qat-q4_0-gguf', 'diskformer', 'text-generation', 'diskformer-chat', { budget: 2.5e9, downloadBytes: 14.44e9 });
|
|
21
|
+
const NEMOTRON_3_5_BOLT_E4B = M('danyalmalik/NVIDIA-Nemotron-3.5-Bolt-E4B-ONNX-WebGPU', 'transformers', 'text-generation', 'transformers', { budget: 5e9, downloadBytes: 4.94e9 });
|
|
20
22
|
const MINILM_L6 = M('Xenova/all-MiniLM-L6-v2', 'transformers', 'feature-extraction', 'embed', { downloadBytes: 90e6 });
|
|
21
23
|
const DETR_RESNET_50 = M('Xenova/detr-resnet-50', 'transformers', 'object-detection', 'detect', { downloadBytes: 167e6 });
|
|
22
24
|
|
|
@@ -40,8 +42,12 @@ export const MODELS = {
|
|
|
40
42
|
MINICPM5_2B,
|
|
41
43
|
/** Text diffusion: the whole reply denoises at once (kohra). */
|
|
42
44
|
QWEN3_0_6B_MDLM,
|
|
45
|
+
/** NVIDIA's Nemotron-Labs-Diffusion-3B, block diffusion with a KV cache, q4 (kohra). */
|
|
46
|
+
NEMOTRON_DIFFUSION_3B,
|
|
43
47
|
/** 26B parameters in 2.5 GB of GPU memory; 14.4 GB on disk (diskformer). */
|
|
44
48
|
GEMMA4_26B_A4B,
|
|
49
|
+
/** NVIDIA's Nemotron 3.5 Bolt E4B (dense, text only), a community q4f16 ONNX export in Gemma 4 E4B's graph. */
|
|
50
|
+
NEMOTRON_3_5_BOLT_E4B,
|
|
45
51
|
},
|
|
46
52
|
/** Chat with images in the messages: content [{ type: 'image', image }, { type: 'text', text }]. Gemma 4 takes audio too. */
|
|
47
53
|
vision: { DEFAULT: QWEN3_5_4B, QWEN3_5_4B, GEMMA4_E2B_ONNX, GEMMA4_E4B_ONNX },
|
package/src/sources.js
CHANGED
|
@@ -6,11 +6,13 @@
|
|
|
6
6
|
export const PINS = {
|
|
7
7
|
transformers: '4.3.1',
|
|
8
8
|
wllama: '3.4.1', // LocalMind's pin; its stream-drain workaround (src/backends/wllama.js) is for this version
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
|
|
9
|
+
// v0.3.0: seeded block-KV graphs (Nemotron-Labs-Diffusion-3B), chatFormat, split external data.
|
|
10
|
+
kohra: '85e01f0193163b0f2e9696d4f6f5e12b68a277e9',
|
|
11
|
+
// v0.6.8: every engine (the disk-tier MoE engines, Ling 3.0 Flash, and LocalMind's whole-model engines LFM2.5,
|
|
12
|
+
// Gemma 4 E2B/E4B and Ternary Bonsai 2) under engines/, and the llama.cpp path under ggml/, which loads split GGUFs
|
|
13
|
+
// and drafters, and reads past 2 GiB (Nemotron 3.5 Bolt E4B needs v0.6.8 or later). The hand engines' ingest
|
|
14
|
+
// streams the GGUF header with progress and resumes a dropped range.
|
|
15
|
+
diskformer: '3aad103e47cac76c1471e92a438edfe1c80dd86e',
|
|
14
16
|
};
|
|
15
17
|
|
|
16
18
|
const gh = (repo, sha, path) => `https://cdn.jsdelivr.net/gh/NakliTechie/${repo}@${sha}/${path}`;
|