Files
SRCmail/components/settings
Bernd Rodler 5d7ae230ce feat(ai): real local Ollama chat + BYOK public provider
Decisions 2026-08-05 evening (reprioritizing docs/AI-ASSISTANT-CONCEPT.md's
original P1/P2 server-first sequencing to local-first, since a real Ollama
instance already runs on this Mac with a full model set):

- `local` ships free, no entitlement check — always available wherever
  supportsLocalLlm() is true.
- `public` (BYOK) is available too, explicitly unmonitored for now — no
  seats/metering/consent backend. This reverses the concept doc's decision
  #1 (server-side-only key custody): the client holds its own key, matching
  vncmail-native's existing pattern.
- `server` (VNC-hosted) stays unwired client-side; that infra is "this
  MacBook tonight, the dev k8s cluster tomorrow."

New:
- lib/ai/local-client.ts: listLocalModels/testLocalConnection/chatLocal/
  chatPublic, ported near-verbatim from vncmail-native's proven
  src/api/ai.ts. Direct browser-side fetch, not proxied through this app's
  own server — a server-side proxy would reach the *server's* loopback, not
  the user's own laptop, which defeats the point of "local" once this app
  is hosted remotely.
- lib/ai/key-store.ts: client-held BYOK storage (localStorage — this repo's
  existing convention for client state, no OS keychain reachable from a
  browser tab).
- lib/ai/local-settings.ts: isolated persistence for provider/model/base-URL
  choices. Deliberately NOT folded into stores/settings-store.ts, which has
  a hand-maintained export/import enumeration this prototype-scope state
  doesn't belong in yet.
- Retrieval reuses this app's own already-built app/api/offline/search
  (encrypted SQLite/FTS5 mail index) as context when available, and
  degrades to unaugmented chat — not an error — when it 404s/503s (no index
  in this session, e.g. plain browser rather than Electron).

Rewrote components/settings/ai-assistant-settings.tsx: provider picker,
local runtime config (base URL, model list/refresh, test connection with a
CORS-aware diagnostic per the concept doc's own note on the browser row),
public BYOK config (base URL, model, key, client-side consent toggle), and
a working Ask box.

Verified: typecheck clean, lint clean, translations pass, production build
succeeds. Live-tested against the real Ollama on this machine (confirmed
running: qwen2.5:32b, gemma4, deepseek-r1, llama3.2, hermes3, qwen3) via a
local server + demo-mode session — admin flag round-trips correctly, the
pane renders both provider options, and the CORS-diagnostic path fires
correctly on a real (if here environment-sandboxed, not Ollama-side)
connection failure. Full success end-to-end still wants a real, unsandboxed
browser tab against this Mac's loopback to close out.
2026-08-05 22:41:22 +02:00
..