Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .fern/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
10 changes: 8 additions & 2 deletions .fern/replay.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 4 additions & 13 deletions src/agora_agent/agents/raw_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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.
"""
Expand Down
6 changes: 1 addition & 5 deletions src/agora_agent/agents/types/list_agents_response_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.
"""
Expand Down
94 changes: 32 additions & 62 deletions src/agora_agent/core/pydantic_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -29,19 +29,17 @@
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")
Model = TypeVar("Model", bound=pydantic.BaseModel)


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:
Expand All @@ -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 = {
Expand Down Expand Up @@ -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]:
Expand Down Expand Up @@ -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]

Expand Down
41 changes: 8 additions & 33 deletions src/agora_agent/phone_numbers/raw_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
17 changes: 4 additions & 13 deletions src/agora_agent/telephony/raw_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
Loading
Loading