mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-31 06:56:59 +00:00
Merge 3734837163 into a392a39627
This commit is contained in:
commit
92caf6b0f8
6 changed files with 83 additions and 2 deletions
|
|
@ -417,6 +417,10 @@ DROP_SERVICE_TIER_PROVIDER_WARNING: Final = (
|
|||
"Dropping `service_tier` for model=%s on provider=%s. Only the Anthropic API routes accept it."
|
||||
)
|
||||
|
||||
DROP_THREAD_PROVIDER_WARNING: Final = (
|
||||
"Dropping `thread` for model=%s on provider=%s. Only the Anthropic API keeps Message Threads."
|
||||
)
|
||||
|
||||
DROP_UNSUPPORTED_TOOL_SEARCH_WARNING: Final = (
|
||||
"Dropping the OpenAI `tool_search` tool and the `defer_loading` of the other tools for model=%s on %s "
|
||||
"(drop_params=True) because this route cannot run that tool search."
|
||||
|
|
@ -698,6 +702,17 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
litellm.verbose_logger.warning(DROP_SERVICE_TIER_PROVIDER_WARNING, model, custom_llm_provider)
|
||||
optional_params.pop("service_tier", None)
|
||||
|
||||
@staticmethod
|
||||
def maybe_drop_thread_param(
|
||||
model: str,
|
||||
optional_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
custom_llm_provider: str | None = None,
|
||||
) -> None:
|
||||
if "thread" not in optional_params or custom_llm_provider in (None, "anthropic"):
|
||||
return
|
||||
litellm.verbose_logger.warning(DROP_THREAD_PROVIDER_WARNING, model, custom_llm_provider)
|
||||
optional_params.pop("thread", None)
|
||||
|
||||
@staticmethod
|
||||
def _raise_invalid_reasoning_effort(model: str, value: object, llm_provider: str) -> NoReturn:
|
||||
"""Raise a ``BadRequestError`` for an unrecognised ``reasoning_effort``.
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ class AnthropicAdapter:
|
|||
#########################################################
|
||||
# Created Typed Request Body
|
||||
#########################################################
|
||||
request_body: Final = AnthropicMessagesRequest(model=model, messages=messages, **kwargs)
|
||||
request_body: Final = AnthropicMessagesRequest(model=model, messages=messages, **kwargs) # pyright: ignore[reportUnknownArgumentType] # the request params arrive as a bare dict
|
||||
|
||||
(
|
||||
translated_body,
|
||||
|
|
|
|||
|
|
@ -793,7 +793,7 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
),
|
||||
max_tokens=max_tokens,
|
||||
model=model,
|
||||
**anthropic_messages_optional_request_params,
|
||||
**anthropic_messages_optional_request_params, # pyright: ignore[reportUnknownArgumentType] # the request params arrive as a bare dict
|
||||
)
|
||||
request: Final = (
|
||||
{**dict(anthropic_messages_request), "thinking": gated.thinking}
|
||||
|
|
|
|||
|
|
@ -301,6 +301,11 @@ class AnthropicMessagesRequestUtils:
|
|||
optional_params=filtered_params,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
)
|
||||
AnthropicConfig.maybe_drop_thread_param(
|
||||
model=model,
|
||||
optional_params=filtered_params,
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
)
|
||||
for param in ("temperature", "top_p", "top_k"):
|
||||
if param in filtered_params:
|
||||
AnthropicModelInfo._apply_sampling_param( # pyright: ignore[reportPrivateUsage] # same gating the /chat/completions path applies; forking it would drift
|
||||
|
|
|
|||
|
|
@ -440,6 +440,7 @@ class AnthropicMessagesRequestOptionalParams(TypedDict, total=False):
|
|||
reasoning_effort: str | None
|
||||
safeguards: ReadOnly[list[dict[str, object]] | None]
|
||||
service_tier: ReadOnly[str | None]
|
||||
thread: ReadOnly[Mapping[str, object] | None]
|
||||
|
||||
|
||||
class AnthropicMessagesRequest(AnthropicMessagesRequestOptionalParams, total=False):
|
||||
|
|
|
|||
|
|
@ -1633,6 +1633,66 @@ async def test_anthropic_messages_forwards_safeguards_and_unknown_beta_to_anthro
|
|||
assert response["safeguard_results"] == safeguard_results
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_anthropic_messages_forwards_message_threads_continue_to_anthropic():
|
||||
"""Shape is what Claude Code 2.1.312 sends with the message-threads-2026-08-12 beta, captured 2026-10-29."""
|
||||
from litellm.llms.anthropic.messages.native import handler
|
||||
|
||||
thread = {"type": "continue", "previous_message_id": "msg_01ABC"}
|
||||
tool_result_only = [
|
||||
{"role": "user", "content": [{"type": "tool_result", "tool_use_id": "toolu_01", "content": "README contents"}]}
|
||||
]
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
def upstream_records_the_request(request: httpx.Request) -> httpx.Response:
|
||||
captured["body"] = json.loads(request.content)
|
||||
return httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"id": "msg_02DEF",
|
||||
"type": "message",
|
||||
"role": "assistant",
|
||||
"model": "claude-haiku-4-5",
|
||||
"content": [{"type": "text", "text": "ok"}],
|
||||
"stop_reason": "end_turn",
|
||||
"stop_sequence": None,
|
||||
"usage": {"input_tokens": 1, "output_tokens": 1},
|
||||
},
|
||||
request=request,
|
||||
)
|
||||
|
||||
upstream = AsyncHTTPHandler()
|
||||
upstream.client = httpx.AsyncClient(transport=httpx.MockTransport(upstream_records_the_request))
|
||||
|
||||
await handler.anthropic_messages(
|
||||
max_tokens=16,
|
||||
messages=tool_result_only,
|
||||
model="anthropic/claude-haiku-4-5",
|
||||
custom_llm_provider="anthropic",
|
||||
api_key="sk-test",
|
||||
client=upstream,
|
||||
thread=thread,
|
||||
extra_headers={"anthropic-beta": "message-threads-2026-08-12"},
|
||||
)
|
||||
|
||||
assert captured["body"]["thread"] == thread
|
||||
assert captured["body"]["messages"] == tool_result_only
|
||||
|
||||
|
||||
@pytest.mark.parametrize("custom_llm_provider", ["vertex_ai", "bedrock", "azure_ai", "databricks"])
|
||||
def test_anthropic_messages_drops_thread_where_message_threads_are_not_served(custom_llm_provider: str) -> None:
|
||||
from litellm.llms.anthropic.messages.native.utils import AnthropicMessagesRequestUtils
|
||||
|
||||
optional_params = AnthropicMessagesRequestUtils.get_requested_anthropic_messages_optional_param(
|
||||
params={"max_tokens": 64, "thread": {"type": "create"}},
|
||||
model="claude-haiku-4-5",
|
||||
custom_llm_provider=custom_llm_provider,
|
||||
)
|
||||
|
||||
assert "thread" not in optional_params
|
||||
assert dict(optional_params).get("max_tokens") == 64
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_anthropic_messages_streaming_forwards_safeguards_and_keeps_safeguard_results():
|
||||
"""Shapes are what Claude Code 2.1.278 sends and api.anthropic.com returns, captured 2026-09-21."""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue