Skip to content

fix(#4882,#4883): streaming surfaces provider HTTP errors + Kimi region modes#245

Merged
Skobeltsyn merged 1 commit into
mainfrom
fix/kimi-streaming-errors-and-region
Jul 5, 2026
Merged

fix(#4882,#4883): streaming surfaces provider HTTP errors + Kimi region modes#245
Skobeltsyn merged 1 commit into
mainfrom
fix/kimi-streaming-errors-and-region

Conversation

@Skobeltsyn

Copy link
Copy Markdown
Contributor

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.sendChatStream returned response.body() without checking the status. A non-2xx error body has no data: lines, so parseSseStream skipped it and emitted a lone terminal End — a silent, empty, success-looking stream. In production, streaming with an expired key / a 429 / a provider 5xx returned nothing instead of raising.

Now sendChatStream checks statusCode() and throws LlmProviderException (HTTP status + provider label + a bounded slice of the error body), matching the non-streaming chat() 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 HttpServer returning 401 / 503 → asserts chatStream(...).toList() throws LlmProviderException with the status + body (RED before the fix, GREEN after).

#4883 — Kimi region modes

Moonshot/Kimi runs two independent platforms with non-interchangeable keys. New KimiRegion enum (CHINA / INTERNATIONAL) + a model { kimi("moonshot-v1-8k", region = KimiRegion.INTERNATIONAL) } DSL overload make the region an explicit, typed choice instead of a raw baseUrl string. Additivekimi("...") with no region is byte-identical to before (China default preserved); KimiRegion.INTERNATIONAL.baseUrl is also usable as KimiClient(baseUrl = …).

Verification

  • ./gradlew build -x test green: detekt, checkOneTypePerFile, checkReadmeVersion, checkDetektBaseline, DocsConsistencyTest, compile, jar.
  • New tests green; full deterministic suite green. Sole test red was a flaky live-cloud-api Perplexity call — passed on rerun (unrelated to these changes).
  • Docs: OpenAiClient.md adjunct (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.

⚠️ CodeQL java-kotlin will show its known-authorized red (#4383); build is the gate.

🤖 Generated with Claude Code

…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 Skobeltsyn merged commit 3c008a0 into main Jul 5, 2026
3 of 4 checks passed
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 Skobeltsyn deleted the fix/kimi-streaming-errors-and-region branch July 5, 2026 14:15
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant