mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-14 10:34:06 +02:00
feat(desktop): show the AI assistant in SaaS mode via the cloud kill switch (#6666)
## What & why Chained on top of #6649 (the `cloud/` refactor). The AI assistant was effectively dead on desktop: 1. **Hidden** — `ChatFAB` gates on `aiEngineEnabled`, which desktop reads from the **local** bundled backend's `/api/v1/config/app-config`. The local backend has no AI engine, so the flag is always `false` and the FAB never renders. 2. **Mis-routed** — even if shown, AI calls used `getApiBaseUrl()`, which is empty/local on desktop, so the orchestrate stream and AI result-file download missed the engine (which only runs in the cloud). This PR wires AI properly **without hardcoding it on**, so the cloud keeps the kill switch: flip `aiEngineEnabled` server-side and the desktop FAB disappears on the next load — no desktop release required. (Deliberately *not* assume-on, so a future "turn AI off" doesn't strand shipped versions.) ## Changes **General SaaS app-config service** (reusable for any cloud flag, not just AI): - `desktop/services/saasAppConfigService.ts` — SaaS-mode-only fetch + 5-min cache of the **public** `/api/v1/config/app-config` from the **SaaS** backend over native HTTP (`@tauri-apps/plugin-http`, no CORS). Returns `null` outside SaaS mode. - `desktop/hooks/useSaasAppConfig.ts` — hook over it; reloads on connection-mode change. **AI gating + routing seams:** - `useAiEngineEnabled()` — core reads `useAppConfig()` (web), desktop reads `useSaasAppConfig()`. `ChatFAB` consumes it. - `getAiBaseUrl()` — core uses the normal API base (web), desktop points AI calls at the SaaS backend. `ChatContext` uses it for the orchestrate stream + result-file download. - `operationRouter` — route `/api/v1/ai/*` to the SaaS backend (cloud-only prefix). **Docs:** AGENTS.md gains a short "cloud feature flags on desktop" note so the pattern is maintained. ## Verification - `tsc --noEmit` green for saas / desktop / cloud flavors - `eslint --max-warnings=0` clean (cloud-layer guardrail respected — the platform-coupled bits live in `desktop/`) - New `saasAppConfigService.test.ts` (3 tests) + existing `operationRouter` / `tauriHttpClient` / `httpErrorHandler` suites green - 0 stray compiled artifacts ## Not headlessly verifiable — needs a live Tauri smoke The orchestrate **SSE stream** uses the webview's global `fetch` (native HTTP can't stream the body the same way), so it's subject to browser CORS to the SaaS backend. The `SupabaseSecurityConfig` tauri-origin allowance (from #6649) covers it, but please confirm on a real build: open the FAB in SaaS mode, run an agent task, watch the stream + a result-file download succeed.
This commit is contained in:
@@ -193,6 +193,8 @@ What goes where:
|
||||
|
||||
Rule of thumb — **move, don't copy**: share via `cloud/`, override by shadowing the same `@app/*` path in a leaf (`saas/` or `desktop/`).
|
||||
|
||||
**Cloud feature flags on desktop.** The local `AppConfigContext` reads `/api/v1/config/app-config` from the LOCAL bundled backend, so cloud-only flags (`aiEngineEnabled`, `premiumEnabled`, …) are never seen on desktop. To read the cloud's view, use `useSaasAppConfig()` (`desktop/hooks/useSaasAppConfig.ts`, backed by the general `saasAppConfigService` — SaaS-mode-only, public endpoint, native HTTP, 5-min cache). It returns `null` outside SaaS mode, so cloud features stay off in local/self-hosted and the server keeps the on/off switch (no desktop release needed to flip a flag). Gate a feature behind a per-platform seam — e.g. `useAiEngineEnabled()` (core reads `useAppConfig()`, desktop reads `useSaasAppConfig()`) — rather than hardcoding the flag on.
|
||||
|
||||
#### Component Override Pattern (Stub/Shadow)
|
||||
Use this pattern for desktop-specific or proprietary-specific features WITHOUT runtime checks or conditionals.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user