mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-27 06:13:07 +00:00
fix(bedrock): apply the 16 maxTokens floor to Kimi K3 on Converse (#43875)
* fix(bedrock): apply the 16 maxTokens floor to Kimi K3 on Converse Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(e2e): use lane AWS credentials for the Kimi K3 messages test Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(e2e): bypass the proxy cache and declare test metadata for the Kimi K3 probe --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
This commit is contained in:
parent
d776277647
commit
dd20bb0ae9
4 changed files with 83 additions and 1 deletions
|
|
@ -385,7 +385,7 @@ class AmazonConverseConfig(BaseConfig):
|
|||
|
||||
@staticmethod
|
||||
def _requires_min_max_tokens(model: str) -> bool:
|
||||
return re.search(r"openai\.gpt-\d|xai\.grok-", model) is not None
|
||||
return re.search(r"openai\.gpt-\d|xai\.grok-|moonshotai\.kimi-k3", model) is not None
|
||||
|
||||
def _is_nova_2_model(self, model: str) -> bool:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@
|
|||
- {id: llm.messages.anthropic.vision.nonstream.works, module: llm, tier: P0, subject_endpoint: messages, route: anthropic, capability: vision, streaming: nonstream, assertions: [works], source: "model_prices json", rationale: "Vision via Messages API"}
|
||||
- {id: llm.messages.anthropic.prompt_cache_5m.nonstream.works, module: llm, tier: P0, subject_endpoint: messages, route: anthropic, capability: prompt_cache_5m, streaming: nonstream, assertions: [works], source: "model_prices json", rationale: "Prompt caching via Messages API"}
|
||||
- {id: llm.messages.anthropic.thinking.nonstream.works, module: llm, tier: P1, subject_endpoint: messages, route: anthropic, capability: thinking, streaming: nonstream, assertions: [works], source: "model_prices json", rationale: "Extended thinking via Messages API"}
|
||||
- {id: llm.messages.bedrock_converse.basic.nonstream.works_for_kimi_k3_max_tokens_1, module: llm, tier: P0, subject_endpoint: messages, route: bedrock_converse, capability: basic, streaming: nonstream, assertions: [works_for_kimi_k3_max_tokens_1], source: "llm_translation/test_bedrock_kimi_k3_messages_e2e.py", rationale: "Bedrock Converse accepts max_tokens=1 on the Anthropic Messages surface after LiteLLM applies the model minimum", fail_before_fix: proven}
|
||||
- {id: llm.messages.bedrock_invoke.mid_conversation_system.nonstream.cache_hit, module: llm, tier: P0, subject_endpoint: messages, route: bedrock_invoke, capability: mid_conversation_system, streaming: nonstream, assertions: [works, cache_hit], source: "llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py", rationale: "Flagged Claude 4.8+/5 must keep mid-conversation system reminders in messages; hoisting mutates the system prefix and collapses the prompt cache (#32578/#32831/#32882)", fail_before_fix: proven}
|
||||
- {id: llm.messages.bedrock_invoke.mid_conversation_system.nonstream.works, module: llm, tier: P0, subject_endpoint: messages, route: bedrock_invoke, capability: mid_conversation_system, streaming: nonstream, assertions: [works], source: "llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py", rationale: "Claude <= 4.7 rejects role system inside messages; unflagged models must convert reminders to user turns in place (hoisting collapses the prompt cache) or every Claude Code session 400s (#32831)", fail_before_fix: proven}
|
||||
- {id: llm.messages.bedrock_invoke.web_search_server_tool.nonstream.works, module: llm, tier: P0, subject_endpoint: messages, route: bedrock_invoke, capability: web_search_server_tool, streaming: nonstream, assertions: [works], source: "llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py", rationale: "Bedrock hosts no web_search server tool, so this only works because interception rewrites it before the upstream call and the agentic loop feeds the results back in native shape; a regression that short-circuits or forwards it instead yields raw text or AWS's 400", fail_before_fix: unproven}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Final
|
||||
|
||||
import pytest
|
||||
from anthropic.types import Message, MessageParam
|
||||
from e2e_metadata import Domain, Mode, Provider, Route, Subject, meta
|
||||
from lifecycle import ResourceManager
|
||||
from models import LiteLLMParamsBody
|
||||
from proxy_client import ProxyClient
|
||||
from sdk_clients import NO_PROXY_CACHE, SdkClients
|
||||
|
||||
pytestmark = pytest.mark.e2e
|
||||
|
||||
BEDROCK_MODEL: Final = "bedrock/us.moonshotai.kimi-k3"
|
||||
MODEL_NAME: Final = "claude-kimi-k3"
|
||||
MODEL_SWITCH_BETA: Final = (
|
||||
"claude-code-20250219,context-1m-2025-08-07,interleaved-thinking-2025-05-14,"
|
||||
"redact-thinking-2026-02-12,context-management-2025-06-27,"
|
||||
"prompt-caching-scope-2026-01-05,mid-conversation-system-2026-04-07"
|
||||
)
|
||||
|
||||
|
||||
def _register_model(proxy: ProxyClient, resources: ResourceManager) -> tuple[str, str]:
|
||||
model_id: Final = proxy.create_model(
|
||||
MODEL_NAME,
|
||||
LiteLLMParamsBody(
|
||||
model=BEDROCK_MODEL,
|
||||
aws_access_key_id="os.environ/AWS_ACCESS_KEY_ID",
|
||||
aws_secret_access_key="os.environ/AWS_SECRET_ACCESS_KEY",
|
||||
aws_region_name="os.environ/AWS_REGION",
|
||||
drop_params=True,
|
||||
),
|
||||
)
|
||||
resources.defer(lambda: proxy.delete_model(model_id))
|
||||
return MODEL_NAME, resources.key(models=[MODEL_NAME])
|
||||
|
||||
|
||||
class TestBedrockKimiK3Messages:
|
||||
@pytest.mark.covers("llm.messages.bedrock_converse.basic.nonstream.works_for_kimi_k3_max_tokens_1")
|
||||
@meta(
|
||||
Subject(
|
||||
domain=Domain.LLM_TRANSLATION,
|
||||
route=Route.MESSAGES,
|
||||
providers=(Provider.BEDROCK,),
|
||||
models=(BEDROCK_MODEL,),
|
||||
mode=Mode.NONSTREAM,
|
||||
)
|
||||
)
|
||||
def test_model_switch_probe_max_tokens_1_returns_message(
|
||||
self, proxy: ProxyClient, resources: ResourceManager, sdk: SdkClients
|
||||
) -> None:
|
||||
model, key = _register_model(proxy, resources)
|
||||
client: Final = sdk.anthropic(key)
|
||||
message_param: Final[MessageParam] = {
|
||||
"role": "user",
|
||||
"content": [{"type": "text", "text": "Hi", "cache_control": {"type": "ephemeral"}}],
|
||||
}
|
||||
message: Final = client.messages.create(
|
||||
model=model,
|
||||
max_tokens=1,
|
||||
stream=False,
|
||||
system="You are Claude Code, an assistant for software development.",
|
||||
messages=[message_param],
|
||||
extra_headers={"anthropic-beta": MODEL_SWITCH_BETA},
|
||||
extra_query={"beta": "true"},
|
||||
extra_body=NO_PROXY_CACHE,
|
||||
)
|
||||
|
||||
assert isinstance(message, Message)
|
||||
assert message.role == "assistant"
|
||||
|
|
@ -896,6 +896,16 @@ def test_reasoning_with_forced_tool_choice_switches_to_auto():
|
|||
("us.xai.grok-4.6", "max_tokens", 1, 16),
|
||||
("global.xai.grok-4.6", "max_completion_tokens", 1, 16),
|
||||
("us.xai.grok-4.6", "max_tokens", 32, 32),
|
||||
("us.moonshotai.kimi-k3", "max_tokens", 1, 16),
|
||||
("global.moonshotai.kimi-k3", "max_completion_tokens", 1, 16),
|
||||
("moonshotai.kimi-k3", "max_tokens", 64, 64),
|
||||
(
|
||||
"arn:aws:bedrock:us-east-1:123456789012:inference-profile/us.moonshotai.kimi-k3",
|
||||
"max_tokens",
|
||||
1,
|
||||
16,
|
||||
),
|
||||
("moonshotai.kimi-k2.5", "max_tokens", 1, 1),
|
||||
("anthropic.claude-sonnet-4-5-20250929-v1:0", "max_tokens", 1, 1),
|
||||
("arn:aws:bedrock:us-east-1:123456789012:inference-profile/us.openai.gpt-6-astra", "max_tokens", 1, 16),
|
||||
("arn:aws:bedrock:us-east-1:123456789012:inference-profile/global.xai.grok-4.6", "max_tokens", 1, 16),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue