test: delete 34 legacy tests already covered by e2e (#45340)

Co-authored-by: yuneng <yuneng@berri.ai>
This commit is contained in:
devin-ai-integration[bot] 2026-10-08 09:43:56 -07:00 • committed by GitHub
parent 35b0992533
commit 92654b69a9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 0 additions and 1884 deletions

View file

@ -1095,50 +1095,6 @@ jobs:
- google_generate_content_endpoint_coverage.xml
- google_generate_content_endpoint_coverage
llm_responses_api_testing:
docker:
- *python312_image
working_directory: ~/project
resource_class: large
environment:
REQUEST_TIMEOUT: "180"
steps:
- checkout
- skip_if_unrelated_changes
- setup_google_dns
- install_uv
- install_rust
- restore_cache:
keys:
- v1-uv-cache-{{ checksum "uv.lock" }}
- run:
name: Install Dependencies
command: |
uv sync --frozen --all-groups --all-extras --python 3.12
- save_cache:
paths:
- ~/.cache/uv
key: v1-uv-cache-{{ checksum "uv.lock" }}
# Run pytest and generate JUnit XML report
- run:
name: Run tests
command: |
mkdir -p test-results
TEST_FILES=$(circleci tests glob "tests/llm_responses_api_testing/**/test_*.py")
echo "$TEST_FILES" | circleci tests run \
--verbose \
--command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
-v \
--junitxml=test-results/junit.xml \
--durations=5 \
-n 8 \
--reruns 1 --only-rerun Timeout"
no_output_timeout: 15m
# Store test results
- store_test_results:
path: test-results
ocr_testing:
docker:
- *python312_image
@ -3516,7 +3472,6 @@ workflows:
- realtime_translation_testing
- guardrails_testing
- google_generate_content_endpoint_testing
- llm_responses_api_testing
- ocr_testing
- search_testing
- batches_testing

View file

@ -1,107 +0,0 @@
"""
Bedrock Token Counter Tests.
Tests for the Bedrock token counter implementation using the base test suite.
Note: Not all Bedrock models support token counting. The CountTokens API
is only available for specific models. If the model doesn't support token
counting, the test will be skipped.
"""
import os
from typing import Any, Dict, List
import pytest
from litellm.llms.base_llm.base_utils import BaseTokenCounter
from litellm.llms.bedrock.count_tokens.bedrock_token_counter import BedrockTokenCounter
from tests.litellm_utils_tests.base_token_counter_test import BaseTokenCounterTest
class TestBedrockTokenCounter(BaseTokenCounterTest):
"""Test suite for Bedrock token counter.
Note: Bedrock CountTokens API support varies by model. Some models
(like older Claude versions) may not support token counting.
Use amazon.nova-* models for reliable token counting support.
"""
def get_token_counter(self) -> BaseTokenCounter:
return BedrockTokenCounter()
def get_test_model(self) -> str:
# Use Amazon Nova model which supports token counting
# Alternatively, use environment variable to override
return os.getenv("BEDROCK_TEST_MODEL", "amazon.nova-lite-v1:0")
def get_test_messages(self) -> List[Dict[str, Any]]:
return [{"role": "user", "content": "Hello, how are you today?"}]
def get_deployment_config(self) -> Dict[str, Any]:
# Bedrock uses AWS credentials from environment
# Check for AWS credentials
aws_access_key = os.getenv("AWS_ACCESS_KEY_ID")
aws_secret_key = os.getenv("AWS_SECRET_ACCESS_KEY")
aws_region = os.getenv("AWS_REGION_NAME", "us-east-1")
if not aws_access_key or not aws_secret_key:
pytest.skip(
"AWS credentials not set (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)"
)
return {
"litellm_params": {
"aws_access_key_id": aws_access_key,
"aws_secret_access_key": aws_secret_key,
"aws_region_name": aws_region,
}
}
def get_custom_llm_provider(self) -> str:
return "bedrock"
@pytest.mark.asyncio
async def test_count_tokens_basic(self):
"""
Test basic token counting functionality.
Override to handle models that don't support token counting.
"""
from litellm.types.utils import TokenCountResponse
token_counter = self.get_token_counter()
model = self.get_test_model()
messages = self.get_test_messages()
deployment = self.get_deployment_config()
result = await token_counter.count_tokens(
model_to_use=model,
messages=messages,
contents=None,
deployment=deployment,
request_model=model,
)
print(f"Token count result: {result}")
assert result is not None, "Token counter should return a result"
assert isinstance(
result, TokenCountResponse
), "Result should be TokenCountResponse"
# Check if the model doesn't support token counting
if result.error and "doesn't support counting tokens" in str(
result.error_message
):
pytest.skip(
f"Model {model} doesn't support token counting: {result.error_message}"
)
assert (
result.total_tokens > 0
), f"Token count should be > 0, got {result.total_tokens}"
assert result.tokenizer_type is not None, "tokenizer_type should be set"
assert (
result.error is not True
), f"Token counting should not error: {result.error_message}"

View file

@ -1,550 +0,0 @@
import httpx
import json
import pytest
from typing import Any, Dict, List, Optional
from unittest.mock import MagicMock, Mock, patch
from litellm._uuid import uuid
import time
import base64
import litellm
from abc import ABC, abstractmethod
from litellm.integrations.custom_logger import CustomLogger
from litellm.types.utils import StandardLoggingPayload
from litellm.types.llms.openai import (
ResponseCompletedEvent,
ResponsesAPIResponse,
ResponseAPIUsage,
IncompleteDetails,
)
from openai.types.responses.response_create_params import (
ResponseInputParam,
)
from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler
import openai
def validate_responses_api_response(response, final_chunk: bool = False):
"""
Validate that a response from litellm.responses() or litellm.aresponses()
conforms to the expected ResponsesAPIResponse structure.
Args:
response: The response object to validate
Raises:
AssertionError: If the response doesn't match the expected structure
"""
# Validate response structure
print("response=", json.dumps(response, indent=4, default=str))
assert isinstance(
response, ResponsesAPIResponse
), "Response should be an instance of ResponsesAPIResponse"
# Required fields
assert "id" in response and isinstance(
response["id"], str
), "Response should have a string 'id' field"
assert "created_at" in response and isinstance(
response["created_at"], int
), "Response should have an integer 'created_at' field"
if response.get("status") == "completed":
assert "output" in response and isinstance(
response["output"], list
), "Response should have a list 'output' field"
# Optional fields with their expected types
optional_fields = {
"error": (dict, type(None)), # error can be dict or None
"incomplete_details": (IncompleteDetails, type(None)),
"instructions": (str, type(None)),
"metadata": dict,
"model": str,
"object": str,
"parallel_tool_calls": (bool, type(None)),
"temperature": (int, float, type(None)),
"tool_choice": (dict, str, type(None)),
"tools": (list, type(None)),
"top_p": (int, float, type(None)),
"max_output_tokens": (int, type(None)),
"previous_response_id": (str, type(None)),
"reasoning": (dict, type(None)),
"status": str,
"text": dict,
"truncation": (str, type(None)),
"usage": ResponseAPIUsage,
"user": (str, type(None)),
"store": (bool, type(None)),
}
if final_chunk is False:
optional_fields["usage"] = type(None)
for field, expected_type in optional_fields.items():
if field in response:
assert isinstance(
response[field], expected_type
), f"Field '{field}' should be of type {expected_type}, but got {type(response[field])}"
# Check if output has at least one item
if final_chunk is True and response.get("status") == "completed":
assert (
len(response["output"]) > 0
), "Response 'output' field should have at least one item"
return True # Return True if validation passes
class BaseResponsesAPITest(ABC):
"""
Abstract base test class that enforces a common test across all test classes.
"""
@abstractmethod
def get_base_completion_call_args(self) -> dict:
"""Must return the base completion call args"""
pass
def get_advanced_model_for_shell_tool(self) -> Optional[str]:
"""If specified, overrides the model used by test_responses_api_shell_tool_streaming_sees_shell_output (e.g. openai/gpt-5.2 for shell support)."""
return None
@pytest.mark.parametrize("sync_mode", [True, False])
@pytest.mark.asyncio
async def test_basic_openai_responses_api(self, sync_mode):
litellm.turn_on_debug()
litellm.set_verbose = True
base_completion_call_args = self.get_base_completion_call_args()
try:
if sync_mode:
response = litellm.responses(
input="Basic ping",
max_output_tokens=20,
**base_completion_call_args,
)
else:
response = await litellm.aresponses(
input="Basic ping",
max_output_tokens=20,
**base_completion_call_args,
)
except litellm.InternalServerError:
pytest.skip("Skipping test due to litellm.InternalServerError")
print("litellm response=", json.dumps(response, indent=4, default=str))
# Use the helper function to validate the response
validate_responses_api_response(response, final_chunk=True)
@pytest.mark.parametrize("sync_mode", [True, False])
@pytest.mark.asyncio
@pytest.mark.flaky(retries=3, delay=2)
async def test_basic_openai_responses_api_streaming(self, sync_mode):
litellm.turn_on_debug()
# Enable cost calculation for streaming usage
litellm.include_cost_in_streaming_usage = True
base_completion_call_args = self.get_base_completion_call_args()
collected_content_string = ""
response_completed_event = None
if sync_mode:
response = litellm.responses(
input="Basic ping", stream=True, **base_completion_call_args
)
for event in response:
print("litellm response=", json.dumps(event, indent=4, default=str))
if event.type == "response.output_text.delta":
collected_content_string += event.delta
elif event.type == "response.completed":
response_completed_event = event
else:
response = await litellm.aresponses(
input="Basic ping", stream=True, **base_completion_call_args
)
async for event in response:
print("litellm response=", json.dumps(event, indent=4, default=str))
if event.type == "response.output_text.delta":
collected_content_string += event.delta
elif event.type == "response.completed":
response_completed_event = event
# assert the response completed event is not None
assert response_completed_event is not None
# assert the response completed event has a response
assert response_completed_event.response is not None
# For async agent APIs (like Manus), the response may be in 'running' state
# without content yet - this is valid behavior
response_status = response_completed_event.response.status
if response_status in ["running", "pending"]:
# Running/pending state is acceptable - task started successfully
print(
f"Response is in '{response_status}' state - async agent API behavior"
)
assert response_completed_event.response.id is not None
else:
# For completed responses, validate content and usage
# assert the delta chunks content had len(collected_content_string) > 0
# this content is typically rendered on chat ui's
assert len(collected_content_string) > 0
# assert the response completed event includes the usage
assert response_completed_event.response.usage is not None
# basic test assert the usage seems reasonable
print(
"response_completed_event.response.usage=",
response_completed_event.response.usage,
)
assert (
response_completed_event.response.usage.input_tokens > 0
and response_completed_event.response.usage.input_tokens < 100
)
assert (
response_completed_event.response.usage.output_tokens > 0
and response_completed_event.response.usage.output_tokens < 2000
)
assert (
response_completed_event.response.usage.total_tokens > 0
and response_completed_event.response.usage.total_tokens < 2000
)
# total tokens should be the sum of input and output tokens
assert (
response_completed_event.response.usage.total_tokens
== response_completed_event.response.usage.input_tokens
+ response_completed_event.response.usage.output_tokens
)
# assert the response completed event includes cost when include_cost_in_streaming_usage is True
assert hasattr(
response_completed_event.response.usage, "cost"
), "Cost should be included in streaming responses API usage object"
assert (
response_completed_event.response.usage.cost > 0
), "Cost should be greater than 0"
print(
f"Cost found in streaming response: {response_completed_event.response.usage.cost}"
)
# Reset the setting
litellm.include_cost_in_streaming_usage = False
@pytest.mark.parametrize("sync_mode", [False, True])
@pytest.mark.asyncio
async def test_basic_openai_responses_delete_endpoint(self, sync_mode):
litellm.turn_on_debug()
litellm.set_verbose = True
base_completion_call_args = self.get_base_completion_call_args()
if sync_mode:
response = litellm.responses(
input="Basic ping", max_output_tokens=20, **base_completion_call_args
)
# delete the response
if isinstance(response, ResponsesAPIResponse):
litellm.delete_responses(
response_id=response.id, **base_completion_call_args
)
else:
raise ValueError("response is not a ResponsesAPIResponse")
else:
response = await litellm.aresponses(
input="Basic ping", max_output_tokens=20, **base_completion_call_args
)
# async delete the response
if isinstance(response, ResponsesAPIResponse):
await litellm.adelete_responses(
response_id=response.id, **base_completion_call_args
)
else:
raise ValueError("response is not a ResponsesAPIResponse")
@pytest.mark.parametrize("sync_mode", [True, False])
@pytest.mark.flaky(retries=3, delay=2)
@pytest.mark.asyncio
async def test_basic_openai_responses_streaming_delete_endpoint(self, sync_mode):
# litellm.turn_on_debug()
# litellm.set_verbose = True
base_completion_call_args = self.get_base_completion_call_args()
response_id = None
if sync_mode:
response_id = None
response = litellm.responses(
input="Basic ping",
max_output_tokens=20,
stream=True,
**base_completion_call_args,
)
for event in response:
print("litellm response=", json.dumps(event, indent=4, default=str))
if "response" in event:
response_obj = event.get("response")
if response_obj is not None:
response_id = response_obj.get("id")
print("got response_id=", response_id)
# delete the response
assert response_id is not None
litellm.delete_responses(
response_id=response_id, **base_completion_call_args
)
else:
response = await litellm.aresponses(
input="Basic ping",
max_output_tokens=20,
stream=True,
**base_completion_call_args,
)
async for event in response:
print("litellm response=", json.dumps(event, indent=4, default=str))
if "response" in event:
response_obj = event.get("response")
if response_obj is not None:
response_id = response_obj.get("id")
print("got response_id=", response_id)
# delete the response
assert response_id is not None
await litellm.adelete_responses(
response_id=response_id, **base_completion_call_args
)
@pytest.mark.parametrize("sync_mode", [False, True])
@pytest.mark.flaky(retries=3, delay=2)
@pytest.mark.asyncio
async def test_basic_openai_responses_get_endpoint(self, sync_mode):
litellm.turn_on_debug()
litellm.set_verbose = True
base_completion_call_args = self.get_base_completion_call_args()
if sync_mode:
response = litellm.responses(
input="Basic ping", max_output_tokens=20, **base_completion_call_args
)
# get the response
if isinstance(response, ResponsesAPIResponse):
result = litellm.get_responses(
response_id=response.id, **base_completion_call_args
)
assert result is not None
assert result.id == response.id
assert result.output_text == response.output_text
else:
raise ValueError("response is not a ResponsesAPIResponse")
else:
response = await litellm.aresponses(
input="Basic ping", max_output_tokens=20, **base_completion_call_args
)
# async get the response
if isinstance(response, ResponsesAPIResponse):
result = await litellm.aget_responses(
response_id=response.id, **base_completion_call_args
)
assert result is not None
assert result.id == response.id
assert result.output_text == response.output_text
else:
raise ValueError("response is not a ResponsesAPIResponse")
@pytest.mark.asyncio
async def test_responses_api_with_tool_calls(self):
"""Test that calls the Responses API with tool calls including function call and output"""
litellm.turn_on_debug()
litellm.set_verbose = True
base_completion_call_args = self.get_base_completion_call_args()
# Define the input with message, function call, and function call output
input_data: ResponseInputParam = [
{
"type": "message",
"role": "user",
"content": "How is the weather in São Paulo today ?",
},
{
"type": "function_call",
"arguments": '{"location": "São Paulo, Brazil"}',
"call_id": "fc_1fe70e2a-a596-45ef-b72c-9b8567c460e5",
"name": "get_weather",
"id": "fc_1fe70e2a-a596-45ef-b72c-9b8567c460e5",
"status": "completed",
},
{
"type": "function_call_output",
"call_id": "fc_1fe70e2a-a596-45ef-b72c-9b8567c460e5",
"output": "Rainy",
},
]
# Define the tools
tools = [
{
"type": "function",
"name": "get_weather",
"description": "Get current temperature for a given location.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and country e.g. Bogotá, Colombia",
}
},
"required": ["location"],
"additionalProperties": False,
},
}
]
try:
# Make the responses API call
response = await litellm.aresponses(
input=input_data, store=False, tools=tools, **base_completion_call_args
)
except litellm.InternalServerError:
pytest.skip("Skipping test due to litellm.InternalServerError")
print("litellm response=", json.dumps(response, indent=4, default=str))
# Validate the response structure
validate_responses_api_response(response, final_chunk=True)
# Additional assertions specific to tool calls
assert response is not None
assert "output" in response
# For async agent APIs (like Manus), the response may be in 'running' state
# without output yet - this is valid behavior
if response.get("status") in ["running", "pending"]:
print(
f"Response is in '{response.get('status')}' state - async agent API behavior"
)
assert response.get("id") is not None
else:
assert len(response["output"]) > 0
@pytest.mark.parametrize("sync_mode", [False, True])
@pytest.mark.flaky(retries=3, delay=2)
@pytest.mark.asyncio
async def test_basic_openai_responses_cancel_endpoint(self, sync_mode):
try:
litellm.turn_on_debug()
litellm.set_verbose = True
base_completion_call_args = self.get_base_completion_call_args()
if sync_mode:
response = litellm.responses(
input="Basic ping",
max_output_tokens=20,
background=True,
**base_completion_call_args,
)
# cancel the response
if isinstance(response, ResponsesAPIResponse):
cancel_result = litellm.cancel_responses(
response_id=response.id, **base_completion_call_args
)
assert cancel_result is not None
assert hasattr(cancel_result, "id")
# The actual response structure depends on the provider implementation
assert isinstance(cancel_result, ResponsesAPIResponse)
else:
raise ValueError("response is not a ResponsesAPIResponse")
else:
response = await litellm.aresponses(
input="Basic ping",
max_output_tokens=20,
background=True,
**base_completion_call_args,
)
# async cancel the response
if isinstance(response, ResponsesAPIResponse):
cancel_result = await litellm.acancel_responses(
response_id=response.id, **base_completion_call_args
)
assert cancel_result is not None
assert hasattr(cancel_result, "id")
# The actual response structure depends on the provider implementation
assert isinstance(cancel_result, ResponsesAPIResponse)
else:
raise ValueError("response is not a ResponsesAPIResponse")
except Exception as e:
if "Cannot cancel a completed response" in str(e):
pass
else:
raise e
@pytest.mark.asyncio
async def test_responses_api_context_management_server_side_compaction(self):
"""
E2E test for server-side compaction (context_management) on OpenAI Responses API.
Passes context_management with compact_threshold; validates that the request is
accepted and returns a valid response. Compaction may not run for short inputs.
"""
base_completion_call_args = self.get_base_completion_call_args()
model = base_completion_call_args.get("model") or ""
# Azure does not support compaction context_management (only clear_tool_results)
if "azure/" in str(model):
pytest.skip("context_management compaction is not supported on Azure")
if "openai/" not in str(model):
pytest.skip(
"context_management server-side compaction e2e is only run for OpenAI"
)
context_management = [{"type": "compaction", "compact_threshold": 200000}]
try:
response = await litellm.aresponses(
input="Short ping to verify context_management is accepted.",
max_output_tokens=20,
context_management=context_management,
**base_completion_call_args,
)
except litellm.InternalServerError:
pytest.skip("Skipping test due to litellm.InternalServerError")
validate_responses_api_response(response, final_chunk=True)
assert response.get("id") is not None
assert response.get("status") is not None
@pytest.mark.asyncio
async def test_responses_api_shell_tool(self):
"""
E2E test for Shell tool on OpenAI Responses API.
Passes tools=[{"type": "shell", "environment": {"type": "container_auto"}}];
validates that the request is accepted and returns a valid response.
Only runs for OpenAI; offline coverage for the Azure route lives in
tests/unit/responses/test_responses_api_request_body.py.
"""
base_completion_call_args = self.get_base_completion_call_args()
model = (
self.get_advanced_model_for_shell_tool()
or base_completion_call_args.get("model")
or ""
)
if "openai/" not in str(model):
pytest.skip(
"Shell tool e2e is OpenAI-only; no Azure deployment supports the shell tool yet, re-enable once one exists"
)
tools = [{"type": "shell", "environment": {"type": "container_auto"}}]
input_msg = "List files in /mnt/data and show python --version."
try:
response = await litellm.aresponses(
**{**base_completion_call_args, "model": model},
input=input_msg,
max_output_tokens=256,
tools=tools,
tool_choice="auto",
timeout=90,
)
except litellm.Timeout:
pytest.skip("Provider did not answer the shell tool request within 90s")
except litellm.InternalServerError:
pytest.skip("Skipping test due to litellm.InternalServerError")
except litellm.BadRequestError as e:
if "shell" in str(e).lower() and "not supported" in str(e).lower():
pytest.skip(
"Shell tool is not supported for this model (e.g. gpt-5.5); use a model that supports shell"
)
raise
validate_responses_api_response(response, final_chunk=True)
assert response.get("id") is not None
assert response.get("status") is not None

View file

@ -1,112 +0,0 @@
# conftest.py
import asyncio
import importlib
import pytest
import litellm # noqa: E402
from tests._vcr_conftest_common import ( # noqa: E402,F401
VerboseReporterState,
_pin_multipart_boundary,
apply_vcr_auto_marker_to_items,
emit_cassette_cache_session_banner,
emit_vcr_classification_summary,
emit_vcr_diagnostic_log,
install_live_call_probe,
record_vcr_outcome,
register_persister_if_enabled,
reset_vcr_diag_dir,
vcr_config_dict,
)
_verbose_state = VerboseReporterState()
@pytest.fixture(scope="module")
def vcr_config():
return vcr_config_dict()
def pytest_recording_configure(config, vcr):
register_persister_if_enabled(vcr)
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
outcome = yield
rep = outcome.get_result()
setattr(item, f"rep_{rep.when}", rep)
@pytest.fixture(autouse=True)
def _vcr_outcome_gate(request, vcr):
install_live_call_probe(request, vcr)
yield
record_vcr_outcome(request, vcr)
def pytest_configure(config):
_verbose_state.remember_pluginmanager(config)
reset_vcr_diag_dir()
def pytest_runtest_logreport(report):
_verbose_state.maybe_emit_verdict(report)
@pytest.fixture(scope="session")
def event_loop():
try:
loop = asyncio.get_running_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
yield loop
loop.close()
@pytest.fixture(scope="function", autouse=True)
def setup_and_teardown():
"""
This fixture reloads litellm before every function. To speed up testing by removing callbacks being chained.
"""
importlib.reload(litellm)
try:
if hasattr(litellm, "proxy") and hasattr(litellm.proxy, "proxy_server"):
importlib.reload(litellm.proxy.proxy_server)
except Exception as e:
print(f"Error reloading litellm.proxy.proxy_server: {e}")
loop = asyncio.get_event_loop_policy().new_event_loop()
asyncio.set_event_loop(loop)
print(litellm)
yield
# Teardown code (executes after the yield point)
loop.close() # Close the loop created earlier
asyncio.set_event_loop(None) # Remove the reference to the loop
def pytest_collection_modifyitems(config, items):
apply_vcr_auto_marker_to_items(items)
custom_logger_tests = [
item for item in items if "custom_logger" in item.parent.name
]
other_tests = [item for item in items if "custom_logger" not in item.parent.name]
custom_logger_tests.sort(key=lambda x: x.name)
other_tests.sort(key=lambda x: x.name)
items[:] = custom_logger_tests + other_tests
def pytest_terminal_summary(terminalreporter, exitstatus, config):
emit_cassette_cache_session_banner(terminalreporter)
emit_vcr_classification_summary(terminalreporter)
emit_vcr_diagnostic_log(terminalreporter)

View file

@ -1,90 +0,0 @@
import litellm
from base_responses_api import BaseResponsesAPITest
from openai.types.responses.function_tool import FunctionTool
class TestAnthropicResponsesAPITest(BaseResponsesAPITest):
test_basic_openai_responses_delete_endpoint = None
test_basic_openai_responses_streaming_delete_endpoint = None
test_basic_openai_responses_get_endpoint = None
test_basic_openai_responses_cancel_endpoint = None
def get_base_completion_call_args(self):
# litellm.turn_on_debug()
return {
"model": "anthropic/claude-sonnet-4-5",
}
def test_multiturn_tool_calls():
# Test streaming response with tools for Anthropic
litellm.turn_on_debug()
shell_tool = dict(
FunctionTool(
type="function",
name="shell",
description="Runs a shell command, and returns its output.",
parameters={
"type": "object",
"properties": {
"command": {"type": "array", "items": {"type": "string"}},
"workdir": {
"type": "string",
"description": "The working directory for the command.",
},
},
"required": ["command"],
},
strict=True,
)
)
# Step 1: Initial request with the tool
response = litellm.responses(
input=[
{
"role": "user",
"content": [
{"type": "input_text", "text": "make a hello world html file"}
],
"type": "message",
}
],
model="anthropic/claude-haiku-4-5-20251001",
instructions="You are a helpful coding assistant.",
tools=[shell_tool],
)
print("response=", response)
# Step 2: Send the results of the tool call back to the model
# Get the response ID and tool call ID from the response
response_id = response.id
tool_call_id = None
for item in response.output:
if hasattr(item, "type") and item.type == "function_call":
tool_call_id = getattr(item, "call_id", None)
if tool_call_id:
break
# Validate that we got a tool call with a valid call_id
if not tool_call_id:
raise AssertionError(
f"Expected a function_call with a valid call_id in response.output, but got: {response.output}"
)
# Use await with asyncio.run for the async function
follow_up_response = litellm.responses(
model="anthropic/claude-haiku-4-5-20251001",
previous_response_id=response_id,
input=[
{
"type": "function_call_output",
"call_id": tool_call_id,
"output": '{"output":"<html>\\n<head>\\n <title>Hello Page</title>\\n</head>\\n<body>\\n <h1>Hi</h1>\\n <p>Welcome to this simple webpage!</p>\\n</body>\\n</html> > index.html\\n","metadata":{"exit_code":0,"duration_seconds":0}}',
}
],
tools=[shell_tool],
)
print("follow_up_response=", follow_up_response)

View file

@ -1,34 +0,0 @@
import os
import pytest
import litellm
from base_responses_api import BaseResponsesAPITest
class TestAzureResponsesAPITest(BaseResponsesAPITest):
test_responses_api_with_tool_calls = None
def get_base_completion_call_args(self):
return {
"model": "azure/gpt-4.1-mini",
"truncation": "auto",
"api_base": os.getenv("AZURE_AI_API_BASE"),
"api_key": os.getenv("AZURE_AI_API_KEY"),
"api_version": "2025-03-01-preview",
}
@pytest.mark.asyncio
async def test_azure_responses_api_preview_api_version():
"""
Ensure new azure preview api version is working
"""
litellm.turn_on_debug()
response = await litellm.aresponses(
model="azure/gpt-5-mini",
truncation="auto",
api_version="preview",
api_base=os.getenv("AZURE_AI_API_BASE"),
api_key=os.getenv("AZURE_AI_API_KEY"),
input="Hello, can you tell me a short joke?",
)

View file

@ -1,12 +0,0 @@
from base_responses_api import BaseResponsesAPITest
class TestGoogleAIStudioResponsesAPITest(BaseResponsesAPITest):
test_basic_openai_responses_delete_endpoint = None
test_basic_openai_responses_streaming_delete_endpoint = None
test_basic_openai_responses_get_endpoint = None
test_basic_openai_responses_cancel_endpoint = None
def get_base_completion_call_args(self):
# litellm.turn_on_debug()
return {"model": "gemini/gemini-2.5-flash-lite"}

View file

@ -1,64 +0,0 @@
import json
import pytest
from base_responses_api import BaseResponsesAPITest
import litellm
class TestOpenAIResponsesAPITest(BaseResponsesAPITest):
test_responses_api_with_tool_calls = None
def get_base_completion_call_args(self):
return {
"model": "openai/gpt-5.5",
}
def get_advanced_model_for_shell_tool(self):
return "openai/gpt-5.2"
@pytest.mark.asyncio
@pytest.mark.parametrize("sync_mode", [True, False])
async def test_openai_compact_responses_api(sync_mode):
"""
Test the compact_responses API for OpenAI.
This test verifies that the compact_responses endpoint works correctly
for compressing conversation history.
"""
litellm.turn_on_debug()
litellm.set_verbose = True
input_messages = [
{"role": "user", "content": "Hello, how are you?"},
{"role": "assistant", "content": "I'm doing well, thank you for asking!"},
{"role": "user", "content": "What is the weather like today?"},
]
try:
if sync_mode:
response = litellm.compact_responses(
model="openai/gpt-5.5",
input=input_messages,
instructions="Be helpful and concise",
)
else:
response = await litellm.acompact_responses(
model="openai/gpt-5.5",
input=input_messages,
instructions="Be helpful and concise",
)
except litellm.InternalServerError:
pytest.skip("Skipping test due to InternalServerError")
except litellm.BadRequestError as e:
# compact_responses may not be available for all models/accounts
pytest.skip(f"Skipping test due to BadRequestError: {e}")
print("compact_responses response=", json.dumps(response, indent=4, default=str))
# Validate response structure
assert response is not None
assert "id" in response, "Response should have an 'id' field"
assert "output" in response, "Response should have an 'output' field"
assert isinstance(response["output"], list), "Output should be a list"

View file

@ -26,7 +26,6 @@ provider APIs. The reusable conftest plumbing lives in
`tests/_vcr_conftest_common.py` and is wired into:
- `tests/llm_translation/`
- `tests/llm_responses_api_testing/`
- `tests/audio_tests/`
- `tests/batches_tests/`
- `tests/guardrails_tests/`

View file

@ -1564,25 +1564,6 @@ class BaseAnthropicChatTest(ABC):
print(response)
def test_completion_with_thinking_basic(self):
litellm.turn_on_debug()
base_completion_call_args = self.get_base_completion_call_args_with_thinking()
messages = [{"role": "user", "content": "Generate 5 question + answer pairs"}]
response = self.completion_function(
**base_completion_call_args,
messages=messages,
)
print(f"response: {response}")
assert response.choices[0].message.reasoning_content is not None
assert isinstance(response.choices[0].message.reasoning_content, str)
assert response.choices[0].message.thinking_blocks is not None
assert isinstance(response.choices[0].message.thinking_blocks, list)
assert len(response.choices[0].message.thinking_blocks) > 0
assert response.choices[0].message.thinking_blocks[0]["signature"] is not None
def test_anthropic_thinking_output_stream(self):
# litellm.set_verbose = True
try:

View file

@ -1,138 +0,0 @@
import os
import pytest
from websockets.exceptions import ConnectionClosedError, ConnectionClosedOK
import litellm
@pytest.mark.asyncio
@pytest.mark.skipif(
os.environ.get("OPENAI_API_KEY", None) is None,
reason="No OpenAI API key provided",
)
async def test_openai_realtime_direct_call_no_intent():
"""
End-to-end test calling the actual OpenAI realtime endpoint via LiteLLM SDK
without intent parameter. This should succeed without "Invalid intent" error.
Uses real websocket connection to OpenAI.
"""
import asyncio
import json
class RealTimeWebSocketClient:
def __init__(self):
self.messages_sent = []
self.messages_received = []
self.received_session_created = False
self.connection_successful = False
self._receive_called = False
self.close_code = None
self.close_reason = None
async def accept(self):
pass
async def send_text(self, message):
self.messages_sent.append(message)
try:
if isinstance(message, bytes):
message_str = message.decode("utf-8")
else:
message_str = message
msg_data = json.loads(message_str)
msg_type = msg_data.get("type", "unknown")
if msg_type == "error":
error_info = msg_data.get("error", {})
error_code = error_info.get("code", "unknown")
error_message = error_info.get("message", "unknown")
# Don't fail on error, just record it - some errors are expected
self.messages_received.append(msg_data)
return
if msg_type == "session.created" and not self.received_session_created:
self.messages_received.append(msg_data)
self.received_session_created = True
self.connection_successful = True
except (json.JSONDecodeError, UnicodeDecodeError):
# Non-JSON messages are acceptable
pass
async def receive_text(self):
if not self._receive_called:
self._receive_called = True
max_wait = 60.0
check_interval = 0.1
waited = 0.0
while waited < max_wait:
if self.connection_successful:
break
await asyncio.sleep(check_interval)
waited += check_interval
if not self.connection_successful:
await asyncio.sleep(3.0)
raise ConnectionClosedOK(None, None)
async def close(self, code=1000, reason=""):
self.close_code = code
self.close_reason = reason
@property
def headers(self):
return {}
websocket_client = RealTimeWebSocketClient()
caught_exception = None
try:
await litellm._arealtime(
# OpenAI shut down the gpt-4o-realtime-preview family (incl. the
# undated alias) on 2026-05-07; gpt-realtime is the GA successor.
model="openai/gpt-realtime",
websocket=websocket_client,
api_key=os.environ.get("OPENAI_API_KEY"),
timeout=60,
)
except (ConnectionClosedOK, ConnectionClosedError):
pass
except Exception as e:
caught_exception = e
if "invalid_intent" in str(e).lower():
pytest.fail(f"Still getting invalid intent error: {e}")
# Other exceptions are recorded but don't fail immediately
# Build detailed error message for debugging
error_details = []
error_details.append(f"messages_sent count: {len(websocket_client.messages_sent)}")
error_details.append(
f"messages_received count: {len(websocket_client.messages_received)}"
)
error_details.append(f"close_code: {websocket_client.close_code}")
error_details.append(f"close_reason: {websocket_client.close_reason}")
if caught_exception:
error_details.append(
f"exception: {type(caught_exception).__name__}: {caught_exception}"
)
assert (
websocket_client.connection_successful
), f"Failed to establish connection. Debug info: {'; '.join(error_details)}"
assert (
websocket_client.received_session_created
), "Did not receive session.created response"
assert len(websocket_client.messages_received) > 0, "No messages received"
session_message = websocket_client.messages_received[0]
assert (
session_message["type"] == "session.created"
), f"Expected session.created, got {session_message.get('type')}"
assert (
"session" in session_message
), "session.created response missing session object"
assert "id" in session_message["session"], "Session object missing id field"
assert "model" in session_message["session"], "Session object missing model field"

View file

@ -494,34 +494,6 @@ def test_anthropic_citations_api_streaming():
assert has_citations
@pytest.mark.parametrize(
"model",
[
"anthropic/claude-sonnet-4-5-20250929",
"bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
],
)
def test_anthropic_thinking_output(model):
litellm.turn_on_debug()
resp = completion(
model=model,
messages=[{"role": "user", "content": "What is the capital of France?"}],
thinking={"type": "enabled", "budget_tokens": 1024},
)
print(resp)
assert resp.choices[0].message.reasoning_content is not None
assert isinstance(resp.choices[0].message.reasoning_content, str)
assert resp.choices[0].message.thinking_blocks is not None
assert isinstance(resp.choices[0].message.thinking_blocks, list)
assert len(resp.choices[0].message.thinking_blocks) > 0
assert resp.choices[0].message.thinking_blocks[0]["type"] == "thinking"
assert resp.choices[0].message.thinking_blocks[0]["signature"] is not None
@pytest.mark.parametrize(
"model",
[

View file

@ -279,85 +279,6 @@ def test_bedrock_system_prompt(system, model):
pytest.fail(f"Error occurred: {e}")
def test_bedrock_claude_3_tool_calling():
try:
litellm.set_verbose = True
litellm.turn_on_debug()
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
},
},
"required": ["location"],
},
},
}
]
messages = [
{
"role": "user",
"content": "What's the weather like in Boston today in fahrenheit?",
}
]
response: ModelResponse = completion(
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
messages=messages,
tools=tools,
tool_choice="auto",
) # type: ignore
print(f"response: {response}")
# Add any assertions here to check the response
assert isinstance(response.choices[0].message.tool_calls[0].function.name, str)
assert isinstance(
response.choices[0].message.tool_calls[0].function.arguments, str
)
messages.append(
response.choices[0].message.model_dump()
) # Add assistant tool invokes
tool_result = (
'{"location": "Boston", "temperature": "72", "unit": "fahrenheit"}'
)
# Add user submitted tool results in the OpenAI format
messages.append(
{
"tool_call_id": response.choices[0].message.tool_calls[0].id,
"role": "tool",
"name": response.choices[0].message.tool_calls[0].function.name,
"content": tool_result,
}
)
# In the second response, Claude should deduce answer from tool results
second_response = completion(
model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0",
messages=messages,
tools=tools,
tool_choice="auto",
)
print(f"second response: {second_response}")
assert isinstance(second_response.choices[0].message.content, str)
except RateLimitError:
pass
except Exception as e:
pytest.fail(f"Error occurred: {e}")
def test_completion_bedrock_mistral_completion_auth():
print("calling bedrock mistral completion params auth")

View file

@ -2277,56 +2277,3 @@ def test_caching_thinking_args_hit(): # test in memory cache
except Exception as e:
print(f"error occurred: {traceback.format_exc()}")
pytest.fail(f"Error occurred: {e}")
@pytest.mark.asyncio
async def test_cache_key_in_hidden_params_acompletion():
"""
Test that cache_key is present in _hidden_params on cache hits for acompletion.
Validates fix for missing x-litellm-cache-key header on proxy cache hits.
"""
litellm.cache = Cache(
type="redis",
host=os.environ["REDIS_HOST"],
port=os.environ["REDIS_PORT"],
password=os.environ["REDIS_PASSWORD"],
)
unique_content = f"test cache key hidden params {uuid.uuid4()}"
messages = [{"role": "user", "content": unique_content}]
# First call - cache miss
response1 = await litellm.acompletion(
model="gpt-3.5-turbo",
messages=messages,
mock_response="test response",
caching=True,
)
print(f"Response 1 _hidden_params: {response1._hidden_params}")
assert response1._hidden_params.get("cache_hit") is not True
await asyncio.sleep(0.5)
# Second call - cache hit
response2 = await litellm.acompletion(
model="gpt-3.5-turbo",
messages=messages,
mock_response="test response",
caching=True,
)
print(f"Response 2 _hidden_params: {response2._hidden_params}")
# Verify cache hit occurred
assert response2._hidden_params.get("cache_hit") is True
# Verify cache_key is present in _hidden_params
assert "cache_key" in response2._hidden_params
assert response2._hidden_params["cache_key"] is not None
# Verify both responses have same ID (cache hit)
assert response1.id == response2.id
litellm.cache = None

View file

@ -1413,28 +1413,6 @@ def test_replicate_custom_prompt_dict():
# test_completion_together_ai_mixtral()
def test_completion_together_ai_llama():
litellm.set_verbose = True
model_name = "together_ai/meta-llama/Llama-3.3-70B-Instruct-Turbo"
try:
messages = [
{"role": "user", "content": "What llm are you?"},
]
response = completion(model=model_name, messages=messages, max_tokens=5)
# Add any assertions here to check the response
print(response)
cost = completion_cost(completion_response=response)
assert cost > 0.0
print(
"Cost for completion call together-computer/llama-2-70b: ",
f"${float(cost):.10f}",
)
except litellm.Timeout as e:
pass
except Exception as e:
pytest.fail(f"Error occurred: {e}")
# test_completion_together_ai_yi_chat()
@ -1903,25 +1881,6 @@ def test_langfuse_completion(monkeypatch):
)
def test_deepseek_reasoning_content_completion():
try:
litellm.set_verbose = True
litellm.turn_on_debug()
resp = litellm.completion(
timeout=5,
model="deepseek/deepseek-reasoner",
messages=[{"role": "user", "content": "Tell me a joke."}],
)
assert resp.choices[0].message.reasoning_content is not None
except litellm.Timeout:
pytest.skip("Model is timing out")
def test_qwen_text_completion():
# litellm.turn_on_debug()
resp = litellm.completion(

View file

@ -365,54 +365,6 @@ async def test_async_custom_handler_embedding_optional_param():
# asyncio.run(test_async_custom_handler_embedding_optional_param())
@pytest.mark.asyncio
@pytest.mark.flaky(retries=3, delay=1)
async def test_cost_tracking_with_caching():
"""
Important Test - This tests if that cost is 0 for cached responses
"""
from litellm import Cache
litellm.set_verbose = True
litellm.cache = Cache(
type="redis",
host=os.environ["REDIS_HOST"],
port=os.environ["REDIS_PORT"],
password=os.environ["REDIS_PASSWORD"],
)
customHandler_optional_params = MyCustomHandler()
litellm.callbacks = [customHandler_optional_params]
messages = [
{
"role": "user",
"content": f"write a one sentence poem about: {time.time()}",
}
]
response1 = await litellm.acompletion(
model="gpt-3.5-turbo",
messages=messages,
max_tokens=40,
temperature=0.2,
caching=True,
mock_response="Hey, i'm doing well!",
)
await asyncio.sleep(3) # success callback is async
response_cost = customHandler_optional_params.response_cost
assert response_cost > 0
response2 = await litellm.acompletion(
model="gpt-3.5-turbo",
messages=messages,
max_tokens=40,
temperature=0.2,
caching=True,
)
await asyncio.sleep(1) # success callback is async
response_cost_2 = customHandler_optional_params.response_cost
assert response_cost_2 == 0
@pytest.mark.flaky(retries=3, delay=3)
def test_redis_cache_completion_stream():
# Important Test - This tests if we can add to streaming cache, when custom callbacks are set

View file

@ -1,57 +0,0 @@
import io
import litellm
litellm.failure_callback = ["lunary"]
litellm.success_callback = ["lunary"]
litellm.set_verbose = True
def test_lunary_with_tools():
import litellm
messages = [
{
"role": "user",
"content": "What's the weather like in San Francisco, Tokyo, and Paris?",
}
]
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
},
}
]
response = litellm.completion(
model="gpt-6-luna",
messages=messages,
tools=tools,
tool_choice="auto", # auto is default, but we'll be explicit
)
response_message = response.choices[0].message
assert response.choices[0].message.tool_calls
assert all(call.function.name == "get_current_weather" for call in response.choices[0].message.tool_calls)
print("\nLLM Response:\n", response.choices[0].message)

View file

@ -2729,19 +2729,6 @@ def test_completion_openai_engine() -> None:
# test_completion_openai_engine()
def test_completion_chatgpt_prompt():
try:
print("\n gpt3.5 test\n")
response = text_completion(model="openai/gpt-3.5-turbo", prompt="What's the weather in SF?")
print(response)
response_str = response["choices"][0]["text"]
print("\n", response.choices)
print("\n", response.choices[0])
# print(response.choices[0].text)
except Exception as e:
pytest.fail(f"Error occurred: {e}")
# test_completion_chatgpt_prompt()

View file

@ -24,57 +24,6 @@ global.fetch = async function patchedFetch(url, options) {
jest.retryTimes(3);
describe('Gemini AI Tests', () => {
test('should successfully generate non-streaming content with tags', async () => {
const genAI = new GoogleGenerativeAI(masterKey);
const requestOptions = {
baseUrl: 'http://127.0.0.1:4000/gemini',
customHeaders: {
"tags": "gemini-js-sdk,pass-through-endpoint"
}
};
const model = genAI.getGenerativeModel({
model: 'gemini-3.1-flash-lite'
}, requestOptions);
const prompt = 'Say "hello test" and nothing else';
const result = await model.generateContent(prompt);
expect(result).toBeDefined();
// Use the captured callId
const callId = lastCallId;
console.log("Captured Call ID:", callId);
// Poll for spend data with retries (DB writes can be slow in CI)
let spendData = null;
for (let attempt = 0; attempt < 6; attempt++) {
await new Promise(resolve => setTimeout(resolve, 10000));
const spendResponse = await fetch(
`http://127.0.0.1:4000/spend/logs?request_id=${callId}`,
{ headers: { 'Authorization': `Bearer ${masterKey}` } }
);
spendData = await spendResponse.json();
console.log(`spendData (attempt ${attempt + 1}):`, spendData);
if (spendData && spendData.length > 0 && spendData[0] && spendData[0].request_id) break;
}
if (!spendData || !spendData.length || !spendData[0] || !spendData[0].request_id) {
console.warn('Spend data not available after polling - skipping spend assertions (DB write may be slow in CI)');
return;
}
expect(spendData).toBeDefined();
expect(spendData[0].request_id).toBe(callId);
expect(spendData[0].call_type).toBe('pass_through_endpoint');
expect(spendData[0].request_tags).toEqual(['gemini-js-sdk', 'pass-through-endpoint']);
expect(spendData[0].metadata).toHaveProperty('user_api_key');
expect(spendData[0].model).toContain('gemini');
expect(spendData[0].custom_llm_provider).toBe('gemini');
expect(spendData[0].spend).toBeGreaterThan(0);
}, 90000);
test('should successfully generate streaming content with tags', async () => {
const genAI = new GoogleGenerativeAI(masterKey);

View file

@ -1,13 +1,9 @@
import json
import os
from datetime import datetime
from typing import Dict, Any
import asyncio
import unittest.mock
from unittest.mock import MagicMock
import litellm
import pytest
from dotenv import load_dotenv
from litellm.llms.anthropic.pass_through.messages.handler import (
anthropic_messages,
@ -16,47 +12,12 @@ from litellm.llms.anthropic.pass_through.messages.handler import (
from typing import Optional
from litellm.types.utils import StandardLoggingPayload
from litellm.integrations.custom_logger import CustomLogger
from litellm.router import Router
import importlib
from base_anthropic_unified_messages_test import BaseAnthropicMessagesTest
# Load environment variables
load_dotenv()
@pytest.fixture(scope="session")
def event_loop():
"""Create an instance of the default event loop for each test session."""
loop = asyncio.get_event_loop_policy().new_event_loop()
yield loop
loop.close()
@pytest.fixture(scope="function", autouse=True)
def setup_and_teardown(event_loop): # Add event_loop as a dependency
curr_dir = os.getcwd()
import litellm
from litellm import Router
importlib.reload(litellm)
# Set the event loop from the fixture
asyncio.set_event_loop(event_loop)
print(litellm)
yield
# Clean up any pending tasks
pending = asyncio.all_tasks(event_loop)
for task in pending:
task.cancel()
# Run the event loop until all tasks are cancelled
if pending:
event_loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
def _validate_anthropic_response(response: Dict[str, Any]):
assert "id" in response
assert "content" in response
@ -117,42 +78,3 @@ class TestAnthropicOpenAIAPI(BaseAnthropicMessagesTest):
This is the model name that is expected to be in the logging payload
"""
return "gpt-4.1-mini"
@pytest.mark.asyncio
async def test_anthropic_messages_litellm_router_non_streaming():
"""
Test the anthropic_messages with non-streaming request
"""
litellm.turn_on_debug()
router = Router(
model_list=[
{
"model_name": "claude-special-alias",
"litellm_params": {
"model": "claude-haiku-4-5-20251001",
"api_key": os.getenv("ANTHROPIC_API_KEY"),
},
}
]
)
# Set up test parameters
messages = [{"role": "user", "content": "Hello, can you tell me a short joke?"}]
# Call the handler
response = await router.aanthropic_messages(
messages=messages,
model="claude-special-alias",
max_tokens=100,
)
# Verify response
assert "id" in response
assert "content" in response
assert "model" in response
assert response["role"] == "assistant"
print(f"Non-streaming response: {json.dumps(response, indent=2)}")
return response

View file

@ -109,16 +109,6 @@ async def new_budget(session, i, budget_id=None):
print()
@pytest.mark.asyncio
async def test_end_user_new():
"""
Make 20 parallel calls to /user/new. Assert all worked.
"""
async with aiohttp.ClientSession() as session:
tasks = [new_end_user(session, i, str(uuid.uuid4())) for i in range(1, 11)]
await asyncio.gather(*tasks)
@pytest.mark.asyncio
async def test_enduser_tpm_limits_non_master_key():
"""

View file

@ -183,33 +183,6 @@ async def chat_completion(session, key, model="gpt-4"):
pass
async def chat_completion_streaming(session, key, model="gpt-4"):
client = AsyncOpenAI(api_key=key, base_url="http://0.0.0.0:4000")
messages = [
{"role": "system", "content": "You are a helpful assistant"},
{"role": "user", "content": "Hello!"},
]
prompt_tokens = litellm.token_counter(model="gpt-35-turbo", messages=messages)
data = {
"model": model,
"messages": messages,
"stream": True,
}
response = await client.chat.completions.create(**data)
content = ""
async for chunk in response:
content += chunk.choices[0].delta.content or ""
print(f"content: {content}")
completion_tokens = litellm.token_counter(
model="gpt-35-turbo", text=content, count_response_tokens=True
)
return prompt_tokens, completion_tokens
async def delete_key(session, get_key, auth_key=os.environ["LITELLM_MASTER_KEY"]):
"""
Delete key
@ -367,47 +340,6 @@ async def get_spend_logs(session, request_id):
return await response.json()
@pytest.mark.asyncio
@pytest.mark.flaky(retries=6, delay=2)
@pytest.mark.skip(
reason="Temporarily skipping due to model change. Will be updated soon."
)
async def test_aaaaakey_info_spend_values_streaming():
"""
Test to ensure spend is correctly calculated.
- create key
- make completion call
- assert cost is expected value
"""
async with aiohttp.ClientSession() as session:
## streaming - azure
key_gen = await generate_key(session=session, i=0)
new_key = key_gen["key"]
prompt_tokens, completion_tokens = await chat_completion_streaming(
session=session, key=new_key
)
print(f"prompt_tokens: {prompt_tokens}, completion_tokens: {completion_tokens}")
prompt_cost, completion_cost = litellm.cost_per_token(
model="azure/gpt-4o",
prompt_tokens=prompt_tokens,
completion_tokens=completion_tokens,
)
response_cost = prompt_cost + completion_cost
await asyncio.sleep(8) # allow db log to be updated
print(f"new_key: {new_key}")
key_info = await get_key_info(
session=session, get_key=new_key, call_key=new_key
)
print(
f"response_cost: {response_cost}; key_info spend: {key_info['info']['spend']}"
)
rounded_response_cost = round(response_cost, 8)
rounded_key_info_spend = round(key_info["info"]["spend"], 8)
assert (
rounded_response_cost == rounded_key_info_spend
), f"Expected={rounded_response_cost}, Got={rounded_key_info_spend}"
@pytest.mark.skip(reason="Frequent check on ci/cd leads to read timeout issue.")
@pytest.mark.asyncio
async def test_key_with_budgets():

View file

@ -13,82 +13,6 @@ import litellm
from litellm.proxy._types import UserAPIKeyAuth
@pytest.mark.asyncio
async def test_vector_store_retrieve_basic():
"""Test basic vector store retrieve functionality."""
mock_response = {
"id": "vs_test123",
"object": "vector_store",
"created_at": 1699061776,
"name": "Test Vector Store",
"file_counts": {
"in_progress": 0,
"completed": 5,
"failed": 0,
"cancelled": 0,
"total": 5,
},
"status": "completed",
"usage_bytes": 12345,
}
with patch(
"litellm.vector_stores.main.aretrieve",
new=AsyncMock(return_value=mock_response),
) as mock_retrieve:
router = litellm.Router(model_list=[])
result = await router.avector_store_retrieve(
vector_store_id="vs_test123",
custom_llm_provider="openai",
)
assert result["id"] == "vs_test123"
assert result["object"] == "vector_store"
assert result["status"] == "completed"
mock_retrieve.assert_called_once()
@pytest.mark.asyncio
async def test_vector_store_list_basic():
"""Test basic vector store list functionality."""
mock_response = {
"object": "list",
"data": [
{
"id": "vs_test1",
"object": "vector_store",
"created_at": 1699061776,
"name": "Store 1",
},
{
"id": "vs_test2",
"object": "vector_store",
"created_at": 1699061777,
"name": "Store 2",
},
],
"first_id": "vs_test1",
"last_id": "vs_test2",
"has_more": False,
}
with patch(
"litellm.vector_stores.main.alist",
new=AsyncMock(return_value=mock_response),
) as mock_list:
router = litellm.Router(model_list=[])
result = await router.avector_store_list(
limit=20,
order="desc",
custom_llm_provider="openai",
)
assert result["object"] == "list"
assert len(result["data"]) == 2
assert result["data"][0]["id"] == "vs_test1"
mock_list.assert_called_once()
@pytest.mark.asyncio
async def test_vector_store_update_basic():
"""Test basic vector store update functionality."""
@ -119,76 +43,6 @@ async def test_vector_store_update_basic():
mock_update.assert_called_once()
@pytest.mark.asyncio
async def test_vector_store_delete_basic():
"""Test basic vector store delete functionality."""
mock_response = {
"id": "vs_test123",
"object": "vector_store.deleted",
"deleted": True,
}
with patch(
"litellm.vector_stores.main.adelete",
new=AsyncMock(return_value=mock_response),
) as mock_delete:
router = litellm.Router(model_list=[])
result = await router.avector_store_delete(
vector_store_id="vs_test123",
custom_llm_provider="openai",
)
assert result["id"] == "vs_test123"
assert result["deleted"] is True
assert result["object"] == "vector_store.deleted"
mock_delete.assert_called_once()
@pytest.mark.asyncio
async def test_async_vector_store_retrieve():
"""Test async vector store retrieve."""
mock_response = {
"id": "vs_async123",
"object": "vector_store",
"name": "Async Test Store",
}
with patch(
"litellm.vector_stores.main.aretrieve",
new=AsyncMock(return_value=mock_response),
) as mock_aretrieve:
router = litellm.Router(model_list=[])
result = await router.avector_store_retrieve(
vector_store_id="vs_async123",
custom_llm_provider="openai",
)
assert result["id"] == "vs_async123"
mock_aretrieve.assert_called_once()
@pytest.mark.asyncio
async def test_async_vector_store_list():
"""Test async vector store list."""
mock_response = {
"object": "list",
"data": [{"id": "vs_1"}, {"id": "vs_2"}],
}
with patch(
"litellm.vector_stores.main.alist",
new=AsyncMock(return_value=mock_response),
) as mock_alist:
router = litellm.Router(model_list=[])
result = await router.avector_store_list(
limit=10,
custom_llm_provider="openai",
)
assert len(result["data"]) == 2
mock_alist.assert_called_once()
@pytest.mark.asyncio
async def test_async_vector_store_update():
"""Test async vector store update."""
@ -212,28 +66,6 @@ async def test_async_vector_store_update():
mock_aupdate.assert_called_once()
@pytest.mark.asyncio
async def test_async_vector_store_delete():
"""Test async vector store delete."""
mock_response = {
"id": "vs_async123",
"deleted": True,
}
with patch(
"litellm.vector_stores.main.adelete",
new=AsyncMock(return_value=mock_response),
) as mock_adelete:
router = litellm.Router(model_list=[])
result = await router.avector_store_delete(
vector_store_id="vs_async123",
custom_llm_provider="openai",
)
assert result["deleted"] is True
mock_adelete.assert_called_once()
@pytest.mark.asyncio
async def test_vector_store_list_with_pagination():
"""Test vector store list with pagination parameters."""
@ -335,18 +167,12 @@ if __name__ == "__main__":
# Test basic sync operations
print("✓ Testing basic sync operations...")
asyncio.run(test_vector_store_retrieve_basic())
asyncio.run(test_vector_store_list_basic())
asyncio.run(test_vector_store_update_basic())
asyncio.run(test_vector_store_delete_basic())
print("✓ Basic sync operations successful")
# Test async operations
print("✓ Testing async operations...")
asyncio.run(test_async_vector_store_retrieve())
asyncio.run(test_async_vector_store_list())
asyncio.run(test_async_vector_store_update())
asyncio.run(test_async_vector_store_delete())
print("✓ Async operations successful")
print("\n✅ All smoke tests passed!")

View file

@ -99,18 +99,6 @@ def verify_member_in_team(team_info: Dict, user_email: str) -> bool:
)
def test_team_creation(api_client):
"""Test team creation"""
team_alias = f"Test Team {uuid.uuid4().hex[:6]}"
team_response, team_id = api_client.create_team(team_alias)
# Verify team was created
team_info = api_client.get_team_info(team_id)
assert team_info["team_id"] == team_id
assert team_info["team_info"]["team_alias"] == team_alias
assert "o3-mini" in team_info["team_info"]["models"]
def test_add_single_member(api_client, new_team):
"""Test adding a single member to a new team"""
# Get initial team info