feat: recent Claude models (corrected Vertex IDs), /v1/models improvements, and OpenAI->Anthropic bridge#9
Merged
Conversation
…validation Add model aliases for recently released Claude models: - Claude Opus 4.6, 4.7, 4.8 (no @Date suffix) - Claude Sonnet 4.6 (no @Date suffix) - Claude Sonnet 4 (claude-sonnet-4-20250514) Fix model validation in _handle_anthropic(): the previous check `if "@" not in vertex_model` rejects models without a @Date suffix. Replace with a lookup against known aliases so both formats work.
OpenAI-compatible clients expect 'created' and 'owned_by' fields in model listings. Set owned_by to the actual provider (anthropic, google, or the MaaS publisher name).
Clients that set base_url to /anthropic or /gemini now get model listings from their respective prefix: GET /anthropic/v1/models → anthropic models only GET /gemini/v1/models → gemini models only GET /gemini/v1beta/models → gemini models only This fixes Hermes showing '0 models' for vertex-anthropic provider.
…etions Add translation layer so OpenAI Chat Completions clients can call Claude models through the /v1 endpoint. Requests are converted to Anthropic Messages format, sent to Vertex AI, and responses translated back to OpenAI format. Supports both streaming (SSE) and non-streaming modes. New module: openai_anthropic_bridge.py handles all format conversions.
Vertex AI uses two distinct ID conventions split at the Claude 4.6 generation, and several aliases would 404 as previously written: - 4.6-gen (Opus 4.6/4.7/4.8, Sonnet 4.6) use a DATELESS bare id; the bare id is itself the pinned snapshot. These pass through unchanged and must NOT carry an @Date suffix (a suffix 404s on Vertex). - pre-4.6 models carry a snapshot date that Vertex separates with '@', not '-' (the '-' form is the Claude-API id and 404s on Vertex). Corrections: - Sonnet 4: was mapped to the bare Claude-API id 'claude-sonnet-4-20250514' which 404s on Vertex; now maps to the Vertex id 'claude-sonnet-4@20250514'. (Deprecated, retires 2026-06-15; remove after that date.) - Opus 4.5: was '@20250929' (wrong); the Vertex id is '@20251101'. - Haiku 4.5: was '@20250929' (wrong); the Vertex id is '@20251001'. - Renamed the dated alias keys for Opus/Haiku 4.5 to match their corrected snapshot dates. Update test_config alias assertions: the old "every id contains '@'" invariant is wrong for the dateless 4.6-gen ids. Replace it with generation-aware checks (4.6-gen is bare; pre-4.6 uses '@'-separated 8-digit dates) plus explicit checks for the corrected Sonnet 4 / Opus 4.5 / Haiku 4.5 ids. Co-authored-by: Guillaume Nodet <gnodet@gmail.com>
Finalize the OpenAI->Anthropic bridge:
Response path (anthropic_to_openai_response):
- Walk the content array once, accumulating both text and tool_use
blocks. tool_use blocks are now emitted as OpenAI tool_calls with
function.arguments as a JSON string. Previously tool_use was dropped,
so finish_reason could be "tool_calls" with no tool_calls array.
- finish_reason is forced to "tool_calls" whenever tool_calls is
non-empty, so it can never disagree with the array.
- message.content stays null when only tool_calls are present; the
tool_calls key is omitted entirely when empty.
Streaming path (anthropic_stream_to_openai_stream):
- message_delta is now the sole carrier of finish_reason; message_stop
emits only the [DONE] sentinel. Previously both emitted a
finish_reason chunk, which is an invalid double finish_reason for an
OpenAI stream.
- Thread a stream_id generated once per stream from the caller in
main.py so the chunk id is stable across chunks. This also removes
the F541 f-string ('chatcmpl-stream' had no placeholder and was a
non-unique constant id).
- Document that streamed tool_use translation is intentionally out of
scope (stateless line translator cannot accumulate input_json_delta);
non-streaming requests return tool_calls correctly.
Cosmetic:
- Drop a no-op ternary in _convert_message.
Tests:
- Add tests/test_openai_anthropic_bridge.py covering body conversion,
response tool_calls mapping, and streaming (single finish_reason,
message_stop -> [DONE] only, stable stream id).
- Update test_maas_unknown_model_rejected to match the unified
"unknown model '<id>' ... known aliases" error message.
Co-authored-by: Guillaume Nodet <gnodet@gmail.com>
Reflect the shipped alias set: the dateless 4.6-gen ids (Opus 4.6/4.7/ 4.8, Sonnet 4.6) pass through unchanged, and the pre-4.6 ids use the '@'-separated snapshot dates (Opus 4.5 @20251101, Haiku 4.5 @20251001, Sonnet 4 @20250514). Note the do-not-append-@Date caveat for 4.6-gen and the Sonnet 4 retirement date. Co-authored-by: Guillaume Nodet <gnodet@gmail.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.
Finalizes the recent-models + endpoints + bridge work for review. CI runs on this PR.
What is in it:
Note: region default stays us-east5; confirm it serves the 4.6-gen models or switch to a global/multi-region endpoint.