Skip to content

feat(gateway): take official hosts, output fallback and error shapes from core v0.42.0 - #42

Merged
fylorn merged 1 commit into
devfrom
feat/core-official-and-error-frames
Sep 24, 2026
Merged

fylorn merged 1 commit into
devfrom
feat/core-official-and-error-frames

Conversation

@fylorn

@fylorn fylorn commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

Adopts the shared facts core v0.42.0 now carries, in place of this side's own copies.

Changes

  • Official hosts. Upstream::is_official uses tw_dialect::official::is_official_host for standard upstreams (Azure and Bedrock stay official by shape). The local list had three hosts; core's also covers DeepSeek, Moonshot, Zhipu/Z.ai, DashScope, xAI, and *.amazonaws.com, and compares the parsed host, so https://relay/api.openai.com or https://api.openai.com@relay no longer passes as official.
  • anthropic-version comes from tw_dialect::official::ANTHROPIC_VERSION.
  • Default output length. When an upstream requires max_tokens and the caller set none, it is fallback_max_output_tokens(upstream model) (32000 for Claude, 8192 otherwise) instead of a fixed 4096 that cut Claude answers short. There is no per-model output limit stored here to prefer, so this mirrors the desktop's fallback branch.
  • Stream error frames come from tw_dialect::convert::error_frame(client, status, message). Before, a Responses client got a Chat-shaped event: error frame it skips (the stream just stopped); it now gets response.failed. Anthropic clients get an error event whose error.type follows the status.
  • Whole error bodies come from tw_dialect::convert::error_body in the caller's format. GatewayErrorResponse carries the client dialect; every generation handler sets it. Anthropic clients now get {"type":"error","error":{…}}. The Chat/Responses body's type is OpenAI's own vocabulary (rate_limit_error, server_error, invalid_request_error, …) instead of this gateway's tags (rate_limited, provider_http_error, …); status codes and Retry-After are unchanged.
  • The provider connection test builds its URL with tw_dialect::url::upstream_url. tw_dialect::usage was already the only usage parser; tokens() uses Usage::prompt_total.

Tests

  • Unit: official-host spoofing, error body per dialect.
  • Integration (gateway_error_shapes.rs): Anthropic body on an upstream failure and on a refusal before routing, Chat error type, a failing Responses stream ending in response.failed (with the caller's model), a failing Anthropic stream ending in an error event.
  • Local: fmt, clippy (--all-targets and --lib), 679 unit tests, full integration suite with own containers. The only failures were three tests that resolve public hosts (AWS docs MCP, two MCP tool tests hitting "URL host could not be resolved"), which depend on this machine's DNS and are untouched here.

🤖 Generated with Claude Code

…from core v0.42.0

- `tw_dialect::official::is_official_host` replaces the three-host list
  in transport, so DeepSeek, Moonshot, Z.ai and the rest are official
  too and a relay cannot pass itself off as one through its path or
  user info. `ANTHROPIC_VERSION` comes from there as well.
- The output length written for an upstream that requires one is
  `fallback_max_output_tokens(model)` (32000 for Claude, 8192 else)
  instead of a fixed 4096 that cut Claude answers short.
- Stream error frames come from `tw_dialect::convert::error_frame`:
  Responses clients get `response.failed`, Anthropic clients an
  `error` event of the right type, instead of Chat-shaped frames they
  skip.
- Whole error bodies come from `tw_dialect::convert::error_body` in
  the caller's format. The Chat body's `type` is now OpenAI's own
  vocabulary (`rate_limit_error`, `server_error`, ...).
- The provider test builds its URL with `tw_dialect::url::upstream_url`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@fylorn
fylorn merged commit 3a617f3 into dev Sep 24, 2026
6 checks passed
@fylorn
fylorn deleted the feat/core-official-and-error-frames branch September 24, 2026 07:49
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