el-cloud — opt-in frontier LLM cloud backend
The opt-in frontier cloud backend (ADR-010). It implements
el_core::LlmProvider over reqwest using
the OpenAI Chat Completions API — which OpenAI, Anthropic (compat), Gemini
(compat), Ollama, and any OpenAI-compatible endpoint all speak.
Air-gap is preserved (ADR-004)
This is the project's only outbound network surface, and it is opt-in at the API level:
- Outbound calls happen only when an app explicitly constructs a
CloudProvider. Apps that never build this type have zero outbound surface, even though the crate compiles as part of the workspace. - The
reqwestnetwork dependency is gated to non-wasm32 targets (see the wasm32 note below), so the web surface has no blocking HTTP transport at all. - Every consultation emits a content-free
DomainEvent::FrontierLlmConsulted(theprovider_hashis a CRC32 of the provider prefix — never the API key or any content).
What it provides
CloudProvider— owns a pooledreqwest::blocking::Clientwith explicit timeouts (10 s connect, 60 s idle/per-read, 120 s total per non-streaming request) so a stalled provider can never block an FFI caller indefinitely.new()/Defaultwith_event_sink(|event| …)— register a callback forDomainEvents (e.g. to feed anel_telemetry::MetricsCollector).- implements
LlmProvider::chat(blocking) andchat_stream(SSE).
Provider routing (by model prefix)
| Model string | Base URL |
|---|---|
openai/<model> |
https://api.openai.com/v1 |
anthropic/<model> |
https://api.anthropic.com/v1 (compat) |
gemini/<model> |
https://generativelanguage.googleapis.com/v1beta/openai |
ollama/<model> |
http://localhost:11434/v1 (no key required) |
http(s)://…/<model> |
custom base URL |
The streaming path parses Server-Sent Events strictly: provider error payloads and malformed chunks fail the call (a half-finished stream is never reported as a clean completion), and errors carry only parse category/position/size — never echoed content, per the el-core error contract.
Usage
Use CloudProvider only as an explicit fallback or comparison path; the local
Qwen2.5 0.5B GGUF remains on device and is not sent to the provider.
use ;
use CloudProvider;
let provider = new;
let _local_qwen_model = "models/qwen2.5-0.5b-instruct-q4_k_m.gguf";
// The credential is resolved at runtime from the platform keystore — never embedded.
let req = new
.with_credential
.with_max_tokens;
let resp = provider.chat?;
println!;
# Ok::
wasm32 note
reqwest::blocking is unavailable on wasm32-unknown-unknown (no threads), and
the synchronous LlmProvider::chat cannot await the browser's fetch. The
network modules are therefore gated to non-wasm32, and the web binding
(el-ffi) exposes a throwing cloud constructor instead of silently degrading
(ADR-010 amendment).
Status
Implemented as an explicit egress adapter and a regular workspace member — the
opt-in is enforced at construction, not by excluding it from the build. Uses
rustls-tls so Android cross-compiles need no target OpenSSL sysroot.
Part of the Edge Intelligence workspace. Realizes ADR-010 while preserving ADR-004.