Spaces:
Running
Running
Sync from felladrin/MiniSearch@38e67b6
Browse files- agents.md +1 -1
- changelog.md +1 -0
- client/modules/textGenerationWithWllama.ts +3 -0
- client/modules/wllama.test.ts +12 -0
- client/modules/wllama.ts +13 -0
- docs/ai-integration.md +1 -1
- package-lock.json +3 -3
agents.md
CHANGED
|
@@ -190,7 +190,7 @@ Need to:
|
|
| 190 |
|
| 191 |
1. Check the wasm build can run it: the architecture must exist in `node_modules/@wllama/wllama/esm/wasm/wllama.wasm` (grep the binary for the arch name), and the quant must stay under the ceilings in `docs/ai-integration.md` (shard every file under 2000 MiB; total weights under ~3.7 GB)
|
| 192 |
2. Shard the GGUF (`llama-gguf-split --split --size`, or an equivalent) and publish to a `Felladrin/gguf-sharded-<QUANT>-<Name>` repo
|
| 193 |
-
3. Add to `client/modules/wllama.ts`; thinking-by-default templates need nothing extra
|
| 194 |
4. Run `node scripts/wllama-catalog-check.cjs` and `npx vitest run client/modules/wllama.test.ts`
|
| 195 |
5. Update `docs/ai-integration.md`
|
| 196 |
6. Update `docs/configuration.md` defaults
|
|
|
|
| 190 |
|
| 191 |
1. Check the wasm build can run it: the architecture must exist in `node_modules/@wllama/wllama/esm/wasm/wllama.wasm` (grep the binary for the arch name), and the quant must stay under the ceilings in `docs/ai-integration.md` (shard every file under 2000 MiB; total weights under ~3.7 GB)
|
| 192 |
2. Shard the GGUF (`llama-gguf-split --split --size`, or an equivalent) and publish to a `Felladrin/gguf-sharded-<QUANT>-<Name>` repo
|
| 193 |
+
3. Add to `client/modules/wllama.ts`; thinking-by-default templates need nothing extra (their `reasoning_content` channel is streamed into the thinking UI) but do need `reasoningBudgetTokens` so they cannot think past the context without answering
|
| 194 |
4. Run `node scripts/wllama-catalog-check.cjs` and `npx vitest run client/modules/wllama.test.ts`
|
| 195 |
5. Update `docs/ai-integration.md`
|
| 196 |
6. Update `docs/configuration.md` defaults
|
changelog.md
CHANGED
|
@@ -6,6 +6,7 @@ Notable changes, grouped by date, most recent first.
|
|
| 6 |
## 2026-11-03
|
| 7 |
|
| 8 |
- The five thinking models added on 2026-11-02 (Spark X2.6 1.7B and 4B, Granite 4.2 3B, Qwen 3.5 4B, Gemma 4 E2B) no longer ship with thinking switched off. Their chain of thought arrives on wllama's `reasoning_content` channel and is now wrapped in the configured reasoning markers, so the existing thinking UI shows it while the model reasons and the answer streams in after. The model warmup counts a reasoning token as a working model, so thinking models no longer log a failed warmup.
|
|
|
|
| 9 |
|
| 10 |
|
| 11 |
## 2026-11-02
|
|
|
|
| 6 |
## 2026-11-03
|
| 7 |
|
| 8 |
- The five thinking models added on 2026-11-02 (Spark X2.6 1.7B and 4B, Granite 4.2 3B, Qwen 3.5 4B, Gemma 4 E2B) no longer ship with thinking switched off. Their chain of thought arrives on wllama's `reasoning_content` channel and is now wrapped in the configured reasoning markers, so the existing thinking UI shows it while the model reasons and the answer streams in after. The model warmup counts a reasoning token as a working model, so thinking models no longer log a failed warmup.
|
| 9 |
+
- The same five models now cap their chain of thought with `reasoningBudgetTokens` (wllama's `reasoning_budget_tokens`, 256 tokens): when the model has thought that long without answering, the engine closes the reasoning channel and forces the final answer. Without the cap, Spark X2.6 and Granite 4.2 could spend the whole 4096-token context on reasoning and deliver no answer at all.
|
| 10 |
|
| 11 |
|
| 12 |
## 2026-11-02
|
client/modules/textGenerationWithWllama.ts
CHANGED
|
@@ -201,6 +201,9 @@ async function initializeWllamaInstance(progressCallback?: ProgressCallback) {
|
|
| 201 |
flash_attn: model.flash_attn,
|
| 202 |
embeddings: false,
|
| 203 |
n_gpu_layers: isWebGPUAvailable ? 99999 : 0,
|
|
|
|
|
|
|
|
|
|
| 204 |
progressCallback,
|
| 205 |
},
|
| 206 |
});
|
|
|
|
| 201 |
flash_attn: model.flash_attn,
|
| 202 |
embeddings: false,
|
| 203 |
n_gpu_layers: isWebGPUAvailable ? 99999 : 0,
|
| 204 |
+
...(model.reasoningBudgetTokens
|
| 205 |
+
? { reasoning_budget_tokens: model.reasoningBudgetTokens }
|
| 206 |
+
: {}),
|
| 207 |
progressCallback,
|
| 208 |
},
|
| 209 |
});
|
client/modules/wllama.test.ts
CHANGED
|
@@ -46,6 +46,18 @@ describe("wllamaModels catalog", () => {
|
|
| 46 |
}
|
| 47 |
});
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
it("uses the shared default context size for every model", () => {
|
| 50 |
for (const [id, model] of models) {
|
| 51 |
expect(model.contextSize, id).toBe(4096);
|
|
|
|
| 46 |
}
|
| 47 |
});
|
| 48 |
|
| 49 |
+
it("keeps reasoning budgets small enough to leave room for the answer", () => {
|
| 50 |
+
// The budget forces the final answer once the chain of thought runs
|
| 51 |
+
// this long. It must stay far below the 4096-token context, or the
|
| 52 |
+
// model thinks itself out of the window before answering.
|
| 53 |
+
for (const [id, model] of models) {
|
| 54 |
+
if (model.reasoningBudgetTokens !== undefined) {
|
| 55 |
+
expect(model.reasoningBudgetTokens, id).toBeGreaterThanOrEqual(64);
|
| 56 |
+
expect(model.reasoningBudgetTokens, id).toBeLessThanOrEqual(1024);
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
+
});
|
| 60 |
+
|
| 61 |
it("uses the shared default context size for every model", () => {
|
| 62 |
for (const [id, model] of models) {
|
| 63 |
expect(model.contextSize, id).toBe(4096);
|
client/modules/wllama.ts
CHANGED
|
@@ -141,6 +141,14 @@ export interface WllamaModel {
|
|
| 141 |
* it off.
|
| 142 |
*/
|
| 143 |
readonly chatTemplateKwargs?: Record<string, unknown>;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
getSampling: () => Omit<SamplingParams, "logit_bias">;
|
| 145 |
}
|
| 146 |
|
|
@@ -345,6 +353,7 @@ export const wllamaModels: Readonly<Record<string, WllamaModel>> = {
|
|
| 345 |
hfRepoId: "Felladrin/gguf-sharded-Q4_K_M-Spark-X2.6-1.7B",
|
| 346 |
hfFilePath: "Spark-X2.6-1.7B-Q4_K_M-00001-of-00004.gguf",
|
| 347 |
fileSizeInMegabytes: 1769,
|
|
|
|
| 348 |
},
|
| 349 |
"smollm3-3b": {
|
| 350 |
...createDefaultModelConfig(),
|
|
@@ -380,6 +389,7 @@ export const wllamaModels: Readonly<Record<string, WllamaModel>> = {
|
|
| 380 |
hfRepoId: "Felladrin/gguf-sharded-Q4_K_S-granite-4.2-3b",
|
| 381 |
hfFilePath: "granite-4.2-3b-Q4_K_S-00001-of-00005.gguf",
|
| 382 |
fileSizeInMegabytes: 2143,
|
|
|
|
| 383 |
},
|
| 384 |
"phi-3.5-mini-3.8b": {
|
| 385 |
...createDefaultModelConfig(),
|
|
@@ -408,6 +418,7 @@ export const wllamaModels: Readonly<Record<string, WllamaModel>> = {
|
|
| 408 |
hfRepoId: "Felladrin/gguf-sharded-UD-Q3_K_XL-Qwen3.5-4B",
|
| 409 |
hfFilePath: "Qwen3.5-4B-UD-Q3_K_XL-00001-of-00005.gguf",
|
| 410 |
fileSizeInMegabytes: 2436,
|
|
|
|
| 411 |
},
|
| 412 |
"gemma-4-e2b": {
|
| 413 |
...createDefaultModelConfig(),
|
|
@@ -415,6 +426,7 @@ export const wllamaModels: Readonly<Record<string, WllamaModel>> = {
|
|
| 415 |
hfRepoId: "Felladrin/gguf-sharded-Q3_K_S-gemma-4-e2b-it",
|
| 416 |
hfFilePath: "gemma-4-e2b-it-Q3_K_S-00001-of-00005.gguf",
|
| 417 |
fileSizeInMegabytes: 2446,
|
|
|
|
| 418 |
},
|
| 419 |
"phi-4-mini-reasoning": {
|
| 420 |
...createDefaultModelConfig(),
|
|
@@ -429,5 +441,6 @@ export const wllamaModels: Readonly<Record<string, WllamaModel>> = {
|
|
| 429 |
hfRepoId: "Felladrin/gguf-sharded-Q4_K_M-Spark-X2.6-4B",
|
| 430 |
hfFilePath: "Spark-X2.6-4B-Q4_K_M-00001-of-00007.gguf",
|
| 431 |
fileSizeInMegabytes: 3543,
|
|
|
|
| 432 |
},
|
| 433 |
};
|
|
|
|
| 141 |
* it off.
|
| 142 |
*/
|
| 143 |
readonly chatTemplateKwargs?: Record<string, unknown>;
|
| 144 |
+
/**
|
| 145 |
+
* Hard cap on the chain of thought, in tokens (wllama's
|
| 146 |
+
* `reasoning_budget_tokens`). When the model has thought this long
|
| 147 |
+
* without answering, the engine closes the reasoning channel and forces
|
| 148 |
+
* the final answer, so a long-winded model cannot spend the whole
|
| 149 |
+
* context window thinking and deliver nothing.
|
| 150 |
+
*/
|
| 151 |
+
readonly reasoningBudgetTokens?: number;
|
| 152 |
getSampling: () => Omit<SamplingParams, "logit_bias">;
|
| 153 |
}
|
| 154 |
|
|
|
|
| 353 |
hfRepoId: "Felladrin/gguf-sharded-Q4_K_M-Spark-X2.6-1.7B",
|
| 354 |
hfFilePath: "Spark-X2.6-1.7B-Q4_K_M-00001-of-00004.gguf",
|
| 355 |
fileSizeInMegabytes: 1769,
|
| 356 |
+
reasoningBudgetTokens: 256,
|
| 357 |
},
|
| 358 |
"smollm3-3b": {
|
| 359 |
...createDefaultModelConfig(),
|
|
|
|
| 389 |
hfRepoId: "Felladrin/gguf-sharded-Q4_K_S-granite-4.2-3b",
|
| 390 |
hfFilePath: "granite-4.2-3b-Q4_K_S-00001-of-00005.gguf",
|
| 391 |
fileSizeInMegabytes: 2143,
|
| 392 |
+
reasoningBudgetTokens: 256,
|
| 393 |
},
|
| 394 |
"phi-3.5-mini-3.8b": {
|
| 395 |
...createDefaultModelConfig(),
|
|
|
|
| 418 |
hfRepoId: "Felladrin/gguf-sharded-UD-Q3_K_XL-Qwen3.5-4B",
|
| 419 |
hfFilePath: "Qwen3.5-4B-UD-Q3_K_XL-00001-of-00005.gguf",
|
| 420 |
fileSizeInMegabytes: 2436,
|
| 421 |
+
reasoningBudgetTokens: 256,
|
| 422 |
},
|
| 423 |
"gemma-4-e2b": {
|
| 424 |
...createDefaultModelConfig(),
|
|
|
|
| 426 |
hfRepoId: "Felladrin/gguf-sharded-Q3_K_S-gemma-4-e2b-it",
|
| 427 |
hfFilePath: "gemma-4-e2b-it-Q3_K_S-00001-of-00005.gguf",
|
| 428 |
fileSizeInMegabytes: 2446,
|
| 429 |
+
reasoningBudgetTokens: 256,
|
| 430 |
},
|
| 431 |
"phi-4-mini-reasoning": {
|
| 432 |
...createDefaultModelConfig(),
|
|
|
|
| 441 |
hfRepoId: "Felladrin/gguf-sharded-Q4_K_M-Spark-X2.6-4B",
|
| 442 |
hfFilePath: "Spark-X2.6-4B-Q4_K_M-00001-of-00007.gguf",
|
| 443 |
fileSizeInMegabytes: 3543,
|
| 444 |
+
reasoningBudgetTokens: 256,
|
| 445 |
},
|
| 446 |
};
|
docs/ai-integration.md
CHANGED
|
@@ -38,7 +38,7 @@ Two constraints decide what can join that list, both measured against the shippe
|
|
| 38 |
- **Every model file must be a shard.** Chromium's OPFS storage silently truncates files past 2000 MiB, so a monolithic GGUF above that size arrives corrupted in the browser. Shards also keep progressive download working.
|
| 39 |
- **The wasm linear memory ceiling is 4 GiB.** Models at ~3.5 GB and above OOM during buffer reserve, so the practical catalog ceiling is around 3.7 GB of weights.
|
| 40 |
|
| 41 |
-
Models whose chat template thinks by default (Granite 4.2, Gemma 4, Spark X2.6, Qwen 3.5) keep thinking: wllama splits their chain of thought into a `reasoning_content` channel, and MiniSearch wraps it in the configured reasoning markers so the thinking UI shows it while the answer follows. Thinking spends the same token budget as the answer, so these models are slower
|
| 42 |
|
| 43 |
`node scripts/wllama-catalog-check.cjs` HEADs every shard of every catalog model on HuggingFace and verifies the claimed sizes; run it after adding or re-sharding a model.
|
| 44 |
|
|
|
|
| 38 |
- **Every model file must be a shard.** Chromium's OPFS storage silently truncates files past 2000 MiB, so a monolithic GGUF above that size arrives corrupted in the browser. Shards also keep progressive download working.
|
| 39 |
- **The wasm linear memory ceiling is 4 GiB.** Models at ~3.5 GB and above OOM during buffer reserve, so the practical catalog ceiling is around 3.7 GB of weights.
|
| 40 |
|
| 41 |
+
Models whose chat template thinks by default (Granite 4.2, Gemma 4, Spark X2.6, Qwen 3.5) keep thinking: wllama splits their chain of thought into a `reasoning_content` channel, and MiniSearch wraps it in the configured reasoning markers so the thinking UI shows it while the answer follows. Thinking spends the same token budget as the answer, so these models are slower. To keep a long-winded model from thinking its way out of the context window without ever answering, thinking models ship with `reasoningBudgetTokens` (wllama's `reasoning_budget_tokens`, currently 256): once the chain of thought runs that long, the engine closes the reasoning channel and forces the final answer.
|
| 42 |
|
| 43 |
`node scripts/wllama-catalog-check.cjs` HEADs every shard of every catalog model on HuggingFace and verifies the claimed sizes; run it after adding or re-sharding a model.
|
| 44 |
|
package-lock.json
CHANGED
|
@@ -4659,9 +4659,9 @@
|
|
| 4659 |
}
|
| 4660 |
},
|
| 4661 |
"node_modules/knip": {
|
| 4662 |
-
"version": "6.44.
|
| 4663 |
-
"resolved": "https://registry.npmjs.org/knip/-/knip-6.44.
|
| 4664 |
-
"integrity": "sha512-
|
| 4665 |
"dev": true,
|
| 4666 |
"funding": [
|
| 4667 |
{
|
|
|
|
| 4659 |
}
|
| 4660 |
},
|
| 4661 |
"node_modules/knip": {
|
| 4662 |
+
"version": "6.44.1",
|
| 4663 |
+
"resolved": "https://registry.npmjs.org/knip/-/knip-6.44.1.tgz",
|
| 4664 |
+
"integrity": "sha512-Hbd8nvkIsNgFfXgC7Jsb5LHv7jj6VwA3tmfHd53XPX2z9Vc9RnAZqV0BIiP4OrtYqKwCoLseFHQZerb1bNlbSw==",
|
| 4665 |
"dev": true,
|
| 4666 |
"funding": [
|
| 4667 |
{
|