TAS-32: Anthropic Bedrock Bridge#386
Conversation
Add POST /anthropic/{routeId}/v1/messages so clients speaking the native
Anthropic Messages API (e.g. Claude Code via ANTHROPIC_BASE_URL) can drive
Claude models hosted in Amazon Bedrock, with AI Studio applying auth, budget,
filters, and analytics.
- Translate Anthropic Messages <-> Bedrock Converse (text, tool_use,
tool_result, system, tool_choice) plus prompt caching pass-through
(cache_control -> Converse cache points).
- Stream Converse events as the Anthropic SSE sequence (message_start,
content_block_start/delta/stop with input_json_delta for tool calls,
message_delta, message_stop).
- Converters live in vendors/bedrock; HTTP/SSE orchestration in proxy,
reusing NewBedrockClient, budget/filter/analytics recorders.
- Auth: reuse Bearer app-secret path; add x-api-key fallback for /anthropic.
- Model resolves to the LLM default_model (Bedrock ID) validated against
allowed_models; the client's model name is echoed back.
Deferred: image content blocks, /v1/messages/count_tokens.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cted]" Secret metadata fields (e.g. a Bedrock LLM's aws_access_key_id / aws_secret_access_key / aws_session_token) are redacted to "[redacted]" in GET responses, so the edit form loads placeholders. On save, UpdateLLM overwrote metadata verbatim, persisting "[redacted]" as the real credential and breaking the provider (AWS: UnrecognizedClientException). UpdateLLM now merges metadata via mergeMetadataPreservingRedacted: a field sent as "[redacted]" keeps its existing stored value (mirroring the api_key and datasource-credential handling), a changed field overwrites, and an omitted field is dropped (so e.g. a session token can still be cleared). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an "Anthropic-Compatible Endpoint" card to an app's LLM Access Details,
rendered only for bedrock-vendor LLMs. It displays {proxyUrl}/anthropic/{slug}
(the ANTHROPIC_BASE_URL for the Anthropic Messages -> Bedrock bridge) with a
copy button and usage note, matching the existing OpenAI-Compatible card.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the two coverage gaps that were previously only manually verified:
- Auth wiring (anthropic_bedrock_auth_test.go): end-to-end through createHandler
and the credential validator on /anthropic/{routeId}/v1/messages — valid
x-api-key and Authorization: Bearer both authenticate (reach model resolution),
while an invalid key and missing credentials are rejected with 401. The LLM has
no default_model so authenticated requests stop at model resolution before any
AWS call, isolating auth without a live Bedrock backend.
- Handler error branches (anthropic_bedrock_handler_test.go): entry-handler early
rejections (route not found, non-Bedrock vendor, invalid body, empty messages)
and resolveAnthropicModelID governance (missing default_model, model not in
allowed_models, allowed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ridge Complete the prompt-caching acceptance criterion: previously only cache_control -> cachePoint request insertion was implemented. Now cache-token usage flows back through responses and analytics. - Anthropic response usage gains cache_creation_input_tokens / cache_read_input_tokens, mapped from Bedrock Converse CacheWriteInputTokens / CacheReadInputTokens (non-streaming + streaming message_delta). - recordBedrockChatRecord records CacheWritePromptTokens / CacheReadPromptTokens and costs them via ModelPrice.CacheWritePT / CacheReadPT; this also feeds the existing cache_read / cache_write metrics. Cache tokens are captured from the Converse usage across all Bedrock paths (/ai non-streaming + streaming, /llm/stream native, and the /anthropic bridge). Tests: response and streaming unit tests assert the mapped cache-token usage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
This PR introduces a translation bridge to allow clients using the native Anthropic Messages API to connect to Amazon Bedrock models through AI Studio. This brings Bedrock usage by Anthropic-native tools under the full governance of AI Studio, including authentication, budget management, content filtering, and analytics. Previously, AI Studio only exposed Bedrock via an OpenAI-compatible endpoint, which was incompatible with clients expecting the Anthropic API format. This change adds a new endpoint, The implementation includes support for text, multi-turn tool-use, system prompts, and streaming (SSE). It also correctly maps prompt-caching directives and token counts (including cache-related tokens) into AI Studio's analytics. Additionally, the PR contains two important related changes:
Files Changed AnalysisThe changes are centered in the
Architecture & Impact Assessment
Scope Discovery & Context ExpansionWhile the primary feature is the new translation bridge, the changes have a broader impact:
Metadata
Powered by Visor from Probelabs Last updated: 2026-07-21T16:22:49.350Z | Triggered by: pr_updated | Commit: cc86a4d 💡 TIP: You can chat with Visor using |
Security Issues (2)
Security Issues (2)
Performance Issues (3)
Quality Issues (2)
Powered by Visor from Probelabs Last updated: 2026-07-21T16:22:38.923Z | Triggered by: pr_updated | Commit: cc86a4d 💡 TIP: You can chat with Visor using |
…plane The bridge's routing, auth, and translation all live inside the shared gateway handler (proxy.createHandler, reached via aigateway.Gateway.Handler()). The studio embedded gateway already served /anthropic; the microgateway's gin router only forwarded /llm, /tools, /datasource, and /ai, so /anthropic 404'd on the edge/data plane. Forward /anthropic/*path to the gateway handler, same as /ai/. Adds a routing test mirroring SetupRouter's gateway-mount block. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Re: 🟠 Performance — "A new Amazon Bedrock client is created for every incoming request" (
|
The Anthropic bridge handlers call bedrockVendor.NewBedrockClient(conf), whose name reads like a per-request constructor but actually returns a cached client (sync.Map keyed by LLM ID + credential fingerprint; see vendors/bedrock/bedrock.go). Add an inline note at both call sites so the caching is obvious to readers (and to static reviewers). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Re:
|
Summary
Adds a native Anthropic Messages API → Amazon Bedrock bridge so Claude Code (and any Anthropic-SDK client) can drive Claude models hosted in Bedrock through AI Studio, with full governance — auth, budget, filters, and analytics — instead of bypassing it via
CLAUDE_CODE_USE_BEDROCK.Jira: TAS-32
Before this change, AI Studio only exposed Bedrock through an OpenAI-compatible endpoint (
/ai/{routeId}/v1/chat/completions). Claude Code speaks only the native Anthropic Messages API (POST /v1/messages), so pointing it at a Bedrock LLM didn't work. This adds the missing translation layer.How it works
POST /anthropic/{routeId}/v1/messages→ credential validator (App key) → budget + filters → translate Anthropic Messages ⇄ Bedrock Converse → SigV4-signed call to Bedrock → response translated back → analytics recorded. AWS credentials never leave AI Studio.It follows the existing translation-layer pattern (sibling of the
/ai/router), not the/llm/pass-through: a dedicatedanthropicRouteroutside/llm/middleware →credValidator→ inline model validation → direct Bedrock SDK calls.What's covered
tool_use/tool_result), and system prompts — mapped both ways between Anthropic content blocks and Converse content blocks.message_start→content_block_start/delta/stop→message_delta→message_stop), includinginput_json_deltafor streamed tool arguments.cache_controlmarkers → ConversecachePointblocks (message / system / tools); cache-token usage mapped back on responses + streaming (cache_creation_input_tokens/cache_read_input_tokens) and into analytics/metrics.x-api-keyorAuthorization: Bearer.default_model(a real Bedrock ID; Claude Code's own model name isn't one), validated againstallowed_models./ai/Bedrock path.Changes
proxy/anthropic_messages_models.go(new)vendors/bedrock/anthropic_converse.go(new)proxy/anthropic_bedrock_translator.go(new)anthropicRouter,combinedHandlerdispatch)proxy/proxy.goanthropicpath case +x-api-keyfallback)proxy/credential_validator.goproxy/bedrock_translator.go,proxy/bedrock_streaming.goAlso included (bug found during testing):
services/llm_service.go): editing/saving an LLM was persisting the redacted[redacted]placeholder over real metadata credentials (broke Bedrock AWS keys).UpdateLLMnow preserves the stored value for any metadata field submitted as[redacted], mirroring the existingapi_keyhandling.ui/admin-frontend/src/portal/components/AppDetailView.js).No changes to the LLM/App configuration schema.
Testing
Automated (
go test ./proxy/... ./services/...— green):tool_use/tool_result/ system, cache-point insertion,tool_choice, stop-reason mapping, response mapping incl. cache-token usage.input_json_delta, cache-token usage onmessage_delta.x-api-keyandBearerboth authenticate on/anthropic/{routeId}/v1/messages; invalid/missing → 401 (end-to-end throughcreateHandler).Manual e2e: ran a real Claude Code session against
/anthropic/<slug>(streaming, multi-turn tool use — create/edit files, run tests). Verified streamed output, tool execution, and 16/16 requests logged + metered in AI Studio.Not covered / follow-ups
Converse/ConverseStreamround-trip is exercised only by the manual e2e —NewBedrockClientreturns a concrete*bedrockruntime.Clientwith no mockable interface (same limit as the existing/ai/Bedrock path)./v1/messages/count_tokens(neither required for Claude Code).Reviewer notes — local test