mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-16 04:29:31 +00:00
* feat(telemetry): record proxy requests and provider attempts into the telemetry sink * fix(telemetry): validate env settings, fix the window and only record the request's own provider calls Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(telemetry): bind the call id from a typed local Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(telemetry): record a finished request into the sink current when it finishes Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(telemetry): record every failed provider attempt, including retries and fallbacks on a shared logging object Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(telemetry): report timeouts and connection failures as their own provider status classes Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix(telemetry): record failed attempts from the per-deployment failure hook instead of a new core logging hook Reverts the async_log_attempt_failure_event hook added to CustomLogger and litellm_logging in 3421b38685. The router already calls async_post_call_failure_deployment_hook once per failed attempt, retries and fallbacks included, so every failed fallback still gets its own row without touching the shared logging object. * fix(telemetry): register the attempt logger only once a telemetry group is turned on A proxy that never opts in now carries no telemetry callback. Once registered the logger stays, returning early while every group is off. --------- Co-authored-by: nate <nate@berri.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
37 lines
1.2 KiB
Python
37 lines
1.2 KiB
Python
from typing import Final
|
|
|
|
import pytest
|
|
|
|
from litellm.proxy.telemetry.blocks import count_blocks
|
|
from litellm.telemetry.records import BlockCounts, BlockType
|
|
|
|
|
|
def test_counts_string_content_part_lists_tool_calls_and_tool_messages() -> None:
|
|
messages: Final = [
|
|
{"role": "system", "content": "be brief"},
|
|
{
|
|
"role": "user",
|
|
"content": [
|
|
{"type": "text", "text": "what is in this picture"},
|
|
{"type": "image_url", "image_url": {"url": "data:image/png;base64,AAAA"}},
|
|
{"type": "something_new"},
|
|
],
|
|
},
|
|
{"role": "assistant", "content": None, "tool_calls": [{"id": "a"}, {"id": "b"}]},
|
|
{"role": "tool", "content": "42", "tool_call_id": "a"},
|
|
]
|
|
assert count_blocks(messages) == BlockCounts(
|
|
total=7,
|
|
by_type=(
|
|
(BlockType.IMAGE, 1),
|
|
(BlockType.OTHER, 1),
|
|
(BlockType.TEXT, 2),
|
|
(BlockType.TOOL_RESULT, 1),
|
|
(BlockType.TOOL_USE, 2),
|
|
),
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("messages", [None, "a prompt string", [{"content": "no role"}]])
|
|
def test_anything_that_is_not_a_message_list_has_no_block_counts(messages: object) -> None:
|
|
assert count_blocks(messages) is None
|