diff --git a/litellm/__init__.py b/litellm/__init__.py index e42bfbf031..017bd46acb 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -570,6 +570,7 @@ from .utils import ( _calculate_retry_after, _should_retry, get_secret, + get_mapped_model_params, ) from .llms.huggingface_restapi import HuggingfaceConfig from .llms.anthropic import AnthropicConfig @@ -592,6 +593,7 @@ from .llms.bedrock import ( AmazonTitanConfig, AmazonAI21Config, AmazonAnthropicConfig, + AmazonAnthropicClaude3Config, AmazonCohereConfig, AmazonLlamaConfig, AmazonStabilityConfig, diff --git a/litellm/llms/bedrock.py b/litellm/llms/bedrock.py index 1a25e167a9..79ba04f42e 100644 --- a/litellm/llms/bedrock.py +++ b/litellm/llms/bedrock.py @@ -1,11 +1,17 @@ import json, copy, types import os from enum import Enum -import time +import time, uuid from typing import Callable, Optional, Any, Union, List import litellm from litellm.utils import ModelResponse, get_secret, Usage, ImageResponse -from .prompt_templates.factory import prompt_factory, custom_prompt +from .prompt_templates.factory import ( + prompt_factory, + custom_prompt, + construct_tool_use_system_prompt, + extract_between_tags, + parse_xml_params, +) import httpx @@ -70,6 +76,59 @@ class AmazonTitanConfig: } +class AmazonAnthropicClaude3Config: + """ + Reference: https://us-west-2.console.aws.amazon.com/bedrock/home?region=us-west-2#/providers?model=claude + + Supported Params for the Amazon / Anthropic Claude 3 models: + + - `max_tokens` (integer) max tokens, + - `anthropic_version` (string) version of anthropic for bedrock - e.g. "bedrock-2023-05-31" + """ + + max_tokens: Optional[int] = litellm.max_tokens + anthropic_version: Optional[str] = "bedrock-2023-05-31" + + def __init__( + self, + max_tokens: Optional[int] = None, + anthropic_version: Optional[str] = None, + ) -> None: + locals_ = locals() + for key, value in locals_.items(): + if key != "self" and value is not None: + setattr(self.__class__, key, value) + + @classmethod + def get_config(cls): + return { + k: v + for k, v in cls.__dict__.items() + if not k.startswith("__") + and not isinstance( + v, + ( + types.FunctionType, + types.BuiltinFunctionType, + classmethod, + staticmethod, + ), + ) + and v is not None + } + + def get_supported_openai_params(self): + return ["max_tokens", "tools", "tool_choice", "stream"] + + def map_openai_params(self, non_default_params: dict, optional_params: dict): + for param, value in non_default_params.items(): + if param == "max_tokens": + optional_params["max_tokens"] = value + if param == "tools": + optional_params["tools"] = value + return optional_params + + class AmazonAnthropicConfig: """ Reference: https://us-west-2.console.aws.amazon.com/bedrock/home?region=us-west-2#/providers?model=claude @@ -123,6 +182,25 @@ class AmazonAnthropicConfig: and v is not None } + def get_supported_openai_params( + self, + ): + return ["max_tokens", "temperature", "stop", "top_p", "stream"] + + def map_openai_params(self, non_default_params: dict, optional_params: dict): + for param, value in non_default_params.items(): + if param == "max_tokens": + optional_params["max_tokens_to_sample"] = value + if param == "temperature": + optional_params["temperature"] = value + if param == "top_p": + optional_params["top_p"] = value + if param == "stop": + optional_params["stop_sequences"] = value + if param == "stream" and value == True: + optional_params["stream"] = value + return optional_params + class AmazonCohereConfig: """ @@ -330,7 +408,8 @@ class AmazonMistralConfig: ) and v is not None } - + + class AmazonStabilityConfig: """ Reference: https://us-west-2.console.aws.amazon.com/bedrock/home?region=us-west-2#/providers?model=stability.stable-diffusion-xl-v0 @@ -542,7 +621,9 @@ def convert_messages_to_prompt(model, messages, provider, custom_prompt_dict): model=model, messages=messages, custom_llm_provider="bedrock" ) elif provider == "mistral": - prompt = prompt_factory(model=model, messages=messages, custom_llm_provider="bedrock") + prompt = prompt_factory( + model=model, messages=messages, custom_llm_provider="bedrock" + ) else: prompt = "" for message in messages: @@ -619,14 +700,47 @@ def completion( inference_params = copy.deepcopy(optional_params) stream = inference_params.pop("stream", False) if provider == "anthropic": - ## LOAD CONFIG - config = litellm.AmazonAnthropicConfig.get_config() - for k, v in config.items(): - if ( - k not in inference_params - ): # completion(top_k=3) > anthropic_config(top_k=3) <- allows for dynamic variables to be passed in - inference_params[k] = v - data = json.dumps({"prompt": prompt, **inference_params}) + if model.startswith("anthropic.claude-3"): + # Separate system prompt from rest of message + system_prompt_idx: Optional[int] = None + for idx, message in enumerate(messages): + if message["role"] == "system": + inference_params["system"] = message["content"] + system_prompt_idx = idx + break + if system_prompt_idx is not None: + messages.pop(system_prompt_idx) + # Format rest of message according to anthropic guidelines + messages = prompt_factory( + model=model, messages=messages, custom_llm_provider="anthropic" + ) + ## LOAD CONFIG + config = litellm.AmazonAnthropicClaude3Config.get_config() + for k, v in config.items(): + if ( + k not in inference_params + ): # completion(top_k=3) > anthropic_config(top_k=3) <- allows for dynamic variables to be passed in + inference_params[k] = v + ## Handle Tool Calling + if "tools" in inference_params: + tool_calling_system_prompt = construct_tool_use_system_prompt( + tools=inference_params["tools"] + ) + inference_params["system"] = ( + inference_params.get("system", "\n") + + tool_calling_system_prompt + ) # add the anthropic tool calling prompt to the system prompt + inference_params.pop("tools") + data = json.dumps({"messages": messages, **inference_params}) + else: + ## LOAD CONFIG + config = litellm.AmazonAnthropicConfig.get_config() + for k, v in config.items(): + if ( + k not in inference_params + ): # completion(top_k=3) > anthropic_config(top_k=3) <- allows for dynamic variables to be passed in + inference_params[k] = v + data = json.dumps({"prompt": prompt, **inference_params}) elif provider == "ai21": ## LOAD CONFIG config = litellm.AmazonAI21Config.get_config() @@ -646,9 +760,9 @@ def completion( ): # completion(top_k=3) > anthropic_config(top_k=3) <- allows for dynamic variables to be passed in inference_params[k] = v if optional_params.get("stream", False) == True: - inference_params[ - "stream" - ] = True # cohere requires stream = True in inference params + inference_params["stream"] = ( + True # cohere requires stream = True in inference params + ) data = json.dumps({"prompt": prompt, **inference_params}) elif provider == "meta": ## LOAD CONFIG @@ -674,7 +788,7 @@ def completion( "textGenerationConfig": inference_params, } ) - elif provider == "mistral": + elif provider == "mistral": ## LOAD CONFIG config = litellm.AmazonMistralConfig.get_config() for k, v in config.items(): @@ -783,8 +897,42 @@ def completion( if provider == "ai21": outputText = response_body.get("completions")[0].get("data").get("text") elif provider == "anthropic": - outputText = response_body["completion"] - model_response["finish_reason"] = response_body["stop_reason"] + if model.startswith("anthropic.claude-3"): + outputText = response_body.get("content")[0].get("text", None) + if "" in outputText: # OUTPUT PARSE FUNCTION CALL + function_name = extract_between_tags("tool_name", outputText)[0] + function_arguments_str = extract_between_tags("invoke", outputText)[ + 0 + ].strip() + function_arguments_str = ( + f"{function_arguments_str}" + ) + function_arguments = parse_xml_params(function_arguments_str) + _message = litellm.Message( + tool_calls=[ + { + "id": f"call_{uuid.uuid4()}", + "type": "function", + "function": { + "name": function_name, + "arguments": json.dumps(function_arguments), + }, + } + ], + content=None, + ) + model_response.choices[0].message = _message # type: ignore + model_response["finish_reason"] = response_body["stop_reason"] + _usage = litellm.Usage( + prompt_tokens=response_body["usage"]["input_tokens"], + completion_tokens=response_body["usage"]["output_tokens"], + total_tokens=response_body["usage"]["input_tokens"] + + response_body["usage"]["output_tokens"], + ) + model_response.usage = _usage + else: + outputText = response_body["completion"] + model_response["finish_reason"] = response_body["stop_reason"] elif provider == "cohere": outputText = response_body["generations"][0]["text"] elif provider == "meta": @@ -803,8 +951,19 @@ def completion( ) else: try: - if len(outputText) > 0: + if ( + len(outputText) > 0 + and hasattr(model_response.choices[0], "message") + and getattr(model_response.choices[0].message, "tool_calls", None) + is None + ): model_response["choices"][0]["message"]["content"] = outputText + elif ( + hasattr(model_response.choices[0], "message") + and getattr(model_response.choices[0].message, "tool_calls", None) + is not None + ): + pass else: raise Exception() except: @@ -814,26 +973,28 @@ def completion( ) ## CALCULATING USAGE - baseten charges on time, not tokens - have some mapping of cost here. - prompt_tokens = response_metadata.get( - "x-amzn-bedrock-input-token-count", len(encoding.encode(prompt)) - ) - completion_tokens = response_metadata.get( - "x-amzn-bedrock-output-token-count", - len( - encoding.encode( - model_response["choices"][0]["message"].get("content", "") - ) - ), - ) + if getattr(model_response.usage, "total_tokens", None) is None: + prompt_tokens = response_metadata.get( + "x-amzn-bedrock-input-token-count", len(encoding.encode(prompt)) + ) + completion_tokens = response_metadata.get( + "x-amzn-bedrock-output-token-count", + len( + encoding.encode( + model_response["choices"][0]["message"].get("content", "") + ) + ), + ) + usage = Usage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=prompt_tokens + completion_tokens, + ) + model_response.usage = usage model_response["created"] = int(time.time()) model_response["model"] = model - usage = Usage( - prompt_tokens=prompt_tokens, - completion_tokens=completion_tokens, - total_tokens=prompt_tokens + completion_tokens, - ) - model_response.usage = usage + model_response._hidden_params["region_name"] = client.meta.region_name print_verbose(f"model_response._hidden_params: {model_response._hidden_params}") return model_response @@ -1118,4 +1279,4 @@ def image_generation( image_dict = {"url": artifact["base64"]} model_response.data = image_dict - return model_response \ No newline at end of file + return model_response diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 23afaf04d6..111b9f8c3c 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -1266,6 +1266,15 @@ "litellm_provider": "bedrock", "mode": "completion" }, + "anthropic.claude-3-sonnet-20240229-v1:0": { + "max_tokens": 200000, + "max_input_tokens": 200000, + "max_output_tokens": 4096, + "input_cost_per_token": 0.000003, + "output_cost_per_token": 0.000015, + "litellm_provider": "bedrock", + "mode": "chat" + }, "anthropic.claude-v1": { "max_tokens": 100000, "max_output_tokens": 8191, diff --git a/litellm/proxy/proxy_cli.py b/litellm/proxy/proxy_cli.py index f6034cba3a..f7eba02ecb 100644 --- a/litellm/proxy/proxy_cli.py +++ b/litellm/proxy/proxy_cli.py @@ -19,6 +19,8 @@ telemetry = None def append_query_params(url, params): + print(f"url: {url}") + print(f"params: {params}") parsed_url = urlparse.urlparse(url) parsed_query = urlparse.parse_qs(parsed_url.query) parsed_query.update(params) diff --git a/litellm/tests/log.txt b/litellm/tests/log.txt new file mode 100644 index 0000000000..7b53823b0f --- /dev/null +++ b/litellm/tests/log.txt @@ -0,0 +1,118 @@ +============================= test session starts ============================== +platform darwin -- Python 3.11.6, pytest-7.3.1, pluggy-1.3.0 +rootdir: /Users/krrishdholakia/Documents/litellm/litellm/tests +plugins: timeout-2.2.0, asyncio-0.23.2, anyio-3.7.1, xdist-3.3.1 +asyncio: mode=Mode.STRICT +collected 1 item + +test_custom_callback_input.py . [100%] + +=============================== warnings summary =============================== +../../../../../../opt/homebrew/lib/python3.11/site-packages/pydantic/_internal/_config.py:271 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pydantic/_internal/_config.py:271 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pydantic/_internal/_config.py:271 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pydantic/_internal/_config.py:271 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pydantic/_internal/_config.py:271 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pydantic/_internal/_config.py:271 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pydantic/_internal/_config.py:271 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pydantic/_internal/_config.py:271 + /opt/homebrew/lib/python3.11/site-packages/pydantic/_internal/_config.py:271: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ + warnings.warn(DEPRECATION_MESSAGE, DeprecationWarning) + +../proxy/_types.py:99 + /Users/krrishdholakia/Documents/litellm/litellm/proxy/_types.py:99: PydanticDeprecatedSince20: `pydantic.config.Extra` is deprecated, use literal values instead (e.g. `extra='allow'`). Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ + extra = Extra.allow # Allow extra fields + +../proxy/_types.py:102 + /Users/krrishdholakia/Documents/litellm/litellm/proxy/_types.py:102: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ + @root_validator(pre=True) + +../proxy/_types.py:131 + /Users/krrishdholakia/Documents/litellm/litellm/proxy/_types.py:131: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ + @root_validator(pre=True) + +../proxy/_types.py:177 + /Users/krrishdholakia/Documents/litellm/litellm/proxy/_types.py:177: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ + @root_validator(pre=True) + +../proxy/_types.py:232 + /Users/krrishdholakia/Documents/litellm/litellm/proxy/_types.py:232: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ + @root_validator(pre=True) + +../proxy/_types.py:244 + /Users/krrishdholakia/Documents/litellm/litellm/proxy/_types.py:244: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ + @root_validator(pre=True) + +../proxy/_types.py:279 + /Users/krrishdholakia/Documents/litellm/litellm/proxy/_types.py:279: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ + @root_validator(pre=True) + +../proxy/_types.py:305 + /Users/krrishdholakia/Documents/litellm/litellm/proxy/_types.py:305: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ + @root_validator(pre=True) + +../../../../../../opt/homebrew/lib/python3.11/site-packages/pydantic/_internal/_fields.py:149 + /opt/homebrew/lib/python3.11/site-packages/pydantic/_internal/_fields.py:149: UserWarning: Field "model_max_budget" has conflict with protected namespace "model_". + + You may be able to resolve this warning by setting `model_config['protected_namespaces'] = ()`. + warnings.warn( + +../proxy/_types.py:553 + /Users/krrishdholakia/Documents/litellm/litellm/proxy/_types.py:553: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ + @root_validator(pre=True) + +../proxy/_types.py:574 + /Users/krrishdholakia/Documents/litellm/litellm/proxy/_types.py:574: PydanticDeprecatedSince20: Pydantic V1 style `@root_validator` validators are deprecated. You should migrate to Pydantic V2 style `@model_validator` validators, see the migration guide for more details. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ + @root_validator(pre=True) + +../utils.py:36 + /Users/krrishdholakia/Documents/litellm/litellm/utils.py:36: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html + import pkg_resources + +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871: 10 warnings + /opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('google')`. + Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages + declare_namespace(pkg) + +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871 + /opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('google.cloud')`. + Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages + declare_namespace(pkg) + +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2350 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2350 +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2350 + /opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2350: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('google')`. + Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages + declare_namespace(parent) + +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871 + /opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('google.logging')`. + Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages + declare_namespace(pkg) + +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871 + /opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('google.iam')`. + Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages + declare_namespace(pkg) + +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871 + /opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('mpl_toolkits')`. + Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages + declare_namespace(pkg) + +../../../../../../opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871 + /opt/homebrew/lib/python3.11/site-packages/pkg_resources/__init__.py:2871: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('sphinxcontrib')`. + Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages + declare_namespace(pkg) + +../llms/prompt_templates/factory.py:6 + /Users/krrishdholakia/Documents/litellm/litellm/llms/prompt_templates/factory.py:6: DeprecationWarning: 'imghdr' is deprecated and slated for removal in Python 3.13 + import imghdr, base64 + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +======================= 1 passed, 43 warnings in 13.05s ======================== diff --git a/litellm/tests/test_amazing_s3_logs.py b/litellm/tests/test_amazing_s3_logs.py index 74d6eb5b94..0ccc0bc15c 100644 --- a/litellm/tests/test_amazing_s3_logs.py +++ b/litellm/tests/test_amazing_s3_logs.py @@ -1,4 +1,4 @@ -## @pytest.mark.skip(reason="AWS Suspended Account") +# # @pytest.mark.skip(reason="AWS Suspended Account") # import sys # import os # import io, asyncio diff --git a/litellm/tests/test_bedrock_completion.py b/litellm/tests/test_bedrock_completion.py index 3e3d8b6bbc..8284b05158 100644 --- a/litellm/tests/test_bedrock_completion.py +++ b/litellm/tests/test_bedrock_completion.py @@ -1,293 +1,401 @@ # @pytest.mark.skip(reason="AWS Suspended Account") -# import sys, os -# import traceback -# from dotenv import load_dotenv -# -# load_dotenv() -# import os, io -# -# sys.path.insert( -# 0, os.path.abspath("../..") -# ) # Adds the parent directory to the system path -# import pytest -# import litellm -# from litellm import embedding, completion, completion_cost, Timeout, ModelResponse -# from litellm import RateLimitError -# -# # litellm.num_retries = 3 -# litellm.cache = None -# litellm.success_callback = [] -# user_message = "Write a short poem about the sky" -# messages = [{"content": user_message, "role": "user"}] -# -# -# @pytest.fixture(autouse=True) -# def reset_callbacks(): -# print("\npytest fixture - resetting callbacks") -# litellm.success_callback = [] -# litellm._async_success_callback = [] -# litellm.failure_callback = [] -# litellm.callbacks = [] +import sys, os +import traceback +from dotenv import load_dotenv + +load_dotenv() +import os, io + +sys.path.insert( + 0, os.path.abspath("../..") +) # Adds the parent directory to the system path +import pytest +import litellm +from litellm import embedding, completion, completion_cost, Timeout, ModelResponse +from litellm import RateLimitError + +# litellm.num_retries = 3 +litellm.cache = None +litellm.success_callback = [] +user_message = "Write a short poem about the sky" +messages = [{"content": user_message, "role": "user"}] -# def test_completion_bedrock_claude_completion_auth(): -# print("calling bedrock claude completion params auth") -# import os - -# 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_NAME"] - -# os.environ.pop("AWS_ACCESS_KEY_ID", None) -# os.environ.pop("AWS_SECRET_ACCESS_KEY", None) -# os.environ.pop("AWS_REGION_NAME", None) - -# try: -# response = completion( -# model="bedrock/anthropic.claude-instant-v1", -# messages=messages, -# max_tokens=10, -# temperature=0.1, -# aws_access_key_id=aws_access_key_id, -# aws_secret_access_key=aws_secret_access_key, -# aws_region_name=aws_region_name, -# ) -# # Add any assertions here to check the response -# print(response) - -# os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id -# os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key -# os.environ["AWS_REGION_NAME"] = aws_region_name -# except RateLimitError: -# pass -# except Exception as e: -# pytest.fail(f"Error occurred: {e}") +@pytest.fixture(autouse=True) +def reset_callbacks(): + print("\npytest fixture - resetting callbacks") + litellm.success_callback = [] + litellm._async_success_callback = [] + litellm.failure_callback = [] + litellm.callbacks = [] -# # test_completion_bedrock_claude_completion_auth() +def test_completion_bedrock_claude_completion_auth(): + print("calling bedrock claude completion params auth") + import os + + 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_NAME"] + + os.environ.pop("AWS_ACCESS_KEY_ID", None) + os.environ.pop("AWS_SECRET_ACCESS_KEY", None) + os.environ.pop("AWS_REGION_NAME", None) + + try: + response = completion( + model="bedrock/anthropic.claude-instant-v1", + messages=messages, + max_tokens=10, + temperature=0.1, + aws_access_key_id=aws_access_key_id, + aws_secret_access_key=aws_secret_access_key, + aws_region_name=aws_region_name, + ) + # Add any assertions here to check the response + print(response) + + os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id + os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key + os.environ["AWS_REGION_NAME"] = aws_region_name + except RateLimitError: + pass + except Exception as e: + pytest.fail(f"Error occurred: {e}") -# def test_completion_bedrock_claude_2_1_completion_auth(): -# print("calling bedrock claude 2.1 completion params auth") -# import os - -# 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_NAME"] - -# os.environ.pop("AWS_ACCESS_KEY_ID", None) -# os.environ.pop("AWS_SECRET_ACCESS_KEY", None) -# os.environ.pop("AWS_REGION_NAME", None) -# try: -# response = completion( -# model="bedrock/anthropic.claude-v2:1", -# messages=messages, -# max_tokens=10, -# temperature=0.1, -# aws_access_key_id=aws_access_key_id, -# aws_secret_access_key=aws_secret_access_key, -# aws_region_name=aws_region_name, -# ) -# # Add any assertions here to check the response -# print(response) - -# os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id -# os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key -# os.environ["AWS_REGION_NAME"] = aws_region_name -# except RateLimitError: -# pass -# except Exception as e: -# pytest.fail(f"Error occurred: {e}") +# test_completion_bedrock_claude_completion_auth() -# # test_completion_bedrock_claude_2_1_completion_auth() +def test_completion_bedrock_claude_2_1_completion_auth(): + print("calling bedrock claude 2.1 completion params auth") + import os + + 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_NAME"] + + os.environ.pop("AWS_ACCESS_KEY_ID", None) + os.environ.pop("AWS_SECRET_ACCESS_KEY", None) + os.environ.pop("AWS_REGION_NAME", None) + try: + response = completion( + model="bedrock/anthropic.claude-v2:1", + messages=messages, + max_tokens=10, + temperature=0.1, + aws_access_key_id=aws_access_key_id, + aws_secret_access_key=aws_secret_access_key, + aws_region_name=aws_region_name, + ) + # Add any assertions here to check the response + print(response) + + os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id + os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key + os.environ["AWS_REGION_NAME"] = aws_region_name + except RateLimitError: + pass + except Exception as e: + pytest.fail(f"Error occurred: {e}") -# def test_completion_bedrock_claude_external_client_auth(): -# print("\ncalling bedrock claude external client auth") -# import os - -# 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_NAME"] - -# os.environ.pop("AWS_ACCESS_KEY_ID", None) -# os.environ.pop("AWS_SECRET_ACCESS_KEY", None) -# os.environ.pop("AWS_REGION_NAME", None) - -# try: -# import boto3 - -# litellm.set_verbose = True - -# bedrock = boto3.client( -# service_name="bedrock-runtime", -# region_name=aws_region_name, -# aws_access_key_id=aws_access_key_id, -# aws_secret_access_key=aws_secret_access_key, -# endpoint_url=f"https://bedrock-runtime.{aws_region_name}.amazonaws.com", -# ) - -# response = completion( -# model="bedrock/anthropic.claude-instant-v1", -# messages=messages, -# max_tokens=10, -# temperature=0.1, -# aws_bedrock_client=bedrock, -# ) -# # Add any assertions here to check the response -# print(response) - -# os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id -# os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key -# os.environ["AWS_REGION_NAME"] = aws_region_name -# except RateLimitError: -# pass -# except Exception as e: -# pytest.fail(f"Error occurred: {e}") +# test_completion_bedrock_claude_2_1_completion_auth() -# # test_completion_bedrock_claude_external_client_auth() +def test_completion_bedrock_claude_external_client_auth(): + print("\ncalling bedrock claude external client auth") + import os + + 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_NAME"] + + os.environ.pop("AWS_ACCESS_KEY_ID", None) + os.environ.pop("AWS_SECRET_ACCESS_KEY", None) + os.environ.pop("AWS_REGION_NAME", None) + + try: + import boto3 + + litellm.set_verbose = True + + bedrock = boto3.client( + service_name="bedrock-runtime", + region_name=aws_region_name, + aws_access_key_id=aws_access_key_id, + aws_secret_access_key=aws_secret_access_key, + endpoint_url=f"https://bedrock-runtime.{aws_region_name}.amazonaws.com", + ) + + response = completion( + model="bedrock/anthropic.claude-instant-v1", + messages=messages, + max_tokens=10, + temperature=0.1, + aws_bedrock_client=bedrock, + ) + # Add any assertions here to check the response + print(response) + + os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id + os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key + os.environ["AWS_REGION_NAME"] = aws_region_name + except RateLimitError: + pass + except Exception as e: + pytest.fail(f"Error occurred: {e}") -# @pytest.mark.skip(reason="Expired token, need to renew") -# def test_completion_bedrock_claude_sts_client_auth(): -# print("\ncalling bedrock claude external client auth") -# import os - -# aws_access_key_id = os.environ["AWS_TEMP_ACCESS_KEY_ID"] -# aws_secret_access_key = os.environ["AWS_TEMP_SECRET_ACCESS_KEY"] -# aws_region_name = os.environ["AWS_REGION_NAME"] -# aws_role_name = os.environ["AWS_TEMP_ROLE_NAME"] - -# try: -# import boto3 - -# litellm.set_verbose = True - -# response = completion( -# model="bedrock/anthropic.claude-instant-v1", -# messages=messages, -# max_tokens=10, -# temperature=0.1, -# aws_region_name=aws_region_name, -# aws_access_key_id=aws_access_key_id, -# aws_secret_access_key=aws_secret_access_key, -# aws_role_name=aws_role_name, -# aws_session_name="my-test-session", -# ) - -# response = embedding( -# model="cohere.embed-multilingual-v3", -# input=["hello world"], -# aws_region_name="us-east-1", -# aws_access_key_id=aws_access_key_id, -# aws_secret_access_key=aws_secret_access_key, -# aws_role_name=aws_role_name, -# aws_session_name="my-test-session", -# ) - -# response = completion( -# model="gpt-3.5-turbo", -# messages=messages, -# aws_region_name="us-east-1", -# aws_access_key_id=aws_access_key_id, -# aws_secret_access_key=aws_secret_access_key, -# aws_role_name=aws_role_name, -# aws_session_name="my-test-session", -# ) -# # Add any assertions here to check the response -# print(response) -# except RateLimitError: -# pass -# except Exception as e: -# pytest.fail(f"Error occurred: {e}") +# test_completion_bedrock_claude_external_client_auth() -# # test_completion_bedrock_claude_sts_client_auth() +@pytest.mark.skip(reason="Expired token, need to renew") +def test_completion_bedrock_claude_sts_client_auth(): + print("\ncalling bedrock claude external client auth") + import os + + aws_access_key_id = os.environ["AWS_TEMP_ACCESS_KEY_ID"] + aws_secret_access_key = os.environ["AWS_TEMP_SECRET_ACCESS_KEY"] + aws_region_name = os.environ["AWS_REGION_NAME"] + aws_role_name = os.environ["AWS_TEMP_ROLE_NAME"] + + try: + import boto3 + + litellm.set_verbose = True + + response = completion( + model="bedrock/anthropic.claude-instant-v1", + messages=messages, + max_tokens=10, + temperature=0.1, + aws_region_name=aws_region_name, + aws_access_key_id=aws_access_key_id, + aws_secret_access_key=aws_secret_access_key, + aws_role_name=aws_role_name, + aws_session_name="my-test-session", + ) + + response = embedding( + model="cohere.embed-multilingual-v3", + input=["hello world"], + aws_region_name="us-east-1", + aws_access_key_id=aws_access_key_id, + aws_secret_access_key=aws_secret_access_key, + aws_role_name=aws_role_name, + aws_session_name="my-test-session", + ) + + response = completion( + model="gpt-3.5-turbo", + messages=messages, + aws_region_name="us-east-1", + aws_access_key_id=aws_access_key_id, + aws_secret_access_key=aws_secret_access_key, + aws_role_name=aws_role_name, + aws_session_name="my-test-session", + ) + # Add any assertions here to check the response + print(response) + except RateLimitError: + pass + except Exception as e: + pytest.fail(f"Error occurred: {e}") -# def test_provisioned_throughput(): -# try: -# litellm.set_verbose = True -# import botocore, json, io -# import botocore.session -# from botocore.stub import Stubber - -# bedrock_client = botocore.session.get_session().create_client( -# "bedrock-runtime", region_name="us-east-1" -# ) - -# expected_params = { -# "accept": "application/json", -# "body": '{"prompt": "\\n\\nHuman: Hello, how are you?\\n\\nAssistant: ", ' -# '"max_tokens_to_sample": 256}', -# "contentType": "application/json", -# "modelId": "provisioned-model-arn", -# } -# response_from_bedrock = { -# "body": io.StringIO( -# json.dumps( -# { -# "completion": " Here is a short poem about the sky:", -# "stop_reason": "max_tokens", -# "stop": None, -# } -# ) -# ), -# "contentType": "contentType", -# "ResponseMetadata": {"HTTPStatusCode": 200}, -# } - -# with Stubber(bedrock_client) as stubber: -# stubber.add_response( -# "invoke_model", -# service_response=response_from_bedrock, -# expected_params=expected_params, -# ) -# response = litellm.completion( -# model="bedrock/anthropic.claude-instant-v1", -# model_id="provisioned-model-arn", -# messages=[{"content": "Hello, how are you?", "role": "user"}], -# aws_bedrock_client=bedrock_client, -# ) -# print("response stubbed", response) -# except Exception as e: -# pytest.fail(f"Error occurred: {e}") +# test_completion_bedrock_claude_sts_client_auth() -# # test_provisioned_throughput() +def test_bedrock_claude_3(): + try: + litellm.set_verbose = True + response: ModelResponse = completion( + model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0", + messages=messages, + max_tokens=10, + ) + # Add any assertions here to check the response + assert len(response.choices) > 0 + assert len(response.choices[0].message.content) > 0 + 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") -# import os -# -# # 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_NAME"] -# -# # os.environ.pop("AWS_ACCESS_KEY_ID", None) -# # os.environ.pop("AWS_SECRET_ACCESS_KEY", None) -# # os.environ.pop("AWS_REGION_NAME", None) -# try: -# response:ModelResponse = completion( -# model="bedrock/mistral.mistral-7b-instruct-v0:2", -# messages=messages, -# max_tokens=10, -# temperature=0.1, -# ) -# # Add any assertions here to check the response -# assert len(response.choices) > 0 -# assert len(response.choices[0].message.content) > 0 -# -# # os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id -# # os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key -# # os.environ["AWS_REGION_NAME"] = aws_region_name -# except RateLimitError: -# pass -# except Exception as e: -# pytest.fail(f"Error occurred: {e}") -# -# -# test_completion_bedrock_mistral_completion_auth() \ No newline at end of file +def test_bedrock_claude_3_tool_calling(): + try: + litellm.set_verbose = True + 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?"} + ] + response: ModelResponse = completion( + model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0", + messages=messages, + tools=tools, + tool_choice="auto", + ) + 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 + ) + except RateLimitError: + pass + except Exception as e: + pytest.fail(f"Error occurred: {e}") + + +def encode_image(image_path): + import base64 + + with open(image_path, "rb") as image_file: + return base64.b64encode(image_file.read()).decode("utf-8") + + +@pytest.mark.skip( + reason="we already test claude-3, this is just another way to pass images" +) +def test_completion_claude_3_base64(): + try: + litellm.set_verbose = True + litellm.num_retries = 3 + image_path = "../proxy/cached_logo.jpg" + # Getting the base64 string + base64_image = encode_image(image_path) + resp = litellm.completion( + model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0", + messages=[ + { + "role": "user", + "content": [ + {"type": "text", "text": "Whats in this image?"}, + { + "type": "image_url", + "image_url": { + "url": "data:image/jpeg;base64," + base64_image + }, + }, + ], + } + ], + ) + + prompt_tokens = resp.usage.prompt_tokens + raise Exception("it worked!") + except Exception as e: + if "500 Internal error encountered.'" in str(e): + pass + else: + pytest.fail(f"An exception occurred - {str(e)}") + + +def test_provisioned_throughput(): + try: + litellm.set_verbose = True + import botocore, json, io + import botocore.session + from botocore.stub import Stubber + + bedrock_client = botocore.session.get_session().create_client( + "bedrock-runtime", region_name="us-east-1" + ) + + expected_params = { + "accept": "application/json", + "body": '{"prompt": "\\n\\nHuman: Hello, how are you?\\n\\nAssistant: ", ' + '"max_tokens_to_sample": 256}', + "contentType": "application/json", + "modelId": "provisioned-model-arn", + } + response_from_bedrock = { + "body": io.StringIO( + json.dumps( + { + "completion": " Here is a short poem about the sky:", + "stop_reason": "max_tokens", + "stop": None, + } + ) + ), + "contentType": "contentType", + "ResponseMetadata": {"HTTPStatusCode": 200}, + } + + with Stubber(bedrock_client) as stubber: + stubber.add_response( + "invoke_model", + service_response=response_from_bedrock, + expected_params=expected_params, + ) + response = litellm.completion( + model="bedrock/anthropic.claude-instant-v1", + model_id="provisioned-model-arn", + messages=[{"content": "Hello, how are you?", "role": "user"}], + aws_bedrock_client=bedrock_client, + ) + print("response stubbed", response) + except Exception as e: + pytest.fail(f"Error occurred: {e}") + + +# test_provisioned_throughput() + + +def test_completion_bedrock_mistral_completion_auth(): + print("calling bedrock mistral completion params auth") + import os + + # 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_NAME"] + + # os.environ.pop("AWS_ACCESS_KEY_ID", None) + # os.environ.pop("AWS_SECRET_ACCESS_KEY", None) + # os.environ.pop("AWS_REGION_NAME", None) + try: + response: ModelResponse = completion( + model="bedrock/mistral.mistral-7b-instruct-v0:2", + messages=messages, + max_tokens=10, + temperature=0.1, + ) + # Add any assertions here to check the response + assert len(response.choices) > 0 + assert len(response.choices[0].message.content) > 0 + + # os.environ["AWS_ACCESS_KEY_ID"] = aws_access_key_id + # os.environ["AWS_SECRET_ACCESS_KEY"] = aws_secret_access_key + # os.environ["AWS_REGION_NAME"] = aws_region_name + except RateLimitError: + pass + except Exception as e: + pytest.fail(f"Error occurred: {e}") + + +# test_completion_bedrock_mistral_completion_auth() diff --git a/litellm/tests/test_caching.py b/litellm/tests/test_caching.py index 3a7f969e5c..f649bff027 100644 --- a/litellm/tests/test_caching.py +++ b/litellm/tests/test_caching.py @@ -546,7 +546,6 @@ def test_redis_cache_acompletion_stream(): # test_redis_cache_acompletion_stream() -@pytest.mark.skip(reason="AWS Suspended Account") def test_redis_cache_acompletion_stream_bedrock(): import asyncio diff --git a/litellm/tests/test_completion.py b/litellm/tests/test_completion.py index 22d8b2f6a1..57b0e436f0 100644 --- a/litellm/tests/test_completion.py +++ b/litellm/tests/test_completion.py @@ -1646,7 +1646,6 @@ def test_completion_chat_sagemaker_mistral(): # test_completion_chat_sagemaker_mistral() -@pytest.mark.skip(reason="AWS Suspended Account") def test_completion_bedrock_titan_null_response(): try: response = completion( @@ -1672,7 +1671,6 @@ def test_completion_bedrock_titan_null_response(): pytest.fail(f"An error occurred - {str(e)}") -@pytest.mark.skip(reason="AWS Suspended Account") def test_completion_bedrock_titan(): try: response = completion( @@ -1694,7 +1692,6 @@ def test_completion_bedrock_titan(): # test_completion_bedrock_titan() -@pytest.mark.skip(reason="AWS Suspended Account") def test_completion_bedrock_claude(): print("calling claude") try: @@ -1716,7 +1713,6 @@ def test_completion_bedrock_claude(): # test_completion_bedrock_claude() -@pytest.mark.skip(reason="AWS Suspended Account") def test_completion_bedrock_cohere(): print("calling bedrock cohere") litellm.set_verbose = True diff --git a/litellm/tests/test_completion_cost.py b/litellm/tests/test_completion_cost.py index 034048c633..947da71669 100644 --- a/litellm/tests/test_completion_cost.py +++ b/litellm/tests/test_completion_cost.py @@ -171,7 +171,6 @@ def test_cost_openai_image_gen(): assert cost == 0.019922944 -@pytest.mark.skip(reason="AWS Suspended Account") def test_cost_bedrock_pricing(): """ - get pricing specific to region for a model diff --git a/litellm/tests/test_configs/test_config_no_auth.yaml b/litellm/tests/test_configs/test_config_no_auth.yaml index 9cc32bb0bf..1c5ddf2266 100644 --- a/litellm/tests/test_configs/test_config_no_auth.yaml +++ b/litellm/tests/test_configs/test_config_no_auth.yaml @@ -115,4 +115,13 @@ model_list: model_info: description: this is a test openai model id: 34cb2419-7c63-44ae-a189-53f1d1ce5953 - model_name: test_openai_models \ No newline at end of file + model_name: test_openai_models +- litellm_params: + model: amazon.titan-embed-text-v1 + model_name: amazon-embeddings +- litellm_params: + model: gpt-3.5-turbo + model_info: + description: this is a test openai model + id: 753dca9a-898d-4ff7-9961-5acf7cdf38cf + model_name: test_openai_models diff --git a/litellm/tests/test_custom_callback_input.py b/litellm/tests/test_custom_callback_input.py index 683173b21e..9249333197 100644 --- a/litellm/tests/test_custom_callback_input.py +++ b/litellm/tests/test_custom_callback_input.py @@ -478,7 +478,6 @@ async def test_async_chat_azure_stream(): ## Test Bedrock + sync -@pytest.mark.skip(reason="AWS Suspended Account") def test_chat_bedrock_stream(): try: customHandler = CompletionCustomHandler() @@ -519,7 +518,6 @@ def test_chat_bedrock_stream(): ## Test Bedrock + Async -@pytest.mark.skip(reason="AWS Suspended Account") @pytest.mark.asyncio async def test_async_chat_bedrock_stream(): try: @@ -796,7 +794,6 @@ async def test_async_embedding_azure(): ## Test Bedrock + Async -@pytest.mark.skip(reason="AWS Suspended Account") @pytest.mark.asyncio async def test_async_embedding_bedrock(): try: diff --git a/litellm/tests/test_embedding.py b/litellm/tests/test_embedding.py index 2c9de496c4..a2f71eb982 100644 --- a/litellm/tests/test_embedding.py +++ b/litellm/tests/test_embedding.py @@ -256,7 +256,6 @@ async def test_vertexai_aembedding(): pytest.fail(f"Error occurred: {e}") -@pytest.mark.skip(reason="AWS Suspended Account") def test_bedrock_embedding_titan(): try: # this tests if we support str input for bedrock embedding @@ -302,7 +301,6 @@ def test_bedrock_embedding_titan(): # test_bedrock_embedding_titan() -@pytest.mark.skip(reason="AWS Suspended Account") def test_bedrock_embedding_cohere(): try: litellm.set_verbose = False diff --git a/litellm/tests/test_image_generation.py b/litellm/tests/test_image_generation.py index 0672319a21..59ccaacd8d 100644 --- a/litellm/tests/test_image_generation.py +++ b/litellm/tests/test_image_generation.py @@ -121,7 +121,6 @@ async def test_async_image_generation_azure(): pytest.fail(f"An exception occurred - {str(e)}") -@pytest.mark.skip(reason="AWS Suspended Account") def test_image_generation_bedrock(): try: litellm.set_verbose = True @@ -142,7 +141,6 @@ def test_image_generation_bedrock(): pytest.fail(f"An exception occurred - {str(e)}") -@pytest.mark.skip(reason="AWS Suspended Account") @pytest.mark.asyncio async def test_aimage_generation_bedrock_with_optional_params(): try: diff --git a/litellm/tests/test_provider_specific_config.py b/litellm/tests/test_provider_specific_config.py index dcb4dcb4c7..08a84b5604 100644 --- a/litellm/tests/test_provider_specific_config.py +++ b/litellm/tests/test_provider_specific_config.py @@ -515,7 +515,6 @@ def sagemaker_test_completion(): # Bedrock -@pytest.mark.skip(reason="AWS Suspended Account") def bedrock_test_completion(): litellm.AmazonCohereConfig(max_tokens=10) # litellm.set_verbose=True diff --git a/litellm/tests/test_proxy_server.py b/litellm/tests/test_proxy_server.py index 3db4a980a9..d5e8f09c68 100644 --- a/litellm/tests/test_proxy_server.py +++ b/litellm/tests/test_proxy_server.py @@ -125,7 +125,6 @@ def test_embedding(client_no_auth): pytest.fail(f"LiteLLM Proxy test failed. Exception - {str(e)}") -@pytest.mark.skip(reason="AWS Suspended Account") def test_bedrock_embedding(client_no_auth): global headers from litellm.proxy.proxy_server import user_custom_auth diff --git a/litellm/tests/test_router.py b/litellm/tests/test_router.py index 7c182ee686..dc2076aa36 100644 --- a/litellm/tests/test_router.py +++ b/litellm/tests/test_router.py @@ -575,7 +575,6 @@ def test_azure_embedding_on_router(): # test_azure_embedding_on_router() -@pytest.mark.skip(reason="AWS Suspended Account") def test_bedrock_on_router(): litellm.set_verbose = True print("\n Testing bedrock on router\n") diff --git a/litellm/tests/test_router_timeout.py b/litellm/tests/test_router_timeout.py index 3816c649e9..dff30113be 100644 --- a/litellm/tests/test_router_timeout.py +++ b/litellm/tests/test_router_timeout.py @@ -87,7 +87,6 @@ def test_router_timeouts(): print("********** TOKENS USED SO FAR = ", total_tokens_used) -@pytest.mark.skip(reason="AWS Suspended Account") @pytest.mark.asyncio async def test_router_timeouts_bedrock(): import openai diff --git a/litellm/tests/test_streaming.py b/litellm/tests/test_streaming.py index 5767a944b2..c513447b02 100644 --- a/litellm/tests/test_streaming.py +++ b/litellm/tests/test_streaming.py @@ -727,6 +727,7 @@ def test_completion_claude_stream_bad_key(): # pytest.fail(f"Error occurred: {e}") +@pytest.mark.skip(reason="Replicate changed exceptions") def test_completion_replicate_stream_bad_key(): try: api_key = "bad-key" @@ -764,7 +765,6 @@ def test_completion_replicate_stream_bad_key(): # test_completion_replicate_stream_bad_key() -@pytest.mark.skip(reason="AWS Suspended Account") def test_completion_bedrock_claude_stream(): try: litellm.set_verbose = False @@ -811,7 +811,6 @@ def test_completion_bedrock_claude_stream(): # test_completion_bedrock_claude_stream() -@pytest.mark.skip(reason="AWS Suspended Account") def test_completion_bedrock_ai21_stream(): try: litellm.set_verbose = False @@ -1060,6 +1059,7 @@ def ai21_completion_call_bad_key(): # ai21_completion_call_bad_key() +@pytest.mark.skip(reason="flaky test") @pytest.mark.asyncio async def test_hf_completion_tgi_stream(): try: diff --git a/litellm/utils.py b/litellm/utils.py index 0b601521f9..d4d85cad1b 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -245,10 +245,12 @@ class Message(OpenAIObject): self.role = role if function_call is not None: self.function_call = FunctionCall(**function_call) + if tool_calls is not None: self.tool_calls = [] for tool_call in tool_calls: self.tool_calls.append(ChatCompletionMessageToolCall(**tool_call)) + if logprobs is not None: self._logprobs = logprobs @@ -4111,6 +4113,7 @@ def get_optional_params( and custom_llm_provider != "together_ai" and custom_llm_provider != "mistral" and custom_llm_provider != "anthropic" + and custom_llm_provider != "bedrock" ): if custom_llm_provider == "ollama" or custom_llm_provider == "ollama_chat": # ollama actually supports json output @@ -4518,20 +4521,24 @@ def get_optional_params( if stream: optional_params["stream"] = stream elif "anthropic" in model: - supported_params = ["max_tokens", "temperature", "stop", "top_p", "stream"] + supported_params = get_mapped_model_params( + model=model, custom_llm_provider=custom_llm_provider + ) _check_valid_arg(supported_params=supported_params) # anthropic params on bedrock # \"max_tokens_to_sample\":300,\"temperature\":0.5,\"top_p\":1,\"stop_sequences\":[\"\\\\n\\\\nHuman:\"]}" - if max_tokens is not None: - optional_params["max_tokens_to_sample"] = max_tokens - if temperature is not None: - optional_params["temperature"] = temperature - if top_p is not None: - optional_params["top_p"] = top_p - if stop is not None: - optional_params["stop_sequences"] = stop - if stream: - optional_params["stream"] = stream + if model.startswith("anthropic.claude-3"): + optional_params = ( + litellm.AmazonAnthropicClaude3Config().map_openai_params( + non_default_params=non_default_params, + optional_params=optional_params, + ) + ) + else: + optional_params = litellm.AmazonAnthropicConfig().map_openai_params( + non_default_params=non_default_params, + optional_params=optional_params, + ) elif "amazon" in model: # amazon titan llms supported_params = ["max_tokens", "temperature", "stop", "top_p", "stream"] _check_valid_arg(supported_params=supported_params) @@ -4996,6 +5003,17 @@ def get_optional_params( return optional_params +def get_mapped_model_params(model: str, custom_llm_provider: str): + """ + Returns the supported openai params for a given model + provider + """ + if custom_llm_provider == "bedrock": + if model.startswith("anthropic.claude-3"): + return litellm.AmazonAnthropicClaude3Config().get_supported_openai_params() + else: + return litellm.AmazonAnthropicConfig().get_supported_openai_params() + + def get_llm_provider( model: str, custom_llm_provider: Optional[str] = None, diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 23afaf04d6..111b9f8c3c 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -1266,6 +1266,15 @@ "litellm_provider": "bedrock", "mode": "completion" }, + "anthropic.claude-3-sonnet-20240229-v1:0": { + "max_tokens": 200000, + "max_input_tokens": 200000, + "max_output_tokens": 4096, + "input_cost_per_token": 0.000003, + "output_cost_per_token": 0.000015, + "litellm_provider": "bedrock", + "mode": "chat" + }, "anthropic.claude-v1": { "max_tokens": 100000, "max_output_tokens": 8191,