diff --git a/.stats.yml b/.stats.yml index c92480be..5893a877 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1 +1 @@ -configured_endpoints: 247 +configured_endpoints: 234 diff --git a/api.md b/api.md index bfeceaed..c2d4ddc2 100644 --- a/api.md +++ b/api.md @@ -965,52 +965,6 @@ Methods: - client.notifications.get_preferences() -> NotificationGetPreferencesResponse - client.notifications.update_preferences(\*\*params) -> NotificationUpdatePreferencesResponse -# Esims - -Types: - -```python -from mobilerun_sdk.types import ( - EsimCreateResponse, - EsimRetrieveResponse, - EsimUpdateResponse, - EsimListResponse, - EsimCapacityResponse, - EsimConfirmPaymentResponse, - EsimImportResponse, - EsimInstallResponse, - EsimInstallStatusResponse, - EsimSelectorResponse, -) -``` - -Methods: - -- client.esims.create(\*\*params) -> EsimCreateResponse -- client.esims.retrieve(id) -> EsimRetrieveResponse -- client.esims.update(id, \*\*params) -> EsimUpdateResponse -- client.esims.list(\*\*params) -> EsimListResponse -- client.esims.delete(id) -> None -- client.esims.capacity() -> EsimCapacityResponse -- client.esims.confirm_payment(id) -> EsimConfirmPaymentResponse -- client.esims.import\_(\*\*params) -> EsimImportResponse -- client.esims.install(id, \*\*params) -> EsimInstallResponse -- client.esims.install_status(id) -> EsimInstallStatusResponse -- client.esims.selector(\*\*params) -> EsimSelectorResponse - -## Messages - -Types: - -```python -from mobilerun_sdk.types.esims import MessageListResponse, MessageSendResponse -``` - -Methods: - -- client.esims.messages.list(id, \*\*params) -> MessageListResponse -- client.esims.messages.send(id, \*\*params) -> MessageSendResponse - # Messages Types: diff --git a/src/mobilerun_sdk/_client.py b/src/mobilerun_sdk/_client.py index 4a8abcae..cb8ba65a 100644 --- a/src/mobilerun_sdk/_client.py +++ b/src/mobilerun_sdk/_client.py @@ -38,7 +38,6 @@ if TYPE_CHECKING: from .resources import ( apps, - esims, files, store, tasks, @@ -64,7 +63,6 @@ from .resources.proxies import ProxiesResource, AsyncProxiesResource from .resources.carriers import CarriersResource, AsyncCarriersResource from .resources.profiles import ProfilesResource, AsyncProfilesResource - from .resources.esims.esims import EsimsResource, AsyncEsimsResource from .resources.store.store import StoreResource, AsyncStoreResource from .resources.tasks.tasks import TasksResource, AsyncTasksResource from .resources.notifications import NotificationsResource, AsyncNotificationsResource @@ -249,12 +247,6 @@ def notifications(self) -> NotificationsResource: return NotificationsResource(self) - @cached_property - def esims(self) -> EsimsResource: - from .resources.esims import EsimsResource - - return EsimsResource(self) - @cached_property def messages(self) -> MessagesResource: from .resources.messages import MessagesResource @@ -555,12 +547,6 @@ def notifications(self) -> AsyncNotificationsResource: return AsyncNotificationsResource(self) - @cached_property - def esims(self) -> AsyncEsimsResource: - from .resources.esims import AsyncEsimsResource - - return AsyncEsimsResource(self) - @cached_property def messages(self) -> AsyncMessagesResource: from .resources.messages import AsyncMessagesResource @@ -807,12 +793,6 @@ def notifications(self) -> notifications.NotificationsResourceWithRawResponse: return NotificationsResourceWithRawResponse(self._client.notifications) - @cached_property - def esims(self) -> esims.EsimsResourceWithRawResponse: - from .resources.esims import EsimsResourceWithRawResponse - - return EsimsResourceWithRawResponse(self._client.esims) - @cached_property def messages(self) -> messages.MessagesResourceWithRawResponse: from .resources.messages import MessagesResourceWithRawResponse @@ -936,12 +916,6 @@ def notifications(self) -> notifications.AsyncNotificationsResourceWithRawRespon return AsyncNotificationsResourceWithRawResponse(self._client.notifications) - @cached_property - def esims(self) -> esims.AsyncEsimsResourceWithRawResponse: - from .resources.esims import AsyncEsimsResourceWithRawResponse - - return AsyncEsimsResourceWithRawResponse(self._client.esims) - @cached_property def messages(self) -> messages.AsyncMessagesResourceWithRawResponse: from .resources.messages import AsyncMessagesResourceWithRawResponse @@ -1065,12 +1039,6 @@ def notifications(self) -> notifications.NotificationsResourceWithStreamingRespo return NotificationsResourceWithStreamingResponse(self._client.notifications) - @cached_property - def esims(self) -> esims.EsimsResourceWithStreamingResponse: - from .resources.esims import EsimsResourceWithStreamingResponse - - return EsimsResourceWithStreamingResponse(self._client.esims) - @cached_property def messages(self) -> messages.MessagesResourceWithStreamingResponse: from .resources.messages import MessagesResourceWithStreamingResponse @@ -1194,12 +1162,6 @@ def notifications(self) -> notifications.AsyncNotificationsResourceWithStreaming return AsyncNotificationsResourceWithStreamingResponse(self._client.notifications) - @cached_property - def esims(self) -> esims.AsyncEsimsResourceWithStreamingResponse: - from .resources.esims import AsyncEsimsResourceWithStreamingResponse - - return AsyncEsimsResourceWithStreamingResponse(self._client.esims) - @cached_property def messages(self) -> messages.AsyncMessagesResourceWithStreamingResponse: from .resources.messages import AsyncMessagesResourceWithStreamingResponse diff --git a/src/mobilerun_sdk/resources/__init__.py b/src/mobilerun_sdk/resources/__init__.py index c86ce259..30c0dbfc 100644 --- a/src/mobilerun_sdk/resources/__init__.py +++ b/src/mobilerun_sdk/resources/__init__.py @@ -8,14 +8,6 @@ AppsResourceWithStreamingResponse, AsyncAppsResourceWithStreamingResponse, ) -from .esims import ( - EsimsResource, - AsyncEsimsResource, - EsimsResourceWithRawResponse, - AsyncEsimsResourceWithRawResponse, - EsimsResourceWithStreamingResponse, - AsyncEsimsResourceWithStreamingResponse, -) from .files import ( FilesResource, AsyncFilesResource, @@ -258,12 +250,6 @@ "AsyncNotificationsResourceWithRawResponse", "NotificationsResourceWithStreamingResponse", "AsyncNotificationsResourceWithStreamingResponse", - "EsimsResource", - "AsyncEsimsResource", - "EsimsResourceWithRawResponse", - "AsyncEsimsResourceWithRawResponse", - "EsimsResourceWithStreamingResponse", - "AsyncEsimsResourceWithStreamingResponse", "MessagesResource", "AsyncMessagesResource", "MessagesResourceWithRawResponse", diff --git a/src/mobilerun_sdk/resources/apps.py b/src/mobilerun_sdk/resources/apps.py index e46dbbf0..3f0f323f 100644 --- a/src/mobilerun_sdk/resources/apps.py +++ b/src/mobilerun_sdk/resources/apps.py @@ -183,7 +183,9 @@ def confirm_upload( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AppConfirmUploadResponse: """ - Verifies the APK file exists in R2 and sets the app status to available. + Verifies the uploaded files in R2 and sets the app version status to available. + Idempotent: replaying confirmation for an already-available version returns the + same successful response without re-verifying the files. Args: extra_headers: Send extra headers @@ -506,7 +508,9 @@ async def confirm_upload( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AppConfirmUploadResponse: """ - Verifies the APK file exists in R2 and sets the app status to available. + Verifies the uploaded files in R2 and sets the app version status to available. + Idempotent: replaying confirmation for an already-available version returns the + same successful response without re-verifying the files. Args: extra_headers: Send extra headers diff --git a/src/mobilerun_sdk/resources/assistant/conversations.py b/src/mobilerun_sdk/resources/assistant/conversations.py index 04b2a56c..3747f5dd 100644 --- a/src/mobilerun_sdk/resources/assistant/conversations.py +++ b/src/mobilerun_sdk/resources/assistant/conversations.py @@ -221,6 +221,7 @@ def abort( self, *, session_id: str, + expected_turn_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, @@ -244,7 +245,13 @@ def abort( """ return self._post( "/assistant/chat/abort", - body=maybe_transform({"session_id": session_id}, conversation_abort_params.ConversationAbortParams), + body=maybe_transform( + { + "session_id": session_id, + "expected_turn_id": expected_turn_id, + }, + conversation_abort_params.ConversationAbortParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -263,8 +270,14 @@ def answer_permission( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationAnswerPermissionResponse: - """ - Deliver a HITL approval/rejection for an in-flight turn. + """Deliver a HITL approval/rejection for an in-flight turn. + + Interactive HITL + clients must start the turn with `Accept: text/event-stream`, wait for a + `tool-hitl-approval` event, and send its `permissionId` here at + `/assistant/chat/permission`. Do not submit approval as free-form user text or + as `confirmed: true`. For `devices.reset`, only `once` and `reject` are allowed; + the generic `always` response is rejected with HTTP 400. Args: extra_headers: Send extra headers @@ -428,9 +441,12 @@ def send( The response format follows the Accept header: `text/event-stream` for SSE, `application/json` for a buffered assistant reply. - `sessionId` targets a concrete active chat. The resolved chat session ID is - returned as `chatSessionId` in the JSON body and as the `X-Chat-Session-Id` - response header on the SSE response. + Interactive HITL requires `Accept: text/event-stream`: the stream can emit a + `tool-hitl-approval` event, whose decision must be delivered to + `/assistant/chat/permission`. Buffered JSON responses do not provide an + interactive HITL continuation contract. `sessionId` targets a concrete active + chat. The resolved chat session ID is returned as `chatSessionId` in the JSON + body and as the `X-Chat-Session-Id` response header on the SSE response. Args: extra_headers: Send extra headers @@ -677,6 +693,7 @@ async def abort( self, *, session_id: str, + expected_turn_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, @@ -701,7 +718,11 @@ async def abort( return await self._post( "/assistant/chat/abort", body=await async_maybe_transform( - {"session_id": session_id}, conversation_abort_params.ConversationAbortParams + { + "session_id": session_id, + "expected_turn_id": expected_turn_id, + }, + conversation_abort_params.ConversationAbortParams, ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout @@ -721,8 +742,14 @@ async def answer_permission( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationAnswerPermissionResponse: - """ - Deliver a HITL approval/rejection for an in-flight turn. + """Deliver a HITL approval/rejection for an in-flight turn. + + Interactive HITL + clients must start the turn with `Accept: text/event-stream`, wait for a + `tool-hitl-approval` event, and send its `permissionId` here at + `/assistant/chat/permission`. Do not submit approval as free-form user text or + as `confirmed: true`. For `devices.reset`, only `once` and `reject` are allowed; + the generic `always` response is rejected with HTTP 400. Args: extra_headers: Send extra headers @@ -886,9 +913,12 @@ async def send( The response format follows the Accept header: `text/event-stream` for SSE, `application/json` for a buffered assistant reply. - `sessionId` targets a concrete active chat. The resolved chat session ID is - returned as `chatSessionId` in the JSON body and as the `X-Chat-Session-Id` - response header on the SSE response. + Interactive HITL requires `Accept: text/event-stream`: the stream can emit a + `tool-hitl-approval` event, whose decision must be delivered to + `/assistant/chat/permission`. Buffered JSON responses do not provide an + interactive HITL continuation contract. `sessionId` targets a concrete active + chat. The resolved chat session ID is returned as `chatSessionId` in the JSON + body and as the `X-Chat-Session-Id` response header on the SSE response. Args: extra_headers: Send extra headers diff --git a/src/mobilerun_sdk/resources/connect/proxies.py b/src/mobilerun_sdk/resources/connect/proxies.py index c89fce4c..718dc6d6 100644 --- a/src/mobilerun_sdk/resources/connect/proxies.py +++ b/src/mobilerun_sdk/resources/connect/proxies.py @@ -9,7 +9,7 @@ import httpx from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform +from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform from ..._compat import cached_property from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( @@ -140,6 +140,7 @@ def buy( *, country: str, type: Literal["dedicated_residential", "residential", "mobile"], + idempotency_key: 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, @@ -161,6 +162,7 @@ def buy( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})} return self._post( "/connect/proxies", body=maybe_transform( @@ -505,6 +507,7 @@ async def buy( *, country: str, type: Literal["dedicated_residential", "residential", "mobile"], + idempotency_key: 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, @@ -526,6 +529,7 @@ async def buy( timeout: Override the client-level default timeout for this request, in seconds """ + extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})} return await self._post( "/connect/proxies", body=await async_maybe_transform( diff --git a/src/mobilerun_sdk/resources/devices/apps.py b/src/mobilerun_sdk/resources/devices/apps.py index f89729c8..e672a017 100644 --- a/src/mobilerun_sdk/resources/devices/apps.py +++ b/src/mobilerun_sdk/resources/devices/apps.py @@ -207,7 +207,9 @@ def install( *, bundle_id: str, background: bool | Omit = omit, + country: str | Omit = omit, package_name: str | Omit = omit, + version_code: int | Omit = omit, x_device_display_id: 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. @@ -219,15 +221,16 @@ def install( """Requests an app install on the device. The request body must supply exactly one - of an Android packageName or an iOS bundleId; protected packages are rejected. - background (default false) selects the response contract: false installs inline - and returns the outcome directly (200 on success, an error status on failure); - true accepts the request and runs the download + install in the background, - returning 202 immediately — poll list-app-installs for the backend's view of - that attempt's status. Refuses with 409 once 2 other installs are already - running on the device, in either mode; a repeat request for an app that already - has an install running is also refused with 409 rather than superseding it — - retry once that attempt reaches a terminal state. + of an Android packageName or an iOS bundleId; optional country and versionCode + select an exact regional uploaded Android version, and protected packages are + rejected. background (default false) selects the response contract: false + installs inline and returns the outcome directly (200 on success, an error + status on failure); true accepts the request and runs the download + install in + the background, returning 202 immediately — poll list-app-installs for the + backend's view of that attempt's status. Refuses with 409 once 2 other installs + are already running on the device, in either mode; a repeat request for an app + that already has an install running is also refused with 409 rather than + superseding it — retry once that attempt reaches a terminal state. Args: bundle_id: iOS bundle identifier (e.g. com.example.app) @@ -236,8 +239,13 @@ def install( list-app-installs). false/omitted: install inline and return the outcome directly (200 on success, an error status on failure). + country: Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. MY or SG). + package_name: Android package name (e.g. com.example.app) + version_code: Optional exact app-library version code. Use with country when multiple regional + versions share an identifier. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -256,6 +264,8 @@ def install( package_name: str, background: bool | Omit = omit, bundle_id: str | Omit = omit, + country: str | Omit = omit, + version_code: int | Omit = omit, x_device_display_id: 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. @@ -267,15 +277,16 @@ def install( """Requests an app install on the device. The request body must supply exactly one - of an Android packageName or an iOS bundleId; protected packages are rejected. - background (default false) selects the response contract: false installs inline - and returns the outcome directly (200 on success, an error status on failure); - true accepts the request and runs the download + install in the background, - returning 202 immediately — poll list-app-installs for the backend's view of - that attempt's status. Refuses with 409 once 2 other installs are already - running on the device, in either mode; a repeat request for an app that already - has an install running is also refused with 409 rather than superseding it — - retry once that attempt reaches a terminal state. + of an Android packageName or an iOS bundleId; optional country and versionCode + select an exact regional uploaded Android version, and protected packages are + rejected. background (default false) selects the response contract: false + installs inline and returns the outcome directly (200 on success, an error + status on failure); true accepts the request and runs the download + install in + the background, returning 202 immediately — poll list-app-installs for the + backend's view of that attempt's status. Refuses with 409 once 2 other installs + are already running on the device, in either mode; a repeat request for an app + that already has an install running is also refused with 409 rather than + superseding it — retry once that attempt reaches a terminal state. Args: package_name: Android package name (e.g. com.example.app) @@ -286,6 +297,11 @@ def install( bundle_id: iOS bundle identifier (e.g. com.example.app) + country: Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. MY or SG). + + version_code: Optional exact app-library version code. Use with country when multiple regional + versions share an identifier. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -303,7 +319,9 @@ def install( *, bundle_id: str | Omit = omit, background: bool | Omit = omit, + country: str | Omit = omit, package_name: str | Omit = omit, + version_code: int | Omit = omit, x_device_display_id: 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. @@ -327,7 +345,9 @@ def install( { "bundle_id": bundle_id, "background": background, + "country": country, "package_name": package_name, + "version_code": version_code, }, app_install_params.AppInstallParams, ), @@ -350,11 +370,11 @@ def list_installs( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AppListInstallsResponse: """ - Reports the backend's view of background app-install attempts on this device — - status reflects the install ATTEMPT, not device ground truth; list-apps remains - authoritative for what is actually installed. Records are in-memory and lost on - service restart; terminal records are kept ~15 minutes. Not gated on device - readiness, so it also answers while the device is offline or crashed. + Reports the backend's durable view of background app-install attempts on this + device — status reflects the install ATTEMPT, not device ground truth; list-apps + remains authoritative for what is actually installed. Terminal and projected + timeout records are kept ~15 minutes. Not gated on device readiness, so it also + answers while the device is offline or crashed. Args: extra_headers: Send extra headers @@ -719,7 +739,9 @@ async def install( *, bundle_id: str, background: bool | Omit = omit, + country: str | Omit = omit, package_name: str | Omit = omit, + version_code: int | Omit = omit, x_device_display_id: 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. @@ -731,15 +753,16 @@ async def install( """Requests an app install on the device. The request body must supply exactly one - of an Android packageName or an iOS bundleId; protected packages are rejected. - background (default false) selects the response contract: false installs inline - and returns the outcome directly (200 on success, an error status on failure); - true accepts the request and runs the download + install in the background, - returning 202 immediately — poll list-app-installs for the backend's view of - that attempt's status. Refuses with 409 once 2 other installs are already - running on the device, in either mode; a repeat request for an app that already - has an install running is also refused with 409 rather than superseding it — - retry once that attempt reaches a terminal state. + of an Android packageName or an iOS bundleId; optional country and versionCode + select an exact regional uploaded Android version, and protected packages are + rejected. background (default false) selects the response contract: false + installs inline and returns the outcome directly (200 on success, an error + status on failure); true accepts the request and runs the download + install in + the background, returning 202 immediately — poll list-app-installs for the + backend's view of that attempt's status. Refuses with 409 once 2 other installs + are already running on the device, in either mode; a repeat request for an app + that already has an install running is also refused with 409 rather than + superseding it — retry once that attempt reaches a terminal state. Args: bundle_id: iOS bundle identifier (e.g. com.example.app) @@ -748,8 +771,13 @@ async def install( list-app-installs). false/omitted: install inline and return the outcome directly (200 on success, an error status on failure). + country: Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. MY or SG). + package_name: Android package name (e.g. com.example.app) + version_code: Optional exact app-library version code. Use with country when multiple regional + versions share an identifier. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -768,6 +796,8 @@ async def install( package_name: str, background: bool | Omit = omit, bundle_id: str | Omit = omit, + country: str | Omit = omit, + version_code: int | Omit = omit, x_device_display_id: 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. @@ -779,15 +809,16 @@ async def install( """Requests an app install on the device. The request body must supply exactly one - of an Android packageName or an iOS bundleId; protected packages are rejected. - background (default false) selects the response contract: false installs inline - and returns the outcome directly (200 on success, an error status on failure); - true accepts the request and runs the download + install in the background, - returning 202 immediately — poll list-app-installs for the backend's view of - that attempt's status. Refuses with 409 once 2 other installs are already - running on the device, in either mode; a repeat request for an app that already - has an install running is also refused with 409 rather than superseding it — - retry once that attempt reaches a terminal state. + of an Android packageName or an iOS bundleId; optional country and versionCode + select an exact regional uploaded Android version, and protected packages are + rejected. background (default false) selects the response contract: false + installs inline and returns the outcome directly (200 on success, an error + status on failure); true accepts the request and runs the download + install in + the background, returning 202 immediately — poll list-app-installs for the + backend's view of that attempt's status. Refuses with 409 once 2 other installs + are already running on the device, in either mode; a repeat request for an app + that already has an install running is also refused with 409 rather than + superseding it — retry once that attempt reaches a terminal state. Args: package_name: Android package name (e.g. com.example.app) @@ -798,6 +829,11 @@ async def install( bundle_id: iOS bundle identifier (e.g. com.example.app) + country: Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. MY or SG). + + version_code: Optional exact app-library version code. Use with country when multiple regional + versions share an identifier. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -815,7 +851,9 @@ async def install( *, bundle_id: str | Omit = omit, background: bool | Omit = omit, + country: str | Omit = omit, package_name: str | Omit = omit, + version_code: int | Omit = omit, x_device_display_id: 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. @@ -839,7 +877,9 @@ async def install( { "bundle_id": bundle_id, "background": background, + "country": country, "package_name": package_name, + "version_code": version_code, }, app_install_params.AppInstallParams, ), @@ -862,11 +902,11 @@ async def list_installs( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> AppListInstallsResponse: """ - Reports the backend's view of background app-install attempts on this device — - status reflects the install ATTEMPT, not device ground truth; list-apps remains - authoritative for what is actually installed. Records are in-memory and lost on - service restart; terminal records are kept ~15 minutes. Not gated on device - readiness, so it also answers while the device is offline or crashed. + Reports the backend's durable view of background app-install attempts on this + device — status reflects the install ATTEMPT, not device ground truth; list-apps + remains authoritative for what is actually installed. Terminal and projected + timeout records are kept ~15 minutes. Not gated on device readiness, so it also + answers while the device is offline or crashed. Args: extra_headers: Send extra headers diff --git a/src/mobilerun_sdk/resources/devices/devices.py b/src/mobilerun_sdk/resources/devices/devices.py index ad34958e..a678d943 100644 --- a/src/mobilerun_sdk/resources/devices/devices.py +++ b/src/mobilerun_sdk/resources/devices/devices.py @@ -657,10 +657,9 @@ def resume( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Wakes a parked device: capacity is preflighted (the device's data may be - replicated to another node if its home is full), the device starts running - again, and per-minute billing resumes. On a device that is not parked this is a - no-op ready transition. + Wakes a parked device: backend readiness and any required capacity are + preflighted, the same device starts running again, and per-minute billing + resumes. On a device that is not parked this is a no-op ready transition. Args: extra_headers: Send extra headers @@ -1344,10 +1343,9 @@ async def resume( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: """ - Wakes a parked device: capacity is preflighted (the device's data may be - replicated to another node if its home is full), the device starts running - again, and per-minute billing resumes. On a device that is not parked this is a - no-op ready transition. + Wakes a parked device: backend readiness and any required capacity are + preflighted, the same device starts running again, and per-minute billing + resumes. On a device that is not parked this is a no-op ready transition. Args: extra_headers: Send extra headers diff --git a/src/mobilerun_sdk/resources/devices/keyboard.py b/src/mobilerun_sdk/resources/devices/keyboard.py index a1bd8bbc..dd5439ce 100644 --- a/src/mobilerun_sdk/resources/devices/keyboard.py +++ b/src/mobilerun_sdk/resources/devices/keyboard.py @@ -2,6 +2,8 @@ from __future__ import annotations +from typing_extensions import Literal + import httpx from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given @@ -130,6 +132,7 @@ def write( *, text: str, clear: bool | Omit = omit, + completion_mode: Literal["accepted", "committed"] | Omit = omit, error_rate: float | Omit = omit, stealth: bool | Omit = omit, wpm: int | Omit = omit, @@ -141,13 +144,17 @@ def write( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Types the given text into the focused input field. + """Types text into the focused input field. - Supports optionally clearing - the field first and a stealth mode that emulates human typing speed and error - rate on supported devices. + The optional completionMode defaults to + accepted for backwards-compatible low latency; committed additionally waits for + the complete text or a quiescent UI state. Args: + completion_mode: Completion guarantee. accepted returns after the input provider accepts the + operation; committed additionally waits for the focused UI state to contain the + complete text or become quiescent. + error_rate: Per-character mistake rate for humantouch typing. -1 uses server default. wpm: Words per minute for stealth typing. 0 uses portal default. @@ -175,6 +182,7 @@ def write( { "text": text, "clear": clear, + "completion_mode": completion_mode, "error_rate": error_rate, "stealth": stealth, "wpm": wpm, @@ -298,6 +306,7 @@ async def write( *, text: str, clear: bool | Omit = omit, + completion_mode: Literal["accepted", "committed"] | Omit = omit, error_rate: float | Omit = omit, stealth: bool | Omit = omit, wpm: int | Omit = omit, @@ -309,13 +318,17 @@ async def write( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> None: - """Types the given text into the focused input field. + """Types text into the focused input field. - Supports optionally clearing - the field first and a stealth mode that emulates human typing speed and error - rate on supported devices. + The optional completionMode defaults to + accepted for backwards-compatible low latency; committed additionally waits for + the complete text or a quiescent UI state. Args: + completion_mode: Completion guarantee. accepted returns after the input provider accepts the + operation; committed additionally waits for the focused UI state to contain the + complete text or become quiescent. + error_rate: Per-character mistake rate for humantouch typing. -1 uses server default. wpm: Words per minute for stealth typing. 0 uses portal default. @@ -343,6 +356,7 @@ async def write( { "text": text, "clear": clear, + "completion_mode": completion_mode, "error_rate": error_rate, "stealth": stealth, "wpm": wpm, diff --git a/src/mobilerun_sdk/resources/devices/recordings.py b/src/mobilerun_sdk/resources/devices/recordings.py index 11ed0b6a..1591a3b8 100644 --- a/src/mobilerun_sdk/resources/devices/recordings.py +++ b/src/mobilerun_sdk/resources/devices/recordings.py @@ -135,6 +135,7 @@ def start( device_id: str, *, name: str | Omit = omit, + quality: int | Omit = omit, retention_days: int | Omit = omit, types: Optional[SequenceNotStr[str]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -148,6 +149,14 @@ def start( Start a device recording Args: + quality: Capture quality from 1 (lowest) to 10 (full stream quality). Defaults to the + device's full quality. Honored by devices recording through the portal stream + bridge. + + types: Artifacts to capture: trajectory (input actions), video, and audio (captured + into the video artifact, so it requires video; honored by portal stream-bridge + recorders). Defaults to trajectory and video. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -163,6 +172,7 @@ def start( body=maybe_transform( { "name": name, + "quality": quality, "retention_days": retention_days, "types": types, }, @@ -440,6 +450,7 @@ async def start( device_id: str, *, name: str | Omit = omit, + quality: int | Omit = omit, retention_days: int | Omit = omit, types: Optional[SequenceNotStr[str]] | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -453,6 +464,14 @@ async def start( Start a device recording Args: + quality: Capture quality from 1 (lowest) to 10 (full stream quality). Defaults to the + device's full quality. Honored by devices recording through the portal stream + bridge. + + types: Artifacts to capture: trajectory (input actions), video, and audio (captured + into the video artifact, so it requires video; honored by portal stream-bridge + recorders). Defaults to trajectory and video. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -468,6 +487,7 @@ async def start( body=await async_maybe_transform( { "name": name, + "quality": quality, "retention_days": retention_days, "types": types, }, diff --git a/src/mobilerun_sdk/resources/esims/__init__.py b/src/mobilerun_sdk/resources/esims/__init__.py deleted file mode 100644 index 394c2d72..00000000 --- a/src/mobilerun_sdk/resources/esims/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .esims import ( - EsimsResource, - AsyncEsimsResource, - EsimsResourceWithRawResponse, - AsyncEsimsResourceWithRawResponse, - EsimsResourceWithStreamingResponse, - AsyncEsimsResourceWithStreamingResponse, -) -from .messages import ( - MessagesResource, - AsyncMessagesResource, - MessagesResourceWithRawResponse, - AsyncMessagesResourceWithRawResponse, - MessagesResourceWithStreamingResponse, - AsyncMessagesResourceWithStreamingResponse, -) - -__all__ = [ - "MessagesResource", - "AsyncMessagesResource", - "MessagesResourceWithRawResponse", - "AsyncMessagesResourceWithRawResponse", - "MessagesResourceWithStreamingResponse", - "AsyncMessagesResourceWithStreamingResponse", - "EsimsResource", - "AsyncEsimsResource", - "EsimsResourceWithRawResponse", - "AsyncEsimsResourceWithRawResponse", - "EsimsResourceWithStreamingResponse", - "AsyncEsimsResourceWithStreamingResponse", -] diff --git a/src/mobilerun_sdk/resources/esims/esims.py b/src/mobilerun_sdk/resources/esims/esims.py deleted file mode 100644 index 49347cbe..00000000 --- a/src/mobilerun_sdk/resources/esims/esims.py +++ /dev/null @@ -1,1286 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Literal - -import httpx - -from ...types import ( - esim_list_params, - esim_create_params, - esim_import_params, - esim_update_params, - esim_install_params, - esim_selector_params, -) -from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ..._utils import path_template, maybe_transform, async_maybe_transform -from .messages import ( - MessagesResource, - AsyncMessagesResource, - MessagesResourceWithRawResponse, - AsyncMessagesResourceWithRawResponse, - MessagesResourceWithStreamingResponse, - AsyncMessagesResourceWithStreamingResponse, -) -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.esim_list_response import EsimListResponse -from ...types.esim_create_response import EsimCreateResponse -from ...types.esim_import_response import EsimImportResponse -from ...types.esim_update_response import EsimUpdateResponse -from ...types.esim_install_response import EsimInstallResponse -from ...types.esim_capacity_response import EsimCapacityResponse -from ...types.esim_retrieve_response import EsimRetrieveResponse -from ...types.esim_selector_response import EsimSelectorResponse -from ...types.esim_install_status_response import EsimInstallStatusResponse -from ...types.esim_confirm_payment_response import EsimConfirmPaymentResponse - -__all__ = ["EsimsResource", "AsyncEsimsResource"] - - -class EsimsResource(SyncAPIResource): - @cached_property - def messages(self) -> MessagesResource: - return MessagesResource(self._client) - - @cached_property - def with_raw_response(self) -> EsimsResourceWithRawResponse: - """ - 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/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers - """ - return EsimsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> EsimsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response - """ - return EsimsResourceWithStreamingResponse(self) - - def create( - self, - *, - idempotency_key: str | Omit = omit, - name: Optional[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, - ) -> EsimCreateResponse: - """ - Purchases a physical eSIM from available inventory for the authenticated owner. - Returns 409 when no stock is available, or 402 with a billing checkout URL when - billing capacity is exhausted. - - Args: - idempotency_key: Client-supplied key; replaying the same key returns the original purchase - instead of buying again - - name: Optional user-defined display label — NFC-normalized, up to 15 GRAPHEMES. Omit - or null for no label. - - 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( - "/numbers/esims", - body=maybe_transform( - { - "idempotency_key": idempotency_key, - "name": name, - }, - esim_create_params.EsimCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimCreateResponse, - ) - - 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, - ) -> EsimRetrieveResponse: - """ - Retrieves a single physical eSIM. - - 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("/numbers/esims/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimRetrieveResponse, - ) - - def update( - self, - id: str, - *, - msisdn: Optional[str] | Omit = omit, - name: Optional[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, - ) -> EsimUpdateResponse: - """Updates the eSIM's self-reported msisdn and/or display name. - - Both fields are - optional, but the request body itself is required. Omitting a field leaves it - unchanged; setting it to null or an empty string clears it. `name` is capped at - 15 characters. Available regardless of the eSIM's current status. - - Args: - msisdn: Self-reported E.164 MSISDN for this eSIM's line. Omit to leave unchanged; - null/empty clears it. An unverified label — never used for routing. - - name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code - units; an emoji/flag may span several). Omit to leave unchanged; - null/empty/whitespace-only clears it. - - 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("/numbers/esims/{id}", id=id), - body=maybe_transform( - { - "msisdn": msisdn, - "name": name, - }, - esim_update_params.EsimUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimUpdateResponse, - ) - - def list( - self, - *, - mine: Literal["true", "false"] | Omit = omit, - page: int | Omit = omit, - page_size: int | Omit = omit, - status: Literal["all", "in_stock", "owned", "installing", "installed", "install_failed", "retired"] - | 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, - ) -> EsimListResponse: - """ - Lists physical eSIMs owned by the authenticated owner. - - Args: - mine: Only include eSIMs created by the calling actor. - - 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( - "/numbers/esims", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "mine": mine, - "page": page, - "page_size": page_size, - "status": status, - }, - esim_list_params.EsimListParams, - ), - ), - cast_to=EsimListResponse, - ) - - 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, - ) -> None: - """Removes a physical eSIM. - - Idempotent — returns 204 for a fresh removal or a - replay of an already-removed eSIM. An eSIM currently installed on a device is - uninstalled first, then removed. An eSIM in an intermediate install state - returns 409 `operator_resolution_required` and requires manual resolution. - Returns 404 if the eSIM doesn't exist or isn't owned by the caller. - - 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}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - path_template("/numbers/esims/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def capacity( - self, - *, - # 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, - ) -> EsimCapacityResponse: - """ - Reports whether a free device is currently available, for pre-checking the - import flow before upload. This is a hint only, not a reservation — - `POST /esims/import` re-checks availability at submit time. - """ - return self._get( - "/numbers/esims/capacity", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimCapacityResponse, - ) - - def confirm_payment( - 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, - ) -> EsimConfirmPaymentResponse: - """ - Checks for proof of payment for this eSIM's current rent and confirms it if - found. If no proof is available yet, returns 200 with the eSIM unchanged rather - than an error. Always returns the current eSIM state. - - 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("/numbers/esims/{id}/confirm-payment", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimConfirmPaymentResponse, - ) - - def import_( - self, - *, - auto_install: bool | Omit = omit, - carrier_name: str | Omit = omit, - confirmation_code: str | Omit = omit, - country_code: str | Omit = omit, - device_id: str | Omit = omit, - idempotency_key: str | Omit = omit, - lpa_code: str | Omit = omit, - matching_id: str | Omit = omit, - msisdn: str | Omit = omit, - name: Optional[str] | Omit = omit, - notes: str | Omit = omit, - smdp_address: 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, - ) -> EsimImportResponse: - """ - Registers a bring-your-own (BYO) eSIM activation code as owned inventory. - Provide either `{ smdpAddress, matchingId?, confirmationCode? }` or - `{ lpaCode }` — supplying both, or neither, returns 400. An optional `name` sets - a display label on the created eSIM (up to 15 characters). - - Subject to per-owner and daily import limits, and disabled entirely unless BYO - imports are enabled for this deployment (409 `byo_disabled`). Idempotent via - `idempotencyKey`: replaying the same key with an identical request returns the - original response; the same key with a different request returns 409 - `idempotency_conflict`. - - When rent-first billing is off (default), the import is free — 201 with the - eSIM. Setting `autoInstall: true` additionally dispatches an install immediately - after import (`deviceId` may only be set together with `autoInstall`): this - returns 202 with `{esim, operationId, statusUrl}` when the install claim - succeeds (poll `GET /esims/{id}/install-status`), or 201 with the eSIM plus - `installDispatch: {ok: false, reason}` when the install could not be dispatched - — the import itself still succeeds either way. - - When rent-first billing is on, import additionally requires available device - capacity (409 `device_pool_empty`) and is subject to a per-owner - awaiting-payment cap (409 `byo_awaiting_payment_cap`). On success the eSIM is - created `awaiting_payment` and a checkout is started: 201 with - `{esim, rentStatus, checkoutUrl}` when the checkout URL is ready immediately, or - 202 with `checkoutUrl: null` otherwise — poll `GET /esims/{id}` until it's - populated. Once payment is confirmed, install is triggered automatically. - - Args: - auto_install: Rent OFF only: dispatch install-on-device immediately after a successful import. - No-op when ESIM_BYO_RENT_ENABLED=true. - - device_id: physedge device id to auto-install onto; requires autoInstall:true and rent OFF. - Omit for a random pool device. - - idempotency_key: Client-supplied key; replaying the same key+request returns the original import - instead of importing again - - lpa_code: Full LPA activation code - - msisdn: Self-reported E.164 MSISDN for this eSIM's line — an unverified label, never - used for routing - - name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code - units; an emoji/flag may span several). Omit/null/empty/whitespace-only leaves - it unset. - - smdp_address: SM-DP+ activation host — bare hostname ONLY, no port/scheme/path. - - 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( - "/numbers/esims/import", - body=maybe_transform( - { - "auto_install": auto_install, - "carrier_name": carrier_name, - "confirmation_code": confirmation_code, - "country_code": country_code, - "device_id": device_id, - "idempotency_key": idempotency_key, - "lpa_code": lpa_code, - "matching_id": matching_id, - "msisdn": msisdn, - "name": name, - "notes": notes, - "smdp_address": smdp_address, - }, - esim_import_params.EsimImportParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimImportResponse, - ) - - def install( - self, - id: str, - *, - device_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, - ) -> EsimInstallResponse: - """Installs the eSIM's activation code onto a device. - - `deviceId` is optional — omit - it to use an available device from the pool. This call is asynchronous: it - returns 202 with `{esim, operationId, statusUrl}` immediately, and the result is - available by polling `GET /esims/{id}/install-status`. Retrying with the same - request is safe if a response is lost. - - Returns 409 when the eSIM is not in the `owned` state, or when no device is - currently available (see `reason`). When rent-first billing is enabled, a BYO - eSIM whose rent isn't active returns 402 with `{esim, rentStatus, checkoutUrl}` - instead. - - Args: - device_id: physedge device id to install the eSIM onto; omit for a random pool device - - 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("/numbers/esims/{id}/install", id=id), - body=maybe_transform({"device_id": device_id}, esim_install_params.EsimInstallParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimInstallResponse, - ) - - def install_status( - 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, - ) -> EsimInstallStatusResponse: - """ - Returns the eSIM's current install status, checking for a terminal outcome if an - install is still in progress. - - 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("/numbers/esims/{id}/install-status", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimInstallStatusResponse, - ) - - def selector( - self, - *, - page: int | Omit = omit, - page_size: 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, - ) -> EsimSelectorResponse: - """ - Returns a lightweight list (id, msisdn, carrierName, status, masked iccid) for - use in a message filter dropdown. Unlike `GET /esims`, this includes all - statuses, including retired eSIMs. - - 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 - """ - return self._get( - "/numbers/esims/selector", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "page": page, - "page_size": page_size, - }, - esim_selector_params.EsimSelectorParams, - ), - ), - cast_to=EsimSelectorResponse, - ) - - -class AsyncEsimsResource(AsyncAPIResource): - @cached_property - def messages(self) -> AsyncMessagesResource: - return AsyncMessagesResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncEsimsResourceWithRawResponse: - """ - 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/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers - """ - return AsyncEsimsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncEsimsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response - """ - return AsyncEsimsResourceWithStreamingResponse(self) - - async def create( - self, - *, - idempotency_key: str | Omit = omit, - name: Optional[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, - ) -> EsimCreateResponse: - """ - Purchases a physical eSIM from available inventory for the authenticated owner. - Returns 409 when no stock is available, or 402 with a billing checkout URL when - billing capacity is exhausted. - - Args: - idempotency_key: Client-supplied key; replaying the same key returns the original purchase - instead of buying again - - name: Optional user-defined display label — NFC-normalized, up to 15 GRAPHEMES. Omit - or null for no label. - - 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( - "/numbers/esims", - body=await async_maybe_transform( - { - "idempotency_key": idempotency_key, - "name": name, - }, - esim_create_params.EsimCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimCreateResponse, - ) - - 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, - ) -> EsimRetrieveResponse: - """ - Retrieves a single physical eSIM. - - 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("/numbers/esims/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimRetrieveResponse, - ) - - async def update( - self, - id: str, - *, - msisdn: Optional[str] | Omit = omit, - name: Optional[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, - ) -> EsimUpdateResponse: - """Updates the eSIM's self-reported msisdn and/or display name. - - Both fields are - optional, but the request body itself is required. Omitting a field leaves it - unchanged; setting it to null or an empty string clears it. `name` is capped at - 15 characters. Available regardless of the eSIM's current status. - - Args: - msisdn: Self-reported E.164 MSISDN for this eSIM's line. Omit to leave unchanged; - null/empty clears it. An unverified label — never used for routing. - - name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code - units; an emoji/flag may span several). Omit to leave unchanged; - null/empty/whitespace-only clears it. - - 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("/numbers/esims/{id}", id=id), - body=await async_maybe_transform( - { - "msisdn": msisdn, - "name": name, - }, - esim_update_params.EsimUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimUpdateResponse, - ) - - async def list( - self, - *, - mine: Literal["true", "false"] | Omit = omit, - page: int | Omit = omit, - page_size: int | Omit = omit, - status: Literal["all", "in_stock", "owned", "installing", "installed", "install_failed", "retired"] - | 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, - ) -> EsimListResponse: - """ - Lists physical eSIMs owned by the authenticated owner. - - Args: - mine: Only include eSIMs created by the calling actor. - - 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( - "/numbers/esims", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "mine": mine, - "page": page, - "page_size": page_size, - "status": status, - }, - esim_list_params.EsimListParams, - ), - ), - cast_to=EsimListResponse, - ) - - 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, - ) -> None: - """Removes a physical eSIM. - - Idempotent — returns 204 for a fresh removal or a - replay of an already-removed eSIM. An eSIM currently installed on a device is - uninstalled first, then removed. An eSIM in an intermediate install state - returns 409 `operator_resolution_required` and requires manual resolution. - Returns 404 if the eSIM doesn't exist or isn't owned by the caller. - - 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}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - path_template("/numbers/esims/{id}", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def capacity( - self, - *, - # 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, - ) -> EsimCapacityResponse: - """ - Reports whether a free device is currently available, for pre-checking the - import flow before upload. This is a hint only, not a reservation — - `POST /esims/import` re-checks availability at submit time. - """ - return await self._get( - "/numbers/esims/capacity", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimCapacityResponse, - ) - - async def confirm_payment( - 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, - ) -> EsimConfirmPaymentResponse: - """ - Checks for proof of payment for this eSIM's current rent and confirms it if - found. If no proof is available yet, returns 200 with the eSIM unchanged rather - than an error. Always returns the current eSIM state. - - 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("/numbers/esims/{id}/confirm-payment", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimConfirmPaymentResponse, - ) - - async def import_( - self, - *, - auto_install: bool | Omit = omit, - carrier_name: str | Omit = omit, - confirmation_code: str | Omit = omit, - country_code: str | Omit = omit, - device_id: str | Omit = omit, - idempotency_key: str | Omit = omit, - lpa_code: str | Omit = omit, - matching_id: str | Omit = omit, - msisdn: str | Omit = omit, - name: Optional[str] | Omit = omit, - notes: str | Omit = omit, - smdp_address: 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, - ) -> EsimImportResponse: - """ - Registers a bring-your-own (BYO) eSIM activation code as owned inventory. - Provide either `{ smdpAddress, matchingId?, confirmationCode? }` or - `{ lpaCode }` — supplying both, or neither, returns 400. An optional `name` sets - a display label on the created eSIM (up to 15 characters). - - Subject to per-owner and daily import limits, and disabled entirely unless BYO - imports are enabled for this deployment (409 `byo_disabled`). Idempotent via - `idempotencyKey`: replaying the same key with an identical request returns the - original response; the same key with a different request returns 409 - `idempotency_conflict`. - - When rent-first billing is off (default), the import is free — 201 with the - eSIM. Setting `autoInstall: true` additionally dispatches an install immediately - after import (`deviceId` may only be set together with `autoInstall`): this - returns 202 with `{esim, operationId, statusUrl}` when the install claim - succeeds (poll `GET /esims/{id}/install-status`), or 201 with the eSIM plus - `installDispatch: {ok: false, reason}` when the install could not be dispatched - — the import itself still succeeds either way. - - When rent-first billing is on, import additionally requires available device - capacity (409 `device_pool_empty`) and is subject to a per-owner - awaiting-payment cap (409 `byo_awaiting_payment_cap`). On success the eSIM is - created `awaiting_payment` and a checkout is started: 201 with - `{esim, rentStatus, checkoutUrl}` when the checkout URL is ready immediately, or - 202 with `checkoutUrl: null` otherwise — poll `GET /esims/{id}` until it's - populated. Once payment is confirmed, install is triggered automatically. - - Args: - auto_install: Rent OFF only: dispatch install-on-device immediately after a successful import. - No-op when ESIM_BYO_RENT_ENABLED=true. - - device_id: physedge device id to auto-install onto; requires autoInstall:true and rent OFF. - Omit for a random pool device. - - idempotency_key: Client-supplied key; replaying the same key+request returns the original import - instead of importing again - - lpa_code: Full LPA activation code - - msisdn: Self-reported E.164 MSISDN for this eSIM's line — an unverified label, never - used for routing - - name: User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code - units; an emoji/flag may span several). Omit/null/empty/whitespace-only leaves - it unset. - - smdp_address: SM-DP+ activation host — bare hostname ONLY, no port/scheme/path. - - 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( - "/numbers/esims/import", - body=await async_maybe_transform( - { - "auto_install": auto_install, - "carrier_name": carrier_name, - "confirmation_code": confirmation_code, - "country_code": country_code, - "device_id": device_id, - "idempotency_key": idempotency_key, - "lpa_code": lpa_code, - "matching_id": matching_id, - "msisdn": msisdn, - "name": name, - "notes": notes, - "smdp_address": smdp_address, - }, - esim_import_params.EsimImportParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimImportResponse, - ) - - async def install( - self, - id: str, - *, - device_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, - ) -> EsimInstallResponse: - """Installs the eSIM's activation code onto a device. - - `deviceId` is optional — omit - it to use an available device from the pool. This call is asynchronous: it - returns 202 with `{esim, operationId, statusUrl}` immediately, and the result is - available by polling `GET /esims/{id}/install-status`. Retrying with the same - request is safe if a response is lost. - - Returns 409 when the eSIM is not in the `owned` state, or when no device is - currently available (see `reason`). When rent-first billing is enabled, a BYO - eSIM whose rent isn't active returns 402 with `{esim, rentStatus, checkoutUrl}` - instead. - - Args: - device_id: physedge device id to install the eSIM onto; omit for a random pool device - - 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("/numbers/esims/{id}/install", id=id), - body=await async_maybe_transform({"device_id": device_id}, esim_install_params.EsimInstallParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimInstallResponse, - ) - - async def install_status( - 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, - ) -> EsimInstallStatusResponse: - """ - Returns the eSIM's current install status, checking for a terminal outcome if an - install is still in progress. - - 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("/numbers/esims/{id}/install-status", id=id), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=EsimInstallStatusResponse, - ) - - async def selector( - self, - *, - page: int | Omit = omit, - page_size: 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, - ) -> EsimSelectorResponse: - """ - Returns a lightweight list (id, msisdn, carrierName, status, masked iccid) for - use in a message filter dropdown. Unlike `GET /esims`, this includes all - statuses, including retired eSIMs. - - 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 - """ - return await self._get( - "/numbers/esims/selector", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "page": page, - "page_size": page_size, - }, - esim_selector_params.EsimSelectorParams, - ), - ), - cast_to=EsimSelectorResponse, - ) - - -class EsimsResourceWithRawResponse: - def __init__(self, esims: EsimsResource) -> None: - self._esims = esims - - self.create = to_raw_response_wrapper( - esims.create, - ) - self.retrieve = to_raw_response_wrapper( - esims.retrieve, - ) - self.update = to_raw_response_wrapper( - esims.update, - ) - self.list = to_raw_response_wrapper( - esims.list, - ) - self.delete = to_raw_response_wrapper( - esims.delete, - ) - self.capacity = to_raw_response_wrapper( - esims.capacity, - ) - self.confirm_payment = to_raw_response_wrapper( - esims.confirm_payment, - ) - self.import_ = to_raw_response_wrapper( - esims.import_, - ) - self.install = to_raw_response_wrapper( - esims.install, - ) - self.install_status = to_raw_response_wrapper( - esims.install_status, - ) - self.selector = to_raw_response_wrapper( - esims.selector, - ) - - @cached_property - def messages(self) -> MessagesResourceWithRawResponse: - return MessagesResourceWithRawResponse(self._esims.messages) - - -class AsyncEsimsResourceWithRawResponse: - def __init__(self, esims: AsyncEsimsResource) -> None: - self._esims = esims - - self.create = async_to_raw_response_wrapper( - esims.create, - ) - self.retrieve = async_to_raw_response_wrapper( - esims.retrieve, - ) - self.update = async_to_raw_response_wrapper( - esims.update, - ) - self.list = async_to_raw_response_wrapper( - esims.list, - ) - self.delete = async_to_raw_response_wrapper( - esims.delete, - ) - self.capacity = async_to_raw_response_wrapper( - esims.capacity, - ) - self.confirm_payment = async_to_raw_response_wrapper( - esims.confirm_payment, - ) - self.import_ = async_to_raw_response_wrapper( - esims.import_, - ) - self.install = async_to_raw_response_wrapper( - esims.install, - ) - self.install_status = async_to_raw_response_wrapper( - esims.install_status, - ) - self.selector = async_to_raw_response_wrapper( - esims.selector, - ) - - @cached_property - def messages(self) -> AsyncMessagesResourceWithRawResponse: - return AsyncMessagesResourceWithRawResponse(self._esims.messages) - - -class EsimsResourceWithStreamingResponse: - def __init__(self, esims: EsimsResource) -> None: - self._esims = esims - - self.create = to_streamed_response_wrapper( - esims.create, - ) - self.retrieve = to_streamed_response_wrapper( - esims.retrieve, - ) - self.update = to_streamed_response_wrapper( - esims.update, - ) - self.list = to_streamed_response_wrapper( - esims.list, - ) - self.delete = to_streamed_response_wrapper( - esims.delete, - ) - self.capacity = to_streamed_response_wrapper( - esims.capacity, - ) - self.confirm_payment = to_streamed_response_wrapper( - esims.confirm_payment, - ) - self.import_ = to_streamed_response_wrapper( - esims.import_, - ) - self.install = to_streamed_response_wrapper( - esims.install, - ) - self.install_status = to_streamed_response_wrapper( - esims.install_status, - ) - self.selector = to_streamed_response_wrapper( - esims.selector, - ) - - @cached_property - def messages(self) -> MessagesResourceWithStreamingResponse: - return MessagesResourceWithStreamingResponse(self._esims.messages) - - -class AsyncEsimsResourceWithStreamingResponse: - def __init__(self, esims: AsyncEsimsResource) -> None: - self._esims = esims - - self.create = async_to_streamed_response_wrapper( - esims.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - esims.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - esims.update, - ) - self.list = async_to_streamed_response_wrapper( - esims.list, - ) - self.delete = async_to_streamed_response_wrapper( - esims.delete, - ) - self.capacity = async_to_streamed_response_wrapper( - esims.capacity, - ) - self.confirm_payment = async_to_streamed_response_wrapper( - esims.confirm_payment, - ) - self.import_ = async_to_streamed_response_wrapper( - esims.import_, - ) - self.install = async_to_streamed_response_wrapper( - esims.install, - ) - self.install_status = async_to_streamed_response_wrapper( - esims.install_status, - ) - self.selector = async_to_streamed_response_wrapper( - esims.selector, - ) - - @cached_property - def messages(self) -> AsyncMessagesResourceWithStreamingResponse: - return AsyncMessagesResourceWithStreamingResponse(self._esims.messages) diff --git a/src/mobilerun_sdk/resources/esims/messages.py b/src/mobilerun_sdk/resources/esims/messages.py deleted file mode 100644 index f6d7efad..00000000 --- a/src/mobilerun_sdk/resources/esims/messages.py +++ /dev/null @@ -1,352 +0,0 @@ -# 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 ...types.esims import message_list_params, message_send_params -from ..._base_client import make_request_options -from ...types.esims.message_list_response import MessageListResponse -from ...types.esims.message_send_response import MessageSendResponse - -__all__ = ["MessagesResource", "AsyncMessagesResource"] - - -class MessagesResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> MessagesResourceWithRawResponse: - """ - 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/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers - """ - return MessagesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> MessagesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response - """ - return MessagesResourceWithStreamingResponse(self) - - def list( - self, - id: str, - *, - direction: Literal["all", "inbound", "outbound"] | Omit = omit, - number_id: str | Omit = omit, - page: int | Omit = omit, - page_size: int | Omit = omit, - peer_key: str | Omit = omit, - peer_number: str | Omit = omit, - status: Literal[ - "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed" - ] - | 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, - ) -> MessageListResponse: - """ - List messages for one eSIM - - 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("/numbers/esims/{id}/messages", id=id), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "direction": direction, - "number_id": number_id, - "page": page, - "page_size": page_size, - "peer_key": peer_key, - "peer_number": peer_number, - "status": status, - }, - message_list_params.MessageListParams, - ), - ), - cast_to=MessageListResponse, - ) - - def send( - self, - id: str, - *, - body: str, - to: str, - client_request_id: str | Omit = omit, - delivery_report: 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, - ) -> MessageSendResponse: - """ - Send an SMS through one eSIM - - Args: - body: SMS body text (max 320 chars — smaller than the admin tier's cap; see the - schema's own doc comment for why) - - to: Recipient phone number — normalized to E.164 (spaces/dashes/dots stripped); - rejected with 400 if it doesn't validate as E.164 afterward. - - client_request_id: Client-supplied idempotency key, scoped to (owner, esimId, key). Replaying the - same key + identical payload returns the original send; the same key with a - DIFFERENT payload is a 409 conflict. - - delivery_report: Wait for physedge to confirm carrier delivery before completing the send (adds - executor-side latency, never on this request — sends are always async/202). - Defaults to false for the public tier (opt-in, unlike the admin tier's - default-true). - - 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("/numbers/esims/{id}/messages", id=id), - body=maybe_transform( - { - "body": body, - "to": to, - "client_request_id": client_request_id, - "delivery_report": delivery_report, - }, - message_send_params.MessageSendParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=MessageSendResponse, - ) - - -class AsyncMessagesResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncMessagesResourceWithRawResponse: - """ - 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/droidrun/mobilerun-sdk-python#accessing-raw-response-data-eg-headers - """ - return AsyncMessagesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncMessagesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/droidrun/mobilerun-sdk-python#with_streaming_response - """ - return AsyncMessagesResourceWithStreamingResponse(self) - - async def list( - self, - id: str, - *, - direction: Literal["all", "inbound", "outbound"] | Omit = omit, - number_id: str | Omit = omit, - page: int | Omit = omit, - page_size: int | Omit = omit, - peer_key: str | Omit = omit, - peer_number: str | Omit = omit, - status: Literal[ - "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed" - ] - | 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, - ) -> MessageListResponse: - """ - List messages for one eSIM - - 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("/numbers/esims/{id}/messages", 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( - { - "direction": direction, - "number_id": number_id, - "page": page, - "page_size": page_size, - "peer_key": peer_key, - "peer_number": peer_number, - "status": status, - }, - message_list_params.MessageListParams, - ), - ), - cast_to=MessageListResponse, - ) - - async def send( - self, - id: str, - *, - body: str, - to: str, - client_request_id: str | Omit = omit, - delivery_report: 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, - ) -> MessageSendResponse: - """ - Send an SMS through one eSIM - - Args: - body: SMS body text (max 320 chars — smaller than the admin tier's cap; see the - schema's own doc comment for why) - - to: Recipient phone number — normalized to E.164 (spaces/dashes/dots stripped); - rejected with 400 if it doesn't validate as E.164 afterward. - - client_request_id: Client-supplied idempotency key, scoped to (owner, esimId, key). Replaying the - same key + identical payload returns the original send; the same key with a - DIFFERENT payload is a 409 conflict. - - delivery_report: Wait for physedge to confirm carrier delivery before completing the send (adds - executor-side latency, never on this request — sends are always async/202). - Defaults to false for the public tier (opt-in, unlike the admin tier's - default-true). - - 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("/numbers/esims/{id}/messages", id=id), - body=await async_maybe_transform( - { - "body": body, - "to": to, - "client_request_id": client_request_id, - "delivery_report": delivery_report, - }, - message_send_params.MessageSendParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=MessageSendResponse, - ) - - -class MessagesResourceWithRawResponse: - def __init__(self, messages: MessagesResource) -> None: - self._messages = messages - - self.list = to_raw_response_wrapper( - messages.list, - ) - self.send = to_raw_response_wrapper( - messages.send, - ) - - -class AsyncMessagesResourceWithRawResponse: - def __init__(self, messages: AsyncMessagesResource) -> None: - self._messages = messages - - self.list = async_to_raw_response_wrapper( - messages.list, - ) - self.send = async_to_raw_response_wrapper( - messages.send, - ) - - -class MessagesResourceWithStreamingResponse: - def __init__(self, messages: MessagesResource) -> None: - self._messages = messages - - self.list = to_streamed_response_wrapper( - messages.list, - ) - self.send = to_streamed_response_wrapper( - messages.send, - ) - - -class AsyncMessagesResourceWithStreamingResponse: - def __init__(self, messages: AsyncMessagesResource) -> None: - self._messages = messages - - self.list = async_to_streamed_response_wrapper( - messages.list, - ) - self.send = async_to_streamed_response_wrapper( - messages.send, - ) diff --git a/src/mobilerun_sdk/resources/mailboxes/mailboxes.py b/src/mobilerun_sdk/resources/mailboxes/mailboxes.py index 0a62f3c9..50e03570 100644 --- a/src/mobilerun_sdk/resources/mailboxes/mailboxes.py +++ b/src/mobilerun_sdk/resources/mailboxes/mailboxes.py @@ -75,7 +75,8 @@ def create( self, *, client_request_id: str, - billing_preference: Literal["included", "rent"] | Omit = omit, + billing_preference: Literal["included", "included_only", "rent"] | Omit = omit, + domain_id: str | Omit = omit, label: str | Omit = omit, local_part: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -85,22 +86,22 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxCreateResponse: - """ - Reserves a permanently-allocated, individually-rented mailbox and starts an - Autumn rental checkout. An optional localPart selects the full address local - part; omitting it keeps the default random, non-guessable mx\\__-prefixed address. - The address is withheld until the first payment is confirmed. Idempotent on - (owner, clientRequestId): same key + payload replays (200); a conflicting or - already-held local part returns 409. 201 when the checkout URL is already - persisted, otherwise 202 (poll GET for the URL). + """Creates a mailbox on the default domain or a connected custom domain. + + An + optional `localPart` selects the address. Replaying the same `clientRequestId` + and payload returns the original mailbox. Poll the mailbox when a 202 response + does not yet include a checkout URL. Args: - billing_preference: Funding preference. Omit or use included for included-first activation; rent - always preserves package capacity and starts paid checkout. + billing_preference: included uses package capacity when available and otherwise starts paid + checkout; included_only fails without creating a paid reservation when no + included slot remains; rent always starts paid checkout. + + domain_id: Optional active custom mailbox domain owned by the caller. Omit to use the + system domain. - local_part: Optional full mailbox local part (the address before "@"). Trimmed and - lowercased before validation. Omit for a random, non-guessable mx\\__-prefixed - address. + local_part: Optional mailbox name before the "@". Omit to generate a random address. extra_headers: Send extra headers @@ -116,6 +117,7 @@ def create( { "client_request_id": client_request_id, "billing_preference": billing_preference, + "domain_id": domain_id, "label": label, "local_part": local_part, }, @@ -248,12 +250,9 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxDeleteResponse: - """For paid rent, schedules end-of-cycle cancellation. - - For an included generation, - archives immediately and releases its package seat. This never deletes the - mailbox, its address, or its messages — the address is permanently reserved. - Idempotent. + """ + Cancels a pending mailbox or schedules an active paid mailbox for cancellation. + Existing addresses and messages are retained. Repeating the request is safe. Args: extra_headers: Send extra headers @@ -284,10 +283,7 @@ def capacity( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxCapacityResponse: - """ - Returns the authoritative number of package-funded mailbox claims currently - available after local reservations. - """ + """Returns the number of mailboxes currently available through included capacity.""" return self._get( "/mailboxes/capacity", options=make_request_options( @@ -311,10 +307,10 @@ def otp( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxOtpResponse: - """ - Returns the highest-confidence, most recent OTP for the mailbox, restricted to - messages of completed/active paid intervals. Does not wait server-side (SDKs - poll). 200 with the best code, 204 when none matches. + """Returns the most likely recent OTP for the mailbox. + + Returns 204 when no matching + code is available. Args: extra_headers: Send extra headers @@ -351,7 +347,7 @@ def restart( self, mailbox_id: str, *, - billing_preference: Literal["included", "rent"] | Omit = omit, + billing_preference: Literal["included", "included_only", "rent"] | 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, @@ -359,13 +355,15 @@ def restart( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxRestartResponse: - """ - Starts a new generation on an archived mailbox, reusing the same permanent - address. Uses included capacity first unless paid rent is requested. + """Restarts an archived mailbox with the same address. + + Uses included capacity when + available unless paid service is requested. Args: - billing_preference: Funding preference. Omit or use included for included-first activation; rent - always preserves package capacity and starts paid checkout. + billing_preference: included uses package capacity when available and otherwise starts paid + checkout; included_only fails without creating a paid reservation when no + included slot remains; rent always starts paid checkout. extra_headers: Send extra headers @@ -399,10 +397,10 @@ def uncancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxUncancelResponse: - """Retracts a scheduled end-of-cycle cancellation for the current generation. + """Withdraws a scheduled cancellation. - Only - valid while cancellation is pending. + Only available while cancellation is + pending. Args: extra_headers: Send extra headers @@ -452,7 +450,8 @@ async def create( self, *, client_request_id: str, - billing_preference: Literal["included", "rent"] | Omit = omit, + billing_preference: Literal["included", "included_only", "rent"] | Omit = omit, + domain_id: str | Omit = omit, label: str | Omit = omit, local_part: str | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -462,22 +461,22 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxCreateResponse: - """ - Reserves a permanently-allocated, individually-rented mailbox and starts an - Autumn rental checkout. An optional localPart selects the full address local - part; omitting it keeps the default random, non-guessable mx\\__-prefixed address. - The address is withheld until the first payment is confirmed. Idempotent on - (owner, clientRequestId): same key + payload replays (200); a conflicting or - already-held local part returns 409. 201 when the checkout URL is already - persisted, otherwise 202 (poll GET for the URL). + """Creates a mailbox on the default domain or a connected custom domain. + + An + optional `localPart` selects the address. Replaying the same `clientRequestId` + and payload returns the original mailbox. Poll the mailbox when a 202 response + does not yet include a checkout URL. Args: - billing_preference: Funding preference. Omit or use included for included-first activation; rent - always preserves package capacity and starts paid checkout. + billing_preference: included uses package capacity when available and otherwise starts paid + checkout; included_only fails without creating a paid reservation when no + included slot remains; rent always starts paid checkout. + + domain_id: Optional active custom mailbox domain owned by the caller. Omit to use the + system domain. - local_part: Optional full mailbox local part (the address before "@"). Trimmed and - lowercased before validation. Omit for a random, non-guessable mx\\__-prefixed - address. + local_part: Optional mailbox name before the "@". Omit to generate a random address. extra_headers: Send extra headers @@ -493,6 +492,7 @@ async def create( { "client_request_id": client_request_id, "billing_preference": billing_preference, + "domain_id": domain_id, "label": label, "local_part": local_part, }, @@ -625,12 +625,9 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxDeleteResponse: - """For paid rent, schedules end-of-cycle cancellation. - - For an included generation, - archives immediately and releases its package seat. This never deletes the - mailbox, its address, or its messages — the address is permanently reserved. - Idempotent. + """ + Cancels a pending mailbox or schedules an active paid mailbox for cancellation. + Existing addresses and messages are retained. Repeating the request is safe. Args: extra_headers: Send extra headers @@ -661,10 +658,7 @@ async def capacity( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxCapacityResponse: - """ - Returns the authoritative number of package-funded mailbox claims currently - available after local reservations. - """ + """Returns the number of mailboxes currently available through included capacity.""" return await self._get( "/mailboxes/capacity", options=make_request_options( @@ -688,10 +682,10 @@ async def otp( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxOtpResponse: - """ - Returns the highest-confidence, most recent OTP for the mailbox, restricted to - messages of completed/active paid intervals. Does not wait server-side (SDKs - poll). 200 with the best code, 204 when none matches. + """Returns the most likely recent OTP for the mailbox. + + Returns 204 when no matching + code is available. Args: extra_headers: Send extra headers @@ -728,7 +722,7 @@ async def restart( self, mailbox_id: str, *, - billing_preference: Literal["included", "rent"] | Omit = omit, + billing_preference: Literal["included", "included_only", "rent"] | 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, @@ -736,13 +730,15 @@ async def restart( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxRestartResponse: - """ - Starts a new generation on an archived mailbox, reusing the same permanent - address. Uses included capacity first unless paid rent is requested. + """Restarts an archived mailbox with the same address. + + Uses included capacity when + available unless paid service is requested. Args: - billing_preference: Funding preference. Omit or use included for included-first activation; rent - always preserves package capacity and starts paid checkout. + billing_preference: included uses package capacity when available and otherwise starts paid + checkout; included_only fails without creating a paid reservation when no + included slot remains; rent always starts paid checkout. extra_headers: Send extra headers @@ -776,10 +772,10 @@ async def uncancel( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MailboxUncancelResponse: - """Retracts a scheduled end-of-cycle cancellation for the current generation. + """Withdraws a scheduled cancellation. - Only - valid while cancellation is pending. + Only available while cancellation is + pending. Args: extra_headers: Send extra headers diff --git a/src/mobilerun_sdk/resources/mailboxes/messages.py b/src/mobilerun_sdk/resources/mailboxes/messages.py index d1baa1f8..2e7c54cd 100644 --- a/src/mobilerun_sdk/resources/mailboxes/messages.py +++ b/src/mobilerun_sdk/resources/mailboxes/messages.py @@ -101,8 +101,8 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageListResponse: """ - Lists messages for a mailbox with keyset pagination and time/sender/hasOtp - filters for polling. + Lists mailbox messages with cursor pagination and optional time, sender, and OTP + filters. Args: extra_headers: Send extra headers @@ -212,8 +212,8 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageListResponse: """ - Lists messages for a mailbox with keyset pagination and time/sender/hasOtp - filters for polling. + Lists mailbox messages with cursor pagination and optional time, sender, and OTP + filters. Args: extra_headers: Send extra headers diff --git a/src/mobilerun_sdk/resources/messages/conversations.py b/src/mobilerun_sdk/resources/messages/conversations.py index 9ef14bfa..397a5a3e 100644 --- a/src/mobilerun_sdk/resources/messages/conversations.py +++ b/src/mobilerun_sdk/resources/messages/conversations.py @@ -60,19 +60,10 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationListResponse: - """Lists the caller's own SMS conversations, one row per thread. + """Lists SMS conversations by recent activity. - Each row includes - the most recent message in the thread, its unread inbound count, and the eSIMs - it was seen through. Optional `esimId` or `numberId` narrows to threads on one - eSIM or number. - - Cursor-paginated via `limit` (default 20, max 100) and - `cursorLastOccurredAt`/`cursorLastMessageId` (both required together, taken from - a previous page's `nextCursor`). Pagination follows each thread's most recent - activity rather than a fixed snapshot, so a thread with new activity can move - ahead of an in-progress page fetch. Clients that need a stable ordering should - snapshot their own view. + Use both cursor fields from + `nextCursor` to fetch the next page. Args: extra_headers: Send extra headers @@ -118,10 +109,8 @@ def mark_read( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationMarkReadResponse: """ - Marks the caller's own inbound messages in a conversation thread as read, up to - and including the given `(upToOccurredAt, upToMessageId)` cursor — typically a - conversation row's `lastMessage`. Idempotent: repeating the call with the same - cursor updates 0 rows. Returns the number of rows updated. + Marks inbound messages in a conversation as read through the supplied cursor. + Repeating the request is safe. Args: peer_key: The thread's canonical peer key (see GET .../conversations) @@ -189,19 +178,10 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationListResponse: - """Lists the caller's own SMS conversations, one row per thread. - - Each row includes - the most recent message in the thread, its unread inbound count, and the eSIMs - it was seen through. Optional `esimId` or `numberId` narrows to threads on one - eSIM or number. + """Lists SMS conversations by recent activity. - Cursor-paginated via `limit` (default 20, max 100) and - `cursorLastOccurredAt`/`cursorLastMessageId` (both required together, taken from - a previous page's `nextCursor`). Pagination follows each thread's most recent - activity rather than a fixed snapshot, so a thread with new activity can move - ahead of an in-progress page fetch. Clients that need a stable ordering should - snapshot their own view. + Use both cursor fields from + `nextCursor` to fetch the next page. Args: extra_headers: Send extra headers @@ -247,10 +227,8 @@ async def mark_read( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> ConversationMarkReadResponse: """ - Marks the caller's own inbound messages in a conversation thread as read, up to - and including the given `(upToOccurredAt, upToMessageId)` cursor — typically a - conversation row's `lastMessage`. Idempotent: repeating the call with the same - cursor updates 0 rows. Returns the number of rows updated. + Marks inbound messages in a conversation as read through the supplied cursor. + Repeating the request is safe. Args: peer_key: The thread's canonical peer key (see GET .../conversations) diff --git a/src/mobilerun_sdk/resources/messages/messages.py b/src/mobilerun_sdk/resources/messages/messages.py index 2e5f30b6..49cc99a2 100644 --- a/src/mobilerun_sdk/resources/messages/messages.py +++ b/src/mobilerun_sdk/resources/messages/messages.py @@ -76,12 +76,9 @@ def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageListResponse: - """Lists the caller's own SMS messages, newest first. - - Supports filtering by - direction, esimId, numberId, status, peerNumber (substring search, min 3 - characters), and peerKey (exact thread match). Each row includes its canonical - thread key (`peerKey`). + """ + Lists SMS messages newest first, with filters for direction, eSIM, phone number, + status, and conversation. Args: extra_headers: Send extra headers @@ -162,12 +159,9 @@ async def list( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> MessageListResponse: - """Lists the caller's own SMS messages, newest first. - - Supports filtering by - direction, esimId, numberId, status, peerNumber (substring search, min 3 - characters), and peerKey (exact thread match). Each row includes its canonical - thread key (`peerKey`). + """ + Lists SMS messages newest first, with filters for direction, eSIM, phone number, + status, and conversation. Args: extra_headers: Send extra headers diff --git a/src/mobilerun_sdk/resources/numbers/numbers.py b/src/mobilerun_sdk/resources/numbers/numbers.py index 7b39353f..25bd6717 100644 --- a/src/mobilerun_sdk/resources/numbers/numbers.py +++ b/src/mobilerun_sdk/resources/numbers/numbers.py @@ -65,7 +65,7 @@ def with_streaming_response(self) -> NumbersResourceWithStreamingResponse: def create( self, *, - billing_preference: Literal["included", "rent"] | Omit = omit, + billing_preference: Literal["included", "included_only", "rent"] | Omit = omit, country: str | Omit = omit, label: Optional[str] | Omit = omit, purpose: str | Omit = omit, @@ -77,24 +77,23 @@ def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NumberCreateResponse: - """Starts a Mobilerun Phone purchase for the authenticated owner. + """Starts a phone-number purchase. - Accepted requests - always return the same asynchronous envelope; poll GET /numbers/phones/{id} for - its business state. `purpose` and `country` are mutually exclusive. + Poll the returned phone number for status + updates. `purpose` and `country` cannot be combined. Args: - billing_preference: Prefer a free package seat ('included', default) or force the paid checkout - ('rent') + billing_preference: Use included capacity when available, require included capacity without paid + fallback (included_only), or start a paid checkout (rent). - country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/countries. Cannot be - combined with `purpose`. + country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/phones/countries. + Cannot be combined with `purpose`. label: User-defined display label — NFC-normalized, up to 100 GRAPHEMES (not UTF-16 code units; an emoji/flag may span several). Display-only, never used for routing. Also seeds the billing entity name at purchase. - purpose: Optional Mobilerun Phone purpose slug from GET /numbers/purposes. + purpose: Optional purpose from GET /numbers/phones/purposes. idempotency_key: Optional request idempotency key. @@ -169,13 +168,10 @@ def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NumberUpdateResponse: - """Updates the phone number's user-defined display label. + """Updates the display label. - Omitting `label` leaves - it unchanged; setting it to null or an empty string clears it. The label is - capped at 100 characters, is display-only, and never affects routing. It also - seeds the billing entity name when set at purchase time; a later change here - does not rename the already-created billing entity. + Omitting `label` leaves it unchanged; null or an + empty string clears it. Args: label: User-defined display label — NFC-normalized, up to 100 GRAPHEMES (not UTF-16 @@ -214,8 +210,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NumberListResponse: """ - Lists phone numbers owned by the authenticated user — both BYO (`user`) and - provisioned (`mobilerun`) numbers. + Lists the caller's phone numbers. Args: extra_headers: Send extra headers @@ -255,25 +250,10 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NumberDeleteResponse: - """Cancels a Mobilerun Phone. - - The outcome depends on the number's current state: - - - If the number is still awaiting payment and no payment for it is currently - being processed, the checkout is closed immediately and the number is retired. - - If the number is on the standard paid plan and already paid and in service, - cancellation is scheduled for the end of the current billing period rather - than taking effect immediately. The number stays usable through the period - already paid for, with no partial refund. Calling this again while a - cancellation is already scheduled is a no-op that returns the same result. The - response's `state` reflects this as `cancel_scheduled` with - `cancelAtPeriodEnd: true`; `currentPeriodEnd` is populated once billing - confirms the cancellation. - - Any other state (already refunding, a permanent billing failure, a payment - currently being processed, an included-plan number, or a non-hosted/BYO number) - returns 409 `not_cancellable`. Returns 404 if the number doesn't exist or isn't - owned by the caller. + """ + Cancels a pending purchase or schedules cancellation of an active paid phone + number. Repeating a scheduled cancellation is safe. Returns 409 when + cancellation is not available. Args: extra_headers: Send extra headers @@ -304,10 +284,7 @@ def countries( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NumberCountriesResponse: - """ - Lists the countries currently offered for a dedicated Mobilerun Phone, with live - stock status. Pass `country` as the `country` field on POST /numbers/phones. - """ + """Lists available countries and current phone-number availability.""" return self._get( "/numbers/phones/countries", options=make_request_options( @@ -363,7 +340,7 @@ def with_streaming_response(self) -> AsyncNumbersResourceWithStreamingResponse: async def create( self, *, - billing_preference: Literal["included", "rent"] | Omit = omit, + billing_preference: Literal["included", "included_only", "rent"] | Omit = omit, country: str | Omit = omit, label: Optional[str] | Omit = omit, purpose: str | Omit = omit, @@ -375,24 +352,23 @@ async def create( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NumberCreateResponse: - """Starts a Mobilerun Phone purchase for the authenticated owner. + """Starts a phone-number purchase. - Accepted requests - always return the same asynchronous envelope; poll GET /numbers/phones/{id} for - its business state. `purpose` and `country` are mutually exclusive. + Poll the returned phone number for status + updates. `purpose` and `country` cannot be combined. Args: - billing_preference: Prefer a free package seat ('included', default) or force the paid checkout - ('rent') + billing_preference: Use included capacity when available, require included capacity without paid + fallback (included_only), or start a paid checkout (rent). - country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/countries. Cannot be - combined with `purpose`. + country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/phones/countries. + Cannot be combined with `purpose`. label: User-defined display label — NFC-normalized, up to 100 GRAPHEMES (not UTF-16 code units; an emoji/flag may span several). Display-only, never used for routing. Also seeds the billing entity name at purchase. - purpose: Optional Mobilerun Phone purpose slug from GET /numbers/purposes. + purpose: Optional purpose from GET /numbers/phones/purposes. idempotency_key: Optional request idempotency key. @@ -467,13 +443,10 @@ async def update( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NumberUpdateResponse: - """Updates the phone number's user-defined display label. + """Updates the display label. - Omitting `label` leaves - it unchanged; setting it to null or an empty string clears it. The label is - capped at 100 characters, is display-only, and never affects routing. It also - seeds the billing entity name when set at purchase time; a later change here - does not rename the already-created billing entity. + Omitting `label` leaves it unchanged; null or an + empty string clears it. Args: label: User-defined display label — NFC-normalized, up to 100 GRAPHEMES (not UTF-16 @@ -512,8 +485,7 @@ async def list( timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NumberListResponse: """ - Lists phone numbers owned by the authenticated user — both BYO (`user`) and - provisioned (`mobilerun`) numbers. + Lists the caller's phone numbers. Args: extra_headers: Send extra headers @@ -553,25 +525,10 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NumberDeleteResponse: - """Cancels a Mobilerun Phone. - - The outcome depends on the number's current state: - - - If the number is still awaiting payment and no payment for it is currently - being processed, the checkout is closed immediately and the number is retired. - - If the number is on the standard paid plan and already paid and in service, - cancellation is scheduled for the end of the current billing period rather - than taking effect immediately. The number stays usable through the period - already paid for, with no partial refund. Calling this again while a - cancellation is already scheduled is a no-op that returns the same result. The - response's `state` reflects this as `cancel_scheduled` with - `cancelAtPeriodEnd: true`; `currentPeriodEnd` is populated once billing - confirms the cancellation. - - Any other state (already refunding, a permanent billing failure, a payment - currently being processed, an included-plan number, or a non-hosted/BYO number) - returns 409 `not_cancellable`. Returns 404 if the number doesn't exist or isn't - owned by the caller. + """ + Cancels a pending purchase or schedules cancellation of an active paid phone + number. Repeating a scheduled cancellation is safe. Returns 409 when + cancellation is not available. Args: extra_headers: Send extra headers @@ -602,10 +559,7 @@ async def countries( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> NumberCountriesResponse: - """ - Lists the countries currently offered for a dedicated Mobilerun Phone, with live - stock status. Pass `country` as the `country` field on POST /numbers/phones. - """ + """Lists available countries and current phone-number availability.""" return await self._get( "/numbers/phones/countries", options=make_request_options( diff --git a/src/mobilerun_sdk/resources/tasks/tasks.py b/src/mobilerun_sdk/resources/tasks/tasks.py index e73ca6bb..c6656997 100644 --- a/src/mobilerun_sdk/resources/tasks/tasks.py +++ b/src/mobilerun_sdk/resources/tasks/tasks.py @@ -121,7 +121,10 @@ def list( page: int | Omit = omit, page_size: int | Omit = omit, query: Optional[str] | Omit = omit, - status: Optional[Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]] + source: Optional[Literal["api", "agent"]] | Omit = omit, + status: Optional[ + Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] + ] | 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. @@ -140,6 +143,8 @@ def list( query: Search in task description. + source: Only tasks created via the API ('api') or spawned by an agent step ('agent'). + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -164,6 +169,7 @@ def list( "page": page, "page_size": page_size, "query": query, + "source": source, "status": status, }, task_list_params.TaskListParams, @@ -278,7 +284,6 @@ def run( device_id: str, task: str, accessibility: bool | Omit = omit, - agent_id: int | Omit = omit, apps: SequenceNotStr[str] | Omit = omit, continue_on_failure: bool | Omit = omit, credentials: Iterable[task_run_params.Credential] | Omit = omit, @@ -287,11 +292,12 @@ def run( files: SequenceNotStr[str] | Omit = omit, llm_model: str | Omit = omit, max_steps: int | Omit = omit, - memory_namespace: str | Omit = omit, output_schema: Optional[Dict[str, object]] | Omit = omit, reasoning: bool | Omit = omit, + recording_enabled: bool | Omit = omit, stealth: bool | Omit = omit, subagent_model: str | Omit = omit, + system_prompt: Optional[str] | Omit = omit, temperature: float | Omit = omit, vision: bool | Omit = omit, vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit, @@ -313,12 +319,19 @@ def run( display_id: The display ID of the device to run the task on. - llm_model: The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash') + execution_timeout: Maximum agent execution time in seconds (1–2700). + + llm_model: The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna') - memory_namespace: Memory namespace for cross-task personalization + recording_enabled: Record device video for the whole task and persist a retrievable reference subagent_model: LLM model used by sub-agent roles: executor, app_opener, structured_output + system_prompt: Optional custom behavioral overlay applied on top of the agent's default system + prompts. Never echoed back in responses or errors. + + temperature: Deprecated and ignored. Sampling behavior is controlled by the model provider. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -335,7 +348,6 @@ def run( "device_id": device_id, "task": task, "accessibility": accessibility, - "agent_id": agent_id, "apps": apps, "continue_on_failure": continue_on_failure, "credentials": credentials, @@ -344,11 +356,12 @@ def run( "files": files, "llm_model": llm_model, "max_steps": max_steps, - "memory_namespace": memory_namespace, "output_schema": output_schema, "reasoning": reasoning, + "recording_enabled": recording_enabled, "stealth": stealth, "subagent_model": subagent_model, + "system_prompt": system_prompt, "temperature": temperature, "vision": vision, "vpn_country": vpn_country, @@ -367,7 +380,6 @@ def run_streamed( device_id: str, task: str, accessibility: bool | Omit = omit, - agent_id: int | Omit = omit, apps: SequenceNotStr[str] | Omit = omit, continue_on_failure: bool | Omit = omit, credentials: Iterable[task_run_streamed_params.Credential] | Omit = omit, @@ -376,11 +388,12 @@ def run_streamed( files: SequenceNotStr[str] | Omit = omit, llm_model: str | Omit = omit, max_steps: int | Omit = omit, - memory_namespace: str | Omit = omit, output_schema: Optional[Dict[str, object]] | Omit = omit, reasoning: bool | Omit = omit, + recording_enabled: bool | Omit = omit, stealth: bool | Omit = omit, subagent_model: str | Omit = omit, + system_prompt: Optional[str] | Omit = omit, temperature: float | Omit = omit, vision: bool | Omit = omit, vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit, @@ -400,12 +413,19 @@ def run_streamed( display_id: The display ID of the device to run the task on. - llm_model: The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash') + execution_timeout: Maximum agent execution time in seconds (1–2700). - memory_namespace: Memory namespace for cross-task personalization + llm_model: The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna') + + recording_enabled: Record device video for the whole task and persist a retrievable reference subagent_model: LLM model used by sub-agent roles: executor, app_opener, structured_output + system_prompt: Optional custom behavioral overlay applied on top of the agent's default system + prompts. Never echoed back in responses or errors. + + temperature: Deprecated and ignored. Sampling behavior is controlled by the model provider. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -421,7 +441,6 @@ def run_streamed( "device_id": device_id, "task": task, "accessibility": accessibility, - "agent_id": agent_id, "apps": apps, "continue_on_failure": continue_on_failure, "credentials": credentials, @@ -430,11 +449,12 @@ def run_streamed( "files": files, "llm_model": llm_model, "max_steps": max_steps, - "memory_namespace": memory_namespace, "output_schema": output_schema, "reasoning": reasoning, + "recording_enabled": recording_enabled, "stealth": stealth, "subagent_model": subagent_model, + "system_prompt": system_prompt, "temperature": temperature, "vision": vision, "vpn_country": vpn_country, @@ -597,7 +617,10 @@ async def list( page: int | Omit = omit, page_size: int | Omit = omit, query: Optional[str] | Omit = omit, - status: Optional[Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]] + source: Optional[Literal["api", "agent"]] | Omit = omit, + status: Optional[ + Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] + ] | 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. @@ -616,6 +639,8 @@ async def list( query: Search in task description. + source: Only tasks created via the API ('api') or spawned by an agent step ('agent'). + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -640,6 +665,7 @@ async def list( "page": page, "page_size": page_size, "query": query, + "source": source, "status": status, }, task_list_params.TaskListParams, @@ -754,7 +780,6 @@ async def run( device_id: str, task: str, accessibility: bool | Omit = omit, - agent_id: int | Omit = omit, apps: SequenceNotStr[str] | Omit = omit, continue_on_failure: bool | Omit = omit, credentials: Iterable[task_run_params.Credential] | Omit = omit, @@ -763,11 +788,12 @@ async def run( files: SequenceNotStr[str] | Omit = omit, llm_model: str | Omit = omit, max_steps: int | Omit = omit, - memory_namespace: str | Omit = omit, output_schema: Optional[Dict[str, object]] | Omit = omit, reasoning: bool | Omit = omit, + recording_enabled: bool | Omit = omit, stealth: bool | Omit = omit, subagent_model: str | Omit = omit, + system_prompt: Optional[str] | Omit = omit, temperature: float | Omit = omit, vision: bool | Omit = omit, vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit, @@ -789,12 +815,19 @@ async def run( display_id: The display ID of the device to run the task on. - llm_model: The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash') + execution_timeout: Maximum agent execution time in seconds (1–2700). + + llm_model: The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna') - memory_namespace: Memory namespace for cross-task personalization + recording_enabled: Record device video for the whole task and persist a retrievable reference subagent_model: LLM model used by sub-agent roles: executor, app_opener, structured_output + system_prompt: Optional custom behavioral overlay applied on top of the agent's default system + prompts. Never echoed back in responses or errors. + + temperature: Deprecated and ignored. Sampling behavior is controlled by the model provider. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -811,7 +844,6 @@ async def run( "device_id": device_id, "task": task, "accessibility": accessibility, - "agent_id": agent_id, "apps": apps, "continue_on_failure": continue_on_failure, "credentials": credentials, @@ -820,11 +852,12 @@ async def run( "files": files, "llm_model": llm_model, "max_steps": max_steps, - "memory_namespace": memory_namespace, "output_schema": output_schema, "reasoning": reasoning, + "recording_enabled": recording_enabled, "stealth": stealth, "subagent_model": subagent_model, + "system_prompt": system_prompt, "temperature": temperature, "vision": vision, "vpn_country": vpn_country, @@ -843,7 +876,6 @@ async def run_streamed( device_id: str, task: str, accessibility: bool | Omit = omit, - agent_id: int | Omit = omit, apps: SequenceNotStr[str] | Omit = omit, continue_on_failure: bool | Omit = omit, credentials: Iterable[task_run_streamed_params.Credential] | Omit = omit, @@ -852,11 +884,12 @@ async def run_streamed( files: SequenceNotStr[str] | Omit = omit, llm_model: str | Omit = omit, max_steps: int | Omit = omit, - memory_namespace: str | Omit = omit, output_schema: Optional[Dict[str, object]] | Omit = omit, reasoning: bool | Omit = omit, + recording_enabled: bool | Omit = omit, stealth: bool | Omit = omit, subagent_model: str | Omit = omit, + system_prompt: Optional[str] | Omit = omit, temperature: float | Omit = omit, vision: bool | Omit = omit, vpn_country: Optional[Literal["US", "BR", "FR", "DE", "IN", "JP", "KR", "ZA"]] | Omit = omit, @@ -876,12 +909,19 @@ async def run_streamed( display_id: The display ID of the device to run the task on. - llm_model: The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash') + execution_timeout: Maximum agent execution time in seconds (1–2700). - memory_namespace: Memory namespace for cross-task personalization + llm_model: The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna') + + recording_enabled: Record device video for the whole task and persist a retrievable reference subagent_model: LLM model used by sub-agent roles: executor, app_opener, structured_output + system_prompt: Optional custom behavioral overlay applied on top of the agent's default system + prompts. Never echoed back in responses or errors. + + temperature: Deprecated and ignored. Sampling behavior is controlled by the model provider. + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -897,7 +937,6 @@ async def run_streamed( "device_id": device_id, "task": task, "accessibility": accessibility, - "agent_id": agent_id, "apps": apps, "continue_on_failure": continue_on_failure, "credentials": credentials, @@ -906,11 +945,12 @@ async def run_streamed( "files": files, "llm_model": llm_model, "max_steps": max_steps, - "memory_namespace": memory_namespace, "output_schema": output_schema, "reasoning": reasoning, + "recording_enabled": recording_enabled, "stealth": stealth, "subagent_model": subagent_model, + "system_prompt": system_prompt, "temperature": temperature, "vision": vision, "vpn_country": vpn_country, diff --git a/src/mobilerun_sdk/resources/workflows/executions.py b/src/mobilerun_sdk/resources/workflows/executions.py index cb7e5a19..cc3f03bd 100644 --- a/src/mobilerun_sdk/resources/workflows/executions.py +++ b/src/mobilerun_sdk/resources/workflows/executions.py @@ -86,6 +86,7 @@ def list( *, flow_id: str | Omit = omit, from_: Optional[str] | Omit = omit, + invocation_id: str | Omit = omit, order_by: Literal["startedAt", "finishedAt", "status"] | Omit = omit, order_by_direction: Literal["asc", "desc"] | Omit = omit, page: int | Omit = omit, @@ -104,8 +105,9 @@ def list( """Return a paginated history of flow executions. Supports filtering by `flowId`, - `triggerId`, `status`, and a `from`/`to` time range, plus free-text `search` and - ordering by startedAt, finishedAt, or status. + `triggerId`, `invocationId` (the client/verify key), `status`, and a `from`/`to` + time range, plus free-text `search` and ordering by startedAt, finishedAt, or + status. Args: extra_headers: Send extra headers @@ -127,6 +129,7 @@ def list( { "flow_id": flow_id, "from_": from_, + "invocation_id": invocation_id, "order_by": order_by, "order_by_direction": order_by_direction, "page": page, @@ -284,6 +287,7 @@ async def list( *, flow_id: str | Omit = omit, from_: Optional[str] | Omit = omit, + invocation_id: str | Omit = omit, order_by: Literal["startedAt", "finishedAt", "status"] | Omit = omit, order_by_direction: Literal["asc", "desc"] | Omit = omit, page: int | Omit = omit, @@ -302,8 +306,9 @@ async def list( """Return a paginated history of flow executions. Supports filtering by `flowId`, - `triggerId`, `status`, and a `from`/`to` time range, plus free-text `search` and - ordering by startedAt, finishedAt, or status. + `triggerId`, `invocationId` (the client/verify key), `status`, and a `from`/`to` + time range, plus free-text `search` and ordering by startedAt, finishedAt, or + status. Args: extra_headers: Send extra headers @@ -325,6 +330,7 @@ async def list( { "flow_id": flow_id, "from_": from_, + "invocation_id": invocation_id, "order_by": order_by, "order_by_direction": order_by_direction, "page": page, diff --git a/src/mobilerun_sdk/resources/workflows/flows/actions.py b/src/mobilerun_sdk/resources/workflows/flows/actions.py index 0fd2150d..26ca8773 100644 --- a/src/mobilerun_sdk/resources/workflows/flows/actions.py +++ b/src/mobilerun_sdk/resources/workflows/flows/actions.py @@ -91,6 +91,7 @@ def add( name_override: str | Omit = omit, overrides: Optional[action_add_params.Overrides] | Omit = omit, parent_flow_action_id: Optional[str] | Omit = omit, + recording_enabled: 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, @@ -126,6 +127,7 @@ def add( "name_override": name_override, "overrides": overrides, "parent_flow_action_id": parent_flow_action_id, + "recording_enabled": recording_enabled, }, action_add_params.ActionAddParams, ), @@ -277,6 +279,7 @@ async def add( name_override: str | Omit = omit, overrides: Optional[action_add_params.Overrides] | Omit = omit, parent_flow_action_id: Optional[str] | Omit = omit, + recording_enabled: 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, @@ -312,6 +315,7 @@ async def add( "name_override": name_override, "overrides": overrides, "parent_flow_action_id": parent_flow_action_id, + "recording_enabled": recording_enabled, }, action_add_params.ActionAddParams, ), diff --git a/src/mobilerun_sdk/resources/workflows/flows/flows.py b/src/mobilerun_sdk/resources/workflows/flows/flows.py index db390fcc..adb266d1 100644 --- a/src/mobilerun_sdk/resources/workflows/flows/flows.py +++ b/src/mobilerun_sdk/resources/workflows/flows/flows.py @@ -86,6 +86,7 @@ def create( notify_on_success: bool | Omit = omit, notify_webhook_id: Optional[str] | Omit = omit, recording_enabled: bool | Omit = omit, + recording_policy: flow_create_params.RecordingPolicy | Omit = omit, self_healing_enabled: bool | Omit = omit, self_healing_max_attempts: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -102,6 +103,9 @@ def create( success or failure. Args: + recording_enabled: Deprecated compatibility field. true maps to recordingPolicy.mode="flow"; false + maps to "off". + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -127,6 +131,7 @@ def create( "notify_on_success": notify_on_success, "notify_webhook_id": notify_webhook_id, "recording_enabled": recording_enabled, + "recording_policy": recording_policy, "self_healing_enabled": self_healing_enabled, "self_healing_max_attempts": self_healing_max_attempts, }, @@ -182,11 +187,13 @@ def update( device_ids: SequenceNotStr[str] | Omit = omit, enabled: bool | Omit = omit, health_monitoring_enabled: bool | Omit = omit, + lifecycle_status: Literal["enabled", "disabled"] | Omit = omit, name: str | Omit = omit, notify_on_failure: bool | Omit = omit, notify_on_success: bool | Omit = omit, notify_webhook_id: Optional[str] | Omit = omit, recording_enabled: bool | Omit = omit, + recording_policy: flow_update_params.RecordingPolicy | Omit = omit, self_healing_enabled: bool | Omit = omit, self_healing_max_attempts: int | Omit = omit, trigger_id: str | Omit = omit, @@ -204,6 +211,11 @@ def update( does not exist. Args: + lifecycle_status: Set the visible agent lifecycle. Archive remains available only through DELETE. + + recording_enabled: Deprecated compatibility field. true maps to recordingPolicy.mode="flow"; false + maps to "off". + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -224,11 +236,13 @@ def update( "device_ids": device_ids, "enabled": enabled, "health_monitoring_enabled": health_monitoring_enabled, + "lifecycle_status": lifecycle_status, "name": name, "notify_on_failure": notify_on_failure, "notify_on_success": notify_on_success, "notify_webhook_id": notify_webhook_id, "recording_enabled": recording_enabled, + "recording_policy": recording_policy, "self_healing_enabled": self_healing_enabled, "self_healing_max_attempts": self_healing_max_attempts, "trigger_id": trigger_id, @@ -318,9 +332,10 @@ def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FlowDeleteResponse: - """Delete a flow by its ID. + """Terminally archive a flow by its ID. - Returns 404 if no flow matches. + Archived flows cannot be restored and are + hidden from customer reads. Repeating the request is idempotent for the owner. Args: extra_headers: Send extra headers @@ -543,6 +558,7 @@ async def create( notify_on_success: bool | Omit = omit, notify_webhook_id: Optional[str] | Omit = omit, recording_enabled: bool | Omit = omit, + recording_policy: flow_create_params.RecordingPolicy | Omit = omit, self_healing_enabled: bool | Omit = omit, self_healing_max_attempts: int | Omit = omit, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -559,6 +575,9 @@ async def create( success or failure. Args: + recording_enabled: Deprecated compatibility field. true maps to recordingPolicy.mode="flow"; false + maps to "off". + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -584,6 +603,7 @@ async def create( "notify_on_success": notify_on_success, "notify_webhook_id": notify_webhook_id, "recording_enabled": recording_enabled, + "recording_policy": recording_policy, "self_healing_enabled": self_healing_enabled, "self_healing_max_attempts": self_healing_max_attempts, }, @@ -639,11 +659,13 @@ async def update( device_ids: SequenceNotStr[str] | Omit = omit, enabled: bool | Omit = omit, health_monitoring_enabled: bool | Omit = omit, + lifecycle_status: Literal["enabled", "disabled"] | Omit = omit, name: str | Omit = omit, notify_on_failure: bool | Omit = omit, notify_on_success: bool | Omit = omit, notify_webhook_id: Optional[str] | Omit = omit, recording_enabled: bool | Omit = omit, + recording_policy: flow_update_params.RecordingPolicy | Omit = omit, self_healing_enabled: bool | Omit = omit, self_healing_max_attempts: int | Omit = omit, trigger_id: str | Omit = omit, @@ -661,6 +683,11 @@ async def update( does not exist. Args: + lifecycle_status: Set the visible agent lifecycle. Archive remains available only through DELETE. + + recording_enabled: Deprecated compatibility field. true maps to recordingPolicy.mode="flow"; false + maps to "off". + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -681,11 +708,13 @@ async def update( "device_ids": device_ids, "enabled": enabled, "health_monitoring_enabled": health_monitoring_enabled, + "lifecycle_status": lifecycle_status, "name": name, "notify_on_failure": notify_on_failure, "notify_on_success": notify_on_success, "notify_webhook_id": notify_webhook_id, "recording_enabled": recording_enabled, + "recording_policy": recording_policy, "self_healing_enabled": self_healing_enabled, "self_healing_max_attempts": self_healing_max_attempts, "trigger_id": trigger_id, @@ -775,9 +804,10 @@ async def delete( extra_body: Body | None = None, timeout: float | httpx.Timeout | None | NotGiven = not_given, ) -> FlowDeleteResponse: - """Delete a flow by its ID. + """Terminally archive a flow by its ID. - Returns 404 if no flow matches. + Archived flows cannot be restored and are + hidden from customer reads. Repeating the request is idempotent for the owner. Args: extra_headers: Send extra headers diff --git a/src/mobilerun_sdk/resources/workflows/triggers.py b/src/mobilerun_sdk/resources/workflows/triggers.py index d569d1eb..752cd1dd 100644 --- a/src/mobilerun_sdk/resources/workflows/triggers.py +++ b/src/mobilerun_sdk/resources/workflows/triggers.py @@ -291,6 +291,7 @@ def fire( trigger_id: str, *, payload: Dict[str, object], + invocation_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, @@ -322,6 +323,10 @@ def fire( Validated against the trigger's customPayloadSchema when one is configured; otherwise only "must be a JSON object" is enforced. + invocation_id: Optional client-supplied idempotency key. When provided, a flow that already has + an execution for this (flow, invocationId) is skipped and `deduplicated` is + true. When omitted a fresh server-side id is generated (no dedup). + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -334,7 +339,13 @@ def fire( raise ValueError(f"Expected a non-empty value for `trigger_id` but received {trigger_id!r}") return self._post( path_template("/triggers/{trigger_id}/fire", trigger_id=trigger_id), - body=maybe_transform({"payload": payload}, trigger_fire_params.TriggerFireParams), + body=maybe_transform( + { + "payload": payload, + "invocation_id": invocation_id, + }, + trigger_fire_params.TriggerFireParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), @@ -604,6 +615,7 @@ async def fire( trigger_id: str, *, payload: Dict[str, object], + invocation_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, @@ -635,6 +647,10 @@ async def fire( Validated against the trigger's customPayloadSchema when one is configured; otherwise only "must be a JSON object" is enforced. + invocation_id: Optional client-supplied idempotency key. When provided, a flow that already has + an execution for this (flow, invocationId) is skipped and `deduplicated` is + true. When omitted a fresh server-side id is generated (no dedup). + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -647,7 +663,13 @@ async def fire( raise ValueError(f"Expected a non-empty value for `trigger_id` but received {trigger_id!r}") return await self._post( path_template("/triggers/{trigger_id}/fire", trigger_id=trigger_id), - body=await async_maybe_transform({"payload": payload}, trigger_fire_params.TriggerFireParams), + body=await async_maybe_transform( + { + "payload": payload, + "invocation_id": invocation_id, + }, + trigger_fire_params.TriggerFireParams, + ), options=make_request_options( extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout ), diff --git a/src/mobilerun_sdk/types/__init__.py b/src/mobilerun_sdk/types/__init__.py index 310d2f0f..1748d456 100644 --- a/src/mobilerun_sdk/types/__init__.py +++ b/src/mobilerun_sdk/types/__init__.py @@ -17,17 +17,12 @@ ) from .app_list_params import AppListParams as AppListParams from .task_run_params import TaskRunParams as TaskRunParams -from .esim_list_params import EsimListParams as EsimListParams from .file_list_params import FileListParams as FileListParams from .task_list_params import TaskListParams as TaskListParams from .app_list_response import AppListResponse as AppListResponse from .proxy_list_params import ProxyListParams as ProxyListParams from .task_run_response import TaskRunResponse as TaskRunResponse from .device_list_params import DeviceListParams as DeviceListParams -from .esim_create_params import EsimCreateParams as EsimCreateParams -from .esim_import_params import EsimImportParams as EsimImportParams -from .esim_list_response import EsimListResponse as EsimListResponse -from .esim_update_params import EsimUpdateParams as EsimUpdateParams from .file_list_response import FileListResponse as FileListResponse from .file_update_params import FileUpdateParams as FileUpdateParams from .mailbox_otp_params import MailboxOtpParams as MailboxOtpParams @@ -36,7 +31,6 @@ from .task_stop_response import TaskStopResponse as TaskStopResponse from .app_delete_response import AppDeleteResponse as AppDeleteResponse from .carrier_list_params import CarrierListParams as CarrierListParams -from .esim_install_params import EsimInstallParams as EsimInstallParams from .mailbox_list_params import MailboxListParams as MailboxListParams from .message_list_params import MessageListParams as MessageListParams from .model_list_response import ModelListResponse as ModelListResponse @@ -48,10 +42,6 @@ from .webhook_list_params import WebhookListParams as WebhookListParams from .device_create_params import DeviceCreateParams as DeviceCreateParams from .device_list_response import DeviceListResponse as DeviceListResponse -from .esim_create_response import EsimCreateResponse as EsimCreateResponse -from .esim_import_response import EsimImportResponse as EsimImportResponse -from .esim_selector_params import EsimSelectorParams as EsimSelectorParams -from .esim_update_response import EsimUpdateResponse as EsimUpdateResponse from .file_delete_response import FileDeleteResponse as FileDeleteResponse from .file_update_response import FileUpdateResponse as FileUpdateResponse from .mailbox_otp_response import MailboxOtpResponse as MailboxOtpResponse @@ -65,7 +55,6 @@ from .carrier_lookup_params import CarrierLookupParams as CarrierLookupParams from .carrier_update_params import CarrierUpdateParams as CarrierUpdateParams from .device_count_response import DeviceCountResponse as DeviceCountResponse -from .esim_install_response import EsimInstallResponse as EsimInstallResponse from .file_confirm_response import FileConfirmResponse as FileConfirmResponse from .mailbox_create_params import MailboxCreateParams as MailboxCreateParams from .mailbox_list_response import MailboxListResponse as MailboxListResponse @@ -84,9 +73,6 @@ from .credential_list_params import CredentialListParams as CredentialListParams from .device_create_response import DeviceCreateResponse as DeviceCreateResponse from .device_set_name_params import DeviceSetNameParams as DeviceSetNameParams -from .esim_capacity_response import EsimCapacityResponse as EsimCapacityResponse -from .esim_retrieve_response import EsimRetrieveResponse as EsimRetrieveResponse -from .esim_selector_response import EsimSelectorResponse as EsimSelectorResponse from .file_upload_url_params import FileUploadURLParams as FileUploadURLParams from .mailbox_restart_params import MailboxRestartParams as MailboxRestartParams from .number_create_response import NumberCreateResponse as NumberCreateResponse @@ -134,11 +120,9 @@ from .app_confirm_upload_response import AppConfirmUploadResponse as AppConfirmUploadResponse from .app_event_retrieve_response import AppEventRetrieveResponse as AppEventRetrieveResponse from .device_fingerprint_response import DeviceFingerprintResponse as DeviceFingerprintResponse -from .esim_install_status_response import EsimInstallStatusResponse as EsimInstallStatusResponse from .file_cancel_pending_response import FileCancelPendingResponse as FileCancelPendingResponse from .task_get_trajectory_response import TaskGetTrajectoryResponse as TaskGetTrajectoryResponse from .webhook_event_types_response import WebhookEventTypesResponse as WebhookEventTypesResponse -from .esim_confirm_payment_response import EsimConfirmPaymentResponse as EsimConfirmPaymentResponse from .notification_catalog_response import NotificationCatalogResponse as NotificationCatalogResponse from .webhook_rotate_secret_response import WebhookRotateSecretResponse as WebhookRotateSecretResponse from .webhook_test_delivery_response import WebhookTestDeliveryResponse as WebhookTestDeliveryResponse diff --git a/src/mobilerun_sdk/types/app_storage_usage_response.py b/src/mobilerun_sdk/types/app_storage_usage_response.py index f1c225ec..f9dd47c4 100644 --- a/src/mobilerun_sdk/types/app_storage_usage_response.py +++ b/src/mobilerun_sdk/types/app_storage_usage_response.py @@ -9,12 +9,19 @@ class Data(BaseModel): available_bytes: float = FieldInfo(alias="availableBytes") - """Remaining bytes — the reliable maximum size for the next upload. + """Remaining bytes — the reliable maximum TOTAL size for the next upload. Advisory snapshot: the quota is enforced under a lock at confirm, so concurrent uploads may reduce actual headroom. """ + max_file_bytes: float = FieldInfo(alias="maxFileBytes") + """Per-file upload cap in bytes (env.MAX_UPLOAD_FILE_BYTES). + + A single file larger than this is rejected at confirm even when it fits the + remaining quota. Source of truth for the client-side per-file limit. + """ + quota_bytes: float = FieldInfo(alias="quotaBytes") """Total storage allowance for the user, in bytes""" diff --git a/src/mobilerun_sdk/types/assistant/conversation_abort_params.py b/src/mobilerun_sdk/types/assistant/conversation_abort_params.py index ced9a891..7c15bc34 100644 --- a/src/mobilerun_sdk/types/assistant/conversation_abort_params.py +++ b/src/mobilerun_sdk/types/assistant/conversation_abort_params.py @@ -11,3 +11,5 @@ class ConversationAbortParams(TypedDict, total=False): session_id: Required[Annotated[str, PropertyInfo(alias="sessionId")]] + + expected_turn_id: Annotated[str, PropertyInfo(alias="expectedTurnId")] diff --git a/src/mobilerun_sdk/types/assistant/conversation_history_response.py b/src/mobilerun_sdk/types/assistant/conversation_history_response.py index 8288033a..3adbc2e3 100644 --- a/src/mobilerun_sdk/types/assistant/conversation_history_response.py +++ b/src/mobilerun_sdk/types/assistant/conversation_history_response.py @@ -8,7 +8,7 @@ from ..._models import BaseModel -__all__ = ["ConversationHistoryResponse", "Message", "MessagePart", "MessageMetadata"] +__all__ = ["ConversationHistoryResponse", "Message", "MessagePart", "MessageMetadata", "TurnState"] class MessagePart(BaseModel): @@ -60,9 +60,33 @@ class Message(BaseModel): """Deprecated: use createdBy.""" +class TurnState(BaseModel): + id: str + + abort_requested: bool = FieldInfo(alias="abortRequested") + + attachable: bool + + claim_held: bool = FieldInfo(alias="claimHeld") + + outcome: Optional[str] = None + + phase: Literal["created", "running", "closed", "delivered", "failed"] + + reaping: bool + + revision: int + + started_at: str = FieldInfo(alias="startedAt") + + class ConversationHistoryResponse(BaseModel): messages: List[Message] turn_active: bool = FieldInfo(alias="turnActive") + last_turn_outcome: Optional[str] = FieldInfo(alias="lastTurnOutcome", default=None) + truncated: Optional[bool] = None + + turn_state: Optional[TurnState] = FieldInfo(alias="turnState", default=None) diff --git a/src/mobilerun_sdk/types/connect/proxy_buy_params.py b/src/mobilerun_sdk/types/connect/proxy_buy_params.py index b8147750..8426ebeb 100644 --- a/src/mobilerun_sdk/types/connect/proxy_buy_params.py +++ b/src/mobilerun_sdk/types/connect/proxy_buy_params.py @@ -2,7 +2,9 @@ from __future__ import annotations -from typing_extensions import Literal, Required, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict + +from ..._utils import PropertyInfo __all__ = ["ProxyBuyParams"] @@ -12,3 +14,5 @@ class ProxyBuyParams(TypedDict, total=False): """ISO 3166-1 alpha-2 country code to provision the proxy in.""" type: Required[Literal["dedicated_residential", "residential", "mobile"]] + + idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] diff --git a/src/mobilerun_sdk/types/connect/proxy_buy_response.py b/src/mobilerun_sdk/types/connect/proxy_buy_response.py index 403a8d80..d512bbef 100644 --- a/src/mobilerun_sdk/types/connect/proxy_buy_response.py +++ b/src/mobilerun_sdk/types/connect/proxy_buy_response.py @@ -27,20 +27,23 @@ class ProxyBuyResponse(BaseModel): port: int - status: Literal["pending_payment", "provisioning", "active", "cancelling", "ended", "error"] + status: Literal["checking", "pending_payment", "provisioning", "active", "cancelling", "ended", "error"] """Lifecycle of a proxy. - A freshly created proxy is `provisioning` — or `pending_payment` until the - customer completes checkout — and becomes `active` once its upstream is - assigned. `cancelling` retains full access through the paid period; when the - subscription expires the proxy is `ended`. `error` marks a failed provisioning - attempt. + A freshly created proxy is `checking` while its billing identity is being + resolved — clients should poll until a `paymentUrl` or a later status appears — + then `provisioning` — or `pending_payment` until the customer completes checkout + — and becomes `active` once its upstream is assigned. `cancelling` retains full + access through the paid period; when the subscription expires the proxy is + `ended`. `error` marks a failed provisioning attempt. """ type: Literal["dedicated_residential", "residential", "mobile"] username: str + billing_mode: Optional[Literal["included", "standalone_paid"]] = FieldInfo(alias="billingMode", default=None) + payment_url: Optional[str] = FieldInfo(alias="paymentUrl", default=None) """Checkout URL to complete payment while status is `pending_payment`. diff --git a/src/mobilerun_sdk/types/connect/proxy_list_response.py b/src/mobilerun_sdk/types/connect/proxy_list_response.py index 26135dca..e68fd457 100644 --- a/src/mobilerun_sdk/types/connect/proxy_list_response.py +++ b/src/mobilerun_sdk/types/connect/proxy_list_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional from datetime import datetime from typing_extensions import Literal @@ -25,20 +25,23 @@ class Item(BaseModel): port: int - status: Literal["pending_payment", "provisioning", "active", "cancelling", "ended", "error"] + status: Literal["checking", "pending_payment", "provisioning", "active", "cancelling", "ended", "error"] """Lifecycle of a proxy. - A freshly created proxy is `provisioning` — or `pending_payment` until the - customer completes checkout — and becomes `active` once its upstream is - assigned. `cancelling` retains full access through the paid period; when the - subscription expires the proxy is `ended`. `error` marks a failed provisioning - attempt. + A freshly created proxy is `checking` while its billing identity is being + resolved — clients should poll until a `paymentUrl` or a later status appears — + then `provisioning` — or `pending_payment` until the customer completes checkout + — and becomes `active` once its upstream is assigned. `cancelling` retains full + access through the paid period; when the subscription expires the proxy is + `ended`. `error` marks a failed provisioning attempt. """ type: Literal["dedicated_residential", "residential", "mobile"] username: str + billing_mode: Optional[Literal["included", "standalone_paid"]] = FieldInfo(alias="billingMode", default=None) + class Pagination(BaseModel): """Pagination metadata for a list response.""" diff --git a/src/mobilerun_sdk/types/connect/proxy_retrieve_response.py b/src/mobilerun_sdk/types/connect/proxy_retrieve_response.py index be8cd872..41014606 100644 --- a/src/mobilerun_sdk/types/connect/proxy_retrieve_response.py +++ b/src/mobilerun_sdk/types/connect/proxy_retrieve_response.py @@ -27,20 +27,23 @@ class ProxyRetrieveResponse(BaseModel): port: int - status: Literal["pending_payment", "provisioning", "active", "cancelling", "ended", "error"] + status: Literal["checking", "pending_payment", "provisioning", "active", "cancelling", "ended", "error"] """Lifecycle of a proxy. - A freshly created proxy is `provisioning` — or `pending_payment` until the - customer completes checkout — and becomes `active` once its upstream is - assigned. `cancelling` retains full access through the paid period; when the - subscription expires the proxy is `ended`. `error` marks a failed provisioning - attempt. + A freshly created proxy is `checking` while its billing identity is being + resolved — clients should poll until a `paymentUrl` or a later status appears — + then `provisioning` — or `pending_payment` until the customer completes checkout + — and becomes `active` once its upstream is assigned. `cancelling` retains full + access through the paid period; when the subscription expires the proxy is + `ended`. `error` marks a failed provisioning attempt. """ type: Literal["dedicated_residential", "residential", "mobile"] username: str + billing_mode: Optional[Literal["included", "standalone_paid"]] = FieldInfo(alias="billingMode", default=None) + payment_url: Optional[str] = FieldInfo(alias="paymentUrl", default=None) """Checkout URL to complete payment while status is `pending_payment`. diff --git a/src/mobilerun_sdk/types/device_create_response.py b/src/mobilerun_sdk/types/device_create_response.py index c792c9f7..307565c2 100644 --- a/src/mobilerun_sdk/types/device_create_response.py +++ b/src/mobilerun_sdk/types/device_create_response.py @@ -2,6 +2,7 @@ from typing import Optional from datetime import datetime +from typing_extensions import Literal from pydantic import Field as FieldInfo @@ -21,6 +22,9 @@ class DeviceCreateResponse(BaseModel): name: str + platform: Literal["android", "ios"] + """Operating system the device runs.""" + state: str state_message: str = FieldInfo(alias="stateMessage") diff --git a/src/mobilerun_sdk/types/device_list_response.py b/src/mobilerun_sdk/types/device_list_response.py index f8c1a26a..e4c0e942 100644 --- a/src/mobilerun_sdk/types/device_list_response.py +++ b/src/mobilerun_sdk/types/device_list_response.py @@ -2,6 +2,7 @@ from typing import List, Optional from datetime import datetime +from typing_extensions import Literal from pydantic import Field as FieldInfo @@ -22,6 +23,9 @@ class Item(BaseModel): name: str + platform: Literal["android", "ios"] + """Operating system the device runs.""" + state: str state_message: str = FieldInfo(alias="stateMessage") diff --git a/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py b/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py index 2e02c5ea..f5a6020c 100644 --- a/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py +++ b/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py @@ -42,6 +42,8 @@ class Capabilities(BaseModel): proxy: bool + recording: bool + reset: bool shell: bool @@ -54,6 +56,8 @@ class Capabilities(BaseModel): time: bool + traffic_inspection: bool = FieldInfo(alias="trafficInspection") + class DeviceRetrieveCapabilitiesResponse(BaseModel): capabilities: Capabilities diff --git a/src/mobilerun_sdk/types/device_retrieve_response.py b/src/mobilerun_sdk/types/device_retrieve_response.py index 6735522c..be523d09 100644 --- a/src/mobilerun_sdk/types/device_retrieve_response.py +++ b/src/mobilerun_sdk/types/device_retrieve_response.py @@ -2,6 +2,7 @@ from typing import Optional from datetime import datetime +from typing_extensions import Literal from pydantic import Field as FieldInfo @@ -21,6 +22,9 @@ class DeviceRetrieveResponse(BaseModel): name: str + platform: Literal["android", "ios"] + """Operating system the device runs.""" + state: str state_message: str = FieldInfo(alias="stateMessage") diff --git a/src/mobilerun_sdk/types/device_set_name_response.py b/src/mobilerun_sdk/types/device_set_name_response.py index f7976eea..026ac9b1 100644 --- a/src/mobilerun_sdk/types/device_set_name_response.py +++ b/src/mobilerun_sdk/types/device_set_name_response.py @@ -2,6 +2,7 @@ from typing import Optional from datetime import datetime +from typing_extensions import Literal from pydantic import Field as FieldInfo @@ -21,6 +22,9 @@ class DeviceSetNameResponse(BaseModel): name: str + platform: Literal["android", "ios"] + """Operating system the device runs.""" + state: str state_message: str = FieldInfo(alias="stateMessage") diff --git a/src/mobilerun_sdk/types/device_wait_ready_response.py b/src/mobilerun_sdk/types/device_wait_ready_response.py index 73a50c61..d8de894d 100644 --- a/src/mobilerun_sdk/types/device_wait_ready_response.py +++ b/src/mobilerun_sdk/types/device_wait_ready_response.py @@ -2,6 +2,7 @@ from typing import Optional from datetime import datetime +from typing_extensions import Literal from pydantic import Field as FieldInfo @@ -21,6 +22,9 @@ class DeviceWaitReadyResponse(BaseModel): name: str + platform: Literal["android", "ios"] + """Operating system the device runs.""" + state: str state_message: str = FieldInfo(alias="stateMessage") diff --git a/src/mobilerun_sdk/types/devices/app_install_params.py b/src/mobilerun_sdk/types/devices/app_install_params.py index f419dd4e..3624dc3a 100644 --- a/src/mobilerun_sdk/types/devices/app_install_params.py +++ b/src/mobilerun_sdk/types/devices/app_install_params.py @@ -21,9 +21,21 @@ class Variant0(TypedDict, total=False): directly (200 on success, an error status on failure). """ + country: str + """Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. + + MY or SG). + """ + package_name: Annotated[str, PropertyInfo(alias="packageName")] """Android package name (e.g. com.example.app)""" + version_code: Annotated[int, PropertyInfo(alias="versionCode")] + """Optional exact app-library version code. + + Use with country when multiple regional versions share an identifier. + """ + x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")] @@ -41,6 +53,18 @@ class Variant1(TypedDict, total=False): bundle_id: Annotated[str, PropertyInfo(alias="bundleId")] """iOS bundle identifier (e.g. com.example.app)""" + country: str + """Optional ISO 3166-1 alpha-2 country of the uploaded app version (e.g. + + MY or SG). + """ + + version_code: Annotated[int, PropertyInfo(alias="versionCode")] + """Optional exact app-library version code. + + Use with country when multiple regional versions share an identifier. + """ + x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")] diff --git a/src/mobilerun_sdk/types/devices/app_list_installs_response.py b/src/mobilerun_sdk/types/devices/app_list_installs_response.py index 796f7b2a..ae079f10 100644 --- a/src/mobilerun_sdk/types/devices/app_list_installs_response.py +++ b/src/mobilerun_sdk/types/devices/app_list_installs_response.py @@ -28,11 +28,10 @@ class Install(BaseModel): updated_at: datetime = FieldInfo(alias="updatedAt") - error_class: Optional[str] = FieldInfo(alias="errorClass", default=None) - """Closed set: download_failed, adb_install_failed, panic, timeout, failed. - - Only present when status is failed. - """ + error_class: Optional[Literal["download_failed", "adb_install_failed", "panic", "timeout", "failed"]] = FieldInfo( + alias="errorClass", default=None + ) + """Only present when status is failed.""" class AppListInstallsResponse(BaseModel): diff --git a/src/mobilerun_sdk/types/devices/keyboard_write_params.py b/src/mobilerun_sdk/types/devices/keyboard_write_params.py index c1340d7a..7bff865f 100644 --- a/src/mobilerun_sdk/types/devices/keyboard_write_params.py +++ b/src/mobilerun_sdk/types/devices/keyboard_write_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing_extensions import Required, Annotated, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict from ..._utils import PropertyInfo @@ -14,6 +14,14 @@ class KeyboardWriteParams(TypedDict, total=False): clear: bool + completion_mode: Annotated[Literal["accepted", "committed"], PropertyInfo(alias="completionMode")] + """Completion guarantee. + + accepted returns after the input provider accepts the operation; committed + additionally waits for the focused UI state to contain the complete text or + become quiescent. + """ + error_rate: Annotated[float, PropertyInfo(alias="errorRate")] """Per-character mistake rate for humantouch typing. -1 uses server default.""" diff --git a/src/mobilerun_sdk/types/devices/recording_start_params.py b/src/mobilerun_sdk/types/devices/recording_start_params.py index 621a86aa..007181d3 100644 --- a/src/mobilerun_sdk/types/devices/recording_start_params.py +++ b/src/mobilerun_sdk/types/devices/recording_start_params.py @@ -14,6 +14,18 @@ class RecordingStartParams(TypedDict, total=False): name: str + quality: int + """Capture quality from 1 (lowest) to 10 (full stream quality). + + Defaults to the device's full quality. Honored by devices recording through the + portal stream bridge. + """ + retention_days: Annotated[int, PropertyInfo(alias="retentionDays")] types: Optional[SequenceNotStr[str]] + """ + Artifacts to capture: trajectory (input actions), video, and audio (captured + into the video artifact, so it requires video; honored by portal stream-bridge + recorders). Defaults to trajectory and video. + """ diff --git a/src/mobilerun_sdk/types/esim_capacity_response.py b/src/mobilerun_sdk/types/esim_capacity_response.py deleted file mode 100644 index 69204004..00000000 --- a/src/mobilerun_sdk/types/esim_capacity_response.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["EsimCapacityResponse", "Data"] - - -class Data(BaseModel): - available: bool - - free_devices: int = FieldInfo(alias="freeDevices") - - -class EsimCapacityResponse(BaseModel): - data: Data diff --git a/src/mobilerun_sdk/types/esim_confirm_payment_response.py b/src/mobilerun_sdk/types/esim_confirm_payment_response.py deleted file mode 100644 index d981ab88..00000000 --- a/src/mobilerun_sdk/types/esim_confirm_payment_response.py +++ /dev/null @@ -1,69 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["EsimConfirmPaymentResponse", "Data"] - - -class Data(BaseModel): - id: str - - carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) - - country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) - - device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) - - iccid: Optional[str] = None - - msisdn: Optional[str] = None - - name: Optional[str] = None - - network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) - - source: Literal["stocked", "byo"] - - status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] - - subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) - - checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) - - current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) - - exempt: Optional[bool] = None - - rent_status: Optional[ - Literal[ - "not_applicable", - "exempt", - "inactive", - "awaiting_payment", - "active", - "cancel_pending", - "refund_pending", - "retiring", - "billing_error", - ] - ] = FieldInfo(alias="rentStatus", default=None) - - -class EsimConfirmPaymentResponse(BaseModel): - data: Data diff --git a/src/mobilerun_sdk/types/esim_create_params.py b/src/mobilerun_sdk/types/esim_create_params.py deleted file mode 100644 index 973cbd1d..00000000 --- a/src/mobilerun_sdk/types/esim_create_params.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Annotated, TypedDict - -from .._utils import PropertyInfo - -__all__ = ["EsimCreateParams"] - - -class EsimCreateParams(TypedDict, total=False): - idempotency_key: Annotated[str, PropertyInfo(alias="idempotencyKey")] - """ - Client-supplied key; replaying the same key returns the original purchase - instead of buying again - """ - - name: Optional[str] - """Optional user-defined display label — NFC-normalized, up to 15 GRAPHEMES. - - Omit or null for no label. - """ diff --git a/src/mobilerun_sdk/types/esim_create_response.py b/src/mobilerun_sdk/types/esim_create_response.py deleted file mode 100644 index 11111f7a..00000000 --- a/src/mobilerun_sdk/types/esim_create_response.py +++ /dev/null @@ -1,69 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["EsimCreateResponse", "Data"] - - -class Data(BaseModel): - id: str - - carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) - - country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) - - device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) - - iccid: Optional[str] = None - - msisdn: Optional[str] = None - - name: Optional[str] = None - - network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) - - source: Literal["stocked", "byo"] - - status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] - - subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) - - checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) - - current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) - - exempt: Optional[bool] = None - - rent_status: Optional[ - Literal[ - "not_applicable", - "exempt", - "inactive", - "awaiting_payment", - "active", - "cancel_pending", - "refund_pending", - "retiring", - "billing_error", - ] - ] = FieldInfo(alias="rentStatus", default=None) - - -class EsimCreateResponse(BaseModel): - data: Data diff --git a/src/mobilerun_sdk/types/esim_import_params.py b/src/mobilerun_sdk/types/esim_import_params.py deleted file mode 100644 index 59433916..00000000 --- a/src/mobilerun_sdk/types/esim_import_params.py +++ /dev/null @@ -1,59 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Annotated, TypedDict - -from .._utils import PropertyInfo - -__all__ = ["EsimImportParams"] - - -class EsimImportParams(TypedDict, total=False): - auto_install: Annotated[bool, PropertyInfo(alias="autoInstall")] - """Rent OFF only: dispatch install-on-device immediately after a successful import. - - No-op when ESIM_BYO_RENT_ENABLED=true. - """ - - carrier_name: Annotated[str, PropertyInfo(alias="carrierName")] - - confirmation_code: Annotated[str, PropertyInfo(alias="confirmationCode")] - - country_code: Annotated[str, PropertyInfo(alias="countryCode")] - - device_id: Annotated[str, PropertyInfo(alias="deviceId")] - """physedge device id to auto-install onto; requires autoInstall:true and rent OFF. - - Omit for a random pool device. - """ - - idempotency_key: Annotated[str, PropertyInfo(alias="idempotencyKey")] - """ - Client-supplied key; replaying the same key+request returns the original import - instead of importing again - """ - - lpa_code: Annotated[str, PropertyInfo(alias="lpaCode")] - """Full LPA activation code""" - - matching_id: Annotated[str, PropertyInfo(alias="matchingId")] - - msisdn: str - """ - Self-reported E.164 MSISDN for this eSIM's line — an unverified label, never - used for routing - """ - - name: Optional[str] - """ - User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code - units; an emoji/flag may span several). Omit/null/empty/whitespace-only leaves - it unset. - """ - - notes: str - - smdp_address: Annotated[str, PropertyInfo(alias="smdpAddress")] - """SM-DP+ activation host — bare hostname ONLY, no port/scheme/path.""" diff --git a/src/mobilerun_sdk/types/esim_import_response.py b/src/mobilerun_sdk/types/esim_import_response.py deleted file mode 100644 index 5ab93dba..00000000 --- a/src/mobilerun_sdk/types/esim_import_response.py +++ /dev/null @@ -1,204 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union, Optional -from datetime import datetime -from typing_extensions import Literal, TypeAlias - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = [ - "EsimImportResponse", - "Data", - "DataPublicEsim", - "DataEsimAwaitingPaymentResponse", - "DataEsimAwaitingPaymentResponseEsim", - "DataEsimImportInstallDispatchFailedResponse", - "DataEsimImportInstallDispatchFailedResponseInstallDispatch", -] - - -class DataPublicEsim(BaseModel): - id: str - - carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) - - country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) - - device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) - - iccid: Optional[str] = None - - msisdn: Optional[str] = None - - name: Optional[str] = None - - network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) - - source: Literal["stocked", "byo"] - - status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] - - subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) - - checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) - - current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) - - exempt: Optional[bool] = None - - rent_status: Optional[ - Literal[ - "not_applicable", - "exempt", - "inactive", - "awaiting_payment", - "active", - "cancel_pending", - "refund_pending", - "retiring", - "billing_error", - ] - ] = FieldInfo(alias="rentStatus", default=None) - - -class DataEsimAwaitingPaymentResponseEsim(BaseModel): - id: str - - carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) - - country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) - - device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) - - iccid: Optional[str] = None - - msisdn: Optional[str] = None - - name: Optional[str] = None - - network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) - - source: Literal["stocked", "byo"] - - status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] - - subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) - - checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) - - current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) - - exempt: Optional[bool] = None - - rent_status: Optional[ - Literal[ - "not_applicable", - "exempt", - "inactive", - "awaiting_payment", - "active", - "cancel_pending", - "refund_pending", - "retiring", - "billing_error", - ] - ] = FieldInfo(alias="rentStatus", default=None) - - -class DataEsimAwaitingPaymentResponse(BaseModel): - checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) - - esim: DataEsimAwaitingPaymentResponseEsim - - rent_status: Literal["awaiting_payment"] = FieldInfo(alias="rentStatus") - - -class DataEsimImportInstallDispatchFailedResponseInstallDispatch(BaseModel): - ok: Literal[False] - - reason: str - - -class DataEsimImportInstallDispatchFailedResponse(BaseModel): - id: str - - carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) - - country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) - - device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) - - iccid: Optional[str] = None - - install_dispatch: DataEsimImportInstallDispatchFailedResponseInstallDispatch = FieldInfo(alias="installDispatch") - - msisdn: Optional[str] = None - - name: Optional[str] = None - - network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) - - source: Literal["stocked", "byo"] - - status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] - - subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) - - checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) - - current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) - - exempt: Optional[bool] = None - - rent_status: Optional[ - Literal[ - "not_applicable", - "exempt", - "inactive", - "awaiting_payment", - "active", - "cancel_pending", - "refund_pending", - "retiring", - "billing_error", - ] - ] = FieldInfo(alias="rentStatus", default=None) - - -Data: TypeAlias = Union[DataPublicEsim, DataEsimAwaitingPaymentResponse, DataEsimImportInstallDispatchFailedResponse] - - -class EsimImportResponse(BaseModel): - data: Data diff --git a/src/mobilerun_sdk/types/esim_install_params.py b/src/mobilerun_sdk/types/esim_install_params.py deleted file mode 100644 index ca23a433..00000000 --- a/src/mobilerun_sdk/types/esim_install_params.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Annotated, TypedDict - -from .._utils import PropertyInfo - -__all__ = ["EsimInstallParams"] - - -class EsimInstallParams(TypedDict, total=False): - device_id: Annotated[str, PropertyInfo(alias="deviceId")] - """physedge device id to install the eSIM onto; omit for a random pool device""" diff --git a/src/mobilerun_sdk/types/esim_install_response.py b/src/mobilerun_sdk/types/esim_install_response.py deleted file mode 100644 index 24ea2f92..00000000 --- a/src/mobilerun_sdk/types/esim_install_response.py +++ /dev/null @@ -1,69 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["EsimInstallResponse", "Data"] - - -class Data(BaseModel): - id: str - - carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) - - country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) - - device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) - - iccid: Optional[str] = None - - msisdn: Optional[str] = None - - name: Optional[str] = None - - network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) - - source: Literal["stocked", "byo"] - - status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] - - subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) - - checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) - - current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) - - exempt: Optional[bool] = None - - rent_status: Optional[ - Literal[ - "not_applicable", - "exempt", - "inactive", - "awaiting_payment", - "active", - "cancel_pending", - "refund_pending", - "retiring", - "billing_error", - ] - ] = FieldInfo(alias="rentStatus", default=None) - - -class EsimInstallResponse(BaseModel): - data: Data diff --git a/src/mobilerun_sdk/types/esim_install_status_response.py b/src/mobilerun_sdk/types/esim_install_status_response.py deleted file mode 100644 index 87f8c3e5..00000000 --- a/src/mobilerun_sdk/types/esim_install_status_response.py +++ /dev/null @@ -1,93 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["EsimInstallStatusResponse", "Data", "DataEsim"] - - -class DataEsim(BaseModel): - id: str - - carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) - - country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) - - device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) - - iccid: Optional[str] = None - - msisdn: Optional[str] = None - - name: Optional[str] = None - - network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) - - source: Literal["stocked", "byo"] - - status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] - - subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) - - checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) - - current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) - - exempt: Optional[bool] = None - - rent_status: Optional[ - Literal[ - "not_applicable", - "exempt", - "inactive", - "awaiting_payment", - "active", - "cancel_pending", - "refund_pending", - "retiring", - "billing_error", - ] - ] = FieldInfo(alias="rentStatus", default=None) - - -class Data(BaseModel): - esim: DataEsim - - operation_id: Optional[str] = FieldInfo(alias="operationId", default=None) - - status: Optional[ - Literal[ - "installing", - "pending_download", - "downloading", - "downloaded", - "enabling", - "configuring_apn", - "active", - "download_failed", - "enable_failed", - "download_outcome_unknown", - "install_failed", - "physical_removal_unconfirmed", - "deleted", - ] - ] = None - - -class EsimInstallStatusResponse(BaseModel): - data: Data diff --git a/src/mobilerun_sdk/types/esim_list_params.py b/src/mobilerun_sdk/types/esim_list_params.py deleted file mode 100644 index a653308b..00000000 --- a/src/mobilerun_sdk/types/esim_list_params.py +++ /dev/null @@ -1,20 +0,0 @@ -# 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__ = ["EsimListParams"] - - -class EsimListParams(TypedDict, total=False): - mine: Literal["true", "false"] - """Only include eSIMs created by the calling actor.""" - - page: int - - page_size: Annotated[int, PropertyInfo(alias="pageSize")] - - status: Literal["all", "in_stock", "owned", "installing", "installed", "install_failed", "retired"] diff --git a/src/mobilerun_sdk/types/esim_list_response.py b/src/mobilerun_sdk/types/esim_list_response.py deleted file mode 100644 index 5c236e21..00000000 --- a/src/mobilerun_sdk/types/esim_list_response.py +++ /dev/null @@ -1,72 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel -from .shared.pagination import Pagination - -__all__ = ["EsimListResponse", "Item"] - - -class Item(BaseModel): - id: str - - carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) - - country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) - - device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) - - iccid: Optional[str] = None - - msisdn: Optional[str] = None - - name: Optional[str] = None - - network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) - - source: Literal["stocked", "byo"] - - status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] - - subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) - - checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) - - current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) - - exempt: Optional[bool] = None - - rent_status: Optional[ - Literal[ - "not_applicable", - "exempt", - "inactive", - "awaiting_payment", - "active", - "cancel_pending", - "refund_pending", - "retiring", - "billing_error", - ] - ] = FieldInfo(alias="rentStatus", default=None) - - -class EsimListResponse(BaseModel): - items: List[Item] - - pagination: Pagination diff --git a/src/mobilerun_sdk/types/esim_retrieve_response.py b/src/mobilerun_sdk/types/esim_retrieve_response.py deleted file mode 100644 index 41cf5a88..00000000 --- a/src/mobilerun_sdk/types/esim_retrieve_response.py +++ /dev/null @@ -1,69 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["EsimRetrieveResponse", "Data"] - - -class Data(BaseModel): - id: str - - carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) - - country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) - - device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) - - iccid: Optional[str] = None - - msisdn: Optional[str] = None - - name: Optional[str] = None - - network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) - - source: Literal["stocked", "byo"] - - status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] - - subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) - - checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) - - current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) - - exempt: Optional[bool] = None - - rent_status: Optional[ - Literal[ - "not_applicable", - "exempt", - "inactive", - "awaiting_payment", - "active", - "cancel_pending", - "refund_pending", - "retiring", - "billing_error", - ] - ] = FieldInfo(alias="rentStatus", default=None) - - -class EsimRetrieveResponse(BaseModel): - data: Data diff --git a/src/mobilerun_sdk/types/esim_selector_params.py b/src/mobilerun_sdk/types/esim_selector_params.py deleted file mode 100644 index d5cd46c1..00000000 --- a/src/mobilerun_sdk/types/esim_selector_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Annotated, TypedDict - -from .._utils import PropertyInfo - -__all__ = ["EsimSelectorParams"] - - -class EsimSelectorParams(TypedDict, total=False): - page: int - - page_size: Annotated[int, PropertyInfo(alias="pageSize")] diff --git a/src/mobilerun_sdk/types/esim_selector_response.py b/src/mobilerun_sdk/types/esim_selector_response.py deleted file mode 100644 index 4288bcf9..00000000 --- a/src/mobilerun_sdk/types/esim_selector_response.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel -from .shared.pagination import Pagination - -__all__ = ["EsimSelectorResponse", "Item"] - - -class Item(BaseModel): - id: str - - carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) - - iccid: Optional[str] = None - - msisdn: Optional[str] = None - - name: Optional[str] = None - - source: Literal["stocked", "byo"] - - status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] - - -class EsimSelectorResponse(BaseModel): - items: List[Item] - - pagination: Pagination diff --git a/src/mobilerun_sdk/types/esim_update_params.py b/src/mobilerun_sdk/types/esim_update_params.py deleted file mode 100644 index a0fdc6de..00000000 --- a/src/mobilerun_sdk/types/esim_update_params.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import TypedDict - -__all__ = ["EsimUpdateParams"] - - -class EsimUpdateParams(TypedDict, total=False): - msisdn: Optional[str] - """Self-reported E.164 MSISDN for this eSIM's line. - - Omit to leave unchanged; null/empty clears it. An unverified label — never used - for routing. - """ - - name: Optional[str] - """ - User-defined display label — NFC-normalized, up to 15 GRAPHEMES (not UTF-16 code - units; an emoji/flag may span several). Omit to leave unchanged; - null/empty/whitespace-only clears it. - """ diff --git a/src/mobilerun_sdk/types/esim_update_response.py b/src/mobilerun_sdk/types/esim_update_response.py deleted file mode 100644 index 407eb7d9..00000000 --- a/src/mobilerun_sdk/types/esim_update_response.py +++ /dev/null @@ -1,69 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from .._models import BaseModel - -__all__ = ["EsimUpdateResponse", "Data"] - - -class Data(BaseModel): - id: str - - carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None) - - country_code: Optional[str] = FieldInfo(alias="countryCode", default=None) - - created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None) - - created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) - - device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) - - device_uuid: Optional[str] = FieldInfo(alias="deviceUuid", default=None) - - iccid: Optional[str] = None - - msisdn: Optional[str] = None - - name: Optional[str] = None - - network_status: Optional[Literal["degraded"]] = FieldInfo(alias="networkStatus", default=None) - - source: Literal["stocked", "byo"] - - status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"] - - subscription_id: Optional[int] = FieldInfo(alias="subscriptionId", default=None) - - updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) - - cancellation_scheduled: Optional[bool] = FieldInfo(alias="cancellationScheduled", default=None) - - checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None) - - current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) - - exempt: Optional[bool] = None - - rent_status: Optional[ - Literal[ - "not_applicable", - "exempt", - "inactive", - "awaiting_payment", - "active", - "cancel_pending", - "refund_pending", - "retiring", - "billing_error", - ] - ] = FieldInfo(alias="rentStatus", default=None) - - -class EsimUpdateResponse(BaseModel): - data: Data diff --git a/src/mobilerun_sdk/types/esims/__init__.py b/src/mobilerun_sdk/types/esims/__init__.py index d059c99c..f8ee8b14 100644 --- a/src/mobilerun_sdk/types/esims/__init__.py +++ b/src/mobilerun_sdk/types/esims/__init__.py @@ -1,8 +1,3 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from __future__ import annotations - -from .message_list_params import MessageListParams as MessageListParams -from .message_send_params import MessageSendParams as MessageSendParams -from .message_list_response import MessageListResponse as MessageListResponse -from .message_send_response import MessageSendResponse as MessageSendResponse diff --git a/src/mobilerun_sdk/types/esims/message_list_params.py b/src/mobilerun_sdk/types/esims/message_list_params.py deleted file mode 100644 index c55e68af..00000000 --- a/src/mobilerun_sdk/types/esims/message_list_params.py +++ /dev/null @@ -1,27 +0,0 @@ -# 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__ = ["MessageListParams"] - - -class MessageListParams(TypedDict, total=False): - direction: Literal["all", "inbound", "outbound"] - - number_id: Annotated[str, PropertyInfo(alias="numberId")] - - page: int - - page_size: Annotated[int, PropertyInfo(alias="pageSize")] - - peer_key: Annotated[str, PropertyInfo(alias="peerKey")] - - peer_number: Annotated[str, PropertyInfo(alias="peerNumber")] - - status: Literal[ - "all", "received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed" - ] diff --git a/src/mobilerun_sdk/types/esims/message_list_response.py b/src/mobilerun_sdk/types/esims/message_list_response.py deleted file mode 100644 index c04b3d46..00000000 --- a/src/mobilerun_sdk/types/esims/message_list_response.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel -from ..shared.pagination import Pagination - -__all__ = ["MessageListResponse", "Item"] - - -class Item(BaseModel): - id: str - - body: Optional[str] = None - - created_at: datetime = FieldInfo(alias="createdAt") - - delivery_status: Optional[str] = FieldInfo(alias="deliveryStatus", default=None) - - detected_sender: Optional[str] = FieldInfo(alias="detectedSender", default=None) - - direction: Literal["inbound", "outbound"] - - esim_id: Optional[str] = FieldInfo(alias="esimId", default=None) - - occurred_at: datetime = FieldInfo(alias="occurredAt") - - peer_key: Optional[str] = FieldInfo(alias="peerKey", default=None) - - peer_number: Optional[str] = FieldInfo(alias="peerNumber", default=None) - - provider_code: Optional[str] = FieldInfo(alias="providerCode", default=None) - - status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"] - - -class MessageListResponse(BaseModel): - items: List[Item] - - pagination: Pagination diff --git a/src/mobilerun_sdk/types/esims/message_send_params.py b/src/mobilerun_sdk/types/esims/message_send_params.py deleted file mode 100644 index 48c2c65a..00000000 --- a/src/mobilerun_sdk/types/esims/message_send_params.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["MessageSendParams"] - - -class MessageSendParams(TypedDict, total=False): - body: Required[str] - """ - SMS body text (max 320 chars — smaller than the admin tier's cap; see the - schema's own doc comment for why) - """ - - to: Required[str] - """ - Recipient phone number — normalized to E.164 (spaces/dashes/dots stripped); - rejected with 400 if it doesn't validate as E.164 afterward. - """ - - client_request_id: Annotated[str, PropertyInfo(alias="clientRequestId")] - """Client-supplied idempotency key, scoped to (owner, esimId, key). - - Replaying the same key + identical payload returns the original send; the same - key with a DIFFERENT payload is a 409 conflict. - """ - - delivery_report: Annotated[bool, PropertyInfo(alias="deliveryReport")] - """ - Wait for physedge to confirm carrier delivery before completing the send (adds - executor-side latency, never on this request — sends are always async/202). - Defaults to false for the public tier (opt-in, unlike the admin tier's - default-true). - """ diff --git a/src/mobilerun_sdk/types/esims/message_send_response.py b/src/mobilerun_sdk/types/esims/message_send_response.py deleted file mode 100644 index 86e545d6..00000000 --- a/src/mobilerun_sdk/types/esims/message_send_response.py +++ /dev/null @@ -1,41 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from pydantic import Field as FieldInfo - -from ..._models import BaseModel - -__all__ = ["MessageSendResponse", "Data"] - - -class Data(BaseModel): - id: str - - body: Optional[str] = None - - created_at: datetime = FieldInfo(alias="createdAt") - - delivery_status: Optional[str] = FieldInfo(alias="deliveryStatus", default=None) - - detected_sender: Optional[str] = FieldInfo(alias="detectedSender", default=None) - - direction: Literal["inbound", "outbound"] - - esim_id: Optional[str] = FieldInfo(alias="esimId", default=None) - - occurred_at: datetime = FieldInfo(alias="occurredAt") - - peer_key: Optional[str] = FieldInfo(alias="peerKey", default=None) - - peer_number: Optional[str] = FieldInfo(alias="peerNumber", default=None) - - provider_code: Optional[str] = FieldInfo(alias="providerCode", default=None) - - status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"] - - -class MessageSendResponse(BaseModel): - data: Data diff --git a/src/mobilerun_sdk/types/file_confirm_response.py b/src/mobilerun_sdk/types/file_confirm_response.py index 7ee2a30c..70ee1b74 100644 --- a/src/mobilerun_sdk/types/file_confirm_response.py +++ b/src/mobilerun_sdk/types/file_confirm_response.py @@ -1,14 +1,55 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Union, Optional from datetime import datetime -from typing_extensions import Literal +from typing_extensions import Literal, TypeAlias from pydantic import Field as FieldInfo from .._models import BaseModel -__all__ = ["FileConfirmResponse"] +__all__ = [ + "FileConfirmResponse", + "CollectionStatus", + "CollectionStatusUnionMember0", + "CollectionStatusUnionMember0Records", + "CollectionStatusUnionMember1", +] + + +class CollectionStatusUnionMember0Records(BaseModel): + reported: int + + unit: str + + +class CollectionStatusUnionMember0(BaseModel): + completeness: Literal["complete", "partial", "none", "unknown"] + + coverage: Literal["exhaustive", "bounded", "unknown"] + + end_reached: bool = FieldInfo(alias="endReached") + + records: CollectionStatusUnionMember0Records + + resumable: bool + + version: Literal[1] + + +class CollectionStatusUnionMember1(BaseModel): + completeness: Literal["unknown"] + + coverage: Literal["unknown"] + + end_reached: Literal[False] = FieldInfo(alias="endReached") + + resumable: Literal[False] + + version: Literal[1] + + +CollectionStatus: TypeAlias = Union[CollectionStatusUnionMember0, CollectionStatusUnionMember1] class FileConfirmResponse(BaseModel): @@ -33,3 +74,5 @@ class FileConfirmResponse(BaseModel): state: Literal["ready"] zone: Literal["user", "agent", "workflow", "skills"] + + collection_status: Optional[CollectionStatus] = FieldInfo(alias="collectionStatus", default=None) diff --git a/src/mobilerun_sdk/types/file_list_response.py b/src/mobilerun_sdk/types/file_list_response.py index 014c11fb..b3ccd796 100644 --- a/src/mobilerun_sdk/types/file_list_response.py +++ b/src/mobilerun_sdk/types/file_list_response.py @@ -1,14 +1,57 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List, Optional +from typing import List, Union, Optional from datetime import datetime -from typing_extensions import Literal +from typing_extensions import Literal, TypeAlias from pydantic import Field as FieldInfo from .._models import BaseModel -__all__ = ["FileListResponse", "File", "Quota"] +__all__ = [ + "FileListResponse", + "File", + "FileCollectionStatus", + "FileCollectionStatusUnionMember0", + "FileCollectionStatusUnionMember0Records", + "FileCollectionStatusUnionMember1", + "Quota", +] + + +class FileCollectionStatusUnionMember0Records(BaseModel): + reported: int + + unit: str + + +class FileCollectionStatusUnionMember0(BaseModel): + completeness: Literal["complete", "partial", "none", "unknown"] + + coverage: Literal["exhaustive", "bounded", "unknown"] + + end_reached: bool = FieldInfo(alias="endReached") + + records: FileCollectionStatusUnionMember0Records + + resumable: bool + + version: Literal[1] + + +class FileCollectionStatusUnionMember1(BaseModel): + completeness: Literal["unknown"] + + coverage: Literal["unknown"] + + end_reached: Literal[False] = FieldInfo(alias="endReached") + + resumable: Literal[False] + + version: Literal[1] + + +FileCollectionStatus: TypeAlias = Union[FileCollectionStatusUnionMember0, FileCollectionStatusUnionMember1] class File(BaseModel): @@ -30,6 +73,8 @@ class File(BaseModel): zone: Literal["user", "agent", "workflow", "skills"] + collection_status: Optional[FileCollectionStatus] = FieldInfo(alias="collectionStatus", default=None) + class Quota(BaseModel): current_bytes: int = FieldInfo(alias="currentBytes") diff --git a/src/mobilerun_sdk/types/file_update_response.py b/src/mobilerun_sdk/types/file_update_response.py index a3903256..e9f21496 100644 --- a/src/mobilerun_sdk/types/file_update_response.py +++ b/src/mobilerun_sdk/types/file_update_response.py @@ -1,14 +1,55 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Union, Optional from datetime import datetime -from typing_extensions import Literal +from typing_extensions import Literal, TypeAlias from pydantic import Field as FieldInfo from .._models import BaseModel -__all__ = ["FileUpdateResponse"] +__all__ = [ + "FileUpdateResponse", + "CollectionStatus", + "CollectionStatusUnionMember0", + "CollectionStatusUnionMember0Records", + "CollectionStatusUnionMember1", +] + + +class CollectionStatusUnionMember0Records(BaseModel): + reported: int + + unit: str + + +class CollectionStatusUnionMember0(BaseModel): + completeness: Literal["complete", "partial", "none", "unknown"] + + coverage: Literal["exhaustive", "bounded", "unknown"] + + end_reached: bool = FieldInfo(alias="endReached") + + records: CollectionStatusUnionMember0Records + + resumable: bool + + version: Literal[1] + + +class CollectionStatusUnionMember1(BaseModel): + completeness: Literal["unknown"] + + coverage: Literal["unknown"] + + end_reached: Literal[False] = FieldInfo(alias="endReached") + + resumable: Literal[False] + + version: Literal[1] + + +CollectionStatus: TypeAlias = Union[CollectionStatusUnionMember0, CollectionStatusUnionMember1] class FileUpdateResponse(BaseModel): @@ -29,3 +70,5 @@ class FileUpdateResponse(BaseModel): size_bytes: float = FieldInfo(alias="sizeBytes") zone: Literal["user", "agent", "workflow", "skills"] + + collection_status: Optional[CollectionStatus] = FieldInfo(alias="collectionStatus", default=None) diff --git a/src/mobilerun_sdk/types/mailbox_capacity_response.py b/src/mobilerun_sdk/types/mailbox_capacity_response.py index 9ca87175..ddeeab6b 100644 --- a/src/mobilerun_sdk/types/mailbox_capacity_response.py +++ b/src/mobilerun_sdk/types/mailbox_capacity_response.py @@ -1,5 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +from typing_extensions import Literal + from pydantic import Field as FieldInfo from .._models import BaseModel @@ -8,8 +10,14 @@ class Data(BaseModel): + included: int + included_remaining: int = FieldInfo(alias="includedRemaining") + remaining: int + + status: Literal["available", "exhausted", "not_included"] + class MailboxCapacityResponse(BaseModel): data: Data diff --git a/src/mobilerun_sdk/types/mailbox_create_params.py b/src/mobilerun_sdk/types/mailbox_create_params.py index bd5b7ce5..68cf68f8 100644 --- a/src/mobilerun_sdk/types/mailbox_create_params.py +++ b/src/mobilerun_sdk/types/mailbox_create_params.py @@ -12,18 +12,20 @@ class MailboxCreateParams(TypedDict, total=False): client_request_id: Required[Annotated[str, PropertyInfo(alias="clientRequestId")]] - billing_preference: Annotated[Literal["included", "rent"], PropertyInfo(alias="billingPreference")] - """Funding preference. + billing_preference: Annotated[Literal["included", "included_only", "rent"], PropertyInfo(alias="billingPreference")] + """ + included uses package capacity when available and otherwise starts paid + checkout; included_only fails without creating a paid reservation when no + included slot remains; rent always starts paid checkout. + """ + + domain_id: Annotated[str, PropertyInfo(alias="domainId")] + """Optional active custom mailbox domain owned by the caller. - Omit or use included for included-first activation; rent always preserves - package capacity and starts paid checkout. + Omit to use the system domain. """ label: str local_part: Annotated[str, PropertyInfo(alias="localPart")] - """Optional full mailbox local part (the address before "@"). - - Trimmed and lowercased before validation. Omit for a random, non-guessable - mx\\__-prefixed address. - """ + """Optional mailbox name before the "@". Omit to generate a random address.""" diff --git a/src/mobilerun_sdk/types/mailbox_create_response.py b/src/mobilerun_sdk/types/mailbox_create_response.py index 0ed4e6c4..2bb8b3c9 100644 --- a/src/mobilerun_sdk/types/mailbox_create_response.py +++ b/src/mobilerun_sdk/types/mailbox_create_response.py @@ -26,7 +26,7 @@ class Data(BaseModel): address: Optional[str] = None - billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode") + billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode") cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd") @@ -38,6 +38,8 @@ class Data(BaseModel): current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + domain_id: Optional[str] = FieldInfo(alias="domainId", default=None) + inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages") label: Optional[str] = None diff --git a/src/mobilerun_sdk/types/mailbox_delete_response.py b/src/mobilerun_sdk/types/mailbox_delete_response.py index 7b6675cd..ac6cd9b8 100644 --- a/src/mobilerun_sdk/types/mailbox_delete_response.py +++ b/src/mobilerun_sdk/types/mailbox_delete_response.py @@ -26,7 +26,7 @@ class Data(BaseModel): address: Optional[str] = None - billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode") + billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode") cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd") @@ -38,6 +38,8 @@ class Data(BaseModel): current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + domain_id: Optional[str] = FieldInfo(alias="domainId", default=None) + inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages") label: Optional[str] = None diff --git a/src/mobilerun_sdk/types/mailbox_list_response.py b/src/mobilerun_sdk/types/mailbox_list_response.py index df935fc8..70ace920 100644 --- a/src/mobilerun_sdk/types/mailbox_list_response.py +++ b/src/mobilerun_sdk/types/mailbox_list_response.py @@ -27,7 +27,7 @@ class Item(BaseModel): address: Optional[str] = None - billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode") + billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode") cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd") @@ -39,6 +39,8 @@ class Item(BaseModel): current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + domain_id: Optional[str] = FieldInfo(alias="domainId", default=None) + inbound_messages: ItemInboundMessages = FieldInfo(alias="inboundMessages") label: Optional[str] = None diff --git a/src/mobilerun_sdk/types/mailbox_otp_response.py b/src/mobilerun_sdk/types/mailbox_otp_response.py index 28ce8f48..540069ac 100644 --- a/src/mobilerun_sdk/types/mailbox_otp_response.py +++ b/src/mobilerun_sdk/types/mailbox_otp_response.py @@ -13,7 +13,7 @@ class Data(BaseModel): code: str - """String to preserve leading zeros""" + """OTP code as text to preserve leading zeros.""" confidence: Literal["high", "medium", "low"] diff --git a/src/mobilerun_sdk/types/mailbox_restart_params.py b/src/mobilerun_sdk/types/mailbox_restart_params.py index 497bb7e0..ca174720 100644 --- a/src/mobilerun_sdk/types/mailbox_restart_params.py +++ b/src/mobilerun_sdk/types/mailbox_restart_params.py @@ -10,9 +10,9 @@ class MailboxRestartParams(TypedDict, total=False): - billing_preference: Annotated[Literal["included", "rent"], PropertyInfo(alias="billingPreference")] - """Funding preference. - - Omit or use included for included-first activation; rent always preserves - package capacity and starts paid checkout. + billing_preference: Annotated[Literal["included", "included_only", "rent"], PropertyInfo(alias="billingPreference")] + """ + included uses package capacity when available and otherwise starts paid + checkout; included_only fails without creating a paid reservation when no + included slot remains; rent always starts paid checkout. """ diff --git a/src/mobilerun_sdk/types/mailbox_restart_response.py b/src/mobilerun_sdk/types/mailbox_restart_response.py index 4bef7939..ab9e1d79 100644 --- a/src/mobilerun_sdk/types/mailbox_restart_response.py +++ b/src/mobilerun_sdk/types/mailbox_restart_response.py @@ -26,7 +26,7 @@ class Data(BaseModel): address: Optional[str] = None - billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode") + billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode") cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd") @@ -38,6 +38,8 @@ class Data(BaseModel): current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + domain_id: Optional[str] = FieldInfo(alias="domainId", default=None) + inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages") label: Optional[str] = None diff --git a/src/mobilerun_sdk/types/mailbox_retrieve_response.py b/src/mobilerun_sdk/types/mailbox_retrieve_response.py index efb60e24..ed490495 100644 --- a/src/mobilerun_sdk/types/mailbox_retrieve_response.py +++ b/src/mobilerun_sdk/types/mailbox_retrieve_response.py @@ -26,7 +26,7 @@ class Data(BaseModel): address: Optional[str] = None - billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode") + billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode") cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd") @@ -38,6 +38,8 @@ class Data(BaseModel): current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + domain_id: Optional[str] = FieldInfo(alias="domainId", default=None) + inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages") label: Optional[str] = None diff --git a/src/mobilerun_sdk/types/mailbox_uncancel_response.py b/src/mobilerun_sdk/types/mailbox_uncancel_response.py index 04688b3b..fc6b588e 100644 --- a/src/mobilerun_sdk/types/mailbox_uncancel_response.py +++ b/src/mobilerun_sdk/types/mailbox_uncancel_response.py @@ -26,7 +26,7 @@ class Data(BaseModel): address: Optional[str] = None - billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode") + billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode") cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd") @@ -38,6 +38,8 @@ class Data(BaseModel): current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + domain_id: Optional[str] = FieldInfo(alias="domainId", default=None) + inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages") label: Optional[str] = None diff --git a/src/mobilerun_sdk/types/mailbox_update_response.py b/src/mobilerun_sdk/types/mailbox_update_response.py index 893d9928..99de186b 100644 --- a/src/mobilerun_sdk/types/mailbox_update_response.py +++ b/src/mobilerun_sdk/types/mailbox_update_response.py @@ -26,7 +26,7 @@ class Data(BaseModel): address: Optional[str] = None - billing_mode: Literal["rent", "included"] = FieldInfo(alias="billingMode") + billing_mode: Literal["rent", "included", "domain"] = FieldInfo(alias="billingMode") cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd") @@ -38,6 +38,8 @@ class Data(BaseModel): current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None) + domain_id: Optional[str] = FieldInfo(alias="domainId", default=None) + inbound_messages: DataInboundMessages = FieldInfo(alias="inboundMessages") label: Optional[str] = None diff --git a/src/mobilerun_sdk/types/number_create_params.py b/src/mobilerun_sdk/types/number_create_params.py index 6098fc62..353cd5fb 100644 --- a/src/mobilerun_sdk/types/number_create_params.py +++ b/src/mobilerun_sdk/types/number_create_params.py @@ -11,14 +11,14 @@ class NumberCreateParams(TypedDict, total=False): - billing_preference: Annotated[Literal["included", "rent"], PropertyInfo(alias="billingPreference")] + billing_preference: Annotated[Literal["included", "included_only", "rent"], PropertyInfo(alias="billingPreference")] """ - Prefer a free package seat ('included', default) or force the paid checkout - ('rent') + Use included capacity when available, require included capacity without paid + fallback (included_only), or start a paid checkout (rent). """ country: str - """Optional ISO 3166-1 alpha-2 country code from GET /numbers/countries. + """Optional ISO 3166-1 alpha-2 country code from GET /numbers/phones/countries. Cannot be combined with `purpose`. """ @@ -31,7 +31,7 @@ class NumberCreateParams(TypedDict, total=False): """ purpose: str - """Optional Mobilerun Phone purpose slug from GET /numbers/purposes.""" + """Optional purpose from GET /numbers/phones/purposes.""" idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")] """Optional request idempotency key.""" diff --git a/src/mobilerun_sdk/types/task_get_status_response.py b/src/mobilerun_sdk/types/task_get_status_response.py index 4446b3bb..0e0f823c 100644 --- a/src/mobilerun_sdk/types/task_get_status_response.py +++ b/src/mobilerun_sdk/types/task_get_status_response.py @@ -33,7 +33,7 @@ class Execution(BaseModel): class TaskGetStatusResponse(BaseModel): - status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] + status: Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] """The status of the task""" execution: Optional[Execution] = None @@ -48,6 +48,12 @@ class TaskGetStatusResponse(BaseModel): output: Optional[Dict[str, object]] = None """Structured output if outputSchema was set""" + recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None) + """Device ID associated with recordingId""" + + recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None) + """ID of the task's whole-task video recording, if recordingEnabled was set""" + steps: Optional[int] = None """Number of steps taken""" diff --git a/src/mobilerun_sdk/types/task_list_params.py b/src/mobilerun_sdk/types/task_list_params.py index 044f84ad..1b08553e 100644 --- a/src/mobilerun_sdk/types/task_list_params.py +++ b/src/mobilerun_sdk/types/task_list_params.py @@ -28,4 +28,9 @@ class TaskListParams(TypedDict, total=False): query: Optional[str] """Search in task description.""" - status: Optional[Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"]] + source: Optional[Literal["api", "agent"]] + """Only tasks created via the API ('api') or spawned by an agent step ('agent').""" + + status: Optional[ + Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] + ] diff --git a/src/mobilerun_sdk/types/task_list_response.py b/src/mobilerun_sdk/types/task_list_response.py index 20a9744c..07a143fd 100644 --- a/src/mobilerun_sdk/types/task_list_response.py +++ b/src/mobilerun_sdk/types/task_list_response.py @@ -32,7 +32,7 @@ class Item(BaseModel): owner_id: str = FieldInfo(alias="ownerId") - status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] + status: Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] task: str @@ -43,8 +43,6 @@ class Item(BaseModel): accessibility: Optional[bool] = None - agent_id: Optional[int] = FieldInfo(alias="agentId", default=None) - apps: Optional[List[str]] = None cancel_requested_at: Optional[datetime] = FieldInfo(alias="cancelRequestedAt", default=None) @@ -71,9 +69,6 @@ class Item(BaseModel): max_steps: Optional[int] = FieldInfo(alias="maxSteps", default=None) - memory_namespace: Optional[str] = FieldInfo(alias="memoryNamespace", default=None) - """Memory namespace for cross-task personalization""" - message: Optional[str] = None output: Optional[Dict[str, object]] = None @@ -82,6 +77,20 @@ class Item(BaseModel): reasoning: Optional[bool] = None + recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None) + + recording_enabled: Optional[bool] = FieldInfo(alias="recordingEnabled", default=None) + """Record device video for the whole task and persist a retrievable reference""" + + recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None) + + source: Optional[Literal["api", "agent"]] = None + """ + Where the task came from: 'api' for tasks created via POST /tasks, 'agent' for + tasks spawned by an agent step. Agent tasks are readable (status, trajectory, + media) but not controllable via this API. + """ + stealth: Optional[bool] = None steps: Optional[int] = None @@ -94,6 +103,7 @@ class Item(BaseModel): succeeded: Optional[bool] = None temperature: Optional[float] = None + """Deprecated and ignored. Sampling behavior is controlled by the model provider.""" updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) diff --git a/src/mobilerun_sdk/types/task_retrieve_response.py b/src/mobilerun_sdk/types/task_retrieve_response.py index 85887f56..b0e25a6b 100644 --- a/src/mobilerun_sdk/types/task_retrieve_response.py +++ b/src/mobilerun_sdk/types/task_retrieve_response.py @@ -31,7 +31,7 @@ class Task(BaseModel): owner_id: str = FieldInfo(alias="ownerId") - status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] + status: Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] task: str @@ -42,8 +42,6 @@ class Task(BaseModel): accessibility: Optional[bool] = None - agent_id: Optional[int] = FieldInfo(alias="agentId", default=None) - apps: Optional[List[str]] = None cancel_requested_at: Optional[datetime] = FieldInfo(alias="cancelRequestedAt", default=None) @@ -70,9 +68,6 @@ class Task(BaseModel): max_steps: Optional[int] = FieldInfo(alias="maxSteps", default=None) - memory_namespace: Optional[str] = FieldInfo(alias="memoryNamespace", default=None) - """Memory namespace for cross-task personalization""" - message: Optional[str] = None output: Optional[Dict[str, object]] = None @@ -81,6 +76,20 @@ class Task(BaseModel): reasoning: Optional[bool] = None + recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None) + + recording_enabled: Optional[bool] = FieldInfo(alias="recordingEnabled", default=None) + """Record device video for the whole task and persist a retrievable reference""" + + recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None) + + source: Optional[Literal["api", "agent"]] = None + """ + Where the task came from: 'api' for tasks created via POST /tasks, 'agent' for + tasks spawned by an agent step. Agent tasks are readable (status, trajectory, + media) but not controllable via this API. + """ + stealth: Optional[bool] = None steps: Optional[int] = None @@ -93,6 +102,7 @@ class Task(BaseModel): succeeded: Optional[bool] = None temperature: Optional[float] = None + """Deprecated and ignored. Sampling behavior is controlled by the model provider.""" updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None) diff --git a/src/mobilerun_sdk/types/task_run_params.py b/src/mobilerun_sdk/types/task_run_params.py index b66cf98f..e0b99bc9 100644 --- a/src/mobilerun_sdk/types/task_run_params.py +++ b/src/mobilerun_sdk/types/task_run_params.py @@ -19,8 +19,6 @@ class TaskRunParams(TypedDict, total=False): accessibility: bool - agent_id: Annotated[int, PropertyInfo(alias="agentId")] - apps: SequenceNotStr[str] continue_on_failure: Annotated[bool, PropertyInfo(alias="continueOnFailure")] @@ -31,27 +29,35 @@ class TaskRunParams(TypedDict, total=False): """The display ID of the device to run the task on.""" execution_timeout: Annotated[int, PropertyInfo(alias="executionTimeout")] + """Maximum agent execution time in seconds (1–2700).""" files: SequenceNotStr[str] llm_model: Annotated[str, PropertyInfo(alias="llmModel")] - """The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash')""" + """The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna')""" max_steps: Annotated[int, PropertyInfo(alias="maxSteps")] - memory_namespace: Annotated[str, PropertyInfo(alias="memoryNamespace")] - """Memory namespace for cross-task personalization""" - output_schema: Annotated[Optional[Dict[str, object]], PropertyInfo(alias="outputSchema")] reasoning: bool + recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")] + """Record device video for the whole task and persist a retrievable reference""" + stealth: bool subagent_model: Annotated[str, PropertyInfo(alias="subagentModel")] """LLM model used by sub-agent roles: executor, app_opener, structured_output""" + system_prompt: Annotated[Optional[str], PropertyInfo(alias="systemPrompt")] + """ + Optional custom behavioral overlay applied on top of the agent's default system + prompts. Never echoed back in responses or errors. + """ + temperature: float + """Deprecated and ignored. Sampling behavior is controlled by the model provider.""" vision: bool diff --git a/src/mobilerun_sdk/types/task_run_response.py b/src/mobilerun_sdk/types/task_run_response.py index 5987ba3d..6b402a65 100644 --- a/src/mobilerun_sdk/types/task_run_response.py +++ b/src/mobilerun_sdk/types/task_run_response.py @@ -14,7 +14,7 @@ class TaskRunResponse(BaseModel): id: str """The ID of the task""" - status: Literal["queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] + status: Literal["prepared", "queued", "created", "running", "cancelling", "completed", "failed", "cancelled"] """The status of the task (queued or created)""" stream_url: Optional[str] = FieldInfo(alias="streamUrl", default=None) diff --git a/src/mobilerun_sdk/types/task_run_streamed_params.py b/src/mobilerun_sdk/types/task_run_streamed_params.py index 2522d16b..5de0656e 100644 --- a/src/mobilerun_sdk/types/task_run_streamed_params.py +++ b/src/mobilerun_sdk/types/task_run_streamed_params.py @@ -19,8 +19,6 @@ class TaskRunStreamedParams(TypedDict, total=False): accessibility: bool - agent_id: Annotated[int, PropertyInfo(alias="agentId")] - apps: SequenceNotStr[str] continue_on_failure: Annotated[bool, PropertyInfo(alias="continueOnFailure")] @@ -31,27 +29,35 @@ class TaskRunStreamedParams(TypedDict, total=False): """The display ID of the device to run the task on.""" execution_timeout: Annotated[int, PropertyInfo(alias="executionTimeout")] + """Maximum agent execution time in seconds (1–2700).""" files: SequenceNotStr[str] llm_model: Annotated[str, PropertyInfo(alias="llmModel")] - """The LLM model identifier to use for the task (e.g. 'google/gemini-3.5-flash')""" + """The LLM model identifier to use for the task (e.g. 'openai/gpt-5.6-luna')""" max_steps: Annotated[int, PropertyInfo(alias="maxSteps")] - memory_namespace: Annotated[str, PropertyInfo(alias="memoryNamespace")] - """Memory namespace for cross-task personalization""" - output_schema: Annotated[Optional[Dict[str, object]], PropertyInfo(alias="outputSchema")] reasoning: bool + recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")] + """Record device video for the whole task and persist a retrievable reference""" + stealth: bool subagent_model: Annotated[str, PropertyInfo(alias="subagentModel")] """LLM model used by sub-agent roles: executor, app_opener, structured_output""" + system_prompt: Annotated[Optional[str], PropertyInfo(alias="systemPrompt")] + """ + Optional custom behavioral overlay applied on top of the agent's default system + prompts. Never echoed back in responses or errors. + """ + temperature: float + """Deprecated and ignored. Sampling behavior is controlled by the model provider.""" vision: bool diff --git a/src/mobilerun_sdk/types/webhook_event_types_response.py b/src/mobilerun_sdk/types/webhook_event_types_response.py index 2d1d9e2f..9c7439d7 100644 --- a/src/mobilerun_sdk/types/webhook_event_types_response.py +++ b/src/mobilerun_sdk/types/webhook_event_types_response.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import List +from typing import List, Optional from typing_extensions import Literal from pydantic import Field as FieldInfo @@ -17,6 +17,8 @@ class DataSourceEventSurfaces(BaseModel): webhook: bool + agent: Optional[bool] = None + class DataSourceEvent(BaseModel): description: str diff --git a/src/mobilerun_sdk/types/workflows/event_dry_run_response.py b/src/mobilerun_sdk/types/workflows/event_dry_run_response.py index b04779e3..e7bb6eee 100644 --- a/src/mobilerun_sdk/types/workflows/event_dry_run_response.py +++ b/src/mobilerun_sdk/types/workflows/event_dry_run_response.py @@ -13,6 +13,7 @@ "DataMatchedFlow", "DataMatchedFlowAction", "DataMatchedFlowFlow", + "DataMatchedFlowFlowRecordingPolicy", "DataMatchedFlowGates", "DataMatchedFlowTrigger", "DataValidation", @@ -23,10 +24,14 @@ class DataMatchedFlowAction(BaseModel): continue_on_error: bool = FieldInfo(alias="continueOnError") + flow_action_id: str = FieldInfo(alias="flowActionId") + method: str name: str + recording_enabled: bool = FieldInfo(alias="recordingEnabled") + service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"] children: Optional[List[object]] = None @@ -38,9 +43,15 @@ class DataMatchedFlowAction(BaseModel): params: Optional[Dict[str, object]] = None +class DataMatchedFlowFlowRecordingPolicy(BaseModel): + mode: Literal["off", "flow", "selected_steps"] + + class DataMatchedFlowFlow(BaseModel): id: str + archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None) + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) consecutive_failures: int = FieldInfo(alias="consecutiveFailures") @@ -58,6 +69,10 @@ class DataMatchedFlowFlow(BaseModel): device_ids: List[str] = FieldInfo(alias="deviceIds") enabled: bool + """ + Compatibility projection of lifecycleStatus; true only when lifecycleStatus is + enabled. + """ health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") @@ -69,6 +84,8 @@ class DataMatchedFlowFlow(BaseModel): last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus") + name: str notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") @@ -80,6 +97,12 @@ class DataMatchedFlowFlow(BaseModel): owner_id: str = FieldInfo(alias="ownerId") recording_enabled: bool = FieldInfo(alias="recordingEnabled") + """ + Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" = + recordingEnabled=false). + """ + + recording_policy: DataMatchedFlowFlowRecordingPolicy = FieldInfo(alias="recordingPolicy") self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") diff --git a/src/mobilerun_sdk/types/workflows/execution_abort_response.py b/src/mobilerun_sdk/types/workflows/execution_abort_response.py index 0d9468bf..8ef853a1 100644 --- a/src/mobilerun_sdk/types/workflows/execution_abort_response.py +++ b/src/mobilerun_sdk/types/workflows/execution_abort_response.py @@ -13,6 +13,12 @@ class Data(BaseModel): id: str + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + """Device this execution targets (the job's deviceId). + + Null for device-less (event-only) runs. + """ + error: Optional[str] = None event_id: Optional[str] = FieldInfo(alias="eventId", default=None) @@ -23,7 +29,14 @@ class Data(BaseModel): flow_name: Optional[str] = FieldInfo(alias="flowName", default=None) - kind: Literal["live", "dry_run"] + invocation_id: Optional[str] = FieldInfo(alias="invocationId", default=None) + """Client/verify invocation key this row belongs to. + + Set on live custom fires (one row per device fan-out) and on verification runs; + null for event/schedule live rows. + """ + + kind: Literal["live", "dry_run", "verification"] recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None) diff --git a/src/mobilerun_sdk/types/workflows/execution_list_params.py b/src/mobilerun_sdk/types/workflows/execution_list_params.py index ccc40d41..83e83d88 100644 --- a/src/mobilerun_sdk/types/workflows/execution_list_params.py +++ b/src/mobilerun_sdk/types/workflows/execution_list_params.py @@ -15,6 +15,8 @@ class ExecutionListParams(TypedDict, total=False): from_: Annotated[Optional[str], PropertyInfo(alias="from")] + invocation_id: Annotated[str, PropertyInfo(alias="invocationId")] + order_by: Annotated[Literal["startedAt", "finishedAt", "status"], PropertyInfo(alias="orderBy")] order_by_direction: Annotated[Literal["asc", "desc"], PropertyInfo(alias="orderByDirection")] diff --git a/src/mobilerun_sdk/types/workflows/execution_list_response.py b/src/mobilerun_sdk/types/workflows/execution_list_response.py index b7c4993f..f3d62b4c 100644 --- a/src/mobilerun_sdk/types/workflows/execution_list_response.py +++ b/src/mobilerun_sdk/types/workflows/execution_list_response.py @@ -8,7 +8,37 @@ from ..._models import BaseModel from ..shared.pagination import Pagination -__all__ = ["ExecutionListResponse", "Item"] +__all__ = ["ExecutionListResponse", "Item", "ItemRecording"] + + +class ItemRecording(BaseModel): + id: str + + attempt: int + + child_index: int = FieldInfo(alias="childIndex") + + flow_action_id: Optional[str] = FieldInfo(alias="flowActionId", default=None) + + iteration_index: int = FieldInfo(alias="iterationIndex") + + last_error: Optional[str] = FieldInfo(alias="lastError", default=None) + + parent_index: int = FieldInfo(alias="parentIndex") + + recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None) + + recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None) + + scope: Literal["flow", "step"] + + started_at: Optional[str] = FieldInfo(alias="startedAt", default=None) + + status: Literal["starting", "recording", "stopping", "stopped", "failed"] + + step_index: int = FieldInfo(alias="stepIndex") + + stopped_at: Optional[str] = FieldInfo(alias="stoppedAt", default=None) class Item(BaseModel): @@ -16,6 +46,12 @@ class Item(BaseModel): created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + """Device this execution targets (the job's deviceId). + + Null for device-less (event-only) runs. + """ + error: Optional[str] = None event_id: Optional[str] = FieldInfo(alias="eventId", default=None) @@ -26,7 +62,14 @@ class Item(BaseModel): flow_name: Optional[str] = FieldInfo(alias="flowName", default=None) - kind: Literal["live", "dry_run"] + invocation_id: Optional[str] = FieldInfo(alias="invocationId", default=None) + """Client/verify invocation key this row belongs to. + + Set on live custom fires (one row per device fan-out) and on verification runs; + null for event/schedule live rows. + """ + + kind: Literal["live", "dry_run", "verification"] recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None) @@ -37,6 +80,12 @@ class Item(BaseModel): the recording failed to start. """ + recordings: List[ItemRecording] + """Durable recording segments ordered by step/loop coordinate and retry attempt. + + Whole-flow recordings use -1 for every coordinate. + """ + started_at: Optional[str] = FieldInfo(alias="startedAt", default=None) status: Optional[Literal["pending", "running", "success", "failed", "cancelled", "skipped", "invalid"]] = None diff --git a/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py b/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py index de6c2d19..9af89a42 100644 --- a/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py +++ b/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py @@ -7,7 +7,7 @@ from ..._models import BaseModel -__all__ = ["ExecutionRetrieveResponse", "Data", "DataFile"] +__all__ = ["ExecutionRetrieveResponse", "Data", "DataFile", "DataRecording"] class DataFile(BaseModel): @@ -20,11 +20,47 @@ class DataFile(BaseModel): size_bytes: int = FieldInfo(alias="sizeBytes") +class DataRecording(BaseModel): + id: str + + attempt: int + + child_index: int = FieldInfo(alias="childIndex") + + flow_action_id: Optional[str] = FieldInfo(alias="flowActionId", default=None) + + iteration_index: int = FieldInfo(alias="iterationIndex") + + last_error: Optional[str] = FieldInfo(alias="lastError", default=None) + + parent_index: int = FieldInfo(alias="parentIndex") + + recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None) + + recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None) + + scope: Literal["flow", "step"] + + started_at: Optional[str] = FieldInfo(alias="startedAt", default=None) + + status: Literal["starting", "recording", "stopping", "stopped", "failed"] + + step_index: int = FieldInfo(alias="stepIndex") + + stopped_at: Optional[str] = FieldInfo(alias="stoppedAt", default=None) + + class Data(BaseModel): id: str created_by: Optional[str] = FieldInfo(alias="createdBy", default=None) + device_id: Optional[str] = FieldInfo(alias="deviceId", default=None) + """Device this execution targets (the job's deviceId). + + Null for device-less (event-only) runs. + """ + error: Optional[str] = None event_id: Optional[str] = FieldInfo(alias="eventId", default=None) @@ -42,7 +78,14 @@ class Data(BaseModel): flow_name: Optional[str] = FieldInfo(alias="flowName", default=None) - kind: Literal["live", "dry_run"] + invocation_id: Optional[str] = FieldInfo(alias="invocationId", default=None) + """Client/verify invocation key this row belongs to. + + Set on live custom fires (one row per device fan-out) and on verification runs; + null for event/schedule live rows. + """ + + kind: Literal["live", "dry_run", "verification"] recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None) @@ -53,6 +96,12 @@ class Data(BaseModel): the recording failed to start. """ + recordings: List[DataRecording] + """Durable recording segments ordered by step/loop coordinate and retry attempt. + + Whole-flow recordings use -1 for every coordinate. + """ + started_at: Optional[str] = FieldInfo(alias="startedAt", default=None) status: Optional[Literal["pending", "running", "success", "failed", "cancelled", "skipped", "invalid"]] = None diff --git a/src/mobilerun_sdk/types/workflows/flow_clone_response.py b/src/mobilerun_sdk/types/workflows/flow_clone_response.py index 14ed8d1f..e08b73dd 100644 --- a/src/mobilerun_sdk/types/workflows/flow_clone_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_clone_response.py @@ -7,12 +7,18 @@ from ..._models import BaseModel -__all__ = ["FlowCloneResponse", "Data"] +__all__ = ["FlowCloneResponse", "Data", "DataRecordingPolicy"] + + +class DataRecordingPolicy(BaseModel): + mode: Literal["off", "flow", "selected_steps"] class Data(BaseModel): id: str + archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None) + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) consecutive_failures: int = FieldInfo(alias="consecutiveFailures") @@ -30,6 +36,10 @@ class Data(BaseModel): device_ids: List[str] = FieldInfo(alias="deviceIds") enabled: bool + """ + Compatibility projection of lifecycleStatus; true only when lifecycleStatus is + enabled. + """ health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") @@ -41,6 +51,8 @@ class Data(BaseModel): last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus") + name: str notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") @@ -52,6 +64,12 @@ class Data(BaseModel): owner_id: str = FieldInfo(alias="ownerId") recording_enabled: bool = FieldInfo(alias="recordingEnabled") + """ + Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" = + recordingEnabled=false). + """ + + recording_policy: DataRecordingPolicy = FieldInfo(alias="recordingPolicy") self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") diff --git a/src/mobilerun_sdk/types/workflows/flow_create_params.py b/src/mobilerun_sdk/types/workflows/flow_create_params.py index cde7b202..1a292cf5 100644 --- a/src/mobilerun_sdk/types/workflows/flow_create_params.py +++ b/src/mobilerun_sdk/types/workflows/flow_create_params.py @@ -8,7 +8,7 @@ from ..._types import SequenceNotStr from ..._utils import PropertyInfo -__all__ = ["FlowCreateParams", "Action", "ActionChild", "ActionChildOverrides", "ActionOverrides"] +__all__ = ["FlowCreateParams", "Action", "ActionChild", "ActionChildOverrides", "ActionOverrides", "RecordingPolicy"] class FlowCreateParams(TypedDict, total=False): @@ -37,6 +37,12 @@ class FlowCreateParams(TypedDict, total=False): notify_webhook_id: Annotated[Optional[str], PropertyInfo(alias="notifyWebhookId")] recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")] + """Deprecated compatibility field. + + true maps to recordingPolicy.mode="flow"; false maps to "off". + """ + + recording_policy: Annotated[RecordingPolicy, PropertyInfo(alias="recordingPolicy")] self_healing_enabled: Annotated[bool, PropertyInfo(alias="selfHealingEnabled")] @@ -58,6 +64,8 @@ class ActionChild(TypedDict, total=False): overrides: Optional[ActionChildOverrides] + recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")] + class ActionOverrides(TypedDict, total=False): params: Dict[str, object] @@ -75,3 +83,9 @@ class Action(TypedDict, total=False): name_override: Annotated[str, PropertyInfo(alias="nameOverride")] overrides: Optional[ActionOverrides] + + recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")] + + +class RecordingPolicy(TypedDict, total=False): + mode: Required[Literal["off", "flow", "selected_steps"]] diff --git a/src/mobilerun_sdk/types/workflows/flow_create_response.py b/src/mobilerun_sdk/types/workflows/flow_create_response.py index a840cf45..d4129117 100644 --- a/src/mobilerun_sdk/types/workflows/flow_create_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_create_response.py @@ -7,12 +7,18 @@ from ..._models import BaseModel -__all__ = ["FlowCreateResponse", "Data"] +__all__ = ["FlowCreateResponse", "Data", "DataRecordingPolicy"] + + +class DataRecordingPolicy(BaseModel): + mode: Literal["off", "flow", "selected_steps"] class Data(BaseModel): id: str + archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None) + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) consecutive_failures: int = FieldInfo(alias="consecutiveFailures") @@ -30,6 +36,10 @@ class Data(BaseModel): device_ids: List[str] = FieldInfo(alias="deviceIds") enabled: bool + """ + Compatibility projection of lifecycleStatus; true only when lifecycleStatus is + enabled. + """ health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") @@ -41,6 +51,8 @@ class Data(BaseModel): last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus") + name: str notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") @@ -52,6 +64,12 @@ class Data(BaseModel): owner_id: str = FieldInfo(alias="ownerId") recording_enabled: bool = FieldInfo(alias="recordingEnabled") + """ + Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" = + recordingEnabled=false). + """ + + recording_policy: DataRecordingPolicy = FieldInfo(alias="recordingPolicy") self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") diff --git a/src/mobilerun_sdk/types/workflows/flow_dry_run_response.py b/src/mobilerun_sdk/types/workflows/flow_dry_run_response.py index d9a5bf30..5592add2 100644 --- a/src/mobilerun_sdk/types/workflows/flow_dry_run_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_dry_run_response.py @@ -13,10 +13,14 @@ class DataAction(BaseModel): continue_on_error: bool = FieldInfo(alias="continueOnError") + flow_action_id: str = FieldInfo(alias="flowActionId") + method: str name: str + recording_enabled: bool = FieldInfo(alias="recordingEnabled") + service: Literal["tasks_api", "devices_api", "agents_api", "webhooks"] children: Optional[List[object]] = None diff --git a/src/mobilerun_sdk/types/workflows/flow_list_response.py b/src/mobilerun_sdk/types/workflows/flow_list_response.py index 5cd546ab..01705f9f 100644 --- a/src/mobilerun_sdk/types/workflows/flow_list_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_list_response.py @@ -8,12 +8,18 @@ from ..._models import BaseModel from ..shared.pagination import Pagination -__all__ = ["FlowListResponse", "Item"] +__all__ = ["FlowListResponse", "Item", "ItemRecordingPolicy"] + + +class ItemRecordingPolicy(BaseModel): + mode: Literal["off", "flow", "selected_steps"] class Item(BaseModel): id: str + archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None) + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) consecutive_failures: int = FieldInfo(alias="consecutiveFailures") @@ -31,6 +37,10 @@ class Item(BaseModel): device_ids: List[str] = FieldInfo(alias="deviceIds") enabled: bool + """ + Compatibility projection of lifecycleStatus; true only when lifecycleStatus is + enabled. + """ health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") @@ -42,6 +52,8 @@ class Item(BaseModel): last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus") + name: str notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") @@ -53,6 +65,12 @@ class Item(BaseModel): owner_id: str = FieldInfo(alias="ownerId") recording_enabled: bool = FieldInfo(alias="recordingEnabled") + """ + Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" = + recordingEnabled=false). + """ + + recording_policy: ItemRecordingPolicy = FieldInfo(alias="recordingPolicy") self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") diff --git a/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py b/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py index dab4caa9..b4cd5806 100644 --- a/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py @@ -7,12 +7,18 @@ from ..._models import BaseModel -__all__ = ["FlowRetrieveResponse", "Data"] +__all__ = ["FlowRetrieveResponse", "Data", "DataRecordingPolicy"] + + +class DataRecordingPolicy(BaseModel): + mode: Literal["off", "flow", "selected_steps"] class Data(BaseModel): id: str + archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None) + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) consecutive_failures: int = FieldInfo(alias="consecutiveFailures") @@ -30,6 +36,10 @@ class Data(BaseModel): device_ids: List[str] = FieldInfo(alias="deviceIds") enabled: bool + """ + Compatibility projection of lifecycleStatus; true only when lifecycleStatus is + enabled. + """ health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") @@ -41,6 +51,8 @@ class Data(BaseModel): last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus") + name: str notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") @@ -52,6 +64,12 @@ class Data(BaseModel): owner_id: str = FieldInfo(alias="ownerId") recording_enabled: bool = FieldInfo(alias="recordingEnabled") + """ + Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" = + recordingEnabled=false). + """ + + recording_policy: DataRecordingPolicy = FieldInfo(alias="recordingPolicy") self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") diff --git a/src/mobilerun_sdk/types/workflows/flow_unblock_response.py b/src/mobilerun_sdk/types/workflows/flow_unblock_response.py index 0429bba4..d71392de 100644 --- a/src/mobilerun_sdk/types/workflows/flow_unblock_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_unblock_response.py @@ -7,12 +7,18 @@ from ..._models import BaseModel -__all__ = ["FlowUnblockResponse", "Data"] +__all__ = ["FlowUnblockResponse", "Data", "DataRecordingPolicy"] + + +class DataRecordingPolicy(BaseModel): + mode: Literal["off", "flow", "selected_steps"] class Data(BaseModel): id: str + archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None) + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) consecutive_failures: int = FieldInfo(alias="consecutiveFailures") @@ -30,6 +36,10 @@ class Data(BaseModel): device_ids: List[str] = FieldInfo(alias="deviceIds") enabled: bool + """ + Compatibility projection of lifecycleStatus; true only when lifecycleStatus is + enabled. + """ health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") @@ -41,6 +51,8 @@ class Data(BaseModel): last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus") + name: str notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") @@ -52,6 +64,12 @@ class Data(BaseModel): owner_id: str = FieldInfo(alias="ownerId") recording_enabled: bool = FieldInfo(alias="recordingEnabled") + """ + Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" = + recordingEnabled=false). + """ + + recording_policy: DataRecordingPolicy = FieldInfo(alias="recordingPolicy") self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") diff --git a/src/mobilerun_sdk/types/workflows/flow_update_params.py b/src/mobilerun_sdk/types/workflows/flow_update_params.py index 8db31b2e..9f32e4bb 100644 --- a/src/mobilerun_sdk/types/workflows/flow_update_params.py +++ b/src/mobilerun_sdk/types/workflows/flow_update_params.py @@ -3,12 +3,12 @@ from __future__ import annotations from typing import Optional -from typing_extensions import Literal, Annotated, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict from ..._types import SequenceNotStr from ..._utils import PropertyInfo -__all__ = ["FlowUpdateParams"] +__all__ = ["FlowUpdateParams", "RecordingPolicy"] class FlowUpdateParams(TypedDict, total=False): @@ -24,6 +24,9 @@ class FlowUpdateParams(TypedDict, total=False): health_monitoring_enabled: Annotated[bool, PropertyInfo(alias="healthMonitoringEnabled")] + lifecycle_status: Annotated[Literal["enabled", "disabled"], PropertyInfo(alias="lifecycleStatus")] + """Set the visible agent lifecycle. Archive remains available only through DELETE.""" + name: str notify_on_failure: Annotated[bool, PropertyInfo(alias="notifyOnFailure")] @@ -33,9 +36,19 @@ class FlowUpdateParams(TypedDict, total=False): notify_webhook_id: Annotated[Optional[str], PropertyInfo(alias="notifyWebhookId")] recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")] + """Deprecated compatibility field. + + true maps to recordingPolicy.mode="flow"; false maps to "off". + """ + + recording_policy: Annotated[RecordingPolicy, PropertyInfo(alias="recordingPolicy")] self_healing_enabled: Annotated[bool, PropertyInfo(alias="selfHealingEnabled")] self_healing_max_attempts: Annotated[int, PropertyInfo(alias="selfHealingMaxAttempts")] trigger_id: Annotated[str, PropertyInfo(alias="triggerId")] + + +class RecordingPolicy(TypedDict, total=False): + mode: Required[Literal["off", "flow", "selected_steps"]] diff --git a/src/mobilerun_sdk/types/workflows/flow_update_response.py b/src/mobilerun_sdk/types/workflows/flow_update_response.py index ad10348f..511e934a 100644 --- a/src/mobilerun_sdk/types/workflows/flow_update_response.py +++ b/src/mobilerun_sdk/types/workflows/flow_update_response.py @@ -7,12 +7,18 @@ from ..._models import BaseModel -__all__ = ["FlowUpdateResponse", "Data"] +__all__ = ["FlowUpdateResponse", "Data", "DataRecordingPolicy"] + + +class DataRecordingPolicy(BaseModel): + mode: Literal["off", "flow", "selected_steps"] class Data(BaseModel): id: str + archived_at: Optional[str] = FieldInfo(alias="archivedAt", default=None) + blocked_at: Optional[str] = FieldInfo(alias="blockedAt", default=None) consecutive_failures: int = FieldInfo(alias="consecutiveFailures") @@ -30,6 +36,10 @@ class Data(BaseModel): device_ids: List[str] = FieldInfo(alias="deviceIds") enabled: bool + """ + Compatibility projection of lifecycleStatus; true only when lifecycleStatus is + enabled. + """ health_monitoring_enabled: bool = FieldInfo(alias="healthMonitoringEnabled") @@ -41,6 +51,8 @@ class Data(BaseModel): last_triggered_at: Optional[str] = FieldInfo(alias="lastTriggeredAt", default=None) + lifecycle_status: Literal["enabled", "disabled", "archived"] = FieldInfo(alias="lifecycleStatus") + name: str notify_on_failure: bool = FieldInfo(alias="notifyOnFailure") @@ -52,6 +64,12 @@ class Data(BaseModel): owner_id: str = FieldInfo(alias="ownerId") recording_enabled: bool = FieldInfo(alias="recordingEnabled") + """ + Deprecated: use recordingPolicy.mode ("flow" = recordingEnabled=true, "off" = + recordingEnabled=false). + """ + + recording_policy: DataRecordingPolicy = FieldInfo(alias="recordingPolicy") self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled") diff --git a/src/mobilerun_sdk/types/workflows/flows/action_add_params.py b/src/mobilerun_sdk/types/workflows/flows/action_add_params.py index 1275209c..88af2ccf 100644 --- a/src/mobilerun_sdk/types/workflows/flows/action_add_params.py +++ b/src/mobilerun_sdk/types/workflows/flows/action_add_params.py @@ -25,6 +25,8 @@ class ActionAddParams(TypedDict, total=False): parent_flow_action_id: Annotated[Optional[str], PropertyInfo(alias="parentFlowActionId")] + recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")] + class ChildOverrides(TypedDict, total=False): params: Dict[str, object] @@ -41,6 +43,8 @@ class Child(TypedDict, total=False): overrides: Optional[ChildOverrides] + recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")] + class Overrides(TypedDict, total=False): params: Dict[str, object] diff --git a/src/mobilerun_sdk/types/workflows/flows/action_add_response.py b/src/mobilerun_sdk/types/workflows/flows/action_add_response.py index 00d02c81..420a30e5 100644 --- a/src/mobilerun_sdk/types/workflows/flows/action_add_response.py +++ b/src/mobilerun_sdk/types/workflows/flows/action_add_response.py @@ -32,6 +32,12 @@ class Data(BaseModel): position: int + recording_enabled: bool = FieldInfo(alias="recordingEnabled") + """ + Selected for per-step recording under the flow's "selected_steps" recording + policy. + """ + class ActionAddResponse(BaseModel): data: Data diff --git a/src/mobilerun_sdk/types/workflows/flows/action_list_response.py b/src/mobilerun_sdk/types/workflows/flows/action_list_response.py index 88c4965b..1ff8dd43 100644 --- a/src/mobilerun_sdk/types/workflows/flows/action_list_response.py +++ b/src/mobilerun_sdk/types/workflows/flows/action_list_response.py @@ -32,6 +32,12 @@ class Data(BaseModel): position: int + recording_enabled: bool = FieldInfo(alias="recordingEnabled") + """ + Selected for per-step recording under the flow's "selected_steps" recording + policy. + """ + class ActionListResponse(BaseModel): data: List[Data] diff --git a/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py b/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py index ec5c42a1..fd89af25 100644 --- a/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py +++ b/src/mobilerun_sdk/types/workflows/flows/action_replace_params.py @@ -29,6 +29,8 @@ class ActionChild(TypedDict, total=False): overrides: Optional[ActionChildOverrides] + recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")] + class ActionOverrides(TypedDict, total=False): params: Dict[str, object] @@ -46,3 +48,5 @@ class Action(TypedDict, total=False): name_override: Annotated[str, PropertyInfo(alias="nameOverride")] overrides: Optional[ActionOverrides] + + recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")] diff --git a/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py b/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py index cf358f90..a9939a84 100644 --- a/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py +++ b/src/mobilerun_sdk/types/workflows/flows/action_replace_response.py @@ -32,6 +32,12 @@ class Data(BaseModel): position: int + recording_enabled: bool = FieldInfo(alias="recordingEnabled") + """ + Selected for per-step recording under the flow's "selected_steps" recording + policy. + """ + class ActionReplaceResponse(BaseModel): data: List[Data] diff --git a/src/mobilerun_sdk/types/workflows/trigger_fire_params.py b/src/mobilerun_sdk/types/workflows/trigger_fire_params.py index 03847b71..1a1f266d 100644 --- a/src/mobilerun_sdk/types/workflows/trigger_fire_params.py +++ b/src/mobilerun_sdk/types/workflows/trigger_fire_params.py @@ -3,7 +3,9 @@ from __future__ import annotations from typing import Dict -from typing_extensions import Required, TypedDict +from typing_extensions import Required, Annotated, TypedDict + +from ..._utils import PropertyInfo __all__ = ["TriggerFireParams"] @@ -15,3 +17,11 @@ class TriggerFireParams(TypedDict, total=False): Validated against the trigger's customPayloadSchema when one is configured; otherwise only "must be a JSON object" is enforced. """ + + invocation_id: Annotated[str, PropertyInfo(alias="invocationId")] + """Optional client-supplied idempotency key. + + When provided, a flow that already has an execution for this (flow, + invocationId) is skipped and `deduplicated` is true. When omitted a fresh + server-side id is generated (no dedup). + """ diff --git a/src/mobilerun_sdk/types/workflows/trigger_fire_response.py b/src/mobilerun_sdk/types/workflows/trigger_fire_response.py index b0b49511..324a5242 100644 --- a/src/mobilerun_sdk/types/workflows/trigger_fire_response.py +++ b/src/mobilerun_sdk/types/workflows/trigger_fire_response.py @@ -8,15 +8,23 @@ class TriggerFireResponse(BaseModel): + deduplicated: bool + """ + True when at least one attached flow was skipped because it already had an + execution for this (flow, invocationId). Only ever true when the client supplied + invocationId. + """ + enqueued_count: int = FieldInfo(alias="enqueuedCount") """Number of flow executions enqueued. - May be 0 if no flows are attached to this trigger, or if all attached flows are - currently in cooldown. + May be 0 if no flows are attached to this trigger, if all attached flows are + currently in cooldown, or if every attached flow was deduplicated. """ invocation_id: str = FieldInfo(alias="invocationId") - """Unique ID for this fire invocation. - - Job IDs in the execution queue are derived from it (one per enqueued flow). + """ + Unique ID for this fire invocation (echoes the client-supplied invocationId, or + a generated one). Job IDs in the execution queue are derived from it (one per + enqueued flow). """ diff --git a/tests/api_resources/assistant/test_conversations.py b/tests/api_resources/assistant/test_conversations.py index 32ef5823..4652e4ad 100644 --- a/tests/api_resources/assistant/test_conversations.py +++ b/tests/api_resources/assistant/test_conversations.py @@ -172,6 +172,15 @@ def test_method_abort(self, client: Mobilerun) -> None: ) assert_matches_type(ConversationAbortResponse, conversation, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_abort_with_all_params(self, client: Mobilerun) -> None: + conversation = client.assistant.conversations.abort( + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + expected_turn_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ConversationAbortResponse, conversation, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_raw_response_abort(self, client: Mobilerun) -> None: @@ -580,6 +589,15 @@ async def test_method_abort(self, async_client: AsyncMobilerun) -> None: ) assert_matches_type(ConversationAbortResponse, conversation, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_abort_with_all_params(self, async_client: AsyncMobilerun) -> None: + conversation = await async_client.assistant.conversations.abort( + session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + expected_turn_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(ConversationAbortResponse, conversation, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_raw_response_abort(self, async_client: AsyncMobilerun) -> None: diff --git a/tests/api_resources/connect/test_proxies.py b/tests/api_resources/connect/test_proxies.py index acd84195..f2e62efb 100644 --- a/tests/api_resources/connect/test_proxies.py +++ b/tests/api_resources/connect/test_proxies.py @@ -113,6 +113,16 @@ def test_method_buy(self, client: Mobilerun) -> None: ) assert_matches_type(ProxyBuyResponse, proxy, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_buy_with_all_params(self, client: Mobilerun) -> None: + proxy = client.connect.proxies.buy( + country="country", + type="dedicated_residential", + idempotency_key="Idempotency-Key", + ) + assert_matches_type(ProxyBuyResponse, proxy, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_raw_response_buy(self, client: Mobilerun) -> None: @@ -395,6 +405,16 @@ async def test_method_buy(self, async_client: AsyncMobilerun) -> None: ) assert_matches_type(ProxyBuyResponse, proxy, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_buy_with_all_params(self, async_client: AsyncMobilerun) -> None: + proxy = await async_client.connect.proxies.buy( + country="country", + type="dedicated_residential", + idempotency_key="Idempotency-Key", + ) + assert_matches_type(ProxyBuyResponse, proxy, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_raw_response_buy(self, async_client: AsyncMobilerun) -> None: diff --git a/tests/api_resources/devices/test_apps.py b/tests/api_resources/devices/test_apps.py index c1281d68..aa3726ed 100644 --- a/tests/api_resources/devices/test_apps.py +++ b/tests/api_resources/devices/test_apps.py @@ -219,7 +219,9 @@ def test_method_install_with_all_params_overload_1(self, client: Mobilerun) -> N device_id="deviceId", bundle_id="x", background=True, + country="se", package_name="x", + version_code=1, x_device_display_id=0, ) assert app is None @@ -278,6 +280,8 @@ def test_method_install_with_all_params_overload_2(self, client: Mobilerun) -> N package_name="x", background=True, bundle_id="x", + country="se", + version_code=1, x_device_display_id=0, ) assert app is None @@ -769,7 +773,9 @@ async def test_method_install_with_all_params_overload_1(self, async_client: Asy device_id="deviceId", bundle_id="x", background=True, + country="se", package_name="x", + version_code=1, x_device_display_id=0, ) assert app is None @@ -828,6 +834,8 @@ async def test_method_install_with_all_params_overload_2(self, async_client: Asy package_name="x", background=True, bundle_id="x", + country="se", + version_code=1, x_device_display_id=0, ) assert app is None diff --git a/tests/api_resources/devices/test_keyboard.py b/tests/api_resources/devices/test_keyboard.py index 766a63b8..29044ca3 100644 --- a/tests/api_resources/devices/test_keyboard.py +++ b/tests/api_resources/devices/test_keyboard.py @@ -138,6 +138,7 @@ def test_method_write_with_all_params(self, client: Mobilerun) -> None: device_id="deviceId", text="text", clear=True, + completion_mode="accepted", error_rate=0, stealth=True, wpm=0, @@ -311,6 +312,7 @@ async def test_method_write_with_all_params(self, async_client: AsyncMobilerun) device_id="deviceId", text="text", clear=True, + completion_mode="accepted", error_rate=0, stealth=True, wpm=0, diff --git a/tests/api_resources/devices/test_recordings.py b/tests/api_resources/devices/test_recordings.py index f3e134fb..4d72e541 100644 --- a/tests/api_resources/devices/test_recordings.py +++ b/tests/api_resources/devices/test_recordings.py @@ -140,6 +140,7 @@ def test_method_start_with_all_params(self, client: Mobilerun) -> None: recording = client.devices.recordings.start( device_id="deviceId", name="name", + quality=1, retention_days=1, types=["string"], ) @@ -511,6 +512,7 @@ async def test_method_start_with_all_params(self, async_client: AsyncMobilerun) recording = await async_client.devices.recordings.start( device_id="deviceId", name="name", + quality=1, retention_days=1, types=["string"], ) diff --git a/tests/api_resources/esims/__init__.py b/tests/api_resources/esims/__init__.py deleted file mode 100644 index fd8019a9..00000000 --- a/tests/api_resources/esims/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/esims/test_messages.py b/tests/api_resources/esims/test_messages.py deleted file mode 100644 index aa71f91d..00000000 --- a/tests/api_resources/esims/test_messages.py +++ /dev/null @@ -1,262 +0,0 @@ -# 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 tests.utils import assert_matches_type -from mobilerun_sdk import Mobilerun, AsyncMobilerun -from mobilerun_sdk.types.esims import MessageListResponse, MessageSendResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestMessages: - 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_list(self, client: Mobilerun) -> None: - message = client.esims.messages.list( - id="550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(MessageListResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_list_with_all_params(self, client: Mobilerun) -> None: - message = client.esims.messages.list( - id="550e8400-e29b-41d4-a716-446655440000", - direction="all", - number_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - page=1, - page_size=1, - peer_key="x", - peer_number="xxx", - status="all", - ) - assert_matches_type(MessageListResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_list(self, client: Mobilerun) -> None: - response = client.esims.messages.with_raw_response.list( - id="550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = response.parse() - assert_matches_type(MessageListResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_list(self, client: Mobilerun) -> None: - with client.esims.messages.with_streaming_response.list( - id="550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - message = response.parse() - assert_matches_type(MessageListResponse, message, 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: Mobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.esims.messages.with_raw_response.list( - id="", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_send(self, client: Mobilerun) -> None: - message = client.esims.messages.send( - id="550e8400-e29b-41d4-a716-446655440000", - body="x", - to="+15551230001", - ) - assert_matches_type(MessageSendResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_send_with_all_params(self, client: Mobilerun) -> None: - message = client.esims.messages.send( - id="550e8400-e29b-41d4-a716-446655440000", - body="x", - to="+15551230001", - client_request_id="x", - delivery_report=True, - ) - assert_matches_type(MessageSendResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_send(self, client: Mobilerun) -> None: - response = client.esims.messages.with_raw_response.send( - id="550e8400-e29b-41d4-a716-446655440000", - body="x", - to="+15551230001", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = response.parse() - assert_matches_type(MessageSendResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_send(self, client: Mobilerun) -> None: - with client.esims.messages.with_streaming_response.send( - id="550e8400-e29b-41d4-a716-446655440000", - body="x", - to="+15551230001", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - message = response.parse() - assert_matches_type(MessageSendResponse, message, 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(self, client: Mobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.esims.messages.with_raw_response.send( - id="", - body="x", - to="+15551230001", - ) - - -class TestAsyncMessages: - 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_list(self, async_client: AsyncMobilerun) -> None: - message = await async_client.esims.messages.list( - id="550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(MessageListResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: - message = await async_client.esims.messages.list( - id="550e8400-e29b-41d4-a716-446655440000", - direction="all", - number_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - page=1, - page_size=1, - peer_key="x", - peer_number="xxx", - status="all", - ) - assert_matches_type(MessageListResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.messages.with_raw_response.list( - id="550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = await response.parse() - assert_matches_type(MessageListResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.messages.with_streaming_response.list( - id="550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - message = await response.parse() - assert_matches_type(MessageListResponse, message, 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: AsyncMobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.esims.messages.with_raw_response.list( - id="", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_send(self, async_client: AsyncMobilerun) -> None: - message = await async_client.esims.messages.send( - id="550e8400-e29b-41d4-a716-446655440000", - body="x", - to="+15551230001", - ) - assert_matches_type(MessageSendResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_send_with_all_params(self, async_client: AsyncMobilerun) -> None: - message = await async_client.esims.messages.send( - id="550e8400-e29b-41d4-a716-446655440000", - body="x", - to="+15551230001", - client_request_id="x", - delivery_report=True, - ) - assert_matches_type(MessageSendResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_send(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.messages.with_raw_response.send( - id="550e8400-e29b-41d4-a716-446655440000", - body="x", - to="+15551230001", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - message = await response.parse() - assert_matches_type(MessageSendResponse, message, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_send(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.messages.with_streaming_response.send( - id="550e8400-e29b-41d4-a716-446655440000", - body="x", - to="+15551230001", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - message = await response.parse() - assert_matches_type(MessageSendResponse, message, 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(self, async_client: AsyncMobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.esims.messages.with_raw_response.send( - id="", - body="x", - to="+15551230001", - ) diff --git a/tests/api_resources/test_esims.py b/tests/api_resources/test_esims.py deleted file mode 100644 index a47275d3..00000000 --- a/tests/api_resources/test_esims.py +++ /dev/null @@ -1,953 +0,0 @@ -# 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 tests.utils import assert_matches_type -from mobilerun_sdk import Mobilerun, AsyncMobilerun -from mobilerun_sdk.types import ( - EsimListResponse, - EsimCreateResponse, - EsimImportResponse, - EsimUpdateResponse, - EsimInstallResponse, - EsimCapacityResponse, - EsimRetrieveResponse, - EsimSelectorResponse, - EsimInstallStatusResponse, - EsimConfirmPaymentResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestEsims: - 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: Mobilerun) -> None: - esim = client.esims.create() - assert_matches_type(EsimCreateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_create_with_all_params(self, client: Mobilerun) -> None: - esim = client.esims.create( - idempotency_key="idempotencyKey", - name="Mom's phone", - ) - assert_matches_type(EsimCreateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_create(self, client: Mobilerun) -> None: - response = client.esims.with_raw_response.create() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = response.parse() - assert_matches_type(EsimCreateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_create(self, client: Mobilerun) -> None: - with client.esims.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = response.parse() - assert_matches_type(EsimCreateResponse, esim, 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: Mobilerun) -> None: - esim = client.esims.retrieve( - "550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(EsimRetrieveResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_retrieve(self, client: Mobilerun) -> None: - response = client.esims.with_raw_response.retrieve( - "550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = response.parse() - assert_matches_type(EsimRetrieveResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_retrieve(self, client: Mobilerun) -> None: - with client.esims.with_streaming_response.retrieve( - "550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = response.parse() - assert_matches_type(EsimRetrieveResponse, esim, 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: Mobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.esims.with_raw_response.retrieve( - "", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_update(self, client: Mobilerun) -> None: - esim = client.esims.update( - id="550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(EsimUpdateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_update_with_all_params(self, client: Mobilerun) -> None: - esim = client.esims.update( - id="550e8400-e29b-41d4-a716-446655440000", - msisdn="+33612345678", - name="Mom's phone", - ) - assert_matches_type(EsimUpdateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_update(self, client: Mobilerun) -> None: - response = client.esims.with_raw_response.update( - id="550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = response.parse() - assert_matches_type(EsimUpdateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_update(self, client: Mobilerun) -> None: - with client.esims.with_streaming_response.update( - id="550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = response.parse() - assert_matches_type(EsimUpdateResponse, esim, 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: Mobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.esims.with_raw_response.update( - id="", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_list(self, client: Mobilerun) -> None: - esim = client.esims.list() - assert_matches_type(EsimListResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_list_with_all_params(self, client: Mobilerun) -> None: - esim = client.esims.list( - mine="true", - page=1, - page_size=1, - status="all", - ) - assert_matches_type(EsimListResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_list(self, client: Mobilerun) -> None: - response = client.esims.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = response.parse() - assert_matches_type(EsimListResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_list(self, client: Mobilerun) -> None: - with client.esims.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = response.parse() - assert_matches_type(EsimListResponse, esim, 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: Mobilerun) -> None: - esim = client.esims.delete( - "550e8400-e29b-41d4-a716-446655440000", - ) - assert esim is None - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_delete(self, client: Mobilerun) -> None: - response = client.esims.with_raw_response.delete( - "550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = response.parse() - assert esim is None - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_delete(self, client: Mobilerun) -> None: - with client.esims.with_streaming_response.delete( - "550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = response.parse() - assert esim 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: Mobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.esims.with_raw_response.delete( - "", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_capacity(self, client: Mobilerun) -> None: - esim = client.esims.capacity() - assert_matches_type(EsimCapacityResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_capacity(self, client: Mobilerun) -> None: - response = client.esims.with_raw_response.capacity() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = response.parse() - assert_matches_type(EsimCapacityResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_capacity(self, client: Mobilerun) -> None: - with client.esims.with_streaming_response.capacity() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = response.parse() - assert_matches_type(EsimCapacityResponse, esim, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_confirm_payment(self, client: Mobilerun) -> None: - esim = client.esims.confirm_payment( - "550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_confirm_payment(self, client: Mobilerun) -> None: - response = client.esims.with_raw_response.confirm_payment( - "550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = response.parse() - assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_confirm_payment(self, client: Mobilerun) -> None: - with client.esims.with_streaming_response.confirm_payment( - "550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = response.parse() - assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_path_params_confirm_payment(self, client: Mobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.esims.with_raw_response.confirm_payment( - "", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_import(self, client: Mobilerun) -> None: - esim = client.esims.import_() - assert_matches_type(EsimImportResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_import_with_all_params(self, client: Mobilerun) -> None: - esim = client.esims.import_( - auto_install=True, - carrier_name="carrierName", - confirmation_code="confirmationCode", - country_code="countryCode", - device_id="physedge-dev-8f3a2c", - idempotency_key="x", - lpa_code="LPA:1$smdp.example.com$QR-MATCH-1", - matching_id="matchingId", - msisdn="+33612345678", - name="Mom's phone", - notes="notes", - smdp_address="smdp.example.com", - ) - assert_matches_type(EsimImportResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_import(self, client: Mobilerun) -> None: - response = client.esims.with_raw_response.import_() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = response.parse() - assert_matches_type(EsimImportResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_import(self, client: Mobilerun) -> None: - with client.esims.with_streaming_response.import_() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = response.parse() - assert_matches_type(EsimImportResponse, esim, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_install(self, client: Mobilerun) -> None: - esim = client.esims.install( - id="550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(EsimInstallResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_install_with_all_params(self, client: Mobilerun) -> None: - esim = client.esims.install( - id="550e8400-e29b-41d4-a716-446655440000", - device_id="physedge-dev-8f3a2c", - ) - assert_matches_type(EsimInstallResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_install(self, client: Mobilerun) -> None: - response = client.esims.with_raw_response.install( - id="550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = response.parse() - assert_matches_type(EsimInstallResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_install(self, client: Mobilerun) -> None: - with client.esims.with_streaming_response.install( - id="550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = response.parse() - assert_matches_type(EsimInstallResponse, esim, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_path_params_install(self, client: Mobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.esims.with_raw_response.install( - id="", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_install_status(self, client: Mobilerun) -> None: - esim = client.esims.install_status( - "550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(EsimInstallStatusResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_install_status(self, client: Mobilerun) -> None: - response = client.esims.with_raw_response.install_status( - "550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = response.parse() - assert_matches_type(EsimInstallStatusResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_install_status(self, client: Mobilerun) -> None: - with client.esims.with_streaming_response.install_status( - "550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = response.parse() - assert_matches_type(EsimInstallStatusResponse, esim, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_path_params_install_status(self, client: Mobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - client.esims.with_raw_response.install_status( - "", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_selector(self, client: Mobilerun) -> None: - esim = client.esims.selector() - assert_matches_type(EsimSelectorResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_method_selector_with_all_params(self, client: Mobilerun) -> None: - esim = client.esims.selector( - page=1, - page_size=1, - ) - assert_matches_type(EsimSelectorResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_raw_response_selector(self, client: Mobilerun) -> None: - response = client.esims.with_raw_response.selector() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = response.parse() - assert_matches_type(EsimSelectorResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - def test_streaming_response_selector(self, client: Mobilerun) -> None: - with client.esims.with_streaming_response.selector() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = response.parse() - assert_matches_type(EsimSelectorResponse, esim, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncEsims: - 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: AsyncMobilerun) -> None: - esim = await async_client.esims.create() - assert_matches_type(EsimCreateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.create( - idempotency_key="idempotencyKey", - name="Mom's phone", - ) - assert_matches_type(EsimCreateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_create(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.with_raw_response.create() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = await response.parse() - assert_matches_type(EsimCreateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.with_streaming_response.create() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = await response.parse() - assert_matches_type(EsimCreateResponse, esim, 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: AsyncMobilerun) -> None: - esim = await async_client.esims.retrieve( - "550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(EsimRetrieveResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.with_raw_response.retrieve( - "550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = await response.parse() - assert_matches_type(EsimRetrieveResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.with_streaming_response.retrieve( - "550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = await response.parse() - assert_matches_type(EsimRetrieveResponse, esim, 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: AsyncMobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.esims.with_raw_response.retrieve( - "", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_update(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.update( - id="550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(EsimUpdateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.update( - id="550e8400-e29b-41d4-a716-446655440000", - msisdn="+33612345678", - name="Mom's phone", - ) - assert_matches_type(EsimUpdateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_update(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.with_raw_response.update( - id="550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = await response.parse() - assert_matches_type(EsimUpdateResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_update(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.with_streaming_response.update( - id="550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = await response.parse() - assert_matches_type(EsimUpdateResponse, esim, 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: AsyncMobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.esims.with_raw_response.update( - id="", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_list(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.list() - assert_matches_type(EsimListResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.list( - mine="true", - page=1, - page_size=1, - status="all", - ) - assert_matches_type(EsimListResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_list(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = await response.parse() - assert_matches_type(EsimListResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = await response.parse() - assert_matches_type(EsimListResponse, esim, 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: AsyncMobilerun) -> None: - esim = await async_client.esims.delete( - "550e8400-e29b-41d4-a716-446655440000", - ) - assert esim is None - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_delete(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.with_raw_response.delete( - "550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = await response.parse() - assert esim is None - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.with_streaming_response.delete( - "550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = await response.parse() - assert esim 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: AsyncMobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.esims.with_raw_response.delete( - "", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_capacity(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.capacity() - assert_matches_type(EsimCapacityResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_capacity(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.with_raw_response.capacity() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = await response.parse() - assert_matches_type(EsimCapacityResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_capacity(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.with_streaming_response.capacity() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = await response.parse() - assert_matches_type(EsimCapacityResponse, esim, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_confirm_payment(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.confirm_payment( - "550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_confirm_payment(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.with_raw_response.confirm_payment( - "550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = await response.parse() - assert_matches_type(EsimConfirmPaymentResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_confirm_payment(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.with_streaming_response.confirm_payment( - "550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = await response.parse() - assert_matches_type(EsimConfirmPaymentResponse, esim, 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_confirm_payment(self, async_client: AsyncMobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.esims.with_raw_response.confirm_payment( - "", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_import(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.import_() - assert_matches_type(EsimImportResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_import_with_all_params(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.import_( - auto_install=True, - carrier_name="carrierName", - confirmation_code="confirmationCode", - country_code="countryCode", - device_id="physedge-dev-8f3a2c", - idempotency_key="x", - lpa_code="LPA:1$smdp.example.com$QR-MATCH-1", - matching_id="matchingId", - msisdn="+33612345678", - name="Mom's phone", - notes="notes", - smdp_address="smdp.example.com", - ) - assert_matches_type(EsimImportResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_import(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.with_raw_response.import_() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = await response.parse() - assert_matches_type(EsimImportResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_import(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.with_streaming_response.import_() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = await response.parse() - assert_matches_type(EsimImportResponse, esim, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_install(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.install( - id="550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(EsimInstallResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_install_with_all_params(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.install( - id="550e8400-e29b-41d4-a716-446655440000", - device_id="physedge-dev-8f3a2c", - ) - assert_matches_type(EsimInstallResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_install(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.with_raw_response.install( - id="550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = await response.parse() - assert_matches_type(EsimInstallResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_install(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.with_streaming_response.install( - id="550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = await response.parse() - assert_matches_type(EsimInstallResponse, esim, 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_install(self, async_client: AsyncMobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.esims.with_raw_response.install( - id="", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_install_status(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.install_status( - "550e8400-e29b-41d4-a716-446655440000", - ) - assert_matches_type(EsimInstallStatusResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_install_status(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.with_raw_response.install_status( - "550e8400-e29b-41d4-a716-446655440000", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = await response.parse() - assert_matches_type(EsimInstallStatusResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_install_status(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.with_streaming_response.install_status( - "550e8400-e29b-41d4-a716-446655440000", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = await response.parse() - assert_matches_type(EsimInstallStatusResponse, esim, 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_install_status(self, async_client: AsyncMobilerun) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `id` but received ''"): - await async_client.esims.with_raw_response.install_status( - "", - ) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_selector(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.selector() - assert_matches_type(EsimSelectorResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_method_selector_with_all_params(self, async_client: AsyncMobilerun) -> None: - esim = await async_client.esims.selector( - page=1, - page_size=1, - ) - assert_matches_type(EsimSelectorResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_raw_response_selector(self, async_client: AsyncMobilerun) -> None: - response = await async_client.esims.with_raw_response.selector() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - esim = await response.parse() - assert_matches_type(EsimSelectorResponse, esim, path=["response"]) - - @pytest.mark.skip(reason="Mock server tests are disabled") - @parametrize - async def test_streaming_response_selector(self, async_client: AsyncMobilerun) -> None: - async with async_client.esims.with_streaming_response.selector() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - esim = await response.parse() - assert_matches_type(EsimSelectorResponse, esim, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/test_mailboxes.py b/tests/api_resources/test_mailboxes.py index fee64e12..45d04734 100644 --- a/tests/api_resources/test_mailboxes.py +++ b/tests/api_resources/test_mailboxes.py @@ -42,6 +42,7 @@ def test_method_create_with_all_params(self, client: Mobilerun) -> None: mailbox = client.mailboxes.create( client_request_id="x", billing_preference="included", + domain_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", label="label", local_part="jane-doe", ) @@ -435,6 +436,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMobilerun) mailbox = await async_client.mailboxes.create( client_request_id="x", billing_preference="included", + domain_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", label="label", local_part="jane-doe", ) diff --git a/tests/api_resources/test_tasks.py b/tests/api_resources/test_tasks.py index cf65f53d..8ff81d06 100644 --- a/tests/api_resources/test_tasks.py +++ b/tests/api_resources/test_tasks.py @@ -84,7 +84,8 @@ def test_method_list_with_all_params(self, client: Mobilerun) -> None: page=1, page_size=1, query="query", - status="queued", + source="api", + status="prepared", ) assert_matches_type(TaskListResponse, task, path=["response"]) @@ -252,7 +253,6 @@ def test_method_run_with_all_params(self, client: Mobilerun) -> None: device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", task="x", accessibility=True, - agent_id=0, apps=["string"], continue_on_failure=True, credentials=[ @@ -262,15 +262,16 @@ def test_method_run_with_all_params(self, client: Mobilerun) -> None: } ], display_id=0, - execution_timeout=0, + execution_timeout=1, files=["string"], llm_model="llmModel", max_steps=0, - memory_namespace="memoryNamespace", output_schema={"foo": "bar"}, reasoning=True, + recording_enabled=True, stealth=True, subagent_model="subagentModel", + system_prompt="systemPrompt", temperature=0, vision=True, vpn_country="US", @@ -322,7 +323,6 @@ def test_method_run_streamed_with_all_params(self, client: Mobilerun) -> None: device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", task="x", accessibility=True, - agent_id=0, apps=["string"], continue_on_failure=True, credentials=[ @@ -332,15 +332,16 @@ def test_method_run_streamed_with_all_params(self, client: Mobilerun) -> None: } ], display_id=0, - execution_timeout=0, + execution_timeout=1, files=["string"], llm_model="llmModel", max_steps=0, - memory_namespace="memoryNamespace", output_schema={"foo": "bar"}, reasoning=True, + recording_enabled=True, stealth=True, subagent_model="subagentModel", + system_prompt="systemPrompt", temperature=0, vision=True, vpn_country="US", @@ -528,7 +529,8 @@ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) - page=1, page_size=1, query="query", - status="queued", + source="api", + status="prepared", ) assert_matches_type(TaskListResponse, task, path=["response"]) @@ -696,7 +698,6 @@ async def test_method_run_with_all_params(self, async_client: AsyncMobilerun) -> device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", task="x", accessibility=True, - agent_id=0, apps=["string"], continue_on_failure=True, credentials=[ @@ -706,15 +707,16 @@ async def test_method_run_with_all_params(self, async_client: AsyncMobilerun) -> } ], display_id=0, - execution_timeout=0, + execution_timeout=1, files=["string"], llm_model="llmModel", max_steps=0, - memory_namespace="memoryNamespace", output_schema={"foo": "bar"}, reasoning=True, + recording_enabled=True, stealth=True, subagent_model="subagentModel", + system_prompt="systemPrompt", temperature=0, vision=True, vpn_country="US", @@ -766,7 +768,6 @@ async def test_method_run_streamed_with_all_params(self, async_client: AsyncMobi device_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", task="x", accessibility=True, - agent_id=0, apps=["string"], continue_on_failure=True, credentials=[ @@ -776,15 +777,16 @@ async def test_method_run_streamed_with_all_params(self, async_client: AsyncMobi } ], display_id=0, - execution_timeout=0, + execution_timeout=1, files=["string"], llm_model="llmModel", max_steps=0, - memory_namespace="memoryNamespace", output_schema={"foo": "bar"}, reasoning=True, + recording_enabled=True, stealth=True, subagent_model="subagentModel", + system_prompt="systemPrompt", temperature=0, vision=True, vpn_country="US", diff --git a/tests/api_resources/workflows/flows/test_actions.py b/tests/api_resources/workflows/flows/test_actions.py index 797f7246..21f7ca88 100644 --- a/tests/api_resources/workflows/flows/test_actions.py +++ b/tests/api_resources/workflows/flows/test_actions.py @@ -88,12 +88,14 @@ def test_method_add_with_all_params(self, client: Mobilerun) -> None: "continue_on_error": True, "name_override": "x", "overrides": {"params": {"foo": "bar"}}, + "recording_enabled": True, } ], continue_on_error=True, name_override="x", overrides={"params": {"foo": "bar"}}, parent_flow_action_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + recording_enabled=True, ) assert_matches_type(ActionAddResponse, action, path=["response"]) @@ -327,12 +329,14 @@ async def test_method_add_with_all_params(self, async_client: AsyncMobilerun) -> "continue_on_error": True, "name_override": "x", "overrides": {"params": {"foo": "bar"}}, + "recording_enabled": True, } ], continue_on_error=True, name_override="x", overrides={"params": {"foo": "bar"}}, parent_flow_action_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + recording_enabled=True, ) assert_matches_type(ActionAddResponse, action, path=["response"]) diff --git a/tests/api_resources/workflows/test_executions.py b/tests/api_resources/workflows/test_executions.py index 7b24f4c0..20711476 100644 --- a/tests/api_resources/workflows/test_executions.py +++ b/tests/api_resources/workflows/test_executions.py @@ -76,6 +76,7 @@ def test_method_list_with_all_params(self, client: Mobilerun) -> None: execution = client.workflows.executions.list( flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", from_="from", + invocation_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", order_by="startedAt", order_by_direction="asc", page=1, @@ -250,6 +251,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncMobilerun) - execution = await async_client.workflows.executions.list( flow_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", from_="from", + invocation_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", order_by="startedAt", order_by_direction="asc", page=1, diff --git a/tests/api_resources/workflows/test_flows.py b/tests/api_resources/workflows/test_flows.py index 845d0f4f..1b4987c7 100644 --- a/tests/api_resources/workflows/test_flows.py +++ b/tests/api_resources/workflows/test_flows.py @@ -57,11 +57,13 @@ def test_method_create_with_all_params(self, client: Mobilerun) -> None: "continue_on_error": True, "name_override": "x", "overrides": {"params": {"foo": "bar"}}, + "recording_enabled": True, } ], "continue_on_error": True, "name_override": "x", "overrides": {"params": {"foo": "bar"}}, + "recording_enabled": True, } ], name="x", @@ -76,6 +78,7 @@ def test_method_create_with_all_params(self, client: Mobilerun) -> None: notify_on_success=True, notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", recording_enabled=True, + recording_policy={"mode": "off"}, self_healing_enabled=True, self_healing_max_attempts=1, ) @@ -182,11 +185,13 @@ def test_method_update_with_all_params(self, client: Mobilerun) -> None: device_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], enabled=True, health_monitoring_enabled=True, + lifecycle_status="enabled", name="x", notify_on_failure=True, notify_on_success=True, notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", recording_enabled=True, + recording_policy={"mode": "off"}, self_healing_enabled=True, self_healing_max_attempts=1, trigger_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", @@ -537,11 +542,13 @@ async def test_method_create_with_all_params(self, async_client: AsyncMobilerun) "continue_on_error": True, "name_override": "x", "overrides": {"params": {"foo": "bar"}}, + "recording_enabled": True, } ], "continue_on_error": True, "name_override": "x", "overrides": {"params": {"foo": "bar"}}, + "recording_enabled": True, } ], name="x", @@ -556,6 +563,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMobilerun) notify_on_success=True, notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", recording_enabled=True, + recording_policy={"mode": "off"}, self_healing_enabled=True, self_healing_max_attempts=1, ) @@ -662,11 +670,13 @@ async def test_method_update_with_all_params(self, async_client: AsyncMobilerun) device_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], enabled=True, health_monitoring_enabled=True, + lifecycle_status="enabled", name="x", notify_on_failure=True, notify_on_success=True, notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", recording_enabled=True, + recording_policy={"mode": "off"}, self_healing_enabled=True, self_healing_max_attempts=1, trigger_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", diff --git a/tests/api_resources/workflows/test_triggers.py b/tests/api_resources/workflows/test_triggers.py index c29dff8d..7149612e 100644 --- a/tests/api_resources/workflows/test_triggers.py +++ b/tests/api_resources/workflows/test_triggers.py @@ -293,6 +293,16 @@ def test_method_fire(self, client: Mobilerun) -> None: ) assert_matches_type(TriggerFireResponse, trigger, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + def test_method_fire_with_all_params(self, client: Mobilerun) -> None: + trigger = client.workflows.triggers.fire( + trigger_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + payload={"foo": "bar"}, + invocation_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(TriggerFireResponse, trigger, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize def test_raw_response_fire(self, client: Mobilerun) -> None: @@ -605,6 +615,16 @@ async def test_method_fire(self, async_client: AsyncMobilerun) -> None: ) assert_matches_type(TriggerFireResponse, trigger, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") + @parametrize + async def test_method_fire_with_all_params(self, async_client: AsyncMobilerun) -> None: + trigger = await async_client.workflows.triggers.fire( + trigger_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + payload={"foo": "bar"}, + invocation_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + ) + assert_matches_type(TriggerFireResponse, trigger, path=["response"]) + @pytest.mark.skip(reason="Mock server tests are disabled") @parametrize async def test_raw_response_fire(self, async_client: AsyncMobilerun) -> None: