107 lines
3.9 KiB
Python
107 lines
3.9 KiB
Python
from __future__ import annotations
|
|
from typing_extensions import deprecated
|
|
from typing import Any, Dict, List, Optional, Union
|
|
|
|
from pydantic import Field, field_serializer, field_validator
|
|
|
|
from guardrails.classes.generic.arbitrary_model import ArbitraryModel
|
|
from guardrails.classes.llm.prompt_callable import PromptCallableBase
|
|
from guardrails.prompt.prompt import Prompt
|
|
from guardrails.prompt.messages import Messages
|
|
from guardrails.prompt.instructions import Instructions
|
|
|
|
|
|
class Inputs(ArbitraryModel):
|
|
"""Inputs represent the input data that is passed into the validation
|
|
loop."""
|
|
|
|
llm_api: Optional[PromptCallableBase] = Field(
|
|
description="The constructed class for calling the LLM.", default=None
|
|
)
|
|
llm_output: Optional[str] = Field(
|
|
description="The string output from an external LLM call"
|
|
"provided by the user via Guard.parse.",
|
|
default=None,
|
|
)
|
|
messages: Optional[
|
|
Union[List[Dict[str, Union[str, Prompt, Instructions]]], Messages]
|
|
] = Field(
|
|
description="The message history provided by the user for chat model calls.",
|
|
default=None,
|
|
)
|
|
prompt_params: Optional[Dict] = Field(
|
|
description="The parameters provided by the user"
|
|
"that will be formatted into the final LLM prompt.",
|
|
default=None,
|
|
)
|
|
num_reasks: Optional[int] = Field(
|
|
description="The total number of reasks allowed; user provided or defaulted.",
|
|
default=None,
|
|
)
|
|
metadata: Optional[Dict[str, Any]] = Field(
|
|
description="The metadata provided by the user to be used during validation.",
|
|
default=None,
|
|
)
|
|
full_schema_reask: Optional[bool] = Field(
|
|
description="Whether to perform reasks across the entire schema"
|
|
"or at the field level.",
|
|
default=None,
|
|
)
|
|
stream: Optional[bool] = Field(
|
|
description="Whether to use streaming.",
|
|
default=False,
|
|
)
|
|
|
|
@field_serializer("llm_api")
|
|
def serialize_llm_api(self, llm_api: PromptCallableBase | None) -> str | None:
|
|
if llm_api:
|
|
return str(llm_api)
|
|
return None
|
|
|
|
@field_validator("llm_api", mode="before")
|
|
@classmethod
|
|
def deserialize_llm_api(cls, llm_api: Any) -> PromptCallableBase | None:
|
|
if isinstance(llm_api, PromptCallableBase):
|
|
return llm_api
|
|
# Note: We can potentially identify the correct
|
|
# PrompCallable Class and reconstruct it,
|
|
# but the previous implementation always just returned None.
|
|
return None
|
|
|
|
@field_serializer("messages")
|
|
def serialize_messages(
|
|
self, messages: list[dict[str, str | Prompt | Instructions]] | Messages | None
|
|
) -> list[dict[str, Any]] | None:
|
|
# Legacy serialization logic from previous to_interface implementation
|
|
# TODO: Just make Prompt, Instructions, and Messages pydantic models
|
|
if messages:
|
|
serialized_messages = []
|
|
for msg in messages:
|
|
ser_msg = {**msg}
|
|
content = ser_msg.get("content")
|
|
if content:
|
|
ser_msg["content"] = (
|
|
content.source if isinstance(content, Prompt) else content
|
|
)
|
|
serialized_messages.append(ser_msg)
|
|
return serialized_messages
|
|
return None
|
|
|
|
@deprecated("Use Inputs.model_dump() instead.")
|
|
def to_interface(self) -> dict[str, Any]:
|
|
return self.model_dump(exclude_none=True, by_alias=True)
|
|
|
|
@deprecated("Use Inputs.model_dump() instead.")
|
|
def to_dict(self) -> dict[str, Any]:
|
|
return self.model_dump(exclude_none=True, by_alias=True)
|
|
|
|
@classmethod
|
|
@deprecated("Use Inputs.model_validate() instead.")
|
|
def from_interface(cls, i_inputs: Any) -> "Inputs":
|
|
return cls.model_validate(i_inputs)
|
|
|
|
@classmethod
|
|
@deprecated("Use Inputs.model_validate() instead.")
|
|
def from_dict(cls, obj: Any) -> "Inputs":
|
|
return cls.model_validate(obj)
|