Skip to content

fix(gemini): route LLM calls through Rust to stop 'Load failed'#2

Merged
guuse merged 2 commits into
mainfrom
fix/gemini-load-failed
Jun 1, 2026
Merged

fix(gemini): route LLM calls through Rust to stop 'Load failed'#2
guuse merged 2 commits into
mainfrom
fix/gemini-load-failed

Conversation

@guuse
Copy link
Copy Markdown
Owner

@guuse guuse commented Jun 1, 2026

Probleem

Bij het classificeren van een dag verscheen "Fout op : Load failed" (bv. 2026-03-09). "Load failed" is de generieke fout die Tauri's WebKit-webview gooit als een browser-fetch mislukt.

Oorzaak: GeminiRepository was de énige externe HTTP-call die via de webview-fetch liep. De webview kapt grote/trage requests af (gemini-2.5-flash op een drukke dag duurt lang + grote prompt) → "Load failed". Elke andere call (Simplicate) gaat al via een Rust reqwest-command (invoke) en heeft dit probleem niet. Bovendien werd er niet geretried op netwerkfouten — alleen op 429.

Fix (beide aanpakken, zoals besproken)

  1. Routeren via Rust — nieuw gemini_request Tauri-command (reqwest), spiegel van simplicate_request. GeminiRepository.callGemini gebruikt nu invoke() i.p.v. fetch(). Geen webview-fetch meer → geen "Load failed".
  2. Retry/backoff in de Rust-laag — transiente fouten (netwerk, HTTP 429, 5xx) worden geretried met exponentiële backoff (2/4/8s) en respect voor Gemini's retryDelay. Een injecteerbare Sleeper maakt de retry-loop testbaar zonder echt te wachten.

De TS-laag mapt de uiteindelijke fout op een nette melding (quota uitgeput / niet bereikbaar / API-fout).

Tests

  • Rust: 8 nieuwe unit-tests (success, 429+retryDelay, 5xx-backoff, retry-uitputting, niet-retrybare 4xx, netwerk-retry + herstel). cargo test → 56 groen.
  • Frontend: GeminiRepository.test.ts mockt nu invoke; retry-asserties verplaatst naar Rust. Volledige suite 808 groen, coverage 99.6% / 98.2% / 100%.

Let op: CI (workflow + hermetische test-setup) zit in #1. Merge #1 eerst naar main, dan main hierin mergen zodat de CI-checks ook op deze PR draaien.

🤖 Generated with Claude Code

Gemini's generateContent call was the only external HTTP request made via
the WebKit webview's fetch(). The webview drops large/slow requests with a
generic 'Load failed' error — which surfaced as 'Fout op <datum>: Load
failed' on heavy days. Every other API call (Simplicate) already goes
through a Rust reqwest command via invoke() to avoid exactly this.

Add a gemini_request Tauri command (reqwest) mirroring simplicate_request,
with retry/backoff on transient failures (network errors, HTTP 429, 5xx)
and an injectable Sleeper so the retry loop is unit-tested without waiting.
GeminiRepository now calls it via invoke() instead of fetch(); the TS layer
maps the surfaced error onto a user-facing message (quota / unreachable /
API error).

- 8 Rust unit tests cover success, 429+retryDelay, 5xx backoff, retry
  exhaustion, non-retryable 4xx, network retry/recovery.
- GeminiRepository tests now mock invoke; retry assertions moved to Rust.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 1, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 99.95% (🎯 95%) 2443 / 2444
🔵 Statements 99.64% (🎯 95%) 2778 / 2788
🔵 Functions 100% (🎯 95%) 704 / 704
🔵 Branches 98.23% (🎯 95%) 1554 / 1582
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/infrastructure/gemini/GeminiRepository.ts 99.45% 98.92% 100% 100% 129
Generated in workflow #5 for commit 2a6cfab by the Vitest Coverage Report Action

It was only used by the test helpers, triggering an unused_imports
warning in non-test builds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@guuse guuse merged commit f644e4c into main Jun 1, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant