7.0 KiB
🔒 Security
- Extended the cloud-metadata IP absolute-block in
NotificationURLValidatorto Apprise plugin schemes (signal, gotify, ntfy/ntfys, mattermost, rocketchat, matrix, json, xml, form, mailto). Previously only the http/https branch ran the IMDS guard, so a notification URL likesignal://169.254.169.254/...would round-trip to Apprise even though Apprise translates it into a plain HTTP request against that host. LAN/loopback reach for self-hosted plugin endpoints (the #4006 use case) is unchanged. - Fix Google Gemini API key leak in
list_models_for_apierror log. The URL constructed at request time embeds the key as a?key=...query parameter (per Google's documented API), so when the underlying request failed, therequestsexception message — and therefore thelogger.exception(...)traceback — contained the full URL with the key. The except handler now redacts the key from the message and useslogger.warning(no exception chain).
🐛 Bug Fixes
-
JavaScript rendering disabled by default in the production Docker image (#3826). The headless-browser fallback in the content fetcher (Crawl4AI/Playwright) was previously attempted on every fetch even though the default Docker production image ships without a Chromium binary - each attempt failed loudly and contributed to the memory growth reported in issue #3826. A new
web.enable_javascript_renderingsetting (defaultfalse) gates the fallback. In limited (mostly accidental) internal benchmark comparisons - between dev instances that happened to have Chromium installed and routine Docker runs that did not - JS rendering did not measurably improve research quality, and most regular benchmark runs are on Docker without Chromium anyway, so the change does not regress observed quality. To enable: install Chromium in the runtime environment (playwright install --with-deps chromium) and toggle the setting in the UI. (#3826) -
Embeddings now work against OpenAI-compatible local servers (LM Studio, vLLM, llama.cpp). Previously the OpenAI embeddings provider only listed itself as available when an API key was configured, and the relevant
embeddings.openai.*settings were not registered for the UI to surface — so users who ran an OpenAI-compatible local server had no way to point the embeddings tab at it. The provider now also reports available when onlyembeddings.openai.base_urlis set, substitutes a placeholder API key for keyless endpoints (matching the LM Studio LLM provider's behavior), and ships a newsettings_openai_embeddings.jsondefaults file that registersembeddings.openai.api_key,embeddings.openai.base_url,embeddings.openai.model, andembeddings.openai.dimensions. The model-list lookup now routes through the configuredbase_urlso model discovery also targets the local server. (#3883) -
"Start Research" button no longer silently does nothing for users with a non-multiple-of-512 context window value. The hidden
context_windowinput on the research form had astep="512"constraint, so any stored value not aligned to that grid (e.g.25000) failed HTML5 form validation. Because the input lives inside adisplay:nonecontainer that is only shown for local providers, the browser could not focus the invalid field to report the error, so submission was aborted with no visible message and no log line — the click appeared to do nothing. Relaxed the step to1so any in-range integer is accepted; the value is still bounded bymin/maxand persisted unchanged. (#3909) -
Chinese/Japanese/Korean text now renders in exported PDFs. The default PDF stylesheet hard-coded a Latin-only font stack, so any CJK characters in the research result were dropped silently from the download even though they displayed correctly in the browser. The minimal CSS now includes a broad CJK fallback chain (Noto Sans CJK, PingFang, Hiragino, Apple SD Gothic Neo, Microsoft YaHei/JhengHei, Yu Gothic, Malgun Gothic, SimSun) covering Windows, macOS, and Linux desktops out of the box, and the Docker image now installs
fonts-noto-cjkso the slim base image has glyph coverage. Linux pip/server installs still need a CJK font package on the host — see install-pip.md and the FAQ for the per-distro commands. (#4055) -
Cross-engine filtering now keeps LLM ranking fallbacks within the subset of results the model actually evaluated, preventing unevaluated search results from leaking into downstream synthesis.
-
Fix file-descriptor leak (
anon_inode:[eventpoll]) in_close_base_llmwhen invoked while an asyncio loop is running. The previous code path skipped the async-client close in that case and documented that the "loop owner" would close instead — but no loop-owner cleanup actually exists in the project, so the innerhttpx.AsyncClient(and itsepoll_createFD) was silently abandoned. The same skip-path fires under the defaultlanggraph-agentstrategy because LangGraph dispatches some tool steps via asyncio internally, so close calls reached from a syncfinallycan still land inside a live loop. Cleanup now runs in a brief daemon thread that owns its own loop, soasyncio.run(aclose())works regardless of the caller's loop state; a bounded 5-secondjoinkeeps it from holding up shutdown if the Ollama server is unresponsive. This is the gap left by #3855's coverage of #3816 — same leak class, different code path.Also fixes a smaller secondary leak in the Docker
HEALTHCHECK:urllib.request.urlopen('http://localhost:5000/api/v1/health')had notimeout=argument, so when the app slowed down (FD exhaustion or otherwise) Docker's 10s healthcheck timeout SIGKILL'd thesh -cwrapper but the python child got reparented to PID 1 and hung forever, each contributing apidfdand a TCP socket against the app. Addingtimeout=8lets the child return/raise before Docker's wall so it exits cleanly and gets reaped.
📝 Other Changes
- Added a "Testing a Release Candidate (Prerelease Image)" subsection to the developer guide (
docs/developing.md) covering both the floating:prereleaseand immutableprerelease-vX.Y.Z-<sha>Docker Hub tags, with a side-by-side compose snippet that runs the RC on port 5001 with isolated volumes so a broken migration cannot affect a production instance. - Pool-dispose failures in the periodic WAL/SHM handle-release workaround (ADR-0004) now log at
WARNINGinstead ofDEBUGso silent drift becomes visible. Documented indocs/CONFIGURATION.mdthatLDR_APP_DEBUG=truealso enables Logurudiagnose=True, which can materialise sensitive locals into exception traces — do not enable in production. - Refactored environment settings to use specialized exception classes, improving error observability and alignment with
TRY003standards.