diff --git a/litellm/integrations/callback_configs.json b/litellm/integrations/callback_configs.json index c40b90cee25..85bfcc6e7ed 100644 --- a/litellm/integrations/callback_configs.json +++ b/litellm/integrations/callback_configs.json @@ -378,6 +378,27 @@ }, "description": "OpenTelemetry Logging Integration" }, + { + "id": "pointfive", + "displayName": "PointFive", + "logo": "pointfive.png", + "supports_key_team_logging": false, + "dynamic_params": { + "POINTFIVE_API_KEY": { + "type": "password", + "ui_name": "API Key", + "description": "PointFive API key, used to request an upload url for each batch of logs", + "required": true + }, + "POINTFIVE_API_URL": { + "type": "text", + "ui_name": "API URL", + "description": "PointFive API endpoint. Leave blank to use https://api.pointfive.co/api/v1/ingestion", + "required": false + } + }, + "description": "PointFive Logging Integration" + }, { "id": "s3", "displayName": "S3", diff --git a/tests/test_litellm/proxy/test_pointfive_dashboard_config.py b/tests/test_litellm/proxy/test_pointfive_dashboard_config.py new file mode 100644 index 00000000000..9e46e7f0b3e --- /dev/null +++ b/tests/test_litellm/proxy/test_pointfive_dashboard_config.py @@ -0,0 +1,47 @@ +import json +from pathlib import Path + +import litellm +from litellm.integrations.custom_logger import CustomLogger + + +def _dashboard_configs() -> tuple[dict, ...]: + path = Path(litellm.__file__).parent / "integrations" / "callback_configs.json" + return tuple(json.loads(path.read_text())) + + +def _pointfive_config() -> dict: + return next(config for config in _dashboard_configs() if config["id"] == "pointfive") + + +def test_pointfive_appears_in_the_dashboard_callback_dropdown(): + """The dropdown is served from callback_configs.json, so an entry only in the dashboard source is invisible.""" + entry = _pointfive_config() + + assert entry["displayName"] == "PointFive" + assert entry["supports_key_team_logging"] is False + assert entry["dynamic_params"]["POINTFIVE_API_KEY"]["required"] is True + assert entry["dynamic_params"]["POINTFIVE_API_KEY"]["type"] == "password" + assert entry["dynamic_params"]["POINTFIVE_API_URL"]["required"] is False + + +def test_the_dropdown_logo_asset_exists(): + """A logo the dashboard cannot resolve degrades silently to a letter tile.""" + logo = _pointfive_config()["logo"] + repo_root = Path(litellm.__file__).parent.parent + asset = repo_root / "ui" / "litellm-dashboard" / "public" / "assets" / "logos" / logo + + assert logo == "pointfive.png" + assert asset.is_file() + + +def test_the_dropdown_fields_are_the_env_vars_the_logger_reads(): + """ + The field names are the environment variables verbatim. + + The proxy would uppercase them either way, but naming them as stored means the edit + form finds the saved values and prefills them instead of showing blanks. + """ + fields = tuple(_pointfive_config()["dynamic_params"]) + + assert fields == tuple(CustomLogger.get_callback_env_vars("pointfive")) diff --git a/ui/litellm-dashboard/public/assets/logos/pointfive.png b/ui/litellm-dashboard/public/assets/logos/pointfive.png new file mode 100644 index 00000000000..4b7a6b8939e Binary files /dev/null and b/ui/litellm-dashboard/public/assets/logos/pointfive.png differ diff --git a/ui/litellm-dashboard/src/components/callback_info_helpers.tsx b/ui/litellm-dashboard/src/components/callback_info_helpers.tsx index dfa35de1b34..8e343e1a6e0 100644 --- a/ui/litellm-dashboard/src/components/callback_info_helpers.tsx +++ b/ui/litellm-dashboard/src/components/callback_info_helpers.tsx @@ -9,6 +9,7 @@ import langsmithLogo from "../../public/assets/logos/langsmith.png"; import newrelicLogo from "../../public/assets/logos/newrelic.png"; import openmeterLogo from "../../public/assets/logos/openmeter.png"; import otelLogo from "../../public/assets/logos/otel.png"; +import pointfiveLogo from "../../public/assets/logos/pointfive.png"; interface CallbackConfig { id: string; @@ -162,6 +163,17 @@ export const CALLBACK_CONFIGS: CallbackConfig[] = [ }, description: "OpenTelemetry Logging Integration", }, + { + id: "pointfive", + displayName: "PointFive", + logo: pointfiveLogo.src, + supports_key_team_logging: false, + dynamic_params: { + POINTFIVE_API_KEY: "password", + POINTFIVE_API_URL: "text", + }, + description: "PointFive Logging Integration", + }, { id: "s3", displayName: "S3",