Skip to content

Custom FX_GATEWAY_CHAT_URL: streaming response finish-event contract undocumented (InvalidProviderFinishReason) #514

Description

@yakimoto

When pointing FX_GATEWAY_CHAT_URL at a custom loopback endpoint, the response streaming contract is partially documented but the FINISH event shape is not — and fx rejects every documented variant.

WHAT WORKS: we captured the request wire format (prompt array body, model in ai-language-model-id header, streaming declared in ai-language-model-streaming) and built a translating proxy that streams responses back. Rendering WORKS when we emit the AI SDK UI stream protocol (SSE with parts: start, start-step, text-start, text-delta, text-end, finish-step, finish) — the model reply visibly streams into the fx UI. A plain OpenAI-completions SSE stream (data: chunk lines + data: [DONE]) does NOT render — fx retries with StreamInterrupted — so the parts protocol appears to be the expected response shape.

WHAT FAILS: after rendering the complete streamed text, fx reports request failed: InvalidProviderFinishReason. We tried every finish-step variant we could derive from the AI SDK stream-protocol docs: bare {"type":"finish-step"}; with finishReason stop; with finishReason unknown; with providerMetadata; with usage; and the message-finish part with and without totalUsage. All rejected identically — the error name suggests fx validates the finish reason against a provider-specific enum the custom-endpoint docs never specify.

ASK: document the exact finish-step/finish event schema a custom FX_GATEWAY_CHAT_URL endpoint must emit (or relax the validation for loopback endpoints). Happy to share our proxy as a reference — it translates a standard OpenAI-compatible upstream into the request/response shapes fx expects, and everything except the terminal event already works.

CONTEXT: this is the same loopback surface as issue #439 (the zero-frame startup). The use case is routing fx inference through a self-hosted model gateway — ours translates to an internal Ollama-backed pool; the request direction works perfectly, streaming render works, only the finish handshake blocks a fully-green custom endpoint.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions