diff --git a/.stats.yml b/.stats.yml
index fa7630c7..027e42a1 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 217
+configured_endpoints: 236
diff --git a/api.md b/api.md
index 444c197a..3081e9c2 100644
--- a/api.md
+++ b/api.md
@@ -325,6 +325,19 @@ Methods:
- client.devices.tasks.list(device_id, \*\*params) -> TaskListResponse
+## Clipboard
+
+Types:
+
+```python
+from mobilerun_sdk.types.devices import ClipboardGetResponse
+```
+
+Methods:
+
+- client.devices.clipboard.get(device_id) -> ClipboardGetResponse
+- client.devices.clipboard.set(device_id, \*\*params) -> None
+
## Timezone
Types:
@@ -806,17 +819,64 @@ Methods:
- client.webhooks.deliveries.retrieve_attempts(delivery_id, \*, id) -> DeliveryRetrieveAttemptsResponse
- client.webhooks.deliveries.stats(\*\*params) -> DeliveryStatsResponse
-# Agents
+# Files
Types:
```python
-from mobilerun_sdk.types import AgentListResponse
+from mobilerun_sdk.types import (
+ FileUpdateResponse,
+ FileListResponse,
+ FileDeleteResponse,
+ FileCancelPendingResponse,
+ FileConfirmResponse,
+ FileUploadURLResponse,
+)
+```
+
+Methods:
+
+- client.files.update(file_id, \*\*params) -> FileUpdateResponse
+- client.files.list(\*\*params) -> FileListResponse
+- client.files.delete(file_id) -> FileDeleteResponse
+- client.files.cancel_pending(file_id) -> FileCancelPendingResponse
+- client.files.confirm(file_id) -> FileConfirmResponse
+- client.files.download(file_id) -> None
+- client.files.upload_url(\*\*params) -> FileUploadURLResponse
+
+# Assistant
+
+## Conversations
+
+Types:
+
+```python
+from mobilerun_sdk.types.assistant import (
+ ConversationCreateResponse,
+ ConversationUpdateResponse,
+ ConversationListResponse,
+ ConversationAbortResponse,
+ ConversationAnswerPermissionResponse,
+ ConversationAnswerQuestionResponse,
+ ConversationHistoryResponse,
+ ConversationRejectQuestionResponse,
+ ConversationSendResponse,
+ ConversationStreamResponse,
+)
```
Methods:
-- client.agents.list() -> AgentListResponse
+- client.assistant.conversations.create(\*\*params) -> ConversationCreateResponse
+- client.assistant.conversations.update(id, \*\*params) -> ConversationUpdateResponse
+- client.assistant.conversations.list(\*\*params) -> ConversationListResponse
+- client.assistant.conversations.abort(\*\*params) -> ConversationAbortResponse
+- client.assistant.conversations.answer_permission(\*\*params) -> ConversationAnswerPermissionResponse
+- client.assistant.conversations.answer_question(\*\*params) -> ConversationAnswerQuestionResponse
+- client.assistant.conversations.history(\*\*params) -> ConversationHistoryResponse
+- client.assistant.conversations.reject_question(\*\*params) -> ConversationRejectQuestionResponse
+- client.assistant.conversations.send(\*\*params) -> ConversationSendResponse
+- client.assistant.conversations.stream(\*\*params) -> str
# AppEvents
@@ -893,7 +953,7 @@ Methods:
- client.esims.import\_(\*\*params) -> EsimImportResponse
- client.esims.install(id, \*\*params) -> EsimInstallResponse
- client.esims.install_status(id) -> EsimInstallStatusResponse
-- client.esims.selector() -> EsimSelectorResponse
+- client.esims.selector(\*\*params) -> EsimSelectorResponse
## Messages
@@ -941,6 +1001,7 @@ Types:
from mobilerun_sdk.types import (
NumberCreateResponse,
NumberRetrieveResponse,
+ NumberUpdateResponse,
NumberListResponse,
NumberDeleteResponse,
NumberCountriesResponse,
@@ -952,6 +1013,7 @@ Methods:
- client.numbers.create(\*\*params) -> NumberCreateResponse
- client.numbers.retrieve(id) -> NumberRetrieveResponse
+- client.numbers.update(id, \*\*params) -> NumberUpdateResponse
- client.numbers.list(\*\*params) -> NumberListResponse
- client.numbers.delete(id) -> NumberDeleteResponse
- client.numbers.countries() -> NumberCountriesResponse
diff --git a/src/mobilerun_sdk/_client.py b/src/mobilerun_sdk/_client.py
index 218abfaf..a8adddde 100644
--- a/src/mobilerun_sdk/_client.py
+++ b/src/mobilerun_sdk/_client.py
@@ -39,9 +39,9 @@
from .resources import (
apps,
esims,
+ files,
store,
tasks,
- agents,
models,
connect,
devices,
@@ -51,13 +51,14 @@
messages,
profiles,
webhooks,
+ assistant,
workflows,
app_events,
credentials,
notifications,
)
from .resources.apps import AppsResource, AsyncAppsResource
- from .resources.agents import AgentsResource, AsyncAgentsResource
+ from .resources.files import FilesResource, AsyncFilesResource
from .resources.models import ModelsResource, AsyncModelsResource
from .resources.proxies import ProxiesResource, AsyncProxiesResource
from .resources.carriers import CarriersResource, AsyncCarriersResource
@@ -71,6 +72,7 @@
from .resources.numbers.numbers import NumbersResource, AsyncNumbersResource
from .resources.messages.messages import MessagesResource, AsyncMessagesResource
from .resources.webhooks.webhooks import WebhooksResource, AsyncWebhooksResource
+ from .resources.assistant.assistant import AssistantResource, AsyncAssistantResource
from .resources.workflows.workflows import WorkflowsResource, AsyncWorkflowsResource
from .resources.app_events.app_events import AppEventsResource, AsyncAppEventsResource
from .resources.credentials.credentials import CredentialsResource, AsyncCredentialsResource
@@ -216,10 +218,16 @@ def webhooks(self) -> WebhooksResource:
return WebhooksResource(self)
@cached_property
- def agents(self) -> AgentsResource:
- from .resources.agents import AgentsResource
+ def files(self) -> FilesResource:
+ from .resources.files import FilesResource
- return AgentsResource(self)
+ return FilesResource(self)
+
+ @cached_property
+ def assistant(self) -> AssistantResource:
+ from .resources.assistant import AssistantResource
+
+ return AssistantResource(self)
@cached_property
def app_events(self) -> AppEventsResource:
@@ -510,10 +518,16 @@ def webhooks(self) -> AsyncWebhooksResource:
return AsyncWebhooksResource(self)
@cached_property
- def agents(self) -> AsyncAgentsResource:
- from .resources.agents import AsyncAgentsResource
+ def files(self) -> AsyncFilesResource:
+ from .resources.files import AsyncFilesResource
- return AsyncAgentsResource(self)
+ return AsyncFilesResource(self)
+
+ @cached_property
+ def assistant(self) -> AsyncAssistantResource:
+ from .resources.assistant import AsyncAssistantResource
+
+ return AsyncAssistantResource(self)
@cached_property
def app_events(self) -> AsyncAppEventsResource:
@@ -750,10 +764,16 @@ def webhooks(self) -> webhooks.WebhooksResourceWithRawResponse:
return WebhooksResourceWithRawResponse(self._client.webhooks)
@cached_property
- def agents(self) -> agents.AgentsResourceWithRawResponse:
- from .resources.agents import AgentsResourceWithRawResponse
+ def files(self) -> files.FilesResourceWithRawResponse:
+ from .resources.files import FilesResourceWithRawResponse
+
+ return FilesResourceWithRawResponse(self._client.files)
+
+ @cached_property
+ def assistant(self) -> assistant.AssistantResourceWithRawResponse:
+ from .resources.assistant import AssistantResourceWithRawResponse
- return AgentsResourceWithRawResponse(self._client.agents)
+ return AssistantResourceWithRawResponse(self._client.assistant)
@cached_property
def app_events(self) -> app_events.AppEventsResourceWithRawResponse:
@@ -867,10 +887,16 @@ def webhooks(self) -> webhooks.AsyncWebhooksResourceWithRawResponse:
return AsyncWebhooksResourceWithRawResponse(self._client.webhooks)
@cached_property
- def agents(self) -> agents.AsyncAgentsResourceWithRawResponse:
- from .resources.agents import AsyncAgentsResourceWithRawResponse
+ def files(self) -> files.AsyncFilesResourceWithRawResponse:
+ from .resources.files import AsyncFilesResourceWithRawResponse
- return AsyncAgentsResourceWithRawResponse(self._client.agents)
+ return AsyncFilesResourceWithRawResponse(self._client.files)
+
+ @cached_property
+ def assistant(self) -> assistant.AsyncAssistantResourceWithRawResponse:
+ from .resources.assistant import AsyncAssistantResourceWithRawResponse
+
+ return AsyncAssistantResourceWithRawResponse(self._client.assistant)
@cached_property
def app_events(self) -> app_events.AsyncAppEventsResourceWithRawResponse:
@@ -984,10 +1010,16 @@ def webhooks(self) -> webhooks.WebhooksResourceWithStreamingResponse:
return WebhooksResourceWithStreamingResponse(self._client.webhooks)
@cached_property
- def agents(self) -> agents.AgentsResourceWithStreamingResponse:
- from .resources.agents import AgentsResourceWithStreamingResponse
+ def files(self) -> files.FilesResourceWithStreamingResponse:
+ from .resources.files import FilesResourceWithStreamingResponse
- return AgentsResourceWithStreamingResponse(self._client.agents)
+ return FilesResourceWithStreamingResponse(self._client.files)
+
+ @cached_property
+ def assistant(self) -> assistant.AssistantResourceWithStreamingResponse:
+ from .resources.assistant import AssistantResourceWithStreamingResponse
+
+ return AssistantResourceWithStreamingResponse(self._client.assistant)
@cached_property
def app_events(self) -> app_events.AppEventsResourceWithStreamingResponse:
@@ -1101,10 +1133,16 @@ def webhooks(self) -> webhooks.AsyncWebhooksResourceWithStreamingResponse:
return AsyncWebhooksResourceWithStreamingResponse(self._client.webhooks)
@cached_property
- def agents(self) -> agents.AsyncAgentsResourceWithStreamingResponse:
- from .resources.agents import AsyncAgentsResourceWithStreamingResponse
+ def files(self) -> files.AsyncFilesResourceWithStreamingResponse:
+ from .resources.files import AsyncFilesResourceWithStreamingResponse
+
+ return AsyncFilesResourceWithStreamingResponse(self._client.files)
+
+ @cached_property
+ def assistant(self) -> assistant.AsyncAssistantResourceWithStreamingResponse:
+ from .resources.assistant import AsyncAssistantResourceWithStreamingResponse
- return AsyncAgentsResourceWithStreamingResponse(self._client.agents)
+ return AsyncAssistantResourceWithStreamingResponse(self._client.assistant)
@cached_property
def app_events(self) -> app_events.AsyncAppEventsResourceWithStreamingResponse:
diff --git a/src/mobilerun_sdk/resources/__init__.py b/src/mobilerun_sdk/resources/__init__.py
index afef0f85..1181afd4 100644
--- a/src/mobilerun_sdk/resources/__init__.py
+++ b/src/mobilerun_sdk/resources/__init__.py
@@ -16,6 +16,14 @@
EsimsResourceWithStreamingResponse,
AsyncEsimsResourceWithStreamingResponse,
)
+from .files import (
+ FilesResource,
+ AsyncFilesResource,
+ FilesResourceWithRawResponse,
+ AsyncFilesResourceWithRawResponse,
+ FilesResourceWithStreamingResponse,
+ AsyncFilesResourceWithStreamingResponse,
+)
from .store import (
StoreResource,
AsyncStoreResource,
@@ -32,14 +40,6 @@
TasksResourceWithStreamingResponse,
AsyncTasksResourceWithStreamingResponse,
)
-from .agents import (
- AgentsResource,
- AsyncAgentsResource,
- AgentsResourceWithRawResponse,
- AsyncAgentsResourceWithRawResponse,
- AgentsResourceWithStreamingResponse,
- AsyncAgentsResourceWithStreamingResponse,
-)
from .models import (
ModelsResource,
AsyncModelsResource,
@@ -112,6 +112,14 @@
WebhooksResourceWithStreamingResponse,
AsyncWebhooksResourceWithStreamingResponse,
)
+from .assistant import (
+ AssistantResource,
+ AsyncAssistantResource,
+ AssistantResourceWithRawResponse,
+ AsyncAssistantResourceWithRawResponse,
+ AssistantResourceWithStreamingResponse,
+ AsyncAssistantResourceWithStreamingResponse,
+)
from .workflows import (
WorkflowsResource,
AsyncWorkflowsResource,
@@ -212,12 +220,18 @@
"AsyncWebhooksResourceWithRawResponse",
"WebhooksResourceWithStreamingResponse",
"AsyncWebhooksResourceWithStreamingResponse",
- "AgentsResource",
- "AsyncAgentsResource",
- "AgentsResourceWithRawResponse",
- "AsyncAgentsResourceWithRawResponse",
- "AgentsResourceWithStreamingResponse",
- "AsyncAgentsResourceWithStreamingResponse",
+ "FilesResource",
+ "AsyncFilesResource",
+ "FilesResourceWithRawResponse",
+ "AsyncFilesResourceWithRawResponse",
+ "FilesResourceWithStreamingResponse",
+ "AsyncFilesResourceWithStreamingResponse",
+ "AssistantResource",
+ "AsyncAssistantResource",
+ "AssistantResourceWithRawResponse",
+ "AsyncAssistantResourceWithRawResponse",
+ "AssistantResourceWithStreamingResponse",
+ "AsyncAssistantResourceWithStreamingResponse",
"AppEventsResource",
"AsyncAppEventsResource",
"AppEventsResourceWithRawResponse",
diff --git a/src/mobilerun_sdk/resources/agents.py b/src/mobilerun_sdk/resources/agents.py
deleted file mode 100644
index 7d7bb86f..00000000
--- a/src/mobilerun_sdk/resources/agents.py
+++ /dev/null
@@ -1,135 +0,0 @@
-# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-
-from __future__ import annotations
-
-import httpx
-
-from .._types import Body, Query, Headers, NotGiven, not_given
-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.agent_list_response import AgentListResponse
-
-__all__ = ["AgentsResource", "AsyncAgentsResource"]
-
-
-class AgentsResource(SyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AgentsResourceWithRawResponse:
- """
- 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 AgentsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AgentsResourceWithStreamingResponse:
- """
- 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 AgentsResourceWithStreamingResponse(self)
-
- def list(
- 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,
- ) -> AgentListResponse:
- """List all available agents with their default configurations."""
- return self._get(
- "/agents",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=AgentListResponse,
- )
-
-
-class AsyncAgentsResource(AsyncAPIResource):
- @cached_property
- def with_raw_response(self) -> AsyncAgentsResourceWithRawResponse:
- """
- 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 AsyncAgentsResourceWithRawResponse(self)
-
- @cached_property
- def with_streaming_response(self) -> AsyncAgentsResourceWithStreamingResponse:
- """
- 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 AsyncAgentsResourceWithStreamingResponse(self)
-
- async def list(
- 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,
- ) -> AgentListResponse:
- """List all available agents with their default configurations."""
- return await self._get(
- "/agents",
- options=make_request_options(
- extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
- ),
- cast_to=AgentListResponse,
- )
-
-
-class AgentsResourceWithRawResponse:
- def __init__(self, agents: AgentsResource) -> None:
- self._agents = agents
-
- self.list = to_raw_response_wrapper(
- agents.list,
- )
-
-
-class AsyncAgentsResourceWithRawResponse:
- def __init__(self, agents: AsyncAgentsResource) -> None:
- self._agents = agents
-
- self.list = async_to_raw_response_wrapper(
- agents.list,
- )
-
-
-class AgentsResourceWithStreamingResponse:
- def __init__(self, agents: AgentsResource) -> None:
- self._agents = agents
-
- self.list = to_streamed_response_wrapper(
- agents.list,
- )
-
-
-class AsyncAgentsResourceWithStreamingResponse:
- def __init__(self, agents: AsyncAgentsResource) -> None:
- self._agents = agents
-
- self.list = async_to_streamed_response_wrapper(
- agents.list,
- )
diff --git a/src/mobilerun_sdk/resources/assistant/__init__.py b/src/mobilerun_sdk/resources/assistant/__init__.py
new file mode 100644
index 00000000..86480a80
--- /dev/null
+++ b/src/mobilerun_sdk/resources/assistant/__init__.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .assistant import (
+ AssistantResource,
+ AsyncAssistantResource,
+ AssistantResourceWithRawResponse,
+ AsyncAssistantResourceWithRawResponse,
+ AssistantResourceWithStreamingResponse,
+ AsyncAssistantResourceWithStreamingResponse,
+)
+from .conversations import (
+ ConversationsResource,
+ AsyncConversationsResource,
+ ConversationsResourceWithRawResponse,
+ AsyncConversationsResourceWithRawResponse,
+ ConversationsResourceWithStreamingResponse,
+ AsyncConversationsResourceWithStreamingResponse,
+)
+
+__all__ = [
+ "ConversationsResource",
+ "AsyncConversationsResource",
+ "ConversationsResourceWithRawResponse",
+ "AsyncConversationsResourceWithRawResponse",
+ "ConversationsResourceWithStreamingResponse",
+ "AsyncConversationsResourceWithStreamingResponse",
+ "AssistantResource",
+ "AsyncAssistantResource",
+ "AssistantResourceWithRawResponse",
+ "AsyncAssistantResourceWithRawResponse",
+ "AssistantResourceWithStreamingResponse",
+ "AsyncAssistantResourceWithStreamingResponse",
+]
diff --git a/src/mobilerun_sdk/resources/assistant/assistant.py b/src/mobilerun_sdk/resources/assistant/assistant.py
new file mode 100644
index 00000000..b97d67bd
--- /dev/null
+++ b/src/mobilerun_sdk/resources/assistant/assistant.py
@@ -0,0 +1,102 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from .conversations import (
+ ConversationsResource,
+ AsyncConversationsResource,
+ ConversationsResourceWithRawResponse,
+ AsyncConversationsResourceWithRawResponse,
+ ConversationsResourceWithStreamingResponse,
+ AsyncConversationsResourceWithStreamingResponse,
+)
+
+__all__ = ["AssistantResource", "AsyncAssistantResource"]
+
+
+class AssistantResource(SyncAPIResource):
+ @cached_property
+ def conversations(self) -> ConversationsResource:
+ return ConversationsResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AssistantResourceWithRawResponse:
+ """
+ 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 AssistantResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AssistantResourceWithStreamingResponse:
+ """
+ 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 AssistantResourceWithStreamingResponse(self)
+
+
+class AsyncAssistantResource(AsyncAPIResource):
+ @cached_property
+ def conversations(self) -> AsyncConversationsResource:
+ return AsyncConversationsResource(self._client)
+
+ @cached_property
+ def with_raw_response(self) -> AsyncAssistantResourceWithRawResponse:
+ """
+ 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 AsyncAssistantResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncAssistantResourceWithStreamingResponse:
+ """
+ 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 AsyncAssistantResourceWithStreamingResponse(self)
+
+
+class AssistantResourceWithRawResponse:
+ def __init__(self, assistant: AssistantResource) -> None:
+ self._assistant = assistant
+
+ @cached_property
+ def conversations(self) -> ConversationsResourceWithRawResponse:
+ return ConversationsResourceWithRawResponse(self._assistant.conversations)
+
+
+class AsyncAssistantResourceWithRawResponse:
+ def __init__(self, assistant: AsyncAssistantResource) -> None:
+ self._assistant = assistant
+
+ @cached_property
+ def conversations(self) -> AsyncConversationsResourceWithRawResponse:
+ return AsyncConversationsResourceWithRawResponse(self._assistant.conversations)
+
+
+class AssistantResourceWithStreamingResponse:
+ def __init__(self, assistant: AssistantResource) -> None:
+ self._assistant = assistant
+
+ @cached_property
+ def conversations(self) -> ConversationsResourceWithStreamingResponse:
+ return ConversationsResourceWithStreamingResponse(self._assistant.conversations)
+
+
+class AsyncAssistantResourceWithStreamingResponse:
+ def __init__(self, assistant: AsyncAssistantResource) -> None:
+ self._assistant = assistant
+
+ @cached_property
+ def conversations(self) -> AsyncConversationsResourceWithStreamingResponse:
+ return AsyncConversationsResourceWithStreamingResponse(self._assistant.conversations)
diff --git a/src/mobilerun_sdk/resources/assistant/conversations.py b/src/mobilerun_sdk/resources/assistant/conversations.py
new file mode 100644
index 00000000..04b2a56c
--- /dev/null
+++ b/src/mobilerun_sdk/resources/assistant/conversations.py
@@ -0,0 +1,1105 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Iterable, Optional
+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, strip_not_given, 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 ..._streaming import Stream, AsyncStream
+from ..._base_client import make_request_options
+from ...types.assistant import (
+ conversation_list_params,
+ conversation_send_params,
+ conversation_abort_params,
+ conversation_create_params,
+ conversation_stream_params,
+ conversation_update_params,
+ conversation_history_params,
+ conversation_answer_question_params,
+ conversation_reject_question_params,
+ conversation_answer_permission_params,
+)
+from ...types.assistant.conversation_list_response import ConversationListResponse
+from ...types.assistant.conversation_send_response import ConversationSendResponse
+from ...types.assistant.conversation_abort_response import ConversationAbortResponse
+from ...types.assistant.conversation_create_response import ConversationCreateResponse
+from ...types.assistant.conversation_stream_response import ConversationStreamResponse
+from ...types.assistant.conversation_update_response import ConversationUpdateResponse
+from ...types.assistant.conversation_history_response import ConversationHistoryResponse
+from ...types.assistant.conversation_answer_question_response import ConversationAnswerQuestionResponse
+from ...types.assistant.conversation_reject_question_response import ConversationRejectQuestionResponse
+from ...types.assistant.conversation_answer_permission_response import ConversationAnswerPermissionResponse
+
+__all__ = ["ConversationsResource", "AsyncConversationsResource"]
+
+
+class ConversationsResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> ConversationsResourceWithRawResponse:
+ """
+ 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 ConversationsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> ConversationsResourceWithStreamingResponse:
+ """
+ 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 ConversationsResourceWithStreamingResponse(self)
+
+ def create(
+ self,
+ *,
+ title: str,
+ agent: str | Omit = omit,
+ description: str | Omit = omit,
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ConversationCreateResponse:
+ """Creates a titled agent session.
+
+ Setup may occur on the first prompt. Idempotent
+ via the `Idempotency-Key` header — a duplicate submit by the same authenticated
+ caller within the 24-hour idempotency window returns the already-created session
+ instead of a second one.
+
+ Args:
+ idempotency_key: Optional client key. Reusing the same key with the same request body by the same
+ authenticated caller within 24 hours returns the already-created session instead
+ of a second one.
+
+ 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
+ """
+ extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})}
+ return self._post(
+ "/assistant/chat/sessions",
+ body=maybe_transform(
+ {
+ "title": title,
+ "agent": agent,
+ "description": description,
+ },
+ conversation_create_params.ConversationCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationCreateResponse,
+ )
+
+ def update(
+ self,
+ id: str,
+ *,
+ description: Optional[str] | Omit = omit,
+ pinned: bool | Omit = omit,
+ status: Literal["active", "archived"] | Omit = omit,
+ title: 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,
+ ) -> ConversationUpdateResponse:
+ """Rename, change status, and/or pin.
+
+ Title updates apply best-effort. Archiving
+ always clears the pinned flag. `title` is rejected with 409
+ `code: "session_title_managed_by_workflow"` when this chat is bound to a
+ workflow — a bound chat's title is managed by the workflow. Other fields
+ (description, status, pinned) remain updateable; archiving a bound chat stays
+ allowed.
+
+ 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._patch(
+ path_template("/assistant/chat/sessions/{id}", id=id),
+ body=maybe_transform(
+ {
+ "description": description,
+ "pinned": pinned,
+ "status": status,
+ "title": title,
+ },
+ conversation_update_params.ConversationUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationUpdateResponse,
+ )
+
+ def list(
+ self,
+ *,
+ kind: Literal["chat", "agent_workflow"] | Omit = omit,
+ mine: Literal["true", "false"] | Omit = omit,
+ workflow_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,
+ ) -> ConversationListResponse:
+ """
+ Default (`kind` absent or `chat`): active named chat sessions, pinned first then
+ most recent activity — `workflowId` must be absent, or the request 400s.
+ `mine=true` (only valid with `kind=chat`) narrows to sessions the caller
+ created. `kind=agent_workflow`: workflow-linked sessions for one workflow
+ (`workflowId` required, or the request 400s), no status filter, newest episode
+ first.
+
+ 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(
+ "/assistant/chat/sessions",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "kind": kind,
+ "mine": mine,
+ "workflow_id": workflow_id,
+ },
+ conversation_list_params.ConversationListParams,
+ ),
+ ),
+ cast_to=ConversationListResponse,
+ )
+
+ def abort(
+ self,
+ *,
+ session_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,
+ ) -> ConversationAbortResponse:
+ """Abort the in-flight chat turn owned by `sessionId`.
+
+ Idempotent. A turn owned by
+ a different session is left untouched (204).
+
+ 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._post(
+ "/assistant/chat/abort",
+ body=maybe_transform({"session_id": session_id}, conversation_abort_params.ConversationAbortParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationAbortResponse,
+ )
+
+ def answer_permission(
+ self,
+ *,
+ permission_id: str,
+ response: Literal["once", "always", "reject"],
+ # 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,
+ ) -> ConversationAnswerPermissionResponse:
+ """
+ Deliver a HITL approval/rejection for an in-flight turn.
+
+ 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._post(
+ "/assistant/chat/permission",
+ body=maybe_transform(
+ {
+ "permission_id": permission_id,
+ "response": response,
+ },
+ conversation_answer_permission_params.ConversationAnswerPermissionParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationAnswerPermissionResponse,
+ )
+
+ def answer_question(
+ self,
+ *,
+ answers: Iterable[Iterable[conversation_answer_question_params.Answer]],
+ question_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,
+ ) -> ConversationAnswerQuestionResponse:
+ """Deliver the user's answers to the agent's pending question for an in-flight
+ turn.
+
+ Idempotent via the `idempotency-key` header.
+
+ 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._post(
+ "/assistant/chat/question",
+ body=maybe_transform(
+ {
+ "answers": answers,
+ "question_id": question_id,
+ },
+ conversation_answer_question_params.ConversationAnswerQuestionParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationAnswerQuestionResponse,
+ )
+
+ def history(
+ self,
+ *,
+ session_id: str,
+ limit: int | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ConversationHistoryResponse:
+ """Return the user's chat history for the given session.
+
+ History remains readable
+ after the session is no longer active.
+
+ 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(
+ "/assistant/chat/messages",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform(
+ {
+ "session_id": session_id,
+ "limit": limit,
+ },
+ conversation_history_params.ConversationHistoryParams,
+ ),
+ ),
+ cast_to=ConversationHistoryResponse,
+ )
+
+ def reject_question(
+ self,
+ *,
+ question_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,
+ ) -> ConversationRejectQuestionResponse:
+ """Dismiss the agent's pending question.
+
+ Already-resolved questions return 200
+ (no-op) so multi-tab dismiss stays idempotent.
+
+ 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._post(
+ "/assistant/chat/question/reject",
+ body=maybe_transform(
+ {"question_id": question_id}, conversation_reject_question_params.ConversationRejectQuestionParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationRejectQuestionResponse,
+ )
+
+ def send(
+ self,
+ *,
+ message: str,
+ session_id: str,
+ agent: 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,
+ ) -> ConversationSendResponse:
+ """Send a single user message.
+
+ 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.
+
+ 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._post(
+ "/assistant/chat/message",
+ body=maybe_transform(
+ {
+ "message": message,
+ "session_id": session_id,
+ "agent": agent,
+ },
+ conversation_send_params.ConversationSendParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationSendResponse,
+ )
+
+ def stream(
+ self,
+ *,
+ session_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,
+ ) -> Stream[ConversationStreamResponse]:
+ """Reconnect to the in-flight turn stream.
+
+ Replays buffered events from the start
+ of the active turn, then continues live until the turn finishes. Responds 204
+ when no active turn exists for the requested session. Upstream streaming
+ failures return a retryable 503 with `Retry-After`. Resume is best-effort. Does
+ not start an inactive session.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ extra_headers = {"Accept": "text/event-stream", **(extra_headers or {})}
+ return self._get(
+ "/assistant/chat/stream",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"session_id": session_id}, conversation_stream_params.ConversationStreamParams),
+ ),
+ cast_to=str,
+ stream=True,
+ stream_cls=Stream[ConversationStreamResponse],
+ )
+
+
+class AsyncConversationsResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncConversationsResourceWithRawResponse:
+ """
+ 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 AsyncConversationsResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncConversationsResourceWithStreamingResponse:
+ """
+ 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 AsyncConversationsResourceWithStreamingResponse(self)
+
+ async def create(
+ self,
+ *,
+ title: str,
+ agent: str | Omit = omit,
+ description: str | Omit = omit,
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ConversationCreateResponse:
+ """Creates a titled agent session.
+
+ Setup may occur on the first prompt. Idempotent
+ via the `Idempotency-Key` header — a duplicate submit by the same authenticated
+ caller within the 24-hour idempotency window returns the already-created session
+ instead of a second one.
+
+ Args:
+ idempotency_key: Optional client key. Reusing the same key with the same request body by the same
+ authenticated caller within 24 hours returns the already-created session instead
+ of a second one.
+
+ 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
+ """
+ extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})}
+ return await self._post(
+ "/assistant/chat/sessions",
+ body=await async_maybe_transform(
+ {
+ "title": title,
+ "agent": agent,
+ "description": description,
+ },
+ conversation_create_params.ConversationCreateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationCreateResponse,
+ )
+
+ async def update(
+ self,
+ id: str,
+ *,
+ description: Optional[str] | Omit = omit,
+ pinned: bool | Omit = omit,
+ status: Literal["active", "archived"] | Omit = omit,
+ title: 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,
+ ) -> ConversationUpdateResponse:
+ """Rename, change status, and/or pin.
+
+ Title updates apply best-effort. Archiving
+ always clears the pinned flag. `title` is rejected with 409
+ `code: "session_title_managed_by_workflow"` when this chat is bound to a
+ workflow — a bound chat's title is managed by the workflow. Other fields
+ (description, status, pinned) remain updateable; archiving a bound chat stays
+ allowed.
+
+ 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._patch(
+ path_template("/assistant/chat/sessions/{id}", id=id),
+ body=await async_maybe_transform(
+ {
+ "description": description,
+ "pinned": pinned,
+ "status": status,
+ "title": title,
+ },
+ conversation_update_params.ConversationUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationUpdateResponse,
+ )
+
+ async def list(
+ self,
+ *,
+ kind: Literal["chat", "agent_workflow"] | Omit = omit,
+ mine: Literal["true", "false"] | Omit = omit,
+ workflow_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,
+ ) -> ConversationListResponse:
+ """
+ Default (`kind` absent or `chat`): active named chat sessions, pinned first then
+ most recent activity — `workflowId` must be absent, or the request 400s.
+ `mine=true` (only valid with `kind=chat`) narrows to sessions the caller
+ created. `kind=agent_workflow`: workflow-linked sessions for one workflow
+ (`workflowId` required, or the request 400s), no status filter, newest episode
+ first.
+
+ 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(
+ "/assistant/chat/sessions",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "kind": kind,
+ "mine": mine,
+ "workflow_id": workflow_id,
+ },
+ conversation_list_params.ConversationListParams,
+ ),
+ ),
+ cast_to=ConversationListResponse,
+ )
+
+ async def abort(
+ self,
+ *,
+ session_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,
+ ) -> ConversationAbortResponse:
+ """Abort the in-flight chat turn owned by `sessionId`.
+
+ Idempotent. A turn owned by
+ a different session is left untouched (204).
+
+ 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._post(
+ "/assistant/chat/abort",
+ body=await async_maybe_transform(
+ {"session_id": session_id}, conversation_abort_params.ConversationAbortParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationAbortResponse,
+ )
+
+ async def answer_permission(
+ self,
+ *,
+ permission_id: str,
+ response: Literal["once", "always", "reject"],
+ # 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,
+ ) -> ConversationAnswerPermissionResponse:
+ """
+ Deliver a HITL approval/rejection for an in-flight turn.
+
+ 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._post(
+ "/assistant/chat/permission",
+ body=await async_maybe_transform(
+ {
+ "permission_id": permission_id,
+ "response": response,
+ },
+ conversation_answer_permission_params.ConversationAnswerPermissionParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationAnswerPermissionResponse,
+ )
+
+ async def answer_question(
+ self,
+ *,
+ answers: Iterable[Iterable[conversation_answer_question_params.Answer]],
+ question_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,
+ ) -> ConversationAnswerQuestionResponse:
+ """Deliver the user's answers to the agent's pending question for an in-flight
+ turn.
+
+ Idempotent via the `idempotency-key` header.
+
+ 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._post(
+ "/assistant/chat/question",
+ body=await async_maybe_transform(
+ {
+ "answers": answers,
+ "question_id": question_id,
+ },
+ conversation_answer_question_params.ConversationAnswerQuestionParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationAnswerQuestionResponse,
+ )
+
+ async def history(
+ self,
+ *,
+ session_id: str,
+ limit: int | Omit = omit,
+ # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
+ # The extra values given here take precedence over values defined on the client or passed to this method.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ConversationHistoryResponse:
+ """Return the user's chat history for the given session.
+
+ History remains readable
+ after the session is no longer active.
+
+ 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(
+ "/assistant/chat/messages",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {
+ "session_id": session_id,
+ "limit": limit,
+ },
+ conversation_history_params.ConversationHistoryParams,
+ ),
+ ),
+ cast_to=ConversationHistoryResponse,
+ )
+
+ async def reject_question(
+ self,
+ *,
+ question_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,
+ ) -> ConversationRejectQuestionResponse:
+ """Dismiss the agent's pending question.
+
+ Already-resolved questions return 200
+ (no-op) so multi-tab dismiss stays idempotent.
+
+ 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._post(
+ "/assistant/chat/question/reject",
+ body=await async_maybe_transform(
+ {"question_id": question_id}, conversation_reject_question_params.ConversationRejectQuestionParams
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationRejectQuestionResponse,
+ )
+
+ async def send(
+ self,
+ *,
+ message: str,
+ session_id: str,
+ agent: 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,
+ ) -> ConversationSendResponse:
+ """Send a single user message.
+
+ 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.
+
+ 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._post(
+ "/assistant/chat/message",
+ body=await async_maybe_transform(
+ {
+ "message": message,
+ "session_id": session_id,
+ "agent": agent,
+ },
+ conversation_send_params.ConversationSendParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ConversationSendResponse,
+ )
+
+ async def stream(
+ self,
+ *,
+ session_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,
+ ) -> AsyncStream[ConversationStreamResponse]:
+ """Reconnect to the in-flight turn stream.
+
+ Replays buffered events from the start
+ of the active turn, then continues live until the turn finishes. Responds 204
+ when no active turn exists for the requested session. Upstream streaming
+ failures return a retryable 503 with `Retry-After`. Resume is best-effort. Does
+ not start an inactive session.
+
+ Args:
+ extra_headers: Send extra headers
+
+ extra_query: Add additional query parameters to the request
+
+ extra_body: Add additional JSON properties to the request
+
+ timeout: Override the client-level default timeout for this request, in seconds
+ """
+ extra_headers = {"Accept": "text/event-stream", **(extra_headers or {})}
+ return await self._get(
+ "/assistant/chat/stream",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform(
+ {"session_id": session_id}, conversation_stream_params.ConversationStreamParams
+ ),
+ ),
+ cast_to=str,
+ stream=True,
+ stream_cls=AsyncStream[ConversationStreamResponse],
+ )
+
+
+class ConversationsResourceWithRawResponse:
+ def __init__(self, conversations: ConversationsResource) -> None:
+ self._conversations = conversations
+
+ self.create = to_raw_response_wrapper(
+ conversations.create,
+ )
+ self.update = to_raw_response_wrapper(
+ conversations.update,
+ )
+ self.list = to_raw_response_wrapper(
+ conversations.list,
+ )
+ self.abort = to_raw_response_wrapper(
+ conversations.abort,
+ )
+ self.answer_permission = to_raw_response_wrapper(
+ conversations.answer_permission,
+ )
+ self.answer_question = to_raw_response_wrapper(
+ conversations.answer_question,
+ )
+ self.history = to_raw_response_wrapper(
+ conversations.history,
+ )
+ self.reject_question = to_raw_response_wrapper(
+ conversations.reject_question,
+ )
+ self.send = to_raw_response_wrapper(
+ conversations.send,
+ )
+ self.stream = to_raw_response_wrapper(
+ conversations.stream,
+ )
+
+
+class AsyncConversationsResourceWithRawResponse:
+ def __init__(self, conversations: AsyncConversationsResource) -> None:
+ self._conversations = conversations
+
+ self.create = async_to_raw_response_wrapper(
+ conversations.create,
+ )
+ self.update = async_to_raw_response_wrapper(
+ conversations.update,
+ )
+ self.list = async_to_raw_response_wrapper(
+ conversations.list,
+ )
+ self.abort = async_to_raw_response_wrapper(
+ conversations.abort,
+ )
+ self.answer_permission = async_to_raw_response_wrapper(
+ conversations.answer_permission,
+ )
+ self.answer_question = async_to_raw_response_wrapper(
+ conversations.answer_question,
+ )
+ self.history = async_to_raw_response_wrapper(
+ conversations.history,
+ )
+ self.reject_question = async_to_raw_response_wrapper(
+ conversations.reject_question,
+ )
+ self.send = async_to_raw_response_wrapper(
+ conversations.send,
+ )
+ self.stream = async_to_raw_response_wrapper(
+ conversations.stream,
+ )
+
+
+class ConversationsResourceWithStreamingResponse:
+ def __init__(self, conversations: ConversationsResource) -> None:
+ self._conversations = conversations
+
+ self.create = to_streamed_response_wrapper(
+ conversations.create,
+ )
+ self.update = to_streamed_response_wrapper(
+ conversations.update,
+ )
+ self.list = to_streamed_response_wrapper(
+ conversations.list,
+ )
+ self.abort = to_streamed_response_wrapper(
+ conversations.abort,
+ )
+ self.answer_permission = to_streamed_response_wrapper(
+ conversations.answer_permission,
+ )
+ self.answer_question = to_streamed_response_wrapper(
+ conversations.answer_question,
+ )
+ self.history = to_streamed_response_wrapper(
+ conversations.history,
+ )
+ self.reject_question = to_streamed_response_wrapper(
+ conversations.reject_question,
+ )
+ self.send = to_streamed_response_wrapper(
+ conversations.send,
+ )
+ self.stream = to_streamed_response_wrapper(
+ conversations.stream,
+ )
+
+
+class AsyncConversationsResourceWithStreamingResponse:
+ def __init__(self, conversations: AsyncConversationsResource) -> None:
+ self._conversations = conversations
+
+ self.create = async_to_streamed_response_wrapper(
+ conversations.create,
+ )
+ self.update = async_to_streamed_response_wrapper(
+ conversations.update,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ conversations.list,
+ )
+ self.abort = async_to_streamed_response_wrapper(
+ conversations.abort,
+ )
+ self.answer_permission = async_to_streamed_response_wrapper(
+ conversations.answer_permission,
+ )
+ self.answer_question = async_to_streamed_response_wrapper(
+ conversations.answer_question,
+ )
+ self.history = async_to_streamed_response_wrapper(
+ conversations.history,
+ )
+ self.reject_question = async_to_streamed_response_wrapper(
+ conversations.reject_question,
+ )
+ self.send = async_to_streamed_response_wrapper(
+ conversations.send,
+ )
+ self.stream = async_to_streamed_response_wrapper(
+ conversations.stream,
+ )
diff --git a/src/mobilerun_sdk/resources/devices/__init__.py b/src/mobilerun_sdk/resources/devices/__init__.py
index 4f1a6d2b..7a429240 100644
--- a/src/mobilerun_sdk/resources/devices/__init__.py
+++ b/src/mobilerun_sdk/resources/devices/__init__.py
@@ -128,6 +128,14 @@
TimezoneResourceWithStreamingResponse,
AsyncTimezoneResourceWithStreamingResponse,
)
+from .clipboard import (
+ ClipboardResource,
+ AsyncClipboardResource,
+ ClipboardResourceWithRawResponse,
+ AsyncClipboardResourceWithRawResponse,
+ ClipboardResourceWithStreamingResponse,
+ AsyncClipboardResourceWithStreamingResponse,
+)
from .deep_link import (
DeepLinkResource,
AsyncDeepLinkResource,
@@ -220,6 +228,12 @@
"AsyncTasksResourceWithRawResponse",
"TasksResourceWithStreamingResponse",
"AsyncTasksResourceWithStreamingResponse",
+ "ClipboardResource",
+ "AsyncClipboardResource",
+ "ClipboardResourceWithRawResponse",
+ "AsyncClipboardResourceWithRawResponse",
+ "ClipboardResourceWithStreamingResponse",
+ "AsyncClipboardResourceWithStreamingResponse",
"TimezoneResource",
"AsyncTimezoneResource",
"TimezoneResourceWithRawResponse",
diff --git a/src/mobilerun_sdk/resources/devices/clipboard.py b/src/mobilerun_sdk/resources/devices/clipboard.py
new file mode 100644
index 00000000..7c641500
--- /dev/null
+++ b/src/mobilerun_sdk/resources/devices/clipboard.py
@@ -0,0 +1,285 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+import httpx
+
+from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+from ..._utils import is_given, path_template, maybe_transform, strip_not_given, async_maybe_transform
+from ..._compat import cached_property
+from ..._resource import SyncAPIResource, AsyncAPIResource
+from ..._response import (
+ to_raw_response_wrapper,
+ to_streamed_response_wrapper,
+ async_to_raw_response_wrapper,
+ async_to_streamed_response_wrapper,
+)
+from ..._base_client import make_request_options
+from ...types.devices import clipboard_set_params
+from ...types.devices.clipboard_get_response import ClipboardGetResponse
+
+__all__ = ["ClipboardResource", "AsyncClipboardResource"]
+
+
+class ClipboardResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> ClipboardResourceWithRawResponse:
+ """
+ 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 ClipboardResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> ClipboardResourceWithStreamingResponse:
+ """
+ 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 ClipboardResourceWithStreamingResponse(self)
+
+ def get(
+ self,
+ device_id: str,
+ *,
+ 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ClipboardGetResponse:
+ """Returns the current text content of the device's clipboard.
+
+ Devices without
+ clipboard support return an unsupported-feature error.
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._get(
+ path_template("/devices/{device_id}/clipboard", device_id=device_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ClipboardGetResponse,
+ )
+
+ def set(
+ self,
+ device_id: str,
+ *,
+ text: str,
+ 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> None:
+ """
+ Replaces the device's clipboard content with the text in the request body; an
+ empty text clears the clipboard. Devices without clipboard support return an
+ unsupported-feature error.
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return self._post(
+ path_template("/devices/{device_id}/clipboard", device_id=device_id),
+ body=maybe_transform({"text": text}, clipboard_set_params.ClipboardSetParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class AsyncClipboardResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncClipboardResourceWithRawResponse:
+ """
+ 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 AsyncClipboardResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncClipboardResourceWithStreamingResponse:
+ """
+ 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 AsyncClipboardResourceWithStreamingResponse(self)
+
+ async def get(
+ self,
+ device_id: str,
+ *,
+ 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> ClipboardGetResponse:
+ """Returns the current text content of the device's clipboard.
+
+ Devices without
+ clipboard support return an unsupported-feature error.
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._get(
+ path_template("/devices/{device_id}/clipboard", device_id=device_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=ClipboardGetResponse,
+ )
+
+ async def set(
+ self,
+ device_id: str,
+ *,
+ text: str,
+ 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.
+ extra_headers: Headers | None = None,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> None:
+ """
+ Replaces the device's clipboard content with the text in the request body; an
+ empty text clears the clipboard. Devices without clipboard support return an
+ unsupported-feature error.
+
+ 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 device_id:
+ raise ValueError(f"Expected a non-empty value for `device_id` but received {device_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ extra_headers = {
+ **strip_not_given(
+ {"X-Device-Display-ID": str(x_device_display_id) if is_given(x_device_display_id) else not_given}
+ ),
+ **(extra_headers or {}),
+ }
+ return await self._post(
+ path_template("/devices/{device_id}/clipboard", device_id=device_id),
+ body=await async_maybe_transform({"text": text}, clipboard_set_params.ClipboardSetParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+
+class ClipboardResourceWithRawResponse:
+ def __init__(self, clipboard: ClipboardResource) -> None:
+ self._clipboard = clipboard
+
+ self.get = to_raw_response_wrapper(
+ clipboard.get,
+ )
+ self.set = to_raw_response_wrapper(
+ clipboard.set,
+ )
+
+
+class AsyncClipboardResourceWithRawResponse:
+ def __init__(self, clipboard: AsyncClipboardResource) -> None:
+ self._clipboard = clipboard
+
+ self.get = async_to_raw_response_wrapper(
+ clipboard.get,
+ )
+ self.set = async_to_raw_response_wrapper(
+ clipboard.set,
+ )
+
+
+class ClipboardResourceWithStreamingResponse:
+ def __init__(self, clipboard: ClipboardResource) -> None:
+ self._clipboard = clipboard
+
+ self.get = to_streamed_response_wrapper(
+ clipboard.get,
+ )
+ self.set = to_streamed_response_wrapper(
+ clipboard.set,
+ )
+
+
+class AsyncClipboardResourceWithStreamingResponse:
+ def __init__(self, clipboard: AsyncClipboardResource) -> None:
+ self._clipboard = clipboard
+
+ self.get = async_to_streamed_response_wrapper(
+ clipboard.get,
+ )
+ self.set = async_to_streamed_response_wrapper(
+ clipboard.set,
+ )
diff --git a/src/mobilerun_sdk/resources/devices/devices.py b/src/mobilerun_sdk/resources/devices/devices.py
index b3cfb65a..ad34958e 100644
--- a/src/mobilerun_sdk/resources/devices/devices.py
+++ b/src/mobilerun_sdk/resources/devices/devices.py
@@ -124,6 +124,14 @@
AsyncTimezoneResourceWithStreamingResponse,
)
from ..._compat import cached_property
+from .clipboard import (
+ ClipboardResource,
+ AsyncClipboardResource,
+ ClipboardResourceWithRawResponse,
+ AsyncClipboardResourceWithRawResponse,
+ ClipboardResourceWithStreamingResponse,
+ AsyncClipboardResourceWithStreamingResponse,
+)
from .deep_link import (
DeepLinkResource,
AsyncDeepLinkResource,
@@ -224,6 +232,10 @@ def state(self) -> StateResource:
def tasks(self) -> TasksResource:
return TasksResource(self._client)
+ @cached_property
+ def clipboard(self) -> ClipboardResource:
+ return ClipboardResource(self._client)
+
@cached_property
def timezone(self) -> TimezoneResource:
return TimezoneResource(self._client)
@@ -907,6 +919,10 @@ def state(self) -> AsyncStateResource:
def tasks(self) -> AsyncTasksResource:
return AsyncTasksResource(self._client)
+ @cached_property
+ def clipboard(self) -> AsyncClipboardResource:
+ return AsyncClipboardResource(self._client)
+
@cached_property
def timezone(self) -> AsyncTimezoneResource:
return AsyncTimezoneResource(self._client)
@@ -1633,6 +1649,10 @@ def state(self) -> StateResourceWithRawResponse:
def tasks(self) -> TasksResourceWithRawResponse:
return TasksResourceWithRawResponse(self._devices.tasks)
+ @cached_property
+ def clipboard(self) -> ClipboardResourceWithRawResponse:
+ return ClipboardResourceWithRawResponse(self._devices.clipboard)
+
@cached_property
def timezone(self) -> TimezoneResourceWithRawResponse:
return TimezoneResourceWithRawResponse(self._devices.timezone)
@@ -1750,6 +1770,10 @@ def state(self) -> AsyncStateResourceWithRawResponse:
def tasks(self) -> AsyncTasksResourceWithRawResponse:
return AsyncTasksResourceWithRawResponse(self._devices.tasks)
+ @cached_property
+ def clipboard(self) -> AsyncClipboardResourceWithRawResponse:
+ return AsyncClipboardResourceWithRawResponse(self._devices.clipboard)
+
@cached_property
def timezone(self) -> AsyncTimezoneResourceWithRawResponse:
return AsyncTimezoneResourceWithRawResponse(self._devices.timezone)
@@ -1867,6 +1891,10 @@ def state(self) -> StateResourceWithStreamingResponse:
def tasks(self) -> TasksResourceWithStreamingResponse:
return TasksResourceWithStreamingResponse(self._devices.tasks)
+ @cached_property
+ def clipboard(self) -> ClipboardResourceWithStreamingResponse:
+ return ClipboardResourceWithStreamingResponse(self._devices.clipboard)
+
@cached_property
def timezone(self) -> TimezoneResourceWithStreamingResponse:
return TimezoneResourceWithStreamingResponse(self._devices.timezone)
@@ -1984,6 +2012,10 @@ def state(self) -> AsyncStateResourceWithStreamingResponse:
def tasks(self) -> AsyncTasksResourceWithStreamingResponse:
return AsyncTasksResourceWithStreamingResponse(self._devices.tasks)
+ @cached_property
+ def clipboard(self) -> AsyncClipboardResourceWithStreamingResponse:
+ return AsyncClipboardResourceWithStreamingResponse(self._devices.clipboard)
+
@cached_property
def timezone(self) -> AsyncTimezoneResourceWithStreamingResponse:
return AsyncTimezoneResourceWithStreamingResponse(self._devices.timezone)
diff --git a/src/mobilerun_sdk/resources/esims/esims.py b/src/mobilerun_sdk/resources/esims/esims.py
index 39132580..49347cbe 100644
--- a/src/mobilerun_sdk/resources/esims/esims.py
+++ b/src/mobilerun_sdk/resources/esims/esims.py
@@ -7,7 +7,14 @@
import httpx
-from ...types import esim_list_params, esim_create_params, esim_import_params, esim_update_params, esim_install_params
+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 (
@@ -69,6 +76,7 @@ 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,
@@ -85,6 +93,9 @@ def create(
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
@@ -95,7 +106,13 @@ def create(
"""
return self._post(
"/numbers/esims",
- body=maybe_transform({"idempotency_key": idempotency_key}, esim_create_params.EsimCreateParams),
+ 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
),
@@ -522,6 +539,8 @@ def install_status(
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,
@@ -532,12 +551,31 @@ def selector(
"""
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, and is not paginated.
+ 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
+ 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,
)
@@ -571,6 +609,7 @@ 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,
@@ -587,6 +626,9 @@ async def create(
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
@@ -597,7 +639,13 @@ async def create(
"""
return await self._post(
"/numbers/esims",
- body=await async_maybe_transform({"idempotency_key": idempotency_key}, esim_create_params.EsimCreateParams),
+ 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
),
@@ -1024,6 +1072,8 @@ async def install_status(
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,
@@ -1034,12 +1084,31 @@ async def selector(
"""
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, and is not paginated.
+ 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
+ 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,
)
diff --git a/src/mobilerun_sdk/resources/files.py b/src/mobilerun_sdk/resources/files.py
new file mode 100644
index 00000000..739ba6f8
--- /dev/null
+++ b/src/mobilerun_sdk/resources/files.py
@@ -0,0 +1,703 @@
+# 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 file_list_params, file_update_params, file_upload_url_params
+from .._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given
+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 (
+ 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.file_list_response import FileListResponse
+from ..types.file_delete_response import FileDeleteResponse
+from ..types.file_update_response import FileUpdateResponse
+from ..types.file_confirm_response import FileConfirmResponse
+from ..types.file_upload_url_response import FileUploadURLResponse
+from ..types.file_cancel_pending_response import FileCancelPendingResponse
+
+__all__ = ["FilesResource", "AsyncFilesResource"]
+
+
+class FilesResource(SyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> FilesResourceWithRawResponse:
+ """
+ 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 FilesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> FilesResourceWithStreamingResponse:
+ """
+ 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 FilesResourceWithStreamingResponse(self)
+
+ def update(
+ self,
+ file_id: str,
+ *,
+ display_name: Optional[str] | Omit = omit,
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> FileUpdateResponse:
+ """Partial update of `displayName` and/or `enabled`.
+
+ Only files with `zone=skills`
+ are mutable; other zones return 422 `unsupported_zone`.
+
+ 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 file_id:
+ raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}")
+ return self._patch(
+ path_template("/agents/files/{file_id}", file_id=file_id),
+ body=maybe_transform(
+ {
+ "display_name": display_name,
+ "enabled": enabled,
+ },
+ file_update_params.FileUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=FileUpdateResponse,
+ )
+
+ def list(
+ self,
+ *,
+ zone: Literal["user", "agent", "workflow", "skills"] | 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,
+ ) -> FileListResponse:
+ """
+ List the user's ready files, optionally filtered by zone
+
+ 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(
+ "/agents/files",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=maybe_transform({"zone": zone}, file_list_params.FileListParams),
+ ),
+ cast_to=FileListResponse,
+ )
+
+ def delete(
+ self,
+ file_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,
+ ) -> FileDeleteResponse:
+ """
+ Hard-delete a file
+
+ 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 file_id:
+ raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}")
+ return self._delete(
+ path_template("/agents/files/{file_id}", file_id=file_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=FileDeleteResponse,
+ )
+
+ def cancel_pending(
+ self,
+ file_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,
+ ) -> FileCancelPendingResponse:
+ """Soft-cancels an in-flight upload before confirm.
+
+ Only acts on `pending` rows —
+ refuses to touch `ready` to avoid wiping confirmed files. Idempotent:
+ `{ cancelled: false }` if the row exists but is no longer pending.
+
+ 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 file_id:
+ raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}")
+ return self._delete(
+ path_template("/agents/files/{file_id}/pending", file_id=file_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=FileCancelPendingResponse,
+ )
+
+ def confirm(
+ self,
+ file_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,
+ ) -> FileConfirmResponse:
+ """
+ Confirm a file upload by server-side HEAD validation
+
+ 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 file_id:
+ raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}")
+ return self._post(
+ path_template("/agents/files/{file_id}/confirm", file_id=file_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=FileConfirmResponse,
+ )
+
+ def download(
+ self,
+ file_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:
+ """Redirects to a short-lived presigned download URL.
+
+ Missing, non-ready, and files
+ owned by another tenant all return the same 404 response.
+
+ 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 file_id:
+ raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return self._get(
+ path_template("/agents/files/{file_id}/download", file_id=file_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ def upload_url(
+ self,
+ *,
+ filename: str,
+ mime_type: str,
+ size_bytes: int,
+ zone: Literal["user", "skills"] | Omit = omit,
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> FileUploadURLResponse:
+ """
+ Mint a presigned PUT URL for a user file upload
+
+ 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
+ """
+ extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})}
+ return self._post(
+ "/agents/files/upload-url",
+ body=maybe_transform(
+ {
+ "filename": filename,
+ "mime_type": mime_type,
+ "size_bytes": size_bytes,
+ "zone": zone,
+ },
+ file_upload_url_params.FileUploadURLParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=FileUploadURLResponse,
+ )
+
+
+class AsyncFilesResource(AsyncAPIResource):
+ @cached_property
+ def with_raw_response(self) -> AsyncFilesResourceWithRawResponse:
+ """
+ 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 AsyncFilesResourceWithRawResponse(self)
+
+ @cached_property
+ def with_streaming_response(self) -> AsyncFilesResourceWithStreamingResponse:
+ """
+ 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 AsyncFilesResourceWithStreamingResponse(self)
+
+ async def update(
+ self,
+ file_id: str,
+ *,
+ display_name: Optional[str] | Omit = omit,
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> FileUpdateResponse:
+ """Partial update of `displayName` and/or `enabled`.
+
+ Only files with `zone=skills`
+ are mutable; other zones return 422 `unsupported_zone`.
+
+ 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 file_id:
+ raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}")
+ return await self._patch(
+ path_template("/agents/files/{file_id}", file_id=file_id),
+ body=await async_maybe_transform(
+ {
+ "display_name": display_name,
+ "enabled": enabled,
+ },
+ file_update_params.FileUpdateParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=FileUpdateResponse,
+ )
+
+ async def list(
+ self,
+ *,
+ zone: Literal["user", "agent", "workflow", "skills"] | 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,
+ ) -> FileListResponse:
+ """
+ List the user's ready files, optionally filtered by zone
+
+ 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(
+ "/agents/files",
+ options=make_request_options(
+ extra_headers=extra_headers,
+ extra_query=extra_query,
+ extra_body=extra_body,
+ timeout=timeout,
+ query=await async_maybe_transform({"zone": zone}, file_list_params.FileListParams),
+ ),
+ cast_to=FileListResponse,
+ )
+
+ async def delete(
+ self,
+ file_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,
+ ) -> FileDeleteResponse:
+ """
+ Hard-delete a file
+
+ 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 file_id:
+ raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}")
+ return await self._delete(
+ path_template("/agents/files/{file_id}", file_id=file_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=FileDeleteResponse,
+ )
+
+ async def cancel_pending(
+ self,
+ file_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,
+ ) -> FileCancelPendingResponse:
+ """Soft-cancels an in-flight upload before confirm.
+
+ Only acts on `pending` rows —
+ refuses to touch `ready` to avoid wiping confirmed files. Idempotent:
+ `{ cancelled: false }` if the row exists but is no longer pending.
+
+ 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 file_id:
+ raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}")
+ return await self._delete(
+ path_template("/agents/files/{file_id}/pending", file_id=file_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=FileCancelPendingResponse,
+ )
+
+ async def confirm(
+ self,
+ file_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,
+ ) -> FileConfirmResponse:
+ """
+ Confirm a file upload by server-side HEAD validation
+
+ 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 file_id:
+ raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}")
+ return await self._post(
+ path_template("/agents/files/{file_id}/confirm", file_id=file_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=FileConfirmResponse,
+ )
+
+ async def download(
+ self,
+ file_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:
+ """Redirects to a short-lived presigned download URL.
+
+ Missing, non-ready, and files
+ owned by another tenant all return the same 404 response.
+
+ 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 file_id:
+ raise ValueError(f"Expected a non-empty value for `file_id` but received {file_id!r}")
+ extra_headers = {"Accept": "*/*", **(extra_headers or {})}
+ return await self._get(
+ path_template("/agents/files/{file_id}/download", file_id=file_id),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NoneType,
+ )
+
+ async def upload_url(
+ self,
+ *,
+ filename: str,
+ mime_type: str,
+ size_bytes: int,
+ zone: Literal["user", "skills"] | Omit = omit,
+ 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,
+ extra_query: Query | None = None,
+ extra_body: Body | None = None,
+ timeout: float | httpx.Timeout | None | NotGiven = not_given,
+ ) -> FileUploadURLResponse:
+ """
+ Mint a presigned PUT URL for a user file upload
+
+ 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
+ """
+ extra_headers = {**strip_not_given({"Idempotency-Key": idempotency_key}), **(extra_headers or {})}
+ return await self._post(
+ "/agents/files/upload-url",
+ body=await async_maybe_transform(
+ {
+ "filename": filename,
+ "mime_type": mime_type,
+ "size_bytes": size_bytes,
+ "zone": zone,
+ },
+ file_upload_url_params.FileUploadURLParams,
+ ),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=FileUploadURLResponse,
+ )
+
+
+class FilesResourceWithRawResponse:
+ def __init__(self, files: FilesResource) -> None:
+ self._files = files
+
+ self.update = to_raw_response_wrapper(
+ files.update,
+ )
+ self.list = to_raw_response_wrapper(
+ files.list,
+ )
+ self.delete = to_raw_response_wrapper(
+ files.delete,
+ )
+ self.cancel_pending = to_raw_response_wrapper(
+ files.cancel_pending,
+ )
+ self.confirm = to_raw_response_wrapper(
+ files.confirm,
+ )
+ self.download = to_raw_response_wrapper(
+ files.download,
+ )
+ self.upload_url = to_raw_response_wrapper(
+ files.upload_url,
+ )
+
+
+class AsyncFilesResourceWithRawResponse:
+ def __init__(self, files: AsyncFilesResource) -> None:
+ self._files = files
+
+ self.update = async_to_raw_response_wrapper(
+ files.update,
+ )
+ self.list = async_to_raw_response_wrapper(
+ files.list,
+ )
+ self.delete = async_to_raw_response_wrapper(
+ files.delete,
+ )
+ self.cancel_pending = async_to_raw_response_wrapper(
+ files.cancel_pending,
+ )
+ self.confirm = async_to_raw_response_wrapper(
+ files.confirm,
+ )
+ self.download = async_to_raw_response_wrapper(
+ files.download,
+ )
+ self.upload_url = async_to_raw_response_wrapper(
+ files.upload_url,
+ )
+
+
+class FilesResourceWithStreamingResponse:
+ def __init__(self, files: FilesResource) -> None:
+ self._files = files
+
+ self.update = to_streamed_response_wrapper(
+ files.update,
+ )
+ self.list = to_streamed_response_wrapper(
+ files.list,
+ )
+ self.delete = to_streamed_response_wrapper(
+ files.delete,
+ )
+ self.cancel_pending = to_streamed_response_wrapper(
+ files.cancel_pending,
+ )
+ self.confirm = to_streamed_response_wrapper(
+ files.confirm,
+ )
+ self.download = to_streamed_response_wrapper(
+ files.download,
+ )
+ self.upload_url = to_streamed_response_wrapper(
+ files.upload_url,
+ )
+
+
+class AsyncFilesResourceWithStreamingResponse:
+ def __init__(self, files: AsyncFilesResource) -> None:
+ self._files = files
+
+ self.update = async_to_streamed_response_wrapper(
+ files.update,
+ )
+ self.list = async_to_streamed_response_wrapper(
+ files.list,
+ )
+ self.delete = async_to_streamed_response_wrapper(
+ files.delete,
+ )
+ self.cancel_pending = async_to_streamed_response_wrapper(
+ files.cancel_pending,
+ )
+ self.confirm = async_to_streamed_response_wrapper(
+ files.confirm,
+ )
+ self.download = async_to_streamed_response_wrapper(
+ files.download,
+ )
+ self.upload_url = async_to_streamed_response_wrapper(
+ files.upload_url,
+ )
diff --git a/src/mobilerun_sdk/resources/models.py b/src/mobilerun_sdk/resources/models.py
index 4bb2764f..e32c8324 100644
--- a/src/mobilerun_sdk/resources/models.py
+++ b/src/mobilerun_sdk/resources/models.py
@@ -51,7 +51,7 @@ def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> ModelListResponse:
- """Get all LLM models"""
+ """List available LLM models."""
return self._get(
"/models",
options=make_request_options(
@@ -93,7 +93,7 @@ async def list(
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = not_given,
) -> ModelListResponse:
- """Get all LLM models"""
+ """List available LLM models."""
return await self._get(
"/models",
options=make_request_options(
diff --git a/src/mobilerun_sdk/resources/numbers/numbers.py b/src/mobilerun_sdk/resources/numbers/numbers.py
index 2ec46354..7b39353f 100644
--- a/src/mobilerun_sdk/resources/numbers/numbers.py
+++ b/src/mobilerun_sdk/resources/numbers/numbers.py
@@ -2,11 +2,12 @@
from __future__ import annotations
+from typing import Optional
from typing_extensions import Literal
import httpx
-from ...types import number_list_params, number_create_params
+from ...types import number_list_params, number_create_params, number_update_params
from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given
from ..._utils import path_template, maybe_transform, strip_not_given, async_maybe_transform
from .messages import (
@@ -29,6 +30,7 @@
from ...types.number_list_response import NumberListResponse
from ...types.number_create_response import NumberCreateResponse
from ...types.number_delete_response import NumberDeleteResponse
+from ...types.number_update_response import NumberUpdateResponse
from ...types.number_purposes_response import NumberPurposesResponse
from ...types.number_retrieve_response import NumberRetrieveResponse
from ...types.number_countries_response import NumberCountriesResponse
@@ -65,6 +67,7 @@ def create(
*,
billing_preference: Literal["included", "rent"] | Omit = omit,
country: str | Omit = omit,
+ label: Optional[str] | Omit = omit,
purpose: str | Omit = omit,
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.
@@ -87,6 +90,10 @@ def create(
country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/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.
idempotency_key: Optional request idempotency key.
@@ -106,6 +113,7 @@ def create(
{
"billing_preference": billing_preference,
"country": country,
+ "label": label,
"purpose": purpose,
},
number_create_params.NumberCreateParams,
@@ -149,6 +157,50 @@ def retrieve(
cast_to=NumberRetrieveResponse,
)
+ def update(
+ self,
+ id: str,
+ *,
+ label: 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,
+ ) -> NumberUpdateResponse:
+ """Updates the phone number's user-defined 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.
+
+ Args:
+ 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.
+
+ 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/phones/{id}", id=id),
+ body=maybe_transform({"label": label}, number_update_params.NumberUpdateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NumberUpdateResponse,
+ )
+
def list(
self,
*,
@@ -313,6 +365,7 @@ async def create(
*,
billing_preference: Literal["included", "rent"] | Omit = omit,
country: str | Omit = omit,
+ label: Optional[str] | Omit = omit,
purpose: str | Omit = omit,
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.
@@ -335,6 +388,10 @@ async def create(
country: Optional ISO 3166-1 alpha-2 country code from GET /numbers/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.
idempotency_key: Optional request idempotency key.
@@ -354,6 +411,7 @@ async def create(
{
"billing_preference": billing_preference,
"country": country,
+ "label": label,
"purpose": purpose,
},
number_create_params.NumberCreateParams,
@@ -397,6 +455,50 @@ async def retrieve(
cast_to=NumberRetrieveResponse,
)
+ async def update(
+ self,
+ id: str,
+ *,
+ label: 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,
+ ) -> NumberUpdateResponse:
+ """Updates the phone number's user-defined 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.
+
+ Args:
+ 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.
+
+ 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/phones/{id}", id=id),
+ body=await async_maybe_transform({"label": label}, number_update_params.NumberUpdateParams),
+ options=make_request_options(
+ extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
+ ),
+ cast_to=NumberUpdateResponse,
+ )
+
async def list(
self,
*,
@@ -542,6 +644,9 @@ def __init__(self, numbers: NumbersResource) -> None:
self.retrieve = to_raw_response_wrapper(
numbers.retrieve,
)
+ self.update = to_raw_response_wrapper(
+ numbers.update,
+ )
self.list = to_raw_response_wrapper(
numbers.list,
)
@@ -570,6 +675,9 @@ def __init__(self, numbers: AsyncNumbersResource) -> None:
self.retrieve = async_to_raw_response_wrapper(
numbers.retrieve,
)
+ self.update = async_to_raw_response_wrapper(
+ numbers.update,
+ )
self.list = async_to_raw_response_wrapper(
numbers.list,
)
@@ -598,6 +706,9 @@ def __init__(self, numbers: NumbersResource) -> None:
self.retrieve = to_streamed_response_wrapper(
numbers.retrieve,
)
+ self.update = to_streamed_response_wrapper(
+ numbers.update,
+ )
self.list = to_streamed_response_wrapper(
numbers.list,
)
@@ -626,6 +737,9 @@ def __init__(self, numbers: AsyncNumbersResource) -> None:
self.retrieve = async_to_streamed_response_wrapper(
numbers.retrieve,
)
+ self.update = async_to_streamed_response_wrapper(
+ numbers.update,
+ )
self.list = async_to_streamed_response_wrapper(
numbers.list,
)
diff --git a/src/mobilerun_sdk/resources/workflows/flows/flows.py b/src/mobilerun_sdk/resources/workflows/flows/flows.py
index 79277a29..db390fcc 100644
--- a/src/mobilerun_sdk/resources/workflows/flows/flows.py
+++ b/src/mobilerun_sdk/resources/workflows/flows/flows.py
@@ -85,6 +85,7 @@ def create(
notify_on_failure: bool | Omit = omit,
notify_on_success: bool | Omit = omit,
notify_webhook_id: Optional[str] | Omit = omit,
+ recording_enabled: bool | 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.
@@ -125,6 +126,7 @@ def create(
"notify_on_failure": notify_on_failure,
"notify_on_success": notify_on_success,
"notify_webhook_id": notify_webhook_id,
+ "recording_enabled": recording_enabled,
"self_healing_enabled": self_healing_enabled,
"self_healing_max_attempts": self_healing_max_attempts,
},
@@ -184,6 +186,7 @@ def update(
notify_on_failure: bool | Omit = omit,
notify_on_success: bool | Omit = omit,
notify_webhook_id: Optional[str] | Omit = omit,
+ recording_enabled: bool | Omit = omit,
self_healing_enabled: bool | Omit = omit,
self_healing_max_attempts: int | Omit = omit,
trigger_id: str | Omit = omit,
@@ -225,6 +228,7 @@ def update(
"notify_on_failure": notify_on_failure,
"notify_on_success": notify_on_success,
"notify_webhook_id": notify_webhook_id,
+ "recording_enabled": recording_enabled,
"self_healing_enabled": self_healing_enabled,
"self_healing_max_attempts": self_healing_max_attempts,
"trigger_id": trigger_id,
@@ -538,6 +542,7 @@ async def create(
notify_on_failure: bool | Omit = omit,
notify_on_success: bool | Omit = omit,
notify_webhook_id: Optional[str] | Omit = omit,
+ recording_enabled: bool | 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.
@@ -578,6 +583,7 @@ async def create(
"notify_on_failure": notify_on_failure,
"notify_on_success": notify_on_success,
"notify_webhook_id": notify_webhook_id,
+ "recording_enabled": recording_enabled,
"self_healing_enabled": self_healing_enabled,
"self_healing_max_attempts": self_healing_max_attempts,
},
@@ -637,6 +643,7 @@ async def update(
notify_on_failure: bool | Omit = omit,
notify_on_success: bool | Omit = omit,
notify_webhook_id: Optional[str] | Omit = omit,
+ recording_enabled: bool | Omit = omit,
self_healing_enabled: bool | Omit = omit,
self_healing_max_attempts: int | Omit = omit,
trigger_id: str | Omit = omit,
@@ -678,6 +685,7 @@ async def update(
"notify_on_failure": notify_on_failure,
"notify_on_success": notify_on_success,
"notify_webhook_id": notify_webhook_id,
+ "recording_enabled": recording_enabled,
"self_healing_enabled": self_healing_enabled,
"self_healing_max_attempts": self_healing_max_attempts,
"trigger_id": trigger_id,
diff --git a/src/mobilerun_sdk/types/__init__.py b/src/mobilerun_sdk/types/__init__.py
index f634c2c1..92c43f3d 100644
--- a/src/mobilerun_sdk/types/__init__.py
+++ b/src/mobilerun_sdk/types/__init__.py
@@ -18,6 +18,7 @@
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
@@ -27,10 +28,11 @@
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 .number_list_params import NumberListParams as NumberListParams
from .task_list_response import TaskListResponse as TaskListResponse
from .task_stop_response import TaskStopResponse as TaskStopResponse
-from .agent_list_response import AgentListResponse as AgentListResponse
from .app_delete_response import AppDeleteResponse as AppDeleteResponse
from .carrier_list_params import CarrierListParams as CarrierListParams
from .esim_install_params import EsimInstallParams as EsimInstallParams
@@ -46,9 +48,13 @@
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 .number_create_params import NumberCreateParams as NumberCreateParams
from .number_list_response import NumberListResponse as NumberListResponse
+from .number_update_params import NumberUpdateParams as NumberUpdateParams
from .app_event_list_params import AppEventListParams as AppEventListParams
from .app_retrieve_response import AppRetrieveResponse as AppRetrieveResponse
from .carrier_create_params import CarrierCreateParams as CarrierCreateParams
@@ -57,6 +63,7 @@
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 .message_list_response import MessageListResponse as MessageListResponse
from .profile_create_params import ProfileCreateParams as ProfileCreateParams
from .profile_list_response import ProfileListResponse as ProfileListResponse
@@ -74,8 +81,10 @@
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 .number_create_response import NumberCreateResponse as NumberCreateResponse
from .number_delete_response import NumberDeleteResponse as NumberDeleteResponse
+from .number_update_response import NumberUpdateResponse as NumberUpdateResponse
from .task_retrieve_response import TaskRetrieveResponse as TaskRetrieveResponse
from .app_event_list_response import AppEventListResponse as AppEventListResponse
from .carrier_create_response import CarrierCreateResponse as CarrierCreateResponse
@@ -93,6 +102,7 @@
from .credential_list_response import CredentialListResponse as CredentialListResponse
from .device_retrieve_response import DeviceRetrieveResponse as DeviceRetrieveResponse
from .device_set_name_response import DeviceSetNameResponse as DeviceSetNameResponse
+from .file_upload_url_response import FileUploadURLResponse as FileUploadURLResponse
from .number_purposes_response import NumberPurposesResponse as NumberPurposesResponse
from .number_retrieve_response import NumberRetrieveResponse as NumberRetrieveResponse
from .task_get_status_response import TaskGetStatusResponse as TaskGetStatusResponse
@@ -111,6 +121,7 @@
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
diff --git a/src/mobilerun_sdk/types/agent_list_response.py b/src/mobilerun_sdk/types/agent_list_response.py
deleted file mode 100644
index fc366d60..00000000
--- a/src/mobilerun_sdk/types/agent_list_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 TypeAlias
-
-from pydantic import Field as FieldInfo
-
-from .._models import BaseModel
-
-__all__ = ["AgentListResponse", "AgentListResponseItem"]
-
-
-class AgentListResponseItem(BaseModel):
- id: int
-
- description: Optional[str] = None
-
- icon: str
-
- llm_model: str = FieldInfo(alias="llmModel")
-
- max_steps: int = FieldInfo(alias="maxSteps")
-
- name: str
-
- reasoning: bool
-
- subagent_model: Optional[str] = FieldInfo(alias="subagentModel", default=None)
-
- vision: bool
-
-
-AgentListResponse: TypeAlias = List[AgentListResponseItem]
diff --git a/src/mobilerun_sdk/types/app_list_response.py b/src/mobilerun_sdk/types/app_list_response.py
index 5d85ac9c..c7088c0c 100644
--- a/src/mobilerun_sdk/types/app_list_response.py
+++ b/src/mobilerun_sdk/types/app_list_response.py
@@ -292,7 +292,7 @@ class ItemVersion(BaseModel):
size_bytes: Optional[int] = FieldInfo(alias="sizeBytes", default=None)
- source: Literal["user", "system", "portal", "store"]
+ source: Literal["user", "system", "portal", "store", "catalog"]
status: Literal["queued", "available", "failed"]
diff --git a/src/mobilerun_sdk/types/app_list_versions_response.py b/src/mobilerun_sdk/types/app_list_versions_response.py
index a2bfedbd..a4181ed7 100644
--- a/src/mobilerun_sdk/types/app_list_versions_response.py
+++ b/src/mobilerun_sdk/types/app_list_versions_response.py
@@ -281,7 +281,7 @@ class Data(BaseModel):
size_bytes: Optional[int] = FieldInfo(alias="sizeBytes", default=None)
- source: Literal["user", "system", "portal", "store"]
+ source: Literal["user", "system", "portal", "store", "catalog"]
status: Literal["queued", "available", "failed"]
diff --git a/src/mobilerun_sdk/types/assistant/__init__.py b/src/mobilerun_sdk/types/assistant/__init__.py
new file mode 100644
index 00000000..292b0d5d
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/__init__.py
@@ -0,0 +1,32 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from .conversation_list_params import ConversationListParams as ConversationListParams
+from .conversation_send_params import ConversationSendParams as ConversationSendParams
+from .conversation_abort_params import ConversationAbortParams as ConversationAbortParams
+from .conversation_create_params import ConversationCreateParams as ConversationCreateParams
+from .conversation_list_response import ConversationListResponse as ConversationListResponse
+from .conversation_send_response import ConversationSendResponse as ConversationSendResponse
+from .conversation_stream_params import ConversationStreamParams as ConversationStreamParams
+from .conversation_update_params import ConversationUpdateParams as ConversationUpdateParams
+from .conversation_abort_response import ConversationAbortResponse as ConversationAbortResponse
+from .conversation_history_params import ConversationHistoryParams as ConversationHistoryParams
+from .conversation_create_response import ConversationCreateResponse as ConversationCreateResponse
+from .conversation_stream_response import ConversationStreamResponse as ConversationStreamResponse
+from .conversation_update_response import ConversationUpdateResponse as ConversationUpdateResponse
+from .conversation_history_response import ConversationHistoryResponse as ConversationHistoryResponse
+from .conversation_answer_question_params import ConversationAnswerQuestionParams as ConversationAnswerQuestionParams
+from .conversation_reject_question_params import ConversationRejectQuestionParams as ConversationRejectQuestionParams
+from .conversation_answer_permission_params import (
+ ConversationAnswerPermissionParams as ConversationAnswerPermissionParams,
+)
+from .conversation_answer_question_response import (
+ ConversationAnswerQuestionResponse as ConversationAnswerQuestionResponse,
+)
+from .conversation_reject_question_response import (
+ ConversationRejectQuestionResponse as ConversationRejectQuestionResponse,
+)
+from .conversation_answer_permission_response import (
+ ConversationAnswerPermissionResponse as ConversationAnswerPermissionResponse,
+)
diff --git a/src/mobilerun_sdk/types/assistant/conversation_abort_params.py b/src/mobilerun_sdk/types/assistant/conversation_abort_params.py
new file mode 100644
index 00000000..ced9a891
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_abort_params.py
@@ -0,0 +1,13 @@
+# 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__ = ["ConversationAbortParams"]
+
+
+class ConversationAbortParams(TypedDict, total=False):
+ session_id: Required[Annotated[str, PropertyInfo(alias="sessionId")]]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_abort_response.py b/src/mobilerun_sdk/types/assistant/conversation_abort_response.py
new file mode 100644
index 00000000..179518b5
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_abort_response.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["ConversationAbortResponse"]
+
+
+class ConversationAbortResponse(BaseModel):
+ ok: Literal[True]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_answer_permission_params.py b/src/mobilerun_sdk/types/assistant/conversation_answer_permission_params.py
new file mode 100644
index 00000000..038e0123
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_answer_permission_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ConversationAnswerPermissionParams"]
+
+
+class ConversationAnswerPermissionParams(TypedDict, total=False):
+ permission_id: Required[Annotated[str, PropertyInfo(alias="permissionId")]]
+
+ response: Required[Literal["once", "always", "reject"]]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_answer_permission_response.py b/src/mobilerun_sdk/types/assistant/conversation_answer_permission_response.py
new file mode 100644
index 00000000..7830fdac
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_answer_permission_response.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["ConversationAnswerPermissionResponse"]
+
+
+class ConversationAnswerPermissionResponse(BaseModel):
+ ok: Literal[True]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_answer_question_params.py b/src/mobilerun_sdk/types/assistant/conversation_answer_question_params.py
new file mode 100644
index 00000000..3a45efec
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_answer_question_params.py
@@ -0,0 +1,33 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Union, Iterable
+from typing_extensions import Required, Annotated, TypeAlias, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ConversationAnswerQuestionParams", "Answer", "AnswerLabel", "AnswerCustom", "AnswerUnionMember2"]
+
+
+class ConversationAnswerQuestionParams(TypedDict, total=False):
+ answers: Required[Iterable[Iterable[Answer]]]
+
+ question_id: Required[Annotated[str, PropertyInfo(alias="questionId")]]
+
+
+class AnswerLabel(TypedDict, total=False):
+ label: Required[str]
+
+
+class AnswerCustom(TypedDict, total=False):
+ custom: Required[str]
+
+
+class AnswerUnionMember2(TypedDict, total=False):
+ custom: Required[str]
+
+ label: Required[str]
+
+
+Answer: TypeAlias = Union[AnswerLabel, AnswerCustom, AnswerUnionMember2]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_answer_question_response.py b/src/mobilerun_sdk/types/assistant/conversation_answer_question_response.py
new file mode 100644
index 00000000..404041c9
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_answer_question_response.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["ConversationAnswerQuestionResponse"]
+
+
+class ConversationAnswerQuestionResponse(BaseModel):
+ ok: Literal[True]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_create_params.py b/src/mobilerun_sdk/types/assistant/conversation_create_params.py
new file mode 100644
index 00000000..96755aa4
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_create_params.py
@@ -0,0 +1,24 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ConversationCreateParams"]
+
+
+class ConversationCreateParams(TypedDict, total=False):
+ title: Required[str]
+
+ agent: str
+
+ description: str
+
+ idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")]
+ """Optional client key.
+
+ Reusing the same key with the same request body by the same authenticated caller
+ within 24 hours returns the already-created session instead of a second one.
+ """
diff --git a/src/mobilerun_sdk/types/assistant/conversation_create_response.py b/src/mobilerun_sdk/types/assistant/conversation_create_response.py
new file mode 100644
index 00000000..34341512
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_create_response.py
@@ -0,0 +1,50 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["ConversationCreateResponse", "Session"]
+
+
+class Session(BaseModel):
+ id: str
+
+ agent: Optional[str] = None
+
+ base_prompt_tokens: Optional[float] = FieldInfo(alias="basePromptTokens", default=None)
+
+ context_exhausted_at: Optional[str] = FieldInfo(alias="contextExhaustedAt", default=None)
+
+ cost_cents: float = FieldInfo(alias="costCents")
+
+ cost_usd: float = FieldInfo(alias="costUsd")
+
+ created_at: str = FieldInfo(alias="createdAt")
+
+ description: Optional[str] = None
+
+ last_active_at: str = FieldInfo(alias="lastActiveAt")
+
+ peak_prompt_tokens: Optional[float] = FieldInfo(alias="peakPromptTokens", default=None)
+
+ pinned: bool
+
+ prompt_status: Literal["ready", "machine_replaced"] = FieldInfo(alias="promptStatus")
+
+ status: str
+
+ title: str
+
+ turn_active: bool = FieldInfo(alias="turnActive")
+
+ turn_started_at: Optional[str] = FieldInfo(alias="turnStartedAt", default=None)
+
+ created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
+
+
+class ConversationCreateResponse(BaseModel):
+ session: Session
diff --git a/src/mobilerun_sdk/types/assistant/conversation_history_params.py b/src/mobilerun_sdk/types/assistant/conversation_history_params.py
new file mode 100644
index 00000000..ecf0dbe0
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_history_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ConversationHistoryParams"]
+
+
+class ConversationHistoryParams(TypedDict, total=False):
+ session_id: Required[Annotated[str, PropertyInfo(alias="sessionId")]]
+
+ limit: int
diff --git a/src/mobilerun_sdk/types/assistant/conversation_history_response.py b/src/mobilerun_sdk/types/assistant/conversation_history_response.py
new file mode 100644
index 00000000..8288033a
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_history_response.py
@@ -0,0 +1,68 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import TYPE_CHECKING, Dict, List, Optional
+from datetime import datetime
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["ConversationHistoryResponse", "Message", "MessagePart", "MessageMetadata"]
+
+
+class MessagePart(BaseModel):
+ type: str
+
+ if TYPE_CHECKING:
+ # Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a
+ # value to this field, so for compatibility we avoid doing it at runtime.
+ __pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride]
+
+ # Stub to indicate that arbitrary properties are accepted.
+ # To access properties that are not valid identifiers you can use `getattr`, e.g.
+ # `getattr(obj, '$type')`
+ def __getattr__(self, attr: str) -> object: ...
+ else:
+ __pydantic_extra__: Dict[str, object]
+
+
+class MessageMetadata(BaseModel):
+ agent: Optional[str] = None
+
+ agent_message_id: Optional[str] = FieldInfo(alias="agentMessageId", default=None)
+
+ agent_session_id: Optional[str] = FieldInfo(alias="agentSessionId", default=None)
+
+ turn_anchor_message_id: Optional[str] = FieldInfo(alias="turnAnchorMessageId", default=None)
+
+
+class Message(BaseModel):
+ id: str
+
+ parts: List[MessagePart]
+
+ role: Literal["user", "assistant", "system"]
+
+ created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
+
+ created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
+
+ feedback: Optional[bool] = None
+
+ metadata: Optional[MessageMetadata] = None
+
+ source: Optional[Literal["cloud", "telegram", "api", "workflow", "notification"]] = None
+
+ synthetic: Optional[bool] = None
+
+ user_id: Optional[str] = FieldInfo(alias="userId", default=None)
+ """Deprecated: use createdBy."""
+
+
+class ConversationHistoryResponse(BaseModel):
+ messages: List[Message]
+
+ turn_active: bool = FieldInfo(alias="turnActive")
+
+ truncated: Optional[bool] = None
diff --git a/src/mobilerun_sdk/types/assistant/conversation_list_params.py b/src/mobilerun_sdk/types/assistant/conversation_list_params.py
new file mode 100644
index 00000000..616be183
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_list_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ConversationListParams"]
+
+
+class ConversationListParams(TypedDict, total=False):
+ kind: Literal["chat", "agent_workflow"]
+
+ mine: Literal["true", "false"]
+
+ workflow_id: Annotated[str, PropertyInfo(alias="workflowId")]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_list_response.py b/src/mobilerun_sdk/types/assistant/conversation_list_response.py
new file mode 100644
index 00000000..3f3ba16a
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_list_response.py
@@ -0,0 +1,105 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import List, Union, Optional
+from typing_extensions import Literal, TypeAlias
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["ConversationListResponse", "Session", "SessionUnionMember0", "SessionUnionMember1"]
+
+
+class SessionUnionMember0(BaseModel):
+ id: str
+
+ agent: Optional[str] = None
+
+ base_prompt_tokens: Optional[float] = FieldInfo(alias="basePromptTokens", default=None)
+
+ context_exhausted_at: Optional[str] = FieldInfo(alias="contextExhaustedAt", default=None)
+
+ cost_cents: float = FieldInfo(alias="costCents")
+
+ cost_usd: float = FieldInfo(alias="costUsd")
+
+ created_at: str = FieldInfo(alias="createdAt")
+
+ description: Optional[str] = None
+
+ episode: int
+
+ kind: Literal["chat"]
+
+ last_active_at: str = FieldInfo(alias="lastActiveAt")
+
+ peak_prompt_tokens: Optional[float] = FieldInfo(alias="peakPromptTokens", default=None)
+
+ pinned: bool
+
+ prompt_status: Literal["ready", "machine_replaced"] = FieldInfo(alias="promptStatus")
+
+ source_execution_id: None = FieldInfo(alias="sourceExecutionId", default=None)
+
+ status: str
+
+ title: str
+
+ turn_active: bool = FieldInfo(alias="turnActive")
+
+ turn_started_at: Optional[str] = FieldInfo(alias="turnStartedAt", default=None)
+
+ workflow_id: None = FieldInfo(alias="workflowId", default=None)
+
+ created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
+
+
+class SessionUnionMember1(BaseModel):
+ id: str
+
+ agent: Optional[str] = None
+
+ base_prompt_tokens: Optional[float] = FieldInfo(alias="basePromptTokens", default=None)
+
+ context_exhausted_at: Optional[str] = FieldInfo(alias="contextExhaustedAt", default=None)
+
+ cost_cents: float = FieldInfo(alias="costCents")
+
+ cost_usd: float = FieldInfo(alias="costUsd")
+
+ created_at: str = FieldInfo(alias="createdAt")
+
+ description: Optional[str] = None
+
+ episode: int
+
+ kind: Literal["agent_workflow"]
+
+ last_active_at: str = FieldInfo(alias="lastActiveAt")
+
+ peak_prompt_tokens: Optional[float] = FieldInfo(alias="peakPromptTokens", default=None)
+
+ pinned: bool
+
+ prompt_status: Literal["ready", "machine_replaced"] = FieldInfo(alias="promptStatus")
+
+ source_execution_id: str = FieldInfo(alias="sourceExecutionId")
+
+ status: str
+
+ title: str
+
+ turn_active: bool = FieldInfo(alias="turnActive")
+
+ turn_started_at: Optional[str] = FieldInfo(alias="turnStartedAt", default=None)
+
+ workflow_id: str = FieldInfo(alias="workflowId")
+
+ created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
+
+
+Session: TypeAlias = Union[SessionUnionMember0, SessionUnionMember1]
+
+
+class ConversationListResponse(BaseModel):
+ sessions: List[Session]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_reject_question_params.py b/src/mobilerun_sdk/types/assistant/conversation_reject_question_params.py
new file mode 100644
index 00000000..32db68e7
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_reject_question_params.py
@@ -0,0 +1,13 @@
+# 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__ = ["ConversationRejectQuestionParams"]
+
+
+class ConversationRejectQuestionParams(TypedDict, total=False):
+ question_id: Required[Annotated[str, PropertyInfo(alias="questionId")]]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_reject_question_response.py b/src/mobilerun_sdk/types/assistant/conversation_reject_question_response.py
new file mode 100644
index 00000000..b6e30890
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_reject_question_response.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from ..._models import BaseModel
+
+__all__ = ["ConversationRejectQuestionResponse"]
+
+
+class ConversationRejectQuestionResponse(BaseModel):
+ ok: Literal[True]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_send_params.py b/src/mobilerun_sdk/types/assistant/conversation_send_params.py
new file mode 100644
index 00000000..60413764
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_send_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ConversationSendParams"]
+
+
+class ConversationSendParams(TypedDict, total=False):
+ message: Required[str]
+
+ session_id: Required[Annotated[str, PropertyInfo(alias="sessionId")]]
+
+ agent: str
diff --git a/src/mobilerun_sdk/types/assistant/conversation_send_response.py b/src/mobilerun_sdk/types/assistant/conversation_send_response.py
new file mode 100644
index 00000000..7b558a5f
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_send_response.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["ConversationSendResponse"]
+
+
+class ConversationSendResponse(BaseModel):
+ assistant_text: str = FieldInfo(alias="assistantText")
+
+ chat_session_id: str = FieldInfo(alias="chatSessionId")
+
+ error_text: Optional[str] = FieldInfo(alias="errorText", default=None)
diff --git a/src/mobilerun_sdk/types/assistant/conversation_stream_params.py b/src/mobilerun_sdk/types/assistant/conversation_stream_params.py
new file mode 100644
index 00000000..ccd2c6c6
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_stream_params.py
@@ -0,0 +1,13 @@
+# 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__ = ["ConversationStreamParams"]
+
+
+class ConversationStreamParams(TypedDict, total=False):
+ session_id: Required[Annotated[str, PropertyInfo(alias="sessionId")]]
diff --git a/src/mobilerun_sdk/types/assistant/conversation_stream_response.py b/src/mobilerun_sdk/types/assistant/conversation_stream_response.py
new file mode 100644
index 00000000..8e8f2698
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_stream_response.py
@@ -0,0 +1,7 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import TypeAlias
+
+__all__ = ["ConversationStreamResponse"]
+
+ConversationStreamResponse: TypeAlias = str
diff --git a/src/mobilerun_sdk/types/assistant/conversation_update_params.py b/src/mobilerun_sdk/types/assistant/conversation_update_params.py
new file mode 100644
index 00000000..3acb4ee9
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_update_params.py
@@ -0,0 +1,18 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["ConversationUpdateParams"]
+
+
+class ConversationUpdateParams(TypedDict, total=False):
+ description: Optional[str]
+
+ pinned: bool
+
+ status: Literal["active", "archived"]
+
+ title: str
diff --git a/src/mobilerun_sdk/types/assistant/conversation_update_response.py b/src/mobilerun_sdk/types/assistant/conversation_update_response.py
new file mode 100644
index 00000000..514fad09
--- /dev/null
+++ b/src/mobilerun_sdk/types/assistant/conversation_update_response.py
@@ -0,0 +1,50 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+from typing_extensions import Literal
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["ConversationUpdateResponse", "Session"]
+
+
+class Session(BaseModel):
+ id: str
+
+ agent: Optional[str] = None
+
+ base_prompt_tokens: Optional[float] = FieldInfo(alias="basePromptTokens", default=None)
+
+ context_exhausted_at: Optional[str] = FieldInfo(alias="contextExhaustedAt", default=None)
+
+ cost_cents: float = FieldInfo(alias="costCents")
+
+ cost_usd: float = FieldInfo(alias="costUsd")
+
+ created_at: str = FieldInfo(alias="createdAt")
+
+ description: Optional[str] = None
+
+ last_active_at: str = FieldInfo(alias="lastActiveAt")
+
+ peak_prompt_tokens: Optional[float] = FieldInfo(alias="peakPromptTokens", default=None)
+
+ pinned: bool
+
+ prompt_status: Literal["ready", "machine_replaced"] = FieldInfo(alias="promptStatus")
+
+ status: str
+
+ title: str
+
+ turn_active: bool = FieldInfo(alias="turnActive")
+
+ turn_started_at: Optional[str] = FieldInfo(alias="turnStartedAt", default=None)
+
+ created_by: Optional[str] = FieldInfo(alias="createdBy", default=None)
+
+
+class ConversationUpdateResponse(BaseModel):
+ session: Session
diff --git a/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py b/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py
index d8b598b2..2e02c5ea 100644
--- a/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py
+++ b/src/mobilerun_sdk/types/device_retrieve_capabilities_response.py
@@ -20,6 +20,8 @@ class Capabilities(BaseModel):
camera_injection: bool = FieldInfo(alias="cameraInjection")
+ clipboard: bool
+
esim: bool
files: bool
diff --git a/src/mobilerun_sdk/types/devices/__init__.py b/src/mobilerun_sdk/types/devices/__init__.py
index 18dfbe66..6b5d3494 100644
--- a/src/mobilerun_sdk/types/devices/__init__.py
+++ b/src/mobilerun_sdk/types/devices/__init__.py
@@ -29,6 +29,7 @@
from .state_time_response import StateTimeResponse as StateTimeResponse
from .timezone_set_params import TimezoneSetParams as TimezoneSetParams
from .action_global_params import ActionGlobalParams as ActionGlobalParams
+from .clipboard_set_params import ClipboardSetParams as ClipboardSetParams
from .esim_activate_params import EsimActivateParams as EsimActivateParams
from .esim_status_response import EsimStatusResponse as EsimStatusResponse
from .file_download_params import FileDownloadParams as FileDownloadParams
@@ -40,6 +41,7 @@
from .proxy_status_response import ProxyStatusResponse as ProxyStatusResponse
from .recording_list_params import RecordingListParams as RecordingListParams
from .timezone_get_response import TimezoneGetResponse as TimezoneGetResponse
+from .clipboard_get_response import ClipboardGetResponse as ClipboardGetResponse
from .esim_activate_response import EsimActivateResponse as EsimActivateResponse
from .file_download_response import FileDownloadResponse as FileDownloadResponse
from .recording_start_params import RecordingStartParams as RecordingStartParams
diff --git a/src/mobilerun_sdk/types/devices/clipboard_get_response.py b/src/mobilerun_sdk/types/devices/clipboard_get_response.py
new file mode 100644
index 00000000..f5b53a04
--- /dev/null
+++ b/src/mobilerun_sdk/types/devices/clipboard_get_response.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing import Optional
+
+from pydantic import Field as FieldInfo
+
+from ..._models import BaseModel
+
+__all__ = ["ClipboardGetResponse"]
+
+
+class ClipboardGetResponse(BaseModel):
+ text: str
+
+ schema_: Optional[str] = FieldInfo(alias="$schema", default=None)
+ """A URL to the JSON Schema for this object."""
diff --git a/src/mobilerun_sdk/types/devices/clipboard_set_params.py b/src/mobilerun_sdk/types/devices/clipboard_set_params.py
new file mode 100644
index 00000000..0d665423
--- /dev/null
+++ b/src/mobilerun_sdk/types/devices/clipboard_set_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Required, Annotated, TypedDict
+
+from ..._utils import PropertyInfo
+
+__all__ = ["ClipboardSetParams"]
+
+
+class ClipboardSetParams(TypedDict, total=False):
+ text: Required[str]
+
+ x_device_display_id: Annotated[int, PropertyInfo(alias="X-Device-Display-ID")]
diff --git a/src/mobilerun_sdk/types/esim_create_params.py b/src/mobilerun_sdk/types/esim_create_params.py
index 1e76c2c9..973cbd1d 100644
--- a/src/mobilerun_sdk/types/esim_create_params.py
+++ b/src/mobilerun_sdk/types/esim_create_params.py
@@ -2,6 +2,7 @@
from __future__ import annotations
+from typing import Optional
from typing_extensions import Annotated, TypedDict
from .._utils import PropertyInfo
@@ -15,3 +16,9 @@ class EsimCreateParams(TypedDict, total=False):
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_list_response.py b/src/mobilerun_sdk/types/esim_list_response.py
index a0440fe0..5c236e21 100644
--- a/src/mobilerun_sdk/types/esim_list_response.py
+++ b/src/mobilerun_sdk/types/esim_list_response.py
@@ -9,10 +9,10 @@
from .._models import BaseModel
from .shared.pagination import Pagination
-__all__ = ["EsimListResponse", "Data", "DataItem"]
+__all__ = ["EsimListResponse", "Item"]
-class DataItem(BaseModel):
+class Item(BaseModel):
id: str
carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
@@ -66,11 +66,7 @@ class DataItem(BaseModel):
] = FieldInfo(alias="rentStatus", default=None)
-class Data(BaseModel):
- items: List[DataItem]
+class EsimListResponse(BaseModel):
+ items: List[Item]
pagination: Pagination
-
-
-class EsimListResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/esim_selector_params.py b/src/mobilerun_sdk/types/esim_selector_params.py
new file mode 100644
index 00000000..d5cd46c1
--- /dev/null
+++ b/src/mobilerun_sdk/types/esim_selector_params.py
@@ -0,0 +1,15 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import 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
index 7eedbf93..4288bcf9 100644
--- a/src/mobilerun_sdk/types/esim_selector_response.py
+++ b/src/mobilerun_sdk/types/esim_selector_response.py
@@ -6,11 +6,12 @@
from pydantic import Field as FieldInfo
from .._models import BaseModel
+from .shared.pagination import Pagination
-__all__ = ["EsimSelectorResponse", "Data", "DataItem"]
+__all__ = ["EsimSelectorResponse", "Item"]
-class DataItem(BaseModel):
+class Item(BaseModel):
id: str
carrier_name: Optional[str] = FieldInfo(alias="carrierName", default=None)
@@ -26,9 +27,7 @@ class DataItem(BaseModel):
status: Literal["in_stock", "owned", "installing", "installed", "install_failed", "retired"]
-class Data(BaseModel):
- items: List[DataItem]
-
-
class EsimSelectorResponse(BaseModel):
- data: Data
+ items: List[Item]
+
+ pagination: Pagination
diff --git a/src/mobilerun_sdk/types/esims/message_list_response.py b/src/mobilerun_sdk/types/esims/message_list_response.py
index 077b2c78..c04b3d46 100644
--- a/src/mobilerun_sdk/types/esims/message_list_response.py
+++ b/src/mobilerun_sdk/types/esims/message_list_response.py
@@ -9,10 +9,10 @@
from ..._models import BaseModel
from ..shared.pagination import Pagination
-__all__ = ["MessageListResponse", "Data", "DataItem"]
+__all__ = ["MessageListResponse", "Item"]
-class DataItem(BaseModel):
+class Item(BaseModel):
id: str
body: Optional[str] = None
@@ -38,11 +38,7 @@ class DataItem(BaseModel):
status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"]
-class Data(BaseModel):
- items: List[DataItem]
+class MessageListResponse(BaseModel):
+ items: List[Item]
pagination: Pagination
-
-
-class MessageListResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/file_cancel_pending_response.py b/src/mobilerun_sdk/types/file_cancel_pending_response.py
new file mode 100644
index 00000000..811c6b32
--- /dev/null
+++ b/src/mobilerun_sdk/types/file_cancel_pending_response.py
@@ -0,0 +1,9 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from .._models import BaseModel
+
+__all__ = ["FileCancelPendingResponse"]
+
+
+class FileCancelPendingResponse(BaseModel):
+ cancelled: bool
diff --git a/src/mobilerun_sdk/types/file_confirm_response.py b/src/mobilerun_sdk/types/file_confirm_response.py
new file mode 100644
index 00000000..7ee2a30c
--- /dev/null
+++ b/src/mobilerun_sdk/types/file_confirm_response.py
@@ -0,0 +1,35 @@
+# 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__ = ["FileConfirmResponse"]
+
+
+class FileConfirmResponse(BaseModel):
+ actual_size_bytes: float = FieldInfo(alias="actualSizeBytes")
+
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ created_by: Literal["user", "agent", "workflow"] = FieldInfo(alias="createdBy")
+
+ display_name: Optional[str] = FieldInfo(alias="displayName", default=None)
+
+ enabled: bool
+
+ file_id: str = FieldInfo(alias="fileId")
+
+ filename: str
+
+ mime_type: str = FieldInfo(alias="mimeType")
+
+ size_bytes: float = FieldInfo(alias="sizeBytes")
+
+ state: Literal["ready"]
+
+ zone: Literal["user", "agent", "workflow", "skills"]
diff --git a/src/mobilerun_sdk/types/file_delete_response.py b/src/mobilerun_sdk/types/file_delete_response.py
new file mode 100644
index 00000000..66dabbab
--- /dev/null
+++ b/src/mobilerun_sdk/types/file_delete_response.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from typing_extensions import Literal
+
+from .._models import BaseModel
+
+__all__ = ["FileDeleteResponse"]
+
+
+class FileDeleteResponse(BaseModel):
+ ok: Literal[True]
diff --git a/src/mobilerun_sdk/types/file_list_params.py b/src/mobilerun_sdk/types/file_list_params.py
new file mode 100644
index 00000000..fe1d5561
--- /dev/null
+++ b/src/mobilerun_sdk/types/file_list_params.py
@@ -0,0 +1,11 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, TypedDict
+
+__all__ = ["FileListParams"]
+
+
+class FileListParams(TypedDict, total=False):
+ zone: Literal["user", "agent", "workflow", "skills"]
diff --git a/src/mobilerun_sdk/types/file_list_response.py b/src/mobilerun_sdk/types/file_list_response.py
new file mode 100644
index 00000000..014c11fb
--- /dev/null
+++ b/src/mobilerun_sdk/types/file_list_response.py
@@ -0,0 +1,43 @@
+# 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
+
+__all__ = ["FileListResponse", "File", "Quota"]
+
+
+class File(BaseModel):
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ created_by: Literal["user", "agent", "workflow"] = FieldInfo(alias="createdBy")
+
+ display_name: Optional[str] = FieldInfo(alias="displayName", default=None)
+
+ enabled: bool
+
+ file_id: str = FieldInfo(alias="fileId")
+
+ filename: str
+
+ mime_type: str = FieldInfo(alias="mimeType")
+
+ size_bytes: float = FieldInfo(alias="sizeBytes")
+
+ zone: Literal["user", "agent", "workflow", "skills"]
+
+
+class Quota(BaseModel):
+ current_bytes: int = FieldInfo(alias="currentBytes")
+
+ quota_bytes: int = FieldInfo(alias="quotaBytes")
+
+
+class FileListResponse(BaseModel):
+ files: List[File]
+
+ quota: Quota
diff --git a/src/mobilerun_sdk/types/file_update_params.py b/src/mobilerun_sdk/types/file_update_params.py
new file mode 100644
index 00000000..e6da4e5a
--- /dev/null
+++ b/src/mobilerun_sdk/types/file_update_params.py
@@ -0,0 +1,16 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["FileUpdateParams"]
+
+
+class FileUpdateParams(TypedDict, total=False):
+ display_name: Annotated[Optional[str], PropertyInfo(alias="displayName")]
+
+ enabled: bool
diff --git a/src/mobilerun_sdk/types/file_update_response.py b/src/mobilerun_sdk/types/file_update_response.py
new file mode 100644
index 00000000..a3903256
--- /dev/null
+++ b/src/mobilerun_sdk/types/file_update_response.py
@@ -0,0 +1,31 @@
+# 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__ = ["FileUpdateResponse"]
+
+
+class FileUpdateResponse(BaseModel):
+ created_at: datetime = FieldInfo(alias="createdAt")
+
+ created_by: Literal["user", "agent", "workflow"] = FieldInfo(alias="createdBy")
+
+ display_name: Optional[str] = FieldInfo(alias="displayName", default=None)
+
+ enabled: bool
+
+ file_id: str = FieldInfo(alias="fileId")
+
+ filename: str
+
+ mime_type: str = FieldInfo(alias="mimeType")
+
+ size_bytes: float = FieldInfo(alias="sizeBytes")
+
+ zone: Literal["user", "agent", "workflow", "skills"]
diff --git a/src/mobilerun_sdk/types/file_upload_url_params.py b/src/mobilerun_sdk/types/file_upload_url_params.py
new file mode 100644
index 00000000..98c7f0c0
--- /dev/null
+++ b/src/mobilerun_sdk/types/file_upload_url_params.py
@@ -0,0 +1,21 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing_extensions import Literal, Required, Annotated, TypedDict
+
+from .._utils import PropertyInfo
+
+__all__ = ["FileUploadURLParams"]
+
+
+class FileUploadURLParams(TypedDict, total=False):
+ filename: Required[str]
+
+ mime_type: Required[Annotated[str, PropertyInfo(alias="mimeType")]]
+
+ size_bytes: Required[Annotated[int, PropertyInfo(alias="sizeBytes")]]
+
+ zone: Literal["user", "skills"]
+
+ idempotency_key: Annotated[str, PropertyInfo(alias="Idempotency-Key")]
diff --git a/src/mobilerun_sdk/types/file_upload_url_response.py b/src/mobilerun_sdk/types/file_upload_url_response.py
new file mode 100644
index 00000000..d376779a
--- /dev/null
+++ b/src/mobilerun_sdk/types/file_upload_url_response.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from datetime import datetime
+
+from pydantic import Field as FieldInfo
+
+from .._models import BaseModel
+
+__all__ = ["FileUploadURLResponse"]
+
+
+class FileUploadURLResponse(BaseModel):
+ expires_at: datetime = FieldInfo(alias="expiresAt")
+
+ file_id: str = FieldInfo(alias="fileId")
+
+ put_url: str = FieldInfo(alias="putUrl")
diff --git a/src/mobilerun_sdk/types/message_list_response.py b/src/mobilerun_sdk/types/message_list_response.py
index aaaa20b6..9bce1d48 100644
--- a/src/mobilerun_sdk/types/message_list_response.py
+++ b/src/mobilerun_sdk/types/message_list_response.py
@@ -9,10 +9,10 @@
from .._models import BaseModel
from .shared.pagination import Pagination
-__all__ = ["MessageListResponse", "Data", "DataItem"]
+__all__ = ["MessageListResponse", "Item"]
-class DataItem(BaseModel):
+class Item(BaseModel):
id: str
body: Optional[str] = None
@@ -38,11 +38,7 @@ class DataItem(BaseModel):
status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"]
-class Data(BaseModel):
- items: List[DataItem]
+class MessageListResponse(BaseModel):
+ items: List[Item]
pagination: Pagination
-
-
-class MessageListResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/messages/conversation_list_response.py b/src/mobilerun_sdk/types/messages/conversation_list_response.py
index da1e4585..6e3e622e 100644
--- a/src/mobilerun_sdk/types/messages/conversation_list_response.py
+++ b/src/mobilerun_sdk/types/messages/conversation_list_response.py
@@ -8,10 +8,10 @@
from ..._models import BaseModel
-__all__ = ["ConversationListResponse", "Data", "DataItem", "DataItemLastMessage", "DataNextCursor"]
+__all__ = ["ConversationListResponse", "Item", "ItemLastMessage", "NextCursor"]
-class DataItemLastMessage(BaseModel):
+class ItemLastMessage(BaseModel):
id: str
body: Optional[str] = None
@@ -23,27 +23,23 @@ class DataItemLastMessage(BaseModel):
status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"]
-class DataItem(BaseModel):
+class Item(BaseModel):
esim_ids: List[str] = FieldInfo(alias="esimIds")
- last_message: DataItemLastMessage = FieldInfo(alias="lastMessage")
+ last_message: ItemLastMessage = FieldInfo(alias="lastMessage")
peer_key: str = FieldInfo(alias="peerKey")
unread_count: int = FieldInfo(alias="unreadCount")
-class DataNextCursor(BaseModel):
+class NextCursor(BaseModel):
last_message_id: str = FieldInfo(alias="lastMessageId")
last_occurred_at: datetime = FieldInfo(alias="lastOccurredAt")
-class Data(BaseModel):
- items: List[DataItem]
-
- next_cursor: Optional[DataNextCursor] = FieldInfo(alias="nextCursor", default=None)
-
-
class ConversationListResponse(BaseModel):
- data: Data
+ items: List[Item]
+
+ next_cursor: Optional[NextCursor] = FieldInfo(alias="nextCursor", default=None)
diff --git a/src/mobilerun_sdk/types/model_list_response.py b/src/mobilerun_sdk/types/model_list_response.py
index 81d802a5..8a1931c6 100644
--- a/src/mobilerun_sdk/types/model_list_response.py
+++ b/src/mobilerun_sdk/types/model_list_response.py
@@ -8,17 +8,22 @@
class Data(BaseModel):
- id: Optional[str] = None
+ id: str
+ """Model identifier"""
- created: Optional[float] = None
+ owned_by: str
+ """Model owner/provider"""
- object: Optional[str] = None
+ created: Optional[int] = None
+ """Creation timestamp"""
- owned_by: Optional[str] = None
+ object: Optional[str] = None
+ """Object type"""
class ModelListResponse(BaseModel):
- data: Optional[List[Data]] = None
+ data: List[Data]
+ """Available models"""
object: Optional[str] = None
- """Always "list" for list responses"""
+ """Object type"""
diff --git a/src/mobilerun_sdk/types/number_create_params.py b/src/mobilerun_sdk/types/number_create_params.py
index 5083087f..6098fc62 100644
--- a/src/mobilerun_sdk/types/number_create_params.py
+++ b/src/mobilerun_sdk/types/number_create_params.py
@@ -2,6 +2,7 @@
from __future__ import annotations
+from typing import Optional
from typing_extensions import Literal, Annotated, TypedDict
from .._utils import PropertyInfo
@@ -22,6 +23,13 @@ class NumberCreateParams(TypedDict, total=False):
Cannot be combined with `purpose`.
"""
+ label: Optional[str]
+ """
+ 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: str
"""Optional Mobilerun Phone purpose slug from GET /numbers/purposes."""
diff --git a/src/mobilerun_sdk/types/number_delete_response.py b/src/mobilerun_sdk/types/number_delete_response.py
index 4049d3d8..4e9351eb 100644
--- a/src/mobilerun_sdk/types/number_delete_response.py
+++ b/src/mobilerun_sdk/types/number_delete_response.py
@@ -30,6 +30,8 @@ class Data(BaseModel):
current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
+ label: Optional[str] = None
+
phone_number: Optional[str] = FieldInfo(alias="phoneNumber", default=None)
purpose: Optional[str] = None
diff --git a/src/mobilerun_sdk/types/number_list_response.py b/src/mobilerun_sdk/types/number_list_response.py
index 2ada07db..59a3eccd 100644
--- a/src/mobilerun_sdk/types/number_list_response.py
+++ b/src/mobilerun_sdk/types/number_list_response.py
@@ -9,10 +9,10 @@
from .._models import BaseModel
from .shared.pagination import Pagination
-__all__ = ["NumberListResponse", "Data", "DataItem"]
+__all__ = ["NumberListResponse", "Item"]
-class DataItem(BaseModel):
+class Item(BaseModel):
id: str
cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd")
@@ -31,6 +31,8 @@ class DataItem(BaseModel):
current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
+ label: Optional[str] = None
+
phone_number: Optional[str] = FieldInfo(alias="phoneNumber", default=None)
purpose: Optional[str] = None
@@ -40,11 +42,7 @@ class DataItem(BaseModel):
updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
-class Data(BaseModel):
- items: List[DataItem]
+class NumberListResponse(BaseModel):
+ items: List[Item]
pagination: Pagination
-
-
-class NumberListResponse(BaseModel):
- data: Data
diff --git a/src/mobilerun_sdk/types/number_retrieve_response.py b/src/mobilerun_sdk/types/number_retrieve_response.py
index 70a88c99..dcd5843f 100644
--- a/src/mobilerun_sdk/types/number_retrieve_response.py
+++ b/src/mobilerun_sdk/types/number_retrieve_response.py
@@ -30,6 +30,8 @@ class Data(BaseModel):
current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
+ label: Optional[str] = None
+
phone_number: Optional[str] = FieldInfo(alias="phoneNumber", default=None)
purpose: Optional[str] = None
diff --git a/src/mobilerun_sdk/types/number_update_params.py b/src/mobilerun_sdk/types/number_update_params.py
new file mode 100644
index 00000000..0c4372ba
--- /dev/null
+++ b/src/mobilerun_sdk/types/number_update_params.py
@@ -0,0 +1,17 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+from __future__ import annotations
+
+from typing import Optional
+from typing_extensions import TypedDict
+
+__all__ = ["NumberUpdateParams"]
+
+
+class NumberUpdateParams(TypedDict, total=False):
+ label: Optional[str]
+ """
+ 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.
+ """
diff --git a/src/mobilerun_sdk/types/number_update_response.py b/src/mobilerun_sdk/types/number_update_response.py
new file mode 100644
index 00000000..e6166cb1
--- /dev/null
+++ b/src/mobilerun_sdk/types/number_update_response.py
@@ -0,0 +1,45 @@
+# 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
+
+__all__ = ["NumberUpdateResponse", "Data"]
+
+
+class Data(BaseModel):
+ id: str
+
+ cancel_at_period_end: bool = FieldInfo(alias="cancelAtPeriodEnd")
+
+ cancellable: bool
+
+ can_send: bool = FieldInfo(alias="canSend")
+
+ capabilities: Optional[List[Literal["sms", "voice"]]] = None
+
+ checkout_url: Optional[str] = FieldInfo(alias="checkoutUrl", default=None)
+
+ country_code: Optional[str] = FieldInfo(alias="countryCode", default=None)
+
+ created_at: Optional[datetime] = FieldInfo(alias="createdAt", default=None)
+
+ current_period_end: Optional[datetime] = FieldInfo(alias="currentPeriodEnd", default=None)
+
+ label: Optional[str] = None
+
+ phone_number: Optional[str] = FieldInfo(alias="phoneNumber", default=None)
+
+ purpose: Optional[str] = None
+
+ state: Literal["awaiting_payment", "provisioning", "active", "cancel_scheduled", "expired", "failed"]
+
+ updated_at: Optional[datetime] = FieldInfo(alias="updatedAt", default=None)
+
+
+class NumberUpdateResponse(BaseModel):
+ data: Data
diff --git a/src/mobilerun_sdk/types/numbers/message_list_response.py b/src/mobilerun_sdk/types/numbers/message_list_response.py
index 3d9b3c3d..62ad7986 100644
--- a/src/mobilerun_sdk/types/numbers/message_list_response.py
+++ b/src/mobilerun_sdk/types/numbers/message_list_response.py
@@ -7,11 +7,12 @@
from pydantic import Field as FieldInfo
from ..._models import BaseModel
+from ..shared.pagination import Pagination
-__all__ = ["MessageListResponse", "Data", "DataItem", "DataPagination"]
+__all__ = ["MessageListResponse", "Item"]
-class DataItem(BaseModel):
+class Item(BaseModel):
id: str
body: Optional[str] = None
@@ -35,25 +36,7 @@ class DataItem(BaseModel):
status: Literal["received", "queued", "claimed", "sending", "sent", "sent_unconfirmed", "delivered", "failed"]
-class DataPagination(BaseModel):
- has_next: bool = FieldInfo(alias="hasNext")
-
- has_prev: bool = FieldInfo(alias="hasPrev")
-
- page: int
-
- pages: int
-
- page_size: int = FieldInfo(alias="pageSize")
-
- total: int
-
-
-class Data(BaseModel):
- items: List[DataItem]
-
- pagination: DataPagination
-
-
class MessageListResponse(BaseModel):
- data: Data
+ items: List[Item]
+
+ pagination: Pagination
diff --git a/src/mobilerun_sdk/types/store/app_list_response.py b/src/mobilerun_sdk/types/store/app_list_response.py
index 7ee43700..c8dce76d 100644
--- a/src/mobilerun_sdk/types/store/app_list_response.py
+++ b/src/mobilerun_sdk/types/store/app_list_response.py
@@ -282,7 +282,7 @@ class ItemVersion(BaseModel):
size_bytes: Optional[int] = FieldInfo(alias="sizeBytes", default=None)
- source: Literal["user", "system", "portal", "store"]
+ source: Literal["user", "system", "portal", "store", "catalog"]
status: Literal["queued", "available", "failed"]
diff --git a/src/mobilerun_sdk/types/store/app_retrieve_response.py b/src/mobilerun_sdk/types/store/app_retrieve_response.py
index a8cff78c..c9461110 100644
--- a/src/mobilerun_sdk/types/store/app_retrieve_response.py
+++ b/src/mobilerun_sdk/types/store/app_retrieve_response.py
@@ -281,7 +281,7 @@ class DataVersion(BaseModel):
size_bytes: Optional[int] = FieldInfo(alias="sizeBytes", default=None)
- source: Literal["user", "system", "portal", "store"]
+ source: Literal["user", "system", "portal", "store", "catalog"]
status: Literal["queued", "available", "failed"]
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 c3509640..b04779e3 100644
--- a/src/mobilerun_sdk/types/workflows/event_dry_run_response.py
+++ b/src/mobilerun_sdk/types/workflows/event_dry_run_response.py
@@ -79,6 +79,8 @@ class DataMatchedFlowFlow(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts")
diff --git a/src/mobilerun_sdk/types/workflows/execution_abort_response.py b/src/mobilerun_sdk/types/workflows/execution_abort_response.py
index 853122f0..0d9468bf 100644
--- a/src/mobilerun_sdk/types/workflows/execution_abort_response.py
+++ b/src/mobilerun_sdk/types/workflows/execution_abort_response.py
@@ -25,6 +25,15 @@ class Data(BaseModel):
kind: Literal["live", "dry_run"]
+ recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None)
+
+ recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None)
+ """
+ Device-recording id (devices-api) for this execution, set once the worker starts
+ a recording. Null when the flow has recording disabled, no device is bound, or
+ the recording failed to start.
+ """
+
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_list_response.py b/src/mobilerun_sdk/types/workflows/execution_list_response.py
index 93c5a45c..b7c4993f 100644
--- a/src/mobilerun_sdk/types/workflows/execution_list_response.py
+++ b/src/mobilerun_sdk/types/workflows/execution_list_response.py
@@ -28,6 +28,15 @@ class Item(BaseModel):
kind: Literal["live", "dry_run"]
+ recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None)
+
+ recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None)
+ """
+ Device-recording id (devices-api) for this execution, set once the worker starts
+ a recording. Null when the flow has recording disabled, no device is bound, or
+ the recording failed to start.
+ """
+
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 d67a8f4f..de6c2d19 100644
--- a/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py
+++ b/src/mobilerun_sdk/types/workflows/execution_retrieve_response.py
@@ -44,6 +44,15 @@ class Data(BaseModel):
kind: Literal["live", "dry_run"]
+ recording_device_id: Optional[str] = FieldInfo(alias="recordingDeviceId", default=None)
+
+ recording_id: Optional[str] = FieldInfo(alias="recordingId", default=None)
+ """
+ Device-recording id (devices-api) for this execution, set once the worker starts
+ a recording. Null when the flow has recording disabled, no device is bound, or
+ the recording failed to start.
+ """
+
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 0688cdc4..14ed8d1f 100644
--- a/src/mobilerun_sdk/types/workflows/flow_clone_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_clone_response.py
@@ -51,6 +51,8 @@ class Data(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts")
diff --git a/src/mobilerun_sdk/types/workflows/flow_create_params.py b/src/mobilerun_sdk/types/workflows/flow_create_params.py
index 002ee9d7..cde7b202 100644
--- a/src/mobilerun_sdk/types/workflows/flow_create_params.py
+++ b/src/mobilerun_sdk/types/workflows/flow_create_params.py
@@ -36,6 +36,8 @@ class FlowCreateParams(TypedDict, total=False):
notify_webhook_id: Annotated[Optional[str], PropertyInfo(alias="notifyWebhookId")]
+ recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
+
self_healing_enabled: Annotated[bool, PropertyInfo(alias="selfHealingEnabled")]
self_healing_max_attempts: Annotated[int, PropertyInfo(alias="selfHealingMaxAttempts")]
diff --git a/src/mobilerun_sdk/types/workflows/flow_create_response.py b/src/mobilerun_sdk/types/workflows/flow_create_response.py
index d35319d3..a840cf45 100644
--- a/src/mobilerun_sdk/types/workflows/flow_create_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_create_response.py
@@ -51,6 +51,8 @@ class Data(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts")
diff --git a/src/mobilerun_sdk/types/workflows/flow_list_response.py b/src/mobilerun_sdk/types/workflows/flow_list_response.py
index 36819ffe..5cd546ab 100644
--- a/src/mobilerun_sdk/types/workflows/flow_list_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_list_response.py
@@ -52,6 +52,8 @@ class Item(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts")
diff --git a/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py b/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py
index 3c017332..dab4caa9 100644
--- a/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_retrieve_response.py
@@ -51,6 +51,8 @@ class Data(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts")
diff --git a/src/mobilerun_sdk/types/workflows/flow_unblock_response.py b/src/mobilerun_sdk/types/workflows/flow_unblock_response.py
index f36de0cd..0429bba4 100644
--- a/src/mobilerun_sdk/types/workflows/flow_unblock_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_unblock_response.py
@@ -51,6 +51,8 @@ class Data(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts")
diff --git a/src/mobilerun_sdk/types/workflows/flow_update_params.py b/src/mobilerun_sdk/types/workflows/flow_update_params.py
index d7f9e64a..8db31b2e 100644
--- a/src/mobilerun_sdk/types/workflows/flow_update_params.py
+++ b/src/mobilerun_sdk/types/workflows/flow_update_params.py
@@ -32,6 +32,8 @@ class FlowUpdateParams(TypedDict, total=False):
notify_webhook_id: Annotated[Optional[str], PropertyInfo(alias="notifyWebhookId")]
+ recording_enabled: Annotated[bool, PropertyInfo(alias="recordingEnabled")]
+
self_healing_enabled: Annotated[bool, PropertyInfo(alias="selfHealingEnabled")]
self_healing_max_attempts: Annotated[int, PropertyInfo(alias="selfHealingMaxAttempts")]
diff --git a/src/mobilerun_sdk/types/workflows/flow_update_response.py b/src/mobilerun_sdk/types/workflows/flow_update_response.py
index b33c1b3e..ad10348f 100644
--- a/src/mobilerun_sdk/types/workflows/flow_update_response.py
+++ b/src/mobilerun_sdk/types/workflows/flow_update_response.py
@@ -51,6 +51,8 @@ class Data(BaseModel):
owner_id: str = FieldInfo(alias="ownerId")
+ recording_enabled: bool = FieldInfo(alias="recordingEnabled")
+
self_healing_enabled: bool = FieldInfo(alias="selfHealingEnabled")
self_healing_max_attempts: int = FieldInfo(alias="selfHealingMaxAttempts")
diff --git a/tests/api_resources/assistant/__init__.py b/tests/api_resources/assistant/__init__.py
new file mode 100644
index 00000000..fd8019a9
--- /dev/null
+++ b/tests/api_resources/assistant/__init__.py
@@ -0,0 +1 @@
+# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
diff --git a/tests/api_resources/assistant/test_conversations.py b/tests/api_resources/assistant/test_conversations.py
new file mode 100644
index 00000000..32ef5823
--- /dev/null
+++ b/tests/api_resources/assistant/test_conversations.py
@@ -0,0 +1,838 @@
+# 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.assistant import (
+ ConversationListResponse,
+ ConversationSendResponse,
+ ConversationAbortResponse,
+ ConversationCreateResponse,
+ ConversationUpdateResponse,
+ ConversationHistoryResponse,
+ ConversationAnswerQuestionResponse,
+ ConversationRejectQuestionResponse,
+ ConversationAnswerPermissionResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestConversations:
+ 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:
+ conversation = client.assistant.conversations.create(
+ title="x",
+ )
+ assert_matches_type(ConversationCreateResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_create_with_all_params(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.create(
+ title="x",
+ agent="x",
+ description="description",
+ idempotency_key="Idempotency-Key",
+ )
+ assert_matches_type(ConversationCreateResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_create(self, client: Mobilerun) -> None:
+ response = client.assistant.conversations.with_raw_response.create(
+ title="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = response.parse()
+ assert_matches_type(ConversationCreateResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_create(self, client: Mobilerun) -> None:
+ with client.assistant.conversations.with_streaming_response.create(
+ title="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = response.parse()
+ assert_matches_type(ConversationCreateResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ConversationUpdateResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update_with_all_params(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ description="description",
+ pinned=True,
+ status="active",
+ title="x",
+ )
+ assert_matches_type(ConversationUpdateResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_update(self, client: Mobilerun) -> None:
+ response = client.assistant.conversations.with_raw_response.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = response.parse()
+ assert_matches_type(ConversationUpdateResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_update(self, client: Mobilerun) -> None:
+ with client.assistant.conversations.with_streaming_response.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = response.parse()
+ assert_matches_type(ConversationUpdateResponse, conversation, 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.assistant.conversations.with_raw_response.update(
+ id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.list()
+ assert_matches_type(ConversationListResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.list(
+ kind="chat",
+ mine="true",
+ workflow_id="x",
+ )
+ assert_matches_type(ConversationListResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Mobilerun) -> None:
+ response = client.assistant.conversations.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = response.parse()
+ assert_matches_type(ConversationListResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Mobilerun) -> None:
+ with client.assistant.conversations.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = response.parse()
+ assert_matches_type(ConversationListResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_abort(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.abort(
+ session_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:
+ response = client.assistant.conversations.with_raw_response.abort(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = response.parse()
+ assert_matches_type(ConversationAbortResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_abort(self, client: Mobilerun) -> None:
+ with client.assistant.conversations.with_streaming_response.abort(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = response.parse()
+ assert_matches_type(ConversationAbortResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_answer_permission(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.answer_permission(
+ permission_id="x",
+ response="once",
+ )
+ assert_matches_type(ConversationAnswerPermissionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_answer_permission(self, client: Mobilerun) -> None:
+ response = client.assistant.conversations.with_raw_response.answer_permission(
+ permission_id="x",
+ response="once",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = response.parse()
+ assert_matches_type(ConversationAnswerPermissionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_answer_permission(self, client: Mobilerun) -> None:
+ with client.assistant.conversations.with_streaming_response.answer_permission(
+ permission_id="x",
+ response="once",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = response.parse()
+ assert_matches_type(ConversationAnswerPermissionResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_answer_question(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.answer_question(
+ answers=[[{"label": "x"}]],
+ question_id="x",
+ )
+ assert_matches_type(ConversationAnswerQuestionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_answer_question(self, client: Mobilerun) -> None:
+ response = client.assistant.conversations.with_raw_response.answer_question(
+ answers=[[{"label": "x"}]],
+ question_id="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = response.parse()
+ assert_matches_type(ConversationAnswerQuestionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_answer_question(self, client: Mobilerun) -> None:
+ with client.assistant.conversations.with_streaming_response.answer_question(
+ answers=[[{"label": "x"}]],
+ question_id="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = response.parse()
+ assert_matches_type(ConversationAnswerQuestionResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_history(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.history(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ConversationHistoryResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_history_with_all_params(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.history(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ limit=1,
+ )
+ assert_matches_type(ConversationHistoryResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_history(self, client: Mobilerun) -> None:
+ response = client.assistant.conversations.with_raw_response.history(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = response.parse()
+ assert_matches_type(ConversationHistoryResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_history(self, client: Mobilerun) -> None:
+ with client.assistant.conversations.with_streaming_response.history(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = response.parse()
+ assert_matches_type(ConversationHistoryResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_reject_question(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.reject_question(
+ question_id="x",
+ )
+ assert_matches_type(ConversationRejectQuestionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_reject_question(self, client: Mobilerun) -> None:
+ response = client.assistant.conversations.with_raw_response.reject_question(
+ question_id="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = response.parse()
+ assert_matches_type(ConversationRejectQuestionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_reject_question(self, client: Mobilerun) -> None:
+ with client.assistant.conversations.with_streaming_response.reject_question(
+ question_id="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = response.parse()
+ assert_matches_type(ConversationRejectQuestionResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_send(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.send(
+ message="x",
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ConversationSendResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_send_with_all_params(self, client: Mobilerun) -> None:
+ conversation = client.assistant.conversations.send(
+ message="x",
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ agent="agent",
+ )
+ assert_matches_type(ConversationSendResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_send(self, client: Mobilerun) -> None:
+ response = client.assistant.conversations.with_raw_response.send(
+ message="x",
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = response.parse()
+ assert_matches_type(ConversationSendResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_send(self, client: Mobilerun) -> None:
+ with client.assistant.conversations.with_streaming_response.send(
+ message="x",
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = response.parse()
+ assert_matches_type(ConversationSendResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_stream(self, client: Mobilerun) -> None:
+ conversation_stream = client.assistant.conversations.stream(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ conversation_stream.response.close()
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_stream(self, client: Mobilerun) -> None:
+ response = client.assistant.conversations.with_raw_response.stream(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ stream = response.parse()
+ stream.close()
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_stream(self, client: Mobilerun) -> None:
+ with client.assistant.conversations.with_streaming_response.stream(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ stream = response.parse()
+ stream.close()
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncConversations:
+ 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:
+ conversation = await async_client.assistant.conversations.create(
+ title="x",
+ )
+ assert_matches_type(ConversationCreateResponse, conversation, 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:
+ conversation = await async_client.assistant.conversations.create(
+ title="x",
+ agent="x",
+ description="description",
+ idempotency_key="Idempotency-Key",
+ )
+ assert_matches_type(ConversationCreateResponse, conversation, 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.assistant.conversations.with_raw_response.create(
+ title="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = await response.parse()
+ assert_matches_type(ConversationCreateResponse, conversation, 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.assistant.conversations.with_streaming_response.create(
+ title="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = await response.parse()
+ assert_matches_type(ConversationCreateResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_update(self, async_client: AsyncMobilerun) -> None:
+ conversation = await async_client.assistant.conversations.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ConversationUpdateResponse, conversation, 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:
+ conversation = await async_client.assistant.conversations.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ description="description",
+ pinned=True,
+ status="active",
+ title="x",
+ )
+ assert_matches_type(ConversationUpdateResponse, conversation, 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.assistant.conversations.with_raw_response.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = await response.parse()
+ assert_matches_type(ConversationUpdateResponse, conversation, 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.assistant.conversations.with_streaming_response.update(
+ id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = await response.parse()
+ assert_matches_type(ConversationUpdateResponse, conversation, 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.assistant.conversations.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:
+ conversation = await async_client.assistant.conversations.list()
+ assert_matches_type(ConversationListResponse, conversation, 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:
+ conversation = await async_client.assistant.conversations.list(
+ kind="chat",
+ mine="true",
+ workflow_id="x",
+ )
+ assert_matches_type(ConversationListResponse, conversation, 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.assistant.conversations.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = await response.parse()
+ assert_matches_type(ConversationListResponse, conversation, 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.assistant.conversations.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = await response.parse()
+ assert_matches_type(ConversationListResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_abort(self, async_client: AsyncMobilerun) -> None:
+ conversation = await async_client.assistant.conversations.abort(
+ session_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:
+ response = await async_client.assistant.conversations.with_raw_response.abort(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = await response.parse()
+ assert_matches_type(ConversationAbortResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_abort(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.assistant.conversations.with_streaming_response.abort(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = await response.parse()
+ assert_matches_type(ConversationAbortResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_answer_permission(self, async_client: AsyncMobilerun) -> None:
+ conversation = await async_client.assistant.conversations.answer_permission(
+ permission_id="x",
+ response="once",
+ )
+ assert_matches_type(ConversationAnswerPermissionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_answer_permission(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.assistant.conversations.with_raw_response.answer_permission(
+ permission_id="x",
+ response="once",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = await response.parse()
+ assert_matches_type(ConversationAnswerPermissionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_answer_permission(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.assistant.conversations.with_streaming_response.answer_permission(
+ permission_id="x",
+ response="once",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = await response.parse()
+ assert_matches_type(ConversationAnswerPermissionResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_answer_question(self, async_client: AsyncMobilerun) -> None:
+ conversation = await async_client.assistant.conversations.answer_question(
+ answers=[[{"label": "x"}]],
+ question_id="x",
+ )
+ assert_matches_type(ConversationAnswerQuestionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_answer_question(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.assistant.conversations.with_raw_response.answer_question(
+ answers=[[{"label": "x"}]],
+ question_id="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = await response.parse()
+ assert_matches_type(ConversationAnswerQuestionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_answer_question(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.assistant.conversations.with_streaming_response.answer_question(
+ answers=[[{"label": "x"}]],
+ question_id="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = await response.parse()
+ assert_matches_type(ConversationAnswerQuestionResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_history(self, async_client: AsyncMobilerun) -> None:
+ conversation = await async_client.assistant.conversations.history(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ConversationHistoryResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_history_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ conversation = await async_client.assistant.conversations.history(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ limit=1,
+ )
+ assert_matches_type(ConversationHistoryResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_history(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.assistant.conversations.with_raw_response.history(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = await response.parse()
+ assert_matches_type(ConversationHistoryResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_history(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.assistant.conversations.with_streaming_response.history(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = await response.parse()
+ assert_matches_type(ConversationHistoryResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_reject_question(self, async_client: AsyncMobilerun) -> None:
+ conversation = await async_client.assistant.conversations.reject_question(
+ question_id="x",
+ )
+ assert_matches_type(ConversationRejectQuestionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_reject_question(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.assistant.conversations.with_raw_response.reject_question(
+ question_id="x",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = await response.parse()
+ assert_matches_type(ConversationRejectQuestionResponse, conversation, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_reject_question(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.assistant.conversations.with_streaming_response.reject_question(
+ question_id="x",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = await response.parse()
+ assert_matches_type(ConversationRejectQuestionResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_send(self, async_client: AsyncMobilerun) -> None:
+ conversation = await async_client.assistant.conversations.send(
+ message="x",
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(ConversationSendResponse, conversation, 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:
+ conversation = await async_client.assistant.conversations.send(
+ message="x",
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ agent="agent",
+ )
+ assert_matches_type(ConversationSendResponse, conversation, 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.assistant.conversations.with_raw_response.send(
+ message="x",
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ conversation = await response.parse()
+ assert_matches_type(ConversationSendResponse, conversation, 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.assistant.conversations.with_streaming_response.send(
+ message="x",
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ conversation = await response.parse()
+ assert_matches_type(ConversationSendResponse, conversation, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_stream(self, async_client: AsyncMobilerun) -> None:
+ conversation_stream = await async_client.assistant.conversations.stream(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ await conversation_stream.response.aclose()
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_stream(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.assistant.conversations.with_raw_response.stream(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ stream = await response.parse()
+ await stream.close()
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_stream(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.assistant.conversations.with_streaming_response.stream(
+ session_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ stream = await response.parse()
+ await stream.close()
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/devices/test_clipboard.py b/tests/api_resources/devices/test_clipboard.py
new file mode 100644
index 00000000..aef973ba
--- /dev/null
+++ b/tests/api_resources/devices/test_clipboard.py
@@ -0,0 +1,238 @@
+# 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.devices import ClipboardGetResponse
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestClipboard:
+ 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_get(self, client: Mobilerun) -> None:
+ clipboard = client.devices.clipboard.get(
+ device_id="deviceId",
+ )
+ assert_matches_type(ClipboardGetResponse, clipboard, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_get_with_all_params(self, client: Mobilerun) -> None:
+ clipboard = client.devices.clipboard.get(
+ device_id="deviceId",
+ x_device_display_id=0,
+ )
+ assert_matches_type(ClipboardGetResponse, clipboard, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_get(self, client: Mobilerun) -> None:
+ response = client.devices.clipboard.with_raw_response.get(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ clipboard = response.parse()
+ assert_matches_type(ClipboardGetResponse, clipboard, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_get(self, client: Mobilerun) -> None:
+ with client.devices.clipboard.with_streaming_response.get(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ clipboard = response.parse()
+ assert_matches_type(ClipboardGetResponse, clipboard, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_path_params_get(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.clipboard.with_raw_response.get(
+ device_id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_set(self, client: Mobilerun) -> None:
+ clipboard = client.devices.clipboard.set(
+ device_id="deviceId",
+ text="text",
+ )
+ assert clipboard is None
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_set_with_all_params(self, client: Mobilerun) -> None:
+ clipboard = client.devices.clipboard.set(
+ device_id="deviceId",
+ text="text",
+ x_device_display_id=0,
+ )
+ assert clipboard is None
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_set(self, client: Mobilerun) -> None:
+ response = client.devices.clipboard.with_raw_response.set(
+ device_id="deviceId",
+ text="text",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ clipboard = response.parse()
+ assert clipboard is None
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_set(self, client: Mobilerun) -> None:
+ with client.devices.clipboard.with_streaming_response.set(
+ device_id="deviceId",
+ text="text",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ clipboard = response.parse()
+ assert clipboard is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_path_params_set(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ client.devices.clipboard.with_raw_response.set(
+ device_id="",
+ text="text",
+ )
+
+
+class TestAsyncClipboard:
+ 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_get(self, async_client: AsyncMobilerun) -> None:
+ clipboard = await async_client.devices.clipboard.get(
+ device_id="deviceId",
+ )
+ assert_matches_type(ClipboardGetResponse, clipboard, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_get_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ clipboard = await async_client.devices.clipboard.get(
+ device_id="deviceId",
+ x_device_display_id=0,
+ )
+ assert_matches_type(ClipboardGetResponse, clipboard, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_get(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.clipboard.with_raw_response.get(
+ device_id="deviceId",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ clipboard = await response.parse()
+ assert_matches_type(ClipboardGetResponse, clipboard, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_get(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.clipboard.with_streaming_response.get(
+ device_id="deviceId",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ clipboard = await response.parse()
+ assert_matches_type(ClipboardGetResponse, clipboard, 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_get(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.clipboard.with_raw_response.get(
+ device_id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_set(self, async_client: AsyncMobilerun) -> None:
+ clipboard = await async_client.devices.clipboard.set(
+ device_id="deviceId",
+ text="text",
+ )
+ assert clipboard is None
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_set_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ clipboard = await async_client.devices.clipboard.set(
+ device_id="deviceId",
+ text="text",
+ x_device_display_id=0,
+ )
+ assert clipboard is None
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_set(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.devices.clipboard.with_raw_response.set(
+ device_id="deviceId",
+ text="text",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ clipboard = await response.parse()
+ assert clipboard is None
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_set(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.devices.clipboard.with_streaming_response.set(
+ device_id="deviceId",
+ text="text",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ clipboard = await response.parse()
+ assert clipboard 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_set(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `device_id` but received ''"):
+ await async_client.devices.clipboard.with_raw_response.set(
+ device_id="",
+ text="text",
+ )
diff --git a/tests/api_resources/test_agents.py b/tests/api_resources/test_agents.py
deleted file mode 100644
index 8087dead..00000000
--- a/tests/api_resources/test_agents.py
+++ /dev/null
@@ -1,80 +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 AgentListResponse
-
-base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
-
-
-class TestAgents:
- 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:
- agent = client.agents.list()
- assert_matches_type(AgentListResponse, agent, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_raw_response_list(self, client: Mobilerun) -> None:
- response = client.agents.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- agent = response.parse()
- assert_matches_type(AgentListResponse, agent, path=["response"])
-
- @pytest.mark.skip(reason="Mock server tests are disabled")
- @parametrize
- def test_streaming_response_list(self, client: Mobilerun) -> None:
- with client.agents.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- agent = response.parse()
- assert_matches_type(AgentListResponse, agent, path=["response"])
-
- assert cast(Any, response.is_closed) is True
-
-
-class TestAsyncAgents:
- 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:
- agent = await async_client.agents.list()
- assert_matches_type(AgentListResponse, agent, 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.agents.with_raw_response.list()
-
- assert response.is_closed is True
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
- agent = await response.parse()
- assert_matches_type(AgentListResponse, agent, 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.agents.with_streaming_response.list() as response:
- assert not response.is_closed
- assert response.http_request.headers.get("X-Stainless-Lang") == "python"
-
- agent = await response.parse()
- assert_matches_type(AgentListResponse, agent, path=["response"])
-
- assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_esims.py b/tests/api_resources/test_esims.py
index 4040193e..a47275d3 100644
--- a/tests/api_resources/test_esims.py
+++ b/tests/api_resources/test_esims.py
@@ -39,6 +39,7 @@ def test_method_create(self, client: Mobilerun) -> None:
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"])
@@ -455,6 +456,15 @@ 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:
@@ -494,6 +504,7 @@ async def test_method_create(self, async_client: AsyncMobilerun) -> None:
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"])
@@ -910,6 +921,15 @@ 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:
diff --git a/tests/api_resources/test_files.py b/tests/api_resources/test_files.py
new file mode 100644
index 00000000..47decef9
--- /dev/null
+++ b/tests/api_resources/test_files.py
@@ -0,0 +1,647 @@
+# 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 (
+ FileListResponse,
+ FileDeleteResponse,
+ FileUpdateResponse,
+ FileConfirmResponse,
+ FileUploadURLResponse,
+ FileCancelPendingResponse,
+)
+
+base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
+
+
+class TestFiles:
+ 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_update(self, client: Mobilerun) -> None:
+ file = client.files.update(
+ file_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(FileUpdateResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update_with_all_params(self, client: Mobilerun) -> None:
+ file = client.files.update(
+ file_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ display_name="x",
+ enabled=True,
+ )
+ assert_matches_type(FileUpdateResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_update(self, client: Mobilerun) -> None:
+ response = client.files.with_raw_response.update(
+ file_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = response.parse()
+ assert_matches_type(FileUpdateResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_update(self, client: Mobilerun) -> None:
+ with client.files.with_streaming_response.update(
+ file_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = response.parse()
+ assert_matches_type(FileUpdateResponse, file, 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 `file_id` but received ''"):
+ client.files.with_raw_response.update(
+ file_id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list(self, client: Mobilerun) -> None:
+ file = client.files.list()
+ assert_matches_type(FileListResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_list_with_all_params(self, client: Mobilerun) -> None:
+ file = client.files.list(
+ zone="user",
+ )
+ assert_matches_type(FileListResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_list(self, client: Mobilerun) -> None:
+ response = client.files.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = response.parse()
+ assert_matches_type(FileListResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_list(self, client: Mobilerun) -> None:
+ with client.files.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = response.parse()
+ assert_matches_type(FileListResponse, file, 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:
+ file = client.files.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(FileDeleteResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_delete(self, client: Mobilerun) -> None:
+ response = client.files.with_raw_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = response.parse()
+ assert_matches_type(FileDeleteResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_delete(self, client: Mobilerun) -> None:
+ with client.files.with_streaming_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = response.parse()
+ assert_matches_type(FileDeleteResponse, file, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_path_params_delete(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"):
+ client.files.with_raw_response.delete(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_cancel_pending(self, client: Mobilerun) -> None:
+ file = client.files.cancel_pending(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(FileCancelPendingResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_cancel_pending(self, client: Mobilerun) -> None:
+ response = client.files.with_raw_response.cancel_pending(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = response.parse()
+ assert_matches_type(FileCancelPendingResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_cancel_pending(self, client: Mobilerun) -> None:
+ with client.files.with_streaming_response.cancel_pending(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = response.parse()
+ assert_matches_type(FileCancelPendingResponse, file, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_path_params_cancel_pending(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"):
+ client.files.with_raw_response.cancel_pending(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_confirm(self, client: Mobilerun) -> None:
+ file = client.files.confirm(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(FileConfirmResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_confirm(self, client: Mobilerun) -> None:
+ response = client.files.with_raw_response.confirm(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = response.parse()
+ assert_matches_type(FileConfirmResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_confirm(self, client: Mobilerun) -> None:
+ with client.files.with_streaming_response.confirm(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = response.parse()
+ assert_matches_type(FileConfirmResponse, file, 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(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"):
+ client.files.with_raw_response.confirm(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_download(self, client: Mobilerun) -> None:
+ file = client.files.download(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert file is None
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_download(self, client: Mobilerun) -> None:
+ response = client.files.with_raw_response.download(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = response.parse()
+ assert file is None
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_download(self, client: Mobilerun) -> None:
+ with client.files.with_streaming_response.download(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = response.parse()
+ assert file is None
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_path_params_download(self, client: Mobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"):
+ client.files.with_raw_response.download(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_upload_url(self, client: Mobilerun) -> None:
+ file = client.files.upload_url(
+ filename="x",
+ mime_type="x",
+ size_bytes=1,
+ )
+ assert_matches_type(FileUploadURLResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_upload_url_with_all_params(self, client: Mobilerun) -> None:
+ file = client.files.upload_url(
+ filename="x",
+ mime_type="x",
+ size_bytes=1,
+ zone="user",
+ idempotency_key="x",
+ )
+ assert_matches_type(FileUploadURLResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_upload_url(self, client: Mobilerun) -> None:
+ response = client.files.with_raw_response.upload_url(
+ filename="x",
+ mime_type="x",
+ size_bytes=1,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = response.parse()
+ assert_matches_type(FileUploadURLResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_upload_url(self, client: Mobilerun) -> None:
+ with client.files.with_streaming_response.upload_url(
+ filename="x",
+ mime_type="x",
+ size_bytes=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = response.parse()
+ assert_matches_type(FileUploadURLResponse, file, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+
+class TestAsyncFiles:
+ 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_update(self, async_client: AsyncMobilerun) -> None:
+ file = await async_client.files.update(
+ file_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(FileUpdateResponse, file, 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:
+ file = await async_client.files.update(
+ file_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ display_name="x",
+ enabled=True,
+ )
+ assert_matches_type(FileUpdateResponse, file, 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.files.with_raw_response.update(
+ file_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = await response.parse()
+ assert_matches_type(FileUpdateResponse, file, 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.files.with_streaming_response.update(
+ file_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = await response.parse()
+ assert_matches_type(FileUpdateResponse, file, 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 `file_id` but received ''"):
+ await async_client.files.with_raw_response.update(
+ file_id="",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_list(self, async_client: AsyncMobilerun) -> None:
+ file = await async_client.files.list()
+ assert_matches_type(FileListResponse, file, 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:
+ file = await async_client.files.list(
+ zone="user",
+ )
+ assert_matches_type(FileListResponse, file, 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.files.with_raw_response.list()
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = await response.parse()
+ assert_matches_type(FileListResponse, file, 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.files.with_streaming_response.list() as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = await response.parse()
+ assert_matches_type(FileListResponse, file, 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:
+ file = await async_client.files.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(FileDeleteResponse, file, path=["response"])
+
+ @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.files.with_raw_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = await response.parse()
+ assert_matches_type(FileDeleteResponse, file, path=["response"])
+
+ @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.files.with_streaming_response.delete(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = await response.parse()
+ assert_matches_type(FileDeleteResponse, file, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_path_params_delete(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"):
+ await async_client.files.with_raw_response.delete(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_cancel_pending(self, async_client: AsyncMobilerun) -> None:
+ file = await async_client.files.cancel_pending(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(FileCancelPendingResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_cancel_pending(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.files.with_raw_response.cancel_pending(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = await response.parse()
+ assert_matches_type(FileCancelPendingResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_cancel_pending(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.files.with_streaming_response.cancel_pending(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = await response.parse()
+ assert_matches_type(FileCancelPendingResponse, file, 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_cancel_pending(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"):
+ await async_client.files.with_raw_response.cancel_pending(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_confirm(self, async_client: AsyncMobilerun) -> None:
+ file = await async_client.files.confirm(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert_matches_type(FileConfirmResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_confirm(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.files.with_raw_response.confirm(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = await response.parse()
+ assert_matches_type(FileConfirmResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_confirm(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.files.with_streaming_response.confirm(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = await response.parse()
+ assert_matches_type(FileConfirmResponse, file, 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(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"):
+ await async_client.files.with_raw_response.confirm(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_download(self, async_client: AsyncMobilerun) -> None:
+ file = await async_client.files.download(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+ assert file is None
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_download(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.files.with_raw_response.download(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = await response.parse()
+ assert file is None
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_download(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.files.with_streaming_response.download(
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = await response.parse()
+ assert file 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_download(self, async_client: AsyncMobilerun) -> None:
+ with pytest.raises(ValueError, match=r"Expected a non-empty value for `file_id` but received ''"):
+ await async_client.files.with_raw_response.download(
+ "",
+ )
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_upload_url(self, async_client: AsyncMobilerun) -> None:
+ file = await async_client.files.upload_url(
+ filename="x",
+ mime_type="x",
+ size_bytes=1,
+ )
+ assert_matches_type(FileUploadURLResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_upload_url_with_all_params(self, async_client: AsyncMobilerun) -> None:
+ file = await async_client.files.upload_url(
+ filename="x",
+ mime_type="x",
+ size_bytes=1,
+ zone="user",
+ idempotency_key="x",
+ )
+ assert_matches_type(FileUploadURLResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_raw_response_upload_url(self, async_client: AsyncMobilerun) -> None:
+ response = await async_client.files.with_raw_response.upload_url(
+ filename="x",
+ mime_type="x",
+ size_bytes=1,
+ )
+
+ assert response.is_closed is True
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+ file = await response.parse()
+ assert_matches_type(FileUploadURLResponse, file, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_streaming_response_upload_url(self, async_client: AsyncMobilerun) -> None:
+ async with async_client.files.with_streaming_response.upload_url(
+ filename="x",
+ mime_type="x",
+ size_bytes=1,
+ ) as response:
+ assert not response.is_closed
+ assert response.http_request.headers.get("X-Stainless-Lang") == "python"
+
+ file = await response.parse()
+ assert_matches_type(FileUploadURLResponse, file, path=["response"])
+
+ assert cast(Any, response.is_closed) is True
diff --git a/tests/api_resources/test_numbers.py b/tests/api_resources/test_numbers.py
index bf4d09de..44193174 100644
--- a/tests/api_resources/test_numbers.py
+++ b/tests/api_resources/test_numbers.py
@@ -13,6 +13,7 @@
NumberListResponse,
NumberCreateResponse,
NumberDeleteResponse,
+ NumberUpdateResponse,
NumberPurposesResponse,
NumberRetrieveResponse,
NumberCountriesResponse,
@@ -36,6 +37,7 @@ def test_method_create_with_all_params(self, client: Mobilerun) -> None:
number = client.numbers.create(
billing_preference="included",
country="de",
+ label="Support line",
purpose="telegram",
idempotency_key="x",
)
@@ -105,6 +107,57 @@ def test_path_params_retrieve(self, client: Mobilerun) -> None:
"",
)
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update(self, client: Mobilerun) -> None:
+ number = client.numbers.update(
+ id="550e8400-e29b-41d4-a716-446655440000",
+ )
+ assert_matches_type(NumberUpdateResponse, number, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_method_update_with_all_params(self, client: Mobilerun) -> None:
+ number = client.numbers.update(
+ id="550e8400-e29b-41d4-a716-446655440000",
+ label="Support line",
+ )
+ assert_matches_type(NumberUpdateResponse, number, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_raw_response_update(self, client: Mobilerun) -> None:
+ response = client.numbers.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"
+ number = response.parse()
+ assert_matches_type(NumberUpdateResponse, number, path=["response"])
+
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ def test_streaming_response_update(self, client: Mobilerun) -> None:
+ with client.numbers.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"
+
+ number = response.parse()
+ assert_matches_type(NumberUpdateResponse, number, 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.numbers.with_raw_response.update(
+ id="",
+ )
+
@pytest.mark.skip(reason="Mock server tests are disabled")
@parametrize
def test_method_list(self, client: Mobilerun) -> None:
@@ -258,6 +311,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMobilerun)
number = await async_client.numbers.create(
billing_preference="included",
country="de",
+ label="Support line",
purpose="telegram",
idempotency_key="x",
)
@@ -327,6 +381,57 @@ async def test_path_params_retrieve(self, async_client: AsyncMobilerun) -> None:
"",
)
+ @pytest.mark.skip(reason="Mock server tests are disabled")
+ @parametrize
+ async def test_method_update(self, async_client: AsyncMobilerun) -> None:
+ number = await async_client.numbers.update(
+ id="550e8400-e29b-41d4-a716-446655440000",
+ )
+ assert_matches_type(NumberUpdateResponse, number, 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:
+ number = await async_client.numbers.update(
+ id="550e8400-e29b-41d4-a716-446655440000",
+ label="Support line",
+ )
+ assert_matches_type(NumberUpdateResponse, number, 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.numbers.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"
+ number = await response.parse()
+ assert_matches_type(NumberUpdateResponse, number, 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.numbers.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"
+
+ number = await response.parse()
+ assert_matches_type(NumberUpdateResponse, number, 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.numbers.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:
diff --git a/tests/api_resources/workflows/test_flows.py b/tests/api_resources/workflows/test_flows.py
index 0cbbda1c..845d0f4f 100644
--- a/tests/api_resources/workflows/test_flows.py
+++ b/tests/api_resources/workflows/test_flows.py
@@ -75,6 +75,7 @@ def test_method_create_with_all_params(self, client: Mobilerun) -> None:
notify_on_failure=True,
notify_on_success=True,
notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ recording_enabled=True,
self_healing_enabled=True,
self_healing_max_attempts=1,
)
@@ -185,6 +186,7 @@ def test_method_update_with_all_params(self, client: Mobilerun) -> None:
notify_on_failure=True,
notify_on_success=True,
notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ recording_enabled=True,
self_healing_enabled=True,
self_healing_max_attempts=1,
trigger_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
@@ -553,6 +555,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMobilerun)
notify_on_failure=True,
notify_on_success=True,
notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ recording_enabled=True,
self_healing_enabled=True,
self_healing_max_attempts=1,
)
@@ -663,6 +666,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncMobilerun)
notify_on_failure=True,
notify_on_success=True,
notify_webhook_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ recording_enabled=True,
self_healing_enabled=True,
self_healing_max_attempts=1,
trigger_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",