Skip to main content

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_documents answers corpus questions ("how many documents do I have") with an exact count instead of guessing from search hits; search_documents runs filtered retrieval and reports how many chunks matched; get_document_text pulls 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 /search and 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-alpha path 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 /search endpoint 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.
  • .env backups can no longer be staged (#173). .gitignore covered .env but not the timestamped .env.bak.* files editors leave behind, which held a full copy of API_KEY_CLIENTS. Nothing leaked.

Maintenance

  • Product version bumped to 0.4.0 through the supported path (pyproject.toml, uv.lock, openapi.json in sync).
  • CI trimmed to the checks currently in use; the disabled jobs' bodies are intact behind an if: false and 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 alpha is now 0.5 instead of behaving as 0.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 from 0.75, while the sparse floor remains 1.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 from 0.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 with POST /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=true on 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>. Omitting version_id applies 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 .pptx and .xlsx parsing. Legacy .ppt and .xls conversion is available when LibreOffice conversion is explicitly enabled.

  • Search result highlights. Search requests can set highlight: true to receive matched-term spans for returned chunk text.

  • Runtime version visibility. GET /health now returns the Product Version, and /openapi.json exposes the same value as info.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.toml and checked with just 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 status includes 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. Use mode=hard only 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/health

    The 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" }.