Skip to content

Releases: SemplificaAI/MikeRust

v0.5.6 — Chat composer UX fixes

08 Jun 09:46

Choose a tag to compare

MikeRust v0.5.6 — Chat composer UX fixes

Two bug fixes in the chat composer that surfaced during hands-on
testing of the v0.5.5 cycle, plus an opt-in experimental local-only
LLM mode for Ollama users (off by default).

Bug fixes

Doc picker — project scope

The "Sfoglia tutti" picker inside a project-scoped chat used to show
every document the user had ever uploaded anywhere — including
documents from other projects and standalone-chat attachments. It
now restricts to the current project's documents via the existing
?project_id=… filter in documents.rs::list_documents.

Standalone chats (Assistant tool, no project attached) keep the
global picker unchanged — that's the path the user takes to add a
library-wide doc to a fresh conversation.

New-chat-in-project confirm modal

Clicking + (new chat) in the sidebar while a project-scoped chat
was active used to silently inherit the project on the new chat —
the user had no way to know the chip had carried over until they
glanced at the composer. Reported as confusing.

The new flow:

  • If the active chat is in a project, clicking + now opens a
    confirm modal: "Stai lavorando dentro un progetto. Vuoi
    mantenere il progetto associato alla nuova chat?"
    with two
    action buttons — Chat indipendente / Sì, mantieni il
    progetto
    — and implicit cancel via the X / Esc / backdrop
    click.
  • If the active chat is not in a project, the flow is unchanged
    (no modal, instant new chat).

Internally this also fixes the long-standing "chip persists
silently" bug where the composer's $effect early-returned on a
null activeProjectId instead of clearing the chip. A new monotonic
chatStore.clearProjectTick lets the modal's "Chat indipendente"
branch reset the chip without race conditions.

New (opt-in, experimental)

Local-only LLM mode for Ollama users

New toggle in Settings → Modelli LLM → "Modalità sicura locale".
Off by default, retro-compatible with existing local-provider
configurations.

When on:

  • The local provider's base URL is locked to http://localhost:11434
    (loopback only — refuses LAN endpoints or public IPs).
  • The chat composer's model picker collapses to two curated entries
    (Qwen 3.5 4B q4_K_M and Gemma 4 E2B IT GGUF Q4_K_M), both
    derived through Ollama Modelfiles MikeRust creates on demand with
    thinking suppression baked in.
  • Install / cancel / parallel-download UX directly from Settings,
    with real-time progress streaming.

Backed by:

  • New module src/llm/ollama_manager.rs
    wrapping ollama-rs 0.3.
  • Schema migration 0032 — adds user_settings.local_secure_mode INTEGER DEFAULT 0.
  • 13 new unit tests across llm::local and llm::ollama_manager
    (15/15 + 6/6 green).

Treat this as an experimental preview for the v0.6.x line. The
mechanism is feature-complete and tested, but the UX around model
discovery / context-window tuning / cross-platform Ollama detection
is still being refined. Power users who want to try it can flip the
toggle; everyone else can ignore it — the rest of the local
provider works exactly as before.

Downloads

Pre-built MSIs for Windows:

  • MikeRust_0.5.6_x64.msi — Windows x86_64
  • MikeRust_0.5.6_arm64.msi — Windows ARM64, Snapdragon X Elite
    native

Drop-in replacement for v0.5.5.

Migration notes

  • New schema migration 0032 is applied automatically on first
    launch. The only column added defaults to 0 — existing installs
    preserve their custom Ollama URL and free-form model id.
  • New direct dependencies: ollama-rs = 0.3 (with stream) and
    async-stream = 0.3. Both pure Rust, no native libs added.

License

MikeRust is distributed under AGPL-3.0-only. The Semplifica
wordmark and logo are trademarks; see NOTICE.md. The full
licence text is available in-app under Settings → Licenza.

v0.5.5 — stable consolidation of the v0.5.4 amendment cycle

07 Jun 13:57

Choose a tag to compare

MikeRust v0.5.5

Stable consolidation of the v0.5.4 amendment cycle. The v0.5.4 tag
was force-rewritten several times as fixes were appended
(back-stack regressions, untrack boundaries, export-shape gaps,
tabular review rename); v0.5.5 marks the end of that iteration with
a clean, non-rewritten tag.

What's in v0.5.5

Everything from the v0.5.4 cycle — see the v0.5.4 release notes for
the full per-feature breakdown — plus the final polish landed
during the same testing session:

Closed .mikeprj export-shape gaps

The v0.5.4 audit ("Known gaps" section in the v0.5.4 release notes)
called out fields the exporter wasn't reading or was
reading-and-discarding. All fixed:

  • ProjectRecord gains domain and isolation_mode — the
    recipient lands on the same domain filter and retrieval-scope
    mode the source project had.
  • DocumentRecord gains domain, project_folder_id (path
    hint), and the accept/reject decision tuple from migration 0029
    (decision, decision_reason, decision_summary).
    content_hash is rehydrated on import from the manifest's
    sha256 so tabular dedup-by-hash works immediately.
  • TabularReviewRecord gains domain (review-level — can diverge
    from the project's).
  • WorkflowRecord gains domain. The exporter also stops
    hard-coding type = "assistant" and discarding columns_config
    — a custom tabular workflow finally travels intact.

All new fields are Option<…> with #[serde(default)] so older
archives still deserialise cleanly. Two new back-compat tests pin
the behaviour; 21/21 mikeprj tests green.

Tabular reviews — per-row Pencil rename

The Revisioni tabellari list view gains a Pencil icon between the
domain Badge and the Trash on every row — parity with the
Projects-list rename affordance. Opens a small inline modal with
the current title pre-filled, Enter submits, Escape cancels, Save
is disabled when the input is empty or unchanged. New i18n keys
TabularReviews.renameReview and TabularReviews.renamedToast
localised in all six locales.

What v0.5.5 inherits from v0.5.4

The full v0.5.4 work ships in v0.5.5 — to recap the highlights:

  • Tabular extraction now works for ANY upload path — the new
    "Upload" button in the doc picker lets the user upload directly
    from the filesystem; the previously silent load_document_text
    failures (relative storage key + missing extension defeating
    pdfium) are fixed with absolute-path resolution and
    file_type-driven extension synthesis.
  • Schema hotfix — migration 0031 drops the residual FK on
    tabular_reviews.workflow_id → workflows(id) that blocked
    every preset-based "Nuova revisione" with SQLite error 787.
  • Per-row tabular dedup on re-upload — adding a document that
    is byte-identical to one already extracted in the same review
    (filename + SHA-256 content_hash) inherits the earlier row's
    cells instead of re-running the LLM.
  • Project-flow polish — "Nuova revisione" inside a project,
    scope-correct doc picker (domain + project_id + global rules),
    per-row Export icon on the Projects list, "Importa progetto"
    button on the Projects header.
  • Generic router back-stack — drill-downs always return to the
    originating screen. First consumer wired is Chat-from-Project →
    "Torna a {nome progetto}". The navTick signal handles
    re-navigation to the same route (sidebar accordion clicks);
    every mutating router method runs inside untrack(…) so callers
    inside $effect bodies don't accidentally loop on the
    read-modify-writes.
  • Sidebar "Progetti recenti" accordion — top 5 projects by
    updated_at DESC between the tool nav and the existing Chat
    recenti accordion.
  • PickerModal select-all / deselect-all — multi-select pickers
    gain a toggle bar between the search input and the list. Scope
    is the visible (search + filter applied) set.

Downloads

Pre-built MSIs for Windows:

  • MikeRust_0.5.5_x64.msi — Windows x86_64
  • MikeRust_0.5.5_arm64.msi — Windows ARM64, Snapdragon X Elite native

Drop-in replacement for v0.5.4 (and any of its force-retag drops):
same database schema (migration 0031 still the latest), same
on-disk paths, same config.

Migration notes

  • No new database migration. Schema unchanged from v0.5.4.
  • v0.5.4 users: install MikeRust_0.5.5_*.msi on top.
  • v0.5.3 and earlier: same — the auto-migration runs on first
    launch.

License

MikeRust is distributed under AGPL-3.0-only. The Semplifica
wordmark and logo are trademarks; see NOTICE.md. The full licence
text is available in-app under Settings → Licenza.

v0.5.4 — tabular-review FK hotfix + four UX up# MikeRust v0.5.4

05 Jun 22:16

Choose a tag to compare

MikeRust v0.5.4

Bundle release on top of v0.5.3. What started as a single SQLite
schema hotfix grew into a full tabular-review pass after the same
testing session surfaced the biggest practical bug: tabular
reviews could only analyse documents that had previously been
attached to a chat or uploaded into a project — files dragged in
directly from the filesystem went through a different storage path
and silently failed extraction, leaving every cell as "Document
text unavailable". v0.5.4 fixes that, adds in-place upload from the
review's own picker so the user no longer has to bounce through a
chat, and dedups re-uploads so identical content doesn't get
re-extracted by the LLM. Layout and a couple of UX upgrades came
along for the ride.

Highlight — tabular extraction now works for ANY upload path

The previously hidden contract was: only documents that went through
the chat/project flow (cache-based storage layout with text
extracted at upload time and a sidecar .txt persisted alongside)
worked in tabular reviews. Files uploaded by other means used the
legacy cache=false storage layout — documents/<uid>/<doc_id>
with no extension and no extracted-text sidecar. When the
extraction job tried to read those it hit two cascading bugs in
load_document_text:

  1. The storage key was being passed as-is to
    extract_text_dispatch. That key is a relative path (e.g.
    documents/<uid>/<doc>); pdfium needs an absolute on-disk
    path to open a PDF, so every PDF failed silently and the row
    surfaced as "Document text unavailable".
  2. The dispatcher dispatches on the path's file extension. The
    legacy key has none, so even after fixing the absolute-path
    problem the dispatcher fell into the catch-all branch and
    returned "format not supported".

Both legs fixed:

  • The storage key is now resolved to an absolute path under
    STORAGE_PATH / default_storage_path() before dispatch.
  • The query also reads file_type from the documents row. When
    the on-disk path has no extension, a sibling with the right
    suffix (.pdf / .docx / …) is materialised so pdfium can open
    it directly and the dispatcher's extension match hits the right
    branch.

Exhaustive [tabular][doc-text] tracing was added at every branch
(sidecar hit, sidecar miss, storage.get failure, extension
synthesis, dispatch result, skip reason) so the next regression
surfaces in mike-tauri.log directly.

This unblocks the new "Upload" button in the tabular-review doc
picker (see "Upload affordance inside the doc picker" below): files
the user drags in from the filesystem now get extracted just like
chat-attached or project-attached docs.

Schema hotfix — preset workflows blocked tabular-review creation

Tabular-review creation against preset workflows

Picking any of the 49 built-in workflow presets (legal, insurance,
medical-legal, finance) in the "Nuova revisione" modal returned

error returned from database: (code: 787) FOREIGN KEY constraint failed

directly in the modal and refused to create the review.

The root cause was a residual foreign key from the v0.1.0 schema:

CREATE TABLE tabular_reviews (
    ...
    workflow_id TEXT REFERENCES workflows(id) ON DELETE SET NULL,
    ...
);

Built-in workflows live as JSON manifests under
config/workflow-presets/ and are merged into the registry
in-memory at startup — they intentionally never own a row in the
workflows table. We hit and fixed the same pattern on
workflow_hidden in migration 0022; tabular_reviews carried the
same FK and the bug had been latent since the JSON-preset registry
shipped.

New migration 0031 rebuilds tabular_reviews dropping the
workflow_id FK while keeping the user_id / project_id
references intact and preserving all existing data plus the
domain index. After the migration runs once on first launch of
v0.5.4, workflow_id is a free text id that resolves either against
the DB workflows table (user-created workflows) or the in-memory
preset registry (built-in workflows).

No frontend / backend code change — the route handler was already
binding workflow_id as a free string. No behaviour change for any
existing review.

UX upgrades from the same testing session

Four quality-of-life improvements landed alongside the schema fix
because they touch the same screens:

Workflow picker now labels Tabellare vs Assistente

The chat composer's "Allega un workflow" modal renders a coloured
pill on the right of each row — Tabellare in purple, Assistente in
blue, using the brand-audit Badge tones that already existed but
hadn't been surfaced. Identifies workflow kind at a glance without
opening the workflow.

Upload affordance inside the doc picker

The "Aggiungi documenti" modal on the tabular-review detail page
gains an "Upload" button bottom-left. Selected files upload
sequentially via documentsApi.upload, refresh the picker list, and
are automatically linked to the review — the user does not re-tick
files they just uploaded. The "Conferma" button now stays enabled
even with zero items ticked once an upload has succeeded during the
session, so the user has a clean way out (Cancel implied undo of an
action that had already committed).

Import Project button on the Projects list

A secondary "Importa progetto" button next to "Nuovo progetto"
triggers a .mikeprj file picker, reusing the email-prompt modal
that was previously reachable only by drag-and-dropping a .mikeprj
file onto the page. The POST /project/import endpoint and the
ProjectImport.* i18n catalogue were already complete since
v0.4.x — this just makes the affordance discoverable.

Tabular layout + dedup polish

Tabular detail — full-width layout

The grid no longer constrains itself to max-w-6xl (~1152 px).
Header and table fill the available container width — wide monitors
stop wasting 60%+ of the horizontal real estate. The side
document-viewer panel resizes/collapses independently and the grid
shrinks back when it is open, expands edge-to-edge when it isn't.

Tabular row dedup on re-upload

Adding a document that is byte-identical to one already extracted in
the same review (match key: filename + SHA-256 content_hash) now
inherits the earlier row's cells + status instead of asking the LLM
to re-extract them. Rows still in pending are ignored — there is
nothing to copy yet. Hits log as
[tabular][dedup] review=… new_doc=… inherits cells ….

Prereq for this feature: the legacy upload path now also computes
the SHA-256 content_hash. Without it the dedup join couldn't match
any document coming through the new picker Upload affordance.

Project-flow polish

"Nuova revisione" inside a project

The project's Revisioni tabellari tab gains a "Nuova revisione"
button — parity with the existing "Nuova chat" affordance on the
Conversazioni tab. The inline modal lists tabular workflows scoped
to the project's own domain, inherits project_id + the project's
domain on submit, and drills straight into the new review's
extraction grid without leaving the project shell. Existing review
rows on that tab are now click-targets and open the same inline
detail.

Scope-correct doc picker in tabular reviews

The "Aggiungi documenti" modal of a tabular review previously
surfaced every document the user had ever uploaded anywhere —
including cross-domain chat attachments and other projects' files.
It now applies, in order:

  • domain == review.domain (always);
  • if the review is project-scoped, the project's
    Ambito di recupero mode drives the rest:
    • rigoroso → only docs with project_id == review.project_id;
    • condiviso → also include global docs
      (project_id IS NULL);
  • if the review is not project-scoped → only global docs.

Backend GET /document now returns each doc's project_id so the
filter can run client-side. The picker's Upload button inherits the
review's project_id on uploads so a doc added through a
strict-scope picker stays visible there afterwards instead of
vanishing into the global pool.

Generic router back-stack — every drill-down returns to where you came from

The 2026-06-06 nav-consistency directive: a back button from a
drilled-in view must always return to the originating screen, not
to the destination's natural sidebar parent. The
TabularDetail-inside-ProjectDetail fix earlier the same day was
inline; this generalises the mechanism.

The router store gains a small back stack
(goWithReturn(target, ctx, entry) / popBack() /
consumePending(): NavContext). Drill-down callers push a back
entry so the destination renders a context-aware back arrow
("Torna a {name}") that pops the stack and restores the
originating screen's nested state. Standard router.go() clears
the stack (sidebar nav is "switch context", not "drill").

First consumer wired: a chat opened from inside a project pushes
a back entry pointing at that exact project. Assistant.svelte
shows the back arrow whenever the stack is non-empty; clicking it
returns to Projects and re-opens the originating project's detail.

New i18n key Nav.backToProject localised in all six locales.
Extending the mechanism to any future drill-down (Workflow editor,
DOCX template editor, …) is two lines per call-site.

Two follow-up fixes needed to make the back-stack robust:

  1. navTick — clicking a different project in the new sidebar
    accordion while already on the Projects screen did nothing,
    because router.go('projects', { projectId: X }) short-circuited
    on current === 'projects' and the destination $effect never
    re-fired. The router now exposes a monotonic navTick (bumped
    by every mutating method). Projects.svelte dereferences it
    (`void route...
Read more

v0.5.3 — hotfix: accumulate Gemini parallel tool calls across SSE chunks

05 Jun 09:28

Choose a tag to compare

MikeRust v0.5.3

Single-fix hotfix on top of v0.5.2. The chat loop dropped parallel
tool calls from gemini-3.5-flash mid-stream, surfacing as a
hard 400 from the Gemini API on the next iteration.

The fix

Gemini 3.5 parallel-tool-call accumulator

gemini-3.5-flash streams parallel function calls across separate
SSE chunks (one functionCall per data: line). The chat dispatch
loop in src/routes/chat.rs was replacing its iter_tool_calls
vec on every StreamEvent::ToolCalls event:

Ok(StreamEvent::ToolCalls(calls)) => {
    iter_tool_calls = calls;   // ← drops everything from earlier chunks
}

So when Gemini emitted three parallel calls in iteration 1, only the
last chunk's calls survived — the rest of the parallel batch vanished
before they were ever dispatched. Iteration 2's request to Gemini
then carried a truncated assistant turn that no longer matched the
model's internal record of which calls it had emitted, surfacing as:

Gemini API error 400 Bad Request:
  "Function call is missing a thought_signature in functionCall parts.
   Additional data, function call `default_api:read_document`, position 2."

The fix is one line — extend instead of =:

Ok(StreamEvent::ToolCalls(calls)) => {
    iter_tool_calls.extend(calls);
}

extend is safe for the other providers too. Claude tool use never
emits StreamEvent::ToolCalls in the SSE path (Anthropic streams
deltas through a different channel); the OpenAI-compatible local
adapter emits a single batched event per turn, so extend of one vec
of N is identical to assignment of the same N.

Per the official Gemini docs
(https://ai.google.dev/gemini-api/docs/thought-signatures), only the
first function call in a parallel batch carries a thoughtSignature
and the others must not — so this accumulator fix is sufficient on
its own; the original to_wire_contents echo-back logic in
src/llm/gemini.rs was already correct.

Downloads

Pre-built MSIs for Windows:

  • MikeRust_0.5.3_x64.msi — Windows x86_64
  • MikeRust_0.5.3_arm64.msi — Windows ARM64, Snapdragon X Elite native

Drop-in replacement for v0.5.2: same database schema (migration 0030
still the latest), same on-disk paths, same config.

Migration notes

  • No new database migration. Schema unchanged from v0.5.1/v0.5.2.
  • v0.5.2 users: install MikeRust_0.5.3_*.msi on top — the only
    difference is the one-line fix in the chat dispatch loop.
  • v0.5.1/v0.5.1b users: the v0.5.2 security hardening
    (drop S3 fallback + Parquet size cap + platform-support
    clarification) still applies on top of this hotfix.

License

MikeRust is distributed under AGPL-3.0-only. The Semplifica
wordmark and logo are trademarks; see NOTICE.md. The full licence
text is available in-app under Settings → Licenza.

v0.5.2 — security hardening: drop S3 fallback, parquet size cap, platform-support clarification

27 May 21:06

Choose a tag to compare

MikeRust v0.5.2

Security-driven patch release on top of v0.5.1b. Three changes land
together — all resolve outstanding Dependabot findings without
touching application behaviour.

Known issue: Gemini 3.5 Flash is still not working.

Highlights

Drop the s3-storage feature and the AWS SDK chain

aws-sdk-s3 + aws-config are gone from Cargo.toml. Removing them
drops 70+ transitive crates from the lockfile, including:

  • rustls 0.21.12 + rustls-webpki 0.101.7 — the Dependabot
    advisory that prompted this release. The AWS SDK chain was the
    only path that pulled in the vulnerable 0.21 line of rustls; the
    rest of the codebase (fastembed, sqlx, hf-hub) already uses
    rustls 0.23 + rustls-webpki 0.103.13.
  • aws-smithy-*, aws-sigv4, rustls-native-certs, sct, … the
    full SDK transitive graph.

The S3/R2 path was always feature-gated OFF by default and the
s3-storage feature was never actually wired into
src/storage/mod.rs::make_storage — that function has only ever
returned LocalStorage. The trait stays for the ergonomic win of a
single Box<dyn Storage> handle and to keep the door open for a
sovereign-cloud backend on rustls 0.23 later. End-user behaviour
is unchanged.

local-storage is kept as a no-op feature so anyone who pinned it
in their own manifest still resolves cleanly.

Parquet shard size cap — mitigation for the Thrift advisory

The parquet crate (used by the Italian Legal Cassazione bulk
importer) transitively depends on thrift 0.17.0, which carries an
unfixed-upstream "Memory Allocation with Excessive Size Value"
advisory: a crafted Parquet footer can declare an allocation that
the decoder honours before validating against the actual stream
length, causing a DoS-style OOM. The Apache Thrift Rust bindings
have not shipped a fix; even the latest parquet 58 still depends
on thrift ^0.17, so a version bump alone would not help.

Mitigation lands as a hard byte cap applied before the bytes ever
reach the Parquet decoder:

  • New file config/corpora.json holds the knob
    max_parquet_file_size_mb (default 500 MB — comfortably above
    any legitimate shard from the corpora we ingest, well below the
    threshold at which a malicious footer would matter on a 16 GB
    workstation).
  • New module src/corpora/limits.rs is the loader. Same
    env-override + ancestor-walk pattern as src/presets/model.rs
    (MRUST_CORPORA_LIMITS env var). Falls back to defaults with a
    warning if the JSON is missing or malformed.
  • src/corpora/italian_legal.rs refuses to decode a shard above the
    cap with a clear bail message.
  • docs/CORPUS_PLUGINS.md gains a Security section explaining
    the Thrift advisory, the dila-bulk-xml analogous concern
    (oversized XML / tar-walker hardening), and concrete guidance for
    plugin authors — pin URLs to official publishers, never accept
    user-supplied URLs verbatim, leave the cap at default unless you
    have a specific reason to raise it.

Platform-support clarification (resolves the glib 0.18.5 finding)

README gains a "Supported platforms" section right at the top of
Quick start:

  • Windows is the only currently shipping target (x86_64 + ARM64).
  • macOS is on the roadmap but work hasn't started — codebase
    compiles to aarch64-apple-darwin already; gating items are
    signing / notarisation and a Touch-ID equivalent of the
    Windows-Hello unlock flow.
  • Linux is not supported and there are no plans to add it.

The practical consequence for security scanners: the gtk / glib /
atk / webkit2gtk / tao-linux chain that Tauri pulls in for the
Linux WebView backend is not present in any shipped MSI —
webview2-com + windows-rs are what compile in on Windows.
Advisories on that chain (e.g. glib 0.18.5 flagged 2026-05-26) are
therefore inert for end users and tracked as "not affected — Linux
support is not in scope".

Downloads

Pre-built MSIs for Windows:

  • MikeRust_0.5.2_x64.msi — Windows x86_64
  • MikeRust_0.5.2_arm64.msi — Windows ARM64, Snapdragon X Elite native

Each bundles onnxruntime.dll 1.20.0 + pdfium.dll. Double-click to
install; runtime logs land in %USERPROFILE%\mikerust-data\mike-tauri.log.

Migration notes

  • No new database migration. Schema unchanged from v0.5.1 (still
    at migration 0030).
  • v0.5.1 / v0.5.1b users: install the new MSI on top — no data
    changes, no config changes required.
  • Custom corpus plugin authors: read the new Security section
    in docs/CORPUS_PLUGINS.md before pointing a hf-dataset-bulk
    strategy at a third-party dataset. The max_parquet_file_size_mb
    cap in config/corpora.json will refuse oversized shards by design.
  • Anyone consuming the s3-storage cargo feature in a fork:
    drop the feature flag from your build invocation. The feature is
    gone; local-storage (a no-op) is still accepted for back-compat.

License

MikeRust is distributed under AGPL-3.0-only. The Semplifica
wordmark and logo are trademarks; see NOTICE.md. The full licence
text is available in-app under Settings → Licenza.

v0.5.1b — bugfix: Gemini sampler restored to default for versatile heterogeneous-document analysis

26 May 17:06

Choose a tag to compare

MikeRust v0.5.1b

Hotfix release on top of v0.5.1. Single fix: rolls back the
Gemini temperature override so the model stays versatile when
analysing heterogeneous documents (mixed-content medical records,
multi-format legal bundles, etc.) — the v0.5.1 tightening from 1.0
to 0.5 was making gemini-2.5-flash lose expressiveness on long,
varied inputs.

Everything else from v0.5.1 ships unchanged: hybrid bracket splitter,
cross-message citation lookup, tightened citation rules, orphan KB
cleanup endpoint, A4-fit DOCX viewer, diagnostic logging, and the
E2E test scaffold.

The fix

Gemini white-out on long heterogeneous contexts

Symptom. On gemini-2.5-flash, with a long context made of
varied document types (the "Timeline cronologica clinica" workflow
on three medical PDFs reproduced it cleanly), the model would emit
the first ~30 characters of real content (e.g. a Markdown table
header) and then get stuck in a low-entropy whitespace loop —
generating 155,010 characters of pure spaces in one observed run,
~1.96 million in another — before closing the stream. The user saw
a frozen response with no error.

Root cause. v0.5.1 set temperature = 0.5 on every provider
for citation determinism. On Claude / OpenAI / local that lower
temperature is fine. On Gemini 2.5 Flash specifically, with a
system prompt above ~45 kB plus heterogeneous tool-result content,
the low temperature collapsed the sampler into a repeating-token
regime that the model couldn't escape.

Fix. src/llm/gemini.rs no longer sets temperature on any
Gemini family. generationConfig is now only attached when
thinkingConfig is needed (2.5 family), and legacy 1.5 / 2.0
families get no generationConfig at all. The result: Gemini falls
back to its API default (~1.0), recovering the versatility that
heterogeneous-document analysis depends on, while Claude / OpenAI /
local keep their tighter 0.5 for deterministic citation output.

23 llm::gemini unit tests pass; the regression test
build_body_omits_generation_config_on_legacy_families now pins
the new behaviour.

Downloads

Pre-built MSIs for Windows:

  • MikeRust_0.5.1b_x64.msi — Windows x86_64
  • MikeRust_0.5.1b_arm64.msi — Windows ARM64, Snapdragon X Elite native

Drop-in replacement for v0.5.1: same database schema (migration
0030 still the latest), same on-disk paths, same config. Install
on top of v0.5.1; no migration step.

Migration notes

  • No new database migration. Schema unchanged from v0.5.1.
  • v0.5.1 users: install MikeRust_0.5.1b_*.msi on top — the
    citation pipeline, doc viewer, and KB cleanup endpoint are
    byte-identical to v0.5.1, only the Gemini sampler config differs.
  • v0.5.0 and earlier: the v0.5.1 release notes still apply on
    top of this one for the citation overhaul + A4 viewer + orphan
    cleanup changes.

License

MikeRust is distributed under AGPL-3.0-only. The Semplifica
wordmark and logo are trademarks; see NOTICE.md. The
full licence text is available in-app under Settings → Licenza.

v0.5.1 — citation pipeline overhaul + orphan KB cleanup + A4 doc viewer

26 May 12:39

Choose a tag to compare

MikeRust v0.5.1

Stable consolidation of four work-in-progress drops (formerly tagged
v0.5.1 → v0.5.4) into a single shippable release. v0.5.0 exposed a
clutch of citation-pipeline failures with mid-tier LLMs (Gemini 2.5
Flash, smaller local models): mixed-content brackets, dropped
cross-message references, orphan KB chunks surviving file deletions,
and run-to-run citation inconsistency. This release fixes all of them
— and, while we were in the doc viewer, adds an A4-fit DOCX preview
that auto-zooms when the side panel is resized.

Highlights

Citation pipeline — model-independent post-processors

  1. Hybrid bracket splitter (split_hybrid_citation_brackets).
    Decomposes mixed-content brackets the model occasionally emits
    ([c1, c2, FILE.pdf, p.4, doc-7, doc-8]) into clean ones the
    frontend MARKER_GROUP regex can pill-ify
    ([c1] [c2] [doc-id: FILE.pdf, page 4] [doc-id: doc-7] [doc-id: doc-8]).
    Idempotent; stops at <CITATIONS> so it can't corrupt the
    trailing JSON block (regression test pins this).
  2. Cross-message citation lookup (renderMessageHtml). When a
    [cN] in the current turn has no matching annotation but an
    earlier assistant turn in the same chat did, the pill resolves to
    the older annotation. Catches the common case of models reusing
    cN labels across turns.
  3. Tightened CITATION QUALITY RULES in MRUST_SYSTEM_PROMPT:
    omit empty / short quotes; page ranges only for [[PAGE_BREAK]]
    spans (else integer pages); prefer per-passage over per-document
    citations; prefer attached doc-N over KB gN/pN; re-emit
    cross-turn [cN] annotations in the current turn's
    <CITATIONS> block.

Cross-provider determinism + headroom

  • temperature = 0.5 on every LLM provider
    (Anthropic / Gemini / OpenAI / local-OpenAI-compatible).
    Defaults were 1.0 across the board — too random for structured
    output. Lowering it makes citation extraction reproducible run to
    run across all four providers.
  • max_tokens 4096 → 8192 on Claude + local. Doubles the
    headroom for trailing <CITATIONS> JSON on long answers; Gemini
    was already on its default (≥8192 on the 2.x family).

Orphan KB chunks — chat-time filter + cleanup endpoint

User-reported failure mode: removing a synced doc from the UI left
its embeddings behind, and every chat turn the cosine retrieval kept
surfacing those stale chunks — one chat ended up emitting 12
citations all pointing to the same dead PDF page.

  • retrieve_kb_chunks now probes each chunk's source_path on
    disk and drops missing ones with an
    [rag] orphan KB chunk dropped … warning + per-turn summary.
  • New endpoint POST /sync/cleanup-orphans — per-user cascade
    delete of documents + doc_chunks + synced_files rows whose
    backing file is gone. Returns
    { scanned, orphans, deleted_docs, deleted_chunks, deleted_synced }.
  • Frontend modal: when a citation source 404s, the doc viewer
    surfaces a warning panel with a Pulisci sorgenti rimosse button
    that calls the cleanup endpoint and toasts the row count.

DocxView — A4 fit (default) + reflow toggle

Preserves the document's native A4 page geometry (width + height +
margins, breakPages: true) and applies CSS
zoom = containerWidth / pageWidth (clamped to [0.4, 1.5]) via a
ResizeObserver so the page auto-scales when the user drags the
side-panel divider. A top-right toggle flips to a reflow mode (drops
the page geometry, prose flows the full panel width) for narrow
side-panel reading. ResizeObserver detached in reflow mode so the
responsive cost is zero off-path.

Diagnostic logging

  • [rag][cite-diag] retrieve_kb_chunks … spells out HyDE on/off +
    locale + domain + top-K and clarifies that base cosine retrieval
    always runs regardless of HyDE (removes the recurring "I turned
    HyDE off, why is it still searching?" confusion).
  • [chat][cite-diag] … events trace each step of the citation
    pipeline: final response shape, tail dump, per-step outcome, FINAL
    SSE payload size.
  • [chat] <CITATIONS> block found but is not valid JSON warning
    dumps head / mid / tail (300 chars each) of the offending payload
    for offline diagnosis.

E2E test scaffold

New tests/medical_citations_e2e.rs bypasses the frontend entirely:
places 10 PDFs from tests/medical/ straight into cache + documents
rows, exercises the real POST /chat handler via
tower::ServiceExt::oneshot, parses the SSE stream, and prints a
structured JSON report of citation quality. Gated by #[ignore] +
GEMINI_API_KEY; A/B switches via E2E_HYDE / E2E_MODEL.

$env:GEMINI_API_KEY = "..."
cargo test --test medical_citations_e2e --features rag,pdf `
    -- --ignored --nocapture

v0.4.7 — version badge fix + chat-files popover + License panel

25 May 13:18

Choose a tag to compare

MikeRust v0.4.7

Rollup release that closes a string of UX and persistence gaps reported during the v0.4.x review cycle, plus a hotfix for the visible-version regression introduced in v0.4.6.

Highlights

Generated-docx Accept / Reject flow — full lifecycle

When the model emits a docx the user can now Accept it (keep in chat context) or Reject it (replace with an LLM-generated summary anchored on a mandatory user motive). Re-Accept restores the original; Re-Reject overwrites the archive with a fresh summary. A new "Vedi riassunto" read-only modal surfaces the archived reason + summary after the reject modal closes, so the user can re-read what the model now sees in place of the document.

Backend: documents.decision / decision_reason / decision_summary columns (migration 0029); POST /document/:id/decision runs the summariser and persists; chat::load_attached_docs substitutes the body with a reason + summary stub on every subsequent turn.

Chat-files popover — five categories, one shortcut

New Files button in the composer footer opens a popover listing every document the chat has ever interacted with, across the five categories the chat archive is expected to retain:

Origin Where it comes from
Caricato composer paperclip → documents.chat_id
Generato generate_docx tool → documents.chat_id
Rifiutato (variant) any of the above with decision='rejected' — strikethrough + red badge
Progetto chats.project_iddocuments.project_id
Citato KB / corpora docs cited via messages.annotations

Per-format icon colours (Excel green / Word blue / PDF red / PowerPoint orange / Markdown text-primary). Click a row to open it in the existing doc-viewer side panel, where Accept / Reject / Vedi riassunto / Apri in Word all already work. Backed by a new GET /chat/:id/documents endpoint that survives chat reload, chat switching and message compaction.

Version badge + License panel

Small v{version} badge next to "MikeRust" in the sidebar so the user always knows which build is running. New Settings → Licenza panel shows MikeRust + version, the SPDX identifier (AGPL-3.0-only), a plain-language summary of the AGPL terms and the full bundled LICENSE text in a scrollable monospace block.

Multi-doc anamnesis docx (v0.3.6)

Fixed a Gemini tool-code crash on multi-document anamnesis flows and a doc-label off-by-one (1-indexed labels now match [doc-N] references).

Full changelog by patch

  • v0.4.7 — version badge actually renders (replaced runtime getVersion() + $state with build-time package.json import)
  • v0.4.6 — version label + License settings panel (broken; superseded by 0.4.7)
  • v0.4.5 — chat-files popover surfaces all 5 doc categories (project + KB-referenced)
  • v0.4.4 — chat-files popover backend-sourced, survives reload (new GET /chat/:id/documents)
  • v0.4.3 — chat-files popover MVP
  • v0.4.2 — fix reject modal step-2 transition (untrack(initialReason) in $effect)
  • v0.4.1 — persistent "Vedi riassunto" for rejected docs
  • v0.4.0 — domain-aware system-prompt prologue (66 .md files × 6 locales × 11 domains)

See HISTORY.md for the per-patch details and rationale.

Downloads

Pre-built MSIs for Windows:

  • MikeRust_0.4.7_x64.msi — Windows x86_64
  • MikeRust_0.4.7_arm64.msi — Windows ARM64 (Snapdragon X Elite native)

Each bundles onnxruntime.dll 1.20.0 and pdfium.dll. Double-click to install; runtime logs land in %USERPROFILE%\mikerust-data\mike-tauri.log.

License

MikeRust is distributed under AGPL-3.0-only. The Semplifica wordmark and logo are trademarks; see NOTICE.md. The full licence text is now also available in-app under Settings → Licenza.

v0.3.2 — tool iter cap, Ollama probe proxy, biometric icon

24 May 13:39

Choose a tag to compare

Three independent fixes in one release.

Fixed — chat stops with "too many tool iterations" on multi-doc workflows

Reported on Gemini 2.5 Flash with a medical-anamnesis workflow attached to ten clinical-record PDFs: the model called read_document on a couple of files, then aborted with "stopped: too many tool iterations". MAX_TOOL_ITERATIONS = 5 in src/routes/chat.rs was a holdover from single-doc debug runs; legitimate due-diligence / medical-anamnesis flows need 5–15 source-doc reads before composing the answer. Bumped to 20 — bounds a runaway loop at ~20× the per-turn latency while comfortably covering ten-doc anamnesis flows. Fix applies to every LLM that does tool-use (Gemini, Claude, OpenAI, local Ollama / vLLM, …).

Fixed — Settings → "Modelli LLM" probe CORS-blocked

The Settings page used to issue fetch(${base}/models) directly from the WebView origin http://tauri.localhost. External Ollama / llama-server / vLLM instances rarely whitelist that origin, so the browser blocked every probe with the "No 'Access-Control-Allow-Origin' header is present" message and the model dropdown stayed empty.

  • New backend endpoint GET /models/local/probe?base=…&api_key=… does the server-to-server fetch (no Origin involved → no CORS) and returns the upstream payload verbatim, plus typed error fields (upstream_status, error).
  • ModelsSection.svelte now goes through the proxy instead of fetching the runtime directly.
  • The chat path was never affected — chat-time LLM calls already go through the Rust reqwest client.

Fixed — biometric unlock dialog used a hand-drawn fingerprint

BiometricPrompt.svelte rendered its fingerprint via seven inline SVG paths. The result looked off-centre and hairline-thin against the brand-500 background and didn't match the lucide-svelte icon family the rest of the app uses. Swapped for <Fingerprint size={40} class="text-(--color-brand-500)" /> from lucide-svelte. The currentColor inheritance preserves the brand-tint behaviour, so no styling change at the call site.

Installer artefacts

  • MikeRust_0.3.2_x64.msi — Windows x86_64
  • MikeRust_0.3.2_arm64.msi — Windows ARM64

See HISTORY.md for the cumulative v0.2.x → v0.3.x timeline.

release: v0.3.1 — bundle JSON config registries in the MSI

24 May 08:44

Choose a tag to compare

Configs, workflows, templates were missing.