mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-16 08:23:06 +00:00
Merge branch 'main' into litellm_refactor_01
This commit is contained in:
@@ -475,6 +475,8 @@ router_settings:
|
||||
| DEFAULT_ALLOWED_FAILS | Maximum failures allowed before cooling down a model. Default is 3
|
||||
| DEFAULT_ANTHROPIC_CHAT_MAX_TOKENS | Default maximum tokens for Anthropic chat completions. Default is 4096
|
||||
| DEFAULT_BATCH_SIZE | Default batch size for operations. Default is 512
|
||||
| DEFAULT_CHUNK_OVERLAP | Default chunk overlap for RAG text splitters. Default is 200
|
||||
| DEFAULT_CHUNK_SIZE | Default chunk size for RAG text splitters. Default is 1000
|
||||
| DEFAULT_CLIENT_DISCONNECT_CHECK_TIMEOUT_SECONDS | Timeout in seconds for checking client disconnection. Default is 1
|
||||
| DEFAULT_COOLDOWN_TIME_SECONDS | Duration in seconds to cooldown a model after failures. Default is 5
|
||||
| DEFAULT_CRON_JOB_LOCK_TTL_SECONDS | Time-to-live for cron job locks in seconds. Default is 60 (1 minute)
|
||||
|
||||
Generated
+2
-2
@@ -1,7 +1,7 @@
|
||||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 2.2.0 and should not be changed by hand.
|
||||
package = []
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.8.1,<4.0, !=3.9.7"
|
||||
content-hash = "2cf39473e67ff0615f0a61c9d2ac9f02b38cc08cbb1bdb893d89bee002646623"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "litellm-proxy-extras"
|
||||
version = "0.4.6"
|
||||
version = "0.4.7"
|
||||
description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package."
|
||||
authors = ["BerriAI"]
|
||||
readme = "README.md"
|
||||
@@ -22,7 +22,7 @@ requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.commitizen]
|
||||
version = "0.4.6"
|
||||
version = "0.4.7"
|
||||
version_files = [
|
||||
"pyproject.toml:version",
|
||||
"../requirements.txt:litellm-proxy-extras==",
|
||||
|
||||
@@ -533,6 +533,7 @@ featherless_ai_models: Set = set()
|
||||
palm_models: Set = set()
|
||||
groq_models: Set = set()
|
||||
azure_models: Set = set()
|
||||
azure_anthropic_models: Set = set()
|
||||
azure_text_models: Set = set()
|
||||
anyscale_models: Set = set()
|
||||
cerebras_models: Set = set()
|
||||
@@ -737,6 +738,8 @@ def add_known_models():
|
||||
groq_models.add(key)
|
||||
elif value.get("litellm_provider") == "azure":
|
||||
azure_models.add(key)
|
||||
elif value.get("litellm_provider") == "azure_anthropic":
|
||||
azure_anthropic_models.add(key)
|
||||
elif value.get("litellm_provider") == "anyscale":
|
||||
anyscale_models.add(key)
|
||||
elif value.get("litellm_provider") == "cerebras":
|
||||
@@ -876,6 +879,7 @@ model_list = list(
|
||||
| palm_models
|
||||
| groq_models
|
||||
| azure_models
|
||||
| azure_anthropic_models
|
||||
| anyscale_models
|
||||
| cerebras_models
|
||||
| galadriel_models
|
||||
@@ -965,6 +969,7 @@ models_by_provider: dict = {
|
||||
"palm": palm_models,
|
||||
"groq": groq_models,
|
||||
"azure": azure_models | azure_text_models,
|
||||
"azure_anthropic": azure_anthropic_models,
|
||||
"azure_text": azure_text_models,
|
||||
"anyscale": anyscale_models,
|
||||
"cerebras": cerebras_models,
|
||||
|
||||
@@ -163,7 +163,7 @@ class VertexAIVideoConfig(BaseVideoConfig, VertexBase):
|
||||
headers: dict,
|
||||
model: str,
|
||||
api_key: Optional[str] = None,
|
||||
litellm_params: Optional[GenericLiteLLMParams] = None,
|
||||
litellm_params: Optional[Union[GenericLiteLLMParams, dict]] = None,
|
||||
) -> dict:
|
||||
"""
|
||||
Validate environment and return headers for Vertex AI OCR.
|
||||
|
||||
@@ -10140,6 +10140,19 @@
|
||||
"supports_response_schema": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"fireworks_ai/accounts/fireworks/models/glm-4p6": {
|
||||
"input_cost_per_token": 0.55e-06,
|
||||
"output_cost_per_token": 2.19e-06,
|
||||
"litellm_provider": "fireworks_ai",
|
||||
"max_input_tokens": 202800,
|
||||
"max_output_tokens": 202800,
|
||||
"max_tokens": 202800,
|
||||
"mode": "chat",
|
||||
"source": "https://fireworks.ai/pricing",
|
||||
"supports_function_calling": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"fireworks_ai/accounts/fireworks/models/gpt-oss-120b": {
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"litellm_provider": "fireworks_ai",
|
||||
|
||||
+90
-75
@@ -89,82 +89,12 @@ class VertexPassthroughLoggingHandler:
|
||||
}
|
||||
|
||||
elif "predict" in url_route:
|
||||
from litellm.llms.vertex_ai.image_generation.image_generation_handler import (
|
||||
VertexImageGeneration,
|
||||
return VertexPassthroughLoggingHandler._handle_predict_response(
|
||||
httpx_response=httpx_response,
|
||||
logging_obj=logging_obj,
|
||||
url_route=url_route,
|
||||
kwargs=kwargs,
|
||||
)
|
||||
from litellm.llms.vertex_ai.multimodal_embeddings.transformation import (
|
||||
VertexAIMultimodalEmbeddingConfig,
|
||||
)
|
||||
from litellm.types.utils import PassthroughCallTypes
|
||||
|
||||
vertex_image_generation_class = VertexImageGeneration()
|
||||
|
||||
model = VertexPassthroughLoggingHandler.extract_model_from_url(url_route)
|
||||
|
||||
_json_response = httpx_response.json()
|
||||
|
||||
litellm_prediction_response: Union[
|
||||
ModelResponse, EmbeddingResponse, ImageResponse
|
||||
] = ModelResponse()
|
||||
if vertex_image_generation_class.is_image_generation_response(
|
||||
_json_response
|
||||
):
|
||||
litellm_prediction_response = (
|
||||
vertex_image_generation_class.process_image_generation_response(
|
||||
_json_response,
|
||||
model_response=litellm.ImageResponse(),
|
||||
model=model,
|
||||
)
|
||||
)
|
||||
|
||||
logging_obj.call_type = (
|
||||
PassthroughCallTypes.passthrough_image_generation.value
|
||||
)
|
||||
elif VertexPassthroughLoggingHandler._is_multimodal_embedding_response(
|
||||
json_response=_json_response,
|
||||
):
|
||||
# Use multimodal embedding transformation
|
||||
vertex_multimodal_config = VertexAIMultimodalEmbeddingConfig()
|
||||
litellm_prediction_response = (
|
||||
vertex_multimodal_config.transform_embedding_response(
|
||||
model=model,
|
||||
raw_response=httpx_response,
|
||||
model_response=litellm.EmbeddingResponse(),
|
||||
logging_obj=logging_obj,
|
||||
api_key="",
|
||||
request_data={},
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
)
|
||||
)
|
||||
else:
|
||||
litellm_prediction_response = litellm.vertexAITextEmbeddingConfig.transform_vertex_response_to_openai(
|
||||
response=_json_response,
|
||||
model=model,
|
||||
model_response=litellm.EmbeddingResponse(),
|
||||
)
|
||||
if isinstance(litellm_prediction_response, litellm.EmbeddingResponse):
|
||||
litellm_prediction_response.model = model
|
||||
|
||||
logging_obj.model = model
|
||||
logging_obj.model_call_details["model"] = logging_obj.model
|
||||
logging_obj.model_call_details["custom_llm_provider"] = "vertex_ai"
|
||||
logging_obj.custom_llm_provider = "vertex_ai"
|
||||
response_cost = litellm.completion_cost(
|
||||
completion_response=litellm_prediction_response,
|
||||
model=model,
|
||||
custom_llm_provider="vertex_ai",
|
||||
)
|
||||
|
||||
kwargs["response_cost"] = response_cost
|
||||
kwargs["model"] = model
|
||||
kwargs["custom_llm_provider"] = "vertex_ai"
|
||||
logging_obj.model_call_details["response_cost"] = response_cost
|
||||
|
||||
return {
|
||||
"result": litellm_prediction_response,
|
||||
"kwargs": kwargs,
|
||||
}
|
||||
elif "rawPredict" in url_route or "streamRawPredict" in url_route:
|
||||
from litellm.llms.vertex_ai.vertex_ai_partner_models import (
|
||||
get_vertex_ai_partner_model_config,
|
||||
@@ -266,6 +196,91 @@ class VertexPassthroughLoggingHandler:
|
||||
"kwargs": kwargs,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _handle_predict_response(
|
||||
httpx_response: httpx.Response,
|
||||
logging_obj: LiteLLMLoggingObj,
|
||||
url_route: str,
|
||||
kwargs: dict,
|
||||
) -> PassThroughEndpointLoggingTypedDict:
|
||||
"""Handle predict endpoint responses (embeddings, image generation)."""
|
||||
from litellm.llms.vertex_ai.image_generation.image_generation_handler import (
|
||||
VertexImageGeneration,
|
||||
)
|
||||
from litellm.llms.vertex_ai.multimodal_embeddings.transformation import (
|
||||
VertexAIMultimodalEmbeddingConfig,
|
||||
)
|
||||
from litellm.types.utils import PassthroughCallTypes
|
||||
|
||||
vertex_image_generation_class = VertexImageGeneration()
|
||||
|
||||
model = VertexPassthroughLoggingHandler.extract_model_from_url(url_route)
|
||||
|
||||
_json_response = httpx_response.json()
|
||||
|
||||
litellm_prediction_response: Union[
|
||||
ModelResponse, EmbeddingResponse, ImageResponse
|
||||
] = ModelResponse()
|
||||
if vertex_image_generation_class.is_image_generation_response(
|
||||
_json_response
|
||||
):
|
||||
litellm_prediction_response = (
|
||||
vertex_image_generation_class.process_image_generation_response(
|
||||
_json_response,
|
||||
model_response=litellm.ImageResponse(),
|
||||
model=model,
|
||||
)
|
||||
)
|
||||
|
||||
logging_obj.call_type = (
|
||||
PassthroughCallTypes.passthrough_image_generation.value
|
||||
)
|
||||
elif VertexPassthroughLoggingHandler._is_multimodal_embedding_response(
|
||||
json_response=_json_response,
|
||||
):
|
||||
# Use multimodal embedding transformation
|
||||
vertex_multimodal_config = VertexAIMultimodalEmbeddingConfig()
|
||||
litellm_prediction_response = (
|
||||
vertex_multimodal_config.transform_embedding_response(
|
||||
model=model,
|
||||
raw_response=httpx_response,
|
||||
model_response=litellm.EmbeddingResponse(),
|
||||
logging_obj=logging_obj,
|
||||
api_key="",
|
||||
request_data={},
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
)
|
||||
)
|
||||
else:
|
||||
litellm_prediction_response = litellm.vertexAITextEmbeddingConfig.transform_vertex_response_to_openai(
|
||||
response=_json_response,
|
||||
model=model,
|
||||
model_response=litellm.EmbeddingResponse(),
|
||||
)
|
||||
if isinstance(litellm_prediction_response, litellm.EmbeddingResponse):
|
||||
litellm_prediction_response.model = model
|
||||
|
||||
logging_obj.model = model
|
||||
logging_obj.model_call_details["model"] = logging_obj.model
|
||||
logging_obj.model_call_details["custom_llm_provider"] = "vertex_ai"
|
||||
logging_obj.custom_llm_provider = "vertex_ai"
|
||||
response_cost = litellm.completion_cost(
|
||||
completion_response=litellm_prediction_response,
|
||||
model=model,
|
||||
custom_llm_provider="vertex_ai",
|
||||
)
|
||||
|
||||
kwargs["response_cost"] = response_cost
|
||||
kwargs["model"] = model
|
||||
kwargs["custom_llm_provider"] = "vertex_ai"
|
||||
logging_obj.model_call_details["response_cost"] = response_cost
|
||||
|
||||
return {
|
||||
"result": litellm_prediction_response,
|
||||
"kwargs": kwargs,
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _handle_logging_vertex_collected_chunks(
|
||||
litellm_logging_obj: LiteLLMLoggingObj,
|
||||
|
||||
@@ -126,6 +126,16 @@
|
||||
"options": null,
|
||||
"default_value": null
|
||||
},
|
||||
{
|
||||
"key": "api_key",
|
||||
"label": "AWS Bedrock API Key",
|
||||
"placeholder": null,
|
||||
"tooltip": "You can provide the API Key for accessing the Bedrock API.",
|
||||
"required": false,
|
||||
"field_type": "password",
|
||||
"options": null,
|
||||
"default_value": null
|
||||
},
|
||||
{
|
||||
"key": "aws_session_token",
|
||||
"label": "AWS Session Token",
|
||||
|
||||
@@ -10140,6 +10140,19 @@
|
||||
"supports_response_schema": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"fireworks_ai/accounts/fireworks/models/glm-4p6": {
|
||||
"input_cost_per_token": 0.55e-06,
|
||||
"output_cost_per_token": 2.19e-06,
|
||||
"litellm_provider": "fireworks_ai",
|
||||
"max_input_tokens": 202800,
|
||||
"max_output_tokens": 202800,
|
||||
"max_tokens": 202800,
|
||||
"mode": "chat",
|
||||
"source": "https://fireworks.ai/pricing",
|
||||
"supports_function_calling": true,
|
||||
"supports_response_schema": true,
|
||||
"supports_tool_choice": true
|
||||
},
|
||||
"fireworks_ai/accounts/fireworks/models/gpt-oss-120b": {
|
||||
"input_cost_per_token": 1.5e-07,
|
||||
"litellm_provider": "fireworks_ai",
|
||||
|
||||
Generated
+98
-99
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 2.2.0 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "aiofiles"
|
||||
@@ -2055,6 +2055,26 @@ requests = ["requests (>=2.20.0,<3.0.0)"]
|
||||
testing = ["aiohttp (<3.10.0)", "aiohttp (>=3.6.2,<4.0.0)", "aioresponses", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (<39.0.0) ; python_version < \"3.8\"", "cryptography (>=38.0.3)", "cryptography (>=38.0.3)", "flask", "freezegun", "grpcio", "mock", "oauth2client", "packaging", "pyjwt (>=2.0)", "pyopenssl (<24.3.0)", "pyopenssl (>=20.0.0)", "pytest", "pytest-asyncio", "pytest-cov", "pytest-localserver", "pyu2f (>=0.1.5)", "requests (>=2.20.0,<3.0.0)", "responses", "urllib3"]
|
||||
urllib3 = ["packaging", "urllib3"]
|
||||
|
||||
[[package]]
|
||||
name = "google-cloud-iam"
|
||||
version = "2.19.1"
|
||||
description = "Google Cloud Iam API client library"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
groups = ["main"]
|
||||
markers = "python_version >= \"3.14\" and extra == \"extra-proxy\""
|
||||
files = [
|
||||
{file = "google_cloud_iam-2.19.1-py3-none-any.whl", hash = "sha256:11b08b86d82510021f9dd9f0beb5a08219e070deab09e28d4c0ce49f8c70997d"},
|
||||
{file = "google_cloud_iam-2.19.1.tar.gz", hash = "sha256:f059c369ad98af6be3401f0f5d087775d775fb96833be1e9ab8048c422fb1bf4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0", extras = ["grpc"]}
|
||||
google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0"
|
||||
grpc-google-iam-v1 = ">=0.12.4,<1.0.0"
|
||||
proto-plus = {version = ">=1.25.0,<2.0.0", markers = "python_version >= \"3.13\""}
|
||||
protobuf = ">=3.20.2,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "google-cloud-iam"
|
||||
version = "2.20.0"
|
||||
@@ -2062,7 +2082,7 @@ description = "Google Cloud Iam API client library"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
groups = ["main"]
|
||||
markers = "extra == \"extra-proxy\""
|
||||
markers = "extra == \"extra-proxy\" and python_version < \"3.14\""
|
||||
files = [
|
||||
{file = "google_cloud_iam-2.20.0-py3-none-any.whl", hash = "sha256:643fcf6db3100772f222c7173bc1af15541a05ec1c43785191e835146ed150b8"},
|
||||
{file = "google_cloud_iam-2.20.0.tar.gz", hash = "sha256:06568ed8313f59fac46d21a5aae4c54eb1dda9f6bcecf2736c58ab1065dc9173"},
|
||||
@@ -2072,10 +2092,7 @@ files = [
|
||||
google-api-core = {version = ">=1.34.1,<2.0.dev0 || >=2.11.dev0,<3.0.0", extras = ["grpc"]}
|
||||
google-auth = ">=2.14.1,<2.24.0 || >2.24.0,<2.25.0 || >2.25.0,<3.0.0"
|
||||
grpc-google-iam-v1 = ">=0.12.4,<1.0.0"
|
||||
grpcio = [
|
||||
{version = ">=1.33.2,<2.0.0"},
|
||||
{version = ">=1.75.1,<2.0.0", markers = "python_version >= \"3.14\""},
|
||||
]
|
||||
grpcio = ">=1.33.2,<2.0.0"
|
||||
proto-plus = [
|
||||
{version = ">=1.22.3,<2.0.0"},
|
||||
{version = ">=1.25.0,<2.0.0", markers = "python_version >= \"3.13\""},
|
||||
@@ -2191,6 +2208,8 @@ files = [
|
||||
{file = "greenlet-3.2.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c2ca18a03a8cfb5b25bc1cbe20f3d9a4c80d8c3b13ba3df49ac3961af0b1018d"},
|
||||
{file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fe0a28a7b952a21e2c062cd5756d34354117796c6d9215a87f55e38d15402c5"},
|
||||
{file = "greenlet-3.2.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8854167e06950ca75b898b104b63cc646573aa5fef1353d4508ecdd1ee76254f"},
|
||||
{file = "greenlet-3.2.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f47617f698838ba98f4ff4189aef02e7343952df3a615f847bb575c3feb177a7"},
|
||||
{file = "greenlet-3.2.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af41be48a4f60429d5cad9d22175217805098a9ef7c40bfef44f7669fb9d74d8"},
|
||||
{file = "greenlet-3.2.4-cp310-cp310-win_amd64.whl", hash = "sha256:73f49b5368b5359d04e18d15828eecc1806033db5233397748f4ca813ff1056c"},
|
||||
{file = "greenlet-3.2.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:96378df1de302bc38e99c3a9aa311967b7dc80ced1dcc6f171e99842987882a2"},
|
||||
{file = "greenlet-3.2.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1ee8fae0519a337f2329cb78bd7a8e128ec0f881073d43f023c7b8d4831d5246"},
|
||||
@@ -2200,6 +2219,8 @@ files = [
|
||||
{file = "greenlet-3.2.4-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2523e5246274f54fdadbce8494458a2ebdcdbc7b802318466ac5606d3cded1f8"},
|
||||
{file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1987de92fec508535687fb807a5cea1560f6196285a4cde35c100b8cd632cc52"},
|
||||
{file = "greenlet-3.2.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:55e9c5affaa6775e2c6b67659f3a71684de4c549b3dd9afca3bc773533d284fa"},
|
||||
{file = "greenlet-3.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9c6de1940a7d828635fbd254d69db79e54619f165ee7ce32fda763a9cb6a58c"},
|
||||
{file = "greenlet-3.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03c5136e7be905045160b1b9fdca93dd6727b180feeafda6818e6496434ed8c5"},
|
||||
{file = "greenlet-3.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:9c40adce87eaa9ddb593ccb0fa6a07caf34015a29bf8d344811665b573138db9"},
|
||||
{file = "greenlet-3.2.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3b67ca49f54cede0186854a008109d6ee71f66bd57bb36abd6d0a0267b540cdd"},
|
||||
{file = "greenlet-3.2.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddf9164e7a5b08e9d22511526865780a576f19ddd00d62f8a665949327fde8bb"},
|
||||
@@ -2209,6 +2230,8 @@ files = [
|
||||
{file = "greenlet-3.2.4-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b3812d8d0c9579967815af437d96623f45c0f2ae5f04e366de62a12d83a8fb0"},
|
||||
{file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:abbf57b5a870d30c4675928c37278493044d7c14378350b3aa5d484fa65575f0"},
|
||||
{file = "greenlet-3.2.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:20fb936b4652b6e307b8f347665e2c615540d4b42b3b4c8a321d8286da7e520f"},
|
||||
{file = "greenlet-3.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee7a6ec486883397d70eec05059353b8e83eca9168b9f3f9a361971e77e0bcd0"},
|
||||
{file = "greenlet-3.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:326d234cbf337c9c3def0676412eb7040a35a768efc92504b947b3e9cfc7543d"},
|
||||
{file = "greenlet-3.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:a7d4e128405eea3814a12cc2605e0e6aedb4035bf32697f72deca74de4105e02"},
|
||||
{file = "greenlet-3.2.4-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:1a921e542453fe531144e91e1feedf12e07351b1cf6c9e8a3325ea600a715a31"},
|
||||
{file = "greenlet-3.2.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd3c8e693bff0fff6ba55f140bf390fa92c994083f838fece0f63be121334945"},
|
||||
@@ -2218,6 +2241,8 @@ files = [
|
||||
{file = "greenlet-3.2.4-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23768528f2911bcd7e475210822ffb5254ed10d71f4028387e5a99b4c6699671"},
|
||||
{file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:00fadb3fedccc447f517ee0d3fd8fe49eae949e1cd0f6a611818f4f6fb7dc83b"},
|
||||
{file = "greenlet-3.2.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d25c5091190f2dc0eaa3f950252122edbbadbb682aa7b1ef2f8af0f8c0afefae"},
|
||||
{file = "greenlet-3.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e343822feb58ac4d0a1211bd9399de2b3a04963ddeec21530fc426cc121f19b"},
|
||||
{file = "greenlet-3.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca7f6f1f2649b89ce02f6f229d7c19f680a6238af656f61e0115b24857917929"},
|
||||
{file = "greenlet-3.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:554b03b6e73aaabec3745364d6239e9e012d64c68ccd0b8430c64ccc14939a8b"},
|
||||
{file = "greenlet-3.2.4-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:49a30d5fda2507ae77be16479bdb62a660fa51b1eb4928b524975b3bde77b3c0"},
|
||||
{file = "greenlet-3.2.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:299fd615cd8fc86267b47597123e3f43ad79c9d8a22bebdce535e53550763e2f"},
|
||||
@@ -2225,6 +2250,8 @@ files = [
|
||||
{file = "greenlet-3.2.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b4a1870c51720687af7fa3e7cda6d08d801dae660f75a76f3845b642b4da6ee1"},
|
||||
{file = "greenlet-3.2.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:061dc4cf2c34852b052a8620d40f36324554bc192be474b9e9770e8c042fd735"},
|
||||
{file = "greenlet-3.2.4-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44358b9bf66c8576a9f57a590d5f5d6e72fa4228b763d0e43fee6d3b06d3a337"},
|
||||
{file = "greenlet-3.2.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2917bdf657f5859fbf3386b12d68ede4cf1f04c90c3a6bc1f013dd68a22e2269"},
|
||||
{file = "greenlet-3.2.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:015d48959d4add5d6c9f6c5210ee3803a830dce46356e3bc326d6776bde54681"},
|
||||
{file = "greenlet-3.2.4-cp314-cp314-win_amd64.whl", hash = "sha256:e37ab26028f12dbb0ff65f29a8d3d44a765c61e729647bf2ddfbbed621726f01"},
|
||||
{file = "greenlet-3.2.4-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:b6a7c19cf0d2742d0809a4c05975db036fdff50cd294a93632d6a310bf9ac02c"},
|
||||
{file = "greenlet-3.2.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:27890167f55d2387576d1f41d9487ef171849ea0359ce1510ca6e06c8bece11d"},
|
||||
@@ -2234,6 +2261,8 @@ files = [
|
||||
{file = "greenlet-3.2.4-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9913f1a30e4526f432991f89ae263459b1c64d1608c0d22a5c79c287b3c70df"},
|
||||
{file = "greenlet-3.2.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b90654e092f928f110e0007f572007c9727b5265f7632c2fa7415b4689351594"},
|
||||
{file = "greenlet-3.2.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:81701fd84f26330f0d5f4944d4e92e61afe6319dcd9775e39396e39d7c3e5f98"},
|
||||
{file = "greenlet-3.2.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:28a3c6b7cd72a96f61b0e4b2a36f681025b60ae4779cc73c1535eb5f29560b10"},
|
||||
{file = "greenlet-3.2.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:52206cd642670b0b320a1fd1cbfd95bca0e043179c1d8a045f2c6109dfe973be"},
|
||||
{file = "greenlet-3.2.4-cp39-cp39-win32.whl", hash = "sha256:65458b409c1ed459ea899e939f0e1cdb14f58dbc803f2f93c5eab5694d32671b"},
|
||||
{file = "greenlet-3.2.4-cp39-cp39-win_amd64.whl", hash = "sha256:d2e685ade4dafd447ede19c31277a224a239a0a1a4eca4e6390efedf20260cfb"},
|
||||
{file = "greenlet-3.2.4.tar.gz", hash = "sha256:0dca0d95ff849f9a364385f36ab49f50065d76964944638be9691e1832e9f86d"},
|
||||
@@ -2263,81 +2292,71 @@ protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4
|
||||
|
||||
[[package]]
|
||||
name = "grpcio"
|
||||
version = "1.76.0"
|
||||
version = "1.67.1"
|
||||
description = "HTTP/2-based RPC framework"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main", "dev", "proxy-dev"]
|
||||
files = [
|
||||
{file = "grpcio-1.76.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:65a20de41e85648e00305c1bb09a3598f840422e522277641145a32d42dcefcc"},
|
||||
{file = "grpcio-1.76.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:40ad3afe81676fd9ec6d9d406eda00933f218038433980aa19d401490e46ecde"},
|
||||
{file = "grpcio-1.76.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:035d90bc79eaa4bed83f524331d55e35820725c9fbb00ffa1904d5550ed7ede3"},
|
||||
{file = "grpcio-1.76.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4215d3a102bd95e2e11b5395c78562967959824156af11fa93d18fdd18050990"},
|
||||
{file = "grpcio-1.76.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:49ce47231818806067aea3324d4bf13825b658ad662d3b25fada0bdad9b8a6af"},
|
||||
{file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8cc3309d8e08fd79089e13ed4819d0af72aa935dd8f435a195fd152796752ff2"},
|
||||
{file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:971fd5a1d6e62e00d945423a567e42eb1fa678ba89072832185ca836a94daaa6"},
|
||||
{file = "grpcio-1.76.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d9adda641db7207e800a7f089068f6f645959f2df27e870ee81d44701dd9db3"},
|
||||
{file = "grpcio-1.76.0-cp310-cp310-win32.whl", hash = "sha256:063065249d9e7e0782d03d2bca50787f53bd0fb89a67de9a7b521c4a01f1989b"},
|
||||
{file = "grpcio-1.76.0-cp310-cp310-win_amd64.whl", hash = "sha256:a6ae758eb08088d36812dd5d9af7a9859c05b1e0f714470ea243694b49278e7b"},
|
||||
{file = "grpcio-1.76.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2e1743fbd7f5fa713a1b0a8ac8ebabf0ec980b5d8809ec358d488e273b9cf02a"},
|
||||
{file = "grpcio-1.76.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a8c2cf1209497cf659a667d7dea88985e834c24b7c3b605e6254cbb5076d985c"},
|
||||
{file = "grpcio-1.76.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:08caea849a9d3c71a542827d6df9d5a69067b0a1efbea8a855633ff5d9571465"},
|
||||
{file = "grpcio-1.76.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f0e34c2079d47ae9f6188211db9e777c619a21d4faba6977774e8fa43b085e48"},
|
||||
{file = "grpcio-1.76.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8843114c0cfce61b40ad48df65abcfc00d4dba82eae8718fab5352390848c5da"},
|
||||
{file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8eddfb4d203a237da6f3cc8a540dad0517d274b5a1e9e636fd8d2c79b5c1d397"},
|
||||
{file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:32483fe2aab2c3794101c2a159070584e5db11d0aa091b2c0ea9c4fc43d0d749"},
|
||||
{file = "grpcio-1.76.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dcfe41187da8992c5f40aa8c5ec086fa3672834d2be57a32384c08d5a05b4c00"},
|
||||
{file = "grpcio-1.76.0-cp311-cp311-win32.whl", hash = "sha256:2107b0c024d1b35f4083f11245c0e23846ae64d02f40b2b226684840260ed054"},
|
||||
{file = "grpcio-1.76.0-cp311-cp311-win_amd64.whl", hash = "sha256:522175aba7af9113c48ec10cc471b9b9bd4f6ceb36aeb4544a8e2c80ed9d252d"},
|
||||
{file = "grpcio-1.76.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:81fd9652b37b36f16138611c7e884eb82e0cec137c40d3ef7c3f9b3ed00f6ed8"},
|
||||
{file = "grpcio-1.76.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:04bbe1bfe3a68bbfd4e52402ab7d4eb59d72d02647ae2042204326cf4bbad280"},
|
||||
{file = "grpcio-1.76.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d388087771c837cdb6515539f43b9d4bf0b0f23593a24054ac16f7a960be16f4"},
|
||||
{file = "grpcio-1.76.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f8f757bebaaea112c00dba718fc0d3260052ce714e25804a03f93f5d1c6cc11"},
|
||||
{file = "grpcio-1.76.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:980a846182ce88c4f2f7e2c22c56aefd515daeb36149d1c897f83cf57999e0b6"},
|
||||
{file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f92f88e6c033db65a5ae3d97905c8fea9c725b63e28d5a75cb73b49bda5024d8"},
|
||||
{file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4baf3cbe2f0be3289eb68ac8ae771156971848bb8aaff60bad42005539431980"},
|
||||
{file = "grpcio-1.76.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:615ba64c208aaceb5ec83bfdce7728b80bfeb8be97562944836a7a0a9647d882"},
|
||||
{file = "grpcio-1.76.0-cp312-cp312-win32.whl", hash = "sha256:45d59a649a82df5718fd9527ce775fd66d1af35e6d31abdcdc906a49c6822958"},
|
||||
{file = "grpcio-1.76.0-cp312-cp312-win_amd64.whl", hash = "sha256:c088e7a90b6017307f423efbb9d1ba97a22aa2170876223f9709e9d1de0b5347"},
|
||||
{file = "grpcio-1.76.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:26ef06c73eb53267c2b319f43e6634c7556ea37672029241a056629af27c10e2"},
|
||||
{file = "grpcio-1.76.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:45e0111e73f43f735d70786557dc38141185072d7ff8dc1829d6a77ac1471468"},
|
||||
{file = "grpcio-1.76.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:83d57312a58dcfe2a3a0f9d1389b299438909a02db60e2f2ea2ae2d8034909d3"},
|
||||
{file = "grpcio-1.76.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3e2a27c89eb9ac3d81ec8835e12414d73536c6e620355d65102503064a4ed6eb"},
|
||||
{file = "grpcio-1.76.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61f69297cba3950a524f61c7c8ee12e55c486cb5f7db47ff9dcee33da6f0d3ae"},
|
||||
{file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a15c17af8839b6801d554263c546c69c4d7718ad4321e3166175b37eaacca77"},
|
||||
{file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:25a18e9810fbc7e7f03ec2516addc116a957f8cbb8cbc95ccc80faa072743d03"},
|
||||
{file = "grpcio-1.76.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:931091142fd8cc14edccc0845a79248bc155425eee9a98b2db2ea4f00a235a42"},
|
||||
{file = "grpcio-1.76.0-cp313-cp313-win32.whl", hash = "sha256:5e8571632780e08526f118f74170ad8d50fb0a48c23a746bef2a6ebade3abd6f"},
|
||||
{file = "grpcio-1.76.0-cp313-cp313-win_amd64.whl", hash = "sha256:f9f7bd5faab55f47231ad8dba7787866b69f5e93bc306e3915606779bbfb4ba8"},
|
||||
{file = "grpcio-1.76.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:ff8a59ea85a1f2191a0ffcc61298c571bc566332f82e5f5be1b83c9d8e668a62"},
|
||||
{file = "grpcio-1.76.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:06c3d6b076e7b593905d04fdba6a0525711b3466f43b3400266f04ff735de0cd"},
|
||||
{file = "grpcio-1.76.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd5ef5932f6475c436c4a55e4336ebbe47bd3272be04964a03d316bbf4afbcbc"},
|
||||
{file = "grpcio-1.76.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b331680e46239e090f5b3cead313cc772f6caa7d0fc8de349337563125361a4a"},
|
||||
{file = "grpcio-1.76.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2229ae655ec4e8999599469559e97630185fdd53ae1e8997d147b7c9b2b72cba"},
|
||||
{file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:490fa6d203992c47c7b9e4a9d39003a0c2bcc1c9aa3c058730884bbbb0ee9f09"},
|
||||
{file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:479496325ce554792dba6548fae3df31a72cef7bad71ca2e12b0e58f9b336bfc"},
|
||||
{file = "grpcio-1.76.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c9b93f79f48b03ada57ea24725d83a30284a012ec27eab2cf7e50a550cbbbcc"},
|
||||
{file = "grpcio-1.76.0-cp314-cp314-win32.whl", hash = "sha256:747fa73efa9b8b1488a95d0ba1039c8e2dca0f741612d80415b1e1c560febf4e"},
|
||||
{file = "grpcio-1.76.0-cp314-cp314-win_amd64.whl", hash = "sha256:922fa70ba549fce362d2e2871ab542082d66e2aaf0c19480ea453905b01f384e"},
|
||||
{file = "grpcio-1.76.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:8ebe63ee5f8fa4296b1b8cfc743f870d10e902ca18afc65c68cf46fd39bb0783"},
|
||||
{file = "grpcio-1.76.0-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:3bf0f392c0b806905ed174dcd8bdd5e418a40d5567a05615a030a5aeddea692d"},
|
||||
{file = "grpcio-1.76.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b7604868b38c1bfd5cf72d768aedd7db41d78cb6a4a18585e33fb0f9f2363fd"},
|
||||
{file = "grpcio-1.76.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:e6d1db20594d9daba22f90da738b1a0441a7427552cc6e2e3d1297aeddc00378"},
|
||||
{file = "grpcio-1.76.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d099566accf23d21037f18a2a63d323075bebace807742e4b0ac210971d4dd70"},
|
||||
{file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ebea5cc3aa8ea72e04df9913492f9a96d9348db876f9dda3ad729cfedf7ac416"},
|
||||
{file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0c37db8606c258e2ee0c56b78c62fc9dee0e901b5dbdcf816c2dd4ad652b8b0c"},
|
||||
{file = "grpcio-1.76.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ebebf83299b0cb1721a8859ea98f3a77811e35dce7609c5c963b9ad90728f886"},
|
||||
{file = "grpcio-1.76.0-cp39-cp39-win32.whl", hash = "sha256:0aaa82d0813fd4c8e589fac9b65d7dd88702555f702fb10417f96e2a2a6d4c0f"},
|
||||
{file = "grpcio-1.76.0-cp39-cp39-win_amd64.whl", hash = "sha256:acab0277c40eff7143c2323190ea57b9ee5fd353d8190ee9652369fae735668a"},
|
||||
{file = "grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73"},
|
||||
{file = "grpcio-1.67.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:8b0341d66a57f8a3119b77ab32207072be60c9bf79760fa609c5609f2deb1f3f"},
|
||||
{file = "grpcio-1.67.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:f5a27dddefe0e2357d3e617b9079b4bfdc91341a91565111a21ed6ebbc51b22d"},
|
||||
{file = "grpcio-1.67.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:43112046864317498a33bdc4797ae6a268c36345a910de9b9c17159d8346602f"},
|
||||
{file = "grpcio-1.67.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9b929f13677b10f63124c1a410994a401cdd85214ad83ab67cc077fc7e480f0"},
|
||||
{file = "grpcio-1.67.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7d1797a8a3845437d327145959a2c0c47c05947c9eef5ff1a4c80e499dcc6fa"},
|
||||
{file = "grpcio-1.67.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0489063974d1452436139501bf6b180f63d4977223ee87488fe36858c5725292"},
|
||||
{file = "grpcio-1.67.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9fd042de4a82e3e7aca44008ee2fb5da01b3e5adb316348c21980f7f58adc311"},
|
||||
{file = "grpcio-1.67.1-cp310-cp310-win32.whl", hash = "sha256:638354e698fd0c6c76b04540a850bf1db27b4d2515a19fcd5cf645c48d3eb1ed"},
|
||||
{file = "grpcio-1.67.1-cp310-cp310-win_amd64.whl", hash = "sha256:608d87d1bdabf9e2868b12338cd38a79969eaf920c89d698ead08f48de9c0f9e"},
|
||||
{file = "grpcio-1.67.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:7818c0454027ae3384235a65210bbf5464bd715450e30a3d40385453a85a70cb"},
|
||||
{file = "grpcio-1.67.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ea33986b70f83844cd00814cee4451055cd8cab36f00ac64a31f5bb09b31919e"},
|
||||
{file = "grpcio-1.67.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:c7a01337407dd89005527623a4a72c5c8e2894d22bead0895306b23c6695698f"},
|
||||
{file = "grpcio-1.67.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80b866f73224b0634f4312a4674c1be21b2b4afa73cb20953cbbb73a6b36c3cc"},
|
||||
{file = "grpcio-1.67.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fff78ba10d4250bfc07a01bd6254a6d87dc67f9627adece85c0b2ed754fa96"},
|
||||
{file = "grpcio-1.67.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8a23cbcc5bb11ea7dc6163078be36c065db68d915c24f5faa4f872c573bb400f"},
|
||||
{file = "grpcio-1.67.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1a65b503d008f066e994f34f456e0647e5ceb34cfcec5ad180b1b44020ad4970"},
|
||||
{file = "grpcio-1.67.1-cp311-cp311-win32.whl", hash = "sha256:e29ca27bec8e163dca0c98084040edec3bc49afd10f18b412f483cc68c712744"},
|
||||
{file = "grpcio-1.67.1-cp311-cp311-win_amd64.whl", hash = "sha256:786a5b18544622bfb1e25cc08402bd44ea83edfb04b93798d85dca4d1a0b5be5"},
|
||||
{file = "grpcio-1.67.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:267d1745894200e4c604958da5f856da6293f063327cb049a51fe67348e4f953"},
|
||||
{file = "grpcio-1.67.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:85f69fdc1d28ce7cff8de3f9c67db2b0ca9ba4449644488c1e0303c146135ddb"},
|
||||
{file = "grpcio-1.67.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:f26b0b547eb8d00e195274cdfc63ce64c8fc2d3e2d00b12bf468ece41a0423a0"},
|
||||
{file = "grpcio-1.67.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4422581cdc628f77302270ff839a44f4c24fdc57887dc2a45b7e53d8fc2376af"},
|
||||
{file = "grpcio-1.67.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d7616d2ded471231c701489190379e0c311ee0a6c756f3c03e6a62b95a7146e"},
|
||||
{file = "grpcio-1.67.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8a00efecde9d6fcc3ab00c13f816313c040a28450e5e25739c24f432fc6d3c75"},
|
||||
{file = "grpcio-1.67.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:699e964923b70f3101393710793289e42845791ea07565654ada0969522d0a38"},
|
||||
{file = "grpcio-1.67.1-cp312-cp312-win32.whl", hash = "sha256:4e7b904484a634a0fff132958dabdb10d63e0927398273917da3ee103e8d1f78"},
|
||||
{file = "grpcio-1.67.1-cp312-cp312-win_amd64.whl", hash = "sha256:5721e66a594a6c4204458004852719b38f3d5522082be9061d6510b455c90afc"},
|
||||
{file = "grpcio-1.67.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:aa0162e56fd10a5547fac8774c4899fc3e18c1aa4a4759d0ce2cd00d3696ea6b"},
|
||||
{file = "grpcio-1.67.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:beee96c8c0b1a75d556fe57b92b58b4347c77a65781ee2ac749d550f2a365dc1"},
|
||||
{file = "grpcio-1.67.1-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:a93deda571a1bf94ec1f6fcda2872dad3ae538700d94dc283c672a3b508ba3af"},
|
||||
{file = "grpcio-1.67.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e6f255980afef598a9e64a24efce87b625e3e3c80a45162d111a461a9f92955"},
|
||||
{file = "grpcio-1.67.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e838cad2176ebd5d4a8bb03955138d6589ce9e2ce5d51c3ada34396dbd2dba8"},
|
||||
{file = "grpcio-1.67.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a6703916c43b1d468d0756c8077b12017a9fcb6a1ef13faf49e67d20d7ebda62"},
|
||||
{file = "grpcio-1.67.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:917e8d8994eed1d86b907ba2a61b9f0aef27a2155bca6cbb322430fc7135b7bb"},
|
||||
{file = "grpcio-1.67.1-cp313-cp313-win32.whl", hash = "sha256:e279330bef1744040db8fc432becc8a727b84f456ab62b744d3fdb83f327e121"},
|
||||
{file = "grpcio-1.67.1-cp313-cp313-win_amd64.whl", hash = "sha256:fa0c739ad8b1996bd24823950e3cb5152ae91fca1c09cc791190bf1627ffefba"},
|
||||
{file = "grpcio-1.67.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:178f5db771c4f9a9facb2ab37a434c46cb9be1a75e820f187ee3d1e7805c4f65"},
|
||||
{file = "grpcio-1.67.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f3e49c738396e93b7ba9016e153eb09e0778e776df6090c1b8c91877cc1c426"},
|
||||
{file = "grpcio-1.67.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:24e8a26dbfc5274d7474c27759b54486b8de23c709d76695237515bc8b5baeab"},
|
||||
{file = "grpcio-1.67.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b6c16489326d79ead41689c4b84bc40d522c9a7617219f4ad94bc7f448c5085"},
|
||||
{file = "grpcio-1.67.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e6a4dcf5af7bbc36fd9f81c9f372e8ae580870a9e4b6eafe948cd334b81cf3"},
|
||||
{file = "grpcio-1.67.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:95b5f2b857856ed78d72da93cd7d09b6db8ef30102e5e7fe0961fe4d9f7d48e8"},
|
||||
{file = "grpcio-1.67.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b49359977c6ec9f5d0573ea4e0071ad278ef905aa74e420acc73fd28ce39e9ce"},
|
||||
{file = "grpcio-1.67.1-cp38-cp38-win32.whl", hash = "sha256:f5b76ff64aaac53fede0cc93abf57894ab2a7362986ba22243d06218b93efe46"},
|
||||
{file = "grpcio-1.67.1-cp38-cp38-win_amd64.whl", hash = "sha256:804c6457c3cd3ec04fe6006c739579b8d35c86ae3298ffca8de57b493524b771"},
|
||||
{file = "grpcio-1.67.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:a25bdea92b13ff4d7790962190bf6bf5c4639876e01c0f3dda70fc2769616335"},
|
||||
{file = "grpcio-1.67.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cdc491ae35a13535fd9196acb5afe1af37c8237df2e54427be3eecda3653127e"},
|
||||
{file = "grpcio-1.67.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:85f862069b86a305497e74d0dc43c02de3d1d184fc2c180993aa8aa86fbd19b8"},
|
||||
{file = "grpcio-1.67.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec74ef02010186185de82cc594058a3ccd8d86821842bbac9873fd4a2cf8be8d"},
|
||||
{file = "grpcio-1.67.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01f616a964e540638af5130469451cf580ba8c7329f45ca998ab66e0c7dcdb04"},
|
||||
{file = "grpcio-1.67.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:299b3d8c4f790c6bcca485f9963b4846dd92cf6f1b65d3697145d005c80f9fe8"},
|
||||
{file = "grpcio-1.67.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:60336bff760fbb47d7e86165408126f1dded184448e9a4c892189eb7c9d3f90f"},
|
||||
{file = "grpcio-1.67.1-cp39-cp39-win32.whl", hash = "sha256:5ed601c4c6008429e3d247ddb367fe8c7259c355757448d7c1ef7bd4a6739e8e"},
|
||||
{file = "grpcio-1.67.1-cp39-cp39-win_amd64.whl", hash = "sha256:5db70d32d6703b89912af16d6d45d78406374a8b8ef0d28140351dd0ec610e98"},
|
||||
{file = "grpcio-1.67.1.tar.gz", hash = "sha256:3dc2ed4cabea4dc14d5e708c2b426205956077cc5de419b4d4079315017e9732"},
|
||||
]
|
||||
markers = {main = "extra == \"extra-proxy\""}
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.12,<5.0"
|
||||
|
||||
[package.extras]
|
||||
protobuf = ["grpcio-tools (>=1.76.0)"]
|
||||
protobuf = ["grpcio-tools (>=1.67.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "grpcio-status"
|
||||
@@ -3070,15 +3089,15 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "litellm-proxy-extras"
|
||||
version = "0.4.6"
|
||||
version = "0.4.7"
|
||||
description = "Additional files for the LiteLLM Proxy. Reduces the size of the main litellm package."
|
||||
optional = true
|
||||
python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8"
|
||||
groups = ["main"]
|
||||
markers = "extra == \"proxy\""
|
||||
files = [
|
||||
{file = "litellm_proxy_extras-0.4.6-py3-none-any.whl", hash = "sha256:665ad022fdfd06f3fe97071e49f3b240554a931e57d27850fb815a19d3ea901d"},
|
||||
{file = "litellm_proxy_extras-0.4.6.tar.gz", hash = "sha256:3864bdae26a92906081e591dcf72e1864277e6d58582bee224befb7385fda508"},
|
||||
{file = "litellm_proxy_extras-0.4.7-py3-none-any.whl", hash = "sha256:0ca3c03155ba9553889a83e6c164986d9f128fb7dc584460f3929b6171ac3fe0"},
|
||||
{file = "litellm_proxy_extras-0.4.7.tar.gz", hash = "sha256:bd9e646605c13c277472bff727a7d7cade712c6f4ce2a4683d3df818167030fd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6949,26 +6968,6 @@ examples = ["aiosqlite (>=0.21.0)", "fastapi (>=0.115.12)", "sqlalchemy[asyncio]
|
||||
granian = ["granian (>=2.3.1)"]
|
||||
uvicorn = ["uvicorn (>=0.34.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "starlette"
|
||||
version = "0.49.3"
|
||||
description = "The little ASGI library that shines."
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main", "dev"]
|
||||
files = [
|
||||
{file = "starlette-0.49.3-py3-none-any.whl", hash = "sha256:b579b99715fdc2980cf88c8ec96d3bf1ce16f5a8051a7c2b84ef9b1cdecaea2f"},
|
||||
{file = "starlette-0.49.3.tar.gz", hash = "sha256:1c14546f299b5901a1ea0e34410575bc33bbd741377a10484a54445588d00284"},
|
||||
]
|
||||
markers = {main = "python_version == \"3.9\" and extra == \"proxy\"", dev = "python_version == \"3.9\""}
|
||||
|
||||
[package.dependencies]
|
||||
anyio = ">=3.6.2,<5"
|
||||
typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""}
|
||||
|
||||
[package.extras]
|
||||
full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"]
|
||||
|
||||
[[package]]
|
||||
name = "starlette"
|
||||
version = "0.50.0"
|
||||
@@ -6980,7 +6979,7 @@ files = [
|
||||
{file = "starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca"},
|
||||
{file = "starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca"},
|
||||
]
|
||||
markers = {main = "python_version >= \"3.10\" and (extra == \"mlflow\" or extra == \"proxy\")", dev = "python_version >= \"3.10\""}
|
||||
markers = {main = "python_version >= \"3.10\" and (extra == \"mlflow\" or extra == \"proxy\") or extra == \"proxy\""}
|
||||
|
||||
[package.dependencies]
|
||||
anyio = ">=3.6.2,<5"
|
||||
@@ -8007,4 +8006,4 @@ utils = ["numpydoc"]
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.9,<4.0"
|
||||
content-hash = "1f482f89088b4a28edb7aa58459d17bfd7df36b30c0d53e88e4f7a9b4a65b369"
|
||||
content-hash = "3b6e1c0e9697842545d175e3c9ba5b562635d271fe636b95158de874a1bbb1d5"
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ websockets = {version = "^13.1.0", optional = true}
|
||||
boto3 = {version = "1.36.0", optional = true}
|
||||
redisvl = {version = "^0.4.1", optional = true, markers = "python_version >= '3.9' and python_version < '3.14'"}
|
||||
mcp = {version = "^1.21.2", optional = true, python = ">=3.10"}
|
||||
litellm-proxy-extras = {version = "0.4.6", optional = true}
|
||||
litellm-proxy-extras = {version = "0.4.7", optional = true}
|
||||
rich = {version = "13.7.1", optional = true}
|
||||
litellm-enterprise = {version = "0.1.22", optional = true}
|
||||
diskcache = {version = "^5.6.1", optional = true}
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ sentry_sdk==2.21.0 # for sentry error handling
|
||||
detect-secrets==1.5.0 # Enterprise - secret detection / masking in LLM requests
|
||||
cryptography==44.0.1
|
||||
tzdata==2025.1 # IANA time zone database
|
||||
litellm-proxy-extras==0.4.6 # for proxy extras - e.g. prisma migrations
|
||||
litellm-proxy-extras==0.4.7 # for proxy extras - e.g. prisma migrations
|
||||
### LITELLM PACKAGE DEPENDENCIES
|
||||
python-dotenv==1.0.1 # for env
|
||||
tiktoken==0.8.0 # for calculating usage
|
||||
|
||||
@@ -2,7 +2,6 @@ import os
|
||||
import sys
|
||||
import pytest
|
||||
import asyncio
|
||||
import json
|
||||
from typing import Optional
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
@@ -106,7 +105,7 @@ async def test_mcp_cost_tracking():
|
||||
await asyncio.sleep(2)
|
||||
|
||||
logged_standard_logging_payload = test_logger.standard_logging_payload
|
||||
print("logged_standard_logging_payload", json.dumps(logged_standard_logging_payload, indent=4))
|
||||
print("logged_standard_logging_payload", logged_standard_logging_payload)
|
||||
|
||||
# Add assertions
|
||||
assert response is not None
|
||||
@@ -208,7 +207,7 @@ async def test_mcp_cost_tracking_per_tool():
|
||||
await asyncio.sleep(2)
|
||||
|
||||
logged_standard_logging_payload_1 = test_logger.standard_logging_payload
|
||||
print("logged_standard_logging_payload_1", json.dumps(logged_standard_logging_payload_1, indent=4))
|
||||
print("logged_standard_logging_payload_1", logged_standard_logging_payload_1)
|
||||
|
||||
# Verify expensive tool cost
|
||||
assert logged_standard_logging_payload_1 is not None, "Standard logging payload 1 should not be None"
|
||||
@@ -229,7 +228,7 @@ async def test_mcp_cost_tracking_per_tool():
|
||||
await asyncio.sleep(2)
|
||||
|
||||
logged_standard_logging_payload_2 = test_logger.standard_logging_payload
|
||||
print("logged_standard_logging_payload_2", json.dumps(logged_standard_logging_payload_2, indent=4))
|
||||
print("logged_standard_logging_payload_2", logged_standard_logging_payload_2)
|
||||
|
||||
# Verify cheap tool cost
|
||||
assert logged_standard_logging_payload_2 is not None, "Standard logging payload 2 should not be None"
|
||||
@@ -340,6 +339,6 @@ async def test_mcp_tool_call_hook():
|
||||
|
||||
# check logged standard logging payload
|
||||
logged_standard_logging_payload = test_logger.standard_logging_payload
|
||||
print("logged_standard_logging_payload", json.dumps(logged_standard_logging_payload, indent=4))
|
||||
print("logged_standard_logging_payload", logged_standard_logging_payload)
|
||||
assert logged_standard_logging_payload is not None, "Standard logging payload should not be None"
|
||||
assert logged_standard_logging_payload["response_cost"] == 1.42
|
||||
|
||||
@@ -821,18 +821,22 @@ async def test_vertex_ai_anthropic_token_counting():
|
||||
assert response.original_response["input_tokens"] == 15
|
||||
|
||||
@pytest.mark.parametrize("vertex_location", ["global", "us-central1"])
|
||||
def test_vertex_ai_gemini_token_counting_endpoint(vertex_location):
|
||||
def test_vertex_ai_partner_models_token_counting_endpoint(vertex_location):
|
||||
"""
|
||||
Test that the VertexAIPartnerModelsTokenCounter builds the correct endpoint URL
|
||||
for different vertex locations, including the special 'global' location.
|
||||
"""
|
||||
from litellm.llms.vertex_ai.vertex_ai_partner_models.count_tokens.handler import (
|
||||
VertexAIPartnerModelsTokenCounter,
|
||||
)
|
||||
|
||||
endpoint = VertexAIPartnerModelsTokenCounter()._build_count_tokens_endpoint(
|
||||
model="gemini-2.5-pro",
|
||||
model="claude-3-5-sonnet-20241022",
|
||||
project_id="test-project",
|
||||
vertex_location=vertex_location,
|
||||
api_base=None,
|
||||
)
|
||||
if vertex_location == "global":
|
||||
assert endpoint == "https://aiplatform.googleapis.com"
|
||||
assert endpoint.startswith("https://aiplatform.googleapis.com")
|
||||
else:
|
||||
assert endpoint == f"https://{vertex_location}-aiplatform.googleapis.com"
|
||||
assert endpoint.startswith(f"https://{vertex_location}-aiplatform.googleapis.com")
|
||||
@@ -139,7 +139,7 @@ async def test_create_mcp_server_direct():
|
||||
mock_get_prisma.return_value = mock_prisma
|
||||
|
||||
# Mock server manager
|
||||
mock_manager.add_update_server = mock.Mock()
|
||||
mock_manager.add_update_server = mock.AsyncMock()
|
||||
mock_manager.reload_servers_from_database = mock.AsyncMock()
|
||||
|
||||
# Set up test data
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Query keys factory
|
||||
|
||||
type ListParams = {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
filters?: Record<string, string | number>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a query keys factory for a given resource.
|
||||
*
|
||||
* @param resource - The name of the resource (e.g., "books", "users", "keys")
|
||||
* @returns An object with query key generators following the standard pattern
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const bookKeys = createQueryKeys("books");
|
||||
* // bookKeys.all -> ["books"]
|
||||
* // bookKeys.lists() -> ["books", "list"]
|
||||
* // bookKeys.list({ page: 1 }) -> ["books", "list", { params: { page: 1 } }]
|
||||
* // bookKeys.details() -> ["books", "detail"]
|
||||
* // bookKeys.detail("123") -> ["books", "detail", "123"]
|
||||
* ```
|
||||
*/
|
||||
export function createQueryKeys<T extends string>(resource: T) {
|
||||
const all = [resource] as const;
|
||||
|
||||
return {
|
||||
all,
|
||||
lists: () => [...all, "list"] as const,
|
||||
list: (params?: ListParams) => [...all, "list", { params }] as const,
|
||||
details: () => [...all, "detail"] as const,
|
||||
detail: (uid: string) => [...all, "detail", uid] as const,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { createQueryKeys } from "../common/queryKeysFactory";
|
||||
import { modelInfoCall, modelHubCall } from "@/components/networking";
|
||||
|
||||
const modelKeys = createQueryKeys("models");
|
||||
const modelHubKeys = createQueryKeys("modelHub");
|
||||
|
||||
export const useModelsInfo = (accessToken: string | null, userID: string | null, userRole: string | null) => {
|
||||
return useQuery({
|
||||
queryKey: modelKeys.list({
|
||||
filters: {
|
||||
...(userID && { userID }),
|
||||
...(userRole && { userRole }),
|
||||
},
|
||||
}),
|
||||
queryFn: async () => await modelInfoCall(accessToken!, userID!, userRole!),
|
||||
enabled: Boolean(accessToken && userID && userRole),
|
||||
});
|
||||
};
|
||||
|
||||
export const useModelHub = (accessToken: string | null) => {
|
||||
return useQuery({
|
||||
queryKey: modelHubKeys.list({}),
|
||||
queryFn: async () => await modelHubCall(accessToken!),
|
||||
enabled: Boolean(accessToken),
|
||||
});
|
||||
};
|
||||
@@ -67,7 +67,7 @@ const useAuthorized = () => {
|
||||
userRole: formatUserRole(decoded?.user_role ?? null),
|
||||
premiumUser: decoded?.premium_user ?? null,
|
||||
disabledPersonalKeyCreation: decoded?.disabled_non_admin_personal_key_creation ?? null,
|
||||
showSSOBanner: decoded?.login_method === "username_password" ?? false,
|
||||
showSSOBanner: decoded?.login_method === "username_password",
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
+23
-18
@@ -1,6 +1,7 @@
|
||||
/* @vitest-environment jsdom */
|
||||
import { render } from "@testing-library/react";
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import ModelsAndEndpointsView from "./ModelsAndEndpointsView";
|
||||
|
||||
// Minimal stubs to avoid Next.js router and network usage during render
|
||||
@@ -56,19 +57,24 @@ vi.mock("@/app/(dashboard)/hooks/useTeams", () => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
const createQueryClient = () =>
|
||||
new QueryClient({
|
||||
defaultOptions: { queries: { retry: false, gcTime: 0 } },
|
||||
});
|
||||
|
||||
describe("ModelsAndEndpointsView", () => {
|
||||
it(
|
||||
"should render the models and endpoints view",
|
||||
async () => {
|
||||
// JSDOM polyfill for libraries expecting ResizeObserver (e.g., recharts)
|
||||
// Note: ResizeObserver is now globally mocked in setupTests.ts, but keeping this for backwards compatibility
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(global as any).ResizeObserver = class {
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
disconnect() {}
|
||||
};
|
||||
const { findByText } = render(
|
||||
it("should render the models and endpoints view", async () => {
|
||||
// JSDOM polyfill for libraries expecting ResizeObserver (e.g., recharts)
|
||||
// Note: ResizeObserver is now globally mocked in setupTests.ts, but keeping this for backwards compatibility
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(global as any).ResizeObserver = class {
|
||||
observe() {}
|
||||
unobserve() {}
|
||||
disconnect() {}
|
||||
};
|
||||
const queryClient = createQueryClient();
|
||||
const { findByText } = render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ModelsAndEndpointsView
|
||||
accessToken="123"
|
||||
token="123"
|
||||
@@ -79,10 +85,9 @@ describe("ModelsAndEndpointsView", () => {
|
||||
setModelData={() => {}}
|
||||
premiumUser={false}
|
||||
teams={[]}
|
||||
/>,
|
||||
);
|
||||
expect(await findByText("Model Management", {}, { timeout: 10000 })).toBeInTheDocument();
|
||||
},
|
||||
15000,
|
||||
);
|
||||
/>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
expect(await findByText("Model Management", {}, { timeout: 10000 })).toBeInTheDocument();
|
||||
}, 15000);
|
||||
});
|
||||
|
||||
+37
-18
@@ -1,5 +1,6 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Text, Grid, Col } from "@tremor/react";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { CredentialItem, credentialListCall, CredentialsResponse } from "@/components/networking";
|
||||
|
||||
import { handleAddModelSubmit } from "@/components/add_model/handle_add_model_submit";
|
||||
@@ -9,7 +10,6 @@ import { getDisplayModelName } from "@/components/view_model/model_name_display"
|
||||
import { TabPanel, TabPanels, TabGroup, TabList, Tab, Icon } from "@tremor/react";
|
||||
import { DateRangePickerValue } from "@tremor/react";
|
||||
import {
|
||||
modelInfoCall,
|
||||
modelCostMap,
|
||||
modelMetricsCall,
|
||||
streamingModelMetricsCall,
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
adminGlobalActivityExceptionsPerDeployment,
|
||||
allEndUsersCall,
|
||||
} from "@/components/networking";
|
||||
import { useModelsInfo } from "@/app/(dashboard)/hooks/models/useModels";
|
||||
import { Form } from "antd";
|
||||
import { Typography } from "antd";
|
||||
import { RefreshIcon } from "@heroicons/react/outline";
|
||||
@@ -152,6 +153,14 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [selectedTabIndex, setSelectedTabIndex] = useState(0);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const {
|
||||
data: modelDataResponse,
|
||||
isLoading: isLoadingModels,
|
||||
refetch: refetchModels,
|
||||
} = useModelsInfo(accessToken, userID, userRole);
|
||||
|
||||
const setProviderModelsFn = (provider: Providers) => {
|
||||
const _providerModels = getProviderModels(provider, modelMap);
|
||||
setProviderModels(_providerModels);
|
||||
@@ -180,6 +189,7 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
|
||||
const uploadProps: UploadProps = {
|
||||
name: "file",
|
||||
accept: ".json",
|
||||
pastable: false,
|
||||
beforeUpload: (file) => {
|
||||
if (file.type === "application/json") {
|
||||
const reader = new FileReader();
|
||||
@@ -207,6 +217,9 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
|
||||
// Update the 'lastRefreshed' state to the current date and time
|
||||
const currentDate = new Date();
|
||||
setLastRefreshed(currentDate.toLocaleString());
|
||||
// Invalidate and refetch models data using React Query
|
||||
queryClient.invalidateQueries({ queryKey: ["models", "list"] });
|
||||
refetchModels();
|
||||
};
|
||||
|
||||
const handleSaveRetrySettings = async () => {
|
||||
@@ -239,13 +252,11 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!accessToken || !token || !userRole || !userID) {
|
||||
if (!accessToken || !token || !userRole || !userID || !modelDataResponse) {
|
||||
return;
|
||||
}
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
// Replace with your actual API call for model data
|
||||
const modelDataResponse = await modelInfoCall(accessToken, userID, userRole);
|
||||
setModelData(modelDataResponse);
|
||||
const _providerSettings = await modelSettingsCall(accessToken);
|
||||
if (_providerSettings) {
|
||||
@@ -372,7 +383,7 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
if (accessToken && token && userRole && userID) {
|
||||
if (accessToken && token && userRole && userID && modelDataResponse) {
|
||||
fetchData();
|
||||
}
|
||||
|
||||
@@ -383,11 +394,9 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
|
||||
if (modelMap == null) {
|
||||
fetchModelMap();
|
||||
}
|
||||
}, [accessToken, token, userRole, userID, modelDataResponse]);
|
||||
|
||||
handleRefreshClick();
|
||||
}, [accessToken, token, userRole, userID, modelMap, lastRefreshed, selectedTeam]);
|
||||
|
||||
if (!modelData) {
|
||||
if (!modelData || isLoadingModels) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
@@ -597,15 +606,25 @@ const ModelsAndEndpointsView: React.FC<ModelDashboardProps> = ({
|
||||
setEditModalVisible={setEditModalVisible}
|
||||
setSelectedModel={setSelectedModel}
|
||||
onModelUpdate={(updatedModel) => {
|
||||
// Update the model in the modelData.data array
|
||||
const updatedModelData = {
|
||||
...modelData,
|
||||
data: modelData.data.map((model: any) =>
|
||||
model.model_info.id === updatedModel.model_info.id ? updatedModel : model,
|
||||
),
|
||||
};
|
||||
setModelData(updatedModelData);
|
||||
// Trigger a refresh to update UI
|
||||
// Handle model deletion
|
||||
if (updatedModel.deleted) {
|
||||
const updatedModelData = {
|
||||
...modelData,
|
||||
data: modelData.data.filter((model: any) => model.model_info.id !== updatedModel.model_info.id),
|
||||
};
|
||||
setModelData(updatedModelData);
|
||||
} else {
|
||||
// Update the model in the modelData.data array
|
||||
const updatedModelData = {
|
||||
...modelData,
|
||||
data: modelData.data.map((model: any) =>
|
||||
model.model_info.id === updatedModel.model_info.id ? updatedModel : model,
|
||||
),
|
||||
};
|
||||
setModelData(updatedModelData);
|
||||
}
|
||||
// Invalidate cache and trigger a refresh to update UI
|
||||
queryClient.invalidateQueries({ queryKey: ["models", "list"] });
|
||||
handleRefreshClick();
|
||||
}}
|
||||
modelAccessGroups={availableModelAccessGroups}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import React from "react";
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { screen, render, fireEvent, act } from "@testing-library/react";
|
||||
import { ProviderLogo } from "./ProviderLogo";
|
||||
import * as providerInfoHelpers from "../../provider_info_helpers";
|
||||
|
||||
vi.mock("../../provider_info_helpers");
|
||||
|
||||
describe("ProviderLogo", () => {
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it("should render the component", () => {
|
||||
vi.mocked(providerInfoHelpers.getProviderLogoAndName).mockReturnValue({
|
||||
logo: "",
|
||||
displayName: "Test Provider",
|
||||
});
|
||||
render(<ProviderLogo provider="test" />);
|
||||
expect(screen.getByText("t")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should show fallback when image fails to load", () => {
|
||||
vi.mocked(providerInfoHelpers.getProviderLogoAndName).mockReturnValue({
|
||||
logo: "/path/to/logo.png",
|
||||
displayName: "Test Provider",
|
||||
});
|
||||
render(<ProviderLogo provider="test" />);
|
||||
const img = screen.getByRole("img", { name: "test logo" });
|
||||
expect(img).toBeInTheDocument();
|
||||
|
||||
act(() => {
|
||||
fireEvent.error(img);
|
||||
});
|
||||
|
||||
expect(screen.getByText("t")).toBeInTheDocument();
|
||||
expect(screen.queryByRole("img")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import React, { useState } from "react";
|
||||
import { getProviderLogoAndName } from "../../provider_info_helpers";
|
||||
|
||||
interface ProviderLogoProps {
|
||||
provider: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const ProviderLogo: React.FC<ProviderLogoProps> = ({ provider, className = "w-4 h-4" }) => {
|
||||
const [hasError, setHasError] = useState(false);
|
||||
const { logo } = getProviderLogoAndName(provider);
|
||||
|
||||
const showFallback = hasError || !logo;
|
||||
|
||||
if (showFallback) {
|
||||
return (
|
||||
<div className={`${className} rounded-full bg-gray-200 flex items-center justify-center text-xs`}>
|
||||
{provider?.charAt(0) || "-"}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <img src={logo} alt={`${provider} logo`} className={className} onError={() => setHasError(true)} />;
|
||||
};
|
||||
@@ -3,7 +3,7 @@ import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Badge, Button, Icon } from "@tremor/react";
|
||||
import { Tooltip } from "antd";
|
||||
import { ModelData } from "../../model_dashboard/types";
|
||||
import { getProviderLogoAndName } from "../../provider_info_helpers";
|
||||
import { ProviderLogo } from "./ProviderLogo";
|
||||
|
||||
export const columns = (
|
||||
userRole: string,
|
||||
@@ -62,28 +62,7 @@ export const columns = (
|
||||
{/* Provider Icon */}
|
||||
<div className="flex-shrink-0 mt-0.5">
|
||||
{model.provider ? (
|
||||
<img
|
||||
src={getProviderLogoAndName(model.provider).logo}
|
||||
alt={`${model.provider} logo`}
|
||||
className="w-4 h-4"
|
||||
onError={(e) => {
|
||||
const target = e.currentTarget as HTMLImageElement;
|
||||
const parent = target.parentElement;
|
||||
if (!parent || !parent.contains(target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const fallbackDiv = document.createElement("div");
|
||||
fallbackDiv.className =
|
||||
"w-4 h-4 rounded-full bg-gray-200 flex items-center justify-center text-xs";
|
||||
fallbackDiv.textContent = model.provider?.charAt(0) || "-";
|
||||
parent.replaceChild(fallbackDiv, target);
|
||||
} catch (error) {
|
||||
console.error("Failed to replace provider logo fallback:", error);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<ProviderLogo provider={model.provider} />
|
||||
) : (
|
||||
<div className="w-4 h-4 rounded-full bg-gray-200 flex items-center justify-center text-xs">-</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user