diff --git a/.release-please-manifest.json b/.release-please-manifest.json index cd95c250..1b159305 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.28.0" + ".": "4.29.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 8f3fbc8a..b4e37de6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 34 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/retell%2Ftoddlzt-bd98f7f1d3719abfc66e25f422097c72c6504f85615412419bb88dafebb3d36e.yml -openapi_spec_hash: 202e8e5ba60e0e03c6ef0ddf43af624b +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/retell%2Ftoddlzt-101be623bbd5eca19cb36dd5a5f75052d04ef89578dfd03bf675a5323e43ca8b.yml +openapi_spec_hash: 5f06a39218b958f8973595f616d1586a config_hash: 9d9a24bf8bb4553cbb30ce59eb910b2f diff --git a/CHANGELOG.md b/CHANGELOG.md index 1705d6da..43a26893 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## 4.29.0 (2025-05-14) + +Full Changelog: [v4.28.0...v4.29.0](https://github.com/RetellAI/retell-python-sdk/compare/v4.28.0...v4.29.0) + +### Features + +* **api:** api update ([3f6509c](https://github.com/RetellAI/retell-python-sdk/commit/3f6509cf38b6f1f3cb73b0d8bb918edb54c383ba)) +* **api:** api update ([dc02872](https://github.com/RetellAI/retell-python-sdk/commit/dc028721305eec0c8c6126ac795011b07c6d82cd)) +* **api:** api update ([4e2edb1](https://github.com/RetellAI/retell-python-sdk/commit/4e2edb1f2d4b9aa1116e31d546b005f1d03b1b48)) +* **api:** api update ([3cb87df](https://github.com/RetellAI/retell-python-sdk/commit/3cb87df96dfce683feaa0a4a3b8d7285da07678b)) +* **api:** api update ([fb974a7](https://github.com/RetellAI/retell-python-sdk/commit/fb974a7a9f4367f3146443b7d484997791f40639)) +* **api:** api update ([84bc6f9](https://github.com/RetellAI/retell-python-sdk/commit/84bc6f9064fe0272f3e71a0963ae7f17c92672ff)) +* **api:** api update ([f4a83f3](https://github.com/RetellAI/retell-python-sdk/commit/f4a83f3ec4a359547cc08917fc2277b8b4663fb6)) + + +### Bug Fixes + +* **package:** support direct resource imports ([94bf9a5](https://github.com/RetellAI/retell-python-sdk/commit/94bf9a5e4e91f44902d777683498b82bdba1a691)) + + +### Chores + +* **internal:** avoid errors for isinstance checks on proxies ([ae0efc9](https://github.com/RetellAI/retell-python-sdk/commit/ae0efc9c584268ba9bfd7b5a3681145a97322133)) + ## 4.28.0 (2025-04-28) Full Changelog: [v4.27.0...v4.28.0](https://github.com/RetellAI/retell-python-sdk/compare/v4.27.0...v4.28.0) diff --git a/README.md b/README.md index 6e883efa..ef9b8568 100644 --- a/README.md +++ b/README.md @@ -85,34 +85,19 @@ from retell import Retell client = Retell() -call_responses = client.call.list( - filter_criteria={ - "agent_id": ["agent_oBeDLoLOeuAbiuaMFXRtDOLriT12345"], - "call_status": ["ended"], - "call_successful": [True], - "call_type": ["phone_call"], - "direction": ["inbound"], - "disconnection_reason": ["user_hangup"], - "duration_ms": { - "lower_threshold": 0, - "upper_threshold": 0, - }, - "e2e_latency_p50": { - "lower_threshold": 0, - "upper_threshold": 0, - }, - "from_number": ["string"], - "in_voicemail": [True], - "start_timestamp": { - "lower_threshold": 1738475411000, - "upper_threshold": 1738475421000, - }, - "to_number": ["string"], - "user_sentiment": ["Positive"], - "version": [0], +agent_response = client.agent.create( + response_engine={ + "llm_id": "llm_234sdertfsdsfsdf", + "type": "retell-llm", + }, + voice_id="11labs-Adrian", + user_dtmf_options={ + "digit_limit": 1, + "termination_key": "#", + "timeout_ms": 1000, }, ) -print(call_responses.filter_criteria) +print(agent_response.user_dtmf_options) ``` ## Handling errors diff --git a/pyproject.toml b/pyproject.toml index ba9ae3cd..ed73b4f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "retell-sdk" -version = "4.28.0" +version = "4.29.0" description = "The official Python library for the retell API" dynamic = ["readme"] license = "Apache-2.0" diff --git a/src/retell/__init__.py b/src/retell/__init__.py index a687f078..c5ddb67e 100644 --- a/src/retell/__init__.py +++ b/src/retell/__init__.py @@ -1,5 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import typing as _t + from . import types from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes from ._utils import file_from_path @@ -68,6 +70,9 @@ "DefaultAsyncHttpxClient", ] +if not _t.TYPE_CHECKING: + from ._utils._resources_proxy import resources as resources + _setup_logging() # Update the __module__ attribute for exported symbols so that diff --git a/src/retell/_utils/_proxy.py b/src/retell/_utils/_proxy.py index ffd883e9..0f239a33 100644 --- a/src/retell/_utils/_proxy.py +++ b/src/retell/_utils/_proxy.py @@ -46,7 +46,10 @@ def __dir__(self) -> Iterable[str]: @property # type: ignore @override def __class__(self) -> type: # pyright: ignore - proxied = self.__get_proxied__() + try: + proxied = self.__get_proxied__() + except Exception: + return type(self) if issubclass(type(proxied), LazyProxy): return type(proxied) return proxied.__class__ diff --git a/src/retell/_utils/_resources_proxy.py b/src/retell/_utils/_resources_proxy.py new file mode 100644 index 00000000..c6616a3d --- /dev/null +++ b/src/retell/_utils/_resources_proxy.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import Any +from typing_extensions import override + +from ._proxy import LazyProxy + + +class ResourcesProxy(LazyProxy[Any]): + """A proxy for the `retell.resources` module. + + This is used so that we can lazily import `retell.resources` only when + needed *and* so that users can just import `retell` and reference `retell.resources` + """ + + @override + def __load__(self) -> Any: + import importlib + + mod = importlib.import_module("retell.resources") + return mod + + +resources = ResourcesProxy().__as_proxied__() diff --git a/src/retell/_version.py b/src/retell/_version.py index 1b2b24aa..6b864715 100644 --- a/src/retell/_version.py +++ b/src/retell/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "retell" -__version__ = "4.28.0" # x-release-please-version +__version__ = "4.29.0" # x-release-please-version diff --git a/src/retell/resources/agent.py b/src/retell/resources/agent.py index b864bf43..2f2f3dd0 100644 --- a/src/retell/resources/agent.py +++ b/src/retell/resources/agent.py @@ -52,6 +52,7 @@ def create( response_engine: agent_create_params.ResponseEngine, voice_id: str, agent_name: Optional[str] | NotGiven = NOT_GIVEN, + allow_user_dtmf: bool | NotGiven = NOT_GIVEN, ambient_sound: Optional[ Literal[ "coffee-shop", "convention-hall", "summer-outdoor", "mountain-outdoor", "static-noise", "call-center" @@ -63,6 +64,8 @@ def create( backchannel_words: Optional[List[str]] | NotGiven = NOT_GIVEN, begin_message_delay_ms: int | NotGiven = NOT_GIVEN, boosted_keywords: Optional[List[str]] | NotGiven = NOT_GIVEN, + denoising_mode: Literal["noise-cancellation", "noise-and-background-speech-cancellation"] + | NotGiven = NOT_GIVEN, enable_backchannel: bool | NotGiven = NOT_GIVEN, enable_transcription_formatting: bool | NotGiven = NOT_GIVEN, enable_voicemail_detection: bool | NotGiven = NOT_GIVEN, @@ -119,6 +122,7 @@ def create( responsiveness: float | NotGiven = NOT_GIVEN, ring_duration_ms: int | NotGiven = NOT_GIVEN, stt_mode: Literal["fast", "accurate"] | NotGiven = NOT_GIVEN, + user_dtmf_options: Optional[agent_create_params.UserDtmfOptions] | NotGiven = NOT_GIVEN, version: Optional[float] | NotGiven = NOT_GIVEN, voice_model: Optional[ Literal[ @@ -158,6 +162,9 @@ def create( agent_name: The name of the agent. Only used for your own reference. + allow_user_dtmf: If set to true, DTMF input will be accepted and processed. If false, any DTMF + input will be ignored. Default to true. + ambient_sound: If set, will add ambient environment sound to the call to make experience more realistic. Currently supports the following options: @@ -207,6 +214,8 @@ def create( these words are more likely to get transcribed. Commonly used for names, brands, street, etc. + denoising_mode: If set, determines what denoising mode to use. Default to noise-cancellation. + enable_backchannel: Controls whether the agent would backchannel (agent interjects the speaker with phrases like "yeah", "uh-huh" to signify interest and engagement). Backchannel when enabled tends to show up more in longer user utterances. If not set, agent @@ -339,12 +348,14 @@ def create( "response_engine": response_engine, "voice_id": voice_id, "agent_name": agent_name, + "allow_user_dtmf": allow_user_dtmf, "ambient_sound": ambient_sound, "ambient_sound_volume": ambient_sound_volume, "backchannel_frequency": backchannel_frequency, "backchannel_words": backchannel_words, "begin_message_delay_ms": begin_message_delay_ms, "boosted_keywords": boosted_keywords, + "denoising_mode": denoising_mode, "enable_backchannel": enable_backchannel, "enable_transcription_formatting": enable_transcription_formatting, "enable_voicemail_detection": enable_voicemail_detection, @@ -364,6 +375,7 @@ def create( "responsiveness": responsiveness, "ring_duration_ms": ring_duration_ms, "stt_mode": stt_mode, + "user_dtmf_options": user_dtmf_options, "version": version, "voice_model": voice_model, "voice_speed": voice_speed, @@ -427,6 +439,7 @@ def update( *, query_version: int | NotGiven = NOT_GIVEN, agent_name: Optional[str] | NotGiven = NOT_GIVEN, + allow_user_dtmf: bool | NotGiven = NOT_GIVEN, ambient_sound: Optional[ Literal[ "coffee-shop", "convention-hall", "summer-outdoor", "mountain-outdoor", "static-noise", "call-center" @@ -438,6 +451,8 @@ def update( backchannel_words: Optional[List[str]] | NotGiven = NOT_GIVEN, begin_message_delay_ms: int | NotGiven = NOT_GIVEN, boosted_keywords: Optional[List[str]] | NotGiven = NOT_GIVEN, + denoising_mode: Literal["noise-cancellation", "noise-and-background-speech-cancellation"] + | NotGiven = NOT_GIVEN, enable_backchannel: bool | NotGiven = NOT_GIVEN, enable_transcription_formatting: bool | NotGiven = NOT_GIVEN, enable_voicemail_detection: bool | NotGiven = NOT_GIVEN, @@ -495,6 +510,7 @@ def update( responsiveness: float | NotGiven = NOT_GIVEN, ring_duration_ms: int | NotGiven = NOT_GIVEN, stt_mode: Literal["fast", "accurate"] | NotGiven = NOT_GIVEN, + user_dtmf_options: Optional[agent_update_params.UserDtmfOptions] | NotGiven = NOT_GIVEN, body_version: Optional[float] | NotGiven = NOT_GIVEN, voice_id: str | NotGiven = NOT_GIVEN, voice_model: Optional[ @@ -530,6 +546,9 @@ def update( agent_name: The name of the agent. Only used for your own reference. + allow_user_dtmf: If set to true, DTMF input will be accepted and processed. If false, any DTMF + input will be ignored. Default to true. + ambient_sound: If set, will add ambient environment sound to the call to make experience more realistic. Currently supports the following options: @@ -579,6 +598,8 @@ def update( these words are more likely to get transcribed. Commonly used for names, brands, street, etc. + denoising_mode: If set, determines what denoising mode to use. Default to noise-cancellation. + enable_backchannel: Controls whether the agent would backchannel (agent interjects the speaker with phrases like "yeah", "uh-huh" to signify interest and engagement). Backchannel when enabled tends to show up more in longer user utterances. If not set, agent @@ -718,12 +739,14 @@ def update( body=maybe_transform( { "agent_name": agent_name, + "allow_user_dtmf": allow_user_dtmf, "ambient_sound": ambient_sound, "ambient_sound_volume": ambient_sound_volume, "backchannel_frequency": backchannel_frequency, "backchannel_words": backchannel_words, "begin_message_delay_ms": begin_message_delay_ms, "boosted_keywords": boosted_keywords, + "denoising_mode": denoising_mode, "enable_backchannel": enable_backchannel, "enable_transcription_formatting": enable_transcription_formatting, "enable_voicemail_detection": enable_voicemail_detection, @@ -744,6 +767,7 @@ def update( "responsiveness": responsiveness, "ring_duration_ms": ring_duration_ms, "stt_mode": stt_mode, + "user_dtmf_options": user_dtmf_options, "body_version": body_version, "voice_id": voice_id, "voice_model": voice_model, @@ -879,6 +903,7 @@ async def create( response_engine: agent_create_params.ResponseEngine, voice_id: str, agent_name: Optional[str] | NotGiven = NOT_GIVEN, + allow_user_dtmf: bool | NotGiven = NOT_GIVEN, ambient_sound: Optional[ Literal[ "coffee-shop", "convention-hall", "summer-outdoor", "mountain-outdoor", "static-noise", "call-center" @@ -890,6 +915,8 @@ async def create( backchannel_words: Optional[List[str]] | NotGiven = NOT_GIVEN, begin_message_delay_ms: int | NotGiven = NOT_GIVEN, boosted_keywords: Optional[List[str]] | NotGiven = NOT_GIVEN, + denoising_mode: Literal["noise-cancellation", "noise-and-background-speech-cancellation"] + | NotGiven = NOT_GIVEN, enable_backchannel: bool | NotGiven = NOT_GIVEN, enable_transcription_formatting: bool | NotGiven = NOT_GIVEN, enable_voicemail_detection: bool | NotGiven = NOT_GIVEN, @@ -946,6 +973,7 @@ async def create( responsiveness: float | NotGiven = NOT_GIVEN, ring_duration_ms: int | NotGiven = NOT_GIVEN, stt_mode: Literal["fast", "accurate"] | NotGiven = NOT_GIVEN, + user_dtmf_options: Optional[agent_create_params.UserDtmfOptions] | NotGiven = NOT_GIVEN, version: Optional[float] | NotGiven = NOT_GIVEN, voice_model: Optional[ Literal[ @@ -985,6 +1013,9 @@ async def create( agent_name: The name of the agent. Only used for your own reference. + allow_user_dtmf: If set to true, DTMF input will be accepted and processed. If false, any DTMF + input will be ignored. Default to true. + ambient_sound: If set, will add ambient environment sound to the call to make experience more realistic. Currently supports the following options: @@ -1034,6 +1065,8 @@ async def create( these words are more likely to get transcribed. Commonly used for names, brands, street, etc. + denoising_mode: If set, determines what denoising mode to use. Default to noise-cancellation. + enable_backchannel: Controls whether the agent would backchannel (agent interjects the speaker with phrases like "yeah", "uh-huh" to signify interest and engagement). Backchannel when enabled tends to show up more in longer user utterances. If not set, agent @@ -1166,12 +1199,14 @@ async def create( "response_engine": response_engine, "voice_id": voice_id, "agent_name": agent_name, + "allow_user_dtmf": allow_user_dtmf, "ambient_sound": ambient_sound, "ambient_sound_volume": ambient_sound_volume, "backchannel_frequency": backchannel_frequency, "backchannel_words": backchannel_words, "begin_message_delay_ms": begin_message_delay_ms, "boosted_keywords": boosted_keywords, + "denoising_mode": denoising_mode, "enable_backchannel": enable_backchannel, "enable_transcription_formatting": enable_transcription_formatting, "enable_voicemail_detection": enable_voicemail_detection, @@ -1191,6 +1226,7 @@ async def create( "responsiveness": responsiveness, "ring_duration_ms": ring_duration_ms, "stt_mode": stt_mode, + "user_dtmf_options": user_dtmf_options, "version": version, "voice_model": voice_model, "voice_speed": voice_speed, @@ -1254,6 +1290,7 @@ async def update( *, query_version: int | NotGiven = NOT_GIVEN, agent_name: Optional[str] | NotGiven = NOT_GIVEN, + allow_user_dtmf: bool | NotGiven = NOT_GIVEN, ambient_sound: Optional[ Literal[ "coffee-shop", "convention-hall", "summer-outdoor", "mountain-outdoor", "static-noise", "call-center" @@ -1265,6 +1302,8 @@ async def update( backchannel_words: Optional[List[str]] | NotGiven = NOT_GIVEN, begin_message_delay_ms: int | NotGiven = NOT_GIVEN, boosted_keywords: Optional[List[str]] | NotGiven = NOT_GIVEN, + denoising_mode: Literal["noise-cancellation", "noise-and-background-speech-cancellation"] + | NotGiven = NOT_GIVEN, enable_backchannel: bool | NotGiven = NOT_GIVEN, enable_transcription_formatting: bool | NotGiven = NOT_GIVEN, enable_voicemail_detection: bool | NotGiven = NOT_GIVEN, @@ -1322,6 +1361,7 @@ async def update( responsiveness: float | NotGiven = NOT_GIVEN, ring_duration_ms: int | NotGiven = NOT_GIVEN, stt_mode: Literal["fast", "accurate"] | NotGiven = NOT_GIVEN, + user_dtmf_options: Optional[agent_update_params.UserDtmfOptions] | NotGiven = NOT_GIVEN, body_version: Optional[float] | NotGiven = NOT_GIVEN, voice_id: str | NotGiven = NOT_GIVEN, voice_model: Optional[ @@ -1357,6 +1397,9 @@ async def update( agent_name: The name of the agent. Only used for your own reference. + allow_user_dtmf: If set to true, DTMF input will be accepted and processed. If false, any DTMF + input will be ignored. Default to true. + ambient_sound: If set, will add ambient environment sound to the call to make experience more realistic. Currently supports the following options: @@ -1406,6 +1449,8 @@ async def update( these words are more likely to get transcribed. Commonly used for names, brands, street, etc. + denoising_mode: If set, determines what denoising mode to use. Default to noise-cancellation. + enable_backchannel: Controls whether the agent would backchannel (agent interjects the speaker with phrases like "yeah", "uh-huh" to signify interest and engagement). Backchannel when enabled tends to show up more in longer user utterances. If not set, agent @@ -1545,12 +1590,14 @@ async def update( body=await async_maybe_transform( { "agent_name": agent_name, + "allow_user_dtmf": allow_user_dtmf, "ambient_sound": ambient_sound, "ambient_sound_volume": ambient_sound_volume, "backchannel_frequency": backchannel_frequency, "backchannel_words": backchannel_words, "begin_message_delay_ms": begin_message_delay_ms, "boosted_keywords": boosted_keywords, + "denoising_mode": denoising_mode, "enable_backchannel": enable_backchannel, "enable_transcription_formatting": enable_transcription_formatting, "enable_voicemail_detection": enable_voicemail_detection, @@ -1571,6 +1618,7 @@ async def update( "responsiveness": responsiveness, "ring_duration_ms": ring_duration_ms, "stt_mode": stt_mode, + "user_dtmf_options": user_dtmf_options, "body_version": body_version, "voice_id": voice_id, "voice_model": voice_model, diff --git a/src/retell/types/agent_create_params.py b/src/retell/types/agent_create_params.py index 780bff0b..9e6d980b 100644 --- a/src/retell/types/agent_create_params.py +++ b/src/retell/types/agent_create_params.py @@ -17,6 +17,7 @@ "PostCallAnalysisDataBooleanAnalysisData", "PostCallAnalysisDataNumberAnalysisData", "PronunciationDictionary", + "UserDtmfOptions", ] @@ -37,6 +38,12 @@ class AgentCreateParams(TypedDict, total=False): agent_name: Optional[str] """The name of the agent. Only used for your own reference.""" + allow_user_dtmf: bool + """If set to true, DTMF input will be accepted and processed. + + If false, any DTMF input will be ignored. Default to true. + """ + ambient_sound: Optional[ Literal["coffee-shop", "convention-hall", "summer-outdoor", "mountain-outdoor", "static-noise", "call-center"] ] @@ -107,6 +114,9 @@ class AgentCreateParams(TypedDict, total=False): street, etc. """ + denoising_mode: Literal["noise-cancellation", "noise-and-background-speech-cancellation"] + """If set, determines what denoising mode to use. Default to noise-cancellation.""" + enable_backchannel: bool """ Controls whether the agent would backchannel (agent interjects the speaker with @@ -283,6 +293,8 @@ class AgentCreateParams(TypedDict, total=False): Default to fast mode. """ + user_dtmf_options: Optional[UserDtmfOptions] + version: Optional[float] """Version of the agent.""" @@ -455,3 +467,25 @@ class PronunciationDictionary(TypedDict, total=False): word: Required[str] """The string of word / phrase to be annotated with pronunciation.""" + + +class UserDtmfOptions(TypedDict, total=False): + digit_limit: Optional[int] + """ + The maximum number of digits allowed in the user's DTMF (Dual-Tone + Multi-Frequency) input per turn. Once this limit is reached, the input is + considered complete and a response will be generated immediately. + """ + + termination_key: Optional[str] + """A single key that signals the end of DTMF input. + + Acceptable values include any digit (0–9), the pound/hash symbol (#), or the + asterisk (\\**). + """ + + timeout_ms: int + """The time (in milliseconds) to wait for user DTMF input before timing out. + + The timer resets with each digit received. + """ diff --git a/src/retell/types/agent_response.py b/src/retell/types/agent_response.py index 0d40aa5e..e79b69db 100644 --- a/src/retell/types/agent_response.py +++ b/src/retell/types/agent_response.py @@ -17,6 +17,7 @@ "PostCallAnalysisDataBooleanAnalysisData", "PostCallAnalysisDataNumberAnalysisData", "PronunciationDictionary", + "UserDtmfOptions", ] @@ -126,6 +127,28 @@ class PronunciationDictionary(BaseModel): """The string of word / phrase to be annotated with pronunciation.""" +class UserDtmfOptions(BaseModel): + digit_limit: Optional[int] = None + """ + The maximum number of digits allowed in the user's DTMF (Dual-Tone + Multi-Frequency) input per turn. Once this limit is reached, the input is + considered complete and a response will be generated immediately. + """ + + termination_key: Optional[str] = None + """A single key that signals the end of DTMF input. + + Acceptable values include any digit (0–9), the pound/hash symbol (#), or the + asterisk (\\**). + """ + + timeout_ms: Optional[int] = None + """The time (in milliseconds) to wait for user DTMF input before timing out. + + The timer resets with each digit received. + """ + + class AgentResponse(BaseModel): agent_id: str """Unique id of agent.""" @@ -152,6 +175,12 @@ class AgentResponse(BaseModel): agent_name: Optional[str] = None """The name of the agent. Only used for your own reference.""" + allow_user_dtmf: Optional[bool] = None + """If set to true, DTMF input will be accepted and processed. + + If false, any DTMF input will be ignored. Default to true. + """ + ambient_sound: Optional[ Literal["coffee-shop", "convention-hall", "summer-outdoor", "mountain-outdoor", "static-noise", "call-center"] ] = None @@ -222,6 +251,9 @@ class AgentResponse(BaseModel): street, etc. """ + denoising_mode: Optional[Literal["noise-cancellation", "noise-and-background-speech-cancellation"]] = None + """If set, determines what denoising mode to use. Default to noise-cancellation.""" + enable_backchannel: Optional[bool] = None """ Controls whether the agent would backchannel (agent interjects the speaker with @@ -268,6 +300,9 @@ class AgentResponse(BaseModel): agent would never be interrupted. """ + is_published: Optional[bool] = None + """Whether the agent is published.""" + language: Optional[ Literal[ "en-US", @@ -400,7 +435,9 @@ class AgentResponse(BaseModel): Default to fast mode. """ - version: Optional[float] = None + user_dtmf_options: Optional[UserDtmfOptions] = None + + version: Optional[object] = None """Version of the agent.""" voice_model: Optional[ diff --git a/src/retell/types/agent_update_params.py b/src/retell/types/agent_update_params.py index b7a2d4e2..17d44bdf 100644 --- a/src/retell/types/agent_update_params.py +++ b/src/retell/types/agent_update_params.py @@ -19,6 +19,7 @@ "ResponseEngineResponseEngineRetellLm", "ResponseEngineResponseEngineCustomLm", "ResponseEngineResponseEngineConversationFlow", + "UserDtmfOptions", ] @@ -29,6 +30,12 @@ class AgentUpdateParams(TypedDict, total=False): agent_name: Optional[str] """The name of the agent. Only used for your own reference.""" + allow_user_dtmf: bool + """If set to true, DTMF input will be accepted and processed. + + If false, any DTMF input will be ignored. Default to true. + """ + ambient_sound: Optional[ Literal["coffee-shop", "convention-hall", "summer-outdoor", "mountain-outdoor", "static-noise", "call-center"] ] @@ -99,6 +106,9 @@ class AgentUpdateParams(TypedDict, total=False): street, etc. """ + denoising_mode: Literal["noise-cancellation", "noise-and-background-speech-cancellation"] + """If set, determines what denoising mode to use. Default to noise-cancellation.""" + enable_backchannel: bool """ Controls whether the agent would backchannel (agent interjects the speaker with @@ -282,6 +292,8 @@ class AgentUpdateParams(TypedDict, total=False): Default to fast mode. """ + user_dtmf_options: Optional[UserDtmfOptions] + body_version: Annotated[Optional[float], PropertyInfo(alias="version")] """Version of the agent.""" @@ -460,3 +472,25 @@ class ResponseEngineResponseEngineConversationFlow(TypedDict, total=False): ResponseEngineResponseEngineCustomLm, ResponseEngineResponseEngineConversationFlow, ] + + +class UserDtmfOptions(TypedDict, total=False): + digit_limit: Optional[int] + """ + The maximum number of digits allowed in the user's DTMF (Dual-Tone + Multi-Frequency) input per turn. Once this limit is reached, the input is + considered complete and a response will be generated immediately. + """ + + termination_key: Optional[str] + """A single key that signals the end of DTMF input. + + Acceptable values include any digit (0–9), the pound/hash symbol (#), or the + asterisk (\\**). + """ + + timeout_ms: int + """The time (in milliseconds) to wait for user DTMF input before timing out. + + The timer resets with each digit received. + """ diff --git a/src/retell/types/llm_response.py b/src/retell/types/llm_response.py index e1dbad0b..0096d4e7 100644 --- a/src/retell/types/llm_response.py +++ b/src/retell/types/llm_response.py @@ -742,6 +742,9 @@ class LlmResponse(BaseModel): - Tools of LLM (no state) = general tools """ + is_published: Optional[bool] = None + """Whether the Retell LLM Response Engine is published.""" + knowledge_base_ids: Optional[List[str]] = None """A list of knowledge base ids to use for this resource. @@ -805,5 +808,5 @@ class LlmResponse(BaseModel): longer as additional processing is needed. Default to false. """ - version: Optional[float] = None + version: Optional[object] = None """Version of the Retell LLM.""" diff --git a/tests/api_resources/test_agent.py b/tests/api_resources/test_agent.py index 34e329cd..b8cb7c7b 100644 --- a/tests/api_resources/test_agent.py +++ b/tests/api_resources/test_agent.py @@ -42,12 +42,14 @@ def test_method_create_with_all_params(self, client: Retell) -> None: }, voice_id="11labs-Adrian", agent_name="Jarvis", + allow_user_dtmf=True, ambient_sound="coffee-shop", ambient_sound_volume=1, backchannel_frequency=0.9, backchannel_words=["yeah", "uh-huh"], begin_message_delay_ms=1000, boosted_keywords=["retell", "kroger"], + denoising_mode="noise-cancellation", enable_backchannel=True, enable_transcription_formatting=True, enable_voicemail_detection=True, @@ -80,6 +82,11 @@ def test_method_create_with_all_params(self, client: Retell) -> None: responsiveness=1, ring_duration_ms=30000, stt_mode="fast", + user_dtmf_options={ + "digit_limit": 1, + "termination_key": "#", + "timeout_ms": 1000, + }, version=0, voice_model="eleven_turbo_v2", voice_speed=1, @@ -182,12 +189,14 @@ def test_method_update_with_all_params(self, client: Retell) -> None: agent_id="16b980523634a6dc504898cda492e939", query_version=1, agent_name="Jarvis", + allow_user_dtmf=True, ambient_sound="coffee-shop", ambient_sound_volume=1, backchannel_frequency=0.9, backchannel_words=["yeah", "uh-huh"], begin_message_delay_ms=1000, boosted_keywords=["retell", "kroger"], + denoising_mode="noise-cancellation", enable_backchannel=True, enable_transcription_formatting=True, enable_voicemail_detection=True, @@ -225,6 +234,11 @@ def test_method_update_with_all_params(self, client: Retell) -> None: responsiveness=1, ring_duration_ms=30000, stt_mode="fast", + user_dtmf_options={ + "digit_limit": 1, + "termination_key": "#", + "timeout_ms": 1000, + }, body_version=0, voice_id="11labs-Adrian", voice_model="eleven_turbo_v2", @@ -394,12 +408,14 @@ async def test_method_create_with_all_params(self, async_client: AsyncRetell) -> }, voice_id="11labs-Adrian", agent_name="Jarvis", + allow_user_dtmf=True, ambient_sound="coffee-shop", ambient_sound_volume=1, backchannel_frequency=0.9, backchannel_words=["yeah", "uh-huh"], begin_message_delay_ms=1000, boosted_keywords=["retell", "kroger"], + denoising_mode="noise-cancellation", enable_backchannel=True, enable_transcription_formatting=True, enable_voicemail_detection=True, @@ -432,6 +448,11 @@ async def test_method_create_with_all_params(self, async_client: AsyncRetell) -> responsiveness=1, ring_duration_ms=30000, stt_mode="fast", + user_dtmf_options={ + "digit_limit": 1, + "termination_key": "#", + "timeout_ms": 1000, + }, version=0, voice_model="eleven_turbo_v2", voice_speed=1, @@ -534,12 +555,14 @@ async def test_method_update_with_all_params(self, async_client: AsyncRetell) -> agent_id="16b980523634a6dc504898cda492e939", query_version=1, agent_name="Jarvis", + allow_user_dtmf=True, ambient_sound="coffee-shop", ambient_sound_volume=1, backchannel_frequency=0.9, backchannel_words=["yeah", "uh-huh"], begin_message_delay_ms=1000, boosted_keywords=["retell", "kroger"], + denoising_mode="noise-cancellation", enable_backchannel=True, enable_transcription_formatting=True, enable_voicemail_detection=True, @@ -577,6 +600,11 @@ async def test_method_update_with_all_params(self, async_client: AsyncRetell) -> responsiveness=1, ring_duration_ms=30000, stt_mode="fast", + user_dtmf_options={ + "digit_limit": 1, + "termination_key": "#", + "timeout_ms": 1000, + }, body_version=0, voice_id="11labs-Adrian", voice_model="eleven_turbo_v2", diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py index de63e6ad..516d1db0 100644 --- a/tests/test_utils/test_proxy.py +++ b/tests/test_utils/test_proxy.py @@ -21,3 +21,14 @@ def test_recursive_proxy() -> None: assert dir(proxy) == [] assert type(proxy).__name__ == "RecursiveLazyProxy" assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy" + + +def test_isinstance_does_not_error() -> None: + class AlwaysErrorProxy(LazyProxy[Any]): + @override + def __load__(self) -> Any: + raise RuntimeError("Mocking missing dependency") + + proxy = AlwaysErrorProxy() + assert not isinstance(proxy, dict) + assert isinstance(proxy, LazyProxy)