Skip to content

fix(anthropic): accept system messages without legacy beta - #408

Merged
astaxie merged 4 commits into
astaxie:mainfrom
wozhenbang2004:fix/anthropic-system-without-beta
Oct 31, 2026
Merged

astaxie merged 4 commits into
astaxie:mainfrom
wozhenbang2004:fix/anthropic-system-without-beta

Conversation

@wozhenbang2004

Copy link
Copy Markdown
Contributor

Summary

Allow mid-conversation system entries at the Anthropic Messages admission boundary without requiring the legacy mid-conversation-system-2026-04-07 beta header. Current Claude Code requests omit that header, so the gateway rejects them before selecting an upstream route.

Anthropic's current documentation no longer requires a beta header for basic mid-conversation system messages on supported models.

Related Issue

Related to #404 — addresses the gateway admission failure only. This intentionally does not resolve the separate compatibility problem for OpenAI-compatible upstreams that prohibit system messages after the first turn.

Changes

  • Accept user, assistant, and system roles independently of the legacy beta token; continue rejecting other roles.
  • Remove the obsolete beta-header admission helper.
  • Preserve native Anthropic payload positions, content blocks, and headers, and retain the existing ordered OpenAI conversion. System messages are not moved or merged, which would change their temporal meaning and prompt-cache prefix.
  • Add regression coverage for absent, current Claude Code, and legacy beta headers across buffered and streaming native/OpenAI-compatible routes, plus token counting.
  • Update the English, Simplified Chinese, and Japanese user guides with the support boundary.

Type of Change

  • Bug fix
  • New feature
  • Refactor or maintenance
  • Documentation
  • Deployment or configuration

Verification

  • Red/green against the original main production file using a Go overlay: eight absent/current-header route cases and token counting fail with 400 invalid_message before the fix, while four legacy-header route cases pass. The patched production passes all cases; unsupported roles remain rejected.
  • Focused real-production route tests pass: all platform-selected production Go files are compiled, along with the new tests and selected existing test declarations/fixtures copied unchanged. The 12-case protocol/header/streaming matrix, token counting, and nine existing protocol/authentication/streaming/unsupported-tool tests pass. This memory-bounded file-list run uses normal compiler flags with serial compilation and lower GC settings; it is not the full package suite.
  • Explicit focused go vet on the same production/test file-list passes.
  • Repository tools: 202 passing tests, two skipped, no failures (204 total). Documentation existence/co-change, UI translations, environment contract, source-size, formatting, and whitespace checks pass.
  • Full official CI passed in fork-only validation PR #1, run 41014952914, on validation head ea89113dd7185aa5ac7ada9e3b12ed2681b14405: all four backend shards (including full vet and pinned golangci-lint), Plugin DevKit, PostgreSQL, database N-1 compatibility, Frontend, Frontend browser smoke, Deployment, Repository gates, and the CI aggregate completed successfully (12/12 jobs). Browser smoke was checked separately because the aggregate does not depend on it.
  • The clean six-file candidate is 8e91601e0dbcb33bd21786cf2df7fbe95c7f3647. The validation head differs only by a fork-only CI adapter: three historical release checkout steps explicitly read the upstream repository at the official v0.4.0/v0.5.0 commit SHAs because this fork has no release tags. All test commands, jobs, pinned actions, and permissions are unchanged; the adapter is excluded from this upstream PR.
  • The local full server test package exceeded compilation resources, so no local full-package pass is claimed; GitHub-hosted CI supplied the full verification above. No credential-dependent live upstream SDK smoke tests were run. HTTP upstream fixtures are synthetic.

Compatibility, Security, and Operations

  • Additive admission change for /v1/messages and /v1/messages/count_tokens; no authentication, model authorization, quota, persistence, environment, or deployment changes.
  • Native upstreams remain responsible for their supported models, message placement, and beta-only extensions. Existing content conversion checks are unchanged.
  • OpenAI-compatible upstreams must already support the resulting ordered system messages. This change does not silently hoist, merge, or downgrade them to user instructions.
  • Rollback is a revert; no data migration is needed.

Checklist

  • The PR title and body are written in English.
  • Tests were added or updated for behavior changes, or the reason they are unnecessary is documented.
  • No credentials, local .env files, databases, backups, or runtime logs are included.
  • Environment variable changes are synchronized across examples, Compose, start.sh, and deployment documentation where applicable. (No environment changes.)
  • Shared user-facing behavior is documented consistently in English, Simplified Chinese, and Japanese where applicable.
  • data/model-catalog.yaml remains tracked and catalog changes were reviewed where applicable. (Catalog unchanged.)
  • git diff --check passes.

@astaxie astaxie left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the complete six-file diff at 8e91601e0dbcb33bd21786cf2df7fbe95c7f3647 against the PR base and the explicitly scoped admission part of #404.

Standards

No actionable findings. The English, Simplified Chinese and Japanese guides consistently describe the support boundary, and the new regressions use synthetic upstream fixtures.

Spec and behavior

No actionable implementation defect found. The change removes the obsolete beta-token admission requirement while preserving supported-role validation, authentication, model authorization, quota reservation, guardrail traversal, native payload/header forwarding and ordered OpenAI conversion. The separate limitation of upstreams that reject mid-conversation system messages is explicitly deferred and documented.

Validation

A focused go test -p 1 ./internal/server run compiles the complete server test package and passes the new 12-case native/OpenAI-compatible, beta-header and streaming matrix, token-count regression, unsupported-role rejection, and existing system-conversion/native-streaming coverage. The full backend suites, local PostgreSQL checks and live vendor SDK tests were not rerun.

GitHub reports no checks on this exact PR head. The fork-only validation described in the PR uses a different commit and is not treated as exact-head CI success; merge validation therefore remains pending. Independent retrieval of the linked Anthropic documentation failed with a TLS error, so this review does not claim to have independently verified its current remote wording. No workflow was approved or triggered.

Standards: 0 findings. Spec/behavior: 0 findings.

@astaxie
astaxie merged commit 54a23d3 into astaxie:main Oct 31, 2026
12 checks passed
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.

2 participants