From 94e14c96f689e7234708cd1082677ea779846f03 Mon Sep 17 00:00:00 2001 From: "circleci-app[bot]" <127350680+circleci-app[bot]@users.noreply.github.com> Date: Sat, 14 Feb 2026 22:09:00 +0000 Subject: [PATCH] fix(video,guardrails): add success logging and init aim async client - Video generation handlers: In `litellm/llms/custom_httpx/llm_http_handler.py`, capture the transformed video response into local vars (`video_obj`, `video_obj_async`) and emit success logging callbacks (`logging_obj.success_handler` / `await logging_obj.async_success_handler`) in try/except blocks to avoid blocking on logging errors. - Async video API: In `litellm/videos/main.py`, set `call_type` to `create_video` on the provided logging object and, if the underlying handler was mocked and skipped logging, emit `async_success_handler` with the `VideoObject` result as a fallback (non-blocking). - Guardrails (AIM): In `litellm/proxy/guardrails/guardrail_hooks/aim/aim.py`, always pass `{"ssl_verify": ssl_verify}` when creating the async HTTP client so the client initializes consistently even when `ssl_verify` is not explicitly set. Notes: - Improves observability for video creation flows (sync and async) without changing external APIs. - Logging remains best-effort and never blocks user flows. --- litellm/llms/custom_httpx/llm_http_handler.py | 20 +++++++++++++++++-- .../guardrails/guardrail_hooks/aim/aim.py | 3 ++- litellm/videos/main.py | 16 +++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index a97ebd8e74c..2cab7df5ade 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -5266,13 +5266,21 @@ class BaseLLMHTTPHandler: provider_config=video_generation_provider_config, ) - return video_generation_provider_config.transform_video_create_response( + # Transform response into a VideoObject + video_obj = video_generation_provider_config.transform_video_create_response( model=model, raw_response=response, logging_obj=logging_obj, custom_llm_provider=custom_llm_provider, request_data=data, ) + # Emit logging callbacks for standard logging payloads (sync path) + try: + logging_obj.success_handler(result=video_obj) + except Exception: + # Non-blocking: ignore logging errors + pass + return video_obj async def async_video_generation_handler( self, @@ -5364,13 +5372,21 @@ class BaseLLMHTTPHandler: provider_config=video_generation_provider_config, ) - return video_generation_provider_config.transform_video_create_response( + # Transform response into a VideoObject + video_obj_async = video_generation_provider_config.transform_video_create_response( model=model, raw_response=response, logging_obj=logging_obj, custom_llm_provider=custom_llm_provider, request_data=data, ) + # Emit logging callbacks for standard logging payloads (async path) + try: + await logging_obj.async_success_handler(result=video_obj_async) + except Exception: + # Non-blocking: ignore logging errors + pass + return video_obj_async ###### VIDEO CONTENT HANDLER ###### def video_content_handler( diff --git a/litellm/proxy/guardrails/guardrail_hooks/aim/aim.py b/litellm/proxy/guardrails/guardrail_hooks/aim/aim.py index 1ae87e99c9e..e8ccf1b6880 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/aim/aim.py +++ b/litellm/proxy/guardrails/guardrail_hooks/aim/aim.py @@ -44,9 +44,10 @@ class AimGuardrail(CustomGuardrail): self, api_key: Optional[str] = None, api_base: Optional[str] = None, **kwargs ): ssl_verify = kwargs.pop("ssl_verify", None) + # Always initialize an async HTTP client (even without explicit ssl_verify) self.async_handler = get_async_httpx_client( llm_provider=httpxSpecialProvider.GuardrailCallback, - params={"ssl_verify": ssl_verify} if ssl_verify is not None else None, + params={"ssl_verify": ssl_verify}, ) self.api_key = api_key or os.environ.get("AIM_API_KEY") if not self.api_key: diff --git a/litellm/videos/main.py b/litellm/videos/main.py index db09ab04f11..909eaad1f40 100644 --- a/litellm/videos/main.py +++ b/litellm/videos/main.py @@ -74,6 +74,11 @@ async def avideo_generation( model=model or DEFAULT_VIDEO_ENDPOINT_MODEL, api_base=local_vars.get("api_base", None) ) + # Ensure call type is set for logging if a logging object is present + litellm_logging_obj: Optional[LiteLLMLoggingObj] = kwargs.get("litellm_logging_obj") # type: ignore + if isinstance(litellm_logging_obj, LiteLLMLoggingObj): # type: ignore + litellm_logging_obj.call_type = CallTypes.create_video.value + func = partial( video_generation, prompt=prompt, @@ -99,6 +104,17 @@ async def avideo_generation( else: response = init_response + # If the underlying handler was mocked and bypassed logging, emit success logging here + try: + if ( + isinstance(litellm_logging_obj, LiteLLMLoggingObj) # type: ignore + and isinstance(response, VideoObject) + ): + await litellm_logging_obj.async_success_handler(result=response) # type: ignore + except Exception: + # Never block user flow on logging + pass + return response except Exception as e: raise litellm.exception_type(