feat(ai): enforce local-first routing

Keep external providers behind server consent, task, and prompt-cost gates while persisting actual provider provenance.
This commit is contained in:
cesnimda
2026-08-09 12:30:11 +02:00
parent c3f4a57195
commit 5eb9b3cb96
29 changed files with 967 additions and 145 deletions
+9 -11
View File
@@ -65,16 +65,14 @@ and all-time totals; the workspace displays the monthly calls and estimated toke
## Provider abstraction
Generation goes through the existing `ISummarizerService` ai-service, which routes to the active
provider (`AI_PROVIDER`: ollama | gemini | groq) — production can offload a weak local GPU to a cloud
provider. Each `AiInteraction` records the resolved provider for transparency, and `GET …/ai/modules`
returns the current provider so the UI can show it.
Generation goes through `ISummarizerService` to the ai-service. Ollama is primary; `AI_PROVIDER` names
only the optional external fallback candidate. Fallback is sequential and requires administrator
enablement, task approval, live Pro/user consent and the prompt cost/privacy ceiling. Each
`AiInteraction` records the provider returned by the sidecar, plus bounded model/route metadata in
`ResultJson.meta`; configuration alone is not treated as proof that a provider executed.
**Per-request user-selectable providers** (module 8's "users can choose provider") is a plumbing
extension, not yet wired end-to-end: it needs (a) ai-service to accept a per-request `provider`
override and (b) an API **key configured for each selectable provider**. Both are deployment/credential
concerns (a live paid key per provider), so the code path is left as a documented extension point
rather than shipped half-configured. The abstraction already isolates the change to one method.
Per-request user-selectable providers remain intentionally unsupported. The server-side privacy
policy selects a route, not the browser, and provider credentials remain deployment-only.
## Extension points
@@ -83,8 +81,8 @@ rather than shipped half-configured. The abstraction already isolates the change
- **New cover-letter tone**: add to `CoverLetterModes` + `ModeGuidance`.
- **Structured (JSON) results**: swap a module's prompt for JSON and parse into `ResultJson.meta`; the
UI already renders `result.text` as markdown and can read `meta`.
- **User-selectable provider**: thread a `provider` param through `ISummarizerService`
ai-service; gate on the provider having a configured key (see above).
- **Provider policy**: add task types to the explicit server-side allowlist only after their payload,
accounting and production checks pass; do not add browser provider overrides.
## Security