refactor(types): replace Any with proven types in 24 files (#46663)

* refactor(types): replace Any with proven types in 84 files

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor(types): keep vector store search locals untyped

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor(types): keep runtime payload validation out of the sweep

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor(types): keep only annotation-only Any fixes

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Mateo Wang 2026-10-15 06:10:12 -07:00 • committed by GitHub
parent 452ee4dc08
commit d1a7fcde8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 103 additions and 77 deletions

View file

@ -65,7 +65,7 @@ class AzureBlobCache(BaseCache):
print_verbose(f"Get Azure Blob Cache: key: {key}")
as_bytes: Final = self.container_client.download_blob(key).readall()
as_str: Final = as_bytes.decode("utf-8")
cached_response: Final = json.loads(as_str)
cached_response: Final[object] = json.loads(as_str)
verbose_logger.debug(
"Got Azure Blob Cache: key: %s, cached_response %s. Type Response %s",
@ -86,7 +86,7 @@ class AzureBlobCache(BaseCache):
blob: Final = await self.async_container_client.download_blob(key)
as_bytes: Final = await blob.readall()
as_str: Final = as_bytes.decode("utf-8")
cached_response: Final = json.loads(as_str)
cached_response: Final[object] = json.loads(as_str)
verbose_logger.debug(
"Got Azure Blob Cache: key: %s, cached_response %s. Type Response %s",
key,

View file

@ -10,7 +10,7 @@
## LiteLLM versions of the OpenAI Exception Types
import enum
from collections.abc import Sequence
from collections.abc import Mapping, Sequence
from typing import Any, Final
import httpx
@ -468,7 +468,7 @@ class RateLimitError(openai.RateLimitError):
category: str | RateLimitErrorCategory = (RateLimitErrorCategory.VENDOR_RATE_LIMIT),
rate_limit_type: str | RateLimitType | None = None,
headers: dict[str, str] | None = None,
detail: Any = None,
detail: object = None,
body: object | None = None,
):
self.status_code = 429
@ -1300,8 +1300,8 @@ class ModifyResponseException(Exception):
model: str,
request_data: dict[str, Any],
guardrail_name: str | None = None,
detection_info: dict[str, Any] | None = None,
original_response: Any | None = None,
detection_info: Mapping[str, object] | None = None,
original_response: object = None,
):
self.message = message
self.model = model
@ -1334,7 +1334,7 @@ class SensitiveDataRouteException(Exception):
route_to_model: str,
session_id: str,
guardrail_name: str | None = None,
detection_info: dict[str, Any] | None = None,
detection_info: Mapping[str, object] | None = None,
message: str | None = None,
sticky_session_routing: bool = True,
):

View file

@ -11,7 +11,7 @@ import time
import uuid as uuid_module
from collections.abc import Coroutine
from functools import partial
from typing import Any, Final, Literal, cast
from typing import Final, Literal, cast
import httpx
from openai import AsyncOpenAI, OpenAI
@ -163,7 +163,7 @@ def create_file(
extra_headers: dict[str, str] | None = None,
extra_body: dict[str, str] | None = None,
**kwargs,
) -> OpenAIFileObject | Coroutine[Any, Any, OpenAIFileObject]:
) -> OpenAIFileObject | Coroutine[object, None, OpenAIFileObject]:
"""
Files are used to upload documents that can be used with features like Assistants, Fine-tuning, and Batch API.
@ -867,8 +867,8 @@ def file_content(
) -> (
HttpxBinaryResponseContent
| FileContentStreamingResult
| Coroutine[Any, Any, HttpxBinaryResponseContent]
| Coroutine[Any, Any, FileContentStreamingResult]
| Coroutine[object, None, HttpxBinaryResponseContent]
| Coroutine[object, None, FileContentStreamingResult]
):
"""
Returns the contents of the specified file.

View file

@ -29,21 +29,25 @@ Events:
included only when content capture is enabled).
"""
from collections.abc import Callable
from datetime import datetime
from enum import Enum
from typing import TYPE_CHECKING, Any, Final
from typing import TYPE_CHECKING, Final, Protocol
from litellm.integrations.otel.mappers.utils import drop_none
from litellm.litellm_core_utils.safe_json_dumps import safe_dumps
if TYPE_CHECKING:
from opentelemetry._logs import SeverityNumber as _SeverityNumber
from opentelemetry.trace import Span as _Span
from litellm.integrations.opentelemetry import OpenTelemetryConfig
Span = _Span | Any
Span = _Span
else:
Span = Any
class Span(Protocol):
def set_attribute(self, key: str, value: object) -> None: ...
# OTEL_SEMCONV_STABILITY_OPT_IN is a comma-separated list of category-specific
@ -128,7 +132,7 @@ class OTELGenAISemconvMixin:
def _to_ns(self, dt: datetime) -> int: ...
def _otel_log_types(self) -> tuple[Any, Any]: ...
def _otel_log_types(self) -> tuple[Callable[..., object], type[_SeverityNumber]]: ...
@property
def _gen_ai_semconv_latest_experimental(self) -> bool:

View file

@ -292,7 +292,7 @@ class OpenTelemetryV2(CustomLogger):
# closed here. See ``log_pre_api_call``.
# ====================================================================== #
def log_pre_api_call(self, model, messages, kwargs):
def log_pre_api_call(self, model: str, messages: object, kwargs: Mapping[str, object]) -> None:
"""Open the LLM-call span at the call boundary.
Runs synchronously inside the request task, before the upstream call —
@ -354,7 +354,13 @@ class OpenTelemetryV2(CustomLogger):
_LLMCallSpan(span=span, start_time_ns=start_time_ns, provider=route.provider),
)
async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):
async def async_log_success_event(
self,
kwargs: Mapping[str, object],
response_obj: object,
start_time: datetime | float | None,
end_time: datetime | float | None,
) -> None:
if self._emit_mcp_tool_call(kwargs, start_time, end_time):
return
if self._emit_mcp_list_tools(kwargs, start_time, end_time):
@ -396,7 +402,13 @@ class OpenTelemetryV2(CustomLogger):
except Exception as exc:
verbose_logger.debug("OpenTelemetryV2: metric recording failed: %s", exc)
async def async_log_failure_event(self, kwargs, response_obj, start_time, end_time):
async def async_log_failure_event(
self,
kwargs: Mapping[str, object],
response_obj: object,
start_time: datetime | float | None,
end_time: datetime | float | None,
) -> None:
if self._emit_mcp_tool_call(kwargs, start_time, end_time):
return
if self._emit_mcp_list_tools(kwargs, start_time, end_time):

View file

@ -5,7 +5,7 @@ import re
import time
from collections.abc import Iterator, Mapping, Sequence
from datetime import datetime
from typing import TYPE_CHECKING, Any, Final, cast
from typing import TYPE_CHECKING, Any, Final, TypeAlias, cast
from litellm._logging import format_base64_size, verbose_logger
from litellm.constants import (
@ -28,7 +28,7 @@ if TYPE_CHECKING:
)
LiteLLMModelResponse = _ModelResponse
Span = _Span | Any
Span: TypeAlias = _Span
else:
LiteLLMModelResponse = Any
LiteLLMLoggingObject = Any

View file

@ -198,7 +198,7 @@ class AnthropicResponsesStreamWrapper:
item_id,
{"type": "redacted_thinking", "data": signature},
)
stop: Final = {"type": "content_block_stop", "index": redacted_idx}
stop: Final[dict[str, object]] = {"type": "content_block_stop", "index": redacted_idx}
self._chunk_queue.append(stop)
return
if signature is not None:

View file

@ -1,5 +1,5 @@
## This is a template base class to be used for adding new LLM providers via API calls
from typing import TYPE_CHECKING, Any, Union
from typing import TYPE_CHECKING, Union
import httpx
@ -76,11 +76,17 @@ class BaseLLM:
if hasattr(self, "_aclient_session"):
await self._aclient_session.aclose()
def validate_environment(self, *args, **kwargs) -> Any | None: # set up the environment required to run the model
def validate_environment(
self, *args, **kwargs
) -> object | None: # set up the environment required to run the model
return None
def completion(self, *args, **kwargs) -> Any: # logic for parsing in - calling - parsing out model completion calls
def completion(
self, *args, **kwargs
) -> object | None: # logic for parsing in - calling - parsing out model completion calls
return None
def embedding(self, *args, **kwargs) -> Any: # logic for parsing in - calling - parsing out model embedding calls
def embedding(
self, *args, **kwargs
) -> object | None: # logic for parsing in - calling - parsing out model embedding calls
return None

View file

@ -488,7 +488,7 @@ class BaseConfig(ABC):
"""
return True
def post_stream_processing(self, stream: Any) -> Any:
def post_stream_processing(self, stream: object) -> object:
"""Hook for providers to post-process streaming responses. Default: pass-through."""
return stream

View file

@ -313,7 +313,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM):
return None
try:
data: Final = json.loads(json_str)
data: Final[object] = json.loads(json_str)
# Skip non-dict data (some lines contain JSON strings)
return data if isinstance(data, dict) else None
except json.JSONDecodeError:
@ -391,7 +391,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM):
verbose_logger.warning("Failed to calculate token usage: %s", e)
return None
def _parse_json_response(self, response_json: dict) -> AgentCoreParsedResponse:
def _parse_json_response(self, response_json: object) -> AgentCoreParsedResponse:
"""
Parse direct JSON response (non-streaming).
@ -481,7 +481,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM):
if "application/json" in content_type:
# Direct JSON response
verbose_logger.debug("Parsing JSON response")
response_json: Final = raw_response.json()
response_json: Final[object] = raw_response.json()
verbose_logger.debug("Response JSON: %s", response_json)
return self._parse_json_response(response_json)
else:
@ -705,7 +705,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM):
)
try:
body: Final = response.read()
response_json: Final = json.loads(body)
response_json: Final[object] = json.loads(body)
except (json.JSONDecodeError, Exception) as e:
raise BedrockError(
status_code=response.status_code,
@ -927,7 +927,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM):
)
try:
body: Final = await response.aread()
response_json: Final = json.loads(body)
response_json: Final[object] = json.loads(body)
except (json.JSONDecodeError, Exception) as e:
raise BedrockError(
status_code=response.status_code,

View file

@ -317,7 +317,7 @@ class BlackForestLabsImageEditConfig(BaseImageEditConfig):
The response contains: {"status": "Ready", "result": {"sample": "https://..."}}
"""
try:
raw_response_data: Final = raw_response.json()
raw_response_data: Final[object] = raw_response.json()
except Exception as e:
raise BlackForestLabsError(
status_code=raw_response.status_code,

View file

@ -5,7 +5,8 @@ This module provides guardrail translation support for the rerank endpoint.
The handler processes only the 'query' parameter for guardrails.
"""
from typing import TYPE_CHECKING, Any, Final
from collections.abc import Mapping
from typing import TYPE_CHECKING, Final
from litellm._logging import verbose_proxy_logger
from litellm.llms.base_llm.guardrail_translation.base_translation import BaseTranslation
@ -14,6 +15,7 @@ from litellm.types.utils import GenericGuardrailAPIInputs
if TYPE_CHECKING:
from litellm.integrations.custom_guardrail import CustomGuardrail
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
from litellm.proxy._types import UserAPIKeyAuth
from litellm.types.rerank import RerankResponse
@ -44,7 +46,7 @@ class CohereRerankHandler(BaseTranslation):
data: dict,
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: "LiteLLMLoggingObj | None" = None,
) -> Any:
) -> Mapping[str, object]:
"""
Process input text fields ('query' and 'instruction') by applying
guardrails and writing the sanitized values back.
@ -96,9 +98,9 @@ class CohereRerankHandler(BaseTranslation):
response: "RerankResponse",
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: "LiteLLMLoggingObj | None" = None,
user_api_key_dict: Any | None = None,
user_api_key_dict: "UserAPIKeyAuth | None" = None,
request_data: dict | None = None,
) -> Any:
) -> "RerankResponse":
"""
Process output response - not applicable for rerank.

View file

@ -671,7 +671,7 @@ class BaseLLMAIOHTTPHandler:
status_code: Final = getattr(e, "status_code", 500)
error_headers = getattr(e, "headers", None)
error_text = getattr(e, "text", str(e))
error_response: Final = getattr(e, "response", None)
error_response: Final[object] = getattr(e, "response", None)
if error_headers is None and error_response:
error_headers = getattr(error_response, "headers", None)
if error_response and hasattr(error_response, "text"):

View file

@ -8,14 +8,14 @@
- async_streaming
"""
from collections.abc import AsyncIterator, Callable, Coroutine, Iterator
from collections.abc import AsyncIterator, Callable, Coroutine, Iterator, Sequence
from typing import (
TYPE_CHECKING,
Any,
Union,
)
import httpx
from openai.types.audio.transcription_create_params import FileTypes
from litellm.llms.custom_httpx.http_handler import AsyncHTTPHandler, HTTPHandler
from litellm.types.utils import GenericStreamingChunk
@ -103,7 +103,9 @@ class CustomLLM(BaseLLM):
headers={},
timeout: float | httpx.Timeout | None = None,
client: AsyncHTTPHandler | None = None,
) -> Coroutine[Any, Any, Union[ModelResponse, "CustomStreamWrapper"]] | Union[ModelResponse, "CustomStreamWrapper"]:
) -> (
Coroutine[None, None, Union[ModelResponse, "CustomStreamWrapper"]] | Union[ModelResponse, "CustomStreamWrapper"]
):
raise CustomLLMError(status_code=500, message="Not implemented yet!")
async def astreaming(
@ -188,7 +190,7 @@ class CustomLLM(BaseLLM):
def image_edit(
self,
model: str,
image: Any,
image: Sequence[FileTypes],
prompt: str | None,
model_response: ImageResponse,
api_key: str | None,
@ -203,7 +205,7 @@ class CustomLLM(BaseLLM):
async def aimage_edit(
self,
model: str,
image: Any,
image: Sequence[FileTypes],
prompt: str | None,
model_response: ImageResponse,
api_key: str | None,

View file

@ -89,9 +89,9 @@ class OCRHandler(BaseTranslation):
response: "OCRResponse",
guardrail_to_apply: "CustomGuardrail",
litellm_logging_obj: "LiteLLMLoggingObj | None" = None,
user_api_key_dict: Any | None = None,
user_api_key_dict: object | None = None,
request_data: dict | None = None,
) -> Any:
) -> "OCRResponse":
"""
Process OCR output by applying guardrails to extracted page text.

View file

@ -2,7 +2,7 @@
Translate from OpenAI's `/v1/chat/completions` to SAP Generative AI Hub's Orchestration Service`v2/completion`
"""
from collections.abc import AsyncIterator, Iterator
from collections.abc import AsyncIterator, Iterator, Mapping
from functools import cached_property
from typing import TYPE_CHECKING, Any, Final, Union
@ -55,14 +55,14 @@ _SAP_MODEL_PARAMS_EXCLUDED_KEYS: Final[frozenset[str]] = frozenset(
def validate_dict(
data: dict, model: type[BaseModel]
data: Mapping[str, object], model: type[BaseModel]
) -> dict: # mutable-ok: pydantic validation boundary; both input and output are untyped wire dicts
return model(**data).model_dump(by_alias=True, exclude_unset=True)
def _fold_message_cache_control(
message: dict[str, object],
) -> dict[str, object]:
message: Mapping[str, object],
) -> Mapping[str, object]:
"""Move a message-level cache_control marker onto the content block.
litellm's cache_control_injection_points hook attaches cache_control to the

View file

@ -65,6 +65,7 @@ from litellm.types.guardrails import (
LitellmParams,
PatchGuardrailRequest,
PiiAction,
PiiEntityCategoryMap,
PiiEntityType,
PresidioPresidioConfigModelUserInterface,
SupportedGuardrailIntegrations,
@ -1504,7 +1505,7 @@ async def get_guardrail_ui_settings() -> GuardrailUIAddGuardrailSettings:
)
from litellm.proxy.guardrails.guardrail_registry import guardrail_class_registry
category_maps: Final = [
category_maps: Final[list[PiiEntityCategoryMap]] = [
{
"category": category.value,
"entities": [entity.value for entity in entities],

View file

@ -56,10 +56,7 @@ class BaseRAGIngestion(ABC):
# Extract configs from options
self.ocr_config = ingest_options.get("ocr")
self.chunking_strategy: dict[str, Any] = cast(
dict[str, Any],
ingest_options.get("chunking_strategy") or {"type": "auto"},
)
self.chunking_strategy = ingest_options.get("chunking_strategy") or {"type": "auto"}
self.embedding_config = ingest_options.get("embedding")
self.vector_store_config: dict[str, Any] = cast(dict[str, Any], ingest_options.get("vector_store") or {})
self.ingest_name = ingest_options.get("name")

View file

@ -1,6 +1,6 @@
import asyncio
import contextvars
from collections.abc import Coroutine
from collections.abc import Awaitable
from functools import partial
from typing import Any, Final, Literal
@ -40,7 +40,7 @@ async def arerank(
return_documents: bool | None = None,
max_chunks_per_doc: int | None = None,
**kwargs,
) -> RerankResponse | Coroutine[Any, Any, RerankResponse]:
) -> RerankResponse | Awaitable[RerankResponse]:
"""
Async: Reranks a list of documents based on their relevance to the query
"""
@ -115,7 +115,7 @@ def rerank(
max_chunks_per_doc: int | None = None,
max_tokens_per_doc: int | None = None,
**kwargs,
) -> RerankResponse | Coroutine[Any, Any, RerankResponse]:
) -> RerankResponse | Awaitable[RerankResponse]:
"""
Reranks a list of documents based on their relevance to the query
"""

View file

@ -19,7 +19,7 @@ from litellm.litellm_core_utils.sensitive_data_masker import SensitiveDataMasker
if TYPE_CHECKING:
from opentelemetry.trace import Span as _Span
Span = _Span | Any
Span = _Span
else:
Span = Any

View file

@ -7,6 +7,8 @@ from enum import Enum
from types import MappingProxyType
from typing import TYPE_CHECKING, Any, Final
import httpx
import litellm
from litellm._logging import verbose_router_logger
from litellm.integrations.custom_logger import CustomLogger
@ -132,8 +134,8 @@ def _trigger_cooldown_for_failed_deployment(
if deployment_dict is not None
else None
)
exception_headers: Final = litellm.litellm_core_utils.exception_mapping_utils._get_response_headers(
original_exception=exception
exception_headers: Final[httpx.Headers | None] = (
litellm.litellm_core_utils.exception_mapping_utils._get_response_headers(original_exception=exception)
)
_get_retry_after: Final = (
litellm.utils._get_retry_after_from_exception_header # pyright: ignore[reportPrivateUsage] - as router.py

View file

@ -1,6 +1,6 @@
import builtins
from collections.abc import Mapping
from typing import Any, Literal
from typing import Literal
from pydantic import PrivateAttr
from typing_extensions import ReadOnly, TypedDict
@ -25,7 +25,7 @@ class ContainerObject(LiteLLMBaseModel):
expires_after: ExpiresAfter | None = None
last_active_at: int | None = None
name: str | None = None
_hidden_params: dict[str, Any] = PrivateAttr(default={})
_hidden_params: dict[str, builtins.object] = PrivateAttr(default={})
@property
def hidden_params(self) -> dict[str, builtins.object]: # mutable-ok: API requires mutation

View file

@ -1,6 +1,6 @@
from collections.abc import Iterable, Mapping, Sequence
from enum import Enum
from typing import Any, Final, Literal, TypeAlias
from typing import Final, Literal, TypeAlias
from pydantic import ConfigDict
from typing_extensions import NotRequired, ReadOnly, Required, TypedDict
@ -57,7 +57,7 @@ class AnthropicMessagesTool(TypedDict, total=False):
cache_control: dict | ChatCompletionCachedContent | None
defer_loading: bool
allowed_callers: list[str] | None
input_examples: list[dict[str, Any]] | None
input_examples: list[dict[str, object]] | None
eager_input_streaming: ReadOnly[bool]
@ -86,7 +86,7 @@ class AnthropicWebSearchTool(TypedDict, total=False):
user_location: AnthropicWebSearchUserLocation | None
defer_loading: bool | None
allowed_callers: list[str] | None
input_examples: list[dict[str, Any]] | None
input_examples: list[dict[str, object]] | None
class AnthropicHostedTools(TypedDict, total=False): # for bash_tool and text_editor
@ -95,7 +95,7 @@ class AnthropicHostedTools(TypedDict, total=False): # for bash_tool and text_ed
cache_control: dict | ChatCompletionCachedContent | None
defer_loading: bool | None
allowed_callers: list[str] | None
input_examples: list[dict[str, Any]] | None
input_examples: list[dict[str, object]] | None
class AnthropicCodeExecutionTool(TypedDict, total=False):
@ -104,7 +104,7 @@ class AnthropicCodeExecutionTool(TypedDict, total=False):
cache_control: dict | ChatCompletionCachedContent | None
defer_loading: bool | None
allowed_callers: list[str] | None
input_examples: list[dict[str, Any]] | None
input_examples: list[dict[str, object]] | None
class AnthropicMemoryTool(TypedDict, total=False):
@ -113,7 +113,7 @@ class AnthropicMemoryTool(TypedDict, total=False):
cache_control: dict | ChatCompletionCachedContent | None
defer_loading: bool | None
allowed_callers: list[str] | None
input_examples: list[dict[str, Any]] | None
input_examples: list[dict[str, object]] | None
class AnthropicToolSearchToolRegex(TypedDict, total=False):
@ -131,7 +131,7 @@ class AnthropicToolSearchToolBM25(TypedDict, total=False):
cache_control: dict | ChatCompletionCachedContent | None
defer_loading: bool | None
allowed_callers: list[str] | None
input_examples: list[dict[str, Any]] | None
input_examples: list[dict[str, object]] | None
ANTHROPIC_ADVISOR_TOOL_TYPE: Final = "advisor_20260301"
@ -421,13 +421,13 @@ class AnthropicMessagesRequestOptionalParams(TypedDict, total=False):
inference_geo: str | None
top_p: float | None
mcp_servers: list[AnthropicMcpServerTool] | None
context_management: dict[str, Any] | None
context_management: dict[str, object] | None
compaction: ReadOnly[AnthropicCompaction | None]
container: dict[str, Any] | None # Container config with skills for code execution
container: dict[str, object] | None # Container config with skills for code execution
output_format: AnthropicOutputSchema | None # Structured outputs support
speed: str | None # Fast mode support for Opus models
output_config: AnthropicOutputConfig | None # Configuration for Claude's output behavior
cache_control: dict[str, Any] | None # Automatic prompt caching
cache_control: dict[str, object] | None # Automatic prompt caching
reasoning_effort: str | None
safeguards: ReadOnly[list[dict[str, object]] | None]
service_tier: ReadOnly[str | None]
@ -680,7 +680,7 @@ class AnthropicResponseContentBlockToolUse(LiteLLMBaseModel):
id: str
name: str
input: dict
provider_specific_fields: dict[str, Any] | None = None
provider_specific_fields: dict[str, object] | None = None
model_config = ConfigDict(extra="allow") # Allow provider_specific_fields

View file

@ -156,7 +156,7 @@ class PolicyCreateRequest(LiteLLMBaseModel):
default=None,
description="Condition for when this policy applies.",
)
pipeline: dict[str, Any] | None = Field(
pipeline: dict[str, object] | None = Field(
default=None,
description="Optional guardrail pipeline for ordered execution. Contains 'mode' and 'steps'.",
)
@ -189,7 +189,7 @@ class PolicyUpdateRequest(LiteLLMBaseModel):
default=None,
description="Condition for when this policy applies.",
)
pipeline: dict[str, Any] | None = Field(
pipeline: dict[str, object] | None = Field(
default=None,
description="Optional guardrail pipeline for ordered execution. Contains 'mode' and 'steps'.",
)
@ -216,8 +216,8 @@ class PolicyDBResponse(LiteLLMBaseModel):
description: str | None = Field(default=None, description="Policy description.")
guardrails_add: list[str] = Field(default_factory=list, description="Guardrails to add.")
guardrails_remove: list[str] = Field(default_factory=list, description="Guardrails to remove.")
condition: dict[str, Any] | None = Field(default=None, description="Policy condition.")
pipeline: dict[str, Any] | None = Field(default=None, description="Optional guardrail pipeline.")
condition: dict[str, object] | None = Field(default=None, description="Policy condition.")
pipeline: dict[str, object] | None = Field(default=None, description="Optional guardrail pipeline.")
created_at: datetime | None = Field(default=None, description="When the policy was created.")
updated_at: datetime | None = Field(default=None, description="When the policy was last updated.")
created_by: str | None = Field(default=None, description="Who created the policy.")
@ -272,7 +272,7 @@ class PolicyVersionCompareResponse(LiteLLMBaseModel):
version_a: PolicyDBResponse = Field(description="First version.")
version_b: PolicyDBResponse = Field(description="Second version.")
field_diffs: dict[str, dict[str, Any]] = Field(
field_diffs: dict[str, dict[str, object]] = Field(
default_factory=dict,
description="Field name -> {version_a: val, version_b: val} for differing fields.",
)