smooth-py 0.2.8.dev20251009__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of smooth-py might be problematic. Click here for more details.
smooth/__init__.py
CHANGED
|
@@ -113,12 +113,12 @@ class TaskRequest(BaseModel):
|
|
|
113
113
|
return self.profile_id
|
|
114
114
|
|
|
115
115
|
@session_id.setter
|
|
116
|
-
def session_id(self, value):
|
|
116
|
+
def session_id(self, value: str | None):
|
|
117
117
|
"""(Deprecated) Sets the session ID."""
|
|
118
118
|
warnings.warn("'session_id' is deprecated, use 'profile_id' instead", DeprecationWarning, stacklevel=2)
|
|
119
119
|
self.profile_id = value
|
|
120
120
|
|
|
121
|
-
def model_dump(self, **kwargs) -> dict[str, Any]:
|
|
121
|
+
def model_dump(self, **kwargs: Any) -> dict[str, Any]:
|
|
122
122
|
"""Dump model to dict, including deprecated session_id for retrocompatibility."""
|
|
123
123
|
data = super().model_dump(**kwargs)
|
|
124
124
|
# Add deprecated session_id field for retrocompatibility
|
|
@@ -151,12 +151,12 @@ class BrowserSessionRequest(BaseModel):
|
|
|
151
151
|
return self.profile_id
|
|
152
152
|
|
|
153
153
|
@session_id.setter
|
|
154
|
-
def session_id(self, value):
|
|
154
|
+
def session_id(self, value: str | None):
|
|
155
155
|
"""(Deprecated) Sets the session ID."""
|
|
156
156
|
warnings.warn("'session_id' is deprecated, use 'profile_id' instead", DeprecationWarning, stacklevel=2)
|
|
157
157
|
self.profile_id = value
|
|
158
158
|
|
|
159
|
-
def model_dump(self, **kwargs) -> dict[str, Any]:
|
|
159
|
+
def model_dump(self, **kwargs: Any) -> dict[str, Any]:
|
|
160
160
|
"""Dump model to dict, including deprecated session_id for retrocompatibility."""
|
|
161
161
|
data = super().model_dump(**kwargs)
|
|
162
162
|
# Add deprecated session_id field for retrocompatibility
|
|
@@ -188,7 +188,7 @@ class BrowserSessionResponse(BaseModel):
|
|
|
188
188
|
return self.profile_id
|
|
189
189
|
|
|
190
190
|
@session_id.setter
|
|
191
|
-
def session_id(self, value):
|
|
191
|
+
def session_id(self, value: str):
|
|
192
192
|
"""(Deprecated) Sets the session ID."""
|
|
193
193
|
warnings.warn("'session_id' is deprecated, use 'profile_id' instead", DeprecationWarning, stacklevel=2)
|
|
194
194
|
self.profile_id = value
|
|
@@ -215,12 +215,12 @@ class BrowserProfilesResponse(BaseModel):
|
|
|
215
215
|
return self.profile_ids
|
|
216
216
|
|
|
217
217
|
@session_ids.setter
|
|
218
|
-
def session_ids(self, value):
|
|
218
|
+
def session_ids(self, value: list[str]):
|
|
219
219
|
"""(Deprecated) Sets the session IDs."""
|
|
220
220
|
warnings.warn("'session_ids' is deprecated, use 'profile_ids' instead", DeprecationWarning, stacklevel=2)
|
|
221
221
|
self.profile_ids = value
|
|
222
222
|
|
|
223
|
-
def model_dump(self, **kwargs) -> dict[str, Any]:
|
|
223
|
+
def model_dump(self, **kwargs: Any) -> dict[str, Any]:
|
|
224
224
|
"""Dump model to dict, including deprecated session_ids for retrocompatibility."""
|
|
225
225
|
data = super().model_dump(**kwargs)
|
|
226
226
|
# Add deprecated session_ids field for retrocompatibility
|
|
@@ -347,12 +347,7 @@ class TaskHandle:
|
|
|
347
347
|
|
|
348
348
|
def stop(self):
|
|
349
349
|
"""Stops the task."""
|
|
350
|
-
|
|
351
|
-
response = self._client._client.delete(f"{self._client.base_url}/task/{self._id}")
|
|
352
|
-
self._handle_response(response)
|
|
353
|
-
except requests.exceptions.RequestException as e:
|
|
354
|
-
logger.error(f"Request failed: {e}")
|
|
355
|
-
raise ApiError(status_code=0, detail=f"Request failed: {str(e)}") from None
|
|
350
|
+
self._client._delete_task(self._id)
|
|
356
351
|
|
|
357
352
|
def result(self, timeout: int | None = None, poll_interval: float = 1) -> TaskResponse:
|
|
358
353
|
"""Waits for the task to complete and returns the result."""
|
|
@@ -448,6 +443,18 @@ class SmoothClient(BaseClient):
|
|
|
448
443
|
logger.error(f"Request failed: {e}")
|
|
449
444
|
raise ApiError(status_code=0, detail=f"Request failed: {str(e)}") from None
|
|
450
445
|
|
|
446
|
+
def _delete_task(self, task_id: str):
|
|
447
|
+
"""Deletes a task."""
|
|
448
|
+
if not task_id:
|
|
449
|
+
raise ValueError("Task ID cannot be empty.")
|
|
450
|
+
|
|
451
|
+
try:
|
|
452
|
+
response = self._session.delete(f"{self.base_url}/task/{task_id}")
|
|
453
|
+
self._handle_response(response)
|
|
454
|
+
except requests.exceptions.RequestException as e:
|
|
455
|
+
logger.error(f"Request failed: {e}")
|
|
456
|
+
raise ApiError(status_code=0, detail=f"Request failed: {str(e)}") from None
|
|
457
|
+
|
|
451
458
|
def run(
|
|
452
459
|
self,
|
|
453
460
|
task: str,
|
|
@@ -479,7 +486,7 @@ class SmoothClient(BaseClient):
|
|
|
479
486
|
response_model: If provided, the schema describing the desired output structure.
|
|
480
487
|
url: The starting URL for the task. If not provided, the agent will infer it from the task.
|
|
481
488
|
metadata: A dictionary containing variables or parameters that will be passed to the agent.
|
|
482
|
-
files: A
|
|
489
|
+
files: A list of file ids to pass to the agent.
|
|
483
490
|
agent: The agent to use for the task.
|
|
484
491
|
max_steps: Maximum number of steps the agent can take (max 64).
|
|
485
492
|
device: Device type for the task. Default is mobile.
|
|
@@ -503,7 +510,7 @@ class SmoothClient(BaseClient):
|
|
|
503
510
|
"""
|
|
504
511
|
payload = TaskRequest(
|
|
505
512
|
task=task,
|
|
506
|
-
response_model=response_model
|
|
513
|
+
response_model=response_model if isinstance(response_model, dict | None) else response_model.model_json_schema(),
|
|
507
514
|
url=url,
|
|
508
515
|
metadata=metadata,
|
|
509
516
|
files=files,
|
|
@@ -656,6 +663,10 @@ class AsyncTaskHandle:
|
|
|
656
663
|
"""Returns the task ID."""
|
|
657
664
|
return self._id
|
|
658
665
|
|
|
666
|
+
async def stop(self):
|
|
667
|
+
"""Stops the task."""
|
|
668
|
+
await self._client._delete_task(self._id)
|
|
669
|
+
|
|
659
670
|
async def result(self, timeout: int | None = None, poll_interval: float = 1) -> TaskResponse:
|
|
660
671
|
"""Waits for the task to complete and returns the result."""
|
|
661
672
|
if self._task_response and self._task_response.status not in ["running", "waiting"]:
|
|
@@ -675,7 +686,7 @@ class AsyncTaskHandle:
|
|
|
675
686
|
await asyncio.sleep(poll_interval)
|
|
676
687
|
raise TimeoutError(f"Task {self.id()} did not complete within {timeout} seconds.")
|
|
677
688
|
|
|
678
|
-
async def live_url(self, interactive: bool =
|
|
689
|
+
async def live_url(self, interactive: bool = False, embed: bool = False, timeout: int | None = None):
|
|
679
690
|
"""Returns the live URL for the task."""
|
|
680
691
|
if self._task_response and self._task_response.live_url:
|
|
681
692
|
return _encode_url(self._task_response.live_url, interactive=interactive, embed=embed)
|
|
@@ -684,13 +695,13 @@ class AsyncTaskHandle:
|
|
|
684
695
|
while timeout is None or (time.time() - start_time) < timeout:
|
|
685
696
|
task_response = await self._client._get_task(self.id())
|
|
686
697
|
self._task_response = task_response
|
|
687
|
-
if
|
|
698
|
+
if self._task_response.live_url:
|
|
688
699
|
return _encode_url(self._task_response.live_url, interactive=interactive, embed=embed)
|
|
689
700
|
await asyncio.sleep(1)
|
|
690
701
|
|
|
691
702
|
raise TimeoutError(f"Live URL not available for task {self.id()}.")
|
|
692
703
|
|
|
693
|
-
async def recording_url(self, timeout: int | None = None):
|
|
704
|
+
async def recording_url(self, timeout: int | None = None) -> str:
|
|
694
705
|
"""Returns the recording URL for the task."""
|
|
695
706
|
if self._task_response and self._task_response.recording_url is not None:
|
|
696
707
|
return self._task_response.recording_url
|
|
@@ -745,6 +756,18 @@ class SmoothAsyncClient(BaseClient):
|
|
|
745
756
|
logger.error(f"Request failed: {e}")
|
|
746
757
|
raise ApiError(status_code=0, detail=f"Request failed: {str(e)}") from None
|
|
747
758
|
|
|
759
|
+
async def _delete_task(self, task_id: str):
|
|
760
|
+
"""Deletes a task asynchronously."""
|
|
761
|
+
if not task_id:
|
|
762
|
+
raise ValueError("Task ID cannot be empty.")
|
|
763
|
+
|
|
764
|
+
try:
|
|
765
|
+
response = await self._client.delete(f"{self.base_url}/task/{task_id}")
|
|
766
|
+
self._handle_response(response)
|
|
767
|
+
except httpx.RequestError as e:
|
|
768
|
+
logger.error(f"Request failed: {e}")
|
|
769
|
+
raise ApiError(status_code=0, detail=f"Request failed: {str(e)}") from None
|
|
770
|
+
|
|
748
771
|
async def run(
|
|
749
772
|
self,
|
|
750
773
|
task: str,
|
|
@@ -776,7 +799,7 @@ class SmoothAsyncClient(BaseClient):
|
|
|
776
799
|
response_model: If provided, the schema describing the desired output structure.
|
|
777
800
|
url: The starting URL for the task. If not provided, the agent will infer it from the task.
|
|
778
801
|
metadata: A dictionary containing variables or parameters that will be passed to the agent.
|
|
779
|
-
files: A
|
|
802
|
+
files: A list of file ids to pass to the agent.
|
|
780
803
|
agent: The agent to use for the task.
|
|
781
804
|
max_steps: Maximum number of steps the agent can take (max 64).
|
|
782
805
|
device: Device type for the task. Default is mobile.
|
|
@@ -800,7 +823,7 @@ class SmoothAsyncClient(BaseClient):
|
|
|
800
823
|
"""
|
|
801
824
|
payload = TaskRequest(
|
|
802
825
|
task=task,
|
|
803
|
-
response_model=response_model
|
|
826
|
+
response_model=response_model if isinstance(response_model, dict | None) else response_model.model_json_schema(),
|
|
804
827
|
url=url,
|
|
805
828
|
metadata=metadata,
|
|
806
829
|
files=files,
|
|
@@ -827,8 +850,8 @@ class SmoothAsyncClient(BaseClient):
|
|
|
827
850
|
"""Opens an interactive browser instance asynchronously.
|
|
828
851
|
|
|
829
852
|
Args:
|
|
853
|
+
profile_id: The profile ID to use for the session. If None, a new profile will be created.
|
|
830
854
|
session_id: (Deprecated, now `profile_id`) The session ID to associate with the browser.
|
|
831
|
-
profile_id: The profile ID to associate with the browser.
|
|
832
855
|
live_view: Whether to enable live view for the session.
|
|
833
856
|
|
|
834
857
|
Returns:
|
|
@@ -913,11 +936,12 @@ class SmoothAsyncClient(BaseClient):
|
|
|
913
936
|
if name is None:
|
|
914
937
|
raise ValueError("File name must be provided or the file object must have a 'name' attribute.")
|
|
915
938
|
|
|
916
|
-
files = {"file": (Path(name).name, file)}
|
|
917
939
|
if purpose:
|
|
918
940
|
data = {"file_purpose": purpose}
|
|
919
941
|
else:
|
|
920
942
|
data = None
|
|
943
|
+
|
|
944
|
+
files = {"file": (Path(name).name, file)}
|
|
921
945
|
response = await self._client.post(f"{self.base_url}/file", files=files, data=data)
|
|
922
946
|
data = self._handle_response(response)
|
|
923
947
|
return UploadFileResponse(**data["r"])
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
smooth/__init__.py,sha256=yhlG6m00uOw8umRC7ONImCMCiCkWTV5khj050qfD_V8,38411
|
|
2
|
+
smooth/mcp/__init__.py,sha256=0aJVFi2a8Ah3-5xtgyZ5UMbaaJsBWu2T8QLWoFQITk8,219
|
|
3
|
+
smooth/mcp/server.py,sha256=9SymTD4NOGTMN8P-LNGlvYNvv81yCIZfZeeuhEcAc6s,20068
|
|
4
|
+
smooth_py-0.3.0.dist-info/METADATA,sha256=OJjBn5D0m9N78qyFfiVwN8nd3pSrMNG4V0ubVkMuyfM,7517
|
|
5
|
+
smooth_py-0.3.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
6
|
+
smooth_py-0.3.0.dist-info/RECORD,,
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
smooth/__init__.py,sha256=4jYb61Mn-G6GIjIi4rXvzXQY7yWHfIOVvik8RNNJWcU,37701
|
|
2
|
-
smooth/mcp/__init__.py,sha256=0aJVFi2a8Ah3-5xtgyZ5UMbaaJsBWu2T8QLWoFQITk8,219
|
|
3
|
-
smooth/mcp/server.py,sha256=9SymTD4NOGTMN8P-LNGlvYNvv81yCIZfZeeuhEcAc6s,20068
|
|
4
|
-
smooth_py-0.2.8.dev20251009.dist-info/METADATA,sha256=pyfY6EygBMxQnAoLN8NxgbqwD28XFzCJe24HXCcuaaY,7529
|
|
5
|
-
smooth_py-0.2.8.dev20251009.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
6
|
-
smooth_py-0.2.8.dev20251009.dist-info/RECORD,,
|
|
File without changes
|