mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-28 06:23:07 +00:00
fix(azure_ai): forward the thinking-binding-controls beta header to Foundry (#48033)
This commit is contained in:
parent
acfa7a29ad
commit
23ccff69a1
5 changed files with 72 additions and 6 deletions
|
|
@ -235,7 +235,10 @@ impl AnthropicBeta {
|
|||
BetaProvider::Databricks,
|
||||
],
|
||||
Self::Compact20260112 => &[BetaProvider::AzureAi, BetaProvider::BedrockConverse],
|
||||
Self::ComputerUse20250124 | Self::ComputerUse20251124 | Self::Context1m20250807 => &[],
|
||||
Self::ComputerUse20250124
|
||||
| Self::ComputerUse20251124
|
||||
| Self::Context1m20250807
|
||||
| Self::ThinkingBindingControls20260801 => &[],
|
||||
Self::DangerousToolUse20260903 => &[BetaProvider::BedrockConverse],
|
||||
Self::Effort20251124 => &[BetaProvider::VertexAi],
|
||||
Self::FastMode20260201 | Self::Oauth20250420 => &[
|
||||
|
|
@ -272,7 +275,6 @@ impl AnthropicBeta {
|
|||
BetaProvider::Databricks,
|
||||
],
|
||||
Self::StructuredOutputs20251113 => &[BetaProvider::Bedrock, BetaProvider::VertexAi],
|
||||
Self::ThinkingBindingControls20260801 => &[BetaProvider::AzureAi],
|
||||
Self::ThinkingDisplayUpdates20260818 => &[BetaProvider::Databricks],
|
||||
Self::ToolSearchTool20251019 => &[
|
||||
BetaProvider::Anthropic,
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
"structured-outputs-2025-11-13": "structured-outputs-2025-11-13",
|
||||
"text_editor_20241022": null,
|
||||
"text_editor_20250124": null,
|
||||
"thinking-binding-controls-2026-08-01": null,
|
||||
"thinking-binding-controls-2026-08-01": "thinking-binding-controls-2026-08-01",
|
||||
"thinking-display-updates-2026-08-18": "thinking-display-updates-2026-08-18",
|
||||
"token-efficient-tools-2025-02-19": null,
|
||||
"web-fetch-2025-09-10": "web-fetch-2025-09-10",
|
||||
|
|
|
|||
|
|
@ -4278,6 +4278,9 @@ _ANTHROPIC_API_HEADER_PROVIDERS: Final = ",".join(
|
|||
LlmProviders.VERTEX_AI.value,
|
||||
)
|
||||
)
|
||||
_NATIVE_MESSAGES_ANTHROPIC_API_HEADER_PROVIDERS: Final = ",".join(
|
||||
(LlmProviders.AZURE_AI.value, LlmProviders.DATABRICKS.value)
|
||||
)
|
||||
_ANTHROPIC_OAUTH_CREDENTIAL_PROVIDERS: Final = ",".join(sorted(ANTHROPIC_OAUTH_FORWARD_PROVIDERS))
|
||||
|
||||
|
||||
|
|
@ -4306,7 +4309,7 @@ def add_provider_specific_headers_to_request(
|
|||
custom_llm_provider=_ANTHROPIC_API_HEADER_PROVIDERS, extra_headers=anthropic_api_headers
|
||||
),
|
||||
ProviderSpecificHeader(
|
||||
custom_llm_provider=LlmProviders.DATABRICKS.value,
|
||||
custom_llm_provider=_NATIVE_MESSAGES_ANTHROPIC_API_HEADER_PROVIDERS,
|
||||
extra_headers=anthropic_api_headers,
|
||||
native_anthropic_messages_only=True,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -8111,6 +8111,67 @@ def test_client_anthropic_api_headers_stay_off_openai_compatible_providers():
|
|||
assert forwarded == {}
|
||||
|
||||
|
||||
def test_client_anthropic_api_headers_stay_off_azure_ai_outside_native_messages():
|
||||
forwarded = _headers_forwarded_to({"anthropic-beta": "thinking-binding-controls-2026-08-01"}, "azure_ai")
|
||||
|
||||
assert forwarded == {}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("local_beta_headers_config")
|
||||
async def test_client_thinking_binding_beta_reaches_azure_ai_foundry_claude():
|
||||
import httpx
|
||||
|
||||
from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler
|
||||
|
||||
data: Final[dict] = {"model": "claude-opus-4-8"} # mutable-ok: the function under test writes into it
|
||||
add_provider_specific_headers_to_request(
|
||||
data=data,
|
||||
headers={
|
||||
"content-type": "application/json",
|
||||
"anthropic-beta": "thinking-binding-controls-2026-08-01",
|
||||
"anthropic-version": "2026-08-01",
|
||||
},
|
||||
)
|
||||
received: Final[list[httpx.Request]] = [] # mutable-ok: the fake Foundry endpoint records what the proxy sent
|
||||
|
||||
def foundry_answers(request: httpx.Request) -> httpx.Response:
|
||||
received.append(request)
|
||||
return httpx.Response(
|
||||
status_code=200,
|
||||
json={
|
||||
"id": "msg_01",
|
||||
"type": "message",
|
||||
"role": "assistant",
|
||||
"model": "claude-opus-4-8",
|
||||
"content": [{"type": "text", "text": "hello"}],
|
||||
"stop_reason": "end_turn",
|
||||
"stop_sequence": None,
|
||||
"usage": {"input_tokens": 12, "output_tokens": 6},
|
||||
},
|
||||
request=request,
|
||||
)
|
||||
|
||||
upstream: Final = AsyncHTTPHandler(transport=httpx.MockTransport(foundry_answers))
|
||||
try:
|
||||
await litellm.anthropic.messages.acreate(
|
||||
max_tokens=16,
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
thinking={"type": "adaptive", "block_binding": {"prefix_mismatch_behavior": "drop_block"}},
|
||||
model="azure_ai/claude-opus-4-8",
|
||||
api_key="foundry-key",
|
||||
api_base="https://my-resource.services.ai.azure.com/anthropic",
|
||||
client=upstream,
|
||||
provider_specific_header=data["provider_specific_header"],
|
||||
)
|
||||
finally:
|
||||
await upstream.close()
|
||||
|
||||
assert received[0].headers["anthropic-beta"] == "thinking-binding-controls-2026-08-01"
|
||||
assert received[0].headers["anthropic-version"] == "2026-08-01"
|
||||
assert json.loads(received[0].content)["thinking"]["block_binding"] == {"prefix_mismatch_behavior": "drop_block"}
|
||||
|
||||
|
||||
TYPESAFE_DANGER_ZONE_HEADERS = {
|
||||
"TypeSafe-Danger-Zone-Images": "true",
|
||||
"typesafe-danger-zone-long-context": "true",
|
||||
|
|
|
|||
|
|
@ -429,13 +429,13 @@ class TestAnthropicBetaHeadersFiltering:
|
|||
assert filtered == ["fine-grained-tool-streaming-2025-05-14"]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"provider", ["anthropic", "bedrock", "bedrock_converse", "vertex_ai", "databricks"]
|
||||
"provider", ["anthropic", "azure_ai", "bedrock", "bedrock_converse", "vertex_ai", "databricks"]
|
||||
)
|
||||
def test_thinking_binding_controls_forwarded(self, provider):
|
||||
"""`thinking.block_binding` (preserved thinking, Claude Fable 5.1) is only
|
||||
accepted alongside thinking-binding-controls-2026-08-01. The body field is
|
||||
forwarded untouched, so stripping the header (previously unknown, hence
|
||||
dropped) makes Bedrock and Vertex reject the request with
|
||||
dropped) makes Bedrock, Vertex and Azure AI Foundry reject the request with
|
||||
"thinking.adaptive.block_binding: Extra inputs are not permitted"."""
|
||||
filtered = filter_and_transform_beta_headers(
|
||||
beta_headers=["thinking-binding-controls-2026-08-01"],
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue