smooth-py 0.1.3__tar.gz → 0.1.3.post0__tar.gz

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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: smooth-py
3
- Version: 0.1.3
3
+ Version: 0.1.3.post0
4
4
  Summary:
5
5
  Author: Luca Pinchetti
6
6
  Author-email: luca@circlemind.co
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "smooth-py"
3
- version = "0.1.3"
3
+ version = "0.1.3.post0"
4
4
  description = ""
5
5
  authors = [
6
6
  {name = "Luca Pinchetti",email = "luca@circlemind.co"}
@@ -154,51 +154,65 @@ class BaseClient:
154
154
  class TaskHandle:
155
155
  """A handle to a running task."""
156
156
 
157
- def __init__(self, task_id: str, client: "SmoothClient", live_url: str | None, poll_interval: int, timeout: int | None):
157
+ def __init__(self, task_id: str, client: "SmoothClient"):
158
158
  """Initializes the task handle."""
159
159
  self._client = client
160
- self._poll_interval = poll_interval
161
- self._timeout = timeout
162
160
  self._task_response: TaskResponse | None = None
163
- self._live_url = live_url
164
161
 
165
162
  self.id = task_id
166
163
 
167
- def result(self) -> TaskResponse:
164
+ def result(self, timeout: int | None = None, poll_interval: float = 1) -> TaskResponse:
168
165
  """Waits for the task to complete and returns the result."""
169
166
  if self._task_response and self._task_response.status not in ["running", "waiting"]:
170
167
  return self._task_response
171
168
 
169
+ if timeout is not None and timeout < 1:
170
+ raise ValueError("Timeout must be at least 1 second.")
171
+ if poll_interval < 0.1:
172
+ raise ValueError("Poll interval must be at least 100 milliseconds.")
173
+
172
174
  start_time = time.time()
173
- while self._timeout is None or (time.time() - start_time) < self._timeout:
175
+ while timeout is None or (time.time() - start_time) < timeout:
174
176
  task_response = self._client._get_task(self.id) # pyright: ignore [reportPrivateUsage]
177
+ self._task_response = task_response
175
178
  if task_response.status not in ["running", "waiting"]:
176
- self._task_response = task_response
177
179
  return task_response
178
- time.sleep(self._poll_interval)
179
- raise TimeoutError(f"Task {self.id} did not complete within {self._timeout} seconds.")
180
+ time.sleep(poll_interval)
181
+ raise TimeoutError(f"Task {self.id} did not complete within {timeout} seconds.")
180
182
 
181
- def live_url(self, interactive: bool = True, embed: bool = False) -> str:
183
+ def live_url(self, interactive: bool = True, embed: bool = False, timeout: int | None = None):
182
184
  """Returns the live URL for the task."""
183
185
  params = {
184
186
  "interactive": interactive,
185
187
  "embed": embed
186
188
  }
187
- return f"{self._live_url}?{urlencode(params)}"
188
189
 
189
- def recording_url(self) -> str:
190
+ if self._task_response and self._task_response.live_url:
191
+ return f"{self._task_response.live_url}?{urlencode(params)}"
192
+
193
+ start_time = time.time()
194
+ while timeout is None or (time.time() - start_time) < timeout:
195
+ task_response = self._client._get_task(self.id) # pyright: ignore [reportPrivateUsage]
196
+ self._task_response = task_response
197
+ if self._task_response.live_url:
198
+ return f"{self._task_response.live_url}?{urlencode(params)}"
199
+ time.sleep(1)
200
+
201
+ raise TimeoutError(f"Live URL not available for task {self.id}.")
202
+
203
+ def recording_url(self, timeout: int | None = None) -> str:
190
204
  """Returns the recording URL for the task."""
191
205
  if self._task_response and self._task_response.recording_url is not None:
192
206
  return self._task_response.recording_url
193
207
 
194
208
  start_time = time.time()
195
- while (time.time() - start_time) < 8:
209
+ while timeout is None or (time.time() - start_time) < timeout:
196
210
  task_response = self._client._get_task(self.id) # pyright: ignore [reportPrivateUsage]
197
211
  self._task_response = task_response
198
212
  if task_response.recording_url is not None:
199
213
  return task_response.recording_url
200
214
  time.sleep(1)
201
- raise TimeoutError(f"Recording not available for task {self.id}.")
215
+ raise TimeoutError(f"Recording URL not available for task {self.id}.")
202
216
 
203
217
 
204
218
  class SmoothClient(BaseClient):
@@ -249,8 +263,6 @@ class SmoothClient(BaseClient):
249
263
  def run(
250
264
  self,
251
265
  task: str,
252
- poll_interval: int = 1,
253
- timeout: int = 60 * 15,
254
266
  agent: Literal["smooth"] = "smooth",
255
267
  max_steps: int = 32,
256
268
  device: Literal["desktop", "mobile"] = "mobile",
@@ -268,8 +280,6 @@ class SmoothClient(BaseClient):
268
280
 
269
281
  Args:
270
282
  task: The task to run.
271
- poll_interval: The time in seconds to wait between polling for status.
272
- timeout: The maximum time in seconds to wait for the task to complete.
273
283
  agent: The agent to use for the task.
274
284
  max_steps: Maximum number of steps the agent can take (max 64).
275
285
  device: Device type for the task. Default is mobile.
@@ -286,11 +296,6 @@ class SmoothClient(BaseClient):
286
296
  Raises:
287
297
  ApiException: If the API request fails.
288
298
  """
289
- if poll_interval < 0.1:
290
- raise ValueError("Poll interval must be at least 100 milliseconds.")
291
- if timeout < 1:
292
- raise ValueError("Timeout must be at least 1 second.")
293
-
294
299
  payload = TaskRequest(
295
300
  task=task,
296
301
  agent=agent,
@@ -304,12 +309,8 @@ class SmoothClient(BaseClient):
304
309
  proxy_password=proxy_password,
305
310
  )
306
311
  initial_response = self._submit_task(payload)
307
- start_time = time.time()
308
- while time.time() - start_time < 16 and initial_response.live_url is None:
309
- initial_response = self._get_task(initial_response.id)
310
- time.sleep(poll_interval)
311
312
 
312
- return TaskHandle(initial_response.id, self, initial_response.live_url, poll_interval, timeout)
313
+ return TaskHandle(initial_response.id, self)
313
314
 
314
315
  def open_session(self, session_id: str | None = None) -> BrowserSessionResponse:
315
316
  """Gets an interactive browser instance.
@@ -367,51 +368,65 @@ class SmoothClient(BaseClient):
367
368
  class AsyncTaskHandle:
368
369
  """An asynchronous handle to a running task."""
369
370
 
370
- def __init__(self, task_id: str, client: "SmoothAsyncClient", live_url: str | None, poll_interval: int, timeout: int | None):
371
+ def __init__(self, task_id: str, client: "SmoothAsyncClient"):
371
372
  """Initializes the asynchronous task handle."""
372
373
  self._client = client
373
- self._poll_interval = poll_interval
374
- self._timeout = timeout
375
- self._live_url = live_url
376
374
  self._task_response: TaskResponse | None = None
377
375
 
378
376
  self.id = task_id
379
377
 
380
- async def result(self) -> TaskResponse:
378
+ async def result(self, timeout: int | None = None, poll_interval: float = 1) -> TaskResponse:
381
379
  """Waits for the task to complete and returns the result."""
382
380
  if self._task_response and self._task_response.status not in ["running", "waiting"]:
383
381
  return self._task_response
384
382
 
383
+ if timeout is not None and timeout < 1:
384
+ raise ValueError("Timeout must be at least 1 second.")
385
+ if poll_interval < 0.1:
386
+ raise ValueError("Poll interval must be at least 100 milliseconds.")
387
+
385
388
  start_time = time.time()
386
- while self._timeout is None or (time.time() - start_time) < self._timeout:
389
+ while timeout is None or (time.time() - start_time) < timeout:
387
390
  task_response = await self._client._get_task(self.id) # pyright: ignore [reportPrivateUsage]
388
391
  self._task_response = task_response
389
392
  if task_response.status not in ["running", "waiting"]:
390
393
  return task_response
391
- await asyncio.sleep(self._poll_interval)
392
- raise TimeoutError(f"Task {self.id} did not complete within {self._timeout} seconds.")
394
+ await asyncio.sleep(poll_interval)
395
+ raise TimeoutError(f"Task {self.id} did not complete within {timeout} seconds.")
393
396
 
394
- def live_url(self, interactive: bool = True, embed: bool = False) -> str:
397
+ async def live_url(self, interactive: bool = True, embed: bool = False, timeout: int | None = None):
395
398
  """Returns the live URL for the task."""
396
399
  params = {
397
400
  "interactive": interactive,
398
401
  "embed": embed
399
402
  }
400
- return f"{self._live_url}?{urlencode(params)}"
403
+ if self._task_response and self._task_response.live_url:
404
+ return f"{self._task_response.live_url}?{urlencode(params)}"
401
405
 
402
- async def recording_url(self) -> str:
406
+ start_time = time.time()
407
+ while timeout is None or (time.time() - start_time) < timeout:
408
+ task_response = await self._client._get_task(self.id) # pyright: ignore [reportPrivateUsage]
409
+ self._task_response = task_response
410
+ if task_response.live_url is not None:
411
+ return f"{task_response.live_url}?{urlencode(params)}"
412
+ await asyncio.sleep(1)
413
+
414
+ raise TimeoutError(f"Live URL not available for task {self.id}.")
415
+
416
+ async def recording_url(self, timeout: int | None = None):
403
417
  """Returns the recording URL for the task."""
404
418
  if self._task_response and self._task_response.recording_url is not None:
405
419
  return self._task_response.recording_url
406
420
 
407
421
  start_time = time.time()
408
- while (time.time() - start_time) < 8:
422
+ while timeout is None or (time.time() - start_time) < timeout:
409
423
  task_response = await self._client._get_task(self.id) # pyright: ignore [reportPrivateUsage]
410
424
  self._task_response = task_response
411
425
  if task_response.recording_url is not None:
412
426
  return task_response.recording_url
413
427
  await asyncio.sleep(1)
414
- raise TimeoutError(f"Recording not available for task {self.id}.")
428
+
429
+ raise TimeoutError(f"Recording URL not available for task {self.id}.")
415
430
 
416
431
  class SmoothAsyncClient(BaseClient):
417
432
  """An asynchronous client for the API."""
@@ -464,8 +479,6 @@ class SmoothAsyncClient(BaseClient):
464
479
  proxy_server: str | None = None,
465
480
  proxy_username: str | None = None,
466
481
  proxy_password: str | None = None,
467
- poll_interval: int = 1,
468
- timeout: int = 60 * 15,
469
482
  ) -> AsyncTaskHandle:
470
483
  """Runs a task and returns a handle to the task asynchronously.
471
484
 
@@ -492,11 +505,6 @@ class SmoothAsyncClient(BaseClient):
492
505
  Raises:
493
506
  ApiException: If the API request fails.
494
507
  """
495
- if poll_interval < 0.1:
496
- raise ValueError("Poll interval must be at least 100 milliseconds.")
497
- if timeout < 1:
498
- raise ValueError("Timeout must be at least 1 second.")
499
-
500
508
  payload = TaskRequest(
501
509
  task=task,
502
510
  agent=agent,
@@ -511,11 +519,7 @@ class SmoothAsyncClient(BaseClient):
511
519
  )
512
520
 
513
521
  initial_response = await self._submit_task(payload)
514
- start_time = time.time()
515
- while time.time() - start_time < 16 and initial_response.live_url is None:
516
- initial_response = await self._get_task(initial_response.id)
517
- await asyncio.sleep(poll_interval)
518
- return AsyncTaskHandle(initial_response.id, self, initial_response.live_url, poll_interval, timeout)
522
+ return AsyncTaskHandle(initial_response.id, self)
519
523
 
520
524
  async def open_session(self, session_id: str | None = None) -> BrowserSessionResponse:
521
525
  """Opens an interactive browser instance asynchronously.
File without changes