Symmetric to the web BYOK backend (@mana/browser-llm) and @mana/byok-providers.
A new LLMBackendID.byok lets the user bring their own third-party API key
(OpenAI/Anthropic/Gemini/Mistral); the call streams device-direct to the
provider via URLSession — the key never reaches mana infrastructure.
New Sources/ManaLLM/Byok/:
- ByokTypes: ByokProviderID, ByokSelection, ByokMessage, ByokKeyResolver,
ByokProvider protocol, ByokError.
- ByokProviders: 4 URLSession SSE adapters (OpenAI/Mistral share an
OpenAI-compat path; Anthropic + Gemini have their own schemas).
- ByokKeyVault: Keychain store — deliberately app-private, NOT the shared
group.ev.mana.session; no cross-device sync. makeResolver(…) helper.
- ByokBackend: LLMBackend conformance; unavailable without a resolver;
prompt/key never logged (PII/secret).
LLMRouter: setByokResolver / setAllowByokInPick. BYOK is never picked
silently (privacy discipline, mirror of web) — reachable via
backend(for: .byok). LLMBackendID.byok.isOnDeviceLLM == false.
Breaking for apps: LLMBackendID has a new .byok case — exhaustive switches
(e.g. settings UI) must handle it.
swift build + swift test green (23 tests, 11 new — network/keychain-free:
provider registry, availability gating, router pick discipline).
Compliance rule (sensitive content not via BYOK by default) in
mana/docs/COMPLIANCE.md §5.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>