mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-12 08:42:18 +00:00
Merge 4e9afe41da into 467847b2e9
This commit is contained in:
commit
30d23a967d
24 changed files with 827 additions and 45 deletions
|
|
@ -122,6 +122,7 @@ mod tests {
|
|||
"supports_reasoning": true,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_always_on": false,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_legacy_thinking": false,
|
||||
"supports_output_config": true,
|
||||
"supports_sampling_params": false,
|
||||
|
|
@ -144,6 +145,7 @@ mod tests {
|
|||
supports_reasoning: true,
|
||||
supports_adaptive_thinking: true,
|
||||
thinking_always_on: false,
|
||||
thinking_on_by_default: true,
|
||||
supports_legacy_thinking: false,
|
||||
supports_output_config: true,
|
||||
supports_sampling_params: false,
|
||||
|
|
|
|||
|
|
@ -1882,6 +1882,7 @@ mod tests {
|
|||
supports_reasoning: false,
|
||||
supports_adaptive_thinking: false,
|
||||
thinking_always_on: false,
|
||||
thinking_on_by_default: false,
|
||||
supports_legacy_thinking: false,
|
||||
supports_output_config: false,
|
||||
supports_sampling_params: true,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use litellm_llms_types::{
|
|||
formats::{
|
||||
chat_completions::ReasoningEffort,
|
||||
messages::{
|
||||
EffortLevel, MessagesOptionalParams, MessagesRequest, OutputConfig, ThinkingConfig,
|
||||
ThinkingDisplay,
|
||||
ContextEdit, ContextManagement, EffortLevel, MessagesOptionalParams, MessagesRequest,
|
||||
OutputConfig, ThinkingConfig, ThinkingDisplay,
|
||||
},
|
||||
},
|
||||
recognized::Recognized,
|
||||
|
|
@ -144,6 +144,60 @@ fn legacy_reasoning_effort(
|
|||
}
|
||||
}
|
||||
|
||||
fn is_clear_thinking_edit(edit: &Recognized<ContextEdit>) -> bool {
|
||||
match edit {
|
||||
Recognized::Known(ContextEdit::ClearThinking { .. }) => true,
|
||||
Recognized::Known(_) => false,
|
||||
Recognized::Unrecognized(value) => value
|
||||
.get("type")
|
||||
.and_then(Value::as_str)
|
||||
.is_some_and(|edit_type| edit_type.starts_with("clear_thinking_")),
|
||||
}
|
||||
}
|
||||
|
||||
/// Anthropic rejects `clear_thinking_*` edits without thinking. `context_management` goes
|
||||
/// only when such an edit was removed and nothing else is left in it.
|
||||
fn without_clear_thinking_edits(
|
||||
context_management: Option<Recognized<ContextManagement>>,
|
||||
) -> Option<Recognized<ContextManagement>> {
|
||||
match context_management {
|
||||
Some(Recognized::Known(ContextManagement {
|
||||
edits: Some(edits),
|
||||
extra,
|
||||
})) if edits.iter().any(is_clear_thinking_edit) => {
|
||||
let kept: Vec<_> = edits
|
||||
.into_iter()
|
||||
.filter(|edit| !is_clear_thinking_edit(edit))
|
||||
.collect();
|
||||
(!kept.is_empty() || !extra.is_empty()).then(|| {
|
||||
Recognized::Known(ContextManagement {
|
||||
edits: Some(kept),
|
||||
extra,
|
||||
})
|
||||
})
|
||||
}
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
fn without_thinking(
|
||||
params: MessagesOptionalParams,
|
||||
context: &ThinkingContext,
|
||||
) -> MessagesOptionalParams {
|
||||
let thinks_without_thinking_param =
|
||||
context.capabilities.thinking_always_on || context.capabilities.thinking_on_by_default;
|
||||
let context_management = if thinks_without_thinking_param {
|
||||
params.context_management
|
||||
} else {
|
||||
without_clear_thinking_edits(params.context_management)
|
||||
};
|
||||
MessagesOptionalParams {
|
||||
thinking: None,
|
||||
context_management,
|
||||
..params
|
||||
}
|
||||
}
|
||||
|
||||
fn translate_reasoning_effort(
|
||||
request: MessagesRequest,
|
||||
context: &ThinkingContext,
|
||||
|
|
@ -171,9 +225,8 @@ fn translate_reasoning_effort(
|
|||
) else {
|
||||
return Ok(MessagesRequest {
|
||||
params: MessagesOptionalParams {
|
||||
thinking: None,
|
||||
output_config: None,
|
||||
..request.params
|
||||
..without_thinking(request.params, context)
|
||||
},
|
||||
..request
|
||||
});
|
||||
|
|
@ -199,7 +252,13 @@ fn translate_reasoning_effort(
|
|||
});
|
||||
}
|
||||
let Some(budget) = fit_budget_to_max_tokens(budget, request.params.max_tokens) else {
|
||||
return Ok(request);
|
||||
if request.params.thinking.is_some() {
|
||||
return Ok(request);
|
||||
}
|
||||
return Ok(MessagesRequest {
|
||||
params: without_thinking(request.params, context),
|
||||
..request
|
||||
});
|
||||
};
|
||||
let enabled = ThinkingConfig::enabled(budget);
|
||||
Ok(MessagesRequest {
|
||||
|
|
@ -277,15 +336,11 @@ fn translate_adaptive_effort_for_non_adaptive_model(
|
|||
_ => true,
|
||||
};
|
||||
if supports_effort_param(capabilities) && (!adaptive_thinking || level_accepted) {
|
||||
if !adaptive_thinking {
|
||||
return Ok(request);
|
||||
}
|
||||
return Ok(MessagesRequest {
|
||||
params: MessagesOptionalParams {
|
||||
thinking: if adaptive_thinking {
|
||||
None
|
||||
} else {
|
||||
request.params.thinking
|
||||
},
|
||||
..request.params
|
||||
},
|
||||
params: without_thinking(request.params, context),
|
||||
..request
|
||||
});
|
||||
}
|
||||
|
|
@ -294,13 +349,17 @@ fn translate_adaptive_effort_for_non_adaptive_model(
|
|||
} else {
|
||||
None
|
||||
};
|
||||
let thinking = budget
|
||||
.and_then(|budget| fit_budget_to_max_tokens(budget, request.params.max_tokens))
|
||||
.map(|budget| Recognized::Known(ThinkingConfig::enabled(budget)));
|
||||
let params = MessagesOptionalParams {
|
||||
output_config: without_effort(request.params.output_config),
|
||||
..request.params
|
||||
};
|
||||
Ok(MessagesRequest {
|
||||
params: MessagesOptionalParams {
|
||||
thinking: budget
|
||||
.and_then(|budget| fit_budget_to_max_tokens(budget, request.params.max_tokens))
|
||||
.map(|budget| Recognized::Known(ThinkingConfig::enabled(budget))),
|
||||
output_config: without_effort(request.params.output_config),
|
||||
..request.params
|
||||
params: match thinking {
|
||||
Some(_) => MessagesOptionalParams { thinking, ..params },
|
||||
None => without_thinking(params, context),
|
||||
},
|
||||
..request
|
||||
})
|
||||
|
|
@ -458,6 +517,14 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
fn sonnet_5() -> MessagesModelCapabilities {
|
||||
MessagesModelCapabilities {
|
||||
thinking_on_by_default: true,
|
||||
..opus_4_7()
|
||||
}
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
fn newfamily_6() -> MessagesModelCapabilities {
|
||||
MessagesModelCapabilities {
|
||||
|
|
@ -625,6 +692,120 @@ mod tests {
|
|||
assert_eq!(translate(capabilities, input), Ok(request(expected)));
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::reasoning_effort_none(
|
||||
haiku_4_5(),
|
||||
serde_json::json!({"max_tokens": 8192, "reasoning_effort": "none"}),
|
||||
false
|
||||
)]
|
||||
#[case::reasoning_effort_high(
|
||||
haiku_4_5(),
|
||||
serde_json::json!({"max_tokens": 8192, "reasoning_effort": "high"}),
|
||||
true
|
||||
)]
|
||||
#[case::reasoning_effort_budget_cannot_fit(
|
||||
haiku_4_5(),
|
||||
serde_json::json!({"max_tokens": 1024, "reasoning_effort": "high"}),
|
||||
false
|
||||
)]
|
||||
#[case::caller_thinking_kept_when_budget_cannot_fit(
|
||||
haiku_4_5(),
|
||||
serde_json::json!({
|
||||
"max_tokens": 1024,
|
||||
"reasoning_effort": "high",
|
||||
"thinking": {"type": "enabled", "budget_tokens": 1000}
|
||||
}),
|
||||
true
|
||||
)]
|
||||
#[case::effort_model_drops_adaptive(opus_4_5(), claude_code_payload("high", 8192), false)]
|
||||
#[case::adaptive_model_keeps_adaptive(sonnet_4_6(), claude_code_payload("high", 8192), true)]
|
||||
#[case::non_reasoning_model(haiku_3_5(), claude_code_payload("high", 8192), false)]
|
||||
#[case::legacy_thinking_model(haiku_4_5(), claude_code_payload("high", 8192), true)]
|
||||
#[case::always_on_model_keeps_edit(
|
||||
fable_5_1(),
|
||||
serde_json::json!({"max_tokens": 8192, "reasoning_effort": "none"}),
|
||||
true
|
||||
)]
|
||||
#[case::default_thinking_model_keeps_edit(
|
||||
sonnet_5(),
|
||||
serde_json::json!({"max_tokens": 8192, "reasoning_effort": "none"}),
|
||||
true
|
||||
)]
|
||||
#[case::adaptive_model_without_default_thinking_drops_edit(
|
||||
opus_4_7(),
|
||||
serde_json::json!({"max_tokens": 8192, "reasoning_effort": "none"}),
|
||||
false
|
||||
)]
|
||||
fn clear_thinking_edit_is_dropped_with_thinking_except_on_models_that_think_by_default(
|
||||
#[case] capabilities: MessagesModelCapabilities,
|
||||
#[case] fields: Value,
|
||||
#[case] keeps_edit: bool,
|
||||
) {
|
||||
let mut fields = fields;
|
||||
fields.as_object_mut().unwrap().insert(
|
||||
"context_management".into(),
|
||||
serde_json::json!({"edits": [{"type": "clear_thinking_20251015", "keep": "all"}, {"type": "clear_tool_uses_20250919"}]}),
|
||||
);
|
||||
let thinks_without_thinking_param =
|
||||
capabilities.thinking_always_on || capabilities.thinking_on_by_default;
|
||||
let translated = serde_json::to_value(translate(capabilities, fields).unwrap()).unwrap();
|
||||
let edit_types: Vec<&str> = translated["context_management"]["edits"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter_map(|edit| edit["type"].as_str())
|
||||
.collect();
|
||||
let expected: &[&str] = if keeps_edit {
|
||||
&["clear_thinking_20251015", "clear_tool_uses_20250919"]
|
||||
} else {
|
||||
&["clear_tool_uses_20250919"]
|
||||
};
|
||||
assert_eq!(edit_types, expected);
|
||||
assert_eq!(
|
||||
translated.get("thinking").is_some(),
|
||||
keeps_edit && !thinks_without_thinking_param
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::only_clear_thinking_is_removed_whole(
|
||||
serde_json::json!({"edits": [{"type": "clear_thinking_20251015"}]}),
|
||||
None
|
||||
)]
|
||||
#[case::any_clear_thinking_version(
|
||||
serde_json::json!({"edits": [{"type": "clear_thinking_20990101"}, {"type": "compact_20260112"}]}),
|
||||
Some(serde_json::json!({"edits": [{"type": "compact_20260112"}]}))
|
||||
)]
|
||||
#[case::other_keys_kept(
|
||||
serde_json::json!({"edits": [{"type": "clear_thinking_20251015"}], "extra": 1}),
|
||||
Some(serde_json::json!({"edits": [], "extra": 1}))
|
||||
)]
|
||||
#[case::no_clear_thinking_untouched(
|
||||
serde_json::json!({"edits": []}),
|
||||
Some(serde_json::json!({"edits": []}))
|
||||
)]
|
||||
#[case::openai_list_untouched(
|
||||
serde_json::json!([{"type": "compaction"}]),
|
||||
Some(serde_json::json!([{"type": "compaction"}]))
|
||||
)]
|
||||
fn clear_thinking_edits_are_removed(
|
||||
#[case] context_management: Value,
|
||||
#[case] expected: Option<Value>,
|
||||
) {
|
||||
let translated = translate(
|
||||
haiku_4_5(),
|
||||
serde_json::json!({"max_tokens": 8192, "reasoning_effort": "none", "context_management": context_management}),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
serde_json::to_value(translated)
|
||||
.unwrap()
|
||||
.get("context_management")
|
||||
.cloned(),
|
||||
expected
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[case::minimal_floors_at_min_budget("minimal", 1024)]
|
||||
#[case::low("low", 1024)]
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ pub struct MessagesModelCapabilities {
|
|||
#[serde(default)]
|
||||
pub thinking_always_on: bool,
|
||||
#[serde(default)]
|
||||
pub thinking_on_by_default: bool,
|
||||
#[serde(default)]
|
||||
pub supports_legacy_thinking: bool,
|
||||
#[serde(default)]
|
||||
pub supports_output_config: bool,
|
||||
|
|
@ -55,6 +57,7 @@ impl Default for MessagesModelCapabilities {
|
|||
supports_reasoning: false,
|
||||
supports_adaptive_thinking: false,
|
||||
thinking_always_on: false,
|
||||
thinking_on_by_default: false,
|
||||
supports_legacy_thinking: false,
|
||||
supports_output_config: false,
|
||||
supports_sampling_params: true,
|
||||
|
|
|
|||
|
|
@ -155,6 +155,7 @@ pub struct ModelInfoFields {
|
|||
pub supports_adaptive_thinking: Option<bool>,
|
||||
pub supports_legacy_thinking: Option<bool>,
|
||||
pub thinking_always_on: Option<bool>,
|
||||
pub thinking_on_by_default: Option<bool>,
|
||||
pub supports_tool_search: Option<bool>,
|
||||
pub supports_mid_conversation_system: Option<bool>,
|
||||
pub supports_anthropic_thinking_payload: Option<bool>,
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ attributes! {
|
|||
/// Cloud regions the model is available in ('global' or region ids).
|
||||
supported_regions: Vec<String>,
|
||||
thinking_always_on: bool,
|
||||
thinking_on_by_default: bool,
|
||||
token_count_framing: u64 as Count,
|
||||
token_count_model: TokenCountModel,
|
||||
token_count_tokenizer: TokenCountTokenizer,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import copy
|
|||
import json
|
||||
import re
|
||||
import time
|
||||
from collections.abc import Callable, Mapping, Sequence
|
||||
from collections.abc import Callable, Mapping, MutableMapping, Sequence
|
||||
from types import MappingProxyType
|
||||
from typing import TYPE_CHECKING, Any, ClassVar, Final, NoReturn, cast
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ from litellm.litellm_core_utils.prompt_templates.mid_conversation_system import
|
|||
place_mid_conversation_system,
|
||||
split_leading_system_run,
|
||||
)
|
||||
from litellm.litellm_core_utils.reasoning_effort_utils import OPAQUE_VALUE, warn_non_string_reasoning_effort
|
||||
from litellm.litellm_core_utils.reasoning_effort_utils import warn_non_string_reasoning_effort
|
||||
from litellm.llms.base_llm.base_utils import (
|
||||
ResponseFormatSchema,
|
||||
as_json_object,
|
||||
|
|
@ -123,6 +123,7 @@ from ..common_utils import (
|
|||
REFUSAL_STOP_FIELDS,
|
||||
AnthropicError,
|
||||
AnthropicModelInfo,
|
||||
drop_clear_thinking_edits_for_model,
|
||||
eager_input_streaming_flag,
|
||||
process_anthropic_headers,
|
||||
refusal_provider_specific_fields,
|
||||
|
|
@ -183,6 +184,16 @@ def _tool_type(tool: object) -> str | None:
|
|||
return None
|
||||
|
||||
|
||||
def _requested_effort(reasoning_effort: object) -> str | None:
|
||||
match reasoning_effort:
|
||||
case str():
|
||||
return reasoning_effort
|
||||
case {"effort": str(effort)}:
|
||||
return effort
|
||||
case _:
|
||||
return None
|
||||
|
||||
|
||||
def _is_openai_tool_search_tool(tool: object) -> bool:
|
||||
return _tool_type(tool) == "tool_search"
|
||||
|
||||
|
|
@ -1835,6 +1846,10 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
# via ``data = {**optional_params}`` and would 400 with
|
||||
# ``Extra inputs are not permitted``).
|
||||
|
||||
requested_params: Final = cast( # cast-ok: non_default_params is the untyped dict of the shared signature
|
||||
Mapping[str, object], non_default_params
|
||||
)
|
||||
|
||||
for param, value in non_default_params.items():
|
||||
if param == "max_tokens" or param == "max_completion_tokens":
|
||||
optional_params["max_tokens"] = value if isinstance(value, int) else max(1, int(round(value)))
|
||||
|
|
@ -1948,11 +1963,9 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
# send. Coerce to the effort string before mapping — same
|
||||
# shape-tolerance the GPT-5 path already implements in
|
||||
# `_normalize_reasoning_effort_for_chat_completion`.
|
||||
effort_value = value
|
||||
if isinstance(effort_value, dict):
|
||||
effort_value = effort_value.get("effort")
|
||||
if not isinstance(effort_value, str):
|
||||
warn_non_string_reasoning_effort(OPAQUE_VALUE.validate_python(value), model)
|
||||
effort_value = _requested_effort(requested_params[param])
|
||||
if effort_value is None:
|
||||
warn_non_string_reasoning_effort(requested_params[param], model)
|
||||
continue
|
||||
mapped_thinking = AnthropicConfig._map_reasoning_effort(
|
||||
reasoning_effort=effort_value,
|
||||
|
|
@ -2004,6 +2017,14 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
):
|
||||
optional_params["service_tier"] = anthropic_tier # rebind-ok: in-place fill is this method's contract
|
||||
|
||||
mapped_params: Final = cast( # cast-ok: optional_params is the untyped dict of the shared signature
|
||||
MutableMapping[str, object], optional_params
|
||||
)
|
||||
if "thinking" not in mapped_params and (
|
||||
"thinking" in requested_params or _requested_effort(requested_params.get("reasoning_effort")) is not None
|
||||
):
|
||||
drop_clear_thinking_edits_for_model(mapped_params, model, self._resolved_provider)
|
||||
|
||||
## handle thinking tokens
|
||||
self.update_optional_params_with_thinking_tokens(
|
||||
non_default_params=non_default_params, optional_params=optional_params
|
||||
|
|
@ -2290,7 +2311,11 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
and not any_assistant_message_has_thinking_blocks(messages)
|
||||
):
|
||||
if litellm.modify_params:
|
||||
optional_params.pop("thinking", None)
|
||||
mapped_params: Final = cast( # cast-ok: optional_params is the untyped dict of the shared signature
|
||||
MutableMapping[str, object], optional_params
|
||||
)
|
||||
mapped_params.pop("thinking", None)
|
||||
drop_clear_thinking_edits_for_model(mapped_params, model, self._resolved_provider)
|
||||
litellm.verbose_logger.warning(
|
||||
"Dropping 'thinking' param because the last assistant message with tool_calls "
|
||||
"has no thinking_blocks. The model won't use extended thinking for this turn."
|
||||
|
|
|
|||
|
|
@ -1975,17 +1975,67 @@ def strip_encrypted_reasoning_blocks_from_anthropic_messages(
|
|||
return [m for m in stripped if m is not None]
|
||||
|
||||
|
||||
def _is_clear_thinking_edit(edit: object) -> bool:
|
||||
match edit:
|
||||
case {"type": str(edit_type)}:
|
||||
return edit_type.startswith("clear_thinking_")
|
||||
case _:
|
||||
return False
|
||||
|
||||
|
||||
def drop_clear_thinking_edits(params: MutableMapping[str, object]) -> None: # mutable-ok: edits in place
|
||||
"""
|
||||
Remove the ``clear_thinking_*`` context-management edits, which Anthropic
|
||||
rejects without ``thinking``. ``context_management`` itself goes only when
|
||||
such an edit was removed and nothing else is left in it.
|
||||
"""
|
||||
raw_context_management: Final = params.get("context_management")
|
||||
if not isinstance(raw_context_management, dict):
|
||||
return
|
||||
context_management: Final = OBJECT_MAPPING_ADAPTER.validate_python(raw_context_management)
|
||||
raw_edits: Final = context_management.get("edits")
|
||||
if not isinstance(raw_edits, list):
|
||||
return
|
||||
edits: Final = OBJECT_LIST_ADAPTER.validate_python(raw_edits)
|
||||
kept_edits: Final = [edit for edit in edits if not _is_clear_thinking_edit(edit)]
|
||||
if len(kept_edits) == len(edits):
|
||||
return
|
||||
if not kept_edits and len(context_management) == 1:
|
||||
params.pop("context_management")
|
||||
return
|
||||
params["context_management"] = { # rebind-ok: callers mutate their request params in place
|
||||
**context_management,
|
||||
"edits": kept_edits,
|
||||
}
|
||||
|
||||
|
||||
def drop_clear_thinking_edits_for_model(
|
||||
params: MutableMapping[str, object], # mutable-ok: edits in place
|
||||
model: str,
|
||||
custom_llm_provider: str,
|
||||
) -> None:
|
||||
"""Remove the clear_thinking edits unless the model still thinks without a ``thinking`` param."""
|
||||
thinks_without_thinking_param: Final = any(
|
||||
AnthropicModelInfo.supports_model_capability(model, capability, custom_llm_provider)
|
||||
for capability in ("thinking_always_on", "thinking_on_by_default")
|
||||
)
|
||||
if not thinks_without_thinking_param:
|
||||
drop_clear_thinking_edits(params)
|
||||
|
||||
|
||||
def strip_thinking_blocks_from_anthropic_messages_request_dict(
|
||||
data: dict[str, object],
|
||||
) -> None:
|
||||
"""
|
||||
Mutate an Anthropic Messages-style request dict: strip thinking blocks from
|
||||
``messages`` and remove the top-level ``thinking`` extended-thinking param.
|
||||
``messages`` and remove ``thinking`` with its dependent context-management
|
||||
edits (see :func:`drop_clear_thinking_edits`).
|
||||
"""
|
||||
msgs: Final = data.get("messages")
|
||||
if isinstance(msgs, list):
|
||||
data["messages"] = strip_thinking_blocks_from_anthropic_messages(msgs)
|
||||
data.pop("thinking", None)
|
||||
drop_clear_thinking_edits(data)
|
||||
|
||||
|
||||
_DROP_ANTHROPIC_MESSAGE: Final = object()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from collections.abc import AsyncIterator, Mapping, Sequence
|
||||
from collections.abc import AsyncIterator, Mapping, MutableMapping, Sequence
|
||||
from typing import ClassVar, Final
|
||||
|
||||
import httpx
|
||||
|
|
@ -46,6 +46,7 @@ from ...common_utils import (
|
|||
AnthropicError,
|
||||
AnthropicModelInfo,
|
||||
context_management_betas,
|
||||
drop_clear_thinking_edits_for_model,
|
||||
is_claude_model_target,
|
||||
merge_anthropic_beta_headers,
|
||||
optionally_handle_anthropic_oauth,
|
||||
|
|
@ -115,6 +116,16 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
def _resolved_provider(self) -> str:
|
||||
return self.custom_llm_provider or "anthropic"
|
||||
|
||||
def _drop_thinking(
|
||||
self,
|
||||
optional_params: MutableMapping[str, object], # mutable-ok: edits optional params in place
|
||||
model: str,
|
||||
custom_llm_provider: str,
|
||||
max_tokens: int | None,
|
||||
) -> None:
|
||||
optional_params.pop("thinking", None)
|
||||
drop_clear_thinking_edits_for_model(optional_params, model, custom_llm_provider)
|
||||
|
||||
def get_supported_anthropic_messages_params(self, model: str) -> list:
|
||||
return [
|
||||
"messages",
|
||||
|
|
@ -464,9 +475,8 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
messages=messages,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _translate_reasoning_effort_to_anthropic(
|
||||
model: str, optional_params: dict, max_tokens: int | None, custom_llm_provider: str
|
||||
self, model: str, optional_params: dict[str, object], max_tokens: int | None, custom_llm_provider: str
|
||||
) -> None:
|
||||
"""Map OpenAI-style ``reasoning_effort`` to native Anthropic params.
|
||||
|
||||
|
|
@ -495,13 +505,15 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
raise AnthropicError(message=str(e.message), status_code=400)
|
||||
|
||||
if mapped_thinking is None:
|
||||
optional_params.pop("thinking", None)
|
||||
self._drop_thinking(optional_params, model, custom_llm_provider, max_tokens)
|
||||
optional_params.pop("output_config", None)
|
||||
return
|
||||
|
||||
fitted_thinking: Final = AnthropicConfig.cap_thinking_budget_to_max_tokens(mapped_thinking, max_tokens)
|
||||
if fitted_thinking is None:
|
||||
verbose_logger.warning(DROP_UNFITTING_REASONING_EFFORT_WARNING, reasoning_effort, model, max_tokens)
|
||||
if "thinking" not in optional_params:
|
||||
self._drop_thinking(optional_params, model, custom_llm_provider, max_tokens)
|
||||
return
|
||||
|
||||
optional_params.setdefault("thinking", fitted_thinking)
|
||||
|
|
@ -525,9 +537,8 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
existing_output_config.setdefault("effort", mapped_effort)
|
||||
optional_params["output_config"] = existing_output_config
|
||||
|
||||
@staticmethod
|
||||
def _translate_adaptive_effort_for_non_adaptive_model(
|
||||
model: str, optional_params: dict, max_tokens: int | None, custom_llm_provider: str
|
||||
self, model: str, optional_params: dict[str, object], max_tokens: int | None, custom_llm_provider: str
|
||||
) -> None:
|
||||
"""Translate the 4.6+ adaptive-thinking interface (``thinking.type=adaptive``
|
||||
and/or ``output_config.effort``) down to what an older Anthropic model
|
||||
|
|
@ -590,7 +601,7 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
or AnthropicConfig.validate_effort_for_model(model, effort, custom_llm_provider) is None
|
||||
):
|
||||
if adaptive_thinking:
|
||||
optional_params.pop("thinking", None)
|
||||
self._drop_thinking(optional_params, model, custom_llm_provider, max_tokens)
|
||||
return
|
||||
|
||||
supports_thinking: Final = AnthropicModelInfo.supports_model_capability(
|
||||
|
|
@ -618,7 +629,7 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
optional_params["thinking"] = capped_thinking
|
||||
else:
|
||||
verbose_logger.warning(DROP_UNSUPPORTED_ADAPTIVE_EFFORT_WARNING, model)
|
||||
optional_params.pop("thinking", None)
|
||||
self._drop_thinking(optional_params, model, custom_llm_provider, max_tokens)
|
||||
|
||||
if isinstance(output_config, dict) and "effort" in output_config:
|
||||
residual: Final = {k: v for k, v in output_config.items() if k != "effort"}
|
||||
|
|
@ -703,7 +714,7 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
)
|
||||
self._translate_reasoning_effort_to_anthropic(
|
||||
model=model,
|
||||
optional_params=anthropic_messages_optional_request_params,
|
||||
optional_params=anthropic_messages_optional_request_params, # pyright: ignore[reportUnknownArgumentType] # the request params arrive as a bare dict
|
||||
max_tokens=max_tokens,
|
||||
custom_llm_provider=self._resolved_provider,
|
||||
)
|
||||
|
|
@ -727,7 +738,7 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
|
||||
self._translate_adaptive_effort_for_non_adaptive_model(
|
||||
model=model,
|
||||
optional_params=anthropic_messages_optional_request_params,
|
||||
optional_params=anthropic_messages_optional_request_params, # pyright: ignore[reportUnknownArgumentType] # the request params arrive as a bare dict
|
||||
max_tokens=max_tokens,
|
||||
custom_llm_provider=self._resolved_provider,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from collections.abc import AsyncIterator, Mapping, Sequence
|
||||
from collections.abc import AsyncIterator, Mapping, MutableMapping, Sequence
|
||||
from types import MappingProxyType
|
||||
from typing import TYPE_CHECKING, Any, Final, cast
|
||||
|
||||
|
|
@ -100,6 +100,18 @@ class AmazonAnthropicClaudeMessagesConfig(
|
|||
def beta_headers_provider(self) -> str:
|
||||
return self.custom_llm_provider or "bedrock"
|
||||
|
||||
def _drop_thinking(
|
||||
self,
|
||||
optional_params: MutableMapping[str, object], # mutable-ok: edits optional params in place
|
||||
model: str,
|
||||
custom_llm_provider: str,
|
||||
max_tokens: int | None,
|
||||
) -> None:
|
||||
"""Keep the clear_thinking edit: it makes
|
||||
``_ensure_thinking_for_clear_thinking_context_management`` add thinking back,
|
||||
and ``_filter_context_management_for_bedrock_invoke`` strips it before sending."""
|
||||
optional_params.pop("thinking", None)
|
||||
|
||||
def should_strip_billing_metadata(self) -> bool:
|
||||
return True
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
from collections.abc import Mapping
|
||||
from collections.abc import Mapping, MutableMapping
|
||||
from types import MappingProxyType
|
||||
from typing import Final
|
||||
|
||||
from litellm.litellm_core_utils.url_utils import join_api_base
|
||||
from litellm.llms.anthropic.common_utils import drop_clear_thinking_edits_for_model
|
||||
from litellm.llms.bedrock.base_aws_llm import BaseAWSLLM
|
||||
from litellm.llms.bedrock.common_utils import MANTLE_MESSAGES_PATH
|
||||
from litellm.llms.bedrock.messages.mantle_transformation import AmazonMantleMessagesConfig
|
||||
|
|
@ -45,6 +46,26 @@ class BedrockMantleAnthropicMessagesConfig(BedrockMantleAuthMixin, AmazonMantleM
|
|||
}
|
||||
)
|
||||
|
||||
def _drop_thinking(
|
||||
self,
|
||||
optional_params: MutableMapping[str, object], # mutable-ok: edits optional params in place
|
||||
model: str,
|
||||
custom_llm_provider: str,
|
||||
max_tokens: int | None,
|
||||
) -> None:
|
||||
super()._drop_thinking(optional_params, model, custom_llm_provider, max_tokens)
|
||||
if not self._adds_thinking_back_for_clear_thinking(optional_params, model, max_tokens):
|
||||
drop_clear_thinking_edits_for_model(optional_params, model, custom_llm_provider)
|
||||
|
||||
def _adds_thinking_back_for_clear_thinking(
|
||||
self, optional_params: Mapping[str, object], model: str, max_tokens: int | None
|
||||
) -> bool:
|
||||
trial_request: Final = {
|
||||
"context_management": optional_params.get("context_management"),
|
||||
"max_tokens": max_tokens,
|
||||
}
|
||||
return self._ensure_thinking_for_clear_thinking_context_management(trial_request, model, drop_params=False)
|
||||
|
||||
def __init__(self, aws_signer: BaseAWSLLM | None = None) -> None:
|
||||
AmazonMantleMessagesConfig.__init__(self)
|
||||
self._aws_signer = aws_signer or self
|
||||
|
|
|
|||
|
|
@ -154,15 +154,13 @@ class BigModelMessagesConfig(OpenAILikeAnthropicMessagesConfig):
|
|||
model, normalized, request_body, litellm_logging_obj
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _translate_reasoning_effort_to_anthropic(
|
||||
model: str, optional_params: Mapping[str, object], max_tokens: int | None, custom_llm_provider: str
|
||||
self, model: str, optional_params: Mapping[str, object], max_tokens: int | None, custom_llm_provider: str
|
||||
) -> None:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _translate_adaptive_effort_for_non_adaptive_model(
|
||||
model: str, optional_params: Mapping[str, object], max_tokens: int | None, custom_llm_provider: str
|
||||
self, model: str, optional_params: Mapping[str, object], max_tokens: int | None, custom_llm_provider: str
|
||||
) -> None:
|
||||
return None
|
||||
|
||||
|
|
|
|||
|
|
@ -1939,6 +1939,7 @@
|
|||
"anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.25e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1e-05,
|
||||
|
|
@ -2025,6 +2026,7 @@
|
|||
"global.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.25e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1e-05,
|
||||
|
|
@ -2111,6 +2113,7 @@
|
|||
"us.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.875e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1.1e-05,
|
||||
|
|
@ -2197,6 +2200,7 @@
|
|||
"eu.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.875e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1.1e-05,
|
||||
|
|
@ -2278,6 +2282,7 @@
|
|||
"au.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.875e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1.1e-05,
|
||||
|
|
@ -2364,6 +2369,7 @@
|
|||
"jp.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.875e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1.1e-05,
|
||||
|
|
@ -2760,6 +2766,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -2804,6 +2811,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -2848,6 +2856,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -2892,6 +2901,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -2936,6 +2946,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -2980,6 +2991,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -3827,6 +3839,7 @@
|
|||
"deprecation_date": "2027-07-08",
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"input_cost_per_token": 5e-06,
|
||||
"output_cost_per_token": 2.5e-05,
|
||||
"litellm_provider": "azure_ai",
|
||||
|
|
@ -3964,6 +3977,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -16169,6 +16183,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -16702,6 +16717,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -21562,6 +21578,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://www.databricks.com/product/pricing/proprietary-foundation-model-serving",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_function_calling": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
|
|
@ -21719,6 +21736,7 @@
|
|||
"prompt_cache_min_tokens": 1024,
|
||||
"source": "https://www.databricks.com/product/pricing/proprietary-foundation-model-serving",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_function_calling": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
|
|
@ -33155,6 +33173,7 @@
|
|||
"/v1/messages"
|
||||
],
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_reasoning": true,
|
||||
|
|
@ -33222,6 +33241,7 @@
|
|||
"/v1/messages"
|
||||
],
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_reasoning": true,
|
||||
|
|
@ -33265,6 +33285,7 @@
|
|||
"/v1/messages"
|
||||
],
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_reasoning": true,
|
||||
|
|
@ -49386,6 +49407,7 @@
|
|||
"prompt_cache_min_tokens": 1024,
|
||||
"source": "https://aws.amazon.com/bedrock/pricing/",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -49463,6 +49485,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://aws.amazon.com/bedrock/pricing/",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -51863,6 +51886,7 @@
|
|||
"regional_endpoint_uplift_multiplier": 1.1,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"cache_creation_input_token_cost": 6.25e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1e-05,
|
||||
"cache_creation_input_token_cost_batches": 3.125e-06,
|
||||
|
|
@ -51901,6 +51925,7 @@
|
|||
"regional_endpoint_uplift_multiplier": 1.1,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"cache_creation_input_token_cost": 6.25e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1e-05,
|
||||
"cache_creation_input_token_cost_batches": 3.125e-06,
|
||||
|
|
@ -52144,6 +52169,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -59497,6 +59523,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -63607,6 +63634,14 @@
|
|||
"thinking_always_on": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "claude-thinking-on-by-default",
|
||||
"pattern": "claude-[a-z]+-[5-9](?!\\d)(?:[-._]\\d{1,2}(?!\\d))?",
|
||||
"description": "Claude at major version 5 or higher, in any id shape that contains claude-<family>-<major>, so new minors such as claude-sonnet-5-1 and provider-namespaced ids match. Every Claude 5 model thinks when a request carries no thinking param, so a clear_thinking context-management edit stays valid when LiteLLM drops thinking. Two-digit majors are deliberately not matched so ids like claude-opus-41 (4.1) are not read as major 41.",
|
||||
"model_info": {
|
||||
"thinking_on_by_default": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "claude-mid-conversation-system",
|
||||
"pattern": "claude-[a-z]+-(?:4[-._](?:[89]|[1-9]\\d)(?!\\d)|[5-9](?!\\d)(?:[-._]\\d{1,2}(?!\\d))?)",
|
||||
|
|
@ -65707,6 +65742,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://deepinfra.com/pricing",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
|
|
@ -66022,6 +66058,7 @@
|
|||
"prompt_cache_min_tokens": 1024,
|
||||
"source": "https://deepinfra.com/pricing",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
|
|
@ -68035,6 +68072,7 @@
|
|||
"output_cost_per_token": 1.2e-05,
|
||||
"prompt_cache_min_tokens": 1024,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -68110,6 +68148,7 @@
|
|||
"output_cost_per_token": 3e-05,
|
||||
"prompt_cache_min_tokens": 512,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -68323,6 +68362,7 @@
|
|||
"output_cost_per_token": 1.2e-05,
|
||||
"prompt_cache_min_tokens": 1024,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -68388,6 +68428,7 @@
|
|||
"output_cost_per_token": 3e-05,
|
||||
"prompt_cache_min_tokens": 512,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -69225,6 +69266,7 @@
|
|||
"litellm_provider": "perplexity",
|
||||
"mode": "responses",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"prompt_cache_min_tokens": 512,
|
||||
"supports_web_search": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -69248,6 +69290,7 @@
|
|||
"litellm_provider": "perplexity",
|
||||
"mode": "responses",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_web_search": true,
|
||||
"supports_function_calling": true,
|
||||
"input_cost_per_token": 2e-06,
|
||||
|
|
@ -71324,6 +71367,7 @@
|
|||
"supports_vision": true,
|
||||
"supports_web_search": true,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"prompt_cache_min_tokens": 512,
|
||||
"supports_sampling_params": false
|
||||
},
|
||||
|
|
@ -71344,6 +71388,7 @@
|
|||
"supports_vision": true,
|
||||
"prompt_cache_min_tokens": 1024,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_sampling_params": false
|
||||
},
|
||||
"aihubmix/coding-glm-5.3": {
|
||||
|
|
@ -74024,6 +74069,7 @@
|
|||
"apac.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
|
|
@ -74138,6 +74184,7 @@
|
|||
"max_output_tokens": 128000,
|
||||
"mode": "chat",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75628,6 +75675,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75680,6 +75728,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75724,6 +75773,7 @@
|
|||
"thinking_always_on": false,
|
||||
"prompt_cache_min_tokens": 512,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -75771,6 +75821,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75807,6 +75858,7 @@
|
|||
"max_output_tokens": 128000,
|
||||
"mode": "chat",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75863,6 +75915,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75909,6 +75962,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -75949,6 +76003,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonBedrockFoundationModels/current/index.json",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -75990,6 +76045,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonBedrockFoundationModels/current/index.json",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -76036,6 +76092,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -76087,6 +76144,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -76133,6 +76191,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -76160,6 +76219,7 @@
|
|||
"litellm_provider": "perplexity",
|
||||
"mode": "responses",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_web_search": true,
|
||||
"supports_function_calling": true,
|
||||
"input_cost_per_token": 1e-07,
|
||||
|
|
@ -76190,6 +76250,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonBedrockFoundationModels/current/index.json",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -76241,6 +76302,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -76291,6 +76353,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -76335,6 +76398,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -78094,6 +78158,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -78308,6 +78373,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -78472,6 +78538,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -80454,6 +80521,7 @@
|
|||
"prompt_cache_min_tokens": 512.0,
|
||||
"source": "https://www.databricks.com/product/pricing/proprietary-foundation-model-serving",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_anthropic_thinking_payload": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_function_calling": true,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ def anthropic_model_capabilities(model: str, custom_llm_provider: str | None) ->
|
|||
"supports_reasoning": supports("supports_reasoning"),
|
||||
"supports_adaptive_thinking": supports("supports_adaptive_thinking"),
|
||||
"thinking_always_on": supports("thinking_always_on"),
|
||||
"thinking_on_by_default": supports("thinking_on_by_default"),
|
||||
"supports_legacy_thinking": supports("supports_legacy_thinking"),
|
||||
"supports_output_config": supports("supports_output_config"),
|
||||
"supports_sampling_params": AnthropicModelInfo._supports_sampling_params(resolved_model), # pyright: ignore[reportPrivateUsage] # same gate the handler applies
|
||||
|
|
|
|||
|
|
@ -223,6 +223,7 @@ class ProviderSpecificModelInfo(TypedDict, total=False):
|
|||
supports_adaptive_thinking: bool | None
|
||||
supports_legacy_thinking: ReadOnly[bool | None]
|
||||
thinking_always_on: ReadOnly[bool | None]
|
||||
thinking_on_by_default: ReadOnly[bool | None]
|
||||
supports_tool_search: bool | None
|
||||
supports_mid_conversation_system: bool | None
|
||||
supports_url_context: bool | None
|
||||
|
|
|
|||
|
|
@ -7353,6 +7353,7 @@ def get_model_info_helper(
|
|||
supports_adaptive_thinking=_model_info.get("supports_adaptive_thinking", None),
|
||||
supports_legacy_thinking=_model_info.get("supports_legacy_thinking", None),
|
||||
thinking_always_on=_model_info.get("thinking_always_on", None),
|
||||
thinking_on_by_default=_model_info.get("thinking_on_by_default", None),
|
||||
supports_tool_search=_model_info.get("supports_tool_search", None),
|
||||
supports_mid_conversation_system=_model_info.get("supports_mid_conversation_system", None),
|
||||
supports_anthropic_thinking_payload=_model_info.get("supports_anthropic_thinking_payload", None),
|
||||
|
|
|
|||
|
|
@ -1939,6 +1939,7 @@
|
|||
"anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.25e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1e-05,
|
||||
|
|
@ -2025,6 +2026,7 @@
|
|||
"global.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.25e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1e-05,
|
||||
|
|
@ -2111,6 +2113,7 @@
|
|||
"us.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.875e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1.1e-05,
|
||||
|
|
@ -2197,6 +2200,7 @@
|
|||
"eu.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.875e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1.1e-05,
|
||||
|
|
@ -2278,6 +2282,7 @@
|
|||
"au.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.875e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1.1e-05,
|
||||
|
|
@ -2364,6 +2369,7 @@
|
|||
"jp.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"cache_creation_input_token_cost": 6.875e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1.1e-05,
|
||||
|
|
@ -2760,6 +2766,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -2804,6 +2811,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -2848,6 +2856,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -2892,6 +2901,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -2936,6 +2946,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -2980,6 +2991,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -3827,6 +3839,7 @@
|
|||
"deprecation_date": "2027-07-08",
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"input_cost_per_token": 5e-06,
|
||||
"output_cost_per_token": 2.5e-05,
|
||||
"litellm_provider": "azure_ai",
|
||||
|
|
@ -3964,6 +3977,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -16169,6 +16183,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -16702,6 +16717,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -21562,6 +21578,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://www.databricks.com/product/pricing/proprietary-foundation-model-serving",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_function_calling": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
|
|
@ -21719,6 +21736,7 @@
|
|||
"prompt_cache_min_tokens": 1024,
|
||||
"source": "https://www.databricks.com/product/pricing/proprietary-foundation-model-serving",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_function_calling": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
|
|
@ -33155,6 +33173,7 @@
|
|||
"/v1/messages"
|
||||
],
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_reasoning": true,
|
||||
|
|
@ -33222,6 +33241,7 @@
|
|||
"/v1/messages"
|
||||
],
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_reasoning": true,
|
||||
|
|
@ -33265,6 +33285,7 @@
|
|||
"/v1/messages"
|
||||
],
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_parallel_function_calling": true,
|
||||
"supports_reasoning": true,
|
||||
|
|
@ -49386,6 +49407,7 @@
|
|||
"prompt_cache_min_tokens": 1024,
|
||||
"source": "https://aws.amazon.com/bedrock/pricing/",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -49463,6 +49485,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://aws.amazon.com/bedrock/pricing/",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -51863,6 +51886,7 @@
|
|||
"regional_endpoint_uplift_multiplier": 1.1,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"cache_creation_input_token_cost": 6.25e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1e-05,
|
||||
"cache_creation_input_token_cost_batches": 3.125e-06,
|
||||
|
|
@ -51901,6 +51925,7 @@
|
|||
"regional_endpoint_uplift_multiplier": 1.1,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"cache_creation_input_token_cost": 6.25e-06,
|
||||
"cache_creation_input_token_cost_above_1hr": 1e-05,
|
||||
"cache_creation_input_token_cost_batches": 3.125e-06,
|
||||
|
|
@ -52144,6 +52169,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -59497,6 +59523,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -63607,6 +63634,14 @@
|
|||
"thinking_always_on": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "claude-thinking-on-by-default",
|
||||
"pattern": "claude-[a-z]+-[5-9](?!\\d)(?:[-._]\\d{1,2}(?!\\d))?",
|
||||
"description": "Claude at major version 5 or higher, in any id shape that contains claude-<family>-<major>, so new minors such as claude-sonnet-5-1 and provider-namespaced ids match. Every Claude 5 model thinks when a request carries no thinking param, so a clear_thinking context-management edit stays valid when LiteLLM drops thinking. Two-digit majors are deliberately not matched so ids like claude-opus-41 (4.1) are not read as major 41.",
|
||||
"model_info": {
|
||||
"thinking_on_by_default": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "claude-mid-conversation-system",
|
||||
"pattern": "claude-[a-z]+-(?:4[-._](?:[89]|[1-9]\\d)(?!\\d)|[5-9](?!\\d)(?:[-._]\\d{1,2}(?!\\d))?)",
|
||||
|
|
@ -65707,6 +65742,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://deepinfra.com/pricing",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
|
|
@ -66022,6 +66058,7 @@
|
|||
"prompt_cache_min_tokens": 1024,
|
||||
"source": "https://deepinfra.com/pricing",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_function_calling": true,
|
||||
"supports_reasoning": true,
|
||||
"supports_response_schema": true,
|
||||
|
|
@ -68035,6 +68072,7 @@
|
|||
"output_cost_per_token": 1.2e-05,
|
||||
"prompt_cache_min_tokens": 1024,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -68110,6 +68148,7 @@
|
|||
"output_cost_per_token": 3e-05,
|
||||
"prompt_cache_min_tokens": 512,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -68323,6 +68362,7 @@
|
|||
"output_cost_per_token": 1.2e-05,
|
||||
"prompt_cache_min_tokens": 1024,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -68388,6 +68428,7 @@
|
|||
"output_cost_per_token": 3e-05,
|
||||
"prompt_cache_min_tokens": 512,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -69225,6 +69266,7 @@
|
|||
"litellm_provider": "perplexity",
|
||||
"mode": "responses",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"prompt_cache_min_tokens": 512,
|
||||
"supports_web_search": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -69248,6 +69290,7 @@
|
|||
"litellm_provider": "perplexity",
|
||||
"mode": "responses",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_web_search": true,
|
||||
"supports_function_calling": true,
|
||||
"input_cost_per_token": 2e-06,
|
||||
|
|
@ -71324,6 +71367,7 @@
|
|||
"supports_vision": true,
|
||||
"supports_web_search": true,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"prompt_cache_min_tokens": 512,
|
||||
"supports_sampling_params": false
|
||||
},
|
||||
|
|
@ -71344,6 +71388,7 @@
|
|||
"supports_vision": true,
|
||||
"prompt_cache_min_tokens": 1024,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_sampling_params": false
|
||||
},
|
||||
"aihubmix/coding-glm-5.3": {
|
||||
|
|
@ -74024,6 +74069,7 @@
|
|||
"apac.anthropic.claude-opus-5": {
|
||||
"bedrock_converse_supports_strict_tools": false,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"litellm_provider": "bedrock_converse",
|
||||
"supports_tool_search": true,
|
||||
|
|
@ -74138,6 +74184,7 @@
|
|||
"max_output_tokens": 128000,
|
||||
"mode": "chat",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75628,6 +75675,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75680,6 +75728,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75724,6 +75773,7 @@
|
|||
"thinking_always_on": false,
|
||||
"prompt_cache_min_tokens": 512,
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -75771,6 +75821,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75807,6 +75858,7 @@
|
|||
"max_output_tokens": 128000,
|
||||
"mode": "chat",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75863,6 +75915,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -75909,6 +75962,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -75949,6 +76003,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonBedrockFoundationModels/current/index.json",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -75990,6 +76045,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonBedrockFoundationModels/current/index.json",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -76036,6 +76092,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -76087,6 +76144,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -76133,6 +76191,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -76160,6 +76219,7 @@
|
|||
"litellm_provider": "perplexity",
|
||||
"mode": "responses",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_web_search": true,
|
||||
"supports_function_calling": true,
|
||||
"input_cost_per_token": 1e-07,
|
||||
|
|
@ -76190,6 +76250,7 @@
|
|||
"prompt_cache_min_tokens": 512,
|
||||
"source": "https://pricing.us-east-1.amazonaws.com/offers/v1.0/aws/AmazonBedrockFoundationModels/current/index.json",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -76241,6 +76302,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -76291,6 +76353,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -76335,6 +76398,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
"supports_function_calling": true,
|
||||
|
|
@ -78094,6 +78158,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -78308,6 +78373,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -78472,6 +78538,7 @@
|
|||
"search_context_size_medium": 0.01
|
||||
},
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_mid_conversation_system": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_computer_use": true,
|
||||
|
|
@ -80454,6 +80521,7 @@
|
|||
"prompt_cache_min_tokens": 512.0,
|
||||
"source": "https://www.databricks.com/product/pricing/proprietary-foundation-model-serving",
|
||||
"supports_adaptive_thinking": true,
|
||||
"thinking_on_by_default": true,
|
||||
"supports_anthropic_thinking_payload": true,
|
||||
"supports_assistant_prefill": false,
|
||||
"supports_function_calling": true,
|
||||
|
|
|
|||
|
|
@ -9849,3 +9849,108 @@ def test_transform_request_tool_config_point_without_tools_drops_the_key():
|
|||
assert "cache_control_injection_points" not in data
|
||||
assert "tools" not in data
|
||||
assert litellm_params["metadata"] == {}
|
||||
|
||||
|
||||
CLEAR_THINKING_EDIT: Final = {"type": "clear_thinking_20251015", "keep": "all"}
|
||||
CLEAR_TOOL_USES_EDIT: Final = {"type": "clear_tool_uses_20250919"}
|
||||
|
||||
|
||||
def _edits_for(keeps_thinking: bool) -> list[dict[str, str]]:
|
||||
return [CLEAR_THINKING_EDIT, CLEAR_TOOL_USES_EDIT] if keeps_thinking else [CLEAR_TOOL_USES_EDIT]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("model", "params", "keeps_thinking"),
|
||||
[
|
||||
pytest.param(
|
||||
"claude-haiku-4-5",
|
||||
{"thinking": {"type": "adaptive"}, "max_tokens": 1000},
|
||||
False,
|
||||
id="adaptive-unfit-dropped",
|
||||
),
|
||||
pytest.param(
|
||||
"claude-haiku-4-5", {"thinking": {"type": "adaptive"}, "max_tokens": 8192}, True, id="adaptive-translated"
|
||||
),
|
||||
pytest.param("claude-sonnet-4-5", {"reasoning_effort": "none"}, False, id="reasoning-effort-none"),
|
||||
pytest.param(
|
||||
"claude-sonnet-4-5", {"reasoning_effort": {"effort": "none"}}, False, id="reasoning-effort-dict-none"
|
||||
),
|
||||
pytest.param("claude-sonnet-4-5", {"reasoning_effort": "high"}, True, id="reasoning-effort-high"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("context_management_first", [True, False])
|
||||
def test_map_openai_params_drops_clear_thinking_edit_exactly_when_thinking_is(
|
||||
model: str, params: dict[str, object], keeps_thinking: bool, context_management_first: bool
|
||||
) -> None:
|
||||
context_management: Final = {"context_management": {"edits": [CLEAR_THINKING_EDIT, CLEAR_TOOL_USES_EDIT]}}
|
||||
rest: Final = {"max_tokens": 8192, **params}
|
||||
result: Final = AnthropicConfig().map_openai_params(
|
||||
non_default_params={**context_management, **rest}
|
||||
if context_management_first
|
||||
else {**rest, **context_management},
|
||||
optional_params={},
|
||||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
|
||||
assert ("thinking" in result) is keeps_thinking
|
||||
assert result["context_management"] == {"edits": _edits_for(keeps_thinking)}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("model", "reasoning_effort"),
|
||||
[
|
||||
pytest.param("claude-fable-5", "none", id="always-on-model"),
|
||||
pytest.param("claude-sonnet-4-5", {"summary": "concise"}, id="effort-less-dict"),
|
||||
],
|
||||
)
|
||||
def test_map_openai_params_keeps_clear_thinking_edit_when_thinking_was_not_dropped(
|
||||
model: str, reasoning_effort: str | dict[str, str]
|
||||
) -> None:
|
||||
result: Final = AnthropicConfig().map_openai_params(
|
||||
non_default_params={
|
||||
"context_management": {"edits": [CLEAR_THINKING_EDIT]},
|
||||
"max_tokens": 8192,
|
||||
"reasoning_effort": reasoning_effort,
|
||||
},
|
||||
optional_params={},
|
||||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
|
||||
assert result["context_management"] == {"edits": [CLEAR_THINKING_EDIT]}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("model", "modify_params", "keeps_thinking", "keeps_edit"),
|
||||
[
|
||||
pytest.param("claude-sonnet-4-5", True, False, False, id="dropped"),
|
||||
pytest.param("claude-sonnet-4-5", False, True, True, id="modify-params-off"),
|
||||
pytest.param("claude-fable-5", True, False, True, id="always-on-keeps-edit"),
|
||||
],
|
||||
)
|
||||
def test_transform_request_drops_clear_thinking_edit_with_thinking_for_tool_turn_without_thinking_blocks(
|
||||
monkeypatch: pytest.MonkeyPatch, model: str, modify_params: bool, keeps_thinking: bool, keeps_edit: bool
|
||||
) -> None:
|
||||
monkeypatch.setattr(litellm, "modify_params", modify_params)
|
||||
result: Final = AnthropicConfig().transform_request(
|
||||
model=model,
|
||||
messages=[
|
||||
{"role": "user", "content": "Look it up"},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": None,
|
||||
"tool_calls": [{"id": "call_1", "type": "function", "function": {"name": "lookup", "arguments": "{}"}}],
|
||||
},
|
||||
{"role": "tool", "tool_call_id": "call_1", "content": "found"},
|
||||
],
|
||||
optional_params={
|
||||
"thinking": {"type": "enabled", "budget_tokens": 1024},
|
||||
"context_management": {"edits": [CLEAR_THINKING_EDIT, CLEAR_TOOL_USES_EDIT]},
|
||||
},
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert ("thinking" in result) is keeps_thinking
|
||||
assert result["context_management"] == {"edits": _edits_for(keeps_edit)}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
from typing import Final
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.constants import (
|
||||
|
|
@ -334,3 +336,70 @@ def test_reasoning_effort_budget_capped_for_openai_like_messages_upstream():
|
|||
|
||||
assert result["thinking"] == {"type": "enabled", "budget_tokens": 3999}
|
||||
assert result["max_tokens"] == 4000
|
||||
|
||||
|
||||
CLEAR_THINKING_EDIT: Final = {"type": "clear_thinking_20251015", "keep": "all"}
|
||||
CLEAR_TOOL_USES_EDIT: Final = {"type": "clear_tool_uses_20250919"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("model", "params", "keeps_thinking"),
|
||||
[
|
||||
pytest.param("claude-sonnet-4-5", {"reasoning_effort": "none"}, False, id="reasoning-effort-none"),
|
||||
pytest.param("claude-haiku-4-5", {"reasoning_effort": "high"}, True, id="reasoning-effort-high"),
|
||||
pytest.param(
|
||||
"claude-haiku-4-5",
|
||||
{"max_tokens": 1024, "reasoning_effort": "high"},
|
||||
False,
|
||||
id="reasoning-effort-budget-cannot-fit",
|
||||
),
|
||||
pytest.param(
|
||||
"claude-haiku-4-5",
|
||||
{"max_tokens": 1024, "reasoning_effort": "high", "thinking": {"type": "enabled", "budget_tokens": 1000}},
|
||||
True,
|
||||
id="caller-thinking-kept-when-budget-cannot-fit",
|
||||
),
|
||||
pytest.param("claude-opus-4-5", _claude_code_payload(effort="high"), False, id="effort-model-drops-adaptive"),
|
||||
pytest.param("claude-sonnet-4-6", _claude_code_payload(effort="high"), True, id="adaptive-model"),
|
||||
pytest.param("claude-3-5-haiku-latest", _claude_code_payload(), False, id="non-reasoning-model"),
|
||||
pytest.param("claude-haiku-4-5", _claude_code_payload(), True, id="legacy-thinking-model"),
|
||||
pytest.param(
|
||||
"claude-opus-4-8", {"reasoning_effort": "none"}, False, id="adaptive-model-without-default-thinking"
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_clear_thinking_edit_dropped_exactly_when_thinking_is(
|
||||
model: str, params: dict[str, object], keeps_thinking: bool
|
||||
) -> None:
|
||||
result: Final = _transform(
|
||||
model,
|
||||
{
|
||||
"max_tokens": 8192,
|
||||
**params,
|
||||
"context_management": {"edits": [CLEAR_THINKING_EDIT, CLEAR_TOOL_USES_EDIT]},
|
||||
},
|
||||
)
|
||||
|
||||
assert ("thinking" in result) is keeps_thinking
|
||||
expected_edits: Final = [CLEAR_THINKING_EDIT, CLEAR_TOOL_USES_EDIT] if keeps_thinking else [CLEAR_TOOL_USES_EDIT]
|
||||
assert result["context_management"] == {"edits": expected_edits}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model",
|
||||
[
|
||||
"claude-fable-5",
|
||||
"claude-sonnet-5",
|
||||
"claude-opus-5",
|
||||
"claude-haiku-5-5",
|
||||
pytest.param("claude-sonnet-5-1", id="unmapped-claude-5-minor"),
|
||||
pytest.param("claude-opus-5-2-20270101", id="unmapped-dated-claude-5-minor"),
|
||||
],
|
||||
)
|
||||
def test_clear_thinking_edit_kept_when_model_thinks_without_thinking_param(model: str) -> None:
|
||||
result: Final = _transform(
|
||||
model,
|
||||
{"max_tokens": 8192, "reasoning_effort": "none", "context_management": {"edits": [CLEAR_THINKING_EDIT]}},
|
||||
)
|
||||
|
||||
assert result["context_management"] == {"edits": [CLEAR_THINKING_EDIT]}
|
||||
|
|
|
|||
|
|
@ -1612,6 +1612,52 @@ class TestAnthropicThinkingSignatureSelfHeal:
|
|||
assert "thinking" not in data
|
||||
assert data["messages"] == []
|
||||
|
||||
def test_strip_thinking_request_dict_drops_clear_thinking_edits(self) -> None:
|
||||
from litellm.llms.anthropic.common_utils import (
|
||||
strip_thinking_blocks_from_anthropic_messages_request_dict,
|
||||
)
|
||||
|
||||
data: Final[dict[str, object]] = {
|
||||
"messages": [{"role": "assistant", "content": [{"type": "thinking", "thinking": "unsigned"}]}],
|
||||
"thinking": {"type": "adaptive"},
|
||||
"context_management": {"edits": [{"type": "clear_thinking_20251015", "keep": "all"}]},
|
||||
}
|
||||
strip_thinking_blocks_from_anthropic_messages_request_dict(data)
|
||||
assert "context_management" not in data
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("context_management", "expected"),
|
||||
[
|
||||
pytest.param(
|
||||
{"edits": [{"type": "clear_thinking_20990101"}, {"type": "clear_tool_uses_20250919"}]},
|
||||
{"edits": [{"type": "clear_tool_uses_20250919"}]},
|
||||
id="any-clear-thinking-version-dropped-others-kept",
|
||||
),
|
||||
pytest.param({"edits": [{"type": "clear_thinking_20251015"}]}, None, id="emptied-removed"),
|
||||
pytest.param(
|
||||
{"edits": [{"type": "clear_thinking_20251015"}], "extra": 1},
|
||||
{"edits": [], "extra": 1},
|
||||
id="other-keys-kept",
|
||||
),
|
||||
pytest.param({"edits": []}, {"edits": []}, id="empty-edits-untouched"),
|
||||
pytest.param("clear_thinking_20251015", "clear_thinking_20251015", id="non-dict-untouched"),
|
||||
pytest.param({"edits": "clear_thinking"}, {"edits": "clear_thinking"}, id="non-list-edits-untouched"),
|
||||
pytest.param(
|
||||
{"edits": ["clear_thinking_20251015", {"type": "clear_thinking_20251015"}]},
|
||||
{"edits": ["clear_thinking_20251015"]},
|
||||
id="non-dict-edit-kept",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_drop_clear_thinking_edits(self, context_management: object, expected: object) -> None:
|
||||
from litellm.llms.anthropic.common_utils import (
|
||||
drop_clear_thinking_edits,
|
||||
)
|
||||
|
||||
params: Final[dict[str, object]] = {"context_management": context_management}
|
||||
drop_clear_thinking_edits(params)
|
||||
assert params == ({} if expected is None else {"context_management": expected})
|
||||
|
||||
def test_strip_empty_content_blocks_from_anthropic_messages(self):
|
||||
"""Covers #22930. The core regression scenario: an assistant message
|
||||
with an empty text block alongside ``tool_use`` loses the empty block
|
||||
|
|
|
|||
|
|
@ -2195,6 +2195,36 @@ def test_bedrock_invoke_transform_emits_adaptive_thinking_for_opus_4_8():
|
|||
assert result["output_config"]["effort"] == "low"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"thinking_params",
|
||||
[
|
||||
pytest.param({"thinking": {"type": "adaptive"}, "output_config": {"effort": "high"}}, id="adaptive-effort"),
|
||||
pytest.param({"reasoning_effort": "none"}, id="reasoning-effort-none"),
|
||||
],
|
||||
)
|
||||
def test_bedrock_invoke_keeps_thinking_for_clear_thinking_edit_when_base_drops_thinking(
|
||||
thinking_params: dict[str, object],
|
||||
) -> None:
|
||||
from litellm.types.router import GenericLiteLLMParams
|
||||
|
||||
result: Final = AmazonAnthropicClaudeMessagesConfig().transform_anthropic_messages_request(
|
||||
model="anthropic.claude-opus-4-5-20251101-v1:0",
|
||||
messages=[{"role": "user", "content": "hi"}],
|
||||
anthropic_messages_optional_request_params={
|
||||
"max_tokens": 32000,
|
||||
**thinking_params,
|
||||
"context_management": {
|
||||
"edits": [{"type": "clear_thinking_20251015", "keep": "all"}, {"type": "clear_tool_uses_20250919"}]
|
||||
},
|
||||
},
|
||||
litellm_params=GenericLiteLLMParams(),
|
||||
headers={},
|
||||
)
|
||||
|
||||
assert result["thinking"] == {"type": "enabled", "budget_tokens": BEDROCK_MIN_THINKING_BUDGET_TOKENS}
|
||||
assert result["context_management"] == {"edits": [{"type": "clear_tool_uses_20250919"}]}
|
||||
|
||||
|
||||
def test_bedrock_invoke_transform_normalizes_system_role_message_into_system():
|
||||
"""Bedrock Invoke rejects ``role: "system"`` entries in ``messages`` on some
|
||||
Claude aliases; they must be moved into the top-level ``system`` field
|
||||
|
|
@ -4488,7 +4518,10 @@ async def test_bedrock_messages_fallback_to_anthropic_sends_the_tool_names_bedro
|
|||
"aws_region_name": "us-east-1",
|
||||
},
|
||||
},
|
||||
{"model_name": "anthropic-claude", "litellm_params": {"model": "anthropic/claude-opus-4-8", "api_key": "test"}},
|
||||
{
|
||||
"model_name": "anthropic-claude",
|
||||
"litellm_params": {"model": "anthropic/claude-opus-4-8", "api_key": "test"},
|
||||
},
|
||||
],
|
||||
fallbacks=[{"bedrock-claude": ["anthropic-claude"]}],
|
||||
num_retries=0,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import respx
|
|||
|
||||
import litellm
|
||||
from litellm.caching.llm_caching_handler import LLMClientCache
|
||||
from litellm.constants import BEDROCK_MIN_THINKING_BUDGET_TOKENS
|
||||
from litellm.llms.bedrock.base_aws_llm import BaseAWSLLM
|
||||
from litellm.llms.bedrock_mantle.messages.transformation import (
|
||||
BedrockMantleAnthropicMessagesConfig,
|
||||
|
|
@ -224,6 +225,86 @@ class TestRequestBody:
|
|||
)
|
||||
assert "stream" not in body
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("model", "thinking_params", "expected_thinking", "expected_edit_types"),
|
||||
[
|
||||
pytest.param(
|
||||
"anthropic.claude-3-5-haiku-20241022-v1:0",
|
||||
{"thinking": {"type": "adaptive"}},
|
||||
None,
|
||||
["clear_tool_uses_20250919"],
|
||||
id="no-thinking-support-drops-edit",
|
||||
),
|
||||
pytest.param(
|
||||
"anthropic.claude-3-5-haiku-20241022-v1:0",
|
||||
{},
|
||||
None,
|
||||
["clear_thinking_20251015", "clear_tool_uses_20250919"],
|
||||
id="caller-edit-without-thinking-forwarded",
|
||||
),
|
||||
pytest.param(
|
||||
"anthropic.claude-opus-4-5-20251101-v1:0",
|
||||
{"thinking": {"type": "adaptive"}, "output_config": {"effort": "high"}},
|
||||
{"type": "enabled", "budget_tokens": BEDROCK_MIN_THINKING_BUDGET_TOKENS},
|
||||
["clear_thinking_20251015", "clear_tool_uses_20250919"],
|
||||
id="thinking-added-back-keeps-edit",
|
||||
),
|
||||
pytest.param(
|
||||
"anthropic.claude-opus-4-5-20251101-v1:0",
|
||||
{"max_tokens": BEDROCK_MIN_THINKING_BUDGET_TOKENS, "reasoning_effort": "none"},
|
||||
None,
|
||||
["clear_tool_uses_20250919"],
|
||||
id="max-tokens-too-small-to-add-thinking-back-drops-edit",
|
||||
),
|
||||
pytest.param(
|
||||
"anthropic.claude-mythos-preview",
|
||||
{},
|
||||
None,
|
||||
["clear_thinking_20251015", "clear_tool_uses_20250919"],
|
||||
id="always-on-model-keeps-edit",
|
||||
),
|
||||
pytest.param(
|
||||
"anthropic.claude-sonnet-4-6",
|
||||
{"thinking": {"type": "adaptive"}},
|
||||
{"type": "adaptive"},
|
||||
["clear_thinking_20251015", "clear_tool_uses_20250919"],
|
||||
id="adaptive-thinking-keeps-edit",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_clear_thinking_edit_dropped_only_with_dropped_thinking(
|
||||
self,
|
||||
model: str,
|
||||
thinking_params: dict[str, object],
|
||||
expected_thinking: dict[str, object] | None,
|
||||
expected_edit_types: list[str],
|
||||
) -> None:
|
||||
body: Final = BedrockMantleAnthropicMessagesConfig().transform_anthropic_messages_request(
|
||||
model=model,
|
||||
messages=[{"role": "user", "content": "ping"}],
|
||||
anthropic_messages_optional_request_params={
|
||||
"max_tokens": 32000,
|
||||
**thinking_params,
|
||||
"context_management": {
|
||||
"edits": [{"type": "clear_thinking_20251015", "keep": "all"}, {"type": "clear_tool_uses_20250919"}]
|
||||
},
|
||||
},
|
||||
litellm_params=GenericLiteLLMParams(),
|
||||
headers={},
|
||||
)
|
||||
assert body.get("thinking") == expected_thinking
|
||||
assert [edit["type"] for edit in body["context_management"]["edits"]] == expected_edit_types
|
||||
|
||||
def test_disabled_thinking_without_edits_is_untouched(self) -> None:
|
||||
body: Final = BedrockMantleAnthropicMessagesConfig().transform_anthropic_messages_request(
|
||||
model="anthropic.claude-3-5-haiku-20241022-v1:0",
|
||||
messages=[{"role": "user", "content": "ping"}],
|
||||
anthropic_messages_optional_request_params={"max_tokens": 8, "thinking": {"type": "disabled"}},
|
||||
litellm_params=GenericLiteLLMParams(),
|
||||
headers={},
|
||||
)
|
||||
assert body["thinking"] == {"type": "disabled"}
|
||||
|
||||
def test_body_hoists_wrapped_defer_loading_and_drops_custom(self):
|
||||
schema: Final = {"type": "object", "properties": {}}
|
||||
body = BedrockMantleAnthropicMessagesConfig().transform_anthropic_messages_request(
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ class _CopilotThinkingCapabilities(BaseModel):
|
|||
supports_adaptive_thinking: bool | None = None
|
||||
supports_legacy_thinking: bool | None = None
|
||||
thinking_always_on: bool | None = None
|
||||
thinking_on_by_default: bool | None = None
|
||||
|
||||
|
||||
def _copilot_endpoint_rows(path: Path) -> Mapping[str, _CopilotEndpointRow]:
|
||||
|
|
@ -87,6 +88,7 @@ _THINKING_KEYS: Final[tuple[str, ...]] = (
|
|||
"supports_adaptive_thinking",
|
||||
"supports_legacy_thinking",
|
||||
"thinking_always_on",
|
||||
"thinking_on_by_default",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1211,6 +1211,7 @@ _COST_MAP_ROW_SCHEMA: Final = {
|
|||
"supports_anthropic_thinking_payload": {"type": "boolean"},
|
||||
"supports_legacy_thinking": {"type": "boolean"},
|
||||
"thinking_always_on": {"type": "boolean"},
|
||||
"thinking_on_by_default": {"type": "boolean"},
|
||||
"supports_mid_conversation_system": {"type": "boolean"},
|
||||
"supports_sampling_params": {"type": "boolean"},
|
||||
"supports_output_config": {"type": "boolean"},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue