diff --git a/.fern/metadata.json b/.fern/metadata.json index 04f281f..3940dc0 100644 --- a/.fern/metadata.json +++ b/.fern/metadata.json @@ -9,9 +9,10 @@ "filename": "client.py" }, "pydantic_config": { - "skip_validation": true + "skip_validation": true, + "use_pydantic_field_aliases": true }, "exclude_types_from_init_exports": true }, - "originGitCommit": "8994613e045586856dab7b5eab43920dce0154c4" + "originGitCommit": "91f10c5510b7b9689bba8fa654f1da228ac7ad6e" } \ No newline at end of file diff --git a/.fern/replay.lock b/.fern/replay.lock index 07a3233..a15d17e 100644 --- a/.fern/replay.lock +++ b/.fern/replay.lock @@ -30,14 +30,20 @@ generations: cli_version: unknown generator_versions: fernapi/fern-python-sdk: 4.37.0 -current_generation: 74db6c7a490c2ed50d9b514d8af87dbd54192e4e + - commit_sha: 2564d6c4d002d3e6b338b2ac6f6f662d011d532c + tree_hash: 938269a14abe315fb6636e114b92eda79c3435a8 + timestamp: 2026-08-06T06:28:37.161Z + cli_version: unknown + generator_versions: + fernapi/fern-python-sdk: 4.37.0 +current_generation: 2564d6c4d002d3e6b338b2ac6f6f662d011d532c patches: - id: patch-13d8e068 content_hash: sha256:97d879ab169016b9abaf1866427a8ebc45af608f69e063a07e5126c9613c329b original_commit: 13d8e0683ffa08bcfc9a381eb9604adf5abdbe0b original_message: "chore: ignore local venv and planning docs" original_author: plutoless - base_generation: 74db6c7a490c2ed50d9b514d8af87dbd54192e4e + base_generation: 2564d6c4d002d3e6b338b2ac6f6f662d011d532c files: - .gitignore patch_content: | diff --git a/src/agora_agent/agents/raw_client.py b/src/agora_agent/agents/raw_client.py index dc85890..59983f9 100644 --- a/src/agora_agent/agents/raw_client.py +++ b/src/agora_agent/agents/raw_client.py @@ -9,7 +9,6 @@ from ..core.jsonable_encoder import jsonable_encoder from ..core.pagination import AsyncPager, SyncPager from ..core.request_options import RequestOptions -from ..core.serialization import convert_and_respect_annotation_metadata from ..core.unchecked_base_model import construct_type from .types.get_agents_response import GetAgentsResponse from .types.get_history_agents_response import GetHistoryAgentsResponse @@ -82,9 +81,7 @@ def start( "name": name, "preset": preset, "pipeline_id": pipeline_id, - "properties": convert_and_respect_annotation_metadata( - object_=properties, annotation=StartAgentsRequestProperties, direction="write" - ), + "properties": properties, }, headers={ "content-type": "application/json", @@ -420,9 +417,7 @@ def update( f"v2/projects/{jsonable_encoder(appid)}/agents/{jsonable_encoder(agent_id)}/update", method="POST", json={ - "properties": convert_and_respect_annotation_metadata( - object_=properties, annotation=UpdateAgentsRequestProperties, direction="write" - ), + "properties": properties, }, headers={ "content-type": "application/json", @@ -623,9 +618,7 @@ async def start( "name": name, "preset": preset, "pipeline_id": pipeline_id, - "properties": convert_and_respect_annotation_metadata( - object_=properties, annotation=StartAgentsRequestProperties, direction="write" - ), + "properties": properties, }, headers={ "content-type": "application/json", @@ -964,9 +957,7 @@ async def update( f"v2/projects/{jsonable_encoder(appid)}/agents/{jsonable_encoder(agent_id)}/update", method="POST", json={ - "properties": convert_and_respect_annotation_metadata( - object_=properties, annotation=UpdateAgentsRequestProperties, direction="write" - ), + "properties": properties, }, headers={ "content-type": "application/json", diff --git a/src/agora_agent/agents/types/get_turns_agents_response_turns_item_metrics.py b/src/agora_agent/agents/types/get_turns_agents_response_turns_item_metrics.py index ae5002c..ebcefcb 100644 --- a/src/agora_agent/agents/types/get_turns_agents_response_turns_item_metrics.py +++ b/src/agora_agent/agents/types/get_turns_agents_response_turns_item_metrics.py @@ -3,9 +3,7 @@ import typing import pydantic -import typing_extensions from ...core.pydantic_utilities import IS_PYDANTIC_V2 -from ...core.serialization import FieldMetadata from ...core.unchecked_base_model import UncheckedBaseModel from .get_turns_agents_response_turns_item_metrics_segmented_latency_ms_item import ( GetTurnsAgentsResponseTurnsItemMetricsSegmentedLatencyMsItem, @@ -17,9 +15,7 @@ class GetTurnsAgentsResponseTurnsItemMetrics(UncheckedBaseModel): Latency metrics for the turn. """ - e_2_e_latency_ms: typing_extensions.Annotated[typing.Optional[int], FieldMetadata(alias="e2e_latency_ms")] = ( - pydantic.Field(default=None) - ) + e_2_e_latency_ms: typing.Optional[int] = pydantic.Field(alias="e2e_latency_ms", default=None) """ The end-to-end latency in milliseconds for the turn. """ diff --git a/src/agora_agent/agents/types/list_agents_response_data.py b/src/agora_agent/agents/types/list_agents_response_data.py index af31633..c4c008e 100644 --- a/src/agora_agent/agents/types/list_agents_response_data.py +++ b/src/agora_agent/agents/types/list_agents_response_data.py @@ -3,9 +3,7 @@ import typing import pydantic -import typing_extensions from ...core.pydantic_utilities import IS_PYDANTIC_V2 -from ...core.serialization import FieldMetadata from ...core.unchecked_base_model import UncheckedBaseModel from .list_agents_response_data_list_item import ListAgentsResponseDataListItem @@ -20,9 +18,7 @@ class ListAgentsResponseData(UncheckedBaseModel): The number of agents returned. """ - list_: typing_extensions.Annotated[typing.List[ListAgentsResponseDataListItem], FieldMetadata(alias="list")] = ( - pydantic.Field() - ) + list_: typing.List[ListAgentsResponseDataListItem] = pydantic.Field(alias="list") """ A list of agents that meets the criteria. """ diff --git a/src/agora_agent/core/pydantic_utilities.py b/src/agora_agent/core/pydantic_utilities.py index 185e5c4..1da6f10 100644 --- a/src/agora_agent/core/pydantic_utilities.py +++ b/src/agora_agent/core/pydantic_utilities.py @@ -3,7 +3,7 @@ # nopycln: file import datetime as dt from collections import defaultdict -from typing import Any, Callable, ClassVar, Dict, List, Mapping, Optional, Set, Tuple, Type, TypeVar, Union, cast +from typing import Any, Callable, Dict, List, Mapping, Tuple, Type, TypeVar, Union, cast import pydantic @@ -29,7 +29,6 @@ from pydantic.typing import is_union as is_union # type: ignore[no-redef] from .datetime_utils import serialize_datetime -from .serialization import convert_and_respect_annotation_metadata from typing_extensions import TypeAlias T = TypeVar("T") @@ -37,11 +36,10 @@ def parse_obj_as(type_: Type[T], object_: Any) -> T: - dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read") if IS_PYDANTIC_V2: adapter = pydantic.TypeAdapter(type_) # type: ignore[attr-defined] - return adapter.validate_python(dealiased_object) - return pydantic.parse_obj_as(type_, dealiased_object) + return adapter.validate_python(object_) + return pydantic.parse_obj_as(type_, object_) def to_jsonable_with_fallback(obj: Any, fallback_serializer: Callable[[Any], Any]) -> Any: @@ -53,35 +51,13 @@ def to_jsonable_with_fallback(obj: Any, fallback_serializer: Callable[[Any], Any class UniversalBaseModel(pydantic.BaseModel): - if IS_PYDANTIC_V2: - model_config: ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict( # type: ignore[typeddict-unknown-key] - # Allow fields beginning with `model_` to be used in the model - protected_namespaces=(), - ) - - @pydantic.model_serializer(mode="plain", when_used="json") # type: ignore[attr-defined] - def serialize_model(self) -> Any: # type: ignore[name-defined] - serialized = self.dict() # type: ignore[attr-defined] - data = {k: serialize_datetime(v) if isinstance(v, dt.datetime) else v for k, v in serialized.items()} - return data - - else: - - class Config: - smart_union = True - json_encoders = {dt.datetime: serialize_datetime} - - @classmethod - def model_construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model": - dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read") - return cls.construct(_fields_set, **dealiased_object) - - @classmethod - def construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model": - dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read") - if IS_PYDANTIC_V2: - return super().model_construct(_fields_set, **dealiased_object) # type: ignore[misc] - return super().construct(_fields_set, **dealiased_object) + class Config: + populate_by_name = True + smart_union = True + allow_population_by_field_name = True + json_encoders = {dt.datetime: serialize_datetime} + # Allow fields beginning with `model_` to be used in the model + protected_namespaces = () def json(self, **kwargs: Any) -> str: kwargs_with_defaults = { @@ -116,41 +92,35 @@ def dict(self, **kwargs: Any) -> Dict[str, Any]: "exclude_none": True, "exclude_unset": False, } - dict_dump = deep_union_pydantic_dicts( + return deep_union_pydantic_dicts( super().model_dump(**kwargs_with_defaults_exclude_unset), # type: ignore[misc] super().model_dump(**kwargs_with_defaults_exclude_none), # type: ignore[misc] ) - else: - _fields_set = self.__fields_set__.copy() - - fields = _get_model_fields(self.__class__) - for name, field in fields.items(): - if name not in _fields_set: - default = _get_field_default(field) + _fields_set = self.__fields_set__.copy() - # If the default values are non-null act like they've been set - # This effectively allows exclude_unset to work like exclude_none where - # the latter passes through intentionally set none values. - if default is not None or ("exclude_unset" in kwargs and not kwargs["exclude_unset"]): - _fields_set.add(name) + fields = _get_model_fields(self.__class__) + for name, field in fields.items(): + if name not in _fields_set: + default = _get_field_default(field) - if default is not None: - self.__fields_set__.add(name) + # If the default values are non-null act like they've been set + # This effectively allows exclude_unset to work like exclude_none where + # the latter passes through intentionally set none values. + if default is not None or ("exclude_unset" in kwargs and not kwargs["exclude_unset"]): + _fields_set.add(name) - kwargs_with_defaults_exclude_unset_include_fields = { - "by_alias": True, - "exclude_unset": True, - "include": _fields_set, - **kwargs, - } + if default is not None: + self.__fields_set__.add(name) - dict_dump = super().dict(**kwargs_with_defaults_exclude_unset_include_fields) + kwargs_with_defaults_exclude_unset_include_fields = { + "by_alias": True, + "exclude_unset": True, + "include": _fields_set, + **kwargs, + } - return cast( - Dict[str, Any], - convert_and_respect_annotation_metadata(object_=dict_dump, annotation=self.__class__, direction="write"), - ) + return super().dict(**kwargs_with_defaults_exclude_unset_include_fields) def _union_list_of_pydantic_dicts(source: List[Any], destination: List[Any]) -> List[Any]: @@ -184,10 +154,10 @@ def deep_union_pydantic_dicts(source: Dict[str, Any], destination: Dict[str, Any if IS_PYDANTIC_V2: - class V2RootModel(UniversalBaseModel, pydantic.RootModel): # type: ignore[misc, name-defined, type-arg] + class V2RootModel(UniversalBaseModel, pydantic.RootModel): # type: ignore[name-defined, type-arg] pass - UniversalRootModel: TypeAlias = V2RootModel # type: ignore[misc] + UniversalRootModel: TypeAlias = V2RootModel else: UniversalRootModel: TypeAlias = UniversalBaseModel # type: ignore[misc, no-redef] diff --git a/src/agora_agent/phone_numbers/raw_client.py b/src/agora_agent/phone_numbers/raw_client.py index 6a8253a..ab93445 100644 --- a/src/agora_agent/phone_numbers/raw_client.py +++ b/src/agora_agent/phone_numbers/raw_client.py @@ -8,7 +8,6 @@ from ..core.http_response import AsyncHttpResponse, HttpResponse from ..core.jsonable_encoder import jsonable_encoder from ..core.request_options import RequestOptions -from ..core.serialization import convert_and_respect_annotation_metadata from ..core.unchecked_base_model import construct_type from .types.add_phone_numbers_request_inbound_config import AddPhoneNumbersRequestInboundConfig from .types.add_phone_numbers_request_outbound_config import AddPhoneNumbersRequestOutboundConfig @@ -121,12 +120,8 @@ def add( "label": label, "inbound": inbound, "outbound": outbound, - "inbound_config": convert_and_respect_annotation_metadata( - object_=inbound_config, annotation=AddPhoneNumbersRequestInboundConfig, direction="write" - ), - "outbound_config": convert_and_respect_annotation_metadata( - object_=outbound_config, annotation=AddPhoneNumbersRequestOutboundConfig, direction="write" - ), + "inbound_config": inbound_config, + "outbound_config": outbound_config, }, headers={ "content-type": "application/json", @@ -256,16 +251,8 @@ def update( f"v2/phone-numbers/{jsonable_encoder(phone_number)}", method="PATCH", json={ - "inbound_config": convert_and_respect_annotation_metadata( - object_=inbound_config, - annotation=typing.Optional[UpdatePhoneNumbersRequestInboundConfig], - direction="write", - ), - "outbound_config": convert_and_respect_annotation_metadata( - object_=outbound_config, - annotation=typing.Optional[UpdatePhoneNumbersRequestOutboundConfig], - direction="write", - ), + "inbound_config": inbound_config, + "outbound_config": outbound_config, }, headers={ "content-type": "application/json", @@ -386,12 +373,8 @@ async def add( "label": label, "inbound": inbound, "outbound": outbound, - "inbound_config": convert_and_respect_annotation_metadata( - object_=inbound_config, annotation=AddPhoneNumbersRequestInboundConfig, direction="write" - ), - "outbound_config": convert_and_respect_annotation_metadata( - object_=outbound_config, annotation=AddPhoneNumbersRequestOutboundConfig, direction="write" - ), + "inbound_config": inbound_config, + "outbound_config": outbound_config, }, headers={ "content-type": "application/json", @@ -521,16 +504,8 @@ async def update( f"v2/phone-numbers/{jsonable_encoder(phone_number)}", method="PATCH", json={ - "inbound_config": convert_and_respect_annotation_metadata( - object_=inbound_config, - annotation=typing.Optional[UpdatePhoneNumbersRequestInboundConfig], - direction="write", - ), - "outbound_config": convert_and_respect_annotation_metadata( - object_=outbound_config, - annotation=typing.Optional[UpdatePhoneNumbersRequestOutboundConfig], - direction="write", - ), + "inbound_config": inbound_config, + "outbound_config": outbound_config, }, headers={ "content-type": "application/json", diff --git a/src/agora_agent/telephony/raw_client.py b/src/agora_agent/telephony/raw_client.py index b9be934..63a79d2 100644 --- a/src/agora_agent/telephony/raw_client.py +++ b/src/agora_agent/telephony/raw_client.py @@ -9,7 +9,6 @@ from ..core.jsonable_encoder import jsonable_encoder from ..core.pagination import AsyncPager, SyncPager from ..core.request_options import RequestOptions -from ..core.serialization import convert_and_respect_annotation_metadata from ..core.unchecked_base_model import construct_type from .types.call_telephony_request_properties import CallTelephonyRequestProperties from .types.call_telephony_request_sip import CallTelephonyRequestSip @@ -170,13 +169,9 @@ def call( method="POST", json={ "name": name, - "sip": convert_and_respect_annotation_metadata( - object_=sip, annotation=CallTelephonyRequestSip, direction="write" - ), + "sip": sip, "pipeline_id": pipeline_id, - "properties": convert_and_respect_annotation_metadata( - object_=properties, annotation=CallTelephonyRequestProperties, direction="write" - ), + "properties": properties, }, headers={ "content-type": "application/json", @@ -438,13 +433,9 @@ async def call( method="POST", json={ "name": name, - "sip": convert_and_respect_annotation_metadata( - object_=sip, annotation=CallTelephonyRequestSip, direction="write" - ), + "sip": sip, "pipeline_id": pipeline_id, - "properties": convert_and_respect_annotation_metadata( - object_=properties, annotation=CallTelephonyRequestProperties, direction="write" - ), + "properties": properties, }, headers={ "content-type": "application/json", diff --git a/src/agora_agent/telephony/types/list_telephony_response_data.py b/src/agora_agent/telephony/types/list_telephony_response_data.py index 452a84b..d187468 100644 --- a/src/agora_agent/telephony/types/list_telephony_response_data.py +++ b/src/agora_agent/telephony/types/list_telephony_response_data.py @@ -3,9 +3,7 @@ import typing import pydantic -import typing_extensions from ...core.pydantic_utilities import IS_PYDANTIC_V2 -from ...core.serialization import FieldMetadata from ...core.unchecked_base_model import UncheckedBaseModel from .list_telephony_response_data_list_item import ListTelephonyResponseDataListItem @@ -20,9 +18,7 @@ class ListTelephonyResponseData(UncheckedBaseModel): The number of calls returned in this response. """ - list_: typing_extensions.Annotated[typing.List[ListTelephonyResponseDataListItem], FieldMetadata(alias="list")] = ( - pydantic.Field() - ) + list_: typing.List[ListTelephonyResponseDataListItem] = pydantic.Field(alias="list") """ A list of calls that meet the criteria. """ diff --git a/src/agora_agent/types/google_tts_params.py b/src/agora_agent/types/google_tts_params.py index 4a9ee38..f771455 100644 --- a/src/agora_agent/types/google_tts_params.py +++ b/src/agora_agent/types/google_tts_params.py @@ -3,9 +3,7 @@ import typing import pydantic -import typing_extensions from ..core.pydantic_utilities import IS_PYDANTIC_V2 -from ..core.serialization import FieldMetadata from ..core.unchecked_base_model import UncheckedBaseModel from .google_tts_audio_config import GoogleTtsAudioConfig from .google_tts_voice_selection_params import GoogleTtsVoiceSelectionParams @@ -21,12 +19,8 @@ class GoogleTtsParams(UncheckedBaseModel): Google Cloud service account credentials JSON string """ - voice_selection_params: typing_extensions.Annotated[ - GoogleTtsVoiceSelectionParams, FieldMetadata(alias="VoiceSelectionParams") - ] - audio_config: typing_extensions.Annotated[ - typing.Optional[GoogleTtsAudioConfig], FieldMetadata(alias="AudioConfig") - ] = None + voice_selection_params: GoogleTtsVoiceSelectionParams = pydantic.Field(alias="VoiceSelectionParams") + audio_config: typing.Optional[GoogleTtsAudioConfig] = pydantic.Field(alias="AudioConfig", default=None) if IS_PYDANTIC_V2: model_config: typing.ClassVar[pydantic.ConfigDict] = pydantic.ConfigDict(extra="allow", frozen=True) # type: ignore # Pydantic v2 diff --git a/src/agora_agent/types/murf_tts_params.py b/src/agora_agent/types/murf_tts_params.py index 78f78d8..bd00ac6 100644 --- a/src/agora_agent/types/murf_tts_params.py +++ b/src/agora_agent/types/murf_tts_params.py @@ -3,9 +3,7 @@ import typing import pydantic -import typing_extensions from ..core.pydantic_utilities import IS_PYDANTIC_V2 -from ..core.serialization import FieldMetadata from ..core.unchecked_base_model import UncheckedBaseModel @@ -24,9 +22,7 @@ class MurfTtsParams(UncheckedBaseModel): WebSocket endpoint for streaming TTS output """ - voice_id: typing_extensions.Annotated[typing.Optional[str], FieldMetadata(alias="voiceId")] = pydantic.Field( - default=None - ) + voice_id: typing.Optional[str] = pydantic.Field(alias="voiceId", default=None) """ Voice ID (e.g., Matthew) """ diff --git a/src/agora_agent/types/rime_tts_params.py b/src/agora_agent/types/rime_tts_params.py index 75a8d2b..c134a84 100644 --- a/src/agora_agent/types/rime_tts_params.py +++ b/src/agora_agent/types/rime_tts_params.py @@ -3,9 +3,7 @@ import typing import pydantic -import typing_extensions from ..core.pydantic_utilities import IS_PYDANTIC_V2 -from ..core.serialization import FieldMetadata from ..core.unchecked_base_model import UncheckedBaseModel @@ -24,7 +22,7 @@ class RimeTtsParams(UncheckedBaseModel): Rime speaker ID """ - model_id: typing_extensions.Annotated[str, FieldMetadata(alias="modelId")] = pydantic.Field() + model_id: str = pydantic.Field(alias="modelId") """ Rime TTS model ID """ diff --git a/src/agora_agent/types/sensetime_avatar_params.py b/src/agora_agent/types/sensetime_avatar_params.py index d777132..329455f 100644 --- a/src/agora_agent/types/sensetime_avatar_params.py +++ b/src/agora_agent/types/sensetime_avatar_params.py @@ -3,9 +3,7 @@ import typing import pydantic -import typing_extensions from ..core.pydantic_utilities import IS_PYDANTIC_V2 -from ..core.serialization import FieldMetadata from ..core.unchecked_base_model import UncheckedBaseModel from .sensetime_avatar_params_scene_list_item import SensetimeAvatarParamsSceneListItem @@ -25,7 +23,7 @@ class SensetimeAvatarParams(UncheckedBaseModel): Numeric Agora UID string used by the avatar service. """ - app_id: typing_extensions.Annotated[str, FieldMetadata(alias="appId")] = pydantic.Field() + app_id: str = pydantic.Field(alias="appId") """ SenseTime application ID. """ @@ -35,9 +33,7 @@ class SensetimeAvatarParams(UncheckedBaseModel): SenseTime application key. """ - scene_list: typing_extensions.Annotated[ - typing.List[SensetimeAvatarParamsSceneListItem], FieldMetadata(alias="sceneList") - ] = pydantic.Field() + scene_list: typing.List[SensetimeAvatarParamsSceneListItem] = pydantic.Field(alias="sceneList") """ SenseTime scene configuration list. """