2024-10-23 20:54:22 +08:00
|
|
|
import os
|
|
|
|
|
import sys
|
LiteLLM Minor Fixes & Improvements (11/05/2024) (#6590)
* fix(pattern_matching_router.py): update model name using correct function
* fix(langfuse.py): metadata deepcopy can cause unhandled error (#6563)
Co-authored-by: seva <seva@inita.com>
* fix(stream_chunk_builder_utils.py): correctly set prompt tokens + log correct streaming usage
Closes https://github.com/BerriAI/litellm/issues/6488
* build(deps): bump cookie and express in /docs/my-website (#6566)
Bumps [cookie](https://github.com/jshttp/cookie) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.
Updates `cookie` from 0.6.0 to 0.7.1
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1)
Updates `express` from 4.20.0 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.1)
---
updated-dependencies:
- dependency-name: cookie
dependency-type: indirect
- dependency-name: express
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* docs(virtual_keys.md): update Dockerfile reference (#6554)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
* (proxy fix) - call connect on prisma client when running setup (#6534)
* critical fix - call connect on prisma client when running setup
* fix test_proxy_server_prisma_setup
* fix test_proxy_server_prisma_setup
* Add 3.5 haiku (#6588)
* feat: add claude-3-5-haiku-20241022 entries
* feat: add claude-3-5-haiku-20241022 and vertex_ai/claude-3-5-haiku@20241022 models
* add missing entries, remove vision
* remove image token costs
* Litellm perf improvements 3 (#6573)
* perf: move writing key to cache, to background task
* perf(litellm_pre_call_utils.py): add otel tracing for pre-call utils
adds 200ms on calls with pgdb connected
* fix(litellm_pre_call_utils.py'): rename call_type to actual call used
* perf(proxy_server.py): remove db logic from _get_config_from_file
was causing db calls to occur on every llm request, if team_id was set on key
* fix(auth_checks.py): add check for reducing db calls if user/team id does not exist in db
reduces latency/call by ~100ms
* fix(proxy_server.py): minor fix on existing_settings not incl alerting
* fix(exception_mapping_utils.py): map databricks exception string
* fix(auth_checks.py): fix auth check logic
* test: correctly mark flaky test
* fix(utils.py): handle auth token error for tokenizers.from_pretrained
* build: fix map
* build: fix map
* build: fix json for model map
* fix ImageObject conversion (#6584)
* (fix) litellm.text_completion raises a non-blocking error on simple usage (#6546)
* unit test test_huggingface_text_completion_logprobs
* fix return TextCompletionHandler convert_chat_to_text_completion
* fix hf rest api
* fix test_huggingface_text_completion_logprobs
* fix linting errors
* fix importLiteLLMResponseObjectHandler
* fix test for LiteLLMResponseObjectHandler
* fix test text completion
* fix allow using 15 seconds for premium license check
* testing fix bedrock deprecated cohere.command-text-v14
* (feat) add `Predicted Outputs` for OpenAI (#6594)
* bump openai to openai==1.54.0
* add 'prediction' param
* testing fix bedrock deprecated cohere.command-text-v14
* test test_openai_prediction_param.py
* test_openai_prediction_param_with_caching
* doc Predicted Outputs
* doc Predicted Output
* (fix) Vertex Improve Performance when using `image_url` (#6593)
* fix transformation vertex
* test test_process_gemini_image
* test_image_completion_request
* testing fix - bedrock has deprecated cohere.command-text-v14
* fix vertex pdf
* bump: version 1.51.5 → 1.52.0
* fix(lowest_tpm_rpm_routing.py): fix parallel rate limit check (#6577)
* fix(lowest_tpm_rpm_routing.py): fix parallel rate limit check
* fix(lowest_tpm_rpm_v2.py): return headers in correct format
* test: update test
* build(deps): bump cookie and express in /docs/my-website (#6566)
Bumps [cookie](https://github.com/jshttp/cookie) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.
Updates `cookie` from 0.6.0 to 0.7.1
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1)
Updates `express` from 4.20.0 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.1)
---
updated-dependencies:
- dependency-name: cookie
dependency-type: indirect
- dependency-name: express
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* docs(virtual_keys.md): update Dockerfile reference (#6554)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
* (proxy fix) - call connect on prisma client when running setup (#6534)
* critical fix - call connect on prisma client when running setup
* fix test_proxy_server_prisma_setup
* fix test_proxy_server_prisma_setup
* Add 3.5 haiku (#6588)
* feat: add claude-3-5-haiku-20241022 entries
* feat: add claude-3-5-haiku-20241022 and vertex_ai/claude-3-5-haiku@20241022 models
* add missing entries, remove vision
* remove image token costs
* Litellm perf improvements 3 (#6573)
* perf: move writing key to cache, to background task
* perf(litellm_pre_call_utils.py): add otel tracing for pre-call utils
adds 200ms on calls with pgdb connected
* fix(litellm_pre_call_utils.py'): rename call_type to actual call used
* perf(proxy_server.py): remove db logic from _get_config_from_file
was causing db calls to occur on every llm request, if team_id was set on key
* fix(auth_checks.py): add check for reducing db calls if user/team id does not exist in db
reduces latency/call by ~100ms
* fix(proxy_server.py): minor fix on existing_settings not incl alerting
* fix(exception_mapping_utils.py): map databricks exception string
* fix(auth_checks.py): fix auth check logic
* test: correctly mark flaky test
* fix(utils.py): handle auth token error for tokenizers.from_pretrained
* build: fix map
* build: fix map
* build: fix json for model map
* test: remove eol model
* fix(proxy_server.py): fix db config loading logic
* fix(proxy_server.py): fix order of config / db updates, to ensure fields not overwritten
* test: skip test if required env var is missing
* test: fix test
---------
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: paul-gauthier <69695708+paul-gauthier@users.noreply.github.com>
* test: mark flaky test
* test: handle anthropic api instability
* test(test_proxy_utils.py): add testing for db config update logic
* Update setuptools in docker and fastapi to latest verison, in order to upgrade starlette version (#6597)
* build(deps): bump cookie and express in /docs/my-website (#6566)
Bumps [cookie](https://github.com/jshttp/cookie) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.
Updates `cookie` from 0.6.0 to 0.7.1
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1)
Updates `express` from 4.20.0 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.1)
---
updated-dependencies:
- dependency-name: cookie
dependency-type: indirect
- dependency-name: express
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* docs(virtual_keys.md): update Dockerfile reference (#6554)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
* (proxy fix) - call connect on prisma client when running setup (#6534)
* critical fix - call connect on prisma client when running setup
* fix test_proxy_server_prisma_setup
* fix test_proxy_server_prisma_setup
* Add 3.5 haiku (#6588)
* feat: add claude-3-5-haiku-20241022 entries
* feat: add claude-3-5-haiku-20241022 and vertex_ai/claude-3-5-haiku@20241022 models
* add missing entries, remove vision
* remove image token costs
* Litellm perf improvements 3 (#6573)
* perf: move writing key to cache, to background task
* perf(litellm_pre_call_utils.py): add otel tracing for pre-call utils
adds 200ms on calls with pgdb connected
* fix(litellm_pre_call_utils.py'): rename call_type to actual call used
* perf(proxy_server.py): remove db logic from _get_config_from_file
was causing db calls to occur on every llm request, if team_id was set on key
* fix(auth_checks.py): add check for reducing db calls if user/team id does not exist in db
reduces latency/call by ~100ms
* fix(proxy_server.py): minor fix on existing_settings not incl alerting
* fix(exception_mapping_utils.py): map databricks exception string
* fix(auth_checks.py): fix auth check logic
* test: correctly mark flaky test
* fix(utils.py): handle auth token error for tokenizers.from_pretrained
* build: fix map
* build: fix map
* build: fix json for model map
* fix ImageObject conversion (#6584)
* (fix) litellm.text_completion raises a non-blocking error on simple usage (#6546)
* unit test test_huggingface_text_completion_logprobs
* fix return TextCompletionHandler convert_chat_to_text_completion
* fix hf rest api
* fix test_huggingface_text_completion_logprobs
* fix linting errors
* fix importLiteLLMResponseObjectHandler
* fix test for LiteLLMResponseObjectHandler
* fix test text completion
* fix allow using 15 seconds for premium license check
* testing fix bedrock deprecated cohere.command-text-v14
* (feat) add `Predicted Outputs` for OpenAI (#6594)
* bump openai to openai==1.54.0
* add 'prediction' param
* testing fix bedrock deprecated cohere.command-text-v14
* test test_openai_prediction_param.py
* test_openai_prediction_param_with_caching
* doc Predicted Outputs
* doc Predicted Output
* (fix) Vertex Improve Performance when using `image_url` (#6593)
* fix transformation vertex
* test test_process_gemini_image
* test_image_completion_request
* testing fix - bedrock has deprecated cohere.command-text-v14
* fix vertex pdf
* bump: version 1.51.5 → 1.52.0
* Update setuptools in docker and fastapi to latest verison, in order to upgrade starlette version
---------
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: paul-gauthier <69695708+paul-gauthier@users.noreply.github.com>
Co-authored-by: Krish Dholakia <krrishdholakia@gmail.com>
Co-authored-by: Jacob Hagstedt <wcgs@novonordisk.com>
* fix(langfuse.py): fix linting errors
* fix: fix linting errors
* fix: fix casting error
* fix: fix typing error
* fix: add more tests
* fix(utils.py): fix return_processed_chunk_logic
* Revert "Update setuptools in docker and fastapi to latest verison, in order t…" (#6615)
This reverts commit 1a7f7bdfb75df0efbc930b7f2e39febc80e97d5a.
* docs fix clarify team_id on team based logging
* doc fix team based logging with langfuse
* fix flake8 checks
* test: bump sleep time
* refactor: replace claude-instant-1.2 with haiku in testing
* fix(proxy_server.py): move to using sl payload in track_cost_callback
* fix(proxy_server.py): fix linting errors
* fix(proxy_server.py): fallback to kwargs(response_cost) if given
* test: remove claude-instant-1 from tests
* test: fix claude test
* docs fix clarify team_id on team based logging
* doc fix team based logging with langfuse
* build: remove lint.yml
---------
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: Vsevolod Karvetskiy <56288164+karvetskiy@users.noreply.github.com>
Co-authored-by: seva <seva@inita.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: paul-gauthier <69695708+paul-gauthier@users.noreply.github.com>
Co-authored-by: Jacob Hagstedt P Suorra <Jacobh2@users.noreply.github.com>
Co-authored-by: Jacob Hagstedt <wcgs@novonordisk.com>
2024-11-07 06:47:05 +08:00
|
|
|
import threading
|
2024-10-23 20:54:22 +08:00
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
sys.path.insert(
|
|
|
|
|
0, os.path.abspath("../..")
|
|
|
|
|
) # Adds the parent directory to the system-path
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
from litellm.integrations.langfuse.langfuse import (
|
|
|
|
|
LangFuseLogger,
|
|
|
|
|
)
|
|
|
|
|
from litellm.integrations.langfuse.langfuse_handler import LangFuseHandler
|
|
|
|
|
from litellm.litellm_core_utils.litellm_logging import DynamicLoggingCache
|
|
|
|
|
from unittest.mock import Mock, patch
|
2025-01-26 08:50:57 +08:00
|
|
|
from respx import MockRouter
|
2025-01-22 12:26:09 +08:00
|
|
|
from litellm.types.utils import (
|
|
|
|
|
StandardLoggingPayload,
|
|
|
|
|
StandardLoggingModelInformation,
|
|
|
|
|
StandardLoggingMetadata,
|
|
|
|
|
StandardLoggingHiddenParams,
|
|
|
|
|
StandardCallbackDynamicParams,
|
2025-02-07 10:02:26 +08:00
|
|
|
ModelResponse,
|
|
|
|
|
Choices,
|
|
|
|
|
Message,
|
|
|
|
|
TextCompletionResponse,
|
|
|
|
|
TextChoices,
|
2025-01-22 12:26:09 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_standard_logging_payload() -> StandardLoggingPayload:
|
|
|
|
|
return StandardLoggingPayload(
|
|
|
|
|
id="test_id",
|
|
|
|
|
call_type="completion",
|
|
|
|
|
response_cost=0.1,
|
|
|
|
|
response_cost_failure_debug_info=None,
|
|
|
|
|
status="success",
|
|
|
|
|
total_tokens=30,
|
|
|
|
|
prompt_tokens=20,
|
|
|
|
|
completion_tokens=10,
|
|
|
|
|
startTime=1234567890.0,
|
|
|
|
|
endTime=1234567891.0,
|
|
|
|
|
completionStartTime=1234567890.5,
|
|
|
|
|
model_map_information=StandardLoggingModelInformation(
|
|
|
|
|
model_map_key="gpt-3.5-turbo", model_map_value=None
|
|
|
|
|
),
|
|
|
|
|
model="gpt-3.5-turbo",
|
|
|
|
|
model_id="model-123",
|
|
|
|
|
model_group="openai-gpt",
|
|
|
|
|
api_base="https://api.openai.com",
|
|
|
|
|
metadata=StandardLoggingMetadata(
|
|
|
|
|
user_api_key_hash="test_hash",
|
|
|
|
|
user_api_key_org_id=None,
|
|
|
|
|
user_api_key_alias="test_alias",
|
|
|
|
|
user_api_key_team_id="test_team",
|
|
|
|
|
user_api_key_user_id="test_user",
|
|
|
|
|
user_api_key_team_alias="test_team_alias",
|
|
|
|
|
spend_logs_metadata=None,
|
|
|
|
|
requester_ip_address="127.0.0.1",
|
|
|
|
|
requester_metadata=None,
|
|
|
|
|
),
|
|
|
|
|
cache_hit=False,
|
|
|
|
|
cache_key=None,
|
|
|
|
|
saved_cache_cost=0.0,
|
|
|
|
|
request_tags=[],
|
|
|
|
|
end_user=None,
|
|
|
|
|
requester_ip_address="127.0.0.1",
|
|
|
|
|
messages=[{"role": "user", "content": "Hello, world!"}],
|
|
|
|
|
response={"choices": [{"message": {"content": "Hi there!"}}]},
|
|
|
|
|
error_str=None,
|
|
|
|
|
model_parameters={"stream": True},
|
|
|
|
|
hidden_params=StandardLoggingHiddenParams(
|
|
|
|
|
model_id="model-123",
|
|
|
|
|
cache_key=None,
|
|
|
|
|
api_base="https://api.openai.com",
|
|
|
|
|
response_cost="0.1",
|
|
|
|
|
additional_headers=None,
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
|
2024-10-23 20:54:22 +08:00
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def dynamic_logging_cache():
|
|
|
|
|
return DynamicLoggingCache()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
global_langfuse_logger = LangFuseLogger(
|
|
|
|
|
langfuse_public_key="global_public_key",
|
|
|
|
|
langfuse_secret="global_secret",
|
|
|
|
|
langfuse_host="https://global.langfuse.com",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# IMPORTANT: Test that passing both langfuse_secret_key and langfuse_secret works
|
|
|
|
|
standard_params_1 = StandardCallbackDynamicParams(
|
|
|
|
|
langfuse_public_key="test_public_key",
|
|
|
|
|
langfuse_secret="test_secret",
|
|
|
|
|
langfuse_host="https://test.langfuse.com",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
standard_params_2 = StandardCallbackDynamicParams(
|
|
|
|
|
langfuse_public_key="test_public_key",
|
|
|
|
|
langfuse_secret_key="test_secret",
|
|
|
|
|
langfuse_host="https://test.langfuse.com",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("globalLangfuseLogger", [None, global_langfuse_logger])
|
|
|
|
|
@pytest.mark.parametrize("standard_params", [standard_params_1, standard_params_2])
|
|
|
|
|
def test_get_langfuse_logger_for_request_with_dynamic_params(
|
|
|
|
|
dynamic_logging_cache, globalLangfuseLogger, standard_params
|
|
|
|
|
):
|
|
|
|
|
"""
|
|
|
|
|
If StandardCallbackDynamicParams contain langfuse credentials the returned Langfuse logger should use the dynamic params
|
|
|
|
|
|
|
|
|
|
the new Langfuse logger should be cached
|
|
|
|
|
|
|
|
|
|
Even if globalLangfuseLogger is provided, it should use dynamic params if they are passed
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
result = LangFuseHandler.get_langfuse_logger_for_request(
|
|
|
|
|
standard_callback_dynamic_params=standard_params,
|
|
|
|
|
in_memory_dynamic_logger_cache=dynamic_logging_cache,
|
|
|
|
|
globalLangfuseLogger=globalLangfuseLogger,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert isinstance(result, LangFuseLogger)
|
|
|
|
|
assert result.public_key == "test_public_key"
|
|
|
|
|
assert result.secret_key == "test_secret"
|
|
|
|
|
assert result.langfuse_host == "https://test.langfuse.com"
|
|
|
|
|
|
|
|
|
|
print("langfuse logger=", result)
|
|
|
|
|
print("vars in langfuse logger=", vars(result))
|
|
|
|
|
|
|
|
|
|
# Check if the logger is cached
|
|
|
|
|
cached_logger = dynamic_logging_cache.get_cache(
|
|
|
|
|
credentials={
|
|
|
|
|
"langfuse_public_key": "test_public_key",
|
|
|
|
|
"langfuse_secret": "test_secret",
|
|
|
|
|
"langfuse_host": "https://test.langfuse.com",
|
|
|
|
|
},
|
|
|
|
|
service_name="langfuse",
|
|
|
|
|
)
|
|
|
|
|
assert cached_logger is result
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("globalLangfuseLogger", [None, global_langfuse_logger])
|
|
|
|
|
def test_get_langfuse_logger_for_request_with_no_dynamic_params(
|
|
|
|
|
dynamic_logging_cache, globalLangfuseLogger
|
|
|
|
|
):
|
|
|
|
|
"""
|
|
|
|
|
If StandardCallbackDynamicParams are not provided, the globalLangfuseLogger should be returned
|
|
|
|
|
"""
|
|
|
|
|
result = LangFuseHandler.get_langfuse_logger_for_request(
|
|
|
|
|
standard_callback_dynamic_params=StandardCallbackDynamicParams(),
|
|
|
|
|
in_memory_dynamic_logger_cache=dynamic_logging_cache,
|
|
|
|
|
globalLangfuseLogger=globalLangfuseLogger,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert result is not None
|
|
|
|
|
assert isinstance(result, LangFuseLogger)
|
|
|
|
|
|
|
|
|
|
print("langfuse logger=", result)
|
|
|
|
|
|
|
|
|
|
if globalLangfuseLogger is not None:
|
|
|
|
|
assert result.public_key == "global_public_key"
|
|
|
|
|
assert result.secret_key == "global_secret"
|
|
|
|
|
assert result.langfuse_host == "https://global.langfuse.com"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_dynamic_langfuse_credentials_are_passed():
|
|
|
|
|
# Test when credentials are passed
|
|
|
|
|
params_with_credentials = StandardCallbackDynamicParams(
|
|
|
|
|
langfuse_public_key="test_key",
|
|
|
|
|
langfuse_secret="test_secret",
|
|
|
|
|
langfuse_host="https://test.langfuse.com",
|
|
|
|
|
)
|
|
|
|
|
assert (
|
|
|
|
|
LangFuseHandler._dynamic_langfuse_credentials_are_passed(
|
|
|
|
|
params_with_credentials
|
|
|
|
|
)
|
|
|
|
|
is True
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Test when no credentials are passed
|
|
|
|
|
params_without_credentials = StandardCallbackDynamicParams()
|
|
|
|
|
assert (
|
|
|
|
|
LangFuseHandler._dynamic_langfuse_credentials_are_passed(
|
|
|
|
|
params_without_credentials
|
|
|
|
|
)
|
|
|
|
|
is False
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Test when only some credentials are passed
|
|
|
|
|
params_partial_credentials = StandardCallbackDynamicParams(
|
|
|
|
|
langfuse_public_key="test_key"
|
|
|
|
|
)
|
|
|
|
|
assert (
|
|
|
|
|
LangFuseHandler._dynamic_langfuse_credentials_are_passed(
|
|
|
|
|
params_partial_credentials
|
|
|
|
|
)
|
|
|
|
|
is True
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_dynamic_langfuse_logging_config():
|
|
|
|
|
# Test with dynamic params
|
|
|
|
|
dynamic_params = StandardCallbackDynamicParams(
|
|
|
|
|
langfuse_public_key="dynamic_key",
|
|
|
|
|
langfuse_secret="dynamic_secret",
|
|
|
|
|
langfuse_host="https://dynamic.langfuse.com",
|
|
|
|
|
)
|
|
|
|
|
config = LangFuseHandler.get_dynamic_langfuse_logging_config(dynamic_params)
|
|
|
|
|
assert config["langfuse_public_key"] == "dynamic_key"
|
|
|
|
|
assert config["langfuse_secret"] == "dynamic_secret"
|
|
|
|
|
assert config["langfuse_host"] == "https://dynamic.langfuse.com"
|
|
|
|
|
|
|
|
|
|
# Test with no dynamic params
|
|
|
|
|
empty_params = StandardCallbackDynamicParams()
|
|
|
|
|
config = LangFuseHandler.get_dynamic_langfuse_logging_config(empty_params)
|
|
|
|
|
assert config["langfuse_public_key"] is None
|
|
|
|
|
assert config["langfuse_secret"] is None
|
|
|
|
|
assert config["langfuse_host"] is None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_return_global_langfuse_logger():
|
|
|
|
|
mock_cache = Mock()
|
|
|
|
|
global_logger = LangFuseLogger(
|
|
|
|
|
langfuse_public_key="global_key", langfuse_secret="global_secret"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Test with existing global logger
|
|
|
|
|
result = LangFuseHandler._return_global_langfuse_logger(global_logger, mock_cache)
|
|
|
|
|
assert result == global_logger
|
|
|
|
|
|
|
|
|
|
# Test without global logger, but with cached logger, should return cached logger
|
|
|
|
|
mock_cache.get_cache.return_value = global_logger
|
|
|
|
|
result = LangFuseHandler._return_global_langfuse_logger(None, mock_cache)
|
|
|
|
|
assert result == global_logger
|
|
|
|
|
|
|
|
|
|
# Test without global logger and without cached logger, should create new logger
|
|
|
|
|
mock_cache.get_cache.return_value = None
|
|
|
|
|
with patch.object(
|
|
|
|
|
LangFuseHandler,
|
|
|
|
|
"_create_langfuse_logger_from_credentials",
|
|
|
|
|
return_value=global_logger,
|
|
|
|
|
):
|
|
|
|
|
result = LangFuseHandler._return_global_langfuse_logger(None, mock_cache)
|
|
|
|
|
assert result == global_logger
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_langfuse_logger_for_request_with_cached_logger():
|
|
|
|
|
"""
|
|
|
|
|
Test that get_langfuse_logger_for_request returns the cached logger if it exists when dynamic params are passed
|
|
|
|
|
"""
|
|
|
|
|
mock_cache = Mock()
|
|
|
|
|
cached_logger = LangFuseLogger(
|
|
|
|
|
langfuse_public_key="cached_key", langfuse_secret="cached_secret"
|
|
|
|
|
)
|
|
|
|
|
mock_cache.get_cache.return_value = cached_logger
|
|
|
|
|
|
|
|
|
|
dynamic_params = StandardCallbackDynamicParams(
|
|
|
|
|
langfuse_public_key="test_key",
|
|
|
|
|
langfuse_secret="test_secret",
|
|
|
|
|
langfuse_host="https://test.langfuse.com",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
result = LangFuseHandler.get_langfuse_logger_for_request(
|
|
|
|
|
standard_callback_dynamic_params=dynamic_params,
|
|
|
|
|
in_memory_dynamic_logger_cache=mock_cache,
|
|
|
|
|
globalLangfuseLogger=None,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert result == cached_logger
|
|
|
|
|
mock_cache.get_cache.assert_called_once()
|
LiteLLM Minor Fixes & Improvements (11/05/2024) (#6590)
* fix(pattern_matching_router.py): update model name using correct function
* fix(langfuse.py): metadata deepcopy can cause unhandled error (#6563)
Co-authored-by: seva <seva@inita.com>
* fix(stream_chunk_builder_utils.py): correctly set prompt tokens + log correct streaming usage
Closes https://github.com/BerriAI/litellm/issues/6488
* build(deps): bump cookie and express in /docs/my-website (#6566)
Bumps [cookie](https://github.com/jshttp/cookie) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.
Updates `cookie` from 0.6.0 to 0.7.1
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1)
Updates `express` from 4.20.0 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.1)
---
updated-dependencies:
- dependency-name: cookie
dependency-type: indirect
- dependency-name: express
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* docs(virtual_keys.md): update Dockerfile reference (#6554)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
* (proxy fix) - call connect on prisma client when running setup (#6534)
* critical fix - call connect on prisma client when running setup
* fix test_proxy_server_prisma_setup
* fix test_proxy_server_prisma_setup
* Add 3.5 haiku (#6588)
* feat: add claude-3-5-haiku-20241022 entries
* feat: add claude-3-5-haiku-20241022 and vertex_ai/claude-3-5-haiku@20241022 models
* add missing entries, remove vision
* remove image token costs
* Litellm perf improvements 3 (#6573)
* perf: move writing key to cache, to background task
* perf(litellm_pre_call_utils.py): add otel tracing for pre-call utils
adds 200ms on calls with pgdb connected
* fix(litellm_pre_call_utils.py'): rename call_type to actual call used
* perf(proxy_server.py): remove db logic from _get_config_from_file
was causing db calls to occur on every llm request, if team_id was set on key
* fix(auth_checks.py): add check for reducing db calls if user/team id does not exist in db
reduces latency/call by ~100ms
* fix(proxy_server.py): minor fix on existing_settings not incl alerting
* fix(exception_mapping_utils.py): map databricks exception string
* fix(auth_checks.py): fix auth check logic
* test: correctly mark flaky test
* fix(utils.py): handle auth token error for tokenizers.from_pretrained
* build: fix map
* build: fix map
* build: fix json for model map
* fix ImageObject conversion (#6584)
* (fix) litellm.text_completion raises a non-blocking error on simple usage (#6546)
* unit test test_huggingface_text_completion_logprobs
* fix return TextCompletionHandler convert_chat_to_text_completion
* fix hf rest api
* fix test_huggingface_text_completion_logprobs
* fix linting errors
* fix importLiteLLMResponseObjectHandler
* fix test for LiteLLMResponseObjectHandler
* fix test text completion
* fix allow using 15 seconds for premium license check
* testing fix bedrock deprecated cohere.command-text-v14
* (feat) add `Predicted Outputs` for OpenAI (#6594)
* bump openai to openai==1.54.0
* add 'prediction' param
* testing fix bedrock deprecated cohere.command-text-v14
* test test_openai_prediction_param.py
* test_openai_prediction_param_with_caching
* doc Predicted Outputs
* doc Predicted Output
* (fix) Vertex Improve Performance when using `image_url` (#6593)
* fix transformation vertex
* test test_process_gemini_image
* test_image_completion_request
* testing fix - bedrock has deprecated cohere.command-text-v14
* fix vertex pdf
* bump: version 1.51.5 → 1.52.0
* fix(lowest_tpm_rpm_routing.py): fix parallel rate limit check (#6577)
* fix(lowest_tpm_rpm_routing.py): fix parallel rate limit check
* fix(lowest_tpm_rpm_v2.py): return headers in correct format
* test: update test
* build(deps): bump cookie and express in /docs/my-website (#6566)
Bumps [cookie](https://github.com/jshttp/cookie) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.
Updates `cookie` from 0.6.0 to 0.7.1
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1)
Updates `express` from 4.20.0 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.1)
---
updated-dependencies:
- dependency-name: cookie
dependency-type: indirect
- dependency-name: express
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* docs(virtual_keys.md): update Dockerfile reference (#6554)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
* (proxy fix) - call connect on prisma client when running setup (#6534)
* critical fix - call connect on prisma client when running setup
* fix test_proxy_server_prisma_setup
* fix test_proxy_server_prisma_setup
* Add 3.5 haiku (#6588)
* feat: add claude-3-5-haiku-20241022 entries
* feat: add claude-3-5-haiku-20241022 and vertex_ai/claude-3-5-haiku@20241022 models
* add missing entries, remove vision
* remove image token costs
* Litellm perf improvements 3 (#6573)
* perf: move writing key to cache, to background task
* perf(litellm_pre_call_utils.py): add otel tracing for pre-call utils
adds 200ms on calls with pgdb connected
* fix(litellm_pre_call_utils.py'): rename call_type to actual call used
* perf(proxy_server.py): remove db logic from _get_config_from_file
was causing db calls to occur on every llm request, if team_id was set on key
* fix(auth_checks.py): add check for reducing db calls if user/team id does not exist in db
reduces latency/call by ~100ms
* fix(proxy_server.py): minor fix on existing_settings not incl alerting
* fix(exception_mapping_utils.py): map databricks exception string
* fix(auth_checks.py): fix auth check logic
* test: correctly mark flaky test
* fix(utils.py): handle auth token error for tokenizers.from_pretrained
* build: fix map
* build: fix map
* build: fix json for model map
* test: remove eol model
* fix(proxy_server.py): fix db config loading logic
* fix(proxy_server.py): fix order of config / db updates, to ensure fields not overwritten
* test: skip test if required env var is missing
* test: fix test
---------
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: paul-gauthier <69695708+paul-gauthier@users.noreply.github.com>
* test: mark flaky test
* test: handle anthropic api instability
* test(test_proxy_utils.py): add testing for db config update logic
* Update setuptools in docker and fastapi to latest verison, in order to upgrade starlette version (#6597)
* build(deps): bump cookie and express in /docs/my-website (#6566)
Bumps [cookie](https://github.com/jshttp/cookie) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.
Updates `cookie` from 0.6.0 to 0.7.1
- [Release notes](https://github.com/jshttp/cookie/releases)
- [Commits](https://github.com/jshttp/cookie/compare/v0.6.0...v0.7.1)
Updates `express` from 4.20.0 to 4.21.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.1)
---
updated-dependencies:
- dependency-name: cookie
dependency-type: indirect
- dependency-name: express
dependency-type: indirect
...
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* docs(virtual_keys.md): update Dockerfile reference (#6554)
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
* (proxy fix) - call connect on prisma client when running setup (#6534)
* critical fix - call connect on prisma client when running setup
* fix test_proxy_server_prisma_setup
* fix test_proxy_server_prisma_setup
* Add 3.5 haiku (#6588)
* feat: add claude-3-5-haiku-20241022 entries
* feat: add claude-3-5-haiku-20241022 and vertex_ai/claude-3-5-haiku@20241022 models
* add missing entries, remove vision
* remove image token costs
* Litellm perf improvements 3 (#6573)
* perf: move writing key to cache, to background task
* perf(litellm_pre_call_utils.py): add otel tracing for pre-call utils
adds 200ms on calls with pgdb connected
* fix(litellm_pre_call_utils.py'): rename call_type to actual call used
* perf(proxy_server.py): remove db logic from _get_config_from_file
was causing db calls to occur on every llm request, if team_id was set on key
* fix(auth_checks.py): add check for reducing db calls if user/team id does not exist in db
reduces latency/call by ~100ms
* fix(proxy_server.py): minor fix on existing_settings not incl alerting
* fix(exception_mapping_utils.py): map databricks exception string
* fix(auth_checks.py): fix auth check logic
* test: correctly mark flaky test
* fix(utils.py): handle auth token error for tokenizers.from_pretrained
* build: fix map
* build: fix map
* build: fix json for model map
* fix ImageObject conversion (#6584)
* (fix) litellm.text_completion raises a non-blocking error on simple usage (#6546)
* unit test test_huggingface_text_completion_logprobs
* fix return TextCompletionHandler convert_chat_to_text_completion
* fix hf rest api
* fix test_huggingface_text_completion_logprobs
* fix linting errors
* fix importLiteLLMResponseObjectHandler
* fix test for LiteLLMResponseObjectHandler
* fix test text completion
* fix allow using 15 seconds for premium license check
* testing fix bedrock deprecated cohere.command-text-v14
* (feat) add `Predicted Outputs` for OpenAI (#6594)
* bump openai to openai==1.54.0
* add 'prediction' param
* testing fix bedrock deprecated cohere.command-text-v14
* test test_openai_prediction_param.py
* test_openai_prediction_param_with_caching
* doc Predicted Outputs
* doc Predicted Output
* (fix) Vertex Improve Performance when using `image_url` (#6593)
* fix transformation vertex
* test test_process_gemini_image
* test_image_completion_request
* testing fix - bedrock has deprecated cohere.command-text-v14
* fix vertex pdf
* bump: version 1.51.5 → 1.52.0
* Update setuptools in docker and fastapi to latest verison, in order to upgrade starlette version
---------
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: paul-gauthier <69695708+paul-gauthier@users.noreply.github.com>
Co-authored-by: Krish Dholakia <krrishdholakia@gmail.com>
Co-authored-by: Jacob Hagstedt <wcgs@novonordisk.com>
* fix(langfuse.py): fix linting errors
* fix: fix linting errors
* fix: fix casting error
* fix: fix typing error
* fix: add more tests
* fix(utils.py): fix return_processed_chunk_logic
* Revert "Update setuptools in docker and fastapi to latest verison, in order t…" (#6615)
This reverts commit 1a7f7bdfb75df0efbc930b7f2e39febc80e97d5a.
* docs fix clarify team_id on team based logging
* doc fix team based logging with langfuse
* fix flake8 checks
* test: bump sleep time
* refactor: replace claude-instant-1.2 with haiku in testing
* fix(proxy_server.py): move to using sl payload in track_cost_callback
* fix(proxy_server.py): fix linting errors
* fix(proxy_server.py): fallback to kwargs(response_cost) if given
* test: remove claude-instant-1 from tests
* test: fix claude test
* docs fix clarify team_id on team based logging
* doc fix team based logging with langfuse
* build: remove lint.yml
---------
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: Vsevolod Karvetskiy <56288164+karvetskiy@users.noreply.github.com>
Co-authored-by: seva <seva@inita.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Emmanuel Ferdman <emmanuelferdman@gmail.com>
Co-authored-by: Ishaan Jaff <ishaanjaffer0324@gmail.com>
Co-authored-by: paul-gauthier <69695708+paul-gauthier@users.noreply.github.com>
Co-authored-by: Jacob Hagstedt P Suorra <Jacobh2@users.noreply.github.com>
Co-authored-by: Jacob Hagstedt <wcgs@novonordisk.com>
2024-11-07 06:47:05 +08:00
|
|
|
|
2024-11-13 01:20:51 +08:00
|
|
|
|
2025-01-22 12:26:09 +08:00
|
|
|
def test_get_langfuse_tags():
|
|
|
|
|
"""
|
|
|
|
|
Test that _get_langfuse_tags correctly extracts tags from the standard logging payload
|
|
|
|
|
"""
|
|
|
|
|
# Create a mock logging payload with tags
|
|
|
|
|
mock_payload = create_standard_logging_payload()
|
|
|
|
|
mock_payload["request_tags"] = ["tag1", "tag2", "test_tag"]
|
|
|
|
|
|
|
|
|
|
# Test with payload containing tags
|
|
|
|
|
result = global_langfuse_logger._get_langfuse_tags(mock_payload)
|
|
|
|
|
assert result == ["tag1", "tag2", "test_tag"]
|
|
|
|
|
|
|
|
|
|
# Test with payload without tags
|
|
|
|
|
mock_payload["request_tags"] = None
|
|
|
|
|
result = global_langfuse_logger._get_langfuse_tags(mock_payload)
|
|
|
|
|
assert result == []
|
|
|
|
|
|
|
|
|
|
# Test with empty tags list
|
|
|
|
|
mock_payload["request_tags"] = []
|
|
|
|
|
result = global_langfuse_logger._get_langfuse_tags(mock_payload)
|
|
|
|
|
assert result == []
|
2025-01-26 08:50:57 +08:00
|
|
|
|
|
|
|
|
|
2025-01-26 09:17:32 +08:00
|
|
|
@patch.dict(os.environ, {}, clear=True) # Start with empty environment
|
|
|
|
|
def test_get_langfuse_flush_interval():
|
|
|
|
|
"""
|
|
|
|
|
Test that _get_langfuse_flush_interval correctly reads from environment variable
|
|
|
|
|
or falls back to the provided flush_interval
|
|
|
|
|
"""
|
|
|
|
|
default_interval = 60
|
|
|
|
|
|
|
|
|
|
# Test when env var is not set
|
|
|
|
|
result = LangFuseLogger._get_langfuse_flush_interval(
|
|
|
|
|
flush_interval=default_interval
|
|
|
|
|
)
|
|
|
|
|
assert result == default_interval
|
|
|
|
|
|
|
|
|
|
# Test when env var is set
|
|
|
|
|
with patch.dict(os.environ, {"LANGFUSE_FLUSH_INTERVAL": "120"}):
|
|
|
|
|
result = LangFuseLogger._get_langfuse_flush_interval(
|
|
|
|
|
flush_interval=default_interval
|
|
|
|
|
)
|
|
|
|
|
assert result == 120
|
|
|
|
|
|
2025-02-07 10:02:26 +08:00
|
|
|
|
2025-01-26 08:50:57 +08:00
|
|
|
def test_langfuse_e2e_sync(monkeypatch):
|
|
|
|
|
from litellm import completion
|
|
|
|
|
import litellm
|
|
|
|
|
import respx
|
|
|
|
|
import httpx
|
|
|
|
|
import time
|
2025-06-01 03:42:56 +08:00
|
|
|
litellm.disable_aiohttp_transport = True # since this uses respx, we need to set use_aiohttp_transport to False
|
2025-01-26 08:50:57 +08:00
|
|
|
|
|
|
|
|
litellm._turn_on_debug()
|
|
|
|
|
monkeypatch.setattr(litellm, "success_callback", ["langfuse"])
|
|
|
|
|
|
|
|
|
|
with respx.mock:
|
|
|
|
|
# Mock Langfuse
|
|
|
|
|
# Mock any Langfuse endpoint
|
|
|
|
|
langfuse_mock = respx.post(
|
|
|
|
|
"https://*.cloud.langfuse.com/api/public/ingestion"
|
|
|
|
|
).mock(return_value=httpx.Response(200))
|
|
|
|
|
completion(
|
|
|
|
|
model="openai/my-fake-endpoint",
|
|
|
|
|
messages=[{"role": "user", "content": "hello from litellm"}],
|
|
|
|
|
stream=False,
|
|
|
|
|
mock_response="Hello from litellm 2",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
time.sleep(3)
|
|
|
|
|
|
|
|
|
|
assert langfuse_mock.called
|
2025-01-26 09:17:32 +08:00
|
|
|
|
2025-02-07 10:02:26 +08:00
|
|
|
|
|
|
|
|
def test_get_chat_content_for_langfuse():
|
|
|
|
|
"""
|
|
|
|
|
Test that _get_chat_content_for_langfuse correctly extracts content from chat completion responses
|
|
|
|
|
"""
|
|
|
|
|
# Test with valid response
|
|
|
|
|
mock_response = ModelResponse(
|
|
|
|
|
choices=[Choices(message=Message(role="assistant", content="Hello world"))]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
result = LangFuseLogger._get_chat_content_for_langfuse(mock_response)
|
2025-02-27 08:05:33 +08:00
|
|
|
assert result["content"] == "Hello world"
|
|
|
|
|
assert result["role"] == "assistant"
|
2025-02-07 10:02:26 +08:00
|
|
|
|
|
|
|
|
# Test with empty choices
|
|
|
|
|
mock_response = ModelResponse(choices=[])
|
|
|
|
|
result = LangFuseLogger._get_chat_content_for_langfuse(mock_response)
|
|
|
|
|
assert result is None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_text_completion_content_for_langfuse():
|
|
|
|
|
"""
|
|
|
|
|
Test that _get_text_completion_content_for_langfuse correctly extracts content from text completion responses
|
|
|
|
|
"""
|
|
|
|
|
# Test with valid response
|
|
|
|
|
mock_response = TextCompletionResponse(choices=[TextChoices(text="Hello world")])
|
|
|
|
|
result = LangFuseLogger._get_text_completion_content_for_langfuse(mock_response)
|
|
|
|
|
assert result == "Hello world"
|
|
|
|
|
|
|
|
|
|
# Test with empty choices
|
|
|
|
|
mock_response = TextCompletionResponse(choices=[])
|
|
|
|
|
result = LangFuseLogger._get_text_completion_content_for_langfuse(mock_response)
|
|
|
|
|
assert result is None
|
|
|
|
|
|
|
|
|
|
# Test with no choices field
|
|
|
|
|
mock_response = TextCompletionResponse()
|
|
|
|
|
result = LangFuseLogger._get_text_completion_content_for_langfuse(mock_response)
|
|
|
|
|
assert result is None
|