Skip to content

REVIVAL-10: OpenAICompatible named provider + true SSE streaming (OpenRouter/Groq/DeepSeek first-class) #1306

Description

@Chris0Jeky

Wave: REVIVAL Phase 2 (v0.2) — docs/REVIVAL_PLAN.md §4. Review tier: FULL (provider + settings regex). Independent of REVIVAL-08 (can land first).

Context (verified 2026-07-10)

Two adversarially confirmed facts: (1) the OpenAI provider's BaseUrl already accepts any public HTTPS OpenAI-compatible endpoint (OpenRouter/Groq/DeepSeek/Anthropic-compat) with config only — but it's an undocumented hack, and the named-provider list is a hardcoded regex Mock|OpenAi|Gemini|Ollama (LlmProviderSettings.cs:11) plus a DI switch (LlmProviderRegistration.cs:156-163); (2) all four providers fake streamingStreamAsync buffers the full completion then replays word-split tokens, and OpenAI/Ollama even send "stream": false (OpenAiLlmProvider.cs:395-409,262,509; equivalents in Gemini/Ollama/Mock). The SSE chat endpoint's first token arrives only after full completion.

Acceptance criteria

  1. New first-class provider name OpenAICompatible (settings: BaseUrl required, ApiKey, Model, optional extra headers) — same SSRF/HTTPS validation as today; registered through the existing 4-file pattern (settings regex, selection policy, DI switch, provider class — follow the Ollama precedent). The OpenAI provider itself stays unchanged for api.openai.com defaults.
  2. True SSE streaming for the OpenAI-compatible wire format (stream: true + delta parsing) in this one provider — it covers every cheap-model vendor at once. Honest fallback: if the endpoint rejects streaming, degrade to complete-then-emit and mark the result metadata accordingly (no silent fakery).
  3. The chat SSE endpoint (ChatController.cs:155-181) streams real deltas end-to-end for this provider; existing pseudo-streaming providers keep working unchanged (de-faking them is out of scope; Ollama marking is ARCHIVE-08: Dead-surface removal - ink-bleed decision, orphaned Paper code, cohorts stub, voice capture, Ollama marking #1276's decision).
  4. response_format/json_object handling: degrade gracefully when a compat endpoint rejects it (verified edge: instruction extraction sends it) — fall back to prompt-enforced JSON + robust parsing.
  5. Config documented in docs/platform/LLM_PROVIDER_SETUP_GUIDE.md + CONFIGURATION_REFERENCE with copy-paste examples for OpenRouter, Groq, DeepSeek.
  6. Tests: provider unit tests (streaming parse, malformed SSE, mid-stream error, cancellation), selection-policy tests, one resilience test in the existing pattern (LlmProviderResilienceTests).

Traps

  • Circuit breaker/quota/kill-switch/egress wiring must apply to the new provider (registration extension methods — don't bypass LlmProviderRegistration plumbing).
  • SSRF ConnectCallback applies at DNS level; don't weaken it for streaming connections.
  • Tool-calling: implement CompleteWithToolsAsync for the compat provider if cheap (OpenAI wire format), else inherit the NotSupported default — the orchestrator degrades gracefully (verified).

Verification

Unit + resilience tests; live smoke against one real compat endpoint (maintainer key) recorded in PR; chat streaming visibly incremental in dev-up.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Status
    Blocked

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions