fix(#4882,#4883): streaming surfaces provider HTTP errors + Kimi region modes#245
Merged
Merged
Conversation
…on modes
#4882 — OpenAI-compatible streaming no longer swallows non-2xx responses.
`OpenAiClient.sendChatStream` returned `response.body()` without checking the status; an error
body (no `data:` lines) was swallowed by `parseSseStream` into a lone terminal `End` — a silent,
empty, success-looking stream. Now checks `statusCode()` and throws `LlmProviderException`
(status + provider label + bounded error-body slice), matching the non-streaming `chat()` contract.
Fixes silent-empty-output on expired-key / 429 / 5xx for OpenAI, DeepSeek, Kimi, OpenRouter,
Perplexity. Kimi's region-hint wrapping (#4511) still applies. TDD: local 401/503 HttpServer →
assert LlmProviderException.
#4883 — Kimi region modes. New `KimiRegion` enum (CHINA / INTERNATIONAL) + a
`model { kimi("model", region = KimiRegion.INTERNATIONAL) }` DSL overload. Additive: `kimi("model")`
with no region keeps the China default byte-identical. `KimiRegion.INTERNATIONAL.baseUrl` also usable
as `KimiClient(baseUrl = …)`.
Docs: OpenAiClient.md adjunct (streaming error boundary), providers.md (Kimi regions section),
CHANGELOG. Full ./gradlew build green (detekt, checkOneTypePerFile, DocsConsistency, all guards);
sole test red was a flaky live-cloud-api Perplexity call, passed on rerun.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Skobeltsyn
added a commit
that referenced
this pull request
Jul 5, 2026
…on modes (#4883) Brings the two model-layer fixes (merged to main in #245, commit b5bde38 / merge 3c008a0) into the 0.8.2 release: streaming non-2xx now throws LlmProviderException instead of a silent empty stream; KimiRegion China/International DSL modes. CHANGELOG entries moved under [0.8.2]; release summary updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Skobeltsyn
added a commit
that referenced
this pull request
Jul 5, 2026
Version 0.8.2-SNAPSHOT → 0.8.2. Contents (all tickets closed): - x402 buyer trust hardening: mandatory guardrails + binding + deterministic offer selection (#4736) - x402 cross-payment session limits + X402Signer seam (#4739) - x402 CAIP-2 network ids (v2 interop step; v1 wire) (#4740) - release-truth: machine-readable release-metadata.yaml + ReleaseMetadataConsistencyTest (#4735) - streaming surfaces provider HTTP errors instead of a silent empty stream (#4882) - Kimi region modes: KimiRegion China/International (#4883) Single release-cut commit atop main (which already carries the #4882/#4883 code via PR #245), so this merges conflict-free. Surfaces synced to 0.8.2: build.gradle version, README dep + Current Release, release-metadata.yaml currentRelease, roadmap, comparison, CHANGELOG [0.8.2] - 2026-07-01. Full ./gradlew build green (detekt, checkReadmeVersion release-mode, checkDetektBaseline, ReleaseMetadataConsistencyTest, checkOneTypePerFile, DocsConsistency). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two model-layer fixes that fell out of investigating a persistent live-integration failure (Kimi streaming).
#4882 — streaming no longer swallows provider HTTP errors
OpenAiClient.sendChatStreamreturnedresponse.body()without checking the status. A non-2xx error body has nodata:lines, soparseSseStreamskipped it and emitted a lone terminalEnd— a silent, empty, success-looking stream. In production, streaming with an expired key / a 429 / a provider 5xx returned nothing instead of raising.Now
sendChatStreamchecksstatusCode()and throwsLlmProviderException(HTTP status + provider label + a bounded slice of the error body), matching the non-streamingchat()contract. Affects every OpenAI-compatible provider: OpenAI, DeepSeek, Kimi, OpenRouter, Perplexity. Kimi's region-hint wrapping (#4511) still applies on auth errors.TDD: a local
HttpServerreturning 401 / 503 → assertschatStream(...).toList()throwsLlmProviderExceptionwith the status + body (RED before the fix, GREEN after).#4883 — Kimi region modes
Moonshot/Kimi runs two independent platforms with non-interchangeable keys. New
KimiRegionenum (CHINA/INTERNATIONAL) + amodel { kimi("moonshot-v1-8k", region = KimiRegion.INTERNATIONAL) }DSL overload make the region an explicit, typed choice instead of a rawbaseUrlstring. Additive —kimi("...")with no region is byte-identical to before (China default preserved);KimiRegion.INTERNATIONAL.baseUrlis also usable asKimiClient(baseUrl = …).Verification
./gradlew build -x testgreen: detekt,checkOneTypePerFile,checkReadmeVersion,checkDetektBaseline,DocsConsistencyTest, compile, jar.live-cloud-apiPerplexity call — passed on rerun (unrelated to these changes).OpenAiClient.mdadjunct (streaming error boundary) +providers.md(Kimi regions) + CHANGELOG.Pre-existing bug (streaming untouched by 0.8.2) — not a release regression; targets
main(0.8.3-bound), independent of the 0.8.2 release PR #244.java-kotlinwill show its known-authorized red (#4383);buildis the gate.🤖 Generated with Claude Code