Release Notes
v0.4.0
The headline of this release is a rebuilt Chat experience in the operators console.
Added
- Rebuilt console Chat (#186). Chat is now a persistent, multi-provider assistant instead of a single throwaway turn list.
- Redesigned chat UI. A centered conversational column caps both the transcript and the composer, user turns read as right-aligned pills and assistant turns as plain prose, and Send moved inside an auto-growing composer. A conversation rail adds New chat, switching, auto-titling from the first message, rename, delete, and recency grouping; conversations persist in browser-local storage (single-tab correctness; cross-tab is best-effort, last-writer-wins).
- Markdown rendering. Assistant answers render as Markdown — headings, lists, tables, and syntax-highlighted code — instead of raw text.
- Three assistant tools.
list_documentsanswers corpus questions ("how many documents do I have") with an exact count instead of guessing from search hits;search_documentsruns filtered retrieval and reports how many chunks matched;get_document_textpulls one document's text or metadata on demand. - Citations grouped by document. Inline numbered markers with a click-to-open preview card and an on-demand full source list replace the always-expanded Sources block. Document indexes stay stable across a turn.
- Bring-your-own-key across providers. OpenRouter, OpenAI, Anthropic, and Google, with a searchable provider-grouped model picker and error messages that distinguish a bad key, an unsupported model, and a rate limit without leaking provider detail. The key stays in the browser session and is never written to conversation storage.
- Neutral corpus phrasing and a consistent assistant voice. The assistant describes the indexed corpus in neutral terms and answers in one voice across providers and models.
- Embedding provenance and repair (#184). Every embedded point is stamped with a filterable pipeline version plus model, runtime, chunker, and extraction provenance. Client-scoped dry-run and apply tooling backfills legacy points honestly and re-embeds targeted documents from stored chunk text, with the provenance surfaced in the console.
- Cited document chat (#183). The Chat view that #186 rebuilt first shipped here: a stateless BYOK chat route that runs a capped search tool loop against
/searchand streams answers with citations to real document ids and snippets. - Deployed version in the console (#181). The sidebar footer shows the product version reported by
/health, so operators can confirm which release they are on. - LAN access for the console (#171). The console's published port can bind all host interfaces while the backend stays on the internal Compose network. The console still has no app-level auth — it relies on LAN trust or an external auth boundary.
- Private, repeatable console deployment (#167). A non-root standalone Next.js image runs as a loopback-bound production Compose service, resolving the server-only API key from the existing backend mapping.
Fixed
- Disconnecting an OpenRouter key now really removes it (#187). The key was stored under a newer namespaced entry, but a legacy entry was still migrated forward on read and was not cleared on disconnect — so an operator who disconnected could be silently reconnected with that key on the next reload. On a shared workstation that could be someone else's key. Disconnect now clears both entries.
- Hybrid search recall on clean corpora (#170). The dense pre-RRF confidence gate dropped from 0.75 to the calibrated 0.70 (sparse stays at 1.0) and the omitted-
alphapath is locked at 0.5, undoing a regression that returned no results for most queries. Nonsense queries still return nothing. - Document Details panel on long documents (#176). Aggregated entities were rendered once per mentioning chunk with no cap — one annual report produced a 37,446px entity block that pushed the extracted text 41 screens down. Entities are now deduplicated case-insensitively and previewed 12 at a time behind a "+N more" disclosure (nothing is discarded), and reading mode skips layout for off-screen chunks. Measured on the same 2,108-chunk document: entity block 37,446px → 773px, forced layout 197.7ms → 9.5ms.
- Search rail fits above the fold (#175). Console search controls are seated so every control is reachable without scrolling.
- Four WCAG failures in the console (#174). The document drawer no longer re-announces a chunk's full text, entities, and vectors to screen readers on every selection, and the drawer's focus and scroll behavior match what it advertises.
- Search pagination docs and CLI (#172, #178). The
/searchendpoint description, field docs,just search, and the search recipe now state the shipped 200-result retrieval window instead of promising unbounded offsets and totals; the CLI no longer builds requests the API rejects with 422. .envbackups can no longer be staged (#173)..gitignorecovered.envbut not the timestamped.env.bak.*files editors leave behind, which held a full copy ofAPI_KEY_CLIENTS. Nothing leaked.
Maintenance
- Product version bumped to
0.4.0through the supported path (pyproject.toml,uv.lock,openapi.jsonin sync). - CI trimmed to the checks currently in use; the disabled jobs' bodies are intact behind an
if: falseand are documented for re-arming (#188, #165). - Frontend test stability work on the document viewer (#179, #180).
Upgrade Notes
-
Rebuild and restart so the new version and console build are active:
just prod-down
just prod-up rebuild -
Documents embedded before this release carry legacy provenance until backfilled or re-embedded (#184).
-
Existing chat conversations start empty: conversation history is new in this release and is stored per browser.
Confirm the Running Release
Check /health or /openapi.json and confirm the reported version is 0.4.0. The console sidebar footer shows the same value.
v0.3.1
Fixed
- Hybrid search ranking. The effective default
alphais now0.5instead of behaving as0.70, restoring the intended balance between dense semantic and sparse lexical ranking. - Relevance filtering. Clean-corpus floors were recalibrated after a regression made hybrid search return no results for about 13 of 15 queries. The dense floor is now
0.70, down from0.75, while the sparse floor remains1.0. Genuine matches are no longer over-filtered, while gibberish and other queries with no confident match still return no results.
Changed
- Product version. The product version is now
0.3.1(up from0.3.0).
This is a search-regression fix-up release. No other user-facing changes are included.
Upgrade Notes
-
Rebuild or restart the service after updating so the new search defaults and product version are active.
just prod-down
just prod-up rebuild
Confirm the Running Release
Check /health or /openapi.json and confirm the reported version is 0.3.1.
v0.2.0
Added
-
Reversible document deletion.
DELETE /document/{document_id}now performs a soft delete by default. Soft-deleted chunks are hidden from normal search and document listing, but can be restored withPOST /document/{document_id}/restore. -
Hard delete mode. Callers that need physical removal can still pass
mode=hard:curl -X DELETE "http://localhost:8000/document/doc-123?mode=hard" \
-H "X-API-Key: super-secret-key" -
Deleted-document views. Use
include_deleted=trueon search or document listing when building an own-client trash or audit view. This flag does not widen client isolation. -
Version-scoped document operations. Upload metadata can include
version_id, and document delete or restore calls can target a specific version with?version_id=<value>. Omittingversion_idapplies the operation to all live versions of the document for the authenticated client. -
Office file ingestion. The upload pipeline supports PowerPoint and Excel content through native
.pptxand.xlsxparsing. Legacy.pptand.xlsconversion is available when LibreOffice conversion is explicitly enabled. -
Search result highlights. Search requests can set
highlight: trueto receive matched-term spans for returned chunk text. -
Runtime version visibility.
GET /healthnow returns the Product Version, and/openapi.jsonexposes the same value asinfo.version, making it easier to confirm which release is running after an update or rollback.
Changed
- Release version source of truth. The Product Version is managed from
pyproject.tomland checked withjust version-check, so runtime metadata,/health, OpenAPI, and lock metadata stay aligned. - Production runtime sizing. Production startup generates host-aware runtime settings before launching the API and workers.
- Status tooling.
just statusincludes richer local, Docker, JSON, and live status modes for checking API, Redis, Qdrant, and worker health.
Upgrade Notes
-
A plain
DELETE /document/{document_id}no longer physically removes vectors. Usemode=hardonly when permanent removal is required. -
For significant updates, including this version bump, rebuild production services after pulling the release:
just prod-down
just prod-up rebuild -
After restarting, verify the running service version with:
curl http://localhost:8000/healthThe response should include
"version": "0.2.0".
Confirm the Running Release
After updating, confirm the API is serving v0.2.0 from public runtime surfaces:
curl http://localhost:8000/health
curl http://localhost:8000/openapi.json
The health response should include "version": "0.2.0", and the OpenAPI response should include "info": { "version": "0.2.0" }.