mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-07 02:59:05 +00:00
fix(batches): map anthropic batch lines through the anthropic message transformer
Anthropic result lines carry a message-shaped body, so ModelResponse(**body) produced empty choices and a usage key that blocked the batch-rate usage attach. Extract the existing AnthropicResponse -> ModelResponse conversion used for /v1/messages logging into anthropic_message_to_model_response and reuse it for anthropic line items. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
ed23e2e82d
commit
096ba84f00
3 changed files with 34 additions and 15 deletions
|
|
@ -121,11 +121,17 @@ def _line_model(
|
|||
_BatchLineResult: TypeAlias = "ModelResponse | EmbeddingResponse | ResponsesAPIResponse"
|
||||
|
||||
|
||||
def _line_result(call_type: str, response_body: Mapping[str, object]) -> _BatchLineResult:
|
||||
def _line_result(
|
||||
call_type: str, custom_llm_provider: _BatchLineProvider, response_body: Mapping[str, object]
|
||||
) -> _BatchLineResult:
|
||||
if call_type == "aembedding":
|
||||
return EmbeddingResponse(**response_body) # pyright: ignore[reportArgumentType] # provider output bodies are dicts expanded as response ctor kwargs
|
||||
if call_type == "aresponses":
|
||||
return ResponsesAPIResponse(**response_body) # pyright: ignore[reportArgumentType] # same as above
|
||||
if custom_llm_provider == "anthropic":
|
||||
from litellm.litellm_core_utils.litellm_logging import anthropic_message_to_model_response
|
||||
|
||||
return anthropic_message_to_model_response(response_body, None)
|
||||
return ModelResponse(**response_body) # pyright: ignore[reportArgumentType] # same as above
|
||||
|
||||
|
||||
|
|
@ -235,7 +241,7 @@ async def _emit_line_event(
|
|||
|
||||
stats: Final = _safe_output_line_stats(entry, custom_llm_provider, model_name, model_info)
|
||||
try:
|
||||
result: Final = _line_result(call_type, response_body)
|
||||
result: Final = _line_result(call_type, custom_llm_provider, response_body)
|
||||
except Exception: # noqa: BLE001 # one unparseable line must not drop the rest of the batch's line events
|
||||
verbose_logger.warning(
|
||||
"batch output line could not be reconstructed as a %s response, skipping it. custom_id=%s",
|
||||
|
|
|
|||
|
|
@ -535,6 +535,24 @@ def _provider_response_id(source: object) -> str | None:
|
|||
return candidate if isinstance(candidate, str) and candidate else None
|
||||
|
||||
|
||||
def anthropic_message_to_model_response(result: Mapping[str, object], speed: str | None) -> ModelResponse:
|
||||
import httpx
|
||||
|
||||
from litellm.types.llms.anthropic import AnthropicResponse
|
||||
|
||||
pydantic_result: Final = AnthropicResponse.model_validate(result)
|
||||
return litellm.AnthropicConfig().transform_parsed_response(
|
||||
completion_response=pydantic_result.model_dump(),
|
||||
raw_response=httpx.Response(
|
||||
status_code=200,
|
||||
headers={},
|
||||
),
|
||||
model_response=litellm.ModelResponse(id=_provider_response_id(result)),
|
||||
json_mode=None,
|
||||
speed=speed,
|
||||
)
|
||||
|
||||
|
||||
def mask_api_base_credentials(api_base: str) -> str:
|
||||
if "key=" not in api_base:
|
||||
return api_base
|
||||
|
|
@ -4237,19 +4255,8 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
litellm_params={},
|
||||
)
|
||||
else:
|
||||
from litellm.types.llms.anthropic import AnthropicResponse
|
||||
|
||||
pydantic_result: Final = AnthropicResponse.model_validate(result)
|
||||
import httpx
|
||||
|
||||
result = litellm.AnthropicConfig().transform_parsed_response(
|
||||
completion_response=pydantic_result.model_dump(),
|
||||
raw_response=httpx.Response(
|
||||
status_code=200,
|
||||
headers={},
|
||||
),
|
||||
model_response=litellm.ModelResponse(id=provider_response_id),
|
||||
json_mode=None,
|
||||
result = anthropic_message_to_model_response(
|
||||
cast(Mapping[str, object], result),
|
||||
speed=self.optional_params.get("speed") if self.optional_params else None,
|
||||
)
|
||||
return result
|
||||
|
|
|
|||
|
|
@ -368,6 +368,8 @@ ANTHROPIC_OUTPUT_JSONL = json.dumps(
|
|||
"role": "assistant",
|
||||
"content": [{"type": "text", "text": "hello b2"}],
|
||||
"model": "claude-3",
|
||||
"stop_reason": "end_turn",
|
||||
"stop_sequence": None,
|
||||
"usage": {"input_tokens": 1, "output_tokens": 2},
|
||||
},
|
||||
},
|
||||
|
|
@ -482,3 +484,7 @@ async def test_line_items_anthropic_shapes(recorder):
|
|||
line = next(e for e in recorder.success_events if _hidden(e).get("batch_custom_id") == "b2")
|
||||
assert _hidden(line)["batch_line_status_code"] == 200
|
||||
assert line["litellm_params"]["batch_parent_id"] == batch.id
|
||||
payload = _payload(line)
|
||||
assert payload["response"]["choices"][0]["message"]["content"] == "hello b2"
|
||||
assert payload["prompt_tokens"] == 1
|
||||
assert payload["completion_tokens"] == 2
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue