HttpChatProvider
AiProvider over a caller-supplied HTTP endpoint speaking the same data: <json> / data: [DONE] SSE contract as AnthropicProvider/OpenAiProvider/GeminiProvider — the shape cv-siddharth-kmp and Candidai were each hand-rolling their own parser for. Every reply frame decodes as HttpChatStreamEvent; the backend is expected to emit {"text":"..."} per token and close the stream (optionally preceded by a data: [DONE] line, discarded rather than decoded) rather than any vendor-specific event shape. See HttpChatConfig.requireDoneSentinel for a backend whose [DONE] isn't actually optional.
Request body: {"messages":[{"role":"user"|"assistant","content":"..."}],"system"?,"mode"?, "route"?,"maxTokens","temperature"}. system, mode and route are each omitted entirely when absent (explicitNulls = false on the request's Json) rather than sent as "system": null / "mode": null / "route": null — required for a backend that validates mode against a closed allowlist and would 400 a literal null.
Functions
Honest self-report for a capability-aware caller: whether this backend genuinely streams tokens and accepts images, which AiConfig fields it actually reads, and — when it can't run — the real AiFailure reason instead of a bare false. Default answer is conservative (no streaming, no honored config) and blames a missing key, matching every real provider's own isAvailable gate; a provider whose unavailability means something else overrides this.
No separate HTTP call of its own — collects completeStream under AiConfig.timeoutMs and joins its tokens. One call site for the wire contract instead of a second copy of the request/ response handling that completeStream already has right.
Token-by-token variant of complete — so a UI can render the reply as it arrives and a Stop action actually cancels the in-flight request (cancelling the collecting coroutine tears down the underlying HTTP call) instead of leaving it running to completion in the background.