anyformer 0.4.14 → 0.4.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 +17 -0
- package/package.json +1 -1
- package/src/backends/diskformer-onnx.js +18 -7
- package/src/backends/transformers.js +14 -7
- package/src/sources.js +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.15 — 2026-10-30
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- A caller that stops reading a reply early (a `break` out of `for await`, as after a tool call) without aborting
|
|
7
|
+
now stops the reply on `diskformer-onnx` and `transformers`: the back end aborts the engine call (a linked
|
|
8
|
+
AbortController for diskformer-onnx, the stopping criteria's interrupt for transformers.js) and waits for it before
|
|
9
|
+
the next generate() starts. Before, the engine kept generating, and the next reply ran on the same onnxruntime
|
|
10
|
+
sessions beside it: "failed to call OrtRun() … Failed to download data from buffer" or a hang of over 10 minutes in
|
|
11
|
+
Chrome (reported by NakliOS, root-caused by LocalMind). `diskformer-llama` already did this.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- diskformer pin 1fe19f8 → 7ffbea5 (v0.6.13: LFM3-Omni serves one reply at a time; changes only
|
|
15
|
+
`engines/lfm3_omni.js`).
|
|
16
|
+
- Browser tests `omni` and `omni-speech` break out of a reply (text, and spoken at its first speech chunk) without
|
|
17
|
+
aborting, then require the next reply to equal the text reference within 10 s. Passed 2026-10-30 (Chrome, this Mac,
|
|
18
|
+
local files), with `transformers` and the LFM3 1.7B `chat` check.
|
|
19
|
+
|
|
3
20
|
## 0.4.14 — 2026-10-30
|
|
4
21
|
|
|
5
22
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anyformer",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.15",
|
|
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",
|
|
@@ -87,8 +87,12 @@ export const diskformerOnnxBackend = {
|
|
|
87
87
|
let wake = () => {}, done = false, failed = null, text = '', tokens = 0;
|
|
88
88
|
const msgs = await media(messages);
|
|
89
89
|
const sampleRate = engine.speech?.sampling_rate ?? 24000;
|
|
90
|
-
engine
|
|
91
|
-
|
|
90
|
+
// The engine reads this signal, linked to the caller's, so a caller that stops reading can end the reply too.
|
|
91
|
+
const stop = new AbortController();
|
|
92
|
+
const abort = () => stop.abort();
|
|
93
|
+
if (signal?.aborted) abort(); else signal?.addEventListener('abort', abort, { once: true });
|
|
94
|
+
const job = engine.generate(msgs, {
|
|
95
|
+
max_new_tokens: maxNewTokens, do_sample: false, enable_thinking: thinking === true, signal: stop.signal,
|
|
92
96
|
...(tools && { tools }), ...(repetitionPenalty && { repetition_penalty: repetitionPenalty }), ...(seed !== undefined && { seed }),
|
|
93
97
|
...(speech && {
|
|
94
98
|
output_modalities: ['text', 'audio'],
|
|
@@ -100,12 +104,19 @@ export const diskformerOnnxBackend = {
|
|
|
100
104
|
onToken: () => { tokens++; },
|
|
101
105
|
onText: (delta) => { text += delta; queue.push({ text, tokens }); wake(); },
|
|
102
106
|
}).catch((err) => { failed = err; }).finally(() => { done = true; wake(); });
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
try {
|
|
108
|
+
while (true) {
|
|
109
|
+
if (queue.length) { yield queue.shift(); continue; }
|
|
110
|
+
if (done) break;
|
|
111
|
+
await new Promise((r) => { wake = r; });
|
|
112
|
+
}
|
|
113
|
+
if (failed) throw failed;
|
|
114
|
+
} finally {
|
|
115
|
+
signal?.removeEventListener('abort', abort);
|
|
116
|
+
// The caller stopped reading early (a break after a tool call): stop the reply, so the next call on this
|
|
117
|
+
// engine's sessions does not run beside it or queue behind it.
|
|
118
|
+
if (!done) { stop.abort(); await job; }
|
|
107
119
|
}
|
|
108
|
-
if (failed) throw failed;
|
|
109
120
|
},
|
|
110
121
|
dispose: () => engine.dispose(),
|
|
111
122
|
};
|
|
@@ -177,14 +177,21 @@ async function* stream(lib, tokenizer, signal, run) {
|
|
|
177
177
|
token_callback_function: () => { tokens++; },
|
|
178
178
|
});
|
|
179
179
|
const stop = new lib.InterruptableStoppingCriteria();
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
180
|
+
const interrupt = () => stop.interrupt();
|
|
181
|
+
signal?.addEventListener('abort', interrupt, { once: true });
|
|
182
|
+
const job = run(streamer, stop).catch((e) => { failed = e; }).finally(() => { done = true; wake(); });
|
|
183
|
+
try {
|
|
184
|
+
while (true) {
|
|
185
|
+
if (queue.length) { yield queue.shift(); continue; }
|
|
186
|
+
if (done) break;
|
|
187
|
+
await new Promise((r) => { wake = r; });
|
|
188
|
+
}
|
|
189
|
+
if (failed) throw failed;
|
|
190
|
+
} finally {
|
|
191
|
+
signal?.removeEventListener('abort', interrupt);
|
|
192
|
+
// The caller stopped reading early: stop the reply so the next call on this model does not run beside it.
|
|
193
|
+
if (!done) { stop.interrupt(); await job; }
|
|
186
194
|
}
|
|
187
|
-
if (failed) throw failed;
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
// A text-only model in the multimodal layout: the causal-LM class over embed_tokens + decoder_model_merged.
|
package/src/sources.js
CHANGED
|
@@ -9,6 +9,7 @@ export const PINS = {
|
|
|
9
9
|
// v0.3.1: seeded block-KV graphs (Nemotron-Labs-Diffusion-3B), chatFormat, split external data; download progress
|
|
10
10
|
// (progress_callback) and the graph files cached in Cache Storage 'kohra-models'.
|
|
11
11
|
kohra: 'bf95d44c3e3cfc001201baa03fa121c2bf9c7d73',
|
|
12
|
+
// v0.6.13 (7ffbea5): LFM3-Omni serves one reply at a time; overlapping runs broke onnxruntime-web WebGPU.
|
|
12
13
|
// v0.6.12 (1fe19f8): LFM3-Omni speech out (interleaved text and 24 kHz speech; depth and codec decoders). Changes
|
|
13
14
|
// only engines/lfm3_omni.js; its text, image and speech-in gate (3/3) is unchanged.
|
|
14
15
|
// 48f2c2a (main after v0.6.9): engines/lfm3_omni.js, LFM3-Omni-2B on onnxruntime-web 1.30.0 (text, image and speech
|
|
@@ -18,7 +19,7 @@ export const PINS = {
|
|
|
18
19
|
// Gemma 4 E2B/E4B and Ternary Bonsai 2) under engines/, and the llama.cpp path under ggml/, which loads split GGUFs
|
|
19
20
|
// and drafters, and reads past 2 GiB (Nemotron 3.5 Bolt E4B needs v0.6.8 or later). The hand engines' ingest
|
|
20
21
|
// streams the GGUF header with progress and resumes a dropped range.
|
|
21
|
-
diskformer: '
|
|
22
|
+
diskformer: '7ffbea54a5f09494e1f6c970cce7c4c7b1b8460d',
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
const gh = (repo, sha, path) => `https://cdn.jsdelivr.net/gh/NakliTechie/${repo}@${sha}/${path}`;
|