mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-30 01:52:18 +00:00
feat(bedrock_mantle): route Responses API to native OpenAI endpoint
Register BedrockMantleResponsesAPIConfig so /v1/responses hits
bedrock-mantle.{region}.api.aws/openai/v1/responses instead of the
chat-completions fallback. Fix default api_base to use /openai/v1.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
e8fcb01215
commit
f63ce0445b
6 changed files with 96 additions and 6 deletions
|
|
@ -1680,6 +1680,9 @@ if TYPE_CHECKING:
|
|||
from .llms.bedrock_mantle.chat.transformation import (
|
||||
BedrockMantleChatConfig as BedrockMantleChatConfig,
|
||||
)
|
||||
from .llms.bedrock_mantle.responses.transformation import (
|
||||
BedrockMantleResponsesAPIConfig as BedrockMantleResponsesAPIConfig,
|
||||
)
|
||||
from .llms.a2a.chat.transformation import A2AConfig as A2AConfig
|
||||
from .llms.voyage.embedding.transformation import (
|
||||
VoyageEmbeddingConfig as VoyageEmbeddingConfig,
|
||||
|
|
|
|||
|
|
@ -219,6 +219,7 @@ LLM_CONFIG_NAMES = (
|
|||
"OpenAITextCompletionConfig",
|
||||
"GroqChatConfig",
|
||||
"BedrockMantleChatConfig",
|
||||
"BedrockMantleResponsesAPIConfig",
|
||||
"A2AConfig",
|
||||
"GenAIHubOrchestrationConfig",
|
||||
"VoyageEmbeddingConfig",
|
||||
|
|
@ -886,6 +887,10 @@ _LLM_CONFIGS_IMPORT_MAP = {
|
|||
".llms.bedrock_mantle.chat.transformation",
|
||||
"BedrockMantleChatConfig",
|
||||
),
|
||||
"BedrockMantleResponsesAPIConfig": (
|
||||
".llms.bedrock_mantle.responses.transformation",
|
||||
"BedrockMantleResponsesAPIConfig",
|
||||
),
|
||||
"A2AConfig": (".llms.a2a.chat.transformation", "A2AConfig"),
|
||||
"GenAIHubOrchestrationConfig": (
|
||||
".llms.sap.chat.transformation",
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ Amazon Bedrock Mantle - OpenAI-compatible inference engine in Amazon Bedrock.
|
|||
|
||||
API docs: https://docs.aws.amazon.com/bedrock/latest/userguide/bedrock-mantle.html
|
||||
|
||||
Base URL: https://bedrock-mantle.{region}.api.aws/v1
|
||||
Base URL: https://bedrock-mantle.{region}.api.aws/openai/v1
|
||||
Auth: AWS Bedrock API key as Bearer token (set via BEDROCK_MANTLE_API_KEY env var)
|
||||
or region-aware key via BEDROCK_MANTLE_{REGION}_API_KEY.
|
||||
"""
|
||||
|
|
@ -43,7 +43,7 @@ class BedrockMantleChatConfig(OpenAILikeChatConfig):
|
|||
api_base = (
|
||||
api_base
|
||||
or get_secret_str("BEDROCK_MANTLE_API_BASE")
|
||||
or f"https://bedrock-mantle.{region}.api.aws/v1"
|
||||
or f"https://bedrock-mantle.{region}.api.aws/openai/v1"
|
||||
)
|
||||
dynamic_api_key = api_key or get_secret_str("BEDROCK_MANTLE_API_KEY")
|
||||
return api_base, dynamic_api_key
|
||||
|
|
|
|||
61
litellm/llms/bedrock_mantle/responses/transformation.py
Normal file
61
litellm/llms/bedrock_mantle/responses/transformation.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
"""
|
||||
Amazon Bedrock Mantle - OpenAI-compatible Responses API.
|
||||
|
||||
Routes /v1/responses to the provider's native Responses endpoint instead of
|
||||
the chat-completions translation fallback.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from litellm.llms.bedrock_mantle.chat.transformation import BedrockMantleChatConfig
|
||||
from litellm.llms.openai.responses.transformation import OpenAIResponsesAPIConfig
|
||||
from litellm.types.router import GenericLiteLLMParams
|
||||
from litellm.types.utils import LlmProviders
|
||||
|
||||
|
||||
class BedrockMantleResponsesAPIConfig(OpenAIResponsesAPIConfig):
|
||||
@property
|
||||
def custom_llm_provider(self) -> LlmProviders:
|
||||
return LlmProviders.BEDROCK_MANTLE
|
||||
|
||||
def validate_environment(
|
||||
self,
|
||||
headers: dict,
|
||||
model: str,
|
||||
litellm_params: Optional[GenericLiteLLMParams],
|
||||
) -> dict:
|
||||
litellm_params = litellm_params or GenericLiteLLMParams()
|
||||
_, api_key = BedrockMantleChatConfig()._get_openai_compatible_provider_info(
|
||||
api_base=litellm_params.api_base,
|
||||
api_key=litellm_params.api_key,
|
||||
)
|
||||
if api_key:
|
||||
headers["Authorization"] = f"Bearer {api_key}"
|
||||
return headers
|
||||
|
||||
def get_complete_url(
|
||||
self,
|
||||
api_base: Optional[str],
|
||||
litellm_params: dict,
|
||||
) -> str:
|
||||
(
|
||||
resolved_api_base,
|
||||
_,
|
||||
) = BedrockMantleChatConfig()._get_openai_compatible_provider_info(
|
||||
api_base=api_base or litellm_params.get("api_base"),
|
||||
api_key=litellm_params.get("api_key"),
|
||||
)
|
||||
if not resolved_api_base:
|
||||
raise ValueError(
|
||||
"api_base is required for bedrock_mantle Responses API. "
|
||||
"Set BEDROCK_MANTLE_API_BASE or BEDROCK_MANTLE_REGION."
|
||||
)
|
||||
api_base = resolved_api_base.rstrip("/")
|
||||
if api_base.endswith("/responses"):
|
||||
return api_base
|
||||
if api_base.endswith("/v1"):
|
||||
return f"{api_base}/responses"
|
||||
return f"{api_base}/v1/responses"
|
||||
|
||||
def supports_native_websocket(self) -> bool:
|
||||
return False
|
||||
|
|
@ -8865,6 +8865,8 @@ class ProviderConfigManager:
|
|||
return litellm.OpenRouterResponsesAPIConfig()
|
||||
elif litellm.LlmProviders.HOSTED_VLLM == provider:
|
||||
return litellm.HostedVLLMResponsesAPIConfig()
|
||||
elif litellm.LlmProviders.BEDROCK_MANTLE == provider:
|
||||
return litellm.BedrockMantleResponsesAPIConfig()
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
|
|
@ -14,7 +14,11 @@ import pytest
|
|||
|
||||
import litellm
|
||||
from litellm.llms.bedrock_mantle.chat.transformation import BedrockMantleChatConfig
|
||||
from litellm.llms.bedrock_mantle.responses.transformation import (
|
||||
BedrockMantleResponsesAPIConfig,
|
||||
)
|
||||
from litellm.types.utils import LlmProviders
|
||||
from litellm.utils import ProviderConfigManager
|
||||
|
||||
|
||||
class TestBedrockMantleProviderRegistration:
|
||||
|
|
@ -50,7 +54,7 @@ class TestBedrockMantleConfig:
|
|||
monkeypatch.delenv("BEDROCK_MANTLE_API_BASE", raising=False)
|
||||
cfg = BedrockMantleChatConfig()
|
||||
api_base, _ = cfg._get_openai_compatible_provider_info(None, None)
|
||||
assert api_base == "https://bedrock-mantle.eu-west-1.api.aws/v1"
|
||||
assert api_base == "https://bedrock-mantle.eu-west-1.api.aws/openai/v1"
|
||||
|
||||
def test_default_api_base_uses_aws_region(self, monkeypatch):
|
||||
monkeypatch.delenv("BEDROCK_MANTLE_REGION", raising=False)
|
||||
|
|
@ -58,7 +62,7 @@ class TestBedrockMantleConfig:
|
|||
monkeypatch.setenv("AWS_REGION", "ap-northeast-1")
|
||||
cfg = BedrockMantleChatConfig()
|
||||
api_base, _ = cfg._get_openai_compatible_provider_info(None, None)
|
||||
assert api_base == "https://bedrock-mantle.ap-northeast-1.api.aws/v1"
|
||||
assert api_base == "https://bedrock-mantle.ap-northeast-1.api.aws/openai/v1"
|
||||
|
||||
def test_default_api_base_fallback_to_us_east_1(self, monkeypatch):
|
||||
monkeypatch.delenv("BEDROCK_MANTLE_REGION", raising=False)
|
||||
|
|
@ -66,10 +70,10 @@ class TestBedrockMantleConfig:
|
|||
monkeypatch.delenv("AWS_REGION", raising=False)
|
||||
cfg = BedrockMantleChatConfig()
|
||||
api_base, _ = cfg._get_openai_compatible_provider_info(None, None)
|
||||
assert api_base == "https://bedrock-mantle.us-east-1.api.aws/v1"
|
||||
assert api_base == "https://bedrock-mantle.us-east-1.api.aws/openai/v1"
|
||||
|
||||
def test_custom_api_base_overrides_default(self, monkeypatch):
|
||||
custom_base = "https://bedrock-mantle.us-west-2.api.aws/v1"
|
||||
custom_base = "https://bedrock-mantle.us-west-2.api.aws/openai/v1"
|
||||
cfg = BedrockMantleChatConfig()
|
||||
api_base, _ = cfg._get_openai_compatible_provider_info(custom_base, None)
|
||||
assert api_base == custom_base
|
||||
|
|
@ -96,6 +100,21 @@ class TestBedrockMantleConfig:
|
|||
assert "max_tokens" in params
|
||||
|
||||
|
||||
class TestBedrockMantleResponsesConfig:
|
||||
def test_responses_complete_url(self, monkeypatch):
|
||||
monkeypatch.setenv("BEDROCK_MANTLE_REGION", "us-east-1")
|
||||
cfg = BedrockMantleResponsesAPIConfig()
|
||||
url = cfg.get_complete_url(api_base=None, litellm_params={})
|
||||
assert url == "https://bedrock-mantle.us-east-1.api.aws/openai/v1/responses"
|
||||
|
||||
def test_provider_config_manager_registers_responses(self):
|
||||
cfg = ProviderConfigManager.get_provider_responses_api_config(
|
||||
provider="bedrock_mantle",
|
||||
model="gpt-5.5",
|
||||
)
|
||||
assert isinstance(cfg, BedrockMantleResponsesAPIConfig)
|
||||
|
||||
|
||||
class TestBedrockMantleProviderResolution:
|
||||
def test_get_llm_provider_resolves_correctly(self):
|
||||
model, provider, _, _ = litellm.get_llm_provider(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue