diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 25e834f65..aa6f80f47 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.173.0" + ".": "4.174.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 707fc41ea..8a7b6d862 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 1222 +configured_endpoints: 1248 diff --git a/CHANGELOG.md b/CHANGELOG.md index b0b117705..6274568f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [4.174.0](https://github.com/team-telnyx/telnyx-python/compare/v4.173.0...v4.174.0) (2026-08-16) + + +### Features + +* promote from staging 3259c2c ([d48d1c7](https://github.com/team-telnyx/telnyx-python/commit/d48d1c778ed58b7b1c4f34edefbe31617ff02637)) + + +### Bug Fixes + +* **ci:** attest private release provenance ([#417](https://github.com/team-telnyx/telnyx-python/issues/417)) ([3e00ab9](https://github.com/team-telnyx/telnyx-python/commit/3e00ab930be25223f1fd13fb4cdfebffd6859438)) + ## [4.173.0](https://github.com/team-telnyx/telnyx-python/compare/v4.172.0...v4.173.0) (2026-08-11) diff --git a/api.md b/api.md index e0d431b3e..2dd318490 100644 --- a/api.md +++ b/api.md @@ -332,6 +332,8 @@ from telnyx.types import ( CallAIGatherEndedWebhookEvent, CallAIGatherMessageHistoryUpdatedWebhookEvent, CallAIGatherPartialResultsWebhookEvent, + ArtifactCompletedWebhookEvent, + ArtifactFailedWebhookEvent, CallAnsweredWebhookEvent, CallBridgedWebhookEvent, CallConversationEndedWebhookEvent, @@ -388,11 +390,16 @@ from telnyx.types import ( HostedNumberOrderEventWebhookEvent, InboundMessageWebhookEvent, NumberOrderStatusUpdateWebhookEvent, + RecordingAvailableWebhookEvent, ReplacedLinkClickWebhookEvent, + SessionStatusChangedWebhookEvent, + TranscriptCompletedWebhookEvent, TranscriptionWebhookEvent, CallAIGatherEndedWebhookEvent, CallAIGatherMessageHistoryUpdatedWebhookEvent, CallAIGatherPartialResultsWebhookEvent, + ArtifactCompletedWebhookEvent, + ArtifactFailedWebhookEvent, CallAnsweredWebhookEvent, CallBridgedWebhookEvent, CallConversationEndedWebhookEvent, @@ -449,7 +456,10 @@ from telnyx.types import ( HostedNumberOrderEventWebhookEvent, InboundMessageWebhookEvent, NumberOrderStatusUpdateWebhookEvent, + RecordingAvailableWebhookEvent, ReplacedLinkClickWebhookEvent, + SessionStatusChangedWebhookEvent, + TranscriptCompletedWebhookEvent, TranscriptionWebhookEvent, UnsafeUnwrapWebhookEvent, UnwrapWebhookEvent, @@ -4410,7 +4420,9 @@ from telnyx.types.sim_cards import ( ActionBulkEnableVoiceResponse, ActionBulkSetPublicIPsResponse, ActionDisableResponse, + ActionDisableVoiceResponse, ActionEnableResponse, + ActionEnableVoiceResponse, ActionRemovePublicIPResponse, ActionSetPublicIPResponse, ActionSetStandbyResponse, @@ -4426,7 +4438,9 @@ Methods: - client.sim_cards.actions.bulk_enable_voice(\*\*params) -> ActionBulkEnableVoiceResponse - client.sim_cards.actions.bulk_set_public_ips(\*\*params) -> ActionBulkSetPublicIPsResponse - client.sim_cards.actions.disable(id) -> ActionDisableResponse +- client.sim_cards.actions.disable_voice(id) -> ActionDisableVoiceResponse - client.sim_cards.actions.enable(id) -> ActionEnableResponse +- client.sim_cards.actions.enable_voice(id, \*\*params) -> ActionEnableVoiceResponse - client.sim_cards.actions.remove_public_ip(id) -> ActionRemovePublicIPResponse - client.sim_cards.actions.set_public_ip(id, \*\*params) -> ActionSetPublicIPResponse - client.sim_cards.actions.set_standby(id) -> ActionSetStandbyResponse @@ -4564,7 +4578,7 @@ Methods: Types: ```python -from telnyx.types.storage import KvNamespace, KvNamespaceResponseWrapper +from telnyx.types.storage import EdgeComputePaginationMeta, KvNamespace, KvNamespaceResponseWrapper ``` Methods: @@ -4616,6 +4630,33 @@ Methods: - client.storage.cloudfs.actions.rotate_meta_token(id) -> CloudfsFilesystemResponseWrapper +## Sqldbs + +Types: + +```python +from telnyx.types.storage import SqlDatabase, SqlDatabaseResponseWrapper +``` + +Methods: + +- client.storage.sqldbs.create(\*\*params) -> SqlDatabaseResponseWrapper +- client.storage.sqldbs.retrieve(id) -> SqlDatabaseResponseWrapper +- client.storage.sqldbs.list(\*\*params) -> SyncDefaultFlatPagination[SqlDatabase] +- client.storage.sqldbs.delete(id, \*\*params) -> None + +### Actions + +Types: + +```python +from telnyx.types.storage.sqldbs import ActionQueryResponse +``` + +Methods: + +- client.storage.sqldbs.actions.query(id, \*\*params) -> ActionQueryResponse + # SubNumberOrders Types: @@ -6622,3 +6663,93 @@ Methods: - client.pricing.products.retrieve(slug, \*\*params) -> ProductRetrieveResponse - client.pricing.products.list(\*\*params) -> SyncDefaultFlatPagination[ProductListResponse] + +# WebSearch + +Types: + +```python +from telnyx.types import WebSearchResult, WebSearchCreateResponse, WebSearchContentsResponse +``` + +Methods: + +- client.web_search.create(\*\*params) -> WebSearchCreateResponse +- client.web_search.contents(\*\*params) -> WebSearchContentsResponse + +## Research + +Types: + +```python +from telnyx.types.web_search import ( + ResearchCitation, + ResearchCreateResponse, + ResearchRetrieveResponse, +) +``` + +Methods: + +- client.web_search.research.create(\*\*params) -> ResearchCreateResponse +- client.web_search.research.retrieve(task_id) -> ResearchRetrieveResponse + +# MeetingSessions + +Types: + +```python +from telnyx.types import ( + MeetingSession, + MeetingSessionResponse, + MeetingSessionListResponse, + MeetingSessionDeleteRecordingMediaResponse, + MeetingSessionRetrieveEventsResponse, + MeetingSessionRetrieveRecordingsResponse, + MeetingSessionRetrieveTranscriptResponse, +) +``` + +Methods: + +- client.meeting_sessions.create(\*\*params) -> MeetingSessionResponse +- client.meeting_sessions.retrieve(id) -> MeetingSessionResponse +- client.meeting_sessions.update(id, \*\*params) -> MeetingSessionResponse +- client.meeting_sessions.list(\*\*params) -> MeetingSessionListResponse +- client.meeting_sessions.delete(id) -> MeetingSessionResponse +- client.meeting_sessions.delete_recording_media(id) -> MeetingSessionDeleteRecordingMediaResponse +- client.meeting_sessions.retrieve_events(id, \*\*params) -> MeetingSessionRetrieveEventsResponse +- client.meeting_sessions.retrieve_recordings(id) -> MeetingSessionRetrieveRecordingsResponse +- client.meeting_sessions.retrieve_transcript(id, \*\*params) -> MeetingSessionRetrieveTranscriptResponse + +## Actions + +Types: + +```python +from telnyx.types.meeting_sessions import ActionAcceptedResponse +``` + +Methods: + +- client.meeting_sessions.actions.send_chat(id, \*\*params) -> ActionAcceptedResponse +- client.meeting_sessions.actions.speak(id, \*\*params) -> ActionAcceptedResponse +- client.meeting_sessions.actions.stop_speaking(id) -> ActionAcceptedResponse + +## Artifacts + +Types: + +```python +from telnyx.types.meeting_sessions import ( + MeetingSessionArtifact, + MeetingSessionArtifactResponse, + ArtifactListResponse, +) +``` + +Methods: + +- client.meeting_sessions.artifacts.create(id, \*\*params) -> MeetingSessionArtifactResponse +- client.meeting_sessions.artifacts.retrieve(artifact_id, \*, id) -> MeetingSessionArtifactResponse +- client.meeting_sessions.artifacts.list(id) -> ArtifactListResponse diff --git a/pyproject.toml b/pyproject.toml index 34e265ada..57e200825 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "telnyx" -version = "4.173.0" +version = "4.174.0" description = "The official Python library for the telnyx API" dynamic = ["readme"] license = "MIT" diff --git a/src/telnyx/_client.py b/src/telnyx/_client.py index 69888b9c3..d381d8d17 100644 --- a/src/telnyx/_client.py +++ b/src/telnyx/_client.py @@ -76,6 +76,7 @@ global_ips, recordings, reputation, + web_search, well_known, call_events, conferences, @@ -129,6 +130,7 @@ fqdn_connections, inbound_channels, managed_accounts, + meeting_sessions, network_coverage, numbers_features, operator_connect, @@ -326,6 +328,7 @@ from .resources.recordings.recordings import RecordingsResource, AsyncRecordingsResource from .resources.reputation.reputation import ReputationResource, AsyncReputationResource from .resources.telephony_credentials import TelephonyCredentialsResource, AsyncTelephonyCredentialsResource + from .resources.web_search.web_search import WebSearchResource, AsyncWebSearchResource from .resources.dialogflow_connections import DialogflowConnectionsResource, AsyncDialogflowConnectionsResource from .resources.sim_card_order_preview import SimCardOrderPreviewResource, AsyncSimCardOrderPreviewResource from .resources.virtual_cross_connects import VirtualCrossConnectsResource, AsyncVirtualCrossConnectsResource @@ -438,6 +441,7 @@ ) from .resources.fqdn_connections.fqdn_connections import FqdnConnectionsResource, AsyncFqdnConnectionsResource from .resources.managed_accounts.managed_accounts import ManagedAccountsResource, AsyncManagedAccountsResource + from .resources.meeting_sessions.meeting_sessions import MeetingSessionsResource, AsyncMeetingSessionsResource from .resources.operator_connect.operator_connect import OperatorConnectResource, AsyncOperatorConnectResource from .resources.session_analysis.session_analysis import SessionAnalysisResource, AsyncSessionAnalysisResource from .resources.sim_card_data_usage_notifications import ( @@ -1832,6 +1836,18 @@ def pricing(self) -> PricingResource: return PricingResource(self) + @cached_property + def web_search(self) -> WebSearchResource: + from .resources.web_search import WebSearchResource + + return WebSearchResource(self) + + @cached_property + def meeting_sessions(self) -> MeetingSessionsResource: + from .resources.meeting_sessions import MeetingSessionsResource + + return MeetingSessionsResource(self) + @cached_property def with_raw_response(self) -> TelnyxWithRawResponse: return TelnyxWithRawResponse(self) @@ -3319,6 +3335,18 @@ def pricing(self) -> AsyncPricingResource: return AsyncPricingResource(self) + @cached_property + def web_search(self) -> AsyncWebSearchResource: + from .resources.web_search import AsyncWebSearchResource + + return AsyncWebSearchResource(self) + + @cached_property + def meeting_sessions(self) -> AsyncMeetingSessionsResource: + from .resources.meeting_sessions import AsyncMeetingSessionsResource + + return AsyncMeetingSessionsResource(self) + @cached_property def with_raw_response(self) -> AsyncTelnyxWithRawResponse: return AsyncTelnyxWithRawResponse(self) @@ -4742,6 +4770,18 @@ def pricing(self) -> pricing.PricingResourceWithRawResponse: return PricingResourceWithRawResponse(self._client.pricing) + @cached_property + def web_search(self) -> web_search.WebSearchResourceWithRawResponse: + from .resources.web_search import WebSearchResourceWithRawResponse + + return WebSearchResourceWithRawResponse(self._client.web_search) + + @cached_property + def meeting_sessions(self) -> meeting_sessions.MeetingSessionsResourceWithRawResponse: + from .resources.meeting_sessions import MeetingSessionsResourceWithRawResponse + + return MeetingSessionsResourceWithRawResponse(self._client.meeting_sessions) + class AsyncTelnyxWithRawResponse: _client: AsyncTelnyx @@ -6036,6 +6076,18 @@ def pricing(self) -> pricing.AsyncPricingResourceWithRawResponse: return AsyncPricingResourceWithRawResponse(self._client.pricing) + @cached_property + def web_search(self) -> web_search.AsyncWebSearchResourceWithRawResponse: + from .resources.web_search import AsyncWebSearchResourceWithRawResponse + + return AsyncWebSearchResourceWithRawResponse(self._client.web_search) + + @cached_property + def meeting_sessions(self) -> meeting_sessions.AsyncMeetingSessionsResourceWithRawResponse: + from .resources.meeting_sessions import AsyncMeetingSessionsResourceWithRawResponse + + return AsyncMeetingSessionsResourceWithRawResponse(self._client.meeting_sessions) + class TelnyxWithStreamedResponse: _client: Telnyx @@ -7332,6 +7384,18 @@ def pricing(self) -> pricing.PricingResourceWithStreamingResponse: return PricingResourceWithStreamingResponse(self._client.pricing) + @cached_property + def web_search(self) -> web_search.WebSearchResourceWithStreamingResponse: + from .resources.web_search import WebSearchResourceWithStreamingResponse + + return WebSearchResourceWithStreamingResponse(self._client.web_search) + + @cached_property + def meeting_sessions(self) -> meeting_sessions.MeetingSessionsResourceWithStreamingResponse: + from .resources.meeting_sessions import MeetingSessionsResourceWithStreamingResponse + + return MeetingSessionsResourceWithStreamingResponse(self._client.meeting_sessions) + class AsyncTelnyxWithStreamedResponse: _client: AsyncTelnyx @@ -8678,6 +8742,18 @@ def pricing(self) -> pricing.AsyncPricingResourceWithStreamingResponse: return AsyncPricingResourceWithStreamingResponse(self._client.pricing) + @cached_property + def web_search(self) -> web_search.AsyncWebSearchResourceWithStreamingResponse: + from .resources.web_search import AsyncWebSearchResourceWithStreamingResponse + + return AsyncWebSearchResourceWithStreamingResponse(self._client.web_search) + + @cached_property + def meeting_sessions(self) -> meeting_sessions.AsyncMeetingSessionsResourceWithStreamingResponse: + from .resources.meeting_sessions import AsyncMeetingSessionsResourceWithStreamingResponse + + return AsyncMeetingSessionsResourceWithStreamingResponse(self._client.meeting_sessions) + Client = Telnyx diff --git a/src/telnyx/_version.py b/src/telnyx/_version.py index 3ae3a4a89..561210385 100644 --- a/src/telnyx/_version.py +++ b/src/telnyx/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "telnyx" -__version__ = "4.173.0" # x-release-please-version +__version__ = "4.174.0" # x-release-please-version diff --git a/src/telnyx/resources/__init__.py b/src/telnyx/resources/__init__.py index d02c44937..4e27169ab 100644 --- a/src/telnyx/resources/__init__.py +++ b/src/telnyx/resources/__init__.py @@ -313,6 +313,14 @@ ReputationResourceWithStreamingResponse, AsyncReputationResourceWithStreamingResponse, ) +from .web_search import ( + WebSearchResource, + AsyncWebSearchResource, + WebSearchResourceWithRawResponse, + AsyncWebSearchResourceWithRawResponse, + WebSearchResourceWithStreamingResponse, + AsyncWebSearchResourceWithStreamingResponse, +) from .well_known import ( WellKnownResource, AsyncWellKnownResource, @@ -737,6 +745,14 @@ ManagedAccountsResourceWithStreamingResponse, AsyncManagedAccountsResourceWithStreamingResponse, ) +from .meeting_sessions import ( + MeetingSessionsResource, + AsyncMeetingSessionsResource, + MeetingSessionsResourceWithRawResponse, + AsyncMeetingSessionsResourceWithRawResponse, + MeetingSessionsResourceWithStreamingResponse, + AsyncMeetingSessionsResourceWithStreamingResponse, +) from .network_coverage import ( NetworkCoverageResource, AsyncNetworkCoverageResource, @@ -2511,4 +2527,16 @@ "AsyncPricingResourceWithRawResponse", "PricingResourceWithStreamingResponse", "AsyncPricingResourceWithStreamingResponse", + "WebSearchResource", + "AsyncWebSearchResource", + "WebSearchResourceWithRawResponse", + "AsyncWebSearchResourceWithRawResponse", + "WebSearchResourceWithStreamingResponse", + "AsyncWebSearchResourceWithStreamingResponse", + "MeetingSessionsResource", + "AsyncMeetingSessionsResource", + "MeetingSessionsResourceWithRawResponse", + "AsyncMeetingSessionsResourceWithRawResponse", + "MeetingSessionsResourceWithStreamingResponse", + "AsyncMeetingSessionsResourceWithStreamingResponse", ] diff --git a/src/telnyx/resources/calls/actions.py b/src/telnyx/resources/calls/actions.py index 86bcfcc06..83c888d2a 100644 --- a/src/telnyx/resources/calls/actions.py +++ b/src/telnyx/resources/calls/actions.py @@ -14,7 +14,7 @@ StreamBidirectionalTargetLegs, StreamBidirectionalSamplingRate, ) -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given from ..._utils import path_template, maybe_transform, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource @@ -252,7 +252,7 @@ def answer( webhook_retries_policies: Dict[str, action_answer_params.WebhookRetriesPolicies] | Omit = omit, webhook_url: str | Omit = omit, webhook_url_method: Literal["POST", "GET"] | Omit = omit, - webhook_urls: Dict[str, str] | Omit = omit, + webhook_urls: Dict[str, SequenceNotStr[str]] | Omit = omit, webhook_urls_method: Literal["POST", "GET"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -369,9 +369,10 @@ def answer( webhook_url_method: HTTP request type used for `webhook_url`. - webhook_urls: A map of event types to webhook URLs. When an event of the specified type - occurs, the webhook URL associated with that event type will be called instead - of `webhook_url`. Events not mapped here will use the default `webhook_url`. + webhook_urls: A map of event types to arrays of webhook URLs. When an event of the specified + type occurs, the webhook URLs associated with that event type will be called + instead of `webhook_url`. Events not mapped here will use the default + `webhook_url`. webhook_urls_method: HTTP request method to invoke `webhook_urls`. @@ -3934,7 +3935,7 @@ def transfer( webhook_retries_policies: Dict[str, action_transfer_params.WebhookRetriesPolicies] | Omit = omit, webhook_url: str | Omit = omit, webhook_url_method: Literal["POST", "GET"] | Omit = omit, - webhook_urls: Dict[str, str] | Omit = omit, + webhook_urls: Dict[str, SequenceNotStr[str]] | Omit = omit, webhook_urls_method: Literal["POST", "GET"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -4118,9 +4119,10 @@ def transfer( webhook_url_method: HTTP request type used for `webhook_url`. - webhook_urls: A map of event types to webhook URLs. When an event of the specified type - occurs, the webhook URL associated with that event type will be called instead - of `webhook_url`. Events not mapped here will use the default `webhook_url`. + webhook_urls: A map of event types to arrays of webhook URLs. When an event of the specified + type occurs, the webhook URLs associated with that event type will be called + instead of `webhook_url`. Events not mapped here will use the default + `webhook_url`. webhook_urls_method: HTTP request method to invoke `webhook_urls`. @@ -4344,7 +4346,7 @@ async def answer( webhook_retries_policies: Dict[str, action_answer_params.WebhookRetriesPolicies] | Omit = omit, webhook_url: str | Omit = omit, webhook_url_method: Literal["POST", "GET"] | Omit = omit, - webhook_urls: Dict[str, str] | Omit = omit, + webhook_urls: Dict[str, SequenceNotStr[str]] | Omit = omit, webhook_urls_method: Literal["POST", "GET"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -4461,9 +4463,10 @@ async def answer( webhook_url_method: HTTP request type used for `webhook_url`. - webhook_urls: A map of event types to webhook URLs. When an event of the specified type - occurs, the webhook URL associated with that event type will be called instead - of `webhook_url`. Events not mapped here will use the default `webhook_url`. + webhook_urls: A map of event types to arrays of webhook URLs. When an event of the specified + type occurs, the webhook URLs associated with that event type will be called + instead of `webhook_url`. Events not mapped here will use the default + `webhook_url`. webhook_urls_method: HTTP request method to invoke `webhook_urls`. @@ -8028,7 +8031,7 @@ async def transfer( webhook_retries_policies: Dict[str, action_transfer_params.WebhookRetriesPolicies] | Omit = omit, webhook_url: str | Omit = omit, webhook_url_method: Literal["POST", "GET"] | Omit = omit, - webhook_urls: Dict[str, str] | Omit = omit, + webhook_urls: Dict[str, SequenceNotStr[str]] | Omit = omit, webhook_urls_method: Literal["POST", "GET"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -8212,9 +8215,10 @@ async def transfer( webhook_url_method: HTTP request type used for `webhook_url`. - webhook_urls: A map of event types to webhook URLs. When an event of the specified type - occurs, the webhook URL associated with that event type will be called instead - of `webhook_url`. Events not mapped here will use the default `webhook_url`. + webhook_urls: A map of event types to arrays of webhook URLs. When an event of the specified + type occurs, the webhook URLs associated with that event type will be called + instead of `webhook_url`. Events not mapped here will use the default + `webhook_url`. webhook_urls_method: HTTP request method to invoke `webhook_urls`. diff --git a/src/telnyx/resources/calls/calls.py b/src/telnyx/resources/calls/calls.py index 339b9db4e..787f2b457 100644 --- a/src/telnyx/resources/calls/calls.py +++ b/src/telnyx/resources/calls/calls.py @@ -145,7 +145,7 @@ def dial( webhook_retries_policies: Dict[str, call_dial_params.WebhookRetriesPolicies] | Omit = omit, webhook_url: str | Omit = omit, webhook_url_method: Literal["POST", "GET"] | Omit = omit, - webhook_urls: Dict[str, str] | Omit = omit, + webhook_urls: Dict[str, SequenceNotStr[str]] | Omit = omit, webhook_urls_method: Literal["POST", "GET"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -415,10 +415,10 @@ def dial( webhook_url_method: HTTP request type used for `webhook_url`. - webhook_urls: A map of event types to webhook URLs. When an event of the specified type - occurs, the webhook URL associated with that event type will be called instead - of the default webhook URL. Events not mapped here will use the default webhook - URL. + webhook_urls: A map of event types to arrays of webhook URLs. When an event of the specified + type occurs, the webhook URLs associated with that event type will be called + instead of the default webhook URL. Events not mapped here will use the default + webhook URL. webhook_urls_method: HTTP request method to invoke `webhook_urls`. @@ -634,7 +634,7 @@ async def dial( webhook_retries_policies: Dict[str, call_dial_params.WebhookRetriesPolicies] | Omit = omit, webhook_url: str | Omit = omit, webhook_url_method: Literal["POST", "GET"] | Omit = omit, - webhook_urls: Dict[str, str] | Omit = omit, + webhook_urls: Dict[str, SequenceNotStr[str]] | Omit = omit, webhook_urls_method: Literal["POST", "GET"] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -904,10 +904,10 @@ async def dial( webhook_url_method: HTTP request type used for `webhook_url`. - webhook_urls: A map of event types to webhook URLs. When an event of the specified type - occurs, the webhook URL associated with that event type will be called instead - of the default webhook URL. Events not mapped here will use the default webhook - URL. + webhook_urls: A map of event types to arrays of webhook URLs. When an event of the specified + type occurs, the webhook URLs associated with that event type will be called + instead of the default webhook URL. Events not mapped here will use the default + webhook URL. webhook_urls_method: HTTP request method to invoke `webhook_urls`. diff --git a/src/telnyx/resources/meeting_sessions/__init__.py b/src/telnyx/resources/meeting_sessions/__init__.py new file mode 100644 index 000000000..2a1468424 --- /dev/null +++ b/src/telnyx/resources/meeting_sessions/__init__.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .actions import ( + ActionsResource, + AsyncActionsResource, + ActionsResourceWithRawResponse, + AsyncActionsResourceWithRawResponse, + ActionsResourceWithStreamingResponse, + AsyncActionsResourceWithStreamingResponse, +) +from .artifacts import ( + ArtifactsResource, + AsyncArtifactsResource, + ArtifactsResourceWithRawResponse, + AsyncArtifactsResourceWithRawResponse, + ArtifactsResourceWithStreamingResponse, + AsyncArtifactsResourceWithStreamingResponse, +) +from .meeting_sessions import ( + MeetingSessionsResource, + AsyncMeetingSessionsResource, + MeetingSessionsResourceWithRawResponse, + AsyncMeetingSessionsResourceWithRawResponse, + MeetingSessionsResourceWithStreamingResponse, + AsyncMeetingSessionsResourceWithStreamingResponse, +) + +__all__ = [ + "ActionsResource", + "AsyncActionsResource", + "ActionsResourceWithRawResponse", + "AsyncActionsResourceWithRawResponse", + "ActionsResourceWithStreamingResponse", + "AsyncActionsResourceWithStreamingResponse", + "ArtifactsResource", + "AsyncArtifactsResource", + "ArtifactsResourceWithRawResponse", + "AsyncArtifactsResourceWithRawResponse", + "ArtifactsResourceWithStreamingResponse", + "AsyncArtifactsResourceWithStreamingResponse", + "MeetingSessionsResource", + "AsyncMeetingSessionsResource", + "MeetingSessionsResourceWithRawResponse", + "AsyncMeetingSessionsResourceWithRawResponse", + "MeetingSessionsResourceWithStreamingResponse", + "AsyncMeetingSessionsResourceWithStreamingResponse", +] diff --git a/src/telnyx/resources/meeting_sessions/actions.py b/src/telnyx/resources/meeting_sessions/actions.py new file mode 100644 index 000000000..845b7c882 --- /dev/null +++ b/src/telnyx/resources/meeting_sessions/actions.py @@ -0,0 +1,371 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.meeting_sessions import action_speak_params, action_send_chat_params +from ...types.meeting_sessions.action_accepted_response import ActionAcceptedResponse + +__all__ = ["ActionsResource", "AsyncActionsResource"] + + +class ActionsResource(SyncAPIResource): + """Send real-time speech and chat actions to an active meeting session.""" + + @cached_property + def with_raw_response(self) -> ActionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return ActionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ActionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return ActionsResourceWithStreamingResponse(self) + + def send_chat( + self, + id: str, + *, + text: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionAcceptedResponse: + """ + Sends a chat message into a meeting session. + + Args: + text: Chat message text to send in the meeting. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/meeting_sessions/{id}/actions/send_chat", id=id), + body=maybe_transform({"text": text}, action_send_chat_params.ActionSendChatParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionAcceptedResponse, + ) + + def speak( + self, + id: str, + *, + text: str, + interrupt: bool | Omit = omit, + voice: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionAcceptedResponse: + """ + Sends audio / text-to-speech into a meeting session. + + Args: + text: Text for the bot to speak. + + interrupt: If true, interrupt any currently playing audio to speak this text immediately. + + voice: Voice identifier to use for this utterance. When supplied, it overrides the + session-default voice configured at creation; otherwise the speak action uses + that session default. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/meeting_sessions/{id}/actions/speak", id=id), + body=maybe_transform( + { + "text": text, + "interrupt": interrupt, + "voice": voice, + }, + action_speak_params.ActionSpeakParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionAcceptedResponse, + ) + + def stop_speaking( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionAcceptedResponse: + """ + Stops any active text-to-speech playback in a meeting session. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/meeting_sessions/{id}/actions/stop_speaking", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionAcceptedResponse, + ) + + +class AsyncActionsResource(AsyncAPIResource): + """Send real-time speech and chat actions to an active meeting session.""" + + @cached_property + def with_raw_response(self) -> AsyncActionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncActionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncActionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncActionsResourceWithStreamingResponse(self) + + async def send_chat( + self, + id: str, + *, + text: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionAcceptedResponse: + """ + Sends a chat message into a meeting session. + + Args: + text: Chat message text to send in the meeting. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/meeting_sessions/{id}/actions/send_chat", id=id), + body=await async_maybe_transform({"text": text}, action_send_chat_params.ActionSendChatParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionAcceptedResponse, + ) + + async def speak( + self, + id: str, + *, + text: str, + interrupt: bool | Omit = omit, + voice: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionAcceptedResponse: + """ + Sends audio / text-to-speech into a meeting session. + + Args: + text: Text for the bot to speak. + + interrupt: If true, interrupt any currently playing audio to speak this text immediately. + + voice: Voice identifier to use for this utterance. When supplied, it overrides the + session-default voice configured at creation; otherwise the speak action uses + that session default. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/meeting_sessions/{id}/actions/speak", id=id), + body=await async_maybe_transform( + { + "text": text, + "interrupt": interrupt, + "voice": voice, + }, + action_speak_params.ActionSpeakParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionAcceptedResponse, + ) + + async def stop_speaking( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionAcceptedResponse: + """ + Stops any active text-to-speech playback in a meeting session. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/meeting_sessions/{id}/actions/stop_speaking", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionAcceptedResponse, + ) + + +class ActionsResourceWithRawResponse: + def __init__(self, actions: ActionsResource) -> None: + self._actions = actions + + self.send_chat = to_raw_response_wrapper( + actions.send_chat, + ) + self.speak = to_raw_response_wrapper( + actions.speak, + ) + self.stop_speaking = to_raw_response_wrapper( + actions.stop_speaking, + ) + + +class AsyncActionsResourceWithRawResponse: + def __init__(self, actions: AsyncActionsResource) -> None: + self._actions = actions + + self.send_chat = async_to_raw_response_wrapper( + actions.send_chat, + ) + self.speak = async_to_raw_response_wrapper( + actions.speak, + ) + self.stop_speaking = async_to_raw_response_wrapper( + actions.stop_speaking, + ) + + +class ActionsResourceWithStreamingResponse: + def __init__(self, actions: ActionsResource) -> None: + self._actions = actions + + self.send_chat = to_streamed_response_wrapper( + actions.send_chat, + ) + self.speak = to_streamed_response_wrapper( + actions.speak, + ) + self.stop_speaking = to_streamed_response_wrapper( + actions.stop_speaking, + ) + + +class AsyncActionsResourceWithStreamingResponse: + def __init__(self, actions: AsyncActionsResource) -> None: + self._actions = actions + + self.send_chat = async_to_streamed_response_wrapper( + actions.send_chat, + ) + self.speak = async_to_streamed_response_wrapper( + actions.speak, + ) + self.stop_speaking = async_to_streamed_response_wrapper( + actions.stop_speaking, + ) diff --git a/src/telnyx/resources/meeting_sessions/artifacts.py b/src/telnyx/resources/meeting_sessions/artifacts.py new file mode 100644 index 000000000..ba3ee7ed2 --- /dev/null +++ b/src/telnyx/resources/meeting_sessions/artifacts.py @@ -0,0 +1,350 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Query, Headers, NotGiven, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.meeting_sessions import artifact_create_params +from ...types.meeting_sessions.artifact_list_response import ArtifactListResponse +from ...types.meeting_sessions.meeting_session_artifact_response import MeetingSessionArtifactResponse + +__all__ = ["ArtifactsResource", "AsyncArtifactsResource"] + + +class ArtifactsResource(SyncAPIResource): + """Create and retrieve asynchronous summaries and action-item artifacts.""" + + @cached_property + def with_raw_response(self) -> ArtifactsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return ArtifactsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ArtifactsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return ArtifactsResourceWithStreamingResponse(self) + + def create( + self, + id: str, + *, + type: Literal["summary", "action_items"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionArtifactResponse: + """ + Requests asynchronous generation of one `summary` or `action_items` artifact. + Each type requires its own request. Generation requires transcript content and + configured inference and currently reads at most the first 10,000 segments, so + exceptionally long transcripts may produce incomplete artifacts or fail model + limits. + + Args: + type: Type of artifact to generate from the session. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/meeting_sessions/{id}/artifacts", id=id), + body=maybe_transform({"type": type}, artifact_create_params.ArtifactCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionArtifactResponse, + ) + + def retrieve( + self, + artifact_id: str, + *, + id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionArtifactResponse: + """ + Retrieves a single meeting session artifact by ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not artifact_id: + raise ValueError(f"Expected a non-empty value for `artifact_id` but received {artifact_id!r}") + return self._get( + path_template("/meeting_sessions/{id}/artifacts/{artifact_id}", id=id, artifact_id=artifact_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionArtifactResponse, + ) + + def list( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ArtifactListResponse: + """ + Returns a list of artifacts for a meeting session. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/meeting_sessions/{id}/artifacts", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ArtifactListResponse, + ) + + +class AsyncArtifactsResource(AsyncAPIResource): + """Create and retrieve asynchronous summaries and action-item artifacts.""" + + @cached_property + def with_raw_response(self) -> AsyncArtifactsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncArtifactsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncArtifactsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncArtifactsResourceWithStreamingResponse(self) + + async def create( + self, + id: str, + *, + type: Literal["summary", "action_items"], + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionArtifactResponse: + """ + Requests asynchronous generation of one `summary` or `action_items` artifact. + Each type requires its own request. Generation requires transcript content and + configured inference and currently reads at most the first 10,000 segments, so + exceptionally long transcripts may produce incomplete artifacts or fail model + limits. + + Args: + type: Type of artifact to generate from the session. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/meeting_sessions/{id}/artifacts", id=id), + body=await async_maybe_transform({"type": type}, artifact_create_params.ArtifactCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionArtifactResponse, + ) + + async def retrieve( + self, + artifact_id: str, + *, + id: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionArtifactResponse: + """ + Retrieves a single meeting session artifact by ID. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + if not artifact_id: + raise ValueError(f"Expected a non-empty value for `artifact_id` but received {artifact_id!r}") + return await self._get( + path_template("/meeting_sessions/{id}/artifacts/{artifact_id}", id=id, artifact_id=artifact_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionArtifactResponse, + ) + + async def list( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ArtifactListResponse: + """ + Returns a list of artifacts for a meeting session. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/meeting_sessions/{id}/artifacts", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ArtifactListResponse, + ) + + +class ArtifactsResourceWithRawResponse: + def __init__(self, artifacts: ArtifactsResource) -> None: + self._artifacts = artifacts + + self.create = to_raw_response_wrapper( + artifacts.create, + ) + self.retrieve = to_raw_response_wrapper( + artifacts.retrieve, + ) + self.list = to_raw_response_wrapper( + artifacts.list, + ) + + +class AsyncArtifactsResourceWithRawResponse: + def __init__(self, artifacts: AsyncArtifactsResource) -> None: + self._artifacts = artifacts + + self.create = async_to_raw_response_wrapper( + artifacts.create, + ) + self.retrieve = async_to_raw_response_wrapper( + artifacts.retrieve, + ) + self.list = async_to_raw_response_wrapper( + artifacts.list, + ) + + +class ArtifactsResourceWithStreamingResponse: + def __init__(self, artifacts: ArtifactsResource) -> None: + self._artifacts = artifacts + + self.create = to_streamed_response_wrapper( + artifacts.create, + ) + self.retrieve = to_streamed_response_wrapper( + artifacts.retrieve, + ) + self.list = to_streamed_response_wrapper( + artifacts.list, + ) + + +class AsyncArtifactsResourceWithStreamingResponse: + def __init__(self, artifacts: AsyncArtifactsResource) -> None: + self._artifacts = artifacts + + self.create = async_to_streamed_response_wrapper( + artifacts.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + artifacts.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + artifacts.list, + ) diff --git a/src/telnyx/resources/meeting_sessions/meeting_sessions.py b/src/telnyx/resources/meeting_sessions/meeting_sessions.py new file mode 100644 index 000000000..e1e424e44 --- /dev/null +++ b/src/telnyx/resources/meeting_sessions/meeting_sessions.py @@ -0,0 +1,1212 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union +from datetime import datetime +from typing_extensions import Literal + +import httpx + +from ...types import ( + meeting_session_list_params, + meeting_session_create_params, + meeting_session_update_params, + meeting_session_retrieve_events_params, + meeting_session_retrieve_transcript_params, +) +from .actions import ( + ActionsResource, + AsyncActionsResource, + ActionsResourceWithRawResponse, + AsyncActionsResourceWithRawResponse, + ActionsResourceWithStreamingResponse, + AsyncActionsResourceWithStreamingResponse, +) +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from .artifacts import ( + ArtifactsResource, + AsyncArtifactsResource, + ArtifactsResourceWithRawResponse, + AsyncArtifactsResourceWithRawResponse, + ArtifactsResourceWithStreamingResponse, + AsyncArtifactsResourceWithStreamingResponse, +) +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.meeting_session_response import MeetingSessionResponse +from ...types.meeting_session_list_response import MeetingSessionListResponse +from ...types.meeting_session_retrieve_events_response import MeetingSessionRetrieveEventsResponse +from ...types.meeting_session_retrieve_recordings_response import MeetingSessionRetrieveRecordingsResponse +from ...types.meeting_session_retrieve_transcript_response import MeetingSessionRetrieveTranscriptResponse +from ...types.meeting_session_delete_recording_media_response import MeetingSessionDeleteRecordingMediaResponse + +__all__ = ["MeetingSessionsResource", "AsyncMeetingSessionsResource"] + + +class MeetingSessionsResource(SyncAPIResource): + @cached_property + def actions(self) -> ActionsResource: + """Send real-time speech and chat actions to an active meeting session.""" + return ActionsResource(self._client) + + @cached_property + def artifacts(self) -> ArtifactsResource: + """Create and retrieve asynchronous summaries and action-item artifacts.""" + return ArtifactsResource(self._client) + + @cached_property + def with_raw_response(self) -> MeetingSessionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return MeetingSessionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> MeetingSessionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return MeetingSessionsResourceWithStreamingResponse(self) + + def create( + self, + *, + meeting_url: str, + assistant: meeting_session_create_params.Assistant | Omit = omit, + avatar: meeting_session_create_params.Avatar | Omit = omit, + barge_in: bool | Omit = omit, + bot_name: str | Omit = omit, + camera_image: meeting_session_create_params.CameraImage | Omit = omit, + idempotency_key: str | Omit = omit, + join_at: Union[str, datetime] | Omit = omit, + metadata: Dict[str, object] | Omit = omit, + speak_on_enter: str | Omit = omit, + summarize_on_end: bool | Omit = omit, + voice: str | Omit = omit, + webhook_url: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionResponse: + """Creates a new meeting session. + + When an idempotency_key is supplied in the + request body, replay lookup is scoped to the authenticated account and compares + only the key; the request payload is not fingerprinted or compared. If a session + with that key already exists for the account, the existing session is replayed + (200); otherwise a new session is created (201). Supports bring-your-own-key + (BYOK) configuration. The session may enter asynchronous states (e.g. joining, + waiting_for_admission) before becoming active. Optional `camera_image` input is + write-only and applies only when no Avatar or Assistant webpage output takes + precedence. An ignored URL is not fetched. An effective URL source is resolved + before bot creation; neither the source URL nor image bytes are persisted, + returned, or logged. Treat signed URLs as credentials. + + Args: + meeting_url: The meeting URL the bot should join. + + assistant: Request options for attaching a voice assistant to the session. Routing fields + (`call_control_connection_id`, `from`, and `loopback_sip_uri`) are used only to + establish the assistant call leg and are omitted from response objects. + `audio_gate` is returned with `id` in the assistant response object. + + avatar: Request options for attaching a bring-your-own-key avatar to the session. + + barge_in: When enabled, a human participant `speech_on` event interrupts and stops the + current bot audio; it does not bypass admission or initiate speech. Assistant + sessions reject `barge_in: true`. + + bot_name: Display name for the bot in the meeting. Defaults to "Meeting Bot". + + camera_image: Write-only static camera-tile image for this session, not a native account or + participant profile photo. Supply exactly one JPEG source. When effective, the + image is used as the bot's static camera/video output; presentation varies by + meeting platform and recording configuration and is not guaranteed in + recordings. An effective Avatar or Assistant webpage output takes precedence, so + this input is ignored and a URL source is not fetched. + + idempotency_key: Client-supplied idempotency key to safely retry creation requests without + duplicating sessions. Lookup is scoped to the authenticated account and compares + the key only; the request payload is not fingerprinted or compared. + + join_at: ISO-8601 timestamp in the future at which the bot should join. If omitted, the + bot joins immediately. + + metadata: Arbitrary key-value metadata attached to the session. The serialized JSON + representation must not exceed 16384 characters at runtime. + + speak_on_enter: Text the bot speaks when it enters the meeting. + + summarize_on_end: If true, generate a summary artifact when the session ends. + + voice: Session-default voice identifier used for `speak_on_enter` and ordinary speak + actions. A voice supplied on an individual speak action overrides this default + for that utterance. + + webhook_url: HTTPS endpoint to receive session lifecycle callbacks. Static validation + requires HTTPS, rejects embedded credentials and blocked hosts, and enforces + egress policy. Validation makes no network request to the endpoint. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/meeting_sessions", + body=maybe_transform( + { + "meeting_url": meeting_url, + "assistant": assistant, + "avatar": avatar, + "barge_in": barge_in, + "bot_name": bot_name, + "camera_image": camera_image, + "idempotency_key": idempotency_key, + "join_at": join_at, + "metadata": metadata, + "speak_on_enter": speak_on_enter, + "summarize_on_end": summarize_on_end, + "voice": voice, + "webhook_url": webhook_url, + }, + meeting_session_create_params.MeetingSessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionResponse, + ) + + def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionResponse: + """Retrieves a single meeting session by ID. + + A session that does not exist or that + belongs to a different account both return 404. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/meeting_sessions/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionResponse, + ) + + def update( + self, + id: str, + *, + bot_name: str | Omit = omit, + join_at: Union[str, datetime] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionResponse: + """Updates mutable properties of a meeting session. + + Only sessions in the scheduled + state can be updated; any other state returns 409 with the invalid_state error + code. All request fields are optional, and an empty object is a valid no-op + update. + + Args: + bot_name: Updated display name for the bot. + + join_at: ISO-8601 timestamp for the bot to join. May be updated to reschedule. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._patch( + path_template("/meeting_sessions/{id}", id=id), + body=maybe_transform( + { + "bot_name": bot_name, + "join_at": join_at, + }, + meeting_session_update_params.MeetingSessionUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionResponse, + ) + + def list( + self, + *, + status: Literal[ + "scheduled", "joining", "waiting_for_admission", "active", "leaving", "ended", "failed", "admission_denied" + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionListResponse: + """ + Returns a list of meeting sessions, optionally filtered by status. + + Args: + status: Filter meeting sessions by current status. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get( + "/meeting_sessions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"status": status}, meeting_session_list_params.MeetingSessionListParams), + ), + cast_to=MeetingSessionListResponse, + ) + + def delete( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionResponse: + """Stops a meeting session without deleting its persisted record. + + Scheduled bots + are cancelled, while bots that are joining or active are asked to leave. The + persisted meeting session record remains available. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._delete( + path_template("/meeting_sessions/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionResponse, + ) + + def delete_recording_media( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionDeleteRecordingMediaResponse: + """ + **Not yet available in production** — this route is not currently routed on + api.telnyx.com and returns a generic 404; it is documented ahead of rollout. + Irreversibly requests deletion of provider-hosted aggregate recording media + under the provider contract. The operation retains the Telnyx-local Meeting + session, transcript segments, events, artifacts, and usage records. It is + separate from `DELETE /meeting_sessions/{id}`, which stops or cancels + participation without deleting the persisted session. A missing/foreign session + returns 404; provider deletion failures return 502. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._delete( + path_template("/meeting_sessions/{id}/recording_media", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionDeleteRecordingMediaResponse, + ) + + def retrieve_events( + self, + id: str, + *, + after: int | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionRetrieveEventsResponse: + """Returns stored events ordered by ascending `seq`. + + To continue, pass the last + returned item's `seq` as `after`. An empty page means no later stored events + existed at read time; this operation returns no separate next-page cursor. + Default `limit` is 100 and maximum is 1,000. + + Args: + after: Return results with a cursor position after this value. + + limit: Maximum number of results to return per page. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/meeting_sessions/{id}/events", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + }, + meeting_session_retrieve_events_params.MeetingSessionRetrieveEventsParams, + ), + ), + cast_to=MeetingSessionRetrieveEventsResponse, + ) + + def retrieve_recordings( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionRetrieveRecordingsResponse: + """ + Returns recordings for a meeting session. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/meeting_sessions/{id}/recordings", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionRetrieveRecordingsResponse, + ) + + def retrieve_transcript( + self, + id: str, + *, + after: int | Omit = omit, + limit: int | Omit = omit, + wait_seconds: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionRetrieveTranscriptResponse: + """Returns transcript segments ordered by ascending `seq`. + + Default `limit` is 100 + and maximum is 1,000. Continue with `after=meta.next_after`. A long-poll timeout + returns 200 with empty `data` and `meta.next_after: null`; retain the cursor + supplied to that request because null is not a replacement cursor. + + Args: + after: Return results with a cursor position after this value. + + limit: Maximum number of results to return per page. + + wait_seconds: Long-poll duration in seconds. The server holds the connection open for up to + this many seconds, waiting for new or updated results before returning an empty + response. Set to 0 for an immediate response. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/meeting_sessions/{id}/transcript", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "after": after, + "limit": limit, + "wait_seconds": wait_seconds, + }, + meeting_session_retrieve_transcript_params.MeetingSessionRetrieveTranscriptParams, + ), + ), + cast_to=MeetingSessionRetrieveTranscriptResponse, + ) + + +class AsyncMeetingSessionsResource(AsyncAPIResource): + @cached_property + def actions(self) -> AsyncActionsResource: + """Send real-time speech and chat actions to an active meeting session.""" + return AsyncActionsResource(self._client) + + @cached_property + def artifacts(self) -> AsyncArtifactsResource: + """Create and retrieve asynchronous summaries and action-item artifacts.""" + return AsyncArtifactsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncMeetingSessionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncMeetingSessionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncMeetingSessionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncMeetingSessionsResourceWithStreamingResponse(self) + + async def create( + self, + *, + meeting_url: str, + assistant: meeting_session_create_params.Assistant | Omit = omit, + avatar: meeting_session_create_params.Avatar | Omit = omit, + barge_in: bool | Omit = omit, + bot_name: str | Omit = omit, + camera_image: meeting_session_create_params.CameraImage | Omit = omit, + idempotency_key: str | Omit = omit, + join_at: Union[str, datetime] | Omit = omit, + metadata: Dict[str, object] | Omit = omit, + speak_on_enter: str | Omit = omit, + summarize_on_end: bool | Omit = omit, + voice: str | Omit = omit, + webhook_url: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionResponse: + """Creates a new meeting session. + + When an idempotency_key is supplied in the + request body, replay lookup is scoped to the authenticated account and compares + only the key; the request payload is not fingerprinted or compared. If a session + with that key already exists for the account, the existing session is replayed + (200); otherwise a new session is created (201). Supports bring-your-own-key + (BYOK) configuration. The session may enter asynchronous states (e.g. joining, + waiting_for_admission) before becoming active. Optional `camera_image` input is + write-only and applies only when no Avatar or Assistant webpage output takes + precedence. An ignored URL is not fetched. An effective URL source is resolved + before bot creation; neither the source URL nor image bytes are persisted, + returned, or logged. Treat signed URLs as credentials. + + Args: + meeting_url: The meeting URL the bot should join. + + assistant: Request options for attaching a voice assistant to the session. Routing fields + (`call_control_connection_id`, `from`, and `loopback_sip_uri`) are used only to + establish the assistant call leg and are omitted from response objects. + `audio_gate` is returned with `id` in the assistant response object. + + avatar: Request options for attaching a bring-your-own-key avatar to the session. + + barge_in: When enabled, a human participant `speech_on` event interrupts and stops the + current bot audio; it does not bypass admission or initiate speech. Assistant + sessions reject `barge_in: true`. + + bot_name: Display name for the bot in the meeting. Defaults to "Meeting Bot". + + camera_image: Write-only static camera-tile image for this session, not a native account or + participant profile photo. Supply exactly one JPEG source. When effective, the + image is used as the bot's static camera/video output; presentation varies by + meeting platform and recording configuration and is not guaranteed in + recordings. An effective Avatar or Assistant webpage output takes precedence, so + this input is ignored and a URL source is not fetched. + + idempotency_key: Client-supplied idempotency key to safely retry creation requests without + duplicating sessions. Lookup is scoped to the authenticated account and compares + the key only; the request payload is not fingerprinted or compared. + + join_at: ISO-8601 timestamp in the future at which the bot should join. If omitted, the + bot joins immediately. + + metadata: Arbitrary key-value metadata attached to the session. The serialized JSON + representation must not exceed 16384 characters at runtime. + + speak_on_enter: Text the bot speaks when it enters the meeting. + + summarize_on_end: If true, generate a summary artifact when the session ends. + + voice: Session-default voice identifier used for `speak_on_enter` and ordinary speak + actions. A voice supplied on an individual speak action overrides this default + for that utterance. + + webhook_url: HTTPS endpoint to receive session lifecycle callbacks. Static validation + requires HTTPS, rejects embedded credentials and blocked hosts, and enforces + egress policy. Validation makes no network request to the endpoint. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/meeting_sessions", + body=await async_maybe_transform( + { + "meeting_url": meeting_url, + "assistant": assistant, + "avatar": avatar, + "barge_in": barge_in, + "bot_name": bot_name, + "camera_image": camera_image, + "idempotency_key": idempotency_key, + "join_at": join_at, + "metadata": metadata, + "speak_on_enter": speak_on_enter, + "summarize_on_end": summarize_on_end, + "voice": voice, + "webhook_url": webhook_url, + }, + meeting_session_create_params.MeetingSessionCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionResponse, + ) + + async def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionResponse: + """Retrieves a single meeting session by ID. + + A session that does not exist or that + belongs to a different account both return 404. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/meeting_sessions/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionResponse, + ) + + async def update( + self, + id: str, + *, + bot_name: str | Omit = omit, + join_at: Union[str, datetime] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionResponse: + """Updates mutable properties of a meeting session. + + Only sessions in the scheduled + state can be updated; any other state returns 409 with the invalid_state error + code. All request fields are optional, and an empty object is a valid no-op + update. + + Args: + bot_name: Updated display name for the bot. + + join_at: ISO-8601 timestamp for the bot to join. May be updated to reschedule. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._patch( + path_template("/meeting_sessions/{id}", id=id), + body=await async_maybe_transform( + { + "bot_name": bot_name, + "join_at": join_at, + }, + meeting_session_update_params.MeetingSessionUpdateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionResponse, + ) + + async def list( + self, + *, + status: Literal[ + "scheduled", "joining", "waiting_for_admission", "active", "leaving", "ended", "failed", "admission_denied" + ] + | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionListResponse: + """ + Returns a list of meeting sessions, optionally filtered by status. + + Args: + status: Filter meeting sessions by current status. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._get( + "/meeting_sessions", + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + {"status": status}, meeting_session_list_params.MeetingSessionListParams + ), + ), + cast_to=MeetingSessionListResponse, + ) + + async def delete( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionResponse: + """Stops a meeting session without deleting its persisted record. + + Scheduled bots + are cancelled, while bots that are joining or active are asked to leave. The + persisted meeting session record remains available. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._delete( + path_template("/meeting_sessions/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionResponse, + ) + + async def delete_recording_media( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionDeleteRecordingMediaResponse: + """ + **Not yet available in production** — this route is not currently routed on + api.telnyx.com and returns a generic 404; it is documented ahead of rollout. + Irreversibly requests deletion of provider-hosted aggregate recording media + under the provider contract. The operation retains the Telnyx-local Meeting + session, transcript segments, events, artifacts, and usage records. It is + separate from `DELETE /meeting_sessions/{id}`, which stops or cancels + participation without deleting the persisted session. A missing/foreign session + returns 404; provider deletion failures return 502. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._delete( + path_template("/meeting_sessions/{id}/recording_media", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionDeleteRecordingMediaResponse, + ) + + async def retrieve_events( + self, + id: str, + *, + after: int | Omit = omit, + limit: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionRetrieveEventsResponse: + """Returns stored events ordered by ascending `seq`. + + To continue, pass the last + returned item's `seq` as `after`. An empty page means no later stored events + existed at read time; this operation returns no separate next-page cursor. + Default `limit` is 100 and maximum is 1,000. + + Args: + after: Return results with a cursor position after this value. + + limit: Maximum number of results to return per page. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/meeting_sessions/{id}/events", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "after": after, + "limit": limit, + }, + meeting_session_retrieve_events_params.MeetingSessionRetrieveEventsParams, + ), + ), + cast_to=MeetingSessionRetrieveEventsResponse, + ) + + async def retrieve_recordings( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionRetrieveRecordingsResponse: + """ + Returns recordings for a meeting session. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/meeting_sessions/{id}/recordings", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=MeetingSessionRetrieveRecordingsResponse, + ) + + async def retrieve_transcript( + self, + id: str, + *, + after: int | Omit = omit, + limit: int | Omit = omit, + wait_seconds: int | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> MeetingSessionRetrieveTranscriptResponse: + """Returns transcript segments ordered by ascending `seq`. + + Default `limit` is 100 + and maximum is 1,000. Continue with `after=meta.next_after`. A long-poll timeout + returns 200 with empty `data` and `meta.next_after: null`; retain the cursor + supplied to that request because null is not a replacement cursor. + + Args: + after: Return results with a cursor position after this value. + + limit: Maximum number of results to return per page. + + wait_seconds: Long-poll duration in seconds. The server holds the connection open for up to + this many seconds, waiting for new or updated results before returning an empty + response. Set to 0 for an immediate response. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/meeting_sessions/{id}/transcript", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform( + { + "after": after, + "limit": limit, + "wait_seconds": wait_seconds, + }, + meeting_session_retrieve_transcript_params.MeetingSessionRetrieveTranscriptParams, + ), + ), + cast_to=MeetingSessionRetrieveTranscriptResponse, + ) + + +class MeetingSessionsResourceWithRawResponse: + def __init__(self, meeting_sessions: MeetingSessionsResource) -> None: + self._meeting_sessions = meeting_sessions + + self.create = to_raw_response_wrapper( + meeting_sessions.create, + ) + self.retrieve = to_raw_response_wrapper( + meeting_sessions.retrieve, + ) + self.update = to_raw_response_wrapper( + meeting_sessions.update, + ) + self.list = to_raw_response_wrapper( + meeting_sessions.list, + ) + self.delete = to_raw_response_wrapper( + meeting_sessions.delete, + ) + self.delete_recording_media = to_raw_response_wrapper( + meeting_sessions.delete_recording_media, + ) + self.retrieve_events = to_raw_response_wrapper( + meeting_sessions.retrieve_events, + ) + self.retrieve_recordings = to_raw_response_wrapper( + meeting_sessions.retrieve_recordings, + ) + self.retrieve_transcript = to_raw_response_wrapper( + meeting_sessions.retrieve_transcript, + ) + + @cached_property + def actions(self) -> ActionsResourceWithRawResponse: + """Send real-time speech and chat actions to an active meeting session.""" + return ActionsResourceWithRawResponse(self._meeting_sessions.actions) + + @cached_property + def artifacts(self) -> ArtifactsResourceWithRawResponse: + """Create and retrieve asynchronous summaries and action-item artifacts.""" + return ArtifactsResourceWithRawResponse(self._meeting_sessions.artifacts) + + +class AsyncMeetingSessionsResourceWithRawResponse: + def __init__(self, meeting_sessions: AsyncMeetingSessionsResource) -> None: + self._meeting_sessions = meeting_sessions + + self.create = async_to_raw_response_wrapper( + meeting_sessions.create, + ) + self.retrieve = async_to_raw_response_wrapper( + meeting_sessions.retrieve, + ) + self.update = async_to_raw_response_wrapper( + meeting_sessions.update, + ) + self.list = async_to_raw_response_wrapper( + meeting_sessions.list, + ) + self.delete = async_to_raw_response_wrapper( + meeting_sessions.delete, + ) + self.delete_recording_media = async_to_raw_response_wrapper( + meeting_sessions.delete_recording_media, + ) + self.retrieve_events = async_to_raw_response_wrapper( + meeting_sessions.retrieve_events, + ) + self.retrieve_recordings = async_to_raw_response_wrapper( + meeting_sessions.retrieve_recordings, + ) + self.retrieve_transcript = async_to_raw_response_wrapper( + meeting_sessions.retrieve_transcript, + ) + + @cached_property + def actions(self) -> AsyncActionsResourceWithRawResponse: + """Send real-time speech and chat actions to an active meeting session.""" + return AsyncActionsResourceWithRawResponse(self._meeting_sessions.actions) + + @cached_property + def artifacts(self) -> AsyncArtifactsResourceWithRawResponse: + """Create and retrieve asynchronous summaries and action-item artifacts.""" + return AsyncArtifactsResourceWithRawResponse(self._meeting_sessions.artifacts) + + +class MeetingSessionsResourceWithStreamingResponse: + def __init__(self, meeting_sessions: MeetingSessionsResource) -> None: + self._meeting_sessions = meeting_sessions + + self.create = to_streamed_response_wrapper( + meeting_sessions.create, + ) + self.retrieve = to_streamed_response_wrapper( + meeting_sessions.retrieve, + ) + self.update = to_streamed_response_wrapper( + meeting_sessions.update, + ) + self.list = to_streamed_response_wrapper( + meeting_sessions.list, + ) + self.delete = to_streamed_response_wrapper( + meeting_sessions.delete, + ) + self.delete_recording_media = to_streamed_response_wrapper( + meeting_sessions.delete_recording_media, + ) + self.retrieve_events = to_streamed_response_wrapper( + meeting_sessions.retrieve_events, + ) + self.retrieve_recordings = to_streamed_response_wrapper( + meeting_sessions.retrieve_recordings, + ) + self.retrieve_transcript = to_streamed_response_wrapper( + meeting_sessions.retrieve_transcript, + ) + + @cached_property + def actions(self) -> ActionsResourceWithStreamingResponse: + """Send real-time speech and chat actions to an active meeting session.""" + return ActionsResourceWithStreamingResponse(self._meeting_sessions.actions) + + @cached_property + def artifacts(self) -> ArtifactsResourceWithStreamingResponse: + """Create and retrieve asynchronous summaries and action-item artifacts.""" + return ArtifactsResourceWithStreamingResponse(self._meeting_sessions.artifacts) + + +class AsyncMeetingSessionsResourceWithStreamingResponse: + def __init__(self, meeting_sessions: AsyncMeetingSessionsResource) -> None: + self._meeting_sessions = meeting_sessions + + self.create = async_to_streamed_response_wrapper( + meeting_sessions.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + meeting_sessions.retrieve, + ) + self.update = async_to_streamed_response_wrapper( + meeting_sessions.update, + ) + self.list = async_to_streamed_response_wrapper( + meeting_sessions.list, + ) + self.delete = async_to_streamed_response_wrapper( + meeting_sessions.delete, + ) + self.delete_recording_media = async_to_streamed_response_wrapper( + meeting_sessions.delete_recording_media, + ) + self.retrieve_events = async_to_streamed_response_wrapper( + meeting_sessions.retrieve_events, + ) + self.retrieve_recordings = async_to_streamed_response_wrapper( + meeting_sessions.retrieve_recordings, + ) + self.retrieve_transcript = async_to_streamed_response_wrapper( + meeting_sessions.retrieve_transcript, + ) + + @cached_property + def actions(self) -> AsyncActionsResourceWithStreamingResponse: + """Send real-time speech and chat actions to an active meeting session.""" + return AsyncActionsResourceWithStreamingResponse(self._meeting_sessions.actions) + + @cached_property + def artifacts(self) -> AsyncArtifactsResourceWithStreamingResponse: + """Create and retrieve asynchronous summaries and action-item artifacts.""" + return AsyncArtifactsResourceWithStreamingResponse(self._meeting_sessions.artifacts) diff --git a/src/telnyx/resources/phone_numbers/voicemail.py b/src/telnyx/resources/phone_numbers/voicemail.py index b26bdb0a2..d470795b6 100644 --- a/src/telnyx/resources/phone_numbers/voicemail.py +++ b/src/telnyx/resources/phone_numbers/voicemail.py @@ -50,6 +50,7 @@ def create( phone_number_id: str, *, enabled: bool | Omit = omit, + greeting: voicemail_create_params.Greeting | Omit = omit, pin: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -58,12 +59,22 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VoicemailCreateResponse: - """ - Create voicemail settings for a phone number + """Create voicemail settings for a phone number. + + You can also configure a custom + greeting by setting the `greeting` object: use `mode` `custom_greeting` together + with a `media_name` that points to an audio file uploaded through the Media + Storage API, or `mode` `default` to use the standard system greeting. Args: enabled: Whether voicemail is enabled. + greeting: Controls the greeting a caller hears before leaving a voicemail. Set `mode` to + `default` to play the standard system greeting, or to `custom_greeting` to play + your own audio. When `mode` is `custom_greeting`, `media_name` is required and + must reference an audio file already uploaded to your account through the Media + Storage API. + pin: The pin used for voicemail extra_headers: Send extra headers @@ -81,6 +92,7 @@ def create( body=maybe_transform( { "enabled": enabled, + "greeting": greeting, "pin": pin, }, voicemail_create_params.VoicemailCreateParams, @@ -129,6 +141,7 @@ def update( phone_number_id: str, *, enabled: bool | Omit = omit, + greeting: voicemail_update_params.Greeting | Omit = omit, pin: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -137,12 +150,22 @@ def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VoicemailUpdateResponse: - """ - Update voicemail settings for a phone number + """Update voicemail settings for a phone number. + + You can also configure a custom + greeting by setting the `greeting` object: use `mode` `custom_greeting` together + with a `media_name` that points to an audio file uploaded through the Media + Storage API, or `mode` `default` to use the standard system greeting. Args: enabled: Whether voicemail is enabled. + greeting: Controls the greeting a caller hears before leaving a voicemail. Set `mode` to + `default` to play the standard system greeting, or to `custom_greeting` to play + your own audio. When `mode` is `custom_greeting`, `media_name` is required and + must reference an audio file already uploaded to your account through the Media + Storage API. + pin: The pin used for voicemail extra_headers: Send extra headers @@ -160,6 +183,7 @@ def update( body=maybe_transform( { "enabled": enabled, + "greeting": greeting, "pin": pin, }, voicemail_update_params.VoicemailUpdateParams, @@ -198,6 +222,7 @@ async def create( phone_number_id: str, *, enabled: bool | Omit = omit, + greeting: voicemail_create_params.Greeting | Omit = omit, pin: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -206,12 +231,22 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VoicemailCreateResponse: - """ - Create voicemail settings for a phone number + """Create voicemail settings for a phone number. + + You can also configure a custom + greeting by setting the `greeting` object: use `mode` `custom_greeting` together + with a `media_name` that points to an audio file uploaded through the Media + Storage API, or `mode` `default` to use the standard system greeting. Args: enabled: Whether voicemail is enabled. + greeting: Controls the greeting a caller hears before leaving a voicemail. Set `mode` to + `default` to play the standard system greeting, or to `custom_greeting` to play + your own audio. When `mode` is `custom_greeting`, `media_name` is required and + must reference an audio file already uploaded to your account through the Media + Storage API. + pin: The pin used for voicemail extra_headers: Send extra headers @@ -229,6 +264,7 @@ async def create( body=await async_maybe_transform( { "enabled": enabled, + "greeting": greeting, "pin": pin, }, voicemail_create_params.VoicemailCreateParams, @@ -277,6 +313,7 @@ async def update( phone_number_id: str, *, enabled: bool | Omit = omit, + greeting: voicemail_update_params.Greeting | Omit = omit, pin: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. @@ -285,12 +322,22 @@ async def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> VoicemailUpdateResponse: - """ - Update voicemail settings for a phone number + """Update voicemail settings for a phone number. + + You can also configure a custom + greeting by setting the `greeting` object: use `mode` `custom_greeting` together + with a `media_name` that points to an audio file uploaded through the Media + Storage API, or `mode` `default` to use the standard system greeting. Args: enabled: Whether voicemail is enabled. + greeting: Controls the greeting a caller hears before leaving a voicemail. Set `mode` to + `default` to play the standard system greeting, or to `custom_greeting` to play + your own audio. When `mode` is `custom_greeting`, `media_name` is required and + must reference an audio file already uploaded to your account through the Media + Storage API. + pin: The pin used for voicemail extra_headers: Send extra headers @@ -308,6 +355,7 @@ async def update( body=await async_maybe_transform( { "enabled": enabled, + "greeting": greeting, "pin": pin, }, voicemail_update_params.VoicemailUpdateParams, diff --git a/src/telnyx/resources/sim_cards/actions.py b/src/telnyx/resources/sim_cards/actions.py index facf7881f..4ec789536 100644 --- a/src/telnyx/resources/sim_cards/actions.py +++ b/src/telnyx/resources/sim_cards/actions.py @@ -18,6 +18,7 @@ from ..._base_client import AsyncPaginator, make_request_options from ...types.sim_cards import ( action_list_params, + action_enable_voice_params, action_set_public_ip_params, action_bulk_enable_voice_params, action_bulk_disable_voice_params, @@ -29,6 +30,8 @@ from ...types.sim_cards.action_retrieve_response import ActionRetrieveResponse from ...types.sim_cards.wireless_sim_card_action import WirelessSimCardAction from ...types.sim_cards.action_set_standby_response import ActionSetStandbyResponse +from ...types.sim_cards.action_enable_voice_response import ActionEnableVoiceResponse +from ...types.sim_cards.action_disable_voice_response import ActionDisableVoiceResponse from ...types.sim_cards.action_set_public_ip_response import ActionSetPublicIPResponse from ...types.sim_cards.action_remove_public_ip_response import ActionRemovePublicIPResponse from ...types.sim_cards.action_bulk_enable_voice_response import ActionBulkEnableVoiceResponse @@ -191,6 +194,7 @@ def bulk_enable_voice( self, *, sim_card_group_id: str, + connection_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -211,6 +215,11 @@ def bulk_enable_voice( API. Args: + connection_id: The identifier of the Mobile Voice Connection to associate with the SIM cards. + The connection must be owned by the same user and of type + mobile_voice. If omitted, voice is enabled without a connection + association. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -222,7 +231,11 @@ def bulk_enable_voice( return self._post( "/sim_cards/actions/bulk_enable_voice", body=maybe_transform( - {"sim_card_group_id": sim_card_group_id}, action_bulk_enable_voice_params.ActionBulkEnableVoiceParams + { + "sim_card_group_id": sim_card_group_id, + "connection_id": connection_id, + }, + action_bulk_enable_voice_params.ActionBulkEnableVoiceParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -306,6 +319,45 @@ def disable( cast_to=ActionDisableResponse, ) + def disable_voice( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionDisableVoiceResponse: + """This API disables voice calling on a SIM card. + + The SIM card will no longer be + able to make or receive calls.
The API will trigger an asynchronous + operation called a SIM Card Action. The status of the SIM Card Action can be + followed through the + [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) + API. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/sim_cards/{id}/actions/disable_voice", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionDisableVoiceResponse, + ) + def enable( self, id: str, @@ -345,6 +397,54 @@ def enable( cast_to=ActionEnableResponse, ) + def enable_voice( + self, + id: str, + *, + connection_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionEnableVoiceResponse: + """This API enables voice calling on a SIM card. + + When a connection_id + is provided, the SIM is associated with the specified Mobile Voice Connection. + The connection must be owned by the same user and of type + mobile_voice.
The API will trigger an asynchronous operation + called a SIM Card Action. The status of the SIM Card Action can be followed + through the + [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) + API. + + Args: + connection_id: The identifier of the Mobile Voice Connection to associate with this SIM card. + The connection must be owned by the same user and of type + mobile_voice. If omitted, voice is enabled without a connection + association. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/sim_cards/{id}/actions/enable_voice", id=id), + body=maybe_transform({"connection_id": connection_id}, action_enable_voice_params.ActionEnableVoiceParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionEnableVoiceResponse, + ) + def remove_public_ip( self, id: str, @@ -660,6 +760,7 @@ async def bulk_enable_voice( self, *, sim_card_group_id: str, + connection_id: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. # The extra values given here take precedence over values defined on the client or passed to this method. extra_headers: Headers | None = None, @@ -680,6 +781,11 @@ async def bulk_enable_voice( API. Args: + connection_id: The identifier of the Mobile Voice Connection to associate with the SIM cards. + The connection must be owned by the same user and of type + mobile_voice. If omitted, voice is enabled without a connection + association. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -691,7 +797,11 @@ async def bulk_enable_voice( return await self._post( "/sim_cards/actions/bulk_enable_voice", body=await async_maybe_transform( - {"sim_card_group_id": sim_card_group_id}, action_bulk_enable_voice_params.ActionBulkEnableVoiceParams + { + "sim_card_group_id": sim_card_group_id, + "connection_id": connection_id, + }, + action_bulk_enable_voice_params.ActionBulkEnableVoiceParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -775,6 +885,45 @@ async def disable( cast_to=ActionDisableResponse, ) + async def disable_voice( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionDisableVoiceResponse: + """This API disables voice calling on a SIM card. + + The SIM card will no longer be + able to make or receive calls.
The API will trigger an asynchronous + operation called a SIM Card Action. The status of the SIM Card Action can be + followed through the + [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) + API. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/sim_cards/{id}/actions/disable_voice", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionDisableVoiceResponse, + ) + async def enable( self, id: str, @@ -814,6 +963,56 @@ async def enable( cast_to=ActionEnableResponse, ) + async def enable_voice( + self, + id: str, + *, + connection_id: str | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionEnableVoiceResponse: + """This API enables voice calling on a SIM card. + + When a connection_id + is provided, the SIM is associated with the specified Mobile Voice Connection. + The connection must be owned by the same user and of type + mobile_voice.
The API will trigger an asynchronous operation + called a SIM Card Action. The status of the SIM Card Action can be followed + through the + [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) + API. + + Args: + connection_id: The identifier of the Mobile Voice Connection to associate with this SIM card. + The connection must be owned by the same user and of type + mobile_voice. If omitted, voice is enabled without a connection + association. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/sim_cards/{id}/actions/enable_voice", id=id), + body=await async_maybe_transform( + {"connection_id": connection_id}, action_enable_voice_params.ActionEnableVoiceParams + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionEnableVoiceResponse, + ) + async def remove_public_ip( self, id: str, @@ -999,9 +1198,15 @@ def __init__(self, actions: ActionsResource) -> None: self.disable = to_raw_response_wrapper( actions.disable, ) + self.disable_voice = to_raw_response_wrapper( + actions.disable_voice, + ) self.enable = to_raw_response_wrapper( actions.enable, ) + self.enable_voice = to_raw_response_wrapper( + actions.enable_voice, + ) self.remove_public_ip = to_raw_response_wrapper( actions.remove_public_ip, ) @@ -1038,9 +1243,15 @@ def __init__(self, actions: AsyncActionsResource) -> None: self.disable = async_to_raw_response_wrapper( actions.disable, ) + self.disable_voice = async_to_raw_response_wrapper( + actions.disable_voice, + ) self.enable = async_to_raw_response_wrapper( actions.enable, ) + self.enable_voice = async_to_raw_response_wrapper( + actions.enable_voice, + ) self.remove_public_ip = async_to_raw_response_wrapper( actions.remove_public_ip, ) @@ -1077,9 +1288,15 @@ def __init__(self, actions: ActionsResource) -> None: self.disable = to_streamed_response_wrapper( actions.disable, ) + self.disable_voice = to_streamed_response_wrapper( + actions.disable_voice, + ) self.enable = to_streamed_response_wrapper( actions.enable, ) + self.enable_voice = to_streamed_response_wrapper( + actions.enable_voice, + ) self.remove_public_ip = to_streamed_response_wrapper( actions.remove_public_ip, ) @@ -1116,9 +1333,15 @@ def __init__(self, actions: AsyncActionsResource) -> None: self.disable = async_to_streamed_response_wrapper( actions.disable, ) + self.disable_voice = async_to_streamed_response_wrapper( + actions.disable_voice, + ) self.enable = async_to_streamed_response_wrapper( actions.enable, ) + self.enable_voice = async_to_streamed_response_wrapper( + actions.enable_voice, + ) self.remove_public_ip = async_to_streamed_response_wrapper( actions.remove_public_ip, ) diff --git a/src/telnyx/resources/storage/__init__.py b/src/telnyx/resources/storage/__init__.py index c67865182..7a17aa020 100644 --- a/src/telnyx/resources/storage/__init__.py +++ b/src/telnyx/resources/storage/__init__.py @@ -8,6 +8,14 @@ KvsResourceWithStreamingResponse, AsyncKvsResourceWithStreamingResponse, ) +from .sqldbs import ( + SqldbsResource, + AsyncSqldbsResource, + SqldbsResourceWithRawResponse, + AsyncSqldbsResourceWithRawResponse, + SqldbsResourceWithStreamingResponse, + AsyncSqldbsResourceWithStreamingResponse, +) from .buckets import ( BucketsResource, AsyncBucketsResource, @@ -80,6 +88,12 @@ "AsyncCloudfsResourceWithRawResponse", "CloudfsResourceWithStreamingResponse", "AsyncCloudfsResourceWithStreamingResponse", + "SqldbsResource", + "AsyncSqldbsResource", + "SqldbsResourceWithRawResponse", + "AsyncSqldbsResourceWithRawResponse", + "SqldbsResourceWithStreamingResponse", + "AsyncSqldbsResourceWithStreamingResponse", "StorageResource", "AsyncStorageResource", "StorageResourceWithRawResponse", diff --git a/src/telnyx/resources/storage/sqldbs/__init__.py b/src/telnyx/resources/storage/sqldbs/__init__.py new file mode 100644 index 000000000..dddf0c4f4 --- /dev/null +++ b/src/telnyx/resources/storage/sqldbs/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .sqldbs import ( + SqldbsResource, + AsyncSqldbsResource, + SqldbsResourceWithRawResponse, + AsyncSqldbsResourceWithRawResponse, + SqldbsResourceWithStreamingResponse, + AsyncSqldbsResourceWithStreamingResponse, +) +from .actions import ( + ActionsResource, + AsyncActionsResource, + ActionsResourceWithRawResponse, + AsyncActionsResourceWithRawResponse, + ActionsResourceWithStreamingResponse, + AsyncActionsResourceWithStreamingResponse, +) + +__all__ = [ + "ActionsResource", + "AsyncActionsResource", + "ActionsResourceWithRawResponse", + "AsyncActionsResourceWithRawResponse", + "ActionsResourceWithStreamingResponse", + "AsyncActionsResourceWithStreamingResponse", + "SqldbsResource", + "AsyncSqldbsResource", + "SqldbsResourceWithRawResponse", + "AsyncSqldbsResourceWithRawResponse", + "SqldbsResourceWithStreamingResponse", + "AsyncSqldbsResourceWithStreamingResponse", +] diff --git a/src/telnyx/resources/storage/sqldbs/actions.py b/src/telnyx/resources/storage/sqldbs/actions.py new file mode 100644 index 000000000..6951b6d2b --- /dev/null +++ b/src/telnyx/resources/storage/sqldbs/actions.py @@ -0,0 +1,213 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union + +import httpx + +from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ...._base_client import make_request_options +from ....types.storage.sqldbs import action_query_params +from ....types.storage.sqldbs.action_query_response import ActionQueryResponse + +__all__ = ["ActionsResource", "AsyncActionsResource"] + + +class ActionsResource(SyncAPIResource): + """Manage SQL databases and run SQL against them""" + + @cached_property + def with_raw_response(self) -> ActionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return ActionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ActionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return ActionsResourceWithStreamingResponse(self) + + def query( + self, + id: str, + *, + sql: str, + params: SequenceNotStr[Union[str, float, bool, None]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionQueryResponse: + """ + Runs SQL against the database and returns the resulting rows — empty for + statements that return none, such as DDL. Bind positional `?` placeholders with + `params` rather than interpolating values into the SQL string. + + Args: + sql: The SQL to run. Use positional `?` placeholders and supply the values in + `params` rather than interpolating them into this string. + + params: Positional bind parameters, in placeholder order. Each value is a string, a + number, a boolean, or null; booleans are cast to `1`/`0`. The count must match + the number of `?` placeholders exactly — a mismatch is rejected with 422 rather + than binding null for the ones you left out. (Not enforced for multi-statement + scripts or named parameters, where the placeholder count is not the number + bound.) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._post( + path_template("/storage/sqldbs/{id}/actions/query", id=id), + body=maybe_transform( + { + "sql": sql, + "params": params, + }, + action_query_params.ActionQueryParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionQueryResponse, + ) + + +class AsyncActionsResource(AsyncAPIResource): + """Manage SQL databases and run SQL against them""" + + @cached_property + def with_raw_response(self) -> AsyncActionsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncActionsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncActionsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncActionsResourceWithStreamingResponse(self) + + async def query( + self, + id: str, + *, + sql: str, + params: SequenceNotStr[Union[str, float, bool, None]] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ActionQueryResponse: + """ + Runs SQL against the database and returns the resulting rows — empty for + statements that return none, such as DDL. Bind positional `?` placeholders with + `params` rather than interpolating values into the SQL string. + + Args: + sql: The SQL to run. Use positional `?` placeholders and supply the values in + `params` rather than interpolating them into this string. + + params: Positional bind parameters, in placeholder order. Each value is a string, a + number, a boolean, or null; booleans are cast to `1`/`0`. The count must match + the number of `?` placeholders exactly — a mismatch is rejected with 422 rather + than binding null for the ones you left out. (Not enforced for multi-statement + scripts or named parameters, where the placeholder count is not the number + bound.) + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._post( + path_template("/storage/sqldbs/{id}/actions/query", id=id), + body=await async_maybe_transform( + { + "sql": sql, + "params": params, + }, + action_query_params.ActionQueryParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ActionQueryResponse, + ) + + +class ActionsResourceWithRawResponse: + def __init__(self, actions: ActionsResource) -> None: + self._actions = actions + + self.query = to_raw_response_wrapper( + actions.query, + ) + + +class AsyncActionsResourceWithRawResponse: + def __init__(self, actions: AsyncActionsResource) -> None: + self._actions = actions + + self.query = async_to_raw_response_wrapper( + actions.query, + ) + + +class ActionsResourceWithStreamingResponse: + def __init__(self, actions: ActionsResource) -> None: + self._actions = actions + + self.query = to_streamed_response_wrapper( + actions.query, + ) + + +class AsyncActionsResourceWithStreamingResponse: + def __init__(self, actions: AsyncActionsResource) -> None: + self._actions = actions + + self.query = async_to_streamed_response_wrapper( + actions.query, + ) diff --git a/src/telnyx/resources/storage/sqldbs/sqldbs.py b/src/telnyx/resources/storage/sqldbs/sqldbs.py new file mode 100644 index 000000000..522923891 --- /dev/null +++ b/src/telnyx/resources/storage/sqldbs/sqldbs.py @@ -0,0 +1,543 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from .actions import ( + ActionsResource, + AsyncActionsResource, + ActionsResourceWithRawResponse, + AsyncActionsResourceWithRawResponse, + ActionsResourceWithStreamingResponse, + AsyncActionsResourceWithStreamingResponse, +) +from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given +from ...._utils import path_template, maybe_transform, async_maybe_transform +from ...._compat import cached_property +from ...._resource import SyncAPIResource, AsyncAPIResource +from ...._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ....pagination import SyncDefaultFlatPagination, AsyncDefaultFlatPagination +from ...._base_client import AsyncPaginator, make_request_options +from ....types.storage import sqldb_list_params, sqldb_create_params, sqldb_delete_params +from ....types.storage.sql_database import SqlDatabase +from ....types.storage.sql_database_response_wrapper import SqlDatabaseResponseWrapper + +__all__ = ["SqldbsResource", "AsyncSqldbsResource"] + + +class SqldbsResource(SyncAPIResource): + """Manage SQL databases and run SQL against them""" + + @cached_property + def actions(self) -> ActionsResource: + """Manage SQL databases and run SQL against them""" + return ActionsResource(self._client) + + @cached_property + def with_raw_response(self) -> SqldbsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return SqldbsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> SqldbsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return SqldbsResourceWithStreamingResponse(self) + + def create( + self, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SqlDatabaseResponseWrapper: + """Creates a new SQL database. + + Provisioning is asynchronous: the database is + returned with status `pending` and becomes usable once it reaches + `provision_ok`. + + Args: + name: Database name. Lowercase letters, numbers, and hyphens only; must start and end + with a letter or number. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/storage/sqldbs", + body=maybe_transform({"name": name}, sqldb_create_params.SqldbCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SqlDatabaseResponseWrapper, + ) + + def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SqlDatabaseResponseWrapper: + """ + Retrieves a SQL database by its ID, including its provisioning status. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return self._get( + path_template("/storage/sqldbs/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SqlDatabaseResponseWrapper, + ) + + def list( + self, + *, + filter_name: str | Omit = omit, + filter_status: Literal["pending", "provision_ok", "provision_failed", "deleting", "delete_failed"] + | Omit = omit, + page_number: int | Omit = omit, + page_size: int | Omit = omit, + sort: Literal["name", "-name", "status", "-status", "created_at", "-created_at"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SyncDefaultFlatPagination[SqlDatabase]: + """Lists the SQL databases for the authenticated user's organization. + + Results use + page-based pagination (`page[number]`/`page[size]`) and can be filtered and + sorted. + + Args: + filter_name: Filter by exact name match. + + filter_status: Filter by provisioning status. + + page_number: The page number to load. + + page_size: The size of the page. Values above 250 are treated as 250. + + sort: Sort field; prefix with `-` for descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/storage/sqldbs", + page=SyncDefaultFlatPagination[SqlDatabase], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "filter_name": filter_name, + "filter_status": filter_status, + "page_number": page_number, + "page_size": page_size, + "sort": sort, + }, + sqldb_list_params.SqldbListParams, + ), + ), + model=SqlDatabase, + ) + + def delete( + self, + id: str, + *, + force: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Deletes a SQL database and all of the data it holds. + + Deletion is asynchronous + and returns `202` with an empty body — the record is not removed synchronously. + Poll `GET /storage/sqldbs/{id}`, which returns `404` once the database has been + purged; there is no durable `deleted` state. A database still bound by a + function is refused with `409` unless `force=true`. + + Args: + force: Delete the database even when functions still bind it. Their bindings stop + resolving. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return self._delete( + path_template("/storage/sqldbs/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform({"force": force}, sqldb_delete_params.SqldbDeleteParams), + ), + cast_to=NoneType, + ) + + +class AsyncSqldbsResource(AsyncAPIResource): + """Manage SQL databases and run SQL against them""" + + @cached_property + def actions(self) -> AsyncActionsResource: + """Manage SQL databases and run SQL against them""" + return AsyncActionsResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncSqldbsResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncSqldbsResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncSqldbsResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncSqldbsResourceWithStreamingResponse(self) + + async def create( + self, + *, + name: str, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SqlDatabaseResponseWrapper: + """Creates a new SQL database. + + Provisioning is asynchronous: the database is + returned with status `pending` and becomes usable once it reaches + `provision_ok`. + + Args: + name: Database name. Lowercase letters, numbers, and hyphens only; must start and end + with a letter or number. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/storage/sqldbs", + body=await async_maybe_transform({"name": name}, sqldb_create_params.SqldbCreateParams), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SqlDatabaseResponseWrapper, + ) + + async def retrieve( + self, + id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> SqlDatabaseResponseWrapper: + """ + Retrieves a SQL database by its ID, including its provisioning status. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + return await self._get( + path_template("/storage/sqldbs/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=SqlDatabaseResponseWrapper, + ) + + def list( + self, + *, + filter_name: str | Omit = omit, + filter_status: Literal["pending", "provision_ok", "provision_failed", "deleting", "delete_failed"] + | Omit = omit, + page_number: int | Omit = omit, + page_size: int | Omit = omit, + sort: Literal["name", "-name", "status", "-status", "created_at", "-created_at"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> AsyncPaginator[SqlDatabase, AsyncDefaultFlatPagination[SqlDatabase]]: + """Lists the SQL databases for the authenticated user's organization. + + Results use + page-based pagination (`page[number]`/`page[size]`) and can be filtered and + sorted. + + Args: + filter_name: Filter by exact name match. + + filter_status: Filter by provisioning status. + + page_number: The page number to load. + + page_size: The size of the page. Values above 250 are treated as 250. + + sort: Sort field; prefix with `-` for descending order. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._get_api_list( + "/storage/sqldbs", + page=AsyncDefaultFlatPagination[SqlDatabase], + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=maybe_transform( + { + "filter_name": filter_name, + "filter_status": filter_status, + "page_number": page_number, + "page_size": page_size, + "sort": sort, + }, + sqldb_list_params.SqldbListParams, + ), + ), + model=SqlDatabase, + ) + + async def delete( + self, + id: str, + *, + force: bool | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> None: + """Deletes a SQL database and all of the data it holds. + + Deletion is asynchronous + and returns `202` with an empty body — the record is not removed synchronously. + Poll `GET /storage/sqldbs/{id}`, which returns `404` once the database has been + purged; there is no durable `deleted` state. A database still bound by a + function is refused with `409` unless `force=true`. + + Args: + force: Delete the database even when functions still bind it. Their bindings stop + resolving. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not id: + raise ValueError(f"Expected a non-empty value for `id` but received {id!r}") + extra_headers = {"Accept": "*/*", **(extra_headers or {})} + return await self._delete( + path_template("/storage/sqldbs/{id}", id=id), + options=make_request_options( + extra_headers=extra_headers, + extra_query=extra_query, + extra_body=extra_body, + timeout=timeout, + query=await async_maybe_transform({"force": force}, sqldb_delete_params.SqldbDeleteParams), + ), + cast_to=NoneType, + ) + + +class SqldbsResourceWithRawResponse: + def __init__(self, sqldbs: SqldbsResource) -> None: + self._sqldbs = sqldbs + + self.create = to_raw_response_wrapper( + sqldbs.create, + ) + self.retrieve = to_raw_response_wrapper( + sqldbs.retrieve, + ) + self.list = to_raw_response_wrapper( + sqldbs.list, + ) + self.delete = to_raw_response_wrapper( + sqldbs.delete, + ) + + @cached_property + def actions(self) -> ActionsResourceWithRawResponse: + """Manage SQL databases and run SQL against them""" + return ActionsResourceWithRawResponse(self._sqldbs.actions) + + +class AsyncSqldbsResourceWithRawResponse: + def __init__(self, sqldbs: AsyncSqldbsResource) -> None: + self._sqldbs = sqldbs + + self.create = async_to_raw_response_wrapper( + sqldbs.create, + ) + self.retrieve = async_to_raw_response_wrapper( + sqldbs.retrieve, + ) + self.list = async_to_raw_response_wrapper( + sqldbs.list, + ) + self.delete = async_to_raw_response_wrapper( + sqldbs.delete, + ) + + @cached_property + def actions(self) -> AsyncActionsResourceWithRawResponse: + """Manage SQL databases and run SQL against them""" + return AsyncActionsResourceWithRawResponse(self._sqldbs.actions) + + +class SqldbsResourceWithStreamingResponse: + def __init__(self, sqldbs: SqldbsResource) -> None: + self._sqldbs = sqldbs + + self.create = to_streamed_response_wrapper( + sqldbs.create, + ) + self.retrieve = to_streamed_response_wrapper( + sqldbs.retrieve, + ) + self.list = to_streamed_response_wrapper( + sqldbs.list, + ) + self.delete = to_streamed_response_wrapper( + sqldbs.delete, + ) + + @cached_property + def actions(self) -> ActionsResourceWithStreamingResponse: + """Manage SQL databases and run SQL against them""" + return ActionsResourceWithStreamingResponse(self._sqldbs.actions) + + +class AsyncSqldbsResourceWithStreamingResponse: + def __init__(self, sqldbs: AsyncSqldbsResource) -> None: + self._sqldbs = sqldbs + + self.create = async_to_streamed_response_wrapper( + sqldbs.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + sqldbs.retrieve, + ) + self.list = async_to_streamed_response_wrapper( + sqldbs.list, + ) + self.delete = async_to_streamed_response_wrapper( + sqldbs.delete, + ) + + @cached_property + def actions(self) -> AsyncActionsResourceWithStreamingResponse: + """Manage SQL databases and run SQL against them""" + return AsyncActionsResourceWithStreamingResponse(self._sqldbs.actions) diff --git a/src/telnyx/resources/storage/storage.py b/src/telnyx/resources/storage/storage.py index e919df868..0257feda9 100644 --- a/src/telnyx/resources/storage/storage.py +++ b/src/telnyx/resources/storage/storage.py @@ -21,6 +21,14 @@ async_to_raw_response_wrapper, async_to_streamed_response_wrapper, ) +from .sqldbs.sqldbs import ( + SqldbsResource, + AsyncSqldbsResource, + SqldbsResourceWithRawResponse, + AsyncSqldbsResourceWithRawResponse, + SqldbsResourceWithStreamingResponse, + AsyncSqldbsResourceWithStreamingResponse, +) from ..._base_client import make_request_options from .buckets.buckets import ( BucketsResource, @@ -89,6 +97,11 @@ def cloudfs(self) -> CloudfsResource: """ return CloudfsResource(self._client) + @cached_property + def sqldbs(self) -> SqldbsResource: + """Manage SQL databases and run SQL against them""" + return SqldbsResource(self._client) + @cached_property def with_raw_response(self) -> StorageResourceWithRawResponse: """ @@ -158,6 +171,11 @@ def cloudfs(self) -> AsyncCloudfsResource: """ return AsyncCloudfsResource(self._client) + @cached_property + def sqldbs(self) -> AsyncSqldbsResource: + """Manage SQL databases and run SQL against them""" + return AsyncSqldbsResource(self._client) + @cached_property def with_raw_response(self) -> AsyncStorageResourceWithRawResponse: """ @@ -232,6 +250,11 @@ def cloudfs(self) -> CloudfsResourceWithRawResponse: """ return CloudfsResourceWithRawResponse(self._storage.cloudfs) + @cached_property + def sqldbs(self) -> SqldbsResourceWithRawResponse: + """Manage SQL databases and run SQL against them""" + return SqldbsResourceWithRawResponse(self._storage.sqldbs) + class AsyncStorageResourceWithRawResponse: def __init__(self, storage: AsyncStorageResource) -> None: @@ -268,6 +291,11 @@ def cloudfs(self) -> AsyncCloudfsResourceWithRawResponse: """ return AsyncCloudfsResourceWithRawResponse(self._storage.cloudfs) + @cached_property + def sqldbs(self) -> AsyncSqldbsResourceWithRawResponse: + """Manage SQL databases and run SQL against them""" + return AsyncSqldbsResourceWithRawResponse(self._storage.sqldbs) + class StorageResourceWithStreamingResponse: def __init__(self, storage: StorageResource) -> None: @@ -304,6 +332,11 @@ def cloudfs(self) -> CloudfsResourceWithStreamingResponse: """ return CloudfsResourceWithStreamingResponse(self._storage.cloudfs) + @cached_property + def sqldbs(self) -> SqldbsResourceWithStreamingResponse: + """Manage SQL databases and run SQL against them""" + return SqldbsResourceWithStreamingResponse(self._storage.sqldbs) + class AsyncStorageResourceWithStreamingResponse: def __init__(self, storage: AsyncStorageResource) -> None: @@ -339,3 +372,8 @@ def cloudfs(self) -> AsyncCloudfsResourceWithStreamingResponse: Manage CloudFS filesystems — JuiceFS-compatible filesystems backed by Telnyx Cloud Storage """ return AsyncCloudfsResourceWithStreamingResponse(self._storage.cloudfs) + + @cached_property + def sqldbs(self) -> AsyncSqldbsResourceWithStreamingResponse: + """Manage SQL databases and run SQL against them""" + return AsyncSqldbsResourceWithStreamingResponse(self._storage.sqldbs) diff --git a/src/telnyx/resources/web_search/__init__.py b/src/telnyx/resources/web_search/__init__.py new file mode 100644 index 000000000..460187fda --- /dev/null +++ b/src/telnyx/resources/web_search/__init__.py @@ -0,0 +1,33 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from .research import ( + ResearchResource, + AsyncResearchResource, + ResearchResourceWithRawResponse, + AsyncResearchResourceWithRawResponse, + ResearchResourceWithStreamingResponse, + AsyncResearchResourceWithStreamingResponse, +) +from .web_search import ( + WebSearchResource, + AsyncWebSearchResource, + WebSearchResourceWithRawResponse, + AsyncWebSearchResourceWithRawResponse, + WebSearchResourceWithStreamingResponse, + AsyncWebSearchResourceWithStreamingResponse, +) + +__all__ = [ + "ResearchResource", + "AsyncResearchResource", + "ResearchResourceWithRawResponse", + "AsyncResearchResourceWithRawResponse", + "ResearchResourceWithStreamingResponse", + "AsyncResearchResourceWithStreamingResponse", + "WebSearchResource", + "AsyncWebSearchResource", + "WebSearchResourceWithRawResponse", + "AsyncWebSearchResourceWithRawResponse", + "WebSearchResourceWithStreamingResponse", + "AsyncWebSearchResourceWithStreamingResponse", +] diff --git a/src/telnyx/resources/web_search/research.py b/src/telnyx/resources/web_search/research.py new file mode 100644 index 000000000..0df792c13 --- /dev/null +++ b/src/telnyx/resources/web_search/research.py @@ -0,0 +1,322 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +import httpx + +from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given +from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.web_search import research_create_params +from ...types.web_search.research_create_response import ResearchCreateResponse +from ...types.web_search.research_retrieve_response import ResearchRetrieveResponse + +__all__ = ["ResearchResource", "AsyncResearchResource"] + + +class ResearchResource(SyncAPIResource): + """Deep research with citations and async task polling.""" + + @cached_property + def with_raw_response(self) -> ResearchResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return ResearchResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> ResearchResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return ResearchResourceWithStreamingResponse(self) + + def create( + self, + *, + query: str, + background: bool | Omit = omit, + max_sources: int | Omit = omit, + research_effort: Literal["lite", "standard", "deep"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ResearchCreateResponse: + """ + Starts a deep research task that runs multiple searches, reads sources, and + synthesizes an answer with citations. + + ## Synchronous mode (default) + + When `background` is `false` or omitted, the request blocks until the research + completes and returns the answer with citations. This can take up to 120 seconds + depending on `research_effort`. + + ## Asynchronous mode + + When `background` is `true`, the request returns immediately with a `task_id` + and `status: pending`. Poll `GET /web_search/research/{task_id}` to check when + the research completes and retrieve the answer. + + Args: + query: The research question or topic. + + background: When `true`, the research runs asynchronously. The response returns a `task_id` + immediately instead of waiting for the result. Poll + `GET /web_search/research/{task_id}` to check status. + + max_sources: Maximum number of sources to use. + + research_effort: Research depth level. `lite` is fastest, `deep` is most thorough. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/web_search/research", + body=maybe_transform( + { + "query": query, + "background": background, + "max_sources": max_sources, + "research_effort": research_effort, + }, + research_create_params.ResearchCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ResearchCreateResponse, + ) + + def retrieve( + self, + task_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ResearchRetrieveResponse: + """Polls the status of a previously started asynchronous research task. + + When the + status is `completed`, the response includes the answer and citations. When the + status is `failed`, the response includes an error message. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not task_id: + raise ValueError(f"Expected a non-empty value for `task_id` but received {task_id!r}") + return self._get( + path_template("/web_search/research/{task_id}", task_id=task_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ResearchRetrieveResponse, + ) + + +class AsyncResearchResource(AsyncAPIResource): + """Deep research with citations and async task polling.""" + + @cached_property + def with_raw_response(self) -> AsyncResearchResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncResearchResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncResearchResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncResearchResourceWithStreamingResponse(self) + + async def create( + self, + *, + query: str, + background: bool | Omit = omit, + max_sources: int | Omit = omit, + research_effort: Literal["lite", "standard", "deep"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ResearchCreateResponse: + """ + Starts a deep research task that runs multiple searches, reads sources, and + synthesizes an answer with citations. + + ## Synchronous mode (default) + + When `background` is `false` or omitted, the request blocks until the research + completes and returns the answer with citations. This can take up to 120 seconds + depending on `research_effort`. + + ## Asynchronous mode + + When `background` is `true`, the request returns immediately with a `task_id` + and `status: pending`. Poll `GET /web_search/research/{task_id}` to check when + the research completes and retrieve the answer. + + Args: + query: The research question or topic. + + background: When `true`, the research runs asynchronously. The response returns a `task_id` + immediately instead of waiting for the result. Poll + `GET /web_search/research/{task_id}` to check status. + + max_sources: Maximum number of sources to use. + + research_effort: Research depth level. `lite` is fastest, `deep` is most thorough. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/web_search/research", + body=await async_maybe_transform( + { + "query": query, + "background": background, + "max_sources": max_sources, + "research_effort": research_effort, + }, + research_create_params.ResearchCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ResearchCreateResponse, + ) + + async def retrieve( + self, + task_id: str, + *, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> ResearchRetrieveResponse: + """Polls the status of a previously started asynchronous research task. + + When the + status is `completed`, the response includes the answer and citations. When the + status is `failed`, the response includes an error message. + + Args: + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + if not task_id: + raise ValueError(f"Expected a non-empty value for `task_id` but received {task_id!r}") + return await self._get( + path_template("/web_search/research/{task_id}", task_id=task_id), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=ResearchRetrieveResponse, + ) + + +class ResearchResourceWithRawResponse: + def __init__(self, research: ResearchResource) -> None: + self._research = research + + self.create = to_raw_response_wrapper( + research.create, + ) + self.retrieve = to_raw_response_wrapper( + research.retrieve, + ) + + +class AsyncResearchResourceWithRawResponse: + def __init__(self, research: AsyncResearchResource) -> None: + self._research = research + + self.create = async_to_raw_response_wrapper( + research.create, + ) + self.retrieve = async_to_raw_response_wrapper( + research.retrieve, + ) + + +class ResearchResourceWithStreamingResponse: + def __init__(self, research: ResearchResource) -> None: + self._research = research + + self.create = to_streamed_response_wrapper( + research.create, + ) + self.retrieve = to_streamed_response_wrapper( + research.retrieve, + ) + + +class AsyncResearchResourceWithStreamingResponse: + def __init__(self, research: AsyncResearchResource) -> None: + self._research = research + + self.create = async_to_streamed_response_wrapper( + research.create, + ) + self.retrieve = async_to_streamed_response_wrapper( + research.retrieve, + ) diff --git a/src/telnyx/resources/web_search/web_search.py b/src/telnyx/resources/web_search/web_search.py new file mode 100644 index 000000000..42f83923d --- /dev/null +++ b/src/telnyx/resources/web_search/web_search.py @@ -0,0 +1,415 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal + +import httpx + +from ...types import web_search_create_params, web_search_contents_params +from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given +from ..._utils import maybe_transform, async_maybe_transform +from .research import ( + ResearchResource, + AsyncResearchResource, + ResearchResourceWithRawResponse, + AsyncResearchResourceWithRawResponse, + ResearchResourceWithStreamingResponse, + AsyncResearchResourceWithStreamingResponse, +) +from ..._compat import cached_property +from ..._resource import SyncAPIResource, AsyncAPIResource +from ..._response import ( + to_raw_response_wrapper, + to_streamed_response_wrapper, + async_to_raw_response_wrapper, + async_to_streamed_response_wrapper, +) +from ..._base_client import make_request_options +from ...types.web_search_create_response import WebSearchCreateResponse +from ...types.web_search_contents_response import WebSearchContentsResponse + +__all__ = ["WebSearchResource", "AsyncWebSearchResource"] + + +class WebSearchResource(SyncAPIResource): + @cached_property + def research(self) -> ResearchResource: + """Deep research with citations and async task polling.""" + return ResearchResource(self._client) + + @cached_property + def with_raw_response(self) -> WebSearchResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return WebSearchResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> WebSearchResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return WebSearchResourceWithStreamingResponse(self) + + def create( + self, + *, + query: str, + count: int | Omit = omit, + country: str | Omit = omit, + exclude_domains: SequenceNotStr[str] | Omit = omit, + freshness: str | Omit = omit, + include_domains: SequenceNotStr[str] | Omit = omit, + livecrawl: bool | Omit = omit, + safesearch: Literal["off", "moderate", "strict"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WebSearchCreateResponse: + """ + Performs a real-time web search and returns structured, LLM-ready JSON results + with titles, URLs, descriptions, and snippets. Supports filtering by domain, + country, safe search, freshness, and live crawl. + + **Note:** `include_domains` and `exclude_domains` cannot be used in the same + request. Use one or the other. + + Args: + query: The search query text. + + count: Number of results to return (1-100). + + country: Two-letter country code (ISO 3166-1 alpha-2) to bias results. + + exclude_domains: Exclude results from these domains (bare hostnames, e.g. `pinterest.com`). + + freshness: Time-based filter for results. Common values: `day`, `week`, `month`, `year`. + + include_domains: Restrict results to these domains (bare hostnames, e.g. `arxiv.org`). + + livecrawl: When true, the provider crawls pages in real-time for fresh content. The boolean + is translated to the provider's internal enum internally; callers always pass + `true` or `false`. + + safesearch: Safe search filter level. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/web_search", + body=maybe_transform( + { + "query": query, + "count": count, + "country": country, + "exclude_domains": exclude_domains, + "freshness": freshness, + "include_domains": include_domains, + "livecrawl": livecrawl, + "safesearch": safesearch, + }, + web_search_create_params.WebSearchCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WebSearchCreateResponse, + ) + + def contents( + self, + *, + urls: SequenceNotStr[str], + crawl_timeout: int | Omit = omit, + formats: List[Literal["html", "markdown", "metadata"]] | Omit = omit, + max_age: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WebSearchContentsResponse: + """Retrieves clean HTML or Markdown content from a list of URLs. + + Supports up to 20 + URLs per request (public API limit). Specify which formats to return: `html`, + `markdown`, `metadata`. + + Args: + urls: List of URLs to retrieve content from (max 20 for public API). + + crawl_timeout: Timeout for crawling each URL, in seconds (1-60). + + formats: Content formats to return. If omitted, `html` and `metadata` are returned by + default. Retrieval is best-effort per URL: a format field appears only when that + content could be produced, and a freshly crawled page may also include `html` + even when not requested. + + max_age: Maximum age of cached content in seconds. `null` means no limit. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return self._post( + "/web_search/contents", + body=maybe_transform( + { + "urls": urls, + "crawl_timeout": crawl_timeout, + "formats": formats, + "max_age": max_age, + }, + web_search_contents_params.WebSearchContentsParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WebSearchContentsResponse, + ) + + +class AsyncWebSearchResource(AsyncAPIResource): + @cached_property + def research(self) -> AsyncResearchResource: + """Deep research with citations and async task polling.""" + return AsyncResearchResource(self._client) + + @cached_property + def with_raw_response(self) -> AsyncWebSearchResourceWithRawResponse: + """ + This property can be used as a prefix for any HTTP method call to return + the raw response object instead of the parsed content. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#accessing-raw-response-data-eg-headers + """ + return AsyncWebSearchResourceWithRawResponse(self) + + @cached_property + def with_streaming_response(self) -> AsyncWebSearchResourceWithStreamingResponse: + """ + An alternative to `.with_raw_response` that doesn't eagerly read the response body. + + For more information, see https://www.github.com/team-telnyx/telnyx-python#with_streaming_response + """ + return AsyncWebSearchResourceWithStreamingResponse(self) + + async def create( + self, + *, + query: str, + count: int | Omit = omit, + country: str | Omit = omit, + exclude_domains: SequenceNotStr[str] | Omit = omit, + freshness: str | Omit = omit, + include_domains: SequenceNotStr[str] | Omit = omit, + livecrawl: bool | Omit = omit, + safesearch: Literal["off", "moderate", "strict"] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WebSearchCreateResponse: + """ + Performs a real-time web search and returns structured, LLM-ready JSON results + with titles, URLs, descriptions, and snippets. Supports filtering by domain, + country, safe search, freshness, and live crawl. + + **Note:** `include_domains` and `exclude_domains` cannot be used in the same + request. Use one or the other. + + Args: + query: The search query text. + + count: Number of results to return (1-100). + + country: Two-letter country code (ISO 3166-1 alpha-2) to bias results. + + exclude_domains: Exclude results from these domains (bare hostnames, e.g. `pinterest.com`). + + freshness: Time-based filter for results. Common values: `day`, `week`, `month`, `year`. + + include_domains: Restrict results to these domains (bare hostnames, e.g. `arxiv.org`). + + livecrawl: When true, the provider crawls pages in real-time for fresh content. The boolean + is translated to the provider's internal enum internally; callers always pass + `true` or `false`. + + safesearch: Safe search filter level. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/web_search", + body=await async_maybe_transform( + { + "query": query, + "count": count, + "country": country, + "exclude_domains": exclude_domains, + "freshness": freshness, + "include_domains": include_domains, + "livecrawl": livecrawl, + "safesearch": safesearch, + }, + web_search_create_params.WebSearchCreateParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WebSearchCreateResponse, + ) + + async def contents( + self, + *, + urls: SequenceNotStr[str], + crawl_timeout: int | Omit = omit, + formats: List[Literal["html", "markdown", "metadata"]] | Omit = omit, + max_age: Optional[int] | Omit = omit, + # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. + # The extra values given here take precedence over values defined on the client or passed to this method. + extra_headers: Headers | None = None, + extra_query: Query | None = None, + extra_body: Body | None = None, + timeout: float | httpx.Timeout | None | NotGiven = not_given, + ) -> WebSearchContentsResponse: + """Retrieves clean HTML or Markdown content from a list of URLs. + + Supports up to 20 + URLs per request (public API limit). Specify which formats to return: `html`, + `markdown`, `metadata`. + + Args: + urls: List of URLs to retrieve content from (max 20 for public API). + + crawl_timeout: Timeout for crawling each URL, in seconds (1-60). + + formats: Content formats to return. If omitted, `html` and `metadata` are returned by + default. Retrieval is best-effort per URL: a format field appears only when that + content could be produced, and a freshly crawled page may also include `html` + even when not requested. + + max_age: Maximum age of cached content in seconds. `null` means no limit. + + extra_headers: Send extra headers + + extra_query: Add additional query parameters to the request + + extra_body: Add additional JSON properties to the request + + timeout: Override the client-level default timeout for this request, in seconds + """ + return await self._post( + "/web_search/contents", + body=await async_maybe_transform( + { + "urls": urls, + "crawl_timeout": crawl_timeout, + "formats": formats, + "max_age": max_age, + }, + web_search_contents_params.WebSearchContentsParams, + ), + options=make_request_options( + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout + ), + cast_to=WebSearchContentsResponse, + ) + + +class WebSearchResourceWithRawResponse: + def __init__(self, web_search: WebSearchResource) -> None: + self._web_search = web_search + + self.create = to_raw_response_wrapper( + web_search.create, + ) + self.contents = to_raw_response_wrapper( + web_search.contents, + ) + + @cached_property + def research(self) -> ResearchResourceWithRawResponse: + """Deep research with citations and async task polling.""" + return ResearchResourceWithRawResponse(self._web_search.research) + + +class AsyncWebSearchResourceWithRawResponse: + def __init__(self, web_search: AsyncWebSearchResource) -> None: + self._web_search = web_search + + self.create = async_to_raw_response_wrapper( + web_search.create, + ) + self.contents = async_to_raw_response_wrapper( + web_search.contents, + ) + + @cached_property + def research(self) -> AsyncResearchResourceWithRawResponse: + """Deep research with citations and async task polling.""" + return AsyncResearchResourceWithRawResponse(self._web_search.research) + + +class WebSearchResourceWithStreamingResponse: + def __init__(self, web_search: WebSearchResource) -> None: + self._web_search = web_search + + self.create = to_streamed_response_wrapper( + web_search.create, + ) + self.contents = to_streamed_response_wrapper( + web_search.contents, + ) + + @cached_property + def research(self) -> ResearchResourceWithStreamingResponse: + """Deep research with citations and async task polling.""" + return ResearchResourceWithStreamingResponse(self._web_search.research) + + +class AsyncWebSearchResourceWithStreamingResponse: + def __init__(self, web_search: AsyncWebSearchResource) -> None: + self._web_search = web_search + + self.create = async_to_streamed_response_wrapper( + web_search.create, + ) + self.contents = async_to_streamed_response_wrapper( + web_search.contents, + ) + + @cached_property + def research(self) -> AsyncResearchResourceWithStreamingResponse: + """Deep research with citations and async task polling.""" + return AsyncResearchResourceWithStreamingResponse(self._web_search.research) diff --git a/src/telnyx/types/__init__.py b/src/telnyx/types/__init__.py index 68961804e..dbbcdd60a 100644 --- a/src/telnyx/types/__init__.py +++ b/src/telnyx/types/__init__.py @@ -137,6 +137,7 @@ from .group_list_meta import GroupListMeta as GroupListMeta from .inbound_message import InboundMessage as InboundMessage from .managed_account import ManagedAccount as ManagedAccount +from .meeting_session import MeetingSession as MeetingSession from .models_response import ModelsResponse as ModelsResponse from .pagination_meta import PaginationMeta as PaginationMeta from .portout_details import PortoutDetails as PortoutDetails @@ -186,6 +187,7 @@ from .texml_application import TexmlApplication as TexmlApplication from .unsubscribe_group import UnsubscribeGroup as UnsubscribeGroup from .voice_design_data import VoiceDesignData as VoiceDesignData +from .web_search_result import WebSearchResult as WebSearchResult from .whatsapp_location import WhatsappLocation as WhatsappLocation from .whatsapp_reaction import WhatsappReaction as WhatsappReaction from .call_dial_response import CallDialResponse as CallDialResponse @@ -418,6 +420,7 @@ from .email_thread_list_params import EmailThreadListParams as EmailThreadListParams from .enterprise_create_params import EnterpriseCreateParams as EnterpriseCreateParams from .enterprise_update_params import EnterpriseUpdateParams as EnterpriseUpdateParams +from .meeting_session_response import MeetingSessionResponse as MeetingSessionResponse from .number_order_list_params import NumberOrderListParams as NumberOrderListParams from .oauth_client_list_params import OAuthClientListParams as OAuthClientListParams from .ota_update_list_response import OtaUpdateListResponse as OtaUpdateListResponse @@ -435,6 +438,7 @@ from .usage_report_list_params import UsageReportListParams as UsageReportListParams from .user_address_list_params import UserAddressListParams as UserAddressListParams from .voice_design_list_params import VoiceDesignListParams as VoiceDesignListParams +from .web_search_create_params import WebSearchCreateParams as WebSearchCreateParams from .whatsapp_message_content import WhatsappMessageContent as WhatsappMessageContent from .wireguard_interface_read import WireguardInterfaceRead as WireguardInterfaceRead from .address_retrieve_response import AddressRetrieveResponse as AddressRetrieveResponse @@ -521,6 +525,8 @@ from .verify_profile_list_params import VerifyProfileListParams as VerifyProfileListParams from .voice_design_create_params import VoiceDesignCreateParams as VoiceDesignCreateParams from .voice_design_rename_params import VoiceDesignRenameParams as VoiceDesignRenameParams +from .web_search_contents_params import WebSearchContentsParams as WebSearchContentsParams +from .web_search_create_response import WebSearchCreateResponse as WebSearchCreateResponse from .whatsapp_interactive_param import WhatsappInteractiveParam as WhatsappInteractiveParam from .wireguard_peer_list_params import WireguardPeerListParams as WireguardPeerListParams from .access_ip_range_list_params import AccessIPRangeListParams as AccessIPRangeListParams @@ -544,6 +550,7 @@ from .ip_connection_update_params import IPConnectionUpdateParams as IPConnectionUpdateParams from .ledger_billing_group_report import LedgerBillingGroupReport as LedgerBillingGroupReport from .managed_account_list_params import ManagedAccountListParams as ManagedAccountListParams +from .meeting_session_list_params import MeetingSessionListParams as MeetingSessionListParams from .netapps_location_17904fcfbc import NetappsLocation17904fcfbc as NetappsLocation17904fcfbc from .oauth_grant_delete_response import OAuthGrantDeleteResponse as OAuthGrantDeleteResponse from .oauth_oauth_pagination_meta import OAuthOAuthPaginationMeta as OAuthOAuthPaginationMeta @@ -611,12 +618,14 @@ from .verify_profile_update_params import VerifyProfileUpdateParams as VerifyProfileUpdateParams from .voice_design_rename_response import VoiceDesignRenameResponse as VoiceDesignRenameResponse from .voice_design_retrieve_params import VoiceDesignRetrieveParams as VoiceDesignRetrieveParams +from .web_search_contents_response import WebSearchContentsResponse as WebSearchContentsResponse from .webhook_delivery_list_params import WebhookDeliveryListParams as WebhookDeliveryListParams from .websocket_connection_options import WebSocketConnectionOptions as WebSocketConnectionOptions from .wireguard_peer_create_params import WireguardPeerCreateParams as WireguardPeerCreateParams from .wireguard_peer_update_params import WireguardPeerUpdateParams as WireguardPeerUpdateParams from .access_ip_address_list_params import AccessIPAddressListParams as AccessIPAddressListParams from .access_ip_range_create_params import AccessIPRangeCreateParams as AccessIPRangeCreateParams +from .artifact_failed_webhook_event import ArtifactFailedWebhookEvent as ArtifactFailedWebhookEvent from .billing_group_create_response import BillingGroupCreateResponse as BillingGroupCreateResponse from .billing_group_delete_response import BillingGroupDeleteResponse as BillingGroupDeleteResponse from .billing_group_update_response import BillingGroupUpdateResponse as BillingGroupUpdateResponse @@ -642,6 +651,9 @@ from .managed_account_create_params import ManagedAccountCreateParams as ManagedAccountCreateParams from .managed_account_list_response import ManagedAccountListResponse as ManagedAccountListResponse from .managed_account_update_params import ManagedAccountUpdateParams as ManagedAccountUpdateParams +from .meeting_session_create_params import MeetingSessionCreateParams as MeetingSessionCreateParams +from .meeting_session_list_response import MeetingSessionListResponse as MeetingSessionListResponse +from .meeting_session_update_params import MeetingSessionUpdateParams as MeetingSessionUpdateParams from .message_send_group_mms_params import MessageSendGroupMmsParams as MessageSendGroupMmsParams from .message_send_long_code_params import MessageSendLongCodeParams as MessageSendLongCodeParams from .messaging_profile_list_params import MessagingProfileListParams as MessagingProfileListParams @@ -767,6 +779,7 @@ from .verified_number_create_response import VerifiedNumberCreateResponse as VerifiedNumberCreateResponse from .voice_sdk_call_report_log_entry import VoiceSDKCallReportLogEntry as VoiceSDKCallReportLogEntry from .wireguard_interface_list_params import WireguardInterfaceListParams as WireguardInterfaceListParams +from .artifact_completed_webhook_event import ArtifactCompletedWebhookEvent as ArtifactCompletedWebhookEvent from .bulk_sim_card_action_list_params import BulkSimCardActionListParams as BulkSimCardActionListParams from .call_control_application_inbound import CallControlApplicationInbound as CallControlApplicationInbound from .call_dtmf_received_webhook_event import CallDtmfReceivedWebhookEvent as CallDtmfReceivedWebhookEvent @@ -838,6 +851,7 @@ from .porting_list_uk_carriers_response import PortingListUkCarriersResponse as PortingListUkCarriersResponse from .porting_order_activation_settings import PortingOrderActivationSettings as PortingOrderActivationSettings from .porting_order_user_feedback_param import PortingOrderUserFeedbackParam as PortingOrderUserFeedbackParam +from .recording_available_webhook_event import RecordingAvailableWebhookEvent as RecordingAvailableWebhookEvent from .replaced_link_click_webhook_event import ReplacedLinkClickWebhookEvent as ReplacedLinkClickWebhookEvent from .room_recording_delete_bulk_params import RoomRecordingDeleteBulkParams as RoomRecordingDeleteBulkParams from .texml_application_create_response import TexmlApplicationCreateResponse as TexmlApplicationCreateResponse @@ -883,6 +897,7 @@ from .telephony_credential_create_params import TelephonyCredentialCreateParams as TelephonyCredentialCreateParams from .telephony_credential_update_params import TelephonyCredentialUpdateParams as TelephonyCredentialUpdateParams from .traffic_policy_profile_list_params import TrafficPolicyProfileListParams as TrafficPolicyProfileListParams +from .transcript_completed_webhook_event import TranscriptCompletedWebhookEvent as TranscriptCompletedWebhookEvent from .webhook_delivery_retrieve_response import WebhookDeliveryRetrieveResponse as WebhookDeliveryRetrieveResponse from .wireless_blocklist_create_response import WirelessBlocklistCreateResponse as WirelessBlocklistCreateResponse from .wireless_blocklist_delete_response import WirelessBlocklistDeleteResponse as WirelessBlocklistDeleteResponse @@ -962,6 +977,7 @@ from .outbound_voice_profile_create_params import OutboundVoiceProfileCreateParams as OutboundVoiceProfileCreateParams from .outbound_voice_profile_update_params import OutboundVoiceProfileUpdateParams as OutboundVoiceProfileUpdateParams from .private_wireless_gateway_list_params import PrivateWirelessGatewayListParams as PrivateWirelessGatewayListParams +from .session_status_changed_webhook_event import SessionStatusChangedWebhookEvent as SessionStatusChangedWebhookEvent from .sim_card_get_device_details_response import SimCardGetDeviceDetailsResponse as SimCardGetDeviceDetailsResponse from .speech_to_text_list_providers_params import SpeechToTextListProvidersParams as SpeechToTextListProvidersParams from .telephony_credential_create_response import TelephonyCredentialCreateResponse as TelephonyCredentialCreateResponse @@ -1114,6 +1130,9 @@ from .global_ip_health_check_delete_response import ( GlobalIPHealthCheckDeleteResponse as GlobalIPHealthCheckDeleteResponse, ) +from .meeting_session_retrieve_events_params import ( + MeetingSessionRetrieveEventsParams as MeetingSessionRetrieveEventsParams, +) from .messaging_profile_metric_list_response import ( MessagingProfileMetricListResponse as MessagingProfileMetricListResponse, ) @@ -1291,6 +1310,9 @@ from .global_ip_health_check_retrieve_response import ( GlobalIPHealthCheckRetrieveResponse as GlobalIPHealthCheckRetrieveResponse, ) +from .meeting_session_retrieve_events_response import ( + MeetingSessionRetrieveEventsResponse as MeetingSessionRetrieveEventsResponse, +) from .message_retrieve_group_messages_response import ( MessageRetrieveGroupMessagesResponse as MessageRetrieveGroupMessagesResponse, ) @@ -1411,6 +1433,9 @@ from .external_connection_update_location_params import ( ExternalConnectionUpdateLocationParams as ExternalConnectionUpdateLocationParams, ) +from .meeting_session_retrieve_transcript_params import ( + MeetingSessionRetrieveTranscriptParams as MeetingSessionRetrieveTranscriptParams, +) from .notification_event_condition_list_response import ( NotificationEventConditionListResponse as NotificationEventConditionListResponse, ) @@ -1504,6 +1529,12 @@ from .external_connection_update_location_response import ( ExternalConnectionUpdateLocationResponse as ExternalConnectionUpdateLocationResponse, ) +from .meeting_session_retrieve_recordings_response import ( + MeetingSessionRetrieveRecordingsResponse as MeetingSessionRetrieveRecordingsResponse, +) +from .meeting_session_retrieve_transcript_response import ( + MeetingSessionRetrieveTranscriptResponse as MeetingSessionRetrieveTranscriptResponse, +) from .message_send_with_alphanumeric_sender_params import ( MessageSendWithAlphanumericSenderParams as MessageSendWithAlphanumericSenderParams, ) @@ -1561,6 +1592,9 @@ from .sim_card_data_usage_notification_update_params import ( SimCardDataUsageNotificationUpdateParams as SimCardDataUsageNotificationUpdateParams, ) +from .meeting_session_delete_recording_media_response import ( + MeetingSessionDeleteRecordingMediaResponse as MeetingSessionDeleteRecordingMediaResponse, +) from .messaging_hosted_number_order_retrieve_response import ( MessagingHostedNumberOrderRetrieveResponse as MessagingHostedNumberOrderRetrieveResponse, ) diff --git a/src/telnyx/types/artifact_completed_webhook_event.py b/src/telnyx/types/artifact_completed_webhook_event.py new file mode 100644 index 000000000..162dc8900 --- /dev/null +++ b/src/telnyx/types/artifact_completed_webhook_event.py @@ -0,0 +1,63 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["ArtifactCompletedWebhookEvent", "Data", "DataContent", "DataModelProvenance"] + + +class DataContent(BaseModel): + """Generated artifact content.""" + + text: str + """Generated artifact text.""" + + +class DataModelProvenance(BaseModel): + """Model that generated the artifact.""" + + model: str + + provider: str + + +class Data(BaseModel): + """Completed artifact, including its generated content.""" + + artifact_id: str + """Id of the completed artifact.""" + + content: DataContent + """Generated artifact content.""" + + api_model_provenance: DataModelProvenance = FieldInfo(alias="model_provenance") + """Model that generated the artifact.""" + + session_id: str + """The meeting session this event belongs to.""" + + type: Literal["summary", "action_items"] + """Type of the completed artifact.""" + + +class ArtifactCompletedWebhookEvent(BaseModel): + id: str + """Unique event id; deduplicate deliveries on it.""" + + data: Data + """Completed artifact, including its generated content.""" + + event: Literal["artifact.completed"] + """Event type.""" + + occurred_at: datetime + """When the event occurred.""" + + version: str + """Envelope version.""" diff --git a/src/telnyx/types/artifact_completed_webhook_event1.py b/src/telnyx/types/artifact_completed_webhook_event1.py new file mode 100644 index 000000000..162dc8900 --- /dev/null +++ b/src/telnyx/types/artifact_completed_webhook_event1.py @@ -0,0 +1,63 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["ArtifactCompletedWebhookEvent", "Data", "DataContent", "DataModelProvenance"] + + +class DataContent(BaseModel): + """Generated artifact content.""" + + text: str + """Generated artifact text.""" + + +class DataModelProvenance(BaseModel): + """Model that generated the artifact.""" + + model: str + + provider: str + + +class Data(BaseModel): + """Completed artifact, including its generated content.""" + + artifact_id: str + """Id of the completed artifact.""" + + content: DataContent + """Generated artifact content.""" + + api_model_provenance: DataModelProvenance = FieldInfo(alias="model_provenance") + """Model that generated the artifact.""" + + session_id: str + """The meeting session this event belongs to.""" + + type: Literal["summary", "action_items"] + """Type of the completed artifact.""" + + +class ArtifactCompletedWebhookEvent(BaseModel): + id: str + """Unique event id; deduplicate deliveries on it.""" + + data: Data + """Completed artifact, including its generated content.""" + + event: Literal["artifact.completed"] + """Event type.""" + + occurred_at: datetime + """When the event occurred.""" + + version: str + """Envelope version.""" diff --git a/src/telnyx/types/artifact_failed_webhook_event.py b/src/telnyx/types/artifact_failed_webhook_event.py new file mode 100644 index 000000000..937de6765 --- /dev/null +++ b/src/telnyx/types/artifact_failed_webhook_event.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["ArtifactFailedWebhookEvent", "Data"] + + +class Data(BaseModel): + """Failed artifact reference and reason.""" + + artifact_id: str + """Id of the failed artifact.""" + + session_id: str + """The meeting session this event belongs to.""" + + type: Literal["summary", "action_items"] + """Type of the failed artifact.""" + + +class ArtifactFailedWebhookEvent(BaseModel): + id: str + """Unique event id; deduplicate deliveries on it.""" + + data: Data + """Failed artifact reference and reason.""" + + event: Literal["artifact.failed"] + """Event type.""" + + occurred_at: datetime + """When the event occurred.""" + + version: str + """Envelope version.""" diff --git a/src/telnyx/types/artifact_failed_webhook_event1.py b/src/telnyx/types/artifact_failed_webhook_event1.py new file mode 100644 index 000000000..937de6765 --- /dev/null +++ b/src/telnyx/types/artifact_failed_webhook_event1.py @@ -0,0 +1,40 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["ArtifactFailedWebhookEvent", "Data"] + + +class Data(BaseModel): + """Failed artifact reference and reason.""" + + artifact_id: str + """Id of the failed artifact.""" + + session_id: str + """The meeting session this event belongs to.""" + + type: Literal["summary", "action_items"] + """Type of the failed artifact.""" + + +class ArtifactFailedWebhookEvent(BaseModel): + id: str + """Unique event id; deduplicate deliveries on it.""" + + data: Data + """Failed artifact reference and reason.""" + + event: Literal["artifact.failed"] + """Event type.""" + + occurred_at: datetime + """When the event occurred.""" + + version: str + """Envelope version.""" diff --git a/src/telnyx/types/call_dial_params.py b/src/telnyx/types/call_dial_params.py index 72e40904c..6294b818e 100644 --- a/src/telnyx/types/call_dial_params.py +++ b/src/telnyx/types/call_dial_params.py @@ -416,12 +416,12 @@ class CallDialParams(TypedDict, total=False): webhook_url_method: Literal["POST", "GET"] """HTTP request type used for `webhook_url`.""" - webhook_urls: Dict[str, str] - """A map of event types to webhook URLs. + webhook_urls: Dict[str, SequenceNotStr[str]] + """A map of event types to arrays of webhook URLs. - When an event of the specified type occurs, the webhook URL associated with that - event type will be called instead of the default webhook URL. Events not mapped - here will use the default webhook URL. + When an event of the specified type occurs, the webhook URLs associated with + that event type will be called instead of the default webhook URL. Events not + mapped here will use the default webhook URL. """ webhook_urls_method: Literal["POST", "GET"] diff --git a/src/telnyx/types/calls/action_answer_params.py b/src/telnyx/types/calls/action_answer_params.py index cf655ad97..f691253c9 100644 --- a/src/telnyx/types/calls/action_answer_params.py +++ b/src/telnyx/types/calls/action_answer_params.py @@ -5,6 +5,7 @@ from typing import Dict, Iterable from typing_extensions import Literal, Required, TypedDict +from ..._types import SequenceNotStr from ..stream_codec import StreamCodec from ..sip_header_param import SipHeaderParam from ..custom_sip_header_param import CustomSipHeaderParam @@ -182,12 +183,12 @@ class ActionAnswerParams(TypedDict, total=False): webhook_url_method: Literal["POST", "GET"] """HTTP request type used for `webhook_url`.""" - webhook_urls: Dict[str, str] - """A map of event types to webhook URLs. + webhook_urls: Dict[str, SequenceNotStr[str]] + """A map of event types to arrays of webhook URLs. - When an event of the specified type occurs, the webhook URL associated with that - event type will be called instead of `webhook_url`. Events not mapped here will - use the default `webhook_url`. + When an event of the specified type occurs, the webhook URLs associated with + that event type will be called instead of `webhook_url`. Events not mapped here + will use the default `webhook_url`. """ webhook_urls_method: Literal["POST", "GET"] diff --git a/src/telnyx/types/calls/action_transfer_params.py b/src/telnyx/types/calls/action_transfer_params.py index 50e99c68d..6be18c3cc 100644 --- a/src/telnyx/types/calls/action_transfer_params.py +++ b/src/telnyx/types/calls/action_transfer_params.py @@ -5,6 +5,7 @@ from typing import Dict, Iterable from typing_extensions import Literal, Required, Annotated, TypedDict +from ..._types import SequenceNotStr from ..._utils import PropertyInfo from ..sip_header_param import SipHeaderParam from ..custom_sip_header_param import CustomSipHeaderParam @@ -269,12 +270,12 @@ class ActionTransferParams(TypedDict, total=False): webhook_url_method: Literal["POST", "GET"] """HTTP request type used for `webhook_url`.""" - webhook_urls: Dict[str, str] - """A map of event types to webhook URLs. + webhook_urls: Dict[str, SequenceNotStr[str]] + """A map of event types to arrays of webhook URLs. - When an event of the specified type occurs, the webhook URL associated with that - event type will be called instead of `webhook_url`. Events not mapped here will - use the default `webhook_url`. + When an event of the specified type occurs, the webhook URLs associated with + that event type will be called instead of `webhook_url`. Events not mapped here + will use the default `webhook_url`. """ webhook_urls_method: Literal["POST", "GET"] diff --git a/src/telnyx/types/meeting_session.py b/src/telnyx/types/meeting_session.py new file mode 100644 index 000000000..f1938873d --- /dev/null +++ b/src/telnyx/types/meeting_session.py @@ -0,0 +1,140 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["MeetingSession", "Assistant", "Avatar", "Config"] + + +class Assistant(BaseModel): + """Assistant configuration if an assistant is attached, otherwise null.""" + + id: str + """Identifier of the assistant.""" + + audio_gate: Literal["none", "half_duplex"] + """Audio gating strategy for the assistant call leg.""" + + +class Avatar(BaseModel): + """Avatar configuration if an avatar is attached, otherwise null.""" + + avatar_id: str + """Identifier of the avatar.""" + + provider: Literal["anam"] + """Avatar provider identifier.""" + + +class Config(BaseModel): + barge_in: bool + """ + When enabled, a human participant `speech_on` event interrupts and stops the + current bot audio; it does not bypass admission or initiate speech. Assistant + sessions reject `barge_in: true`. + """ + + speak_on_enter: Optional[str] = None + """Text spoken on meeting entry, or null if not set.""" + + summarize_on_end: bool + """Whether a summary artifact is generated on session end.""" + + voice: Optional[str] = None + """Configured voice identifier, or null if not set.""" + + +class MeetingSession(BaseModel): + """Represents a meeting session. + + All serializer fields are present and required; nullable fields use null when absent. No actor, provider-bot, idempotency, routing, key, or internal fields are exposed. + """ + + id: str + """Unique identifier for the meeting session.""" + + account_id: str + """Identifier of the owning account.""" + + assistant: Optional[Assistant] = None + """Assistant configuration if an assistant is attached, otherwise null.""" + + assistant_state: Optional[Literal["starting", "connected", "failed", "ended"]] = None + """Current state of the assistant, or null if no assistant is attached.""" + + assistant_state_changed_at: Optional[datetime] = None + """Timestamp of the last assistant state change, or null.""" + + avatar: Optional[Avatar] = None + """Avatar configuration if an avatar is attached, otherwise null.""" + + avatar_state: Optional[Literal["starting", "connected", "degraded", "disconnected"]] = None + """Current state of the avatar connection, or null if no avatar is attached.""" + + avatar_state_changed_at: Optional[datetime] = None + """Timestamp of the last avatar state change, or null.""" + + bot_name: str + """Display name of the bot in the meeting.""" + + config: Config + + created_at: datetime + """Timestamp when the session was created.""" + + ended_at: Optional[datetime] = None + """Timestamp when the session ended, or null if ongoing.""" + + failure_reason: Optional[str] = None + """Human-readable failure reason if the session failed, or null.""" + + join_at: Optional[datetime] = None + """Scheduled join time, or null for immediate join.""" + + joined_at: Optional[datetime] = None + """ + Timestamp when the session first became `active`, or null if it never became + active. This remains positive admission evidence after terminal transitions. + """ + + meeting_url: str + """The meeting URL the bot joins.""" + + metadata: Dict[str, object] + """Arbitrary key-value metadata attached to the session.""" + + platform: Literal["zoom", "google_meet", "teams", "webex", "unknown"] + """Detected meeting platform.""" + + provider: str + """Provider handling the meeting session.""" + + recording: bool + """Whether the session is being recorded.""" + + status: Literal[ + "scheduled", "joining", "waiting_for_admission", "active", "leaving", "ended", "failed", "admission_denied" + ] + """Lifecycle status. + + `waiting_for_admission` means the bot reached the meeting lobby and may require + host approval. `active` means the bot entered the meeting/media path. `ended` + alone does not prove attendance; use non-null `joined_at` as positive evidence + that the session became active. `admission_denied` is reserved for an explicit + provider denial, while cancellation or another termination can end a + never-admitted session as `ended`. + """ + + status_detail: Optional[str] = None + """Additional human-readable detail about the status, or null.""" + + updated_at: datetime + """Timestamp of the last update to the session.""" + + webhook_url: Optional[str] = None + """Webhook endpoint for session lifecycle callbacks, or null if not configured.""" diff --git a/src/telnyx/types/meeting_session_create_params.py b/src/telnyx/types/meeting_session_create_params.py new file mode 100644 index 000000000..957892156 --- /dev/null +++ b/src/telnyx/types/meeting_session_create_params.py @@ -0,0 +1,174 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, Union +from datetime import datetime +from typing_extensions import Literal, Required, Annotated, TypeAlias, TypedDict + +from .._utils import PropertyInfo + +__all__ = [ + "MeetingSessionCreateParams", + "Assistant", + "Avatar", + "CameraImage", + "CameraImageMeetingSessionCameraImageBase64Source", + "CameraImageMeetingSessionCameraImageURLSource", +] + + +class MeetingSessionCreateParams(TypedDict, total=False): + meeting_url: Required[str] + """The meeting URL the bot should join.""" + + assistant: Assistant + """Request options for attaching a voice assistant to the session. + + Routing fields (`call_control_connection_id`, `from`, and `loopback_sip_uri`) + are used only to establish the assistant call leg and are omitted from response + objects. `audio_gate` is returned with `id` in the assistant response object. + """ + + avatar: Avatar + """Request options for attaching a bring-your-own-key avatar to the session.""" + + barge_in: bool + """ + When enabled, a human participant `speech_on` event interrupts and stops the + current bot audio; it does not bypass admission or initiate speech. Assistant + sessions reject `barge_in: true`. + """ + + bot_name: str + """Display name for the bot in the meeting. Defaults to "Meeting Bot".""" + + camera_image: CameraImage + """ + Write-only static camera-tile image for this session, not a native account or + participant profile photo. Supply exactly one JPEG source. When effective, the + image is used as the bot's static camera/video output; presentation varies by + meeting platform and recording configuration and is not guaranteed in + recordings. An effective Avatar or Assistant webpage output takes precedence, so + this input is ignored and a URL source is not fetched. + """ + + idempotency_key: str + """ + Client-supplied idempotency key to safely retry creation requests without + duplicating sessions. Lookup is scoped to the authenticated account and compares + the key only; the request payload is not fingerprinted or compared. + """ + + join_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """ISO-8601 timestamp in the future at which the bot should join. + + If omitted, the bot joins immediately. + """ + + metadata: Dict[str, object] + """Arbitrary key-value metadata attached to the session. + + The serialized JSON representation must not exceed 16384 characters at runtime. + """ + + speak_on_enter: str + """Text the bot speaks when it enters the meeting.""" + + summarize_on_end: bool + """If true, generate a summary artifact when the session ends.""" + + voice: str + """ + Session-default voice identifier used for `speak_on_enter` and ordinary speak + actions. A voice supplied on an individual speak action overrides this default + for that utterance. + """ + + webhook_url: str + """HTTPS endpoint to receive session lifecycle callbacks. + + Static validation requires HTTPS, rejects embedded credentials and blocked + hosts, and enforces egress policy. Validation makes no network request to the + endpoint. + """ + + +_AssistantReservedKeywords = TypedDict( + "_AssistantReservedKeywords", + { + "from": str, + }, + total=False, +) + + +class Assistant(_AssistantReservedKeywords, total=False): + """Request options for attaching a voice assistant to the session. + + Routing fields (`call_control_connection_id`, `from`, and `loopback_sip_uri`) are used only to establish the assistant call leg and are omitted from response objects. `audio_gate` is returned with `id` in the assistant response object. + """ + + id: Required[str] + """Identifier of the assistant to attach.""" + + call_control_connection_id: Required[str] + """Call control connection used to bridge the assistant into the meeting audio.""" + + loopback_sip_uri: Required[str] + """SIP URI to which the assistant media loopback is established.""" + + audio_gate: Literal["none", "half_duplex"] + """Audio gating strategy for the assistant call leg.""" + + +class Avatar(TypedDict, total=False): + """Request options for attaching a bring-your-own-key avatar to the session.""" + + api_key: Required[str] + """Bring-your-own-key API key for the avatar provider. + + The key is never stored or returned by the API. + """ + + avatar_id: Required[str] + """Identifier of the avatar to use.""" + + provider: Required[Literal["anam"]] + """Avatar provider identifier. Currently only "anam" is supported.""" + + +class CameraImageMeetingSessionCameraImageBase64Source(TypedDict, total=False): + base64_data: Required[str] + """Canonical plain RFC 4648 Base64 for a valid decoded JPEG. + + Data URIs, whitespace, and the URL-safe alphabet are rejected. The encoded value + is limited to 1,835,008 characters and the decoded JPEG to 1,363,148 bytes. The + JPEG is limited to 4,096 pixels per dimension, 4 megapixels, and 128 MB of + decoder memory. The image bytes are not persisted, returned, or logged. + """ + + format: Required[Literal["jpeg"]] + """Only JPEG images are accepted.""" + + +class CameraImageMeetingSessionCameraImageURLSource(TypedDict, total=False): + format: Required[Literal["jpeg"]] + """Only JPEG images are accepted.""" + + url: Required[str] + """ + Public HTTPS JPEG URL with at most 2,048 characters and no credentials, + fragment, surrounding whitespace, raw control characters, or explicit + non-default port. Signed queries are allowed but must be treated as credentials. + Fetching is limited to public network destinations, a five-second timeout, no + redirects, a 2xx image/jpeg response with identity or no content encoding, and a + 1,363,148-byte limit enforced against both declared and streamed content. The + service resolves the URL before bot creation and does not persist, return, or + log the URL or image bytes. + """ + + +CameraImage: TypeAlias = Union[ + CameraImageMeetingSessionCameraImageBase64Source, CameraImageMeetingSessionCameraImageURLSource +] diff --git a/src/telnyx/types/meeting_session_delete_recording_media_response.py b/src/telnyx/types/meeting_session_delete_recording_media_response.py new file mode 100644 index 000000000..225bf8057 --- /dev/null +++ b/src/telnyx/types/meeting_session_delete_recording_media_response.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["MeetingSessionDeleteRecordingMediaResponse", "Data"] + + +class Data(BaseModel): + deletion_status: Literal["requested", "already_in_progress"] + + meeting_session_id: str + """The account-scoped Meeting Session identifier.""" + + provider: Literal["recall"] + + scope: Literal["provider_recording_media"] + + +class MeetingSessionDeleteRecordingMediaResponse(BaseModel): + data: Data diff --git a/src/telnyx/types/meeting_session_list_params.py b/src/telnyx/types/meeting_session_list_params.py new file mode 100644 index 000000000..d6a7b6148 --- /dev/null +++ b/src/telnyx/types/meeting_session_list_params.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, TypedDict + +__all__ = ["MeetingSessionListParams"] + + +class MeetingSessionListParams(TypedDict, total=False): + status: Literal[ + "scheduled", "joining", "waiting_for_admission", "active", "leaving", "ended", "failed", "admission_denied" + ] + """Filter meeting sessions by current status.""" diff --git a/src/telnyx/types/meeting_session_list_response.py b/src/telnyx/types/meeting_session_list_response.py new file mode 100644 index 000000000..a186b764d --- /dev/null +++ b/src/telnyx/types/meeting_session_list_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List + +from .._models import BaseModel +from .meeting_session import MeetingSession + +__all__ = ["MeetingSessionListResponse"] + + +class MeetingSessionListResponse(BaseModel): + data: List[MeetingSession] diff --git a/src/telnyx/types/meeting_session_response.py b/src/telnyx/types/meeting_session_response.py new file mode 100644 index 000000000..5a2d63f77 --- /dev/null +++ b/src/telnyx/types/meeting_session_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from .._models import BaseModel +from .meeting_session import MeetingSession + +__all__ = ["MeetingSessionResponse"] + + +class MeetingSessionResponse(BaseModel): + data: MeetingSession + """Represents a meeting session. + + All serializer fields are present and required; nullable fields use null when + absent. No actor, provider-bot, idempotency, routing, key, or internal fields + are exposed. + """ diff --git a/src/telnyx/types/meeting_session_retrieve_events_params.py b/src/telnyx/types/meeting_session_retrieve_events_params.py new file mode 100644 index 000000000..283777e74 --- /dev/null +++ b/src/telnyx/types/meeting_session_retrieve_events_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["MeetingSessionRetrieveEventsParams"] + + +class MeetingSessionRetrieveEventsParams(TypedDict, total=False): + after: int + """Return results with a cursor position after this value.""" + + limit: int + """Maximum number of results to return per page.""" diff --git a/src/telnyx/types/meeting_session_retrieve_events_response.py b/src/telnyx/types/meeting_session_retrieve_events_response.py new file mode 100644 index 000000000..159442f8e --- /dev/null +++ b/src/telnyx/types/meeting_session_retrieve_events_response.py @@ -0,0 +1,24 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List +from datetime import datetime + +from .._models import BaseModel + +__all__ = ["MeetingSessionRetrieveEventsResponse", "Data"] + + +class Data(BaseModel): + occurred_at: datetime + + payload: Dict[str, object] + + seq: int + + type: str + + +class MeetingSessionRetrieveEventsResponse(BaseModel): + data: List[Data] diff --git a/src/telnyx/types/meeting_session_retrieve_recordings_response.py b/src/telnyx/types/meeting_session_retrieve_recordings_response.py new file mode 100644 index 000000000..e8e18120d --- /dev/null +++ b/src/telnyx/types/meeting_session_retrieve_recordings_response.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional + +from .._models import BaseModel + +__all__ = ["MeetingSessionRetrieveRecordingsResponse", "Data"] + + +class Data(BaseModel): + expires_at: Optional[str] = None + """Expiry timestamp when supplied by the provider, or null. + + The current adapter returns null. + """ + + type: str + + url: str + """Current provider download URL. + + The API does not guarantee URL lifetime or refresh behavior. + """ + + +class MeetingSessionRetrieveRecordingsResponse(BaseModel): + data: List[Data] diff --git a/src/telnyx/types/meeting_session_retrieve_transcript_params.py b/src/telnyx/types/meeting_session_retrieve_transcript_params.py new file mode 100644 index 000000000..366e009f6 --- /dev/null +++ b/src/telnyx/types/meeting_session_retrieve_transcript_params.py @@ -0,0 +1,23 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["MeetingSessionRetrieveTranscriptParams"] + + +class MeetingSessionRetrieveTranscriptParams(TypedDict, total=False): + after: int + """Return results with a cursor position after this value.""" + + limit: int + """Maximum number of results to return per page.""" + + wait_seconds: int + """Long-poll duration in seconds. + + The server holds the connection open for up to this many seconds, waiting for + new or updated results before returning an empty response. Set to 0 for an + immediate response. + """ diff --git a/src/telnyx/types/meeting_session_retrieve_transcript_response.py b/src/telnyx/types/meeting_session_retrieve_transcript_response.py new file mode 100644 index 000000000..b9631bede --- /dev/null +++ b/src/telnyx/types/meeting_session_retrieve_transcript_response.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from datetime import datetime + +from .._models import BaseModel + +__all__ = ["MeetingSessionRetrieveTranscriptResponse", "Data", "Meta"] + + +class Data(BaseModel): + confidence: Optional[float] = None + + occurred_at: datetime + + relative_ts: Optional[float] = None + + seq: int + + speaker_label: Optional[str] = None + + text: str + + +class Meta(BaseModel): + next_after: Optional[int] = None + """ + Cursor to pass as `after` on the next request, or null when the response + contains no segments. + """ + + +class MeetingSessionRetrieveTranscriptResponse(BaseModel): + data: List[Data] + + meta: Meta diff --git a/src/telnyx/types/meeting_session_update_params.py b/src/telnyx/types/meeting_session_update_params.py new file mode 100644 index 000000000..1deec8f19 --- /dev/null +++ b/src/telnyx/types/meeting_session_update_params.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from datetime import datetime +from typing_extensions import Annotated, TypedDict + +from .._utils import PropertyInfo + +__all__ = ["MeetingSessionUpdateParams"] + + +class MeetingSessionUpdateParams(TypedDict, total=False): + bot_name: str + """Updated display name for the bot.""" + + join_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] + """ISO-8601 timestamp for the bot to join. May be updated to reschedule.""" diff --git a/src/telnyx/types/meeting_sessions/__init__.py b/src/telnyx/types/meeting_sessions/__init__.py new file mode 100644 index 000000000..852050435 --- /dev/null +++ b/src/telnyx/types/meeting_sessions/__init__.py @@ -0,0 +1,35 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from .action_speak_params import ActionSpeakParams as ActionSpeakParams +from .artifact_create_params import ArtifactCreateParams as ArtifactCreateParams +from .action_send_chat_params import ActionSendChatParams as ActionSendChatParams + +if TYPE_CHECKING: + from .artifact_list_response import ArtifactListResponse as ArtifactListResponse + from .action_accepted_response import ActionAcceptedResponse as ActionAcceptedResponse + from .meeting_session_artifact import MeetingSessionArtifact as MeetingSessionArtifact + from .meeting_session_artifact_response import MeetingSessionArtifactResponse as MeetingSessionArtifactResponse + + +def __getattr__(name: str) -> Any: + if name == "ActionAcceptedResponse": + from .action_accepted_response import ActionAcceptedResponse + + return ActionAcceptedResponse + if name == "MeetingSessionArtifact": + from .meeting_session_artifact import MeetingSessionArtifact + + return MeetingSessionArtifact + if name == "MeetingSessionArtifactResponse": + from .meeting_session_artifact_response import MeetingSessionArtifactResponse + + return MeetingSessionArtifactResponse + if name == "ArtifactListResponse": + from .artifact_list_response import ArtifactListResponse + + return ArtifactListResponse + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/src/telnyx/types/meeting_sessions/action_accepted_response.py b/src/telnyx/types/meeting_sessions/action_accepted_response.py new file mode 100644 index 000000000..a8a9d1dbf --- /dev/null +++ b/src/telnyx/types/meeting_sessions/action_accepted_response.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["ActionAcceptedResponse", "Data"] + + +class Data(BaseModel): + accepted: Literal[True] + + +class ActionAcceptedResponse(BaseModel): + data: Data diff --git a/src/telnyx/types/meeting_sessions/action_send_chat_params.py b/src/telnyx/types/meeting_sessions/action_send_chat_params.py new file mode 100644 index 000000000..b18355dcf --- /dev/null +++ b/src/telnyx/types/meeting_sessions/action_send_chat_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ActionSendChatParams"] + + +class ActionSendChatParams(TypedDict, total=False): + text: Required[str] + """Chat message text to send in the meeting.""" diff --git a/src/telnyx/types/meeting_sessions/action_speak_params.py b/src/telnyx/types/meeting_sessions/action_speak_params.py new file mode 100644 index 000000000..261e6086b --- /dev/null +++ b/src/telnyx/types/meeting_sessions/action_speak_params.py @@ -0,0 +1,22 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["ActionSpeakParams"] + + +class ActionSpeakParams(TypedDict, total=False): + text: Required[str] + """Text for the bot to speak.""" + + interrupt: bool + """If true, interrupt any currently playing audio to speak this text immediately.""" + + voice: str + """Voice identifier to use for this utterance. + + When supplied, it overrides the session-default voice configured at creation; + otherwise the speak action uses that session default. + """ diff --git a/src/telnyx/types/meeting_sessions/artifact_create_params.py b/src/telnyx/types/meeting_sessions/artifact_create_params.py new file mode 100644 index 000000000..c65966504 --- /dev/null +++ b/src/telnyx/types/meeting_sessions/artifact_create_params.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ArtifactCreateParams"] + + +class ArtifactCreateParams(TypedDict, total=False): + type: Required[Literal["summary", "action_items"]] + """Type of artifact to generate from the session.""" diff --git a/src/telnyx/types/meeting_sessions/artifact_list_response.py b/src/telnyx/types/meeting_sessions/artifact_list_response.py new file mode 100644 index 000000000..e20592b07 --- /dev/null +++ b/src/telnyx/types/meeting_sessions/artifact_list_response.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List + +from ..._models import BaseModel +from .meeting_session_artifact import MeetingSessionArtifact + +__all__ = ["ArtifactListResponse"] + + +class ArtifactListResponse(BaseModel): + data: List[MeetingSessionArtifact] diff --git a/src/telnyx/types/meeting_sessions/meeting_session_artifact.py b/src/telnyx/types/meeting_sessions/meeting_session_artifact.py new file mode 100644 index 000000000..267a9f520 --- /dev/null +++ b/src/telnyx/types/meeting_sessions/meeting_session_artifact.py @@ -0,0 +1,43 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from pydantic import Field as FieldInfo + +from ..._models import BaseModel + +__all__ = ["MeetingSessionArtifact", "Content", "ModelProvenance"] + + +class Content(BaseModel): + text: str + + +class ModelProvenance(BaseModel): + model: str + + provider: str + + +class MeetingSessionArtifact(BaseModel): + id: str + + content: Optional[Content] = None + + created_at: datetime + + failure_reason: Optional[str] = None + + api_model_provenance: Optional[ModelProvenance] = FieldInfo(alias="model_provenance", default=None) + + session_id: str + + status: Literal["pending", "completed", "failed"] + + type: Literal["summary", "action_items"] + + updated_at: datetime diff --git a/src/telnyx/types/meeting_sessions/meeting_session_artifact_response.py b/src/telnyx/types/meeting_sessions/meeting_session_artifact_response.py new file mode 100644 index 000000000..fb8cd2ff9 --- /dev/null +++ b/src/telnyx/types/meeting_sessions/meeting_session_artifact_response.py @@ -0,0 +1,12 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from ..._models import BaseModel +from .meeting_session_artifact import MeetingSessionArtifact + +__all__ = ["MeetingSessionArtifactResponse"] + + +class MeetingSessionArtifactResponse(BaseModel): + data: MeetingSessionArtifact diff --git a/src/telnyx/types/phone_numbers/voicemail_create_params.py b/src/telnyx/types/phone_numbers/voicemail_create_params.py index 161f9ef2a..eeb3f0fa7 100644 --- a/src/telnyx/types/phone_numbers/voicemail_create_params.py +++ b/src/telnyx/types/phone_numbers/voicemail_create_params.py @@ -2,14 +2,46 @@ from __future__ import annotations -from typing_extensions import TypedDict +from typing import Optional +from typing_extensions import Literal, TypedDict -__all__ = ["VoicemailCreateParams"] +__all__ = ["VoicemailCreateParams", "Greeting"] class VoicemailCreateParams(TypedDict, total=False): enabled: bool """Whether voicemail is enabled.""" + greeting: Greeting + """Controls the greeting a caller hears before leaving a voicemail. + + Set `mode` to `default` to play the standard system greeting, or to + `custom_greeting` to play your own audio. When `mode` is `custom_greeting`, + `media_name` is required and must reference an audio file already uploaded to + your account through the Media Storage API. + """ + pin: str """The pin used for voicemail""" + + +class Greeting(TypedDict, total=False): + """Controls the greeting a caller hears before leaving a voicemail. + + Set `mode` to `default` to play the standard system greeting, or to `custom_greeting` to play your own audio. When `mode` is `custom_greeting`, `media_name` is required and must reference an audio file already uploaded to your account through the Media Storage API. + """ + + media_name: Optional[str] + """The name of the media file to play as the greeting. + + Required when `mode` is `custom_greeting`; ignored when `mode` is `default`. The + value must match the `media_name` of a file you previously uploaded with the + Media Storage API (`POST /v2/media`). + """ + + mode: Literal["default", "custom_greeting"] + """The greeting mode. + + `default` plays the standard system greeting. `custom_greeting` plays the audio + referenced by `media_name`. + """ diff --git a/src/telnyx/types/phone_numbers/voicemail_pref_response.py b/src/telnyx/types/phone_numbers/voicemail_pref_response.py index 932d568c6..b988f6256 100644 --- a/src/telnyx/types/phone_numbers/voicemail_pref_response.py +++ b/src/telnyx/types/phone_numbers/voicemail_pref_response.py @@ -3,15 +3,47 @@ from __future__ import annotations from typing import Optional +from typing_extensions import Literal from ..._models import BaseModel -__all__ = ["VoicemailPrefResponse"] +__all__ = ["VoicemailPrefResponse", "Greeting"] + + +class Greeting(BaseModel): + """Controls the greeting a caller hears before leaving a voicemail. + + Set `mode` to `default` to play the standard system greeting, or to `custom_greeting` to play your own audio. When `mode` is `custom_greeting`, `media_name` is required and must reference an audio file already uploaded to your account through the Media Storage API. + """ + + media_name: Optional[str] = None + """The name of the media file to play as the greeting. + + Required when `mode` is `custom_greeting`; ignored when `mode` is `default`. The + value must match the `media_name` of a file you previously uploaded with the + Media Storage API (`POST /v2/media`). + """ + + mode: Optional[Literal["default", "custom_greeting"]] = None + """The greeting mode. + + `default` plays the standard system greeting. `custom_greeting` plays the audio + referenced by `media_name`. + """ class VoicemailPrefResponse(BaseModel): enabled: Optional[bool] = None """Whether voicemail is enabled.""" + greeting: Optional[Greeting] = None + """Controls the greeting a caller hears before leaving a voicemail. + + Set `mode` to `default` to play the standard system greeting, or to + `custom_greeting` to play your own audio. When `mode` is `custom_greeting`, + `media_name` is required and must reference an audio file already uploaded to + your account through the Media Storage API. + """ + pin: Optional[str] = None """The pin used for the voicemail.""" diff --git a/src/telnyx/types/phone_numbers/voicemail_update_params.py b/src/telnyx/types/phone_numbers/voicemail_update_params.py index 2f33b9f7c..9015c8444 100644 --- a/src/telnyx/types/phone_numbers/voicemail_update_params.py +++ b/src/telnyx/types/phone_numbers/voicemail_update_params.py @@ -2,14 +2,46 @@ from __future__ import annotations -from typing_extensions import TypedDict +from typing import Optional +from typing_extensions import Literal, TypedDict -__all__ = ["VoicemailUpdateParams"] +__all__ = ["VoicemailUpdateParams", "Greeting"] class VoicemailUpdateParams(TypedDict, total=False): enabled: bool """Whether voicemail is enabled.""" + greeting: Greeting + """Controls the greeting a caller hears before leaving a voicemail. + + Set `mode` to `default` to play the standard system greeting, or to + `custom_greeting` to play your own audio. When `mode` is `custom_greeting`, + `media_name` is required and must reference an audio file already uploaded to + your account through the Media Storage API. + """ + pin: str """The pin used for voicemail""" + + +class Greeting(TypedDict, total=False): + """Controls the greeting a caller hears before leaving a voicemail. + + Set `mode` to `default` to play the standard system greeting, or to `custom_greeting` to play your own audio. When `mode` is `custom_greeting`, `media_name` is required and must reference an audio file already uploaded to your account through the Media Storage API. + """ + + media_name: Optional[str] + """The name of the media file to play as the greeting. + + Required when `mode` is `custom_greeting`; ignored when `mode` is `default`. The + value must match the `media_name` of a file you previously uploaded with the + Media Storage API (`POST /v2/media`). + """ + + mode: Literal["default", "custom_greeting"] + """The greeting mode. + + `default` plays the standard system greeting. `custom_greeting` plays the audio + referenced by `media_name`. + """ diff --git a/src/telnyx/types/private_wireless_gateway_status.py b/src/telnyx/types/private_wireless_gateway_status.py index c3fe44191..0af4f4543 100644 --- a/src/telnyx/types/private_wireless_gateway_status.py +++ b/src/telnyx/types/private_wireless_gateway_status.py @@ -16,7 +16,7 @@ class PrivateWirelessGatewayStatus(BaseModel): error_code: Optional[str] = None """ This attribute is an - [error code](https://developers.telnyx.com/development/api-fundamentals/api-errors) + [error code](https://developers.telnyx.com/docs/development/api-fundamentals/api-errors) related to the failure reason. """ diff --git a/src/telnyx/types/recording_available_webhook_event.py b/src/telnyx/types/recording_available_webhook_event.py new file mode 100644 index 000000000..5551ffc76 --- /dev/null +++ b/src/telnyx/types/recording_available_webhook_event.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["RecordingAvailableWebhookEvent", "Data"] + + +class Data(BaseModel): + """Available recording types.""" + + recording_types: List[str] + """Available recording types.""" + + session_id: str + """The meeting session this event belongs to.""" + + +class RecordingAvailableWebhookEvent(BaseModel): + id: str + """Unique event id; deduplicate deliveries on it.""" + + data: Data + """Available recording types.""" + + event: Literal["recording.available"] + """Event type.""" + + occurred_at: datetime + """When the event occurred.""" + + version: str + """Envelope version.""" diff --git a/src/telnyx/types/recording_available_webhook_event1.py b/src/telnyx/types/recording_available_webhook_event1.py new file mode 100644 index 000000000..5551ffc76 --- /dev/null +++ b/src/telnyx/types/recording_available_webhook_event1.py @@ -0,0 +1,38 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["RecordingAvailableWebhookEvent", "Data"] + + +class Data(BaseModel): + """Available recording types.""" + + recording_types: List[str] + """Available recording types.""" + + session_id: str + """The meeting session this event belongs to.""" + + +class RecordingAvailableWebhookEvent(BaseModel): + id: str + """Unique event id; deduplicate deliveries on it.""" + + data: Data + """Available recording types.""" + + event: Literal["recording.available"] + """Event type.""" + + occurred_at: datetime + """When the event occurred.""" + + version: str + """Envelope version.""" diff --git a/src/telnyx/types/session_status_changed_webhook_event.py b/src/telnyx/types/session_status_changed_webhook_event.py new file mode 100644 index 000000000..5db8982e5 --- /dev/null +++ b/src/telnyx/types/session_status_changed_webhook_event.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["SessionStatusChangedWebhookEvent", "Data"] + + +class Data(BaseModel): + """Status transition details.""" + + recording: bool + """Whether the session is recording at this lifecycle edge.""" + + session_id: str + """The meeting session this event belongs to.""" + + status: str + """The new session status.""" + + status_detail: Optional[str] = None + """ + Additional detail about the status (for example `timeout_exceeded_everyone_left` + or `cancelled`), or null. + """ + + +class SessionStatusChangedWebhookEvent(BaseModel): + id: str + """Unique event id; deduplicate deliveries on it.""" + + data: Data + """Status transition details.""" + + event: Literal["session.status_changed"] + """Event type.""" + + occurred_at: datetime + """When the event occurred.""" + + version: str + """Envelope version.""" diff --git a/src/telnyx/types/session_status_changed_webhook_event1.py b/src/telnyx/types/session_status_changed_webhook_event1.py new file mode 100644 index 000000000..5db8982e5 --- /dev/null +++ b/src/telnyx/types/session_status_changed_webhook_event1.py @@ -0,0 +1,47 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["SessionStatusChangedWebhookEvent", "Data"] + + +class Data(BaseModel): + """Status transition details.""" + + recording: bool + """Whether the session is recording at this lifecycle edge.""" + + session_id: str + """The meeting session this event belongs to.""" + + status: str + """The new session status.""" + + status_detail: Optional[str] = None + """ + Additional detail about the status (for example `timeout_exceeded_everyone_left` + or `cancelled`), or null. + """ + + +class SessionStatusChangedWebhookEvent(BaseModel): + id: str + """Unique event id; deduplicate deliveries on it.""" + + data: Data + """Status transition details.""" + + event: Literal["session.status_changed"] + """Event type.""" + + occurred_at: datetime + """When the event occurred.""" + + version: str + """Envelope version.""" diff --git a/src/telnyx/types/sim_cards/__init__.py b/src/telnyx/types/sim_cards/__init__.py index 808bdad02..d2175cfac 100644 --- a/src/telnyx/types/sim_cards/__init__.py +++ b/src/telnyx/types/sim_cards/__init__.py @@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Any from .action_list_params import ActionListParams as ActionListParams +from .action_enable_voice_params import ActionEnableVoiceParams as ActionEnableVoiceParams from .action_set_public_ip_params import ActionSetPublicIPParams as ActionSetPublicIPParams from .action_bulk_enable_voice_params import ActionBulkEnableVoiceParams as ActionBulkEnableVoiceParams from .action_bulk_disable_voice_params import ActionBulkDisableVoiceParams as ActionBulkDisableVoiceParams @@ -20,6 +21,8 @@ from .action_retrieve_response import ActionRetrieveResponse as ActionRetrieveResponse from .wireless_sim_card_action import WirelessSimCardAction as WirelessSimCardAction from .action_set_standby_response import ActionSetStandbyResponse as ActionSetStandbyResponse + from .action_enable_voice_response import ActionEnableVoiceResponse as ActionEnableVoiceResponse + from .action_disable_voice_response import ActionDisableVoiceResponse as ActionDisableVoiceResponse from .action_set_public_ip_response import ActionSetPublicIPResponse as ActionSetPublicIPResponse from .action_remove_public_ip_response import ActionRemovePublicIPResponse as ActionRemovePublicIPResponse from .action_bulk_enable_voice_response import ActionBulkEnableVoiceResponse as ActionBulkEnableVoiceResponse @@ -59,10 +62,18 @@ def __getattr__(name: str) -> Any: from .action_disable_response import ActionDisableResponse return ActionDisableResponse + if name == "ActionDisableVoiceResponse": + from .action_disable_voice_response import ActionDisableVoiceResponse + + return ActionDisableVoiceResponse if name == "ActionEnableResponse": from .action_enable_response import ActionEnableResponse return ActionEnableResponse + if name == "ActionEnableVoiceResponse": + from .action_enable_voice_response import ActionEnableVoiceResponse + + return ActionEnableVoiceResponse if name == "ActionRemovePublicIPResponse": from .action_remove_public_ip_response import ActionRemovePublicIPResponse diff --git a/src/telnyx/types/sim_cards/action_bulk_enable_voice_params.py b/src/telnyx/types/sim_cards/action_bulk_enable_voice_params.py index ed1665bcf..391b4f19a 100644 --- a/src/telnyx/types/sim_cards/action_bulk_enable_voice_params.py +++ b/src/telnyx/types/sim_cards/action_bulk_enable_voice_params.py @@ -9,3 +9,11 @@ class ActionBulkEnableVoiceParams(TypedDict, total=False): sim_card_group_id: Required[str] + + connection_id: str + """The identifier of the Mobile Voice Connection to associate with the SIM cards. + + The connection must be owned by the same user and of type + mobile_voice. If omitted, voice is enabled without a connection + association. + """ diff --git a/src/telnyx/types/sim_cards/action_disable_voice_response.py b/src/telnyx/types/sim_cards/action_disable_voice_response.py new file mode 100644 index 000000000..ffa1ed763 --- /dev/null +++ b/src/telnyx/types/sim_cards/action_disable_voice_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +from ..._models import BaseModel +from .wireless_sim_card_action import WirelessSimCardAction + +__all__ = ["ActionDisableVoiceResponse"] + + +class ActionDisableVoiceResponse(BaseModel): + data: Optional[WirelessSimCardAction] = None + """This object represents a SIM card action. + + It allows tracking the current status of an operation that impacts the SIM card. + """ diff --git a/src/telnyx/types/sim_cards/action_enable_voice_params.py b/src/telnyx/types/sim_cards/action_enable_voice_params.py new file mode 100644 index 000000000..661e5fd8e --- /dev/null +++ b/src/telnyx/types/sim_cards/action_enable_voice_params.py @@ -0,0 +1,17 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["ActionEnableVoiceParams"] + + +class ActionEnableVoiceParams(TypedDict, total=False): + connection_id: str + """The identifier of the Mobile Voice Connection to associate with this SIM card. + + The connection must be owned by the same user and of type + mobile_voice. If omitted, voice is enabled without a connection + association. + """ diff --git a/src/telnyx/types/sim_cards/action_enable_voice_response.py b/src/telnyx/types/sim_cards/action_enable_voice_response.py new file mode 100644 index 000000000..8471dac1d --- /dev/null +++ b/src/telnyx/types/sim_cards/action_enable_voice_response.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +from ..._models import BaseModel +from .wireless_sim_card_action import WirelessSimCardAction + +__all__ = ["ActionEnableVoiceResponse"] + + +class ActionEnableVoiceResponse(BaseModel): + data: Optional[WirelessSimCardAction] = None + """This object represents a SIM card action. + + It allows tracking the current status of an operation that impacts the SIM card. + """ diff --git a/src/telnyx/types/sim_cards/action_list_params.py b/src/telnyx/types/sim_cards/action_list_params.py index 8afaabf1a..d53835fa9 100644 --- a/src/telnyx/types/sim_cards/action_list_params.py +++ b/src/telnyx/types/sim_cards/action_list_params.py @@ -29,7 +29,14 @@ class Filter(TypedDict, total=False): """ action_type: Literal[ - "enable", "enable_standby_sim_card", "disable", "set_standby", "remove_public_ip", "set_public_ip" + "enable", + "enable_standby_sim_card", + "disable", + "set_standby", + "remove_public_ip", + "set_public_ip", + "enable_voice", + "disable_voice", ] """Filter by action type.""" diff --git a/src/telnyx/types/sim_cards/wireless_sim_card_action.py b/src/telnyx/types/sim_cards/wireless_sim_card_action.py index 24633853f..d344a4058 100644 --- a/src/telnyx/types/sim_cards/wireless_sim_card_action.py +++ b/src/telnyx/types/sim_cards/wireless_sim_card_action.py @@ -32,7 +32,9 @@ class WirelessSimCardAction(BaseModel): id: Optional[str] = None """Identifies the resource.""" - action_type: Optional[Literal["enable", "enable_standby_sim_card", "disable", "set_standby"]] = None + action_type: Optional[ + Literal["enable", "enable_standby_sim_card", "disable", "set_standby", "enable_voice", "disable_voice"] + ] = None """The operation type. It can be one of the following:
""" diff --git a/src/telnyx/types/storage/__init__.py b/src/telnyx/types/storage/__init__.py index a7e296fbb..a33d2d5ec 100644 --- a/src/telnyx/types/storage/__init__.py +++ b/src/telnyx/types/storage/__init__.py @@ -6,7 +6,10 @@ from .kv_list_params import KvListParams as KvListParams from .kv_create_params import KvCreateParams as KvCreateParams +from .sqldb_list_params import SqldbListParams as SqldbListParams from .cloudf_list_params import CloudfListParams as CloudfListParams +from .sqldb_create_params import SqldbCreateParams as SqldbCreateParams +from .sqldb_delete_params import SqldbDeleteParams as SqldbDeleteParams from .cloudf_create_params import CloudfCreateParams as CloudfCreateParams from .cloudf_update_params import CloudfUpdateParams as CloudfUpdateParams from .migration_create_params import MigrationCreateParams as MigrationCreateParams @@ -16,13 +19,16 @@ if TYPE_CHECKING: from .kv_namespace import KvNamespace as KvNamespace + from .sql_database import SqlDatabase as SqlDatabase from .migration_params import MigrationParams as MigrationParams from .cloudf_list_response import CloudfListResponse as CloudfListResponse from .migration_list_response import MigrationListResponse as MigrationListResponse from .migration_source_params import MigrationSourceParams as MigrationSourceParams from .migration_create_response import MigrationCreateResponse as MigrationCreateResponse from .migration_retrieve_response import MigrationRetrieveResponse as MigrationRetrieveResponse + from .edge_compute_pagination_meta import EdgeComputePaginationMeta as EdgeComputePaginationMeta from .kv_namespace_response_wrapper import KvNamespaceResponseWrapper as KvNamespaceResponseWrapper + from .sql_database_response_wrapper import SqlDatabaseResponseWrapper as SqlDatabaseResponseWrapper from .migration_source_list_response import MigrationSourceListResponse as MigrationSourceListResponse from .migration_source_create_response import MigrationSourceCreateResponse as MigrationSourceCreateResponse from .migration_source_delete_response import MigrationSourceDeleteResponse as MigrationSourceDeleteResponse @@ -79,6 +85,10 @@ def __getattr__(name: str) -> Any: from .migration_list_response import MigrationListResponse return MigrationListResponse + if name == "EdgeComputePaginationMeta": + from .edge_compute_pagination_meta import EdgeComputePaginationMeta + + return EdgeComputePaginationMeta if name == "KvNamespace": from .kv_namespace import KvNamespace @@ -99,4 +109,12 @@ def __getattr__(name: str) -> Any: from .cloudf_list_response import CloudfListResponse return CloudfListResponse + if name == "SqlDatabase": + from .sql_database import SqlDatabase + + return SqlDatabase + if name == "SqlDatabaseResponseWrapper": + from .sql_database_response_wrapper import SqlDatabaseResponseWrapper + + return SqlDatabaseResponseWrapper raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/src/telnyx/types/storage/edge_compute_pagination_meta.py b/src/telnyx/types/storage/edge_compute_pagination_meta.py new file mode 100644 index 000000000..509cc700b --- /dev/null +++ b/src/telnyx/types/storage/edge_compute_pagination_meta.py @@ -0,0 +1,19 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["EdgeComputePaginationMeta"] + + +class EdgeComputePaginationMeta(BaseModel): + page_number: Optional[int] = None + + page_size: Optional[int] = None + + total_pages: Optional[int] = None + + total_results: Optional[int] = None diff --git a/src/telnyx/types/storage/sql_database.py b/src/telnyx/types/storage/sql_database.py new file mode 100644 index 000000000..7f7064c7a --- /dev/null +++ b/src/telnyx/types/storage/sql_database.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from ..._models import BaseModel + +__all__ = ["SqlDatabase"] + + +class SqlDatabase(BaseModel): + id: Optional[str] = None + + created_at: Optional[datetime] = None + + name: Optional[str] = None + + record_type: Optional[str] = None + + status: Optional[Literal["pending", "provision_ok", "provision_failed", "deleting", "delete_failed"]] = None + """Provisioning status. + + A database is usable once `status` is `provision_ok`. Once deletion completes, + the database no longer appears in the API. + """ + + updated_at: Optional[datetime] = None diff --git a/src/telnyx/types/storage/sql_database_response_wrapper.py b/src/telnyx/types/storage/sql_database_response_wrapper.py new file mode 100644 index 000000000..233c8a748 --- /dev/null +++ b/src/telnyx/types/storage/sql_database_response_wrapper.py @@ -0,0 +1,14 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +from ..._models import BaseModel +from .sql_database import SqlDatabase + +__all__ = ["SqlDatabaseResponseWrapper"] + + +class SqlDatabaseResponseWrapper(BaseModel): + data: Optional[SqlDatabase] = None diff --git a/src/telnyx/types/storage/sqldb_create_params.py b/src/telnyx/types/storage/sqldb_create_params.py new file mode 100644 index 000000000..092b040f4 --- /dev/null +++ b/src/telnyx/types/storage/sqldb_create_params.py @@ -0,0 +1,16 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Required, TypedDict + +__all__ = ["SqldbCreateParams"] + + +class SqldbCreateParams(TypedDict, total=False): + name: Required[str] + """Database name. + + Lowercase letters, numbers, and hyphens only; must start and end with a letter + or number. + """ diff --git a/src/telnyx/types/storage/sqldb_delete_params.py b/src/telnyx/types/storage/sqldb_delete_params.py new file mode 100644 index 000000000..d57769d64 --- /dev/null +++ b/src/telnyx/types/storage/sqldb_delete_params.py @@ -0,0 +1,15 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import TypedDict + +__all__ = ["SqldbDeleteParams"] + + +class SqldbDeleteParams(TypedDict, total=False): + force: bool + """Delete the database even when functions still bind it. + + Their bindings stop resolving. + """ diff --git a/src/telnyx/types/storage/sqldb_list_params.py b/src/telnyx/types/storage/sqldb_list_params.py new file mode 100644 index 000000000..30630024e --- /dev/null +++ b/src/telnyx/types/storage/sqldb_list_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Annotated, TypedDict + +from ..._utils import PropertyInfo + +__all__ = ["SqldbListParams"] + + +class SqldbListParams(TypedDict, total=False): + filter_name: Annotated[str, PropertyInfo(alias="filter[name]")] + """Filter by exact name match.""" + + filter_status: Annotated[ + Literal["pending", "provision_ok", "provision_failed", "deleting", "delete_failed"], + PropertyInfo(alias="filter[status]"), + ] + """Filter by provisioning status.""" + + page_number: Annotated[int, PropertyInfo(alias="page[number]")] + """The page number to load.""" + + page_size: Annotated[int, PropertyInfo(alias="page[size]")] + """The size of the page. Values above 250 are treated as 250.""" + + sort: Literal["name", "-name", "status", "-status", "created_at", "-created_at"] + """Sort field; prefix with `-` for descending order.""" diff --git a/src/telnyx/types/storage/sqldbs/__init__.py b/src/telnyx/types/storage/sqldbs/__init__.py new file mode 100644 index 000000000..e4dc66625 --- /dev/null +++ b/src/telnyx/types/storage/sqldbs/__init__.py @@ -0,0 +1,18 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from .action_query_params import ActionQueryParams as ActionQueryParams + +if TYPE_CHECKING: + from .action_query_response import ActionQueryResponse as ActionQueryResponse + + +def __getattr__(name: str) -> Any: + if name == "ActionQueryResponse": + from .action_query_response import ActionQueryResponse + + return ActionQueryResponse + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/src/telnyx/types/storage/sqldbs/action_query_params.py b/src/telnyx/types/storage/sqldbs/action_query_params.py new file mode 100644 index 000000000..cac410e58 --- /dev/null +++ b/src/telnyx/types/storage/sqldbs/action_query_params.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Union +from typing_extensions import Required, TypedDict + +from ...._types import SequenceNotStr + +__all__ = ["ActionQueryParams"] + + +class ActionQueryParams(TypedDict, total=False): + sql: Required[str] + """The SQL to run. + + Use positional `?` placeholders and supply the values in `params` rather than + interpolating them into this string. + """ + + params: SequenceNotStr[Union[str, float, bool, None]] + """Positional bind parameters, in placeholder order. + + Each value is a string, a number, a boolean, or null; booleans are cast to + `1`/`0`. The count must match the number of `?` placeholders exactly — a + mismatch is rejected with 422 rather than binding null for the ones you left + out. (Not enforced for multi-statement scripts or named parameters, where the + placeholder count is not the number bound.) + """ diff --git a/src/telnyx/types/storage/sqldbs/action_query_response.py b/src/telnyx/types/storage/sqldbs/action_query_response.py new file mode 100644 index 000000000..c4f2c348a --- /dev/null +++ b/src/telnyx/types/storage/sqldbs/action_query_response.py @@ -0,0 +1,46 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Dict, List, Optional + +from ...._models import BaseModel + +__all__ = ["ActionQueryResponse", "Data", "DataMeta"] + + +class DataMeta(BaseModel): + changes: Optional[int] = None + """Number of rows added, changed, or removed by the statement.""" + + duration: Optional[float] = None + """Wall-clock duration of the statement, in milliseconds.""" + + last_row_id: Optional[int] = None + """Rowid of the last inserted row, when applicable.""" + + rows_read: Optional[int] = None + + rows_written: Optional[int] = None + + +class Data(BaseModel): + count: Optional[int] = None + """Number of rows returned.""" + + duration: Optional[float] = None + """Wall-clock duration of the request, in milliseconds.""" + + meta: Optional[DataMeta] = None + + results: Optional[List[Dict[str, object]]] = None + """The result rows, each a map of column name to value. + + Empty for statements that return no rows. + """ + + success: Optional[bool] = None + + +class ActionQueryResponse(BaseModel): + data: Optional[Data] = None diff --git a/src/telnyx/types/transcript_completed_webhook_event.py b/src/telnyx/types/transcript_completed_webhook_event.py new file mode 100644 index 000000000..468a567f9 --- /dev/null +++ b/src/telnyx/types/transcript_completed_webhook_event.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["TranscriptCompletedWebhookEvent", "Data"] + + +class Data(BaseModel): + """Finalized transcript details.""" + + ended_at: Optional[datetime] = None + """Session end time, or null when unavailable.""" + + last_seq: Optional[int] = None + """Last transcript segment sequence number, or null for an empty transcript.""" + + segment_count: int + """Number of transcript segments observed during finalization.""" + + session_id: str + """The meeting session this event belongs to.""" + + +class TranscriptCompletedWebhookEvent(BaseModel): + id: str + """Unique event id; deduplicate deliveries on it.""" + + data: Data + """Finalized transcript details.""" + + event: Literal["transcript.completed"] + """Event type.""" + + occurred_at: datetime + """When the event occurred.""" + + version: str + """Envelope version.""" diff --git a/src/telnyx/types/transcript_completed_webhook_event1.py b/src/telnyx/types/transcript_completed_webhook_event1.py new file mode 100644 index 000000000..468a567f9 --- /dev/null +++ b/src/telnyx/types/transcript_completed_webhook_event1.py @@ -0,0 +1,44 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional +from datetime import datetime +from typing_extensions import Literal + +from .._models import BaseModel + +__all__ = ["TranscriptCompletedWebhookEvent", "Data"] + + +class Data(BaseModel): + """Finalized transcript details.""" + + ended_at: Optional[datetime] = None + """Session end time, or null when unavailable.""" + + last_seq: Optional[int] = None + """Last transcript segment sequence number, or null for an empty transcript.""" + + segment_count: int + """Number of transcript segments observed during finalization.""" + + session_id: str + """The meeting session this event belongs to.""" + + +class TranscriptCompletedWebhookEvent(BaseModel): + id: str + """Unique event id; deduplicate deliveries on it.""" + + data: Data + """Finalized transcript details.""" + + event: Literal["transcript.completed"] + """Event type.""" + + occurred_at: datetime + """When the event occurred.""" + + version: str + """Envelope version.""" diff --git a/src/telnyx/types/unsafe_unwrap_webhook_event.py b/src/telnyx/types/unsafe_unwrap_webhook_event.py index a4174b3eb..858d8f248 100644 --- a/src/telnyx/types/unsafe_unwrap_webhook_event.py +++ b/src/telnyx/types/unsafe_unwrap_webhook_event.py @@ -21,6 +21,7 @@ from .call_enqueued_webhook_event import CallEnqueuedWebhookEvent from .transcription_webhook_event import TranscriptionWebhookEvent from .call_initiated_webhook_event import CallInitiatedWebhookEvent +from .artifact_failed_webhook_event import ArtifactFailedWebhookEvent from .call_left_queue_webhook_event import CallLeftQueueWebhookEvent from .delivery_update_webhook_event import DeliveryUpdateWebhookEvent from .inbound_message_webhook_event import InboundMessageWebhookEvent @@ -30,6 +31,7 @@ from .call_fork_stopped_webhook_event import CallForkStoppedWebhookEvent from .call_gather_ended_webhook_event import CallGatherEndedWebhookEvent from .call_refer_failed_webhook_event import CallReferFailedWebhookEvent +from .artifact_completed_webhook_event import ArtifactCompletedWebhookEvent from .call_dtmf_received_webhook_event import CallDtmfReceivedWebhookEvent from .call_refer_started_webhook_event import CallReferStartedWebhookEvent from .call_siprec_failed_webhook_event import CallSiprecFailedWebhookEvent @@ -38,11 +40,13 @@ from .call_playback_ended_webhook_event import CallPlaybackEndedWebhookEvent from .call_siprec_started_webhook_event import CallSiprecStartedWebhookEvent from .call_siprec_stopped_webhook_event import CallSiprecStoppedWebhookEvent +from .recording_available_webhook_event import RecordingAvailableWebhookEvent from .replaced_link_click_webhook_event import ReplacedLinkClickWebhookEvent from .call_ai_gather_ended_webhook_event import CallAIGatherEndedWebhookEvent from .call_recording_error_webhook_event import CallRecordingErrorWebhookEvent from .call_recording_saved_webhook_event import CallRecordingSavedWebhookEvent from .call_refer_completed_webhook_event import CallReferCompletedWebhookEvent +from .transcript_completed_webhook_event import TranscriptCompletedWebhookEvent from .call_payment_progress_webhook_event import CallPaymentProgressWebhookEvent from .call_playback_started_webhook_event import CallPlaybackStartedWebhookEvent from .call_streaming_failed_webhook_event import CallStreamingFailedWebhookEvent @@ -50,6 +54,7 @@ from .call_streaming_started_webhook_event import CallStreamingStartedWebhookEvent from .call_streaming_stopped_webhook_event import CallStreamingStoppedWebhookEvent from .conference_speak_ended_webhook_event import ConferenceSpeakEndedWebhookEvent +from .session_status_changed_webhook_event import SessionStatusChangedWebhookEvent from .call_conversation_ended_webhook_event import CallConversationEndedWebhookEvent from .conference_speak_started_webhook_event import ConferenceSpeakStartedWebhookEvent from .conference_playback_ended_webhook_event import ConferencePlaybackEndedWebhookEvent @@ -80,6 +85,8 @@ CallAIGatherEndedWebhookEvent, CallAIGatherMessageHistoryUpdatedWebhookEvent, CallAIGatherPartialResultsWebhookEvent, + ArtifactCompletedWebhookEvent, + ArtifactFailedWebhookEvent, CallAnsweredWebhookEvent, CallBridgedWebhookEvent, CallConversationEndedWebhookEvent, @@ -143,6 +150,9 @@ HostedNumberOrderEventWebhookEvent, InboundMessageWebhookEvent, NumberOrderStatusUpdateWebhookEvent, + RecordingAvailableWebhookEvent, ReplacedLinkClickWebhookEvent, + SessionStatusChangedWebhookEvent, + TranscriptCompletedWebhookEvent, TranscriptionWebhookEvent, ] diff --git a/src/telnyx/types/unwrap_webhook_event.py b/src/telnyx/types/unwrap_webhook_event.py index f017272b9..1747cbc40 100644 --- a/src/telnyx/types/unwrap_webhook_event.py +++ b/src/telnyx/types/unwrap_webhook_event.py @@ -21,6 +21,7 @@ from .call_enqueued_webhook_event import CallEnqueuedWebhookEvent from .transcription_webhook_event import TranscriptionWebhookEvent from .call_initiated_webhook_event import CallInitiatedWebhookEvent +from .artifact_failed_webhook_event import ArtifactFailedWebhookEvent from .call_left_queue_webhook_event import CallLeftQueueWebhookEvent from .delivery_update_webhook_event import DeliveryUpdateWebhookEvent from .inbound_message_webhook_event import InboundMessageWebhookEvent @@ -30,6 +31,7 @@ from .call_fork_stopped_webhook_event import CallForkStoppedWebhookEvent from .call_gather_ended_webhook_event import CallGatherEndedWebhookEvent from .call_refer_failed_webhook_event import CallReferFailedWebhookEvent +from .artifact_completed_webhook_event import ArtifactCompletedWebhookEvent from .call_dtmf_received_webhook_event import CallDtmfReceivedWebhookEvent from .call_refer_started_webhook_event import CallReferStartedWebhookEvent from .call_siprec_failed_webhook_event import CallSiprecFailedWebhookEvent @@ -38,11 +40,13 @@ from .call_playback_ended_webhook_event import CallPlaybackEndedWebhookEvent from .call_siprec_started_webhook_event import CallSiprecStartedWebhookEvent from .call_siprec_stopped_webhook_event import CallSiprecStoppedWebhookEvent +from .recording_available_webhook_event import RecordingAvailableWebhookEvent from .replaced_link_click_webhook_event import ReplacedLinkClickWebhookEvent from .call_ai_gather_ended_webhook_event import CallAIGatherEndedWebhookEvent from .call_recording_error_webhook_event import CallRecordingErrorWebhookEvent from .call_recording_saved_webhook_event import CallRecordingSavedWebhookEvent from .call_refer_completed_webhook_event import CallReferCompletedWebhookEvent +from .transcript_completed_webhook_event import TranscriptCompletedWebhookEvent from .call_payment_progress_webhook_event import CallPaymentProgressWebhookEvent from .call_playback_started_webhook_event import CallPlaybackStartedWebhookEvent from .call_streaming_failed_webhook_event import CallStreamingFailedWebhookEvent @@ -50,6 +54,7 @@ from .call_streaming_started_webhook_event import CallStreamingStartedWebhookEvent from .call_streaming_stopped_webhook_event import CallStreamingStoppedWebhookEvent from .conference_speak_ended_webhook_event import ConferenceSpeakEndedWebhookEvent +from .session_status_changed_webhook_event import SessionStatusChangedWebhookEvent from .call_conversation_ended_webhook_event import CallConversationEndedWebhookEvent from .conference_speak_started_webhook_event import ConferenceSpeakStartedWebhookEvent from .conference_playback_ended_webhook_event import ConferencePlaybackEndedWebhookEvent @@ -80,6 +85,8 @@ CallAIGatherEndedWebhookEvent, CallAIGatherMessageHistoryUpdatedWebhookEvent, CallAIGatherPartialResultsWebhookEvent, + ArtifactCompletedWebhookEvent, + ArtifactFailedWebhookEvent, CallAnsweredWebhookEvent, CallBridgedWebhookEvent, CallConversationEndedWebhookEvent, @@ -143,6 +150,9 @@ HostedNumberOrderEventWebhookEvent, InboundMessageWebhookEvent, NumberOrderStatusUpdateWebhookEvent, + RecordingAvailableWebhookEvent, ReplacedLinkClickWebhookEvent, + SessionStatusChangedWebhookEvent, + TranscriptCompletedWebhookEvent, TranscriptionWebhookEvent, ] diff --git a/src/telnyx/types/web_search/__init__.py b/src/telnyx/types/web_search/__init__.py new file mode 100644 index 000000000..ba6c5b822 --- /dev/null +++ b/src/telnyx/types/web_search/__init__.py @@ -0,0 +1,28 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import TYPE_CHECKING, Any + +from .research_create_params import ResearchCreateParams as ResearchCreateParams + +if TYPE_CHECKING: + from .research_citation import ResearchCitation as ResearchCitation + from .research_create_response import ResearchCreateResponse as ResearchCreateResponse + from .research_retrieve_response import ResearchRetrieveResponse as ResearchRetrieveResponse + + +def __getattr__(name: str) -> Any: + if name == "ResearchCitation": + from .research_citation import ResearchCitation + + return ResearchCitation + if name == "ResearchCreateResponse": + from .research_create_response import ResearchCreateResponse + + return ResearchCreateResponse + if name == "ResearchRetrieveResponse": + from .research_retrieve_response import ResearchRetrieveResponse + + return ResearchRetrieveResponse + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/src/telnyx/types/web_search/research_citation.py b/src/telnyx/types/web_search/research_citation.py new file mode 100644 index 000000000..08ef980e7 --- /dev/null +++ b/src/telnyx/types/web_search/research_citation.py @@ -0,0 +1,20 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import Optional + +from ..._models import BaseModel + +__all__ = ["ResearchCitation"] + + +class ResearchCitation(BaseModel): + title: str + """Title of the source page.""" + + url: str + """Source URL.""" + + snippet: Optional[str] = None + """Relevant excerpt from the source (if available).""" diff --git a/src/telnyx/types/web_search/research_create_params.py b/src/telnyx/types/web_search/research_create_params.py new file mode 100644 index 000000000..2c4389d0e --- /dev/null +++ b/src/telnyx/types/web_search/research_create_params.py @@ -0,0 +1,25 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +__all__ = ["ResearchCreateParams"] + + +class ResearchCreateParams(TypedDict, total=False): + query: Required[str] + """The research question or topic.""" + + background: bool + """When `true`, the research runs asynchronously. + + The response returns a `task_id` immediately instead of waiting for the result. + Poll `GET /web_search/research/{task_id}` to check status. + """ + + max_sources: int + """Maximum number of sources to use.""" + + research_effort: Literal["lite", "standard", "deep"] + """Research depth level. `lite` is fastest, `deep` is most thorough.""" diff --git a/src/telnyx/types/web_search/research_create_response.py b/src/telnyx/types/web_search/research_create_response.py new file mode 100644 index 000000000..56dd98dfa --- /dev/null +++ b/src/telnyx/types/web_search/research_create_response.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Union, Optional +from typing_extensions import Literal, TypeAlias + +from ..._models import BaseModel +from .research_citation import ResearchCitation + +__all__ = ["ResearchCreateResponse", "Data", "DataResearchResponseSync", "DataResearchResponseAsync"] + + +class DataResearchResponseSync(BaseModel): + """Synchronous research response (when `background` is false or unset).""" + + answer: str + """The synthesized research answer.""" + + citations: Optional[List[ResearchCitation]] = None + """Sources cited in the answer.""" + + +class DataResearchResponseAsync(BaseModel): + """Asynchronous research response (when `background` is true).""" + + status: Literal["pending", "running", "completed", "failed"] + """Current status of the research task.""" + + task_id: str + """Unique identifier for the research task. Use this to poll the status.""" + + +Data: TypeAlias = Union[DataResearchResponseSync, DataResearchResponseAsync] + + +class ResearchCreateResponse(BaseModel): + data: Optional[Data] = None + """Synchronous research response (when `background` is false or unset).""" diff --git a/src/telnyx/types/web_search/research_retrieve_response.py b/src/telnyx/types/web_search/research_retrieve_response.py new file mode 100644 index 000000000..92c2a8abe --- /dev/null +++ b/src/telnyx/types/web_search/research_retrieve_response.py @@ -0,0 +1,32 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal + +from ..._models import BaseModel +from .research_citation import ResearchCitation + +__all__ = ["ResearchRetrieveResponse", "Data"] + + +class Data(BaseModel): + status: Literal["pending", "running", "completed", "failed"] + """Current status of the research task.""" + + task_id: str + """The research task identifier.""" + + answer: Optional[str] = None + """The synthesized research answer (present when status is `completed`).""" + + citations: Optional[List[ResearchCitation]] = None + """Sources cited in the answer (present when status is `completed`).""" + + error: Optional[str] = None + """Always present in poll responses; `null` unless the task failed.""" + + +class ResearchRetrieveResponse(BaseModel): + data: Optional[Data] = None diff --git a/src/telnyx/types/web_search_contents_params.py b/src/telnyx/types/web_search_contents_params.py new file mode 100644 index 000000000..80f20db0e --- /dev/null +++ b/src/telnyx/types/web_search_contents_params.py @@ -0,0 +1,30 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional +from typing_extensions import Literal, Required, TypedDict + +from .._types import SequenceNotStr + +__all__ = ["WebSearchContentsParams"] + + +class WebSearchContentsParams(TypedDict, total=False): + urls: Required[SequenceNotStr[str]] + """List of URLs to retrieve content from (max 20 for public API).""" + + crawl_timeout: int + """Timeout for crawling each URL, in seconds (1-60).""" + + formats: List[Literal["html", "markdown", "metadata"]] + """Content formats to return. + + If omitted, `html` and `metadata` are returned by default. Retrieval is + best-effort per URL: a format field appears only when that content could be + produced, and a freshly crawled page may also include `html` even when not + requested. + """ + + max_age: Optional[int] + """Maximum age of cached content in seconds. `null` means no limit.""" diff --git a/src/telnyx/types/web_search_contents_response.py b/src/telnyx/types/web_search_contents_response.py new file mode 100644 index 000000000..c7314d1ed --- /dev/null +++ b/src/telnyx/types/web_search_contents_response.py @@ -0,0 +1,61 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import TYPE_CHECKING, Dict, List, Optional + +from pydantic import Field as FieldInfo + +from .._models import BaseModel + +__all__ = ["WebSearchContentsResponse", "Data", "DataResult", "DataResultMetadata"] + + +class DataResultMetadata(BaseModel): + """Page metadata (if `metadata` format requested).""" + + favicon_url: Optional[str] = None + """Favicon URL (if available).""" + + site_name: Optional[str] = None + """Site name. Often empty.""" + + if TYPE_CHECKING: + # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a + # value to this field, so for compatibility we avoid doing it at runtime. + __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride] + + # Stub to indicate that arbitrary properties are accepted. + # To access properties that are not valid identifiers you can use `getattr`, e.g. + # `getattr(obj, '$type')` + def __getattr__(self, attr: str) -> object: ... + else: + __pydantic_extra__: Dict[str, object] + + +class DataResult(BaseModel): + url: str + """The source URL.""" + + html: Optional[str] = None + """ + Cleaned HTML content (if `html` format requested; may also be present on freshly + crawled pages). + """ + + markdown: Optional[str] = None + """Markdown content (if `markdown` format requested).""" + + metadata: Optional[DataResultMetadata] = None + """Page metadata (if `metadata` format requested).""" + + title: Optional[str] = None + """Page title (if available).""" + + +class Data(BaseModel): + results: Optional[List[DataResult]] = None + + +class WebSearchContentsResponse(BaseModel): + data: Optional[Data] = None diff --git a/src/telnyx/types/web_search_create_params.py b/src/telnyx/types/web_search_create_params.py new file mode 100644 index 000000000..a05dcf021 --- /dev/null +++ b/src/telnyx/types/web_search_create_params.py @@ -0,0 +1,39 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing_extensions import Literal, Required, TypedDict + +from .._types import SequenceNotStr + +__all__ = ["WebSearchCreateParams"] + + +class WebSearchCreateParams(TypedDict, total=False): + query: Required[str] + """The search query text.""" + + count: int + """Number of results to return (1-100).""" + + country: str + """Two-letter country code (ISO 3166-1 alpha-2) to bias results.""" + + exclude_domains: SequenceNotStr[str] + """Exclude results from these domains (bare hostnames, e.g. `pinterest.com`).""" + + freshness: str + """Time-based filter for results. Common values: `day`, `week`, `month`, `year`.""" + + include_domains: SequenceNotStr[str] + """Restrict results to these domains (bare hostnames, e.g. `arxiv.org`).""" + + livecrawl: bool + """When true, the provider crawls pages in real-time for fresh content. + + The boolean is translated to the provider's internal enum internally; callers + always pass `true` or `false`. + """ + + safesearch: Literal["off", "moderate", "strict"] + """Safe search filter level.""" diff --git a/src/telnyx/types/web_search_create_response.py b/src/telnyx/types/web_search_create_response.py new file mode 100644 index 000000000..629c6d4b9 --- /dev/null +++ b/src/telnyx/types/web_search_create_response.py @@ -0,0 +1,26 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional + +from .._models import BaseModel +from .web_search_result import WebSearchResult + +__all__ = ["WebSearchCreateResponse", "Data", "DataResults"] + + +class DataResults(BaseModel): + web: List[WebSearchResult] + """Web search results.""" + + news: Optional[List[WebSearchResult]] = None + """News search results. Present only when the query surfaces news results.""" + + +class Data(BaseModel): + results: Optional[DataResults] = None + + +class WebSearchCreateResponse(BaseModel): + data: Optional[Data] = None diff --git a/src/telnyx/types/web_search_result.py b/src/telnyx/types/web_search_result.py new file mode 100644 index 000000000..b5e541b0d --- /dev/null +++ b/src/telnyx/types/web_search_result.py @@ -0,0 +1,29 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +from typing import List, Optional + +from .._models import BaseModel + +__all__ = ["WebSearchResult"] + + +class WebSearchResult(BaseModel): + description: str + """Short description or excerpt.""" + + snippets: List[str] + """Relevant text snippets from the page.""" + + title: str + """Result title.""" + + url: str + """Result URL.""" + + favicon_url: Optional[str] = None + """Favicon URL (if available).""" + + thumbnail_url: Optional[str] = None + """Thumbnail image URL (if available).""" diff --git a/tests/api_resources/calls/test_actions.py b/tests/api_resources/calls/test_actions.py index 8dbd9fd94..c1e3c2e49 100644 --- a/tests/api_resources/calls/test_actions.py +++ b/tests/api_resources/calls/test_actions.py @@ -314,8 +314,8 @@ def test_method_answer_with_all_params(self, client: Telnyx) -> None: webhook_url="https://www.example.com/server-b/", webhook_url_method="POST", webhook_urls={ - "call.hangup": "https://www.example.com/webhooks/hangup", - "call.bridge": "https://www.example.com/webhooks/bridge", + "call.hangup": ["https://www.example.com/webhooks/hangup"], + "call.bridge": ["https://www.example.com/webhooks/bridge"], }, webhook_urls_method="POST", ) @@ -2900,8 +2900,8 @@ def test_method_transfer_with_all_params(self, client: Telnyx) -> None: webhook_url="https://www.example.com/server-b/", webhook_url_method="POST", webhook_urls={ - "call.answered": "https://www.example.com/webhooks/answered", - "call.hangup": "https://www.example.com/webhooks/hangup", + "call.answered": ["https://www.example.com/webhooks/answered"], + "call.hangup": ["https://www.example.com/webhooks/hangup"], }, webhook_urls_method="POST", ) @@ -3251,8 +3251,8 @@ async def test_method_answer_with_all_params(self, async_client: AsyncTelnyx) -> webhook_url="https://www.example.com/server-b/", webhook_url_method="POST", webhook_urls={ - "call.hangup": "https://www.example.com/webhooks/hangup", - "call.bridge": "https://www.example.com/webhooks/bridge", + "call.hangup": ["https://www.example.com/webhooks/hangup"], + "call.bridge": ["https://www.example.com/webhooks/bridge"], }, webhook_urls_method="POST", ) @@ -5837,8 +5837,8 @@ async def test_method_transfer_with_all_params(self, async_client: AsyncTelnyx) webhook_url="https://www.example.com/server-b/", webhook_url_method="POST", webhook_urls={ - "call.answered": "https://www.example.com/webhooks/answered", - "call.hangup": "https://www.example.com/webhooks/hangup", + "call.answered": ["https://www.example.com/webhooks/answered"], + "call.hangup": ["https://www.example.com/webhooks/hangup"], }, webhook_urls_method="POST", ) diff --git a/tests/api_resources/meeting_sessions/__init__.py b/tests/api_resources/meeting_sessions/__init__.py new file mode 100644 index 000000000..fd8019a9a --- /dev/null +++ b/tests/api_resources/meeting_sessions/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/meeting_sessions/test_actions.py b/tests/api_resources/meeting_sessions/test_actions.py new file mode 100644 index 000000000..eeb78bba8 --- /dev/null +++ b/tests/api_resources/meeting_sessions/test_actions.py @@ -0,0 +1,314 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types.meeting_sessions import ActionAcceptedResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestActions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_send_chat(self, client: Telnyx) -> None: + action = client.meeting_sessions.actions.send_chat( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="I will send the summary after this call.", + ) + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_send_chat(self, client: Telnyx) -> None: + response = client.meeting_sessions.actions.with_raw_response.send_chat( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="I will send the summary after this call.", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_send_chat(self, client: Telnyx) -> None: + with client.meeting_sessions.actions.with_streaming_response.send_chat( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="I will send the summary after this call.", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_send_chat(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.actions.with_raw_response.send_chat( + id="", + text="I will send the summary after this call.", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_speak(self, client: Telnyx) -> None: + action = client.meeting_sessions.actions.speak( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="Here are the three decisions from this call.", + ) + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_speak_with_all_params(self, client: Telnyx) -> None: + action = client.meeting_sessions.actions.speak( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="Here are the three decisions from this call.", + interrupt=False, + voice="x", + ) + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_speak(self, client: Telnyx) -> None: + response = client.meeting_sessions.actions.with_raw_response.speak( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="Here are the three decisions from this call.", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_speak(self, client: Telnyx) -> None: + with client.meeting_sessions.actions.with_streaming_response.speak( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="Here are the three decisions from this call.", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_speak(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.actions.with_raw_response.speak( + id="", + text="Here are the three decisions from this call.", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_stop_speaking(self, client: Telnyx) -> None: + action = client.meeting_sessions.actions.stop_speaking( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_stop_speaking(self, client: Telnyx) -> None: + response = client.meeting_sessions.actions.with_raw_response.stop_speaking( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_stop_speaking(self, client: Telnyx) -> None: + with client.meeting_sessions.actions.with_streaming_response.stop_speaking( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_stop_speaking(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.actions.with_raw_response.stop_speaking( + "", + ) + + +class TestAsyncActions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_send_chat(self, async_client: AsyncTelnyx) -> None: + action = await async_client.meeting_sessions.actions.send_chat( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="I will send the summary after this call.", + ) + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_send_chat(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.actions.with_raw_response.send_chat( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="I will send the summary after this call.", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = await response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_send_chat(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.actions.with_streaming_response.send_chat( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="I will send the summary after this call.", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = await response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_send_chat(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.actions.with_raw_response.send_chat( + id="", + text="I will send the summary after this call.", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_speak(self, async_client: AsyncTelnyx) -> None: + action = await async_client.meeting_sessions.actions.speak( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="Here are the three decisions from this call.", + ) + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_speak_with_all_params(self, async_client: AsyncTelnyx) -> None: + action = await async_client.meeting_sessions.actions.speak( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="Here are the three decisions from this call.", + interrupt=False, + voice="x", + ) + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_speak(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.actions.with_raw_response.speak( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="Here are the three decisions from this call.", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = await response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_speak(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.actions.with_streaming_response.speak( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + text="Here are the three decisions from this call.", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = await response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_speak(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.actions.with_raw_response.speak( + id="", + text="Here are the three decisions from this call.", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_stop_speaking(self, async_client: AsyncTelnyx) -> None: + action = await async_client.meeting_sessions.actions.stop_speaking( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_stop_speaking(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.actions.with_raw_response.stop_speaking( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = await response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_stop_speaking(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.actions.with_streaming_response.stop_speaking( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = await response.parse() + assert_matches_type(ActionAcceptedResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_stop_speaking(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.actions.with_raw_response.stop_speaking( + "", + ) diff --git a/tests/api_resources/meeting_sessions/test_artifacts.py b/tests/api_resources/meeting_sessions/test_artifacts.py new file mode 100644 index 000000000..fab8c08b9 --- /dev/null +++ b/tests/api_resources/meeting_sessions/test_artifacts.py @@ -0,0 +1,304 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types.meeting_sessions import ArtifactListResponse, MeetingSessionArtifactResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestArtifacts: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Telnyx) -> None: + artifact = client.meeting_sessions.artifacts.create( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + type="summary", + ) + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Telnyx) -> None: + response = client.meeting_sessions.artifacts.with_raw_response.create( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + type="summary", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + artifact = response.parse() + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Telnyx) -> None: + with client.meeting_sessions.artifacts.with_streaming_response.create( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + type="summary", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + artifact = response.parse() + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_create(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.artifacts.with_raw_response.create( + id="", + type="summary", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Telnyx) -> None: + artifact = client.meeting_sessions.artifacts.retrieve( + artifact_id="mtgart_b2c3d4e5-f6a7-8901-bcde-f23456789012", + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Telnyx) -> None: + response = client.meeting_sessions.artifacts.with_raw_response.retrieve( + artifact_id="mtgart_b2c3d4e5-f6a7-8901-bcde-f23456789012", + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + artifact = response.parse() + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Telnyx) -> None: + with client.meeting_sessions.artifacts.with_streaming_response.retrieve( + artifact_id="mtgart_b2c3d4e5-f6a7-8901-bcde-f23456789012", + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + artifact = response.parse() + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.artifacts.with_raw_response.retrieve( + artifact_id="mtgart_b2c3d4e5-f6a7-8901-bcde-f23456789012", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `artifact_id` but received ''"): + client.meeting_sessions.artifacts.with_raw_response.retrieve( + artifact_id="", + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Telnyx) -> None: + artifact = client.meeting_sessions.artifacts.list( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(ArtifactListResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Telnyx) -> None: + response = client.meeting_sessions.artifacts.with_raw_response.list( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + artifact = response.parse() + assert_matches_type(ArtifactListResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Telnyx) -> None: + with client.meeting_sessions.artifacts.with_streaming_response.list( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + artifact = response.parse() + assert_matches_type(ArtifactListResponse, artifact, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_list(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.artifacts.with_raw_response.list( + "", + ) + + +class TestAsyncArtifacts: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncTelnyx) -> None: + artifact = await async_client.meeting_sessions.artifacts.create( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + type="summary", + ) + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.artifacts.with_raw_response.create( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + type="summary", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + artifact = await response.parse() + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.artifacts.with_streaming_response.create( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + type="summary", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + artifact = await response.parse() + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_create(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.artifacts.with_raw_response.create( + id="", + type="summary", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncTelnyx) -> None: + artifact = await async_client.meeting_sessions.artifacts.retrieve( + artifact_id="mtgart_b2c3d4e5-f6a7-8901-bcde-f23456789012", + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.artifacts.with_raw_response.retrieve( + artifact_id="mtgart_b2c3d4e5-f6a7-8901-bcde-f23456789012", + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + artifact = await response.parse() + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.artifacts.with_streaming_response.retrieve( + artifact_id="mtgart_b2c3d4e5-f6a7-8901-bcde-f23456789012", + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + artifact = await response.parse() + assert_matches_type(MeetingSessionArtifactResponse, artifact, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.artifacts.with_raw_response.retrieve( + artifact_id="mtgart_b2c3d4e5-f6a7-8901-bcde-f23456789012", + id="", + ) + + with pytest.raises(ValueError, match=r"Expected a non-empty value for `artifact_id` but received ''"): + await async_client.meeting_sessions.artifacts.with_raw_response.retrieve( + artifact_id="", + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncTelnyx) -> None: + artifact = await async_client.meeting_sessions.artifacts.list( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(ArtifactListResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.artifacts.with_raw_response.list( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + artifact = await response.parse() + assert_matches_type(ArtifactListResponse, artifact, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.artifacts.with_streaming_response.list( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + artifact = await response.parse() + assert_matches_type(ArtifactListResponse, artifact, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_list(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.artifacts.with_raw_response.list( + "", + ) diff --git a/tests/api_resources/phone_numbers/test_voicemail.py b/tests/api_resources/phone_numbers/test_voicemail.py index 39ebf2e4f..5aabf65de 100644 --- a/tests/api_resources/phone_numbers/test_voicemail.py +++ b/tests/api_resources/phone_numbers/test_voicemail.py @@ -35,6 +35,10 @@ def test_method_create_with_all_params(self, client: Telnyx) -> None: voicemail = client.phone_numbers.voicemail.create( phone_number_id="123455678900", enabled=True, + greeting={ + "media_name": "my_voicemail_greeting", + "mode": "custom_greeting", + }, pin="1234", ) assert_matches_type(VoicemailCreateResponse, voicemail, path=["response"]) @@ -129,6 +133,10 @@ def test_method_update_with_all_params(self, client: Telnyx) -> None: voicemail = client.phone_numbers.voicemail.update( phone_number_id="123455678900", enabled=True, + greeting={ + "media_name": "my_voicemail_greeting", + "mode": "custom_greeting", + }, pin="1234", ) assert_matches_type(VoicemailUpdateResponse, voicemail, path=["response"]) @@ -187,6 +195,10 @@ async def test_method_create_with_all_params(self, async_client: AsyncTelnyx) -> voicemail = await async_client.phone_numbers.voicemail.create( phone_number_id="123455678900", enabled=True, + greeting={ + "media_name": "my_voicemail_greeting", + "mode": "custom_greeting", + }, pin="1234", ) assert_matches_type(VoicemailCreateResponse, voicemail, path=["response"]) @@ -281,6 +293,10 @@ async def test_method_update_with_all_params(self, async_client: AsyncTelnyx) -> voicemail = await async_client.phone_numbers.voicemail.update( phone_number_id="123455678900", enabled=True, + greeting={ + "media_name": "my_voicemail_greeting", + "mode": "custom_greeting", + }, pin="1234", ) assert_matches_type(VoicemailUpdateResponse, voicemail, path=["response"]) diff --git a/tests/api_resources/sim_cards/test_actions.py b/tests/api_resources/sim_cards/test_actions.py index 29d7e7adb..1ad77900a 100644 --- a/tests/api_resources/sim_cards/test_actions.py +++ b/tests/api_resources/sim_cards/test_actions.py @@ -16,7 +16,9 @@ WirelessSimCardAction, ActionRetrieveResponse, ActionSetStandbyResponse, + ActionEnableVoiceResponse, ActionSetPublicIPResponse, + ActionDisableVoiceResponse, ActionRemovePublicIPResponse, ActionBulkEnableVoiceResponse, ActionBulkDisableVoiceResponse, @@ -157,6 +159,15 @@ def test_method_bulk_enable_voice(self, client: Telnyx) -> None: ) assert_matches_type(ActionBulkEnableVoiceResponse, action, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_bulk_enable_voice_with_all_params(self, client: Telnyx) -> None: + action = client.sim_cards.actions.bulk_enable_voice( + sim_card_group_id="6b14e151-8493-4fa1-8664-1cc4e6d14158", + connection_id="123456789", + ) + assert_matches_type(ActionBulkEnableVoiceResponse, action, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_raw_response_bulk_enable_voice(self, client: Telnyx) -> None: @@ -259,6 +270,48 @@ def test_path_params_disable(self, client: Telnyx) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_disable_voice(self, client: Telnyx) -> None: + action = client.sim_cards.actions.disable_voice( + "6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) + assert_matches_type(ActionDisableVoiceResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_disable_voice(self, client: Telnyx) -> None: + response = client.sim_cards.actions.with_raw_response.disable_voice( + "6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = response.parse() + assert_matches_type(ActionDisableVoiceResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_disable_voice(self, client: Telnyx) -> None: + with client.sim_cards.actions.with_streaming_response.disable_voice( + "6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = response.parse() + assert_matches_type(ActionDisableVoiceResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_disable_voice(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.sim_cards.actions.with_raw_response.disable_voice( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_enable(self, client: Telnyx) -> None: @@ -301,6 +354,57 @@ def test_path_params_enable(self, client: Telnyx) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_enable_voice(self, client: Telnyx) -> None: + action = client.sim_cards.actions.enable_voice( + id="6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) + assert_matches_type(ActionEnableVoiceResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_enable_voice_with_all_params(self, client: Telnyx) -> None: + action = client.sim_cards.actions.enable_voice( + id="6a09cdc3-8948-47f0-aa62-74ac943d6c58", + connection_id="123456789", + ) + assert_matches_type(ActionEnableVoiceResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_enable_voice(self, client: Telnyx) -> None: + response = client.sim_cards.actions.with_raw_response.enable_voice( + id="6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = response.parse() + assert_matches_type(ActionEnableVoiceResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_enable_voice(self, client: Telnyx) -> None: + with client.sim_cards.actions.with_streaming_response.enable_voice( + id="6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = response.parse() + assert_matches_type(ActionEnableVoiceResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_enable_voice(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.sim_cards.actions.with_raw_response.enable_voice( + id="", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_method_remove_public_ip(self, client: Telnyx) -> None: @@ -605,6 +709,15 @@ async def test_method_bulk_enable_voice(self, async_client: AsyncTelnyx) -> None ) assert_matches_type(ActionBulkEnableVoiceResponse, action, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_bulk_enable_voice_with_all_params(self, async_client: AsyncTelnyx) -> None: + action = await async_client.sim_cards.actions.bulk_enable_voice( + sim_card_group_id="6b14e151-8493-4fa1-8664-1cc4e6d14158", + connection_id="123456789", + ) + assert_matches_type(ActionBulkEnableVoiceResponse, action, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_raw_response_bulk_enable_voice(self, async_client: AsyncTelnyx) -> None: @@ -707,6 +820,48 @@ async def test_path_params_disable(self, async_client: AsyncTelnyx) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_disable_voice(self, async_client: AsyncTelnyx) -> None: + action = await async_client.sim_cards.actions.disable_voice( + "6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) + assert_matches_type(ActionDisableVoiceResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_disable_voice(self, async_client: AsyncTelnyx) -> None: + response = await async_client.sim_cards.actions.with_raw_response.disable_voice( + "6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = await response.parse() + assert_matches_type(ActionDisableVoiceResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_disable_voice(self, async_client: AsyncTelnyx) -> None: + async with async_client.sim_cards.actions.with_streaming_response.disable_voice( + "6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = await response.parse() + assert_matches_type(ActionDisableVoiceResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_disable_voice(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.sim_cards.actions.with_raw_response.disable_voice( + "", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_enable(self, async_client: AsyncTelnyx) -> None: @@ -749,6 +904,57 @@ async def test_path_params_enable(self, async_client: AsyncTelnyx) -> None: "", ) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_enable_voice(self, async_client: AsyncTelnyx) -> None: + action = await async_client.sim_cards.actions.enable_voice( + id="6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) + assert_matches_type(ActionEnableVoiceResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_enable_voice_with_all_params(self, async_client: AsyncTelnyx) -> None: + action = await async_client.sim_cards.actions.enable_voice( + id="6a09cdc3-8948-47f0-aa62-74ac943d6c58", + connection_id="123456789", + ) + assert_matches_type(ActionEnableVoiceResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_enable_voice(self, async_client: AsyncTelnyx) -> None: + response = await async_client.sim_cards.actions.with_raw_response.enable_voice( + id="6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = await response.parse() + assert_matches_type(ActionEnableVoiceResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_enable_voice(self, async_client: AsyncTelnyx) -> None: + async with async_client.sim_cards.actions.with_streaming_response.enable_voice( + id="6a09cdc3-8948-47f0-aa62-74ac943d6c58", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = await response.parse() + assert_matches_type(ActionEnableVoiceResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_enable_voice(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.sim_cards.actions.with_raw_response.enable_voice( + id="", + ) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_method_remove_public_ip(self, async_client: AsyncTelnyx) -> None: diff --git a/tests/api_resources/storage/sqldbs/__init__.py b/tests/api_resources/storage/sqldbs/__init__.py new file mode 100644 index 000000000..fd8019a9a --- /dev/null +++ b/tests/api_resources/storage/sqldbs/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/storage/sqldbs/test_actions.py b/tests/api_resources/storage/sqldbs/test_actions.py new file mode 100644 index 000000000..015c51ae9 --- /dev/null +++ b/tests/api_resources/storage/sqldbs/test_actions.py @@ -0,0 +1,136 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types.storage.sqldbs import ActionQueryResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestActions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_query(self, client: Telnyx) -> None: + action = client.storage.sqldbs.actions.query( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + sql="SELECT * FROM users WHERE name = ?", + ) + assert_matches_type(ActionQueryResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_query_with_all_params(self, client: Telnyx) -> None: + action = client.storage.sqldbs.actions.query( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + sql="SELECT * FROM users WHERE name = ?", + params=["alice"], + ) + assert_matches_type(ActionQueryResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_query(self, client: Telnyx) -> None: + response = client.storage.sqldbs.actions.with_raw_response.query( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + sql="SELECT * FROM users WHERE name = ?", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = response.parse() + assert_matches_type(ActionQueryResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_query(self, client: Telnyx) -> None: + with client.storage.sqldbs.actions.with_streaming_response.query( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + sql="SELECT * FROM users WHERE name = ?", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = response.parse() + assert_matches_type(ActionQueryResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_query(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.storage.sqldbs.actions.with_raw_response.query( + id="", + sql="SELECT * FROM users WHERE name = ?", + ) + + +class TestAsyncActions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_query(self, async_client: AsyncTelnyx) -> None: + action = await async_client.storage.sqldbs.actions.query( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + sql="SELECT * FROM users WHERE name = ?", + ) + assert_matches_type(ActionQueryResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_query_with_all_params(self, async_client: AsyncTelnyx) -> None: + action = await async_client.storage.sqldbs.actions.query( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + sql="SELECT * FROM users WHERE name = ?", + params=["alice"], + ) + assert_matches_type(ActionQueryResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_query(self, async_client: AsyncTelnyx) -> None: + response = await async_client.storage.sqldbs.actions.with_raw_response.query( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + sql="SELECT * FROM users WHERE name = ?", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + action = await response.parse() + assert_matches_type(ActionQueryResponse, action, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_query(self, async_client: AsyncTelnyx) -> None: + async with async_client.storage.sqldbs.actions.with_streaming_response.query( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + sql="SELECT * FROM users WHERE name = ?", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + action = await response.parse() + assert_matches_type(ActionQueryResponse, action, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_query(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.storage.sqldbs.actions.with_raw_response.query( + id="", + sql="SELECT * FROM users WHERE name = ?", + ) diff --git a/tests/api_resources/storage/test_sqldbs.py b/tests/api_resources/storage/test_sqldbs.py new file mode 100644 index 000000000..d9b8e9da5 --- /dev/null +++ b/tests/api_resources/storage/test_sqldbs.py @@ -0,0 +1,362 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.pagination import SyncDefaultFlatPagination, AsyncDefaultFlatPagination +from telnyx.types.storage import ( + SqlDatabase, + SqlDatabaseResponseWrapper, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestSqldbs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Telnyx) -> None: + sqldb = client.storage.sqldbs.create( + name="my-database", + ) + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Telnyx) -> None: + response = client.storage.sqldbs.with_raw_response.create( + name="my-database", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sqldb = response.parse() + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Telnyx) -> None: + with client.storage.sqldbs.with_streaming_response.create( + name="my-database", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sqldb = response.parse() + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Telnyx) -> None: + sqldb = client.storage.sqldbs.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Telnyx) -> None: + response = client.storage.sqldbs.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sqldb = response.parse() + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Telnyx) -> None: + with client.storage.sqldbs.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sqldb = response.parse() + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.storage.sqldbs.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Telnyx) -> None: + sqldb = client.storage.sqldbs.list() + assert_matches_type(SyncDefaultFlatPagination[SqlDatabase], sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Telnyx) -> None: + sqldb = client.storage.sqldbs.list( + filter_name="filter[name]", + filter_status="pending", + page_number=1, + page_size=1, + sort="name", + ) + assert_matches_type(SyncDefaultFlatPagination[SqlDatabase], sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Telnyx) -> None: + response = client.storage.sqldbs.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sqldb = response.parse() + assert_matches_type(SyncDefaultFlatPagination[SqlDatabase], sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Telnyx) -> None: + with client.storage.sqldbs.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sqldb = response.parse() + assert_matches_type(SyncDefaultFlatPagination[SqlDatabase], sqldb, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete(self, client: Telnyx) -> None: + sqldb = client.storage.sqldbs.delete( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert sqldb is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete_with_all_params(self, client: Telnyx) -> None: + sqldb = client.storage.sqldbs.delete( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + force=True, + ) + assert sqldb is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Telnyx) -> None: + response = client.storage.sqldbs.with_raw_response.delete( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sqldb = response.parse() + assert sqldb is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Telnyx) -> None: + with client.storage.sqldbs.with_streaming_response.delete( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sqldb = response.parse() + assert sqldb is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_delete(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.storage.sqldbs.with_raw_response.delete( + id="", + ) + + +class TestAsyncSqldbs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncTelnyx) -> None: + sqldb = await async_client.storage.sqldbs.create( + name="my-database", + ) + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncTelnyx) -> None: + response = await async_client.storage.sqldbs.with_raw_response.create( + name="my-database", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sqldb = await response.parse() + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncTelnyx) -> None: + async with async_client.storage.sqldbs.with_streaming_response.create( + name="my-database", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sqldb = await response.parse() + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncTelnyx) -> None: + sqldb = await async_client.storage.sqldbs.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncTelnyx) -> None: + response = await async_client.storage.sqldbs.with_raw_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sqldb = await response.parse() + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncTelnyx) -> None: + async with async_client.storage.sqldbs.with_streaming_response.retrieve( + "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sqldb = await response.parse() + assert_matches_type(SqlDatabaseResponseWrapper, sqldb, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.storage.sqldbs.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncTelnyx) -> None: + sqldb = await async_client.storage.sqldbs.list() + assert_matches_type(AsyncDefaultFlatPagination[SqlDatabase], sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncTelnyx) -> None: + sqldb = await async_client.storage.sqldbs.list( + filter_name="filter[name]", + filter_status="pending", + page_number=1, + page_size=1, + sort="name", + ) + assert_matches_type(AsyncDefaultFlatPagination[SqlDatabase], sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncTelnyx) -> None: + response = await async_client.storage.sqldbs.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sqldb = await response.parse() + assert_matches_type(AsyncDefaultFlatPagination[SqlDatabase], sqldb, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncTelnyx) -> None: + async with async_client.storage.sqldbs.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sqldb = await response.parse() + assert_matches_type(AsyncDefaultFlatPagination[SqlDatabase], sqldb, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncTelnyx) -> None: + sqldb = await async_client.storage.sqldbs.delete( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert sqldb is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete_with_all_params(self, async_client: AsyncTelnyx) -> None: + sqldb = await async_client.storage.sqldbs.delete( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + force=True, + ) + assert sqldb is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncTelnyx) -> None: + response = await async_client.storage.sqldbs.with_raw_response.delete( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + sqldb = await response.parse() + assert sqldb is None + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncTelnyx) -> None: + async with async_client.storage.sqldbs.with_streaming_response.delete( + id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + sqldb = await response.parse() + assert sqldb is None + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_delete(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.storage.sqldbs.with_raw_response.delete( + id="", + ) diff --git a/tests/api_resources/test_calls.py b/tests/api_resources/test_calls.py index 2f4550748..5acb963ca 100644 --- a/tests/api_resources/test_calls.py +++ b/tests/api_resources/test_calls.py @@ -285,8 +285,8 @@ def test_method_dial_with_all_params(self, client: Telnyx) -> None: webhook_url="https://www.example.com/server-b/", webhook_url_method="POST", webhook_urls={ - "call.hangup": "https://www.example.com/webhooks/hangup", - "call.bridge": "https://www.example.com/webhooks/bridge", + "call.hangup": ["https://www.example.com/webhooks/hangup"], + "call.bridge": ["https://www.example.com/webhooks/bridge"], }, webhook_urls_method="POST", ) @@ -635,8 +635,8 @@ async def test_method_dial_with_all_params(self, async_client: AsyncTelnyx) -> N webhook_url="https://www.example.com/server-b/", webhook_url_method="POST", webhook_urls={ - "call.hangup": "https://www.example.com/webhooks/hangup", - "call.bridge": "https://www.example.com/webhooks/bridge", + "call.hangup": ["https://www.example.com/webhooks/hangup"], + "call.bridge": ["https://www.example.com/webhooks/bridge"], }, webhook_urls_method="POST", ) diff --git a/tests/api_resources/test_meeting_sessions.py b/tests/api_resources/test_meeting_sessions.py new file mode 100644 index 000000000..d0ea5bf4c --- /dev/null +++ b/tests/api_resources/test_meeting_sessions.py @@ -0,0 +1,888 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types import ( + MeetingSessionResponse, + MeetingSessionListResponse, + MeetingSessionRetrieveEventsResponse, + MeetingSessionRetrieveRecordingsResponse, + MeetingSessionRetrieveTranscriptResponse, + MeetingSessionDeleteRecordingMediaResponse, +) +from telnyx._utils import parse_datetime + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestMeetingSessions: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.create( + meeting_url="https://zoom.us/j/1234567890", + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.create( + meeting_url="https://zoom.us/j/1234567890", + assistant={ + "id": "asst_fake-uuid-1234", + "call_control_connection_id": "conn-fake-abcdef", + "from": "+12025550199", + "loopback_sip_uri": "sip:loopback@example.invalid", + "audio_gate": "half_duplex", + }, + avatar={ + "api_key": "fake_avatar_api_key_do_not_use", + "avatar_id": "avatar_fake-001", + "provider": "anam", + }, + barge_in=True, + bot_name="Notetaker", + camera_image={ + "base64_data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/wAALCAACAAIBAREA/8QAFAABAAAAAAAAAAAAAAAAAAAACP/EAB4QAAAEBwAAAAAAAAAAAAAAAAAEBgcCFic1RVNi/9oACAEBAAA/AH8hGJbWR09TxKW4vhC2qHgf/9k=", + "format": "jpeg", + }, + idempotency_key="x", + join_at=parse_datetime("2019-12-27T18:11:19.117Z"), + metadata={"foo": "bar"}, + speak_on_enter="x", + summarize_on_end=True, + voice="x", + webhook_url="https://example.com", + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Telnyx) -> None: + response = client.meeting_sessions.with_raw_response.create( + meeting_url="https://zoom.us/j/1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Telnyx) -> None: + with client.meeting_sessions.with_streaming_response.create( + meeting_url="https://zoom.us/j/1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.retrieve( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Telnyx) -> None: + response = client.meeting_sessions.with_raw_response.retrieve( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Telnyx) -> None: + with client.meeting_sessions.with_streaming_response.retrieve( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_update(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.update( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_update_with_all_params(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.update( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + bot_name="x", + join_at=parse_datetime("2026-08-05T17:00:00Z"), + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_update(self, client: Telnyx) -> None: + response = client.meeting_sessions.with_raw_response.update( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_update(self, client: Telnyx) -> None: + with client.meeting_sessions.with_streaming_response.update( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_update(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.with_raw_response.update( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.list() + assert_matches_type(MeetingSessionListResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_list_with_all_params(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.list( + status="scheduled", + ) + assert_matches_type(MeetingSessionListResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_list(self, client: Telnyx) -> None: + response = client.meeting_sessions.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = response.parse() + assert_matches_type(MeetingSessionListResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_list(self, client: Telnyx) -> None: + with client.meeting_sessions.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = response.parse() + assert_matches_type(MeetingSessionListResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.delete( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete(self, client: Telnyx) -> None: + response = client.meeting_sessions.with_raw_response.delete( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete(self, client: Telnyx) -> None: + with client.meeting_sessions.with_streaming_response.delete( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_delete(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.with_raw_response.delete( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_delete_recording_media(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.delete_recording_media( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionDeleteRecordingMediaResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_delete_recording_media(self, client: Telnyx) -> None: + response = client.meeting_sessions.with_raw_response.delete_recording_media( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = response.parse() + assert_matches_type(MeetingSessionDeleteRecordingMediaResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_delete_recording_media(self, client: Telnyx) -> None: + with client.meeting_sessions.with_streaming_response.delete_recording_media( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = response.parse() + assert_matches_type(MeetingSessionDeleteRecordingMediaResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_delete_recording_media(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.with_raw_response.delete_recording_media( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve_events(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.retrieve_events( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionRetrieveEventsResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve_events_with_all_params(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.retrieve_events( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + after=0, + limit=1, + ) + assert_matches_type(MeetingSessionRetrieveEventsResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve_events(self, client: Telnyx) -> None: + response = client.meeting_sessions.with_raw_response.retrieve_events( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = response.parse() + assert_matches_type(MeetingSessionRetrieveEventsResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve_events(self, client: Telnyx) -> None: + with client.meeting_sessions.with_streaming_response.retrieve_events( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = response.parse() + assert_matches_type(MeetingSessionRetrieveEventsResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve_events(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.with_raw_response.retrieve_events( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve_recordings(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.retrieve_recordings( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionRetrieveRecordingsResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve_recordings(self, client: Telnyx) -> None: + response = client.meeting_sessions.with_raw_response.retrieve_recordings( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = response.parse() + assert_matches_type(MeetingSessionRetrieveRecordingsResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve_recordings(self, client: Telnyx) -> None: + with client.meeting_sessions.with_streaming_response.retrieve_recordings( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = response.parse() + assert_matches_type(MeetingSessionRetrieveRecordingsResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve_recordings(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.with_raw_response.retrieve_recordings( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve_transcript(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.retrieve_transcript( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionRetrieveTranscriptResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve_transcript_with_all_params(self, client: Telnyx) -> None: + meeting_session = client.meeting_sessions.retrieve_transcript( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + after=0, + limit=1, + wait_seconds=0, + ) + assert_matches_type(MeetingSessionRetrieveTranscriptResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve_transcript(self, client: Telnyx) -> None: + response = client.meeting_sessions.with_raw_response.retrieve_transcript( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = response.parse() + assert_matches_type(MeetingSessionRetrieveTranscriptResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve_transcript(self, client: Telnyx) -> None: + with client.meeting_sessions.with_streaming_response.retrieve_transcript( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = response.parse() + assert_matches_type(MeetingSessionRetrieveTranscriptResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve_transcript(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + client.meeting_sessions.with_raw_response.retrieve_transcript( + id="", + ) + + +class TestAsyncMeetingSessions: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.create( + meeting_url="https://zoom.us/j/1234567890", + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.create( + meeting_url="https://zoom.us/j/1234567890", + assistant={ + "id": "asst_fake-uuid-1234", + "call_control_connection_id": "conn-fake-abcdef", + "from": "+12025550199", + "loopback_sip_uri": "sip:loopback@example.invalid", + "audio_gate": "half_duplex", + }, + avatar={ + "api_key": "fake_avatar_api_key_do_not_use", + "avatar_id": "avatar_fake-001", + "provider": "anam", + }, + barge_in=True, + bot_name="Notetaker", + camera_image={ + "base64_data": "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/wAALCAACAAIBAREA/8QAFAABAAAAAAAAAAAAAAAAAAAACP/EAB4QAAAEBwAAAAAAAAAAAAAAAAAEBgcCFic1RVNi/9oACAEBAAA/AH8hGJbWR09TxKW4vhC2qHgf/9k=", + "format": "jpeg", + }, + idempotency_key="x", + join_at=parse_datetime("2019-12-27T18:11:19.117Z"), + metadata={"foo": "bar"}, + speak_on_enter="x", + summarize_on_end=True, + voice="x", + webhook_url="https://example.com", + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.with_raw_response.create( + meeting_url="https://zoom.us/j/1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = await response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.with_streaming_response.create( + meeting_url="https://zoom.us/j/1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = await response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.retrieve( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.with_raw_response.retrieve( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = await response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.with_streaming_response.retrieve( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = await response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.with_raw_response.retrieve( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_update(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.update( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_update_with_all_params(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.update( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + bot_name="x", + join_at=parse_datetime("2026-08-05T17:00:00Z"), + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_update(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.with_raw_response.update( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = await response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_update(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.with_streaming_response.update( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = await response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_update(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.with_raw_response.update( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.list() + assert_matches_type(MeetingSessionListResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.list( + status="scheduled", + ) + assert_matches_type(MeetingSessionListResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_list(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.with_raw_response.list() + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = await response.parse() + assert_matches_type(MeetingSessionListResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_list(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.with_streaming_response.list() as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = await response.parse() + assert_matches_type(MeetingSessionListResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.delete( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.with_raw_response.delete( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = await response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.with_streaming_response.delete( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = await response.parse() + assert_matches_type(MeetingSessionResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_delete(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.with_raw_response.delete( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_delete_recording_media(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.delete_recording_media( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionDeleteRecordingMediaResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_delete_recording_media(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.with_raw_response.delete_recording_media( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = await response.parse() + assert_matches_type(MeetingSessionDeleteRecordingMediaResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_delete_recording_media(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.with_streaming_response.delete_recording_media( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = await response.parse() + assert_matches_type(MeetingSessionDeleteRecordingMediaResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_delete_recording_media(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.with_raw_response.delete_recording_media( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve_events(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.retrieve_events( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionRetrieveEventsResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve_events_with_all_params(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.retrieve_events( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + after=0, + limit=1, + ) + assert_matches_type(MeetingSessionRetrieveEventsResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve_events(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.with_raw_response.retrieve_events( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = await response.parse() + assert_matches_type(MeetingSessionRetrieveEventsResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve_events(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.with_streaming_response.retrieve_events( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = await response.parse() + assert_matches_type(MeetingSessionRetrieveEventsResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve_events(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.with_raw_response.retrieve_events( + id="", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve_recordings(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.retrieve_recordings( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionRetrieveRecordingsResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve_recordings(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.with_raw_response.retrieve_recordings( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = await response.parse() + assert_matches_type(MeetingSessionRetrieveRecordingsResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve_recordings(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.with_streaming_response.retrieve_recordings( + "mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = await response.parse() + assert_matches_type(MeetingSessionRetrieveRecordingsResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve_recordings(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.with_raw_response.retrieve_recordings( + "", + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve_transcript(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.retrieve_transcript( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + assert_matches_type(MeetingSessionRetrieveTranscriptResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve_transcript_with_all_params(self, async_client: AsyncTelnyx) -> None: + meeting_session = await async_client.meeting_sessions.retrieve_transcript( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + after=0, + limit=1, + wait_seconds=0, + ) + assert_matches_type(MeetingSessionRetrieveTranscriptResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve_transcript(self, async_client: AsyncTelnyx) -> None: + response = await async_client.meeting_sessions.with_raw_response.retrieve_transcript( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + meeting_session = await response.parse() + assert_matches_type(MeetingSessionRetrieveTranscriptResponse, meeting_session, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve_transcript(self, async_client: AsyncTelnyx) -> None: + async with async_client.meeting_sessions.with_streaming_response.retrieve_transcript( + id="mtgsess_a1b2c3d4-e5f6-7890-abcd-ef1234567890", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + meeting_session = await response.parse() + assert_matches_type(MeetingSessionRetrieveTranscriptResponse, meeting_session, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve_transcript(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): + await async_client.meeting_sessions.with_raw_response.retrieve_transcript( + id="", + ) diff --git a/tests/api_resources/test_web_search.py b/tests/api_resources/test_web_search.py new file mode 100644 index 000000000..644e9f33c --- /dev/null +++ b/tests/api_resources/test_web_search.py @@ -0,0 +1,215 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types import ( + WebSearchCreateResponse, + WebSearchContentsResponse, +) + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestWebSearch: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Telnyx) -> None: + web_search = client.web_search.create( + query="latest AI agent frameworks", + ) + assert_matches_type(WebSearchCreateResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Telnyx) -> None: + web_search = client.web_search.create( + query="latest AI agent frameworks", + count=10, + country="US", + exclude_domains=["pinterest.com"], + freshness="week", + include_domains=["arxiv.org", "github.com"], + livecrawl=False, + safesearch="moderate", + ) + assert_matches_type(WebSearchCreateResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Telnyx) -> None: + response = client.web_search.with_raw_response.create( + query="latest AI agent frameworks", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + web_search = response.parse() + assert_matches_type(WebSearchCreateResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Telnyx) -> None: + with client.web_search.with_streaming_response.create( + query="latest AI agent frameworks", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + web_search = response.parse() + assert_matches_type(WebSearchCreateResponse, web_search, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_contents(self, client: Telnyx) -> None: + web_search = client.web_search.contents( + urls=["https://en.wikipedia.org/wiki/Artificial_intelligence"], + ) + assert_matches_type(WebSearchContentsResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_contents_with_all_params(self, client: Telnyx) -> None: + web_search = client.web_search.contents( + urls=["https://en.wikipedia.org/wiki/Artificial_intelligence"], + crawl_timeout=10, + formats=["markdown", "metadata"], + max_age=None, + ) + assert_matches_type(WebSearchContentsResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_contents(self, client: Telnyx) -> None: + response = client.web_search.with_raw_response.contents( + urls=["https://en.wikipedia.org/wiki/Artificial_intelligence"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + web_search = response.parse() + assert_matches_type(WebSearchContentsResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_contents(self, client: Telnyx) -> None: + with client.web_search.with_streaming_response.contents( + urls=["https://en.wikipedia.org/wiki/Artificial_intelligence"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + web_search = response.parse() + assert_matches_type(WebSearchContentsResponse, web_search, path=["response"]) + + assert cast(Any, response.is_closed) is True + + +class TestAsyncWebSearch: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncTelnyx) -> None: + web_search = await async_client.web_search.create( + query="latest AI agent frameworks", + ) + assert_matches_type(WebSearchCreateResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncTelnyx) -> None: + web_search = await async_client.web_search.create( + query="latest AI agent frameworks", + count=10, + country="US", + exclude_domains=["pinterest.com"], + freshness="week", + include_domains=["arxiv.org", "github.com"], + livecrawl=False, + safesearch="moderate", + ) + assert_matches_type(WebSearchCreateResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncTelnyx) -> None: + response = await async_client.web_search.with_raw_response.create( + query="latest AI agent frameworks", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + web_search = await response.parse() + assert_matches_type(WebSearchCreateResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncTelnyx) -> None: + async with async_client.web_search.with_streaming_response.create( + query="latest AI agent frameworks", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + web_search = await response.parse() + assert_matches_type(WebSearchCreateResponse, web_search, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_contents(self, async_client: AsyncTelnyx) -> None: + web_search = await async_client.web_search.contents( + urls=["https://en.wikipedia.org/wiki/Artificial_intelligence"], + ) + assert_matches_type(WebSearchContentsResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_contents_with_all_params(self, async_client: AsyncTelnyx) -> None: + web_search = await async_client.web_search.contents( + urls=["https://en.wikipedia.org/wiki/Artificial_intelligence"], + crawl_timeout=10, + formats=["markdown", "metadata"], + max_age=None, + ) + assert_matches_type(WebSearchContentsResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_contents(self, async_client: AsyncTelnyx) -> None: + response = await async_client.web_search.with_raw_response.contents( + urls=["https://en.wikipedia.org/wiki/Artificial_intelligence"], + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + web_search = await response.parse() + assert_matches_type(WebSearchContentsResponse, web_search, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_contents(self, async_client: AsyncTelnyx) -> None: + async with async_client.web_search.with_streaming_response.contents( + urls=["https://en.wikipedia.org/wiki/Artificial_intelligence"], + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + web_search = await response.parse() + assert_matches_type(WebSearchContentsResponse, web_search, path=["response"]) + + assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/web_search/__init__.py b/tests/api_resources/web_search/__init__.py new file mode 100644 index 000000000..fd8019a9a --- /dev/null +++ b/tests/api_resources/web_search/__init__.py @@ -0,0 +1 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/web_search/test_research.py b/tests/api_resources/web_search/test_research.py new file mode 100644 index 000000000..77754a060 --- /dev/null +++ b/tests/api_resources/web_search/test_research.py @@ -0,0 +1,198 @@ +# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +from __future__ import annotations + +import os +from typing import Any, cast + +import pytest + +from telnyx import Telnyx, AsyncTelnyx +from tests.utils import assert_matches_type +from telnyx.types.web_search import ResearchCreateResponse, ResearchRetrieveResponse + +base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") + + +class TestResearch: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create(self, client: Telnyx) -> None: + research = client.web_search.research.create( + query="Compare the performance of RAG vs fine-tuning for domain-specific QA", + ) + assert_matches_type(ResearchCreateResponse, research, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_create_with_all_params(self, client: Telnyx) -> None: + research = client.web_search.research.create( + query="Compare the performance of RAG vs fine-tuning for domain-specific QA", + background=False, + max_sources=20, + research_effort="standard", + ) + assert_matches_type(ResearchCreateResponse, research, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_create(self, client: Telnyx) -> None: + response = client.web_search.research.with_raw_response.create( + query="Compare the performance of RAG vs fine-tuning for domain-specific QA", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + research = response.parse() + assert_matches_type(ResearchCreateResponse, research, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_create(self, client: Telnyx) -> None: + with client.web_search.research.with_streaming_response.create( + query="Compare the performance of RAG vs fine-tuning for domain-specific QA", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + research = response.parse() + assert_matches_type(ResearchCreateResponse, research, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_retrieve(self, client: Telnyx) -> None: + research = client.web_search.research.retrieve( + "bf3026a5-dd57-44dd-b922-200041be3a4b", + ) + assert_matches_type(ResearchRetrieveResponse, research, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_raw_response_retrieve(self, client: Telnyx) -> None: + response = client.web_search.research.with_raw_response.retrieve( + "bf3026a5-dd57-44dd-b922-200041be3a4b", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + research = response.parse() + assert_matches_type(ResearchRetrieveResponse, research, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_streaming_response_retrieve(self, client: Telnyx) -> None: + with client.web_search.research.with_streaming_response.retrieve( + "bf3026a5-dd57-44dd-b922-200041be3a4b", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + research = response.parse() + assert_matches_type(ResearchRetrieveResponse, research, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_path_params_retrieve(self, client: Telnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `task_id` but received ''"): + client.web_search.research.with_raw_response.retrieve( + "", + ) + + +class TestAsyncResearch: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create(self, async_client: AsyncTelnyx) -> None: + research = await async_client.web_search.research.create( + query="Compare the performance of RAG vs fine-tuning for domain-specific QA", + ) + assert_matches_type(ResearchCreateResponse, research, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_create_with_all_params(self, async_client: AsyncTelnyx) -> None: + research = await async_client.web_search.research.create( + query="Compare the performance of RAG vs fine-tuning for domain-specific QA", + background=False, + max_sources=20, + research_effort="standard", + ) + assert_matches_type(ResearchCreateResponse, research, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_create(self, async_client: AsyncTelnyx) -> None: + response = await async_client.web_search.research.with_raw_response.create( + query="Compare the performance of RAG vs fine-tuning for domain-specific QA", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + research = await response.parse() + assert_matches_type(ResearchCreateResponse, research, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_create(self, async_client: AsyncTelnyx) -> None: + async with async_client.web_search.research.with_streaming_response.create( + query="Compare the performance of RAG vs fine-tuning for domain-specific QA", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + research = await response.parse() + assert_matches_type(ResearchCreateResponse, research, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_retrieve(self, async_client: AsyncTelnyx) -> None: + research = await async_client.web_search.research.retrieve( + "bf3026a5-dd57-44dd-b922-200041be3a4b", + ) + assert_matches_type(ResearchRetrieveResponse, research, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_raw_response_retrieve(self, async_client: AsyncTelnyx) -> None: + response = await async_client.web_search.research.with_raw_response.retrieve( + "bf3026a5-dd57-44dd-b922-200041be3a4b", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + research = await response.parse() + assert_matches_type(ResearchRetrieveResponse, research, path=["response"]) + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_streaming_response_retrieve(self, async_client: AsyncTelnyx) -> None: + async with async_client.web_search.research.with_streaming_response.retrieve( + "bf3026a5-dd57-44dd-b922-200041be3a4b", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + research = await response.parse() + assert_matches_type(ResearchRetrieveResponse, research, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_path_params_retrieve(self, async_client: AsyncTelnyx) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `task_id` but received ''"): + await async_client.web_search.research.with_raw_response.retrieve( + "", + ) diff --git a/uv.lock b/uv.lock index 32228bc58..de6bcad63 100644 --- a/uv.lock +++ b/uv.lock @@ -4,10 +4,10 @@ requires-python = ">=3.9" resolution-markers = [ "python_full_version >= '3.14' and extra != 'group-6-telnyx-pydantic-v1' and extra == 'group-6-telnyx-pydantic-v2'", "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-6-telnyx-pydantic-v1' and extra == 'group-6-telnyx-pydantic-v2'", - "python_full_version < '3.10' and extra != 'group-6-telnyx-pydantic-v1' and extra == 'group-6-telnyx-pydantic-v2'", "python_full_version >= '3.10' and extra == 'group-6-telnyx-pydantic-v1' and extra != 'group-6-telnyx-pydantic-v2'", - "python_full_version < '3.10' and extra == 'group-6-telnyx-pydantic-v1' and extra != 'group-6-telnyx-pydantic-v2'", "python_full_version >= '3.10' and extra != 'group-6-telnyx-pydantic-v1' and extra != 'group-6-telnyx-pydantic-v2'", + "python_full_version < '3.10' and extra != 'group-6-telnyx-pydantic-v1' and extra == 'group-6-telnyx-pydantic-v2'", + "python_full_version < '3.10' and extra == 'group-6-telnyx-pydantic-v1' and extra != 'group-6-telnyx-pydantic-v2'", "python_full_version < '3.10' and extra != 'group-6-telnyx-pydantic-v1' and extra != 'group-6-telnyx-pydantic-v2'", ] conflicts = [[ @@ -998,8 +998,8 @@ source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and extra != 'group-6-telnyx-pydantic-v1' and extra == 'group-6-telnyx-pydantic-v2'", "python_full_version >= '3.10' and python_full_version < '3.14' and extra != 'group-6-telnyx-pydantic-v1' and extra == 'group-6-telnyx-pydantic-v2'", - "python_full_version < '3.10' and extra != 'group-6-telnyx-pydantic-v1' and extra == 'group-6-telnyx-pydantic-v2'", "python_full_version >= '3.10' and extra != 'group-6-telnyx-pydantic-v1' and extra != 'group-6-telnyx-pydantic-v2'", + "python_full_version < '3.10' and extra != 'group-6-telnyx-pydantic-v1' and extra == 'group-6-telnyx-pydantic-v2'", "python_full_version < '3.10' and extra != 'group-6-telnyx-pydantic-v1' and extra != 'group-6-telnyx-pydantic-v2'", ] dependencies = [