fleet-python 0.2.126__py3-none-any.whl → 0.2.128__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.
fleet/__init__.py CHANGED
@@ -76,7 +76,7 @@ from . import env
76
76
  from . import global_client as _global_client
77
77
  from ._async import global_client as _async_global_client
78
78
 
79
- __version__ = "0.2.126"
79
+ __version__ = "0.2.128"
80
80
 
81
81
  __all__ = [
82
82
  # Core classes
fleet/_async/__init__.py CHANGED
@@ -44,7 +44,7 @@ from ..types import VerifierFunction
44
44
  from .. import env
45
45
  from . import global_client as _async_global_client
46
46
 
47
- __version__ = "0.2.126"
47
+ __version__ = "0.2.128"
48
48
 
49
49
  __all__ = [
50
50
  # Core classes
fleet/_async/base.py CHANGED
@@ -26,7 +26,7 @@ from .exceptions import (
26
26
  try:
27
27
  from .. import __version__
28
28
  except ImportError:
29
- __version__ = "0.2.126"
29
+ __version__ = "0.2.128"
30
30
 
31
31
  logger = logging.getLogger(__name__)
32
32
 
fleet/_async/client.py CHANGED
@@ -482,6 +482,8 @@ class AsyncEnv(EnvironmentBase):
482
482
  timeout: Optional[int] = 30,
483
483
  needs_upload: bool = True,
484
484
  verifier_runtime_version: Optional[str] = None,
485
+ async_: bool = False,
486
+ poll_interval: float = 5.0,
485
487
  ) -> VerifiersExecuteResponse:
486
488
  return await _execute_verifier_remote(
487
489
  self._load_client,
@@ -495,6 +497,8 @@ class AsyncEnv(EnvironmentBase):
495
497
  timeout,
496
498
  needs_upload,
497
499
  verifier_runtime_version,
500
+ async_=async_,
501
+ poll_interval=poll_interval,
498
502
  )
499
503
 
500
504
  def __getstate__(self):
@@ -601,9 +605,7 @@ class AsyncFleet:
601
605
  )
602
606
 
603
607
  instance = AsyncEnv(client=self.client, **response.json())
604
- # Resources are loaded lazily on first `db()`/`browser()`/`resources()` access
605
- # via `_load_resources()`, so we don't preload here. Eagerly loading would
606
- # fail-fast with a 502 while the container is still warming up.
608
+ await instance.instance.load()
607
609
  return instance
608
610
 
609
611
  async def make_for_task(self, task: Task) -> AsyncEnv:
@@ -655,7 +657,7 @@ class AsyncFleet:
655
657
  else:
656
658
  response = await self.client.request("GET", f"/v1/env/instances/{instance_id}")
657
659
  instance = AsyncEnv(client=self.client, **response.json())
658
- # Resources load lazily on first `db()`/`browser()`/`resources()` access.
660
+ await instance.instance.load()
659
661
  return instance
660
662
 
661
663
  def _create_url_instance(self, base_url: str) -> AsyncEnv:
@@ -1727,6 +1729,8 @@ async def _execute_verifier_remote(
1727
1729
  timeout: Optional[int] = 30,
1728
1730
  needs_upload: bool = True,
1729
1731
  verifier_runtime_version: Optional[str] = None,
1732
+ async_: bool = False,
1733
+ poll_interval: float = 5.0,
1730
1734
  ) -> VerifiersExecuteResponse:
1731
1735
  # Pickle args and kwargs together
1732
1736
  # The first arg should be None as a placeholder for env
@@ -1754,6 +1758,11 @@ async def _execute_verifier_remote(
1754
1758
  if verifier_runtime_version:
1755
1759
  request_data["verifier_runtime_version"] = verifier_runtime_version
1756
1760
 
1761
+ # Async submit-and-poll path. When async_ is False the behavior below is
1762
+ # identical to the original synchronous request.
1763
+ if async_:
1764
+ request_data["async"] = True
1765
+
1757
1766
  # Debug logging
1758
1767
  # logger.debug(
1759
1768
  # f"Sending verifier execute request: key={key}, sha256={bundle_sha[:8]}..., function_name={function_name}"
@@ -1775,4 +1784,21 @@ async def _execute_verifier_remote(
1775
1784
  response_json = response.json()
1776
1785
  # logger.debug(f"Verifier execute response: {response_json}")
1777
1786
 
1778
- return VerifiersExecuteResponse(**response_json)
1787
+ if not async_:
1788
+ return VerifiersExecuteResponse(**response_json)
1789
+
1790
+ # Async: the submit returns a job handle; poll until the job reaches a
1791
+ # terminal state (completed/failed). Branch on `status`, never `success`.
1792
+ job_id = response_json.get("job_id")
1793
+ if not job_id:
1794
+ # No job handle returned (e.g. server ran it inline) - surface as-is.
1795
+ return VerifiersExecuteResponse(**response_json)
1796
+
1797
+ while True:
1798
+ poll_response = await client.request(
1799
+ "GET", f"/v1/verifiers/jobs/{job_id}"
1800
+ )
1801
+ poll_json = poll_response.json()
1802
+ if poll_json.get("status") in ("completed", "failed"):
1803
+ return VerifiersExecuteResponse(**poll_json)
1804
+ await asyncio.sleep(poll_interval)
fleet/_async/models.py CHANGED
@@ -51,7 +51,6 @@ class Instance(BaseModel):
51
51
  team_id: str = Field(..., title="Team Id")
52
52
  region: str = Field(..., title="Region")
53
53
  env_variables: Optional[Dict[str, Any]] = Field(None, title="Env Variables")
54
- multi_env_list: Optional[List[str]] = Field(None, title="Multi Env List")
55
54
 
56
55
 
57
56
  class InstanceRequest(BaseModel):
@@ -259,6 +258,12 @@ class VerifiersExecuteRequest(BaseModel):
259
258
  display_src: Optional[str] = Field(
260
259
  None, description="Display source code", title="Display Src"
261
260
  )
261
+ async_: Optional[bool] = Field(
262
+ None,
263
+ alias="async",
264
+ description="Submit asynchronously and return a job handle instead of waiting",
265
+ title="Async",
266
+ )
262
267
 
263
268
 
264
269
  class VerifiersExecuteResponse(BaseModel):
@@ -303,6 +308,16 @@ class VerifiersExecuteResponse(BaseModel):
303
308
  stdout: Optional[str] = Field(
304
309
  None, description="Captured stdout from execution", title="Stdout"
305
310
  )
311
+ status: Optional[str] = Field(
312
+ None,
313
+ description="Job status for async execution (pending/running/completed/failed)",
314
+ title="Status",
315
+ )
316
+ job_id: Optional[str] = Field(
317
+ None,
318
+ description="Job handle for async execution; poll GET /v1/verifiers/jobs/{job_id}",
319
+ title="Job Id",
320
+ )
306
321
 
307
322
 
308
323
  class DescribeResponse(BaseModel):
@@ -358,7 +373,6 @@ class InstanceResponse(BaseModel):
358
373
  data_version: Optional[str] = Field(None, title="Data Version")
359
374
  urls: Optional[InstanceURLs] = Field(None, title="Urls")
360
375
  health: Optional[bool] = Field(None, title="Health")
361
- multi_env_list: Optional[List[str]] = Field(None, title="Multi Env List")
362
376
 
363
377
 
364
378
  class AccountResponse(BaseModel):
fleet/_async/tasks.py CHANGED
@@ -81,11 +81,23 @@ class Task(BaseModel):
81
81
  # Allow arbitrary types for the verifier field
82
82
  arbitrary_types_allowed = True
83
83
 
84
- def verify(self, env, *args, **kwargs) -> float:
84
+ def verify(
85
+ self,
86
+ env,
87
+ *args,
88
+ async_: bool = False,
89
+ poll_interval: float = 5.0,
90
+ **kwargs,
91
+ ) -> float:
85
92
  """Verify the task using the verifier function (sync version).
86
93
 
87
94
  For sync environments, calls the sync verifier directly.
88
95
  For async verifiers, automatically runs them with asyncio.run().
96
+
97
+ When ``async_`` is True the verifier is submitted to run in the
98
+ background and polled (every ``poll_interval`` seconds) until it
99
+ completes, avoiding HTTP/edge idle timeouts for long-running
100
+ verifiers. When False the behavior is unchanged.
89
101
  """
90
102
  # If verifier doesn't exist but verifier_func does, rebuild it
91
103
  if not self.verifier and self.verifier_func:
@@ -95,7 +107,9 @@ class Task(BaseModel):
95
107
  import asyncio
96
108
  import inspect
97
109
 
98
- result = self.verifier.remote(env, *args, **kwargs)
110
+ result = self.verifier.remote(
111
+ env, *args, async_=async_, poll_interval=poll_interval, **kwargs
112
+ )
99
113
 
100
114
  # If the result is a coroutine, we need to run it
101
115
  if inspect.iscoroutine(result):
@@ -115,18 +129,27 @@ class Task(BaseModel):
115
129
  else:
116
130
  raise ValueError("No verifier function found for this task")
117
131
 
118
- async def verify_async(self, *args, **kwargs) -> float:
132
+ async def verify_async(
133
+ self, *args, async_: bool = False, poll_interval: float = 5.0, **kwargs
134
+ ) -> float:
119
135
  """Verify the task using the verifier function (async version).
120
136
 
121
137
  For async environments, awaits the async verifier.
122
138
  Works with both sync and async verifiers in async contexts.
139
+
140
+ When ``async_`` is True the verifier is submitted to run in the
141
+ background and polled (every ``poll_interval`` seconds) until it
142
+ completes, avoiding HTTP/edge idle timeouts for long-running
143
+ verifiers. When False the behavior is unchanged.
123
144
  """
124
145
  # If verifier doesn't exist but verifier_func does, rebuild it
125
146
  if not self.verifier and self.verifier_func:
126
147
  self._rebuild_verifier()
127
148
 
128
149
  if self.verifier:
129
- result = self.verifier.remote(*args, **kwargs)
150
+ result = self.verifier.remote(
151
+ *args, async_=async_, poll_interval=poll_interval, **kwargs
152
+ )
130
153
  # If it's a coroutine, await it
131
154
  import inspect
132
155
 
@@ -138,19 +161,26 @@ class Task(BaseModel):
138
161
  raise ValueError("No verifier function found for this task")
139
162
 
140
163
  async def verify_detailed_async(
141
- self, *args, **kwargs
164
+ self, *args, async_: bool = False, poll_interval: float = 5.0, **kwargs
142
165
  ) -> "VerifiersExecuteResponse":
143
166
  """Verify the task and return the full execute response model.
144
167
 
145
168
  For async environments, awaits the async verifier.
146
169
  Works with both sync and async verifiers in async contexts.
170
+
171
+ When ``async_`` is True the verifier is submitted to run in the
172
+ background and polled (every ``poll_interval`` seconds) until it
173
+ completes, avoiding HTTP/edge idle timeouts for long-running
174
+ verifiers. When False the behavior is unchanged.
147
175
  """
148
176
  # If verifier doesn't exist but verifier_func does, rebuild it
149
177
  if not self.verifier and self.verifier_func:
150
178
  self._rebuild_verifier()
151
179
 
152
180
  if self.verifier:
153
- result = self.verifier.remote_with_response(*args, **kwargs)
181
+ result = self.verifier.remote_with_response(
182
+ *args, async_=async_, poll_interval=poll_interval, **kwargs
183
+ )
154
184
  # If it's a coroutine, await it
155
185
  import inspect
156
186
 
@@ -161,11 +191,23 @@ class Task(BaseModel):
161
191
  else:
162
192
  raise ValueError("No verifier function found for this task")
163
193
 
164
- def verify_detailed(self, env, *args, **kwargs) -> "VerifiersExecuteResponse":
194
+ def verify_detailed(
195
+ self,
196
+ env,
197
+ *args,
198
+ async_: bool = False,
199
+ poll_interval: float = 5.0,
200
+ **kwargs,
201
+ ) -> "VerifiersExecuteResponse":
165
202
  """Verify the task and return the full execute response model (sync version).
166
203
 
167
204
  For sync environments, calls the sync verifier directly.
168
205
  For async verifiers, automatically runs them with asyncio.run().
206
+
207
+ When ``async_`` is True the verifier is submitted to run in the
208
+ background and polled (every ``poll_interval`` seconds) until it
209
+ completes, avoiding HTTP/edge idle timeouts for long-running
210
+ verifiers. When False the behavior is unchanged.
169
211
  """
170
212
  # If verifier doesn't exist but verifier_func does, rebuild it
171
213
  if not self.verifier and self.verifier_func:
@@ -176,7 +218,9 @@ class Task(BaseModel):
176
218
  import inspect
177
219
 
178
220
  # Check if verifier has remote_with_response method (for decorated verifiers)
179
- result = self.verifier.remote_with_response(env, *args, **kwargs)
221
+ result = self.verifier.remote_with_response(
222
+ env, *args, async_=async_, poll_interval=poll_interval, **kwargs
223
+ )
180
224
 
181
225
  # If the result is a coroutine, we need to run it
182
226
  if inspect.iscoroutine(result):
@@ -154,9 +154,25 @@ class AsyncVerifierFunction:
154
154
  # Return error score 0
155
155
  return 0.0
156
156
 
157
- async def remote(self, env: AsyncEnv, *args, **kwargs) -> float:
158
- """Remote execution of the verifier function with SHA-based bundle caching."""
159
- response = await self.remote_with_response(env, *args, **kwargs)
157
+ async def remote(
158
+ self,
159
+ env: AsyncEnv,
160
+ *args,
161
+ async_: bool = False,
162
+ poll_interval: float = 5.0,
163
+ **kwargs,
164
+ ) -> float:
165
+ """Remote execution of the verifier function with SHA-based bundle caching.
166
+
167
+ When ``async_`` is True the verifier is submitted to run in the
168
+ background and the result is polled (every ``poll_interval`` seconds)
169
+ until it completes — this avoids HTTP/edge idle timeouts for
170
+ long-running verifiers. When False the behavior is unchanged (the
171
+ request blocks until the verifier finishes).
172
+ """
173
+ response = await self.remote_with_response(
174
+ env, *args, async_=async_, poll_interval=poll_interval, **kwargs
175
+ )
160
176
 
161
177
  # Handle response
162
178
  if response.stdout:
@@ -228,9 +244,20 @@ Remote traceback:
228
244
  )
229
245
 
230
246
  async def remote_with_response(
231
- self, env: "AsyncEnv", *args, **kwargs
247
+ self,
248
+ env: "AsyncEnv",
249
+ *args,
250
+ async_: bool = False,
251
+ poll_interval: float = 5.0,
252
+ **kwargs,
232
253
  ) -> "VerifiersExecuteResponse":
233
- """Remote execution of the verifier function that returns the full response model."""
254
+ """Remote execution of the verifier function that returns the full response model.
255
+
256
+ When ``async_`` is True the verifier is submitted asynchronously and
257
+ polled (every ``poll_interval`` seconds) until it reaches a terminal
258
+ state; the returned response is the completed/failed job result. When
259
+ False the request blocks until the verifier finishes (unchanged).
260
+ """
234
261
  args_array = list(args)
235
262
  args_array.append({"env": env.instance_id})
236
263
  args = tuple(args_array)
@@ -254,6 +281,8 @@ Remote traceback:
254
281
  kwargs=kwargs,
255
282
  needs_upload=True,
256
283
  verifier_runtime_version=self.verifier_runtime_version,
284
+ async_=async_,
285
+ poll_interval=poll_interval,
257
286
  )
258
287
 
259
288
  # logger.debug(f"Bundle {bundle_sha[:8]}... uploaded successfully")
@@ -271,6 +300,8 @@ Remote traceback:
271
300
  kwargs=kwargs,
272
301
  needs_upload=False,
273
302
  verifier_runtime_version=self.verifier_runtime_version,
303
+ async_=async_,
304
+ poll_interval=poll_interval,
274
305
  )
275
306
 
276
307
  return response
@@ -292,6 +323,8 @@ Remote traceback:
292
323
  kwargs=kwargs,
293
324
  needs_upload=True,
294
325
  verifier_runtime_version=self.verifier_runtime_version,
326
+ async_=async_,
327
+ poll_interval=poll_interval,
295
328
  )
296
329
  return response
297
330
  else:
fleet/base.py CHANGED
@@ -27,7 +27,7 @@ from .exceptions import (
27
27
  try:
28
28
  from . import __version__
29
29
  except ImportError:
30
- __version__ = "0.2.126"
30
+ __version__ = "0.2.128"
31
31
 
32
32
  logger = logging.getLogger(__name__)
33
33
 
fleet/client.py CHANGED
@@ -22,6 +22,7 @@ import httpx
22
22
  import json
23
23
  import logging
24
24
  import os
25
+ import time
25
26
  from datetime import date, datetime
26
27
  from decimal import Decimal
27
28
  from enum import Enum
@@ -494,6 +495,8 @@ class SyncEnv(EnvironmentBase):
494
495
  timeout: Optional[int] = 30,
495
496
  needs_upload: bool = True,
496
497
  verifier_runtime_version: Optional[str] = None,
498
+ async_: bool = False,
499
+ poll_interval: float = 5.0,
497
500
  ) -> VerifiersExecuteResponse:
498
501
  return _execute_verifier_remote(
499
502
  self._load_client,
@@ -507,6 +510,8 @@ class SyncEnv(EnvironmentBase):
507
510
  timeout,
508
511
  needs_upload,
509
512
  verifier_runtime_version,
513
+ async_=async_,
514
+ poll_interval=poll_interval,
510
515
  )
511
516
 
512
517
  def __getstate__(self):
@@ -613,9 +618,7 @@ class Fleet:
613
618
  )
614
619
 
615
620
  instance = SyncEnv(client=self.client, **response.json())
616
- # Resources load lazily on first `db()`/`browser()`/`resources()` access via
617
- # `_load_resources()`. Skipping the eager preload avoids fail-fast 502s while
618
- # the container is still warming up.
621
+ instance.instance.load()
619
622
  return instance
620
623
 
621
624
  def make_for_task(self, task: Task) -> SyncEnv:
@@ -667,7 +670,7 @@ class Fleet:
667
670
  else:
668
671
  response = self.client.request("GET", f"/v1/env/instances/{instance_id}")
669
672
  instance = SyncEnv(client=self.client, **response.json())
670
- # Resources load lazily on first `db()`/`browser()`/`resources()` access.
673
+ instance.instance.load()
671
674
  return instance
672
675
 
673
676
  def _create_url_instance(self, base_url: str) -> SyncEnv:
@@ -1841,6 +1844,8 @@ def _execute_verifier_remote(
1841
1844
  timeout: Optional[int] = 30,
1842
1845
  needs_upload: bool = True,
1843
1846
  verifier_runtime_version: Optional[str] = None,
1847
+ async_: bool = False,
1848
+ poll_interval: float = 5.0,
1844
1849
  ) -> VerifiersExecuteResponse:
1845
1850
  # Pickle args and kwargs together
1846
1851
  # The first arg should be None as a placeholder for env
@@ -1868,6 +1873,11 @@ def _execute_verifier_remote(
1868
1873
  if verifier_runtime_version:
1869
1874
  request_data["verifier_runtime_version"] = verifier_runtime_version
1870
1875
 
1876
+ # Async submit-and-poll path. When async_ is False the behavior below is
1877
+ # identical to the original synchronous request.
1878
+ if async_:
1879
+ request_data["async"] = True
1880
+
1871
1881
  # Debug logging
1872
1882
  # logger.debug(
1873
1883
  # f"Sending verifier execute request: key={key}, sha256={bundle_sha[:8]}..., function_name={function_name}"
@@ -1889,4 +1899,19 @@ def _execute_verifier_remote(
1889
1899
  response_json = response.json()
1890
1900
  # logger.debug(f"Verifier execute response: {response_json}")
1891
1901
 
1892
- return VerifiersExecuteResponse(**response_json)
1902
+ if not async_:
1903
+ return VerifiersExecuteResponse(**response_json)
1904
+
1905
+ # Async: the submit returns a job handle; poll until the job reaches a
1906
+ # terminal state (completed/failed). Branch on `status`, never `success`.
1907
+ job_id = response_json.get("job_id")
1908
+ if not job_id:
1909
+ # No job handle returned (e.g. server ran it inline) - surface as-is.
1910
+ return VerifiersExecuteResponse(**response_json)
1911
+
1912
+ while True:
1913
+ poll_response = client.request("GET", f"/v1/verifiers/jobs/{job_id}")
1914
+ poll_json = poll_response.json()
1915
+ if poll_json.get("status") in ("completed", "failed"):
1916
+ return VerifiersExecuteResponse(**poll_json)
1917
+ time.sleep(poll_interval)
fleet/models.py CHANGED
@@ -52,7 +52,6 @@ class Instance(BaseModel):
52
52
  region: str = Field(..., title="Region")
53
53
  env_variables: Optional[Dict[str, Any]] = Field(None, title="Env Variables")
54
54
  run_id: Optional[str] = Field(None, title="Run Id")
55
- multi_env_list: Optional[List[str]] = Field(None, title="Multi Env List")
56
55
 
57
56
 
58
57
  class InstanceRequest(BaseModel):
@@ -267,6 +266,12 @@ class VerifiersExecuteRequest(BaseModel):
267
266
  display_src: Optional[str] = Field(
268
267
  None, description="Display source code", title="Display Src"
269
268
  )
269
+ async_: Optional[bool] = Field(
270
+ None,
271
+ alias="async",
272
+ description="Submit asynchronously and return a job handle instead of waiting",
273
+ title="Async",
274
+ )
270
275
 
271
276
 
272
277
  class VerifiersExecuteResponse(BaseModel):
@@ -311,6 +316,16 @@ class VerifiersExecuteResponse(BaseModel):
311
316
  stdout: Optional[str] = Field(
312
317
  None, description="Captured stdout from execution", title="Stdout"
313
318
  )
319
+ status: Optional[str] = Field(
320
+ None,
321
+ description="Job status for async execution (pending/running/completed/failed)",
322
+ title="Status",
323
+ )
324
+ job_id: Optional[str] = Field(
325
+ None,
326
+ description="Job handle for async execution; poll GET /v1/verifiers/jobs/{job_id}",
327
+ title="Job Id",
328
+ )
314
329
 
315
330
 
316
331
  class DescribeResponse(BaseModel):
@@ -370,7 +385,6 @@ class InstanceResponse(BaseModel):
370
385
  profile_id: Optional[str] = Field(None, title="Profile Id")
371
386
  heartbeat_interval: Optional[int] = Field(None, title="Heartbeat Interval")
372
387
  heartbeat_region: Optional[str] = Field(None, title="Heartbeat Region")
373
- multi_env_list: Optional[List[str]] = Field(None, title="Multi Env List")
374
388
 
375
389
 
376
390
  class Run(BaseModel):
fleet/tasks.py CHANGED
@@ -83,11 +83,23 @@ class Task(BaseModel):
83
83
  # Allow arbitrary types for the verifier field
84
84
  arbitrary_types_allowed = True
85
85
 
86
- def verify(self, env, *args, **kwargs) -> float:
86
+ def verify(
87
+ self,
88
+ env,
89
+ *args,
90
+ async_: bool = False,
91
+ poll_interval: float = 5.0,
92
+ **kwargs,
93
+ ) -> float:
87
94
  """Verify the task using the verifier function (sync version).
88
95
 
89
96
  For sync environments, calls the sync verifier directly.
90
97
  For async verifiers, automatically runs them with asyncio.run().
98
+
99
+ When ``async_`` is True the verifier is submitted to run in the
100
+ background and polled (every ``poll_interval`` seconds) until it
101
+ completes, avoiding HTTP/edge idle timeouts for long-running
102
+ verifiers. When False the behavior is unchanged.
91
103
  """
92
104
  # If verifier doesn't exist but verifier_func does, rebuild it
93
105
  if not self.verifier and self.verifier_func:
@@ -97,7 +109,9 @@ class Task(BaseModel):
97
109
  import inspect
98
110
 
99
111
  # Check if verifier has remote method (for decorated verifiers)
100
- result = self.verifier.remote(env, *args, **kwargs)
112
+ result = self.verifier.remote(
113
+ env, *args, async_=async_, poll_interval=poll_interval, **kwargs
114
+ )
101
115
 
102
116
  # If the result is a coroutine, we need to run it
103
117
  if inspect.iscoroutine(result):
@@ -117,18 +131,27 @@ class Task(BaseModel):
117
131
  else:
118
132
  raise ValueError("No verifier function found for this task")
119
133
 
120
- def verify_async(self, *args, **kwargs) -> float:
134
+ def verify_async(
135
+ self, *args, async_: bool = False, poll_interval: float = 5.0, **kwargs
136
+ ) -> float:
121
137
  """Verify the task using the verifier function (async version).
122
138
 
123
139
  For async environments, awaits the async verifier.
124
140
  Works with both sync and async verifiers in async contexts.
141
+
142
+ When ``async_`` is True the verifier is submitted to run in the
143
+ background and polled (every ``poll_interval`` seconds) until it
144
+ completes, avoiding HTTP/edge idle timeouts for long-running
145
+ verifiers. When False the behavior is unchanged.
125
146
  """
126
147
  # If verifier doesn't exist but verifier_func does, rebuild it
127
148
  if not self.verifier and self.verifier_func:
128
149
  self._rebuild_verifier()
129
150
 
130
151
  if self.verifier:
131
- result = self.verifier.remote(*args, **kwargs)
152
+ result = self.verifier.remote(
153
+ *args, async_=async_, poll_interval=poll_interval, **kwargs
154
+ )
132
155
  # If it's a coroutine, await it
133
156
  import inspect
134
157
 
@@ -139,11 +162,23 @@ class Task(BaseModel):
139
162
  else:
140
163
  raise ValueError("No verifier function found for this task")
141
164
 
142
- def verify_detailed(self, env, *args, **kwargs) -> "VerifiersExecuteResponse":
165
+ def verify_detailed(
166
+ self,
167
+ env,
168
+ *args,
169
+ async_: bool = False,
170
+ poll_interval: float = 5.0,
171
+ **kwargs,
172
+ ) -> "VerifiersExecuteResponse":
143
173
  """Verify the task and return the full execute response model.
144
174
 
145
175
  For sync environments, calls the sync verifier directly.
146
176
  For async verifiers, automatically runs them with asyncio.run().
177
+
178
+ When ``async_`` is True the verifier is submitted to run in the
179
+ background and polled (every ``poll_interval`` seconds) until it
180
+ completes, avoiding HTTP/edge idle timeouts for long-running
181
+ verifiers. When False the behavior is unchanged.
147
182
  """
148
183
  # If verifier doesn't exist but verifier_func does, rebuild it
149
184
  if not self.verifier and self.verifier_func:
@@ -153,7 +188,9 @@ class Task(BaseModel):
153
188
  import inspect
154
189
 
155
190
  # Check if verifier has remote_with_response method (for decorated verifiers)
156
- result = self.verifier.remote_with_response(env, *args, **kwargs)
191
+ result = self.verifier.remote_with_response(
192
+ env, *args, async_=async_, poll_interval=poll_interval, **kwargs
193
+ )
157
194
 
158
195
  # If the result is a coroutine, we need to run it
159
196
  if inspect.iscoroutine(result):
@@ -173,18 +210,27 @@ class Task(BaseModel):
173
210
  else:
174
211
  raise ValueError("No verifier function found for this task")
175
212
 
176
- def verify_detailed_async(self, *args, **kwargs) -> "VerifiersExecuteResponse":
213
+ def verify_detailed_async(
214
+ self, *args, async_: bool = False, poll_interval: float = 5.0, **kwargs
215
+ ) -> "VerifiersExecuteResponse":
177
216
  """Verify the task and return the full execute response model (async version).
178
217
 
179
218
  For async environments, returns a coroutine that when awaited returns the response.
180
219
  Works with both sync and async verifiers in async contexts.
220
+
221
+ When ``async_`` is True the verifier is submitted to run in the
222
+ background and polled (every ``poll_interval`` seconds) until it
223
+ completes, avoiding HTTP/edge idle timeouts for long-running
224
+ verifiers. When False the behavior is unchanged.
181
225
  """
182
226
  # If verifier doesn't exist but verifier_func does, rebuild it
183
227
  if not self.verifier and self.verifier_func:
184
228
  self._rebuild_verifier()
185
229
 
186
230
  if self.verifier:
187
- result = self.verifier.remote_with_response(*args, **kwargs)
231
+ result = self.verifier.remote_with_response(
232
+ *args, async_=async_, poll_interval=poll_interval, **kwargs
233
+ )
188
234
  # Return the result (could be a coroutine or a value)
189
235
  return result
190
236
  else:
@@ -165,9 +165,25 @@ class SyncVerifierFunction:
165
165
  # Return error score 0
166
166
  return 0.0
167
167
 
168
- def remote(self, env: "SyncEnv", *args, **kwargs) -> float:
169
- """Remote execution of the verifier function with SHA-based bundle caching."""
170
- response = self.remote_with_response(env, *args, **kwargs)
168
+ def remote(
169
+ self,
170
+ env: "SyncEnv",
171
+ *args,
172
+ async_: bool = False,
173
+ poll_interval: float = 5.0,
174
+ **kwargs,
175
+ ) -> float:
176
+ """Remote execution of the verifier function with SHA-based bundle caching.
177
+
178
+ When ``async_`` is True the verifier is submitted to run in the
179
+ background and the result is polled (every ``poll_interval`` seconds)
180
+ until it completes — this avoids HTTP/edge idle timeouts for
181
+ long-running verifiers. When False the behavior is unchanged (the
182
+ request blocks until the verifier finishes).
183
+ """
184
+ response = self.remote_with_response(
185
+ env, *args, async_=async_, poll_interval=poll_interval, **kwargs
186
+ )
171
187
 
172
188
  # Handle response
173
189
  if response.stdout:
@@ -239,9 +255,20 @@ Remote traceback:
239
255
  )
240
256
 
241
257
  def remote_with_response(
242
- self, env: "SyncEnv", *args, **kwargs
258
+ self,
259
+ env: "SyncEnv",
260
+ *args,
261
+ async_: bool = False,
262
+ poll_interval: float = 5.0,
263
+ **kwargs,
243
264
  ) -> "VerifiersExecuteResponse":
244
- """Remote execution of the verifier function that returns the full response model."""
265
+ """Remote execution of the verifier function that returns the full response model.
266
+
267
+ When ``async_`` is True the verifier is submitted asynchronously and
268
+ polled (every ``poll_interval`` seconds) until it reaches a terminal
269
+ state; the returned response is the completed/failed job result. When
270
+ False the request blocks until the verifier finishes (unchanged).
271
+ """
245
272
  args_array = list(args)
246
273
  args_array.append({"env": env.instance_id})
247
274
  args = tuple(args_array)
@@ -265,6 +292,8 @@ Remote traceback:
265
292
  kwargs=kwargs,
266
293
  needs_upload=True,
267
294
  verifier_runtime_version=self.verifier_runtime_version,
295
+ async_=async_,
296
+ poll_interval=poll_interval,
268
297
  )
269
298
 
270
299
  # logger.debug(f"Bundle {bundle_sha[:8]}... uploaded successfully")
@@ -283,6 +312,8 @@ Remote traceback:
283
312
  kwargs=kwargs,
284
313
  needs_upload=False,
285
314
  verifier_runtime_version=self.verifier_runtime_version,
315
+ async_=async_,
316
+ poll_interval=poll_interval,
286
317
  )
287
318
  return response
288
319
 
@@ -303,6 +334,8 @@ Remote traceback:
303
334
  kwargs=kwargs,
304
335
  needs_upload=True,
305
336
  verifier_runtime_version=self.verifier_runtime_version,
337
+ async_=async_,
338
+ poll_interval=poll_interval,
306
339
  )
307
340
  return response
308
341
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fleet-python
3
- Version: 0.2.126
3
+ Version: 0.2.128
4
4
  Summary: Python SDK for Fleet environments
5
5
  Author-email: Fleet AI <nic@fleet.so>
6
6
  License: Apache-2.0
@@ -24,25 +24,25 @@ examples/openai_simple_example.py,sha256=HmiufucrAZne7tHq9uoEsDWlEhjNC265bQAyIGB
24
24
  examples/query_builder_example.py,sha256=-cOMfWGNifYfYEt_Ds73XpwATZvFDL6F4KTkVxdMjzg,3951
25
25
  examples/quickstart.py,sha256=1VT39IRRhemsJgxi0O0gprdpcw7HB4pYO97GAYagIcg,3788
26
26
  examples/test_cdp_logging.py,sha256=AkCwQCgOTQEI8w3v0knWK_4eXMph7L9x07wj9yIYM10,2836
27
- fleet/__init__.py,sha256=-N0S1jb3G3DdT9YTvnx1MHIG6EvnuaYAiGnVgmuPzEE,7977
28
- fleet/base.py,sha256=GNJFLzknbftMyLbMAViPaTf5WPtMBE26Yp4RO2e8TIc,10209
27
+ fleet/__init__.py,sha256=eCbHM32E7To3Q5t7VJsd6sGQ4_WmrTCNdYT8rfjq8d4,7977
28
+ fleet/base.py,sha256=2Y_9_1pJ3gDzgK_hAMrSvmsSKQgpmCEOX0XXTpq6YB4,10209
29
29
  fleet/cli.py,sha256=arX1E-fjLXtcV3tVVkPHfEXxl7FDn4zRmf0ssXlXaMg,40104
30
- fleet/client.py,sha256=lBy0bqHbXbyOoWk_47bsRglVHpOjM6sv-H8sJIhlwm4,69003
30
+ fleet/client.py,sha256=RzUMoP-XsBcvZkQHUnKic5swflcpsAI9mdIGEusB18I,69820
31
31
  fleet/config.py,sha256=n_wh9Sahu3gGE7nHJ7kqNFUH1qDiBtF4bgZq9MvIBMU,319
32
32
  fleet/exceptions.py,sha256=YqhQonZlxGdLP1HD0DNdKs9Q9BuyeYvK3pc6Glhpl14,5352
33
33
  fleet/global_client.py,sha256=frrDAFNM2ywN0JHLtlm9qbE1dQpnQJsavJpb7xSR_bU,1072
34
34
  fleet/judge.py,sha256=c41hAPFMfZvA0LLGPmp6BjaOsIKPf5Wz90UNUvBorRg,35044
35
- fleet/models.py,sha256=3IMbL_BCTSmOKhiVNuguTJ-y4mVrrcGawRd4_ZnFvXc,25329
36
- fleet/tasks.py,sha256=8pEzXmgC7RslqsMC_0s6shhr_t2WGIRpTRqo-MAQjdg,20778
35
+ fleet/models.py,sha256=_HhgxeN563wG8MAHFGnFqzPlZKXRPDY2J1Ipp6Jiea0,25702
36
+ fleet/tasks.py,sha256=7-bXf-H2EpnKMAT7t0XDiAePn6R76vi-OgTlD1bDt6Q,22500
37
37
  fleet/types.py,sha256=L4Y82xICf1tzyCLqhLYUgEoaIIS5h9T05TyFNHSWs3s,652
38
- fleet/_async/__init__.py,sha256=o2YQI5-Ew6CNQDZAtBEzYwcRTFTGNyackKm1KlI9u1I,9116
39
- fleet/_async/base.py,sha256=9tKbiydjwXikc27LLjkY2xkROnMv3YRuwV4QId5B0Yo,9774
40
- fleet/_async/client.py,sha256=AwslVbMmn8CDXswqdNIVuLu-8Kc2fxB5PbggyvHp_1w,65455
38
+ fleet/_async/__init__.py,sha256=8EM5RKgPnzSw9NnaUZwwV-IyMXYHFX4MJTDRpuAdcqk,9116
39
+ fleet/_async/base.py,sha256=OSRe1j7wKhP4LGnjGruQUXU2Qeao7UWx-1CsEJpiAnk,9774
40
+ fleet/_async/client.py,sha256=Tm9et3n-cAa21fdkOp7FFD9xqi5LeuMvZxm8AuAiqnU,66283
41
41
  fleet/_async/exceptions.py,sha256=fUmPwWhnT8SR97lYsRq0kLHQHKtSh2eJS0VQ2caSzEI,5055
42
42
  fleet/_async/global_client.py,sha256=4WskpLHbsDEgWW7hXMD09W-brkp4euy8w2ZJ88594rQ,1103
43
43
  fleet/_async/judge.py,sha256=Ape82WAveHB9ApbslmoiUnuj5KL-DkdQLThUlOsuxgk,6026
44
- fleet/_async/models.py,sha256=6B_Umf9DYToWENHrvt1ExkBt03X0Th11GDNFL7MEldU,13743
45
- fleet/_async/tasks.py,sha256=rlY6SmWl3ZABXe5-ky63wfwYETd2K-Na_m7g5KI1GoI,20602
44
+ fleet/_async/models.py,sha256=MWNyzxEdODDvgngMCEXpTpOoUd6HN0oIt3Oul8aVJ90,14116
45
+ fleet/_async/tasks.py,sha256=r8HPRchH354hUauf3PruMY4i-jqjfwbIfafwrWEFlZo,22310
46
46
  fleet/_async/env/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
47
  fleet/_async/env/client.py,sha256=FqetvDlABeHLaAc8UF_m_2OFEhXy4ZqH7ly_Nh8p3uA,3479
48
48
  fleet/_async/instance/__init__.py,sha256=PtmJq8J8bh0SOQ2V55QURz5GJfobozwtQoqhaOk3_tI,515
@@ -57,7 +57,7 @@ fleet/_async/resources/mcp.py,sha256=TLEsLiFhfVfZFs0Fu_uDPm-h4FPdvqgQblYqs-PTHhc
57
57
  fleet/_async/resources/sqlite.py,sha256=1ej04wsDlTxnmIB5mqRX6qfx-k0pyx01FUzWqTgylRI,106844
58
58
  fleet/_async/verifiers/__init__.py,sha256=1WTlCNq4tIFbbXaQu5Bf2WppZq0A8suhtZbxMTSOwxI,465
59
59
  fleet/_async/verifiers/bundler.py,sha256=9aWWXFsovBPcndE06IATn5jaeli5fRORAYeenF9heN0,26264
60
- fleet/_async/verifiers/verifier.py,sha256=iSa-rO-E1R3IQTFS9Z7jbQvQVtsDkilITQP9IIQU2JA,14556
60
+ fleet/_async/verifiers/verifier.py,sha256=Afy_6pHtxq4kPwAe-ZalCJ8u9fQI7xalIf_uNn_HUhs,15744
61
61
  fleet/agent/__init__.py,sha256=BuiElLoL_OTq_tmEMD85Zc1x3x9iUerYM7TxLpD22aI,737
62
62
  fleet/agent/orchestrator.py,sha256=ciZFctuv_MOmn_IoK021YpDsPLvuG40YLywsX-oA2j4,30308
63
63
  fleet/agent/types.py,sha256=SjJbMju13EPjTPnH7igv860RhCIIKCIQnGEgc8GnHZM,1476
@@ -100,8 +100,8 @@ fleet/verifiers/db.py,sha256=CwuEaH1xpLdzhH3OpP0Fb5PAezIp4WhAMX4Kvo1WcCU,73138
100
100
  fleet/verifiers/decorator.py,sha256=RuTjjDijbicNfMSjA7HcTpKueEki5dzNOdTuHS7UoZs,3262
101
101
  fleet/verifiers/parse.py,sha256=qz9AfJrTbjlg-LU-lE8Ciqi7Yt2a8-cs17FdpjTLhMk,8550
102
102
  fleet/verifiers/sql_differ.py,sha256=TqTLWyK3uOyLbitT6HYzYEzuSFC39wcyhgk3rcm__k8,6525
103
- fleet/verifiers/verifier.py,sha256=iqGevW7dSd0J5RdRQjpu-zioy_FYAXnzMfkuB3-QmO0,14601
104
- fleet_python-0.2.126.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
103
+ fleet/verifiers/verifier.py,sha256=DQ2m90AOEAhgNT2X7wl5NGDJY6NTSkkMsmLNXhOfs-A,15789
104
+ fleet_python-0.2.128.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
105
105
  scripts/fix_sync_imports.py,sha256=X9fWLTpiPGkSHsjyQUDepOJkxOqw1DPj7nd8wFlFqLQ,8368
106
106
  scripts/unasync.py,sha256=vWVQxRWX8SRZO5cmzEhpvnG_REhCWXpidIGIpWmEcvI,696
107
107
  tests/__init__.py,sha256=Re1SdyxH8NfyL1kjhi7SQkGP1mYeWB-D6UALqdIMd8I,35
@@ -112,8 +112,8 @@ tests/test_instance_dispatch.py,sha256=CvU4C3LBIqsYZdEsEFfontGjyxAZfVYyXnGwxyIvX
112
112
  tests/test_sqlite_resource_dual_mode.py,sha256=Mh8jBd-xsIGDYFsOACKKK_5DXMUYlFFS7W-jaY6AjG4,8734
113
113
  tests/test_sqlite_shared_memory_behavior.py,sha256=fKx_1BmLS3b8x-9pMgjMycpnaHWY8P-2ZuXEspx6Sbw,4082
114
114
  tests/test_verifier_from_string.py,sha256=Lxi3TpFHFb-hG4-UhLKZJkqo84ax9YJY8G6beO-1erM,13581
115
- fleet_python-0.2.126.dist-info/METADATA,sha256=gQhrThOnPTJ8uYTQJVfx2eMqpa_hVsfVVQ5FTrgx7sU,4240
116
- fleet_python-0.2.126.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
117
- fleet_python-0.2.126.dist-info/entry_points.txt,sha256=qKIQ326cHR5WyCd16QnrW-1DpcT0YyxVRDb3IlTyzTA,39
118
- fleet_python-0.2.126.dist-info/top_level.txt,sha256=qb1zIbtEktyhRFZdqVytwg54l64qtoZL0wjHB4bUg3c,29
119
- fleet_python-0.2.126.dist-info/RECORD,,
115
+ fleet_python-0.2.128.dist-info/METADATA,sha256=OxrOpgm1103DZCLYDKkkPKCZUQkwlwuZnPOYtBkN8SE,4240
116
+ fleet_python-0.2.128.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
117
+ fleet_python-0.2.128.dist-info/entry_points.txt,sha256=qKIQ326cHR5WyCd16QnrW-1DpcT0YyxVRDb3IlTyzTA,39
118
+ fleet_python-0.2.128.dist-info/top_level.txt,sha256=qb1zIbtEktyhRFZdqVytwg54l64qtoZL0wjHB4bUg3c,29
119
+ fleet_python-0.2.128.dist-info/RECORD,,