4ce2df0a2b
CI / backend (push) Successful in 52s
CI / frontend (push) Successful in 14s
Deploy Staging / deploy (push) Successful in 18s
CI / backend (pull_request) Successful in 52s
CI / frontend (pull_request) Successful in 15s
Security / secrets (push) Successful in 4s
Security / dependencies (push) Successful in 55s
Security / secrets (pull_request) Successful in 4s
Security / dependencies (pull_request) Successful in 54s
3.7 KiB
3.7 KiB
08 — AI Feature-Flag Integration (Part 8)
How the AI layer plugs into the flag system while staying completely separable from core email logic. Extends the blueprint AI strategy (../06); the gate math lives in 04.
Principle: AI is a guest, never a host
Core email (sync, search-lexical, cleanup, settings, admin) never references an AI type. It calls domain services; those optionally consult AI through a single gate + facade. Remove AI entirely and nothing in the core path breaks.
Core feature code
│ (never touches Ollama/IAiProvider directly)
▼
IAiGate.IsAiFeatureEnabled("summaries", user) ──► false ─► non-AI path / hide
│ true
▼
IInboxAi facade (Application) ──► model router ──► IAiProvider / IEmbeddingProvider
(Null | Ollama | future)
Toggle behaviour (flag-driven)
- Before any AI call, code asks
IAiGate(which folds inai.enabled+ai.<feature>+ provider capability + user opt-in — the AND-chain from 04). - Admin
ai.enabled= off ⇒ gate returns false everywhere ⇒ AI UI hidden, AI code paths skipped. Flip on ⇒ features reappear (hot-reloaded flag cache) with no redeploy. - Per-feature flags allow shipping AI features dark and enabling gradually (rollout).
Fallback when AI is disabled (per feature)
| AI feature | Fallback with AI off |
|---|---|
| Semantic / NL search | Lexical + structured + fuzzy search (still excellent) |
| Thread summary | Hidden; show first snippet + metadata |
| Reply suggestions | Hidden; normal compose |
| Follow-up detection | Heuristic-only (sent + question + no reply in N days) |
| Categorisation | HeuristicClassifier rules only |
| Ask-your-inbox | Feature hidden |
| Dedup | Exact-hash only (no near-dup) |
| Every fallback is first-class, not a broken/greyed feature — this satisfies "AI must never | |
| be required for core functionality." |
Ollama integration layer (local models)
OllamaProvider(IAiProvider) +OllamaEmbeddingProvider(IEmbeddingProvider) talk to a local Ollama (own container, optional Composeaiprofile).- Model router maps logical task → model via config (
Ai:Models:{Chat,Embed,Vision}); swapping a model is a config change, not code. - VRAM guard (RTX 3080 / 10 GB): embeddings hot, 7B warm, vision on-demand (../06).
- Health surfaced to admin (05): reachable? models loaded? VRAM? latency? If Ollama is down, capability = false ⇒ gate falls back gracefully (no user errors).
Safe abstraction (IAIProvider) — separation guarantees
- Interface boundary: only Infrastructure implements providers; Application depends on
IInboxAi/IAiGateabstractions. - Null objects:
NullAiProvider/NullEmbeddingProviderreturn "unavailable" so the DI graph is always valid, AI on or off. - Analyzer pipeline: AI enrichers (
IEmailAnalyzer) declare required capabilities and are skipped when unavailable — adding/removing AI features never touches core sync/search. - Bounded: every AI call has timeout +
CancellationToken+ Polly fallback to the Null path; AI can never hang or crash the core. - Provider-swap: adding a future AI provider = one class + config + (optionally) a flag — no feature-code changes.
Precedence recap (single source of truth)
The effective availability chain and admin master-switch semantics are defined once in 04 — Settings & Feature Flags; this document is the architecture of how features consume that decision.