Repository navigation
Releases
2026.11.12
2026-11-12
- The follow-up question field and its Send button now look like one control: the field has square right corners and shares a single border with the button. The microphone button no longer turns into a solid gray block while an answer is being generated, and its hover and recording fills stay inside the field's border, in the follow-up field and in the search field.
2026-11-09
-
The in-browser engine, wllama, moves from 3.8.1 to 3.13.0. It now handles a model download that stopped midway by itself, so MiniSearch no longer deletes those files before each load.
-
Dictation's on-device model is now Qwen3-ASR 0.6B, run through wllama, instead of Moonshine. It understands every language MiniSearch answers in, not only English, so the setting that prefers it is now on by default for every browser; a profile saved before keeps its value, so a non-English profile turns it on in the Voice settings. The text now appears when the user stops recording rather than while they speak (about 2 seconds for a short query on WebGPU), and a recording ends on its own after two minutes. The first press downloads about 700 MB from Hugging Face, against 51 MB before, and later presses load it from the browser's storage in about 2 seconds; leaving the page or turning dictation off mid-download aborts it. The Moonshine runtime leaves the build, which shrinks from 35.7 MB to 22.2 MB, and the
/dictation-models/route andDICTATION_MODELS_DIRare gone, since the server no longer serves model files.docs/speech-model-evaluation.mdrecords the speech models tried for dictation and reading aloud, and why the others were turned down. -
Reading answers aloud now speaks the answer's language. With no voice chosen, the voice is picked for the language the answer is written in, detected with
franc-min, instead of the browser's: on an English browser, an answer in Portuguese is read by a Portuguese voice. The Voice settings panel lists every local voice (124 in 34 languages today) grouped by language, with the browser's language first, where it used to list only the browser's language, and the engine is no longer labeled "English-only". The detector is a new dependency, a 109 KB script (51 KB compressed) loaded on the first Listen press rather than with the page. A browser language the detector does not know (Danish, Finnish and Catalan among them) keeps its voice, as before, and a chosen voice reads every answer. Japanese, Korean and Hindi have no local voice, so their answers are read by an OS voice of that language.
2026-11-08
- MiniSearch now checks that the GPU can run wllama's shaders before using it, instead of only checking that the browser has WebGPU. The shaders use subgroups and the
subgroup_idbuiltin, so the GPU is used only when the browser's shader compiler supportssubgroup_id, an adapter answers within 5 seconds, it is not a software fallback, and it has thesubgroupsfeature. Otherwise the model runs on the CPU and a new profile starts on the CPU default model. On Chrome 137, which has WebGPU but notsubgroup_id, every model used to abort; it now answers on the CPU with LittleLamb 290M. The logs say which check failed.
2026.11.8
2026-11-08
- A model download that was interrupted, for example by reloading the page halfway, no longer stops every model from loading. wllama 3.8.1 checks every model in its cache before loading any, and throws on the first one that misses a file; before each load, MiniSearch now deletes the files of models whose download did not finish, so only that model downloads again.
- The default system prompt's citation example is now a placeholder,
[example.com](https://example.com/page), instead of a real YouTube video link that small models copied as if it were a source. On the benchmark's eleven core questions, over 110 answers from five small models, links to URLs that are not among the results fell from 12 to 7, the YouTube link disappeared, and the share of answers citing a result stayed level (48% before, 50% after). A saved prompt that is exactly the previous default moves to the new one; an edited prompt stays as it is. - Four models leave the Wllama catalog because they answer worse than LittleLamb 290M, the default for browsers without WebGPU and the catalog's quality floor: StableLM 2 Zephyr 1.6B, SmolLM 2 135M, Granite 4.0 350M and Pints 1.5B (16 to 25 points out of 84 on the benchmark, against 38 for LittleLamb). Granite 4.0 1B goes too: on WebGPU it writes only
@characters until it is stopped, though it answers well on the CPU.docs/wllama-model-evaluation.mdnow holds the scores of every catalog model and the rule that decided. - A browser whose saved settings point at a model that left the catalog switches to the default model on its next answer, and records the switch in the logs. Before, it failed to answer at all.
- Browsers with WebGPU now start on their own default model, Gemma 3 4B, set with the new
WLLAMA_DEFAULT_GPU_MODEL_ID; browsers without it keep LittleLamb 290M fromWLLAMA_DEFAULT_MODEL_ID, which runs well on the CPU. Both only seed a profile that never saved settings. The GPU variable does not fall back to the CPU one, because.env.examplesets that one and most deployments would otherwise hand GPUs the CPU model; a deployment that pinnedWLLAMA_DEFAULT_MODEL_IDand wants the same model on GPUs should set both. Gemma 3 4B scored highest of twelve GPU candidates on the benchmark (docs/wllama-model-evaluation.md), with every point in two runs of fifteen questions in eleven languages, and on WebGPU it started answering in about 8 seconds. - Qwen 3.5 0.8B (533 MB) joins the Wllama catalog. On the benchmark's eleven core questions it scored 70 of 84 (one run), above larger models such as Qwen 3 1.7B (66) and Granite 4.2 3B (59), and on WebGPU it writes about 32 tokens per second. Like Qwen 3.5 4B it ignores
reasoning_effort, so it thinks for the full 1024 tokens before most answers (about 33 seconds on an Apple M1 Max). - The README and the docs no longer give a number of models or a size range, so adding or removing a model does not leave them out of date.
- Thinking models get a 1024-token reasoning budget instead of 256, because a chain of thought cut off that early degraded the answer. Every model is also asked for
reasoning_effort: "low", which Granite 4.2 and Spark X2.6 honor by thinking less; the other templates ignore it. Five models that think by default had no budget at all and now get the same 1024 tokens: LittleLamb 290M, Qwen 3 0.6B, Qwen 3 1.7B, Polaris 4B and DeepSeek R1 Distill Qwen 1.5B. LittleLamb, the default for browsers without WebGPU, thought for up to 3,663 tokens on a single answer and sometimes never answered; with the budget it answered all 33 questions of three benchmark runs.
2026-11-05
- Relative month and year words in a query are anchored to absolute ones before the search leaves the browser: "next month" reaches the engines as "December 2026" and "明年" as "2027年". The anchor is appended rather than substituted, so a query that already names a year keeps its own phrasing, and two anchors per query is the ceiling. The typed query still drives the prompt, the UI, and the history entry; only the copy sent to the search engines changes, and the search cache key changes with it. Anchors skip titles and phrases that are not dates ("明年今日", "登上月球", "the last year of college") and leave "recent" and "latest" alone, because recency is what the engines already rank for. Day words ("tomorrow", "明天") stay as typed: their anchor would be an ISO date, which pages rarely write, and many queries use them as names ("usa today"). Only English and Chinese phrases are recognized.
shared/relativeDates.tsholds the rules andclient/modules/textGeneration.tsapplies them. - The page reader drops structural navigation before it extracts text:
nav,aside,header,footerandformblocks go, and so does any block whose text is mostly links (60% or more, in blocks of 120 characters and up), judged innermost-first so a page-wide wrapper cannot take the article down with it. Inside an<article>, a<main>or arole="main"block, link density removes nothing, because a list of linked titles there is usually the answer itself. The page's title and h1/h2 words also join the passage score at 0.15 weight, so a page whose heading names the query breaks ties against its own navigation. On the sortiraparis December page the extracted text fell from 57,160 to 2,128 characters and the answering passage moved from 10th of 61 to 3rd of 8, which is what puts it inside a page's excerpt share. A link-list home page now contributes far less body text, and the reader accepts that trade: a thin excerpt beats one made of navigation links. - A result from the site the query names gets a bonus on its semantic score before the score filter: +0.5 when a query word equals the domain's label ("disney" and disney.com, subdomains included), +0.75 when the label is the query's own words joined ("disney plus" and disneyplus.com, "coca cola" and coca-cola.com). The bonus is added rather than multiplied because the reranker returns a raw logit that is usually negative, where a factor above one would demote the named site instead of promoting it. Substrings do not count (disneyfan.com gets nothing), filler words never match on their own (plus.com, news.com), and a query that names a year will not promote a page that states a different year, so a brand's recap of last year's event cannot displace fresher reporting; a page that states no year at all keeps the bonus, because relative-time queries are anchored to a year before they reach the search. A label that spells only the start of the query leaves words unused and gets nothing (
tesla investor relationsand teslainvestor.com), a label that starts with a filler word is skipped (the disney storeand thedisney.com), a split label counts from four characters, and a trailing dot on the hostname changes nothing. The site's name comes from the public suffix list, private section included (thetldtspackage), so bbc.co.uk answers "bbc" and a tenant of a shared host such as someone.github.io answers its own name, not "github". The pinned top result is never boosted, so the score spread the client reads relevance tags from keeps its shape. The reranker still never sees the URL, and a result the search did not return cannot be added here: the boost reorders and re-selects what the pipeline already holds, which is enough to move a page into the six the model reads.server/authorityRanking.tsholds the rule anddocs/reranking.mdrecords it. - A text search that asks for an official page can now reach the official site even when the engine's results never included it, behind a new setting,
SEARCH_OFFICIAL_LANE_ENABLED, which is off by default because it sends the engines a second request. When it is on, the query carries navigation intent (官网,排片,营业时间,official,hours,showtimesand the like, in Chinese and English only), and one of the returned results names a site, the server sends a second,site:-scoped query to SearXNG and merges up to three of its results, deduplicated by URL and kept to that registrable domain, behind the pinned first result: the ranking re-sorts only what follows the top result, so a page appended past that window would never be re-sorted at all. The domain has to come from the results themselves, by the same rule the score bonus uses, because guessing<token>.comfrom the query would turn a search box into a scanner; a query that names a brand whose official site is absent from every result gets no second query. The second query is one request with no retry, and its failures count toward neither the SearXNG circuit nor the engine health in/status, so it cannot slow down or degrade the searches users are waiting on. SearXNG still sees the extra request, so an engine that suspends the instance after a CAPTCHA does so for every search. It runs only when SearXNG served the search (never after the fallback), never uses the last five seconds of the search deadline, and is canceled at eight seconds; a failure only logs and is counted, so it can add results but never turn a served search into a 502./statusreportssearches.officialLane(searches,resultsAdded,failures), andserver/officialLane.tsholds the rule.
2026.11.3.1
2026-11-03
- 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_contentchannel 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. - The same five models now cap their chain of thought with
reasoningBudgetTokens(wllama'sreasoning_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.
2026.11.3
2026-11-02
- Five new browser models joined the Wllama catalog: Spark X2.6 1.7B, Granite 4.2 3B, Qwen 3.5 4B, Gemma 4 E2B and Spark X2.6 4B, each tested end to end against the shipped wasm build with the search-answer prompt. The Gemma 4 and Qwen 3.5 architectures were previously absent from the catalog, and the new entries run on the wasm engine's supported architectures (
gemma4,qwen35,spark2_5,granite). Models whose chat template thinks by default ship withchatTemplateKwargs: { enable_thinking: false }, a new per-model field passed to wllama aschat_template_kwargs, because MiniSearch renders only the content channel and a thinking template would otherwise spend the whole token budget on reasoning and answer with nothing.docs/ai-integration.mdnow records the two measured ceilings a candidate must fit (shard files under 2000 MiB, since Chromium's OPFS silently truncates beyond it; total weights under ~3.7 GB, since the wasm linear memory caps at 4 GiB), andnpm run wllama-catalog-checkHEADs every shard of every catalog model on HuggingFace to verify the claimed sizes.
2026.10.20
Release 2026.10.20. See changelog.md for notable changes, and the compare view for the full commit list.
2026.10.11
2026-10-10
- The text-search fallback now cascades over Parallel and You.com instead of asking a single provider. On each search the configured providers are tried in a random order, one after the other, until one returns results, under the same 15-second budget, which is split across the providers still untried and not paused so a hanging one cannot starve the rest. A provider that answers HTTP 429 is paused until its
Retry-Afterand skipped meanwhile, as You.com's acceptable use policy asks. A single search can now reach more than one provider; each sees the query text and this server's IP address, never the user's.SEARCH_FALLBACK_PROVIDERSpicks the providers (all of them when empty), andSEARCH_FALLBACK_PARALLEL_API_KEYandSEARCH_FALLBACK_YOUCOM_API_KEYhold the optional keys.SEARCH_FALLBACK_PROVIDERandSEARCH_FALLBACK_API_KEYare removed: if either is still set while the fallback is enabled, the server stops at start with an error naming the replacement, and so does a provider key with a control character inside it./statusgained per-provider counters undersearches.fallbackProviders.
2026.10.8
2026-10-08
/statusnow reportsauthorization.distinctRejectedTokens, the number of distinct dead tokens the server has cached and keeps refusing. A steady stream of invalid-token rejections with a value of 1 there is one client replaying one stale token, not many old search links, which the existing counters could not tell apart.- Added an optional second source for text searches, so a SearXNG outage no longer has to end in a 502. It stays off unless
SEARCH_FALLBACK_ENABLEDistrueor1, and flipping it takes a restart, since a process keeps the environment it was started with. When it is on, the second source is consulted only after SearXNG has failed (an HTTP error, a network error, every engine unresponsive, or an open circuit), under one 15-second budget for the whole exchange and under a 25-second deadline measured from the start of the search, and only for text searches: image searches still answer 502 as before. The query goes tosearch.parallel.ai, which sees the query text and this server's IP address, never the user's. A retry that comes back with nothing usable now answers HTTP 200 with no results, so the UI shows "No results found" rather than "Text search unavailable"; a retry that fails itself, or that the search deadline has left under two seconds for, falls through to the old 502.SEARCH_FALLBACK_API_KEYis optional and is sent as a Bearer token, which raises the provider's free-tier rate limits./statusgainedsearchesServedByFallbackandsearchesFailedOnFallback, plain counts that never carry a query, so you can see whether the second source is earning its place.
2026.10.7
2026-10-07
- Security: cleared the flagged copy of
postcss-selector-parserthat lives inside the npm the image ships. npm pins its own dependency tree exactly, so neithernpm install -g npm@latestnor a dependency bump reaches a bundled copy, and the npm in the image still carried 7.1.4. This was the one of the image's three code scanning findings that no dependency bump could fix. The image's npm-bundle repair now lists that package among its targets, so the build replaces the bundled copy with the patched release and fails if any copy of that major line survives.
2026.10.6
Release 2026.10.6. See changelog.md for notable changes, and the compare view for the full commit list.
2026.10.2
Release 2026.10.2. See changelog.md for notable changes, and the compare view for the full commit list.