fleet-python 0.2.129__tar.gz → 0.2.130__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.
Files changed (127) hide show
  1. {fleet_python-0.2.129/fleet_python.egg-info → fleet_python-0.2.130}/PKG-INFO +1 -1
  2. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/__init__.py +1 -1
  3. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/__init__.py +1 -1
  4. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/base.py +1 -1
  5. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/client.py +6 -0
  6. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/models.py +3 -0
  7. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/tasks.py +36 -6
  8. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/verifiers/verifier.py +11 -1
  9. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/base.py +1 -1
  10. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/client.py +6 -0
  11. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/models.py +3 -0
  12. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/tasks.py +36 -6
  13. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/verifier.py +11 -1
  14. {fleet_python-0.2.129 → fleet_python-0.2.130/fleet_python.egg-info}/PKG-INFO +1 -1
  15. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet_python.egg-info/SOURCES.txt +1 -0
  16. {fleet_python-0.2.129 → fleet_python-0.2.130}/pyproject.toml +1 -1
  17. fleet_python-0.2.130/tests/test_verifier_cost_team.py +198 -0
  18. {fleet_python-0.2.129 → fleet_python-0.2.130}/LICENSE +0 -0
  19. {fleet_python-0.2.129 → fleet_python-0.2.130}/README.md +0 -0
  20. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/diff_example.py +0 -0
  21. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/dsl_example.py +0 -0
  22. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example.py +0 -0
  23. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/exampleResume.py +0 -0
  24. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_account.py +0 -0
  25. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_action_log.py +0 -0
  26. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_client.py +0 -0
  27. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_mcp_anthropic.py +0 -0
  28. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_mcp_openai.py +0 -0
  29. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_sync.py +0 -0
  30. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_task.py +0 -0
  31. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_tasks.py +0 -0
  32. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_verifier.py +0 -0
  33. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/export_tasks.py +0 -0
  34. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/export_tasks_filtered.py +0 -0
  35. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/fetch_tasks.py +0 -0
  36. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/gemini_example.py +0 -0
  37. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/import_tasks.py +0 -0
  38. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/iterate_verifiers.py +0 -0
  39. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/json_tasks_example.py +0 -0
  40. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/nova_act_example.py +0 -0
  41. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/openai_example.py +0 -0
  42. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/openai_simple_example.py +0 -0
  43. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/query_builder_example.py +0 -0
  44. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/quickstart.py +0 -0
  45. {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/test_cdp_logging.py +0 -0
  46. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/browser.py +0 -0
  47. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/env/__init__.py +0 -0
  48. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/env/client.py +0 -0
  49. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/exceptions.py +0 -0
  50. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/global_client.py +0 -0
  51. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/instance/__init__.py +0 -0
  52. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/instance/base.py +0 -0
  53. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/instance/client.py +0 -0
  54. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/judge.py +0 -0
  55. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/__init__.py +0 -0
  56. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/api.py +0 -0
  57. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/base.py +0 -0
  58. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/browser.py +0 -0
  59. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/filesystem.py +0 -0
  60. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/mcp.py +0 -0
  61. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/sqlite.py +0 -0
  62. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/verifiers/__init__.py +0 -0
  63. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/verifiers/bundler.py +0 -0
  64. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/__init__.py +0 -0
  65. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/Dockerfile +0 -0
  66. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/__init__.py +0 -0
  67. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/agent.py +0 -0
  68. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/mcp/main.py +0 -0
  69. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/mcp_server/__init__.py +0 -0
  70. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/mcp_server/main.py +0 -0
  71. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/mcp_server/tools.py +0 -0
  72. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/requirements.txt +0 -0
  73. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/start.sh +0 -0
  74. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/orchestrator.py +0 -0
  75. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/types.py +0 -0
  76. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/utils.py +0 -0
  77. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/browser.py +0 -0
  78. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/cli.py +0 -0
  79. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/config.py +0 -0
  80. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/env/__init__.py +0 -0
  81. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/env/client.py +0 -0
  82. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/eval/__init__.py +0 -0
  83. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/eval/uploader.py +0 -0
  84. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/exceptions.py +0 -0
  85. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/global_client.py +0 -0
  86. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/instance/__init__.py +0 -0
  87. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/instance/base.py +0 -0
  88. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/instance/client.py +0 -0
  89. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/instance/models.py +0 -0
  90. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/judge.py +0 -0
  91. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/proxy/__init__.py +0 -0
  92. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/proxy/proxy.py +0 -0
  93. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/proxy/whitelist.py +0 -0
  94. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/__init__.py +0 -0
  95. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/api.py +0 -0
  96. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/base.py +0 -0
  97. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/browser.py +0 -0
  98. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/filesystem.py +0 -0
  99. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/mcp.py +0 -0
  100. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/sqlite.py +0 -0
  101. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/types.py +0 -0
  102. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/utils/__init__.py +0 -0
  103. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/utils/http_logging.py +0 -0
  104. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/utils/logging.py +0 -0
  105. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/utils/playwright.py +0 -0
  106. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/__init__.py +0 -0
  107. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/bundler.py +0 -0
  108. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/code.py +0 -0
  109. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/db.py +0 -0
  110. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/decorator.py +0 -0
  111. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/parse.py +0 -0
  112. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/sql_differ.py +0 -0
  113. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet_python.egg-info/dependency_links.txt +0 -0
  114. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet_python.egg-info/entry_points.txt +0 -0
  115. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet_python.egg-info/requires.txt +0 -0
  116. {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet_python.egg-info/top_level.txt +0 -0
  117. {fleet_python-0.2.129 → fleet_python-0.2.130}/scripts/fix_sync_imports.py +0 -0
  118. {fleet_python-0.2.129 → fleet_python-0.2.130}/scripts/unasync.py +0 -0
  119. {fleet_python-0.2.129 → fleet_python-0.2.130}/setup.cfg +0 -0
  120. {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/__init__.py +0 -0
  121. {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_app_method.py +0 -0
  122. {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_expect_exactly.py +0 -0
  123. {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_expect_only.py +0 -0
  124. {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_instance_dispatch.py +0 -0
  125. {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_sqlite_resource_dual_mode.py +0 -0
  126. {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_sqlite_shared_memory_behavior.py +0 -0
  127. {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_verifier_from_string.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fleet-python
3
- Version: 0.2.129
3
+ Version: 0.2.130
4
4
  Summary: Python SDK for Fleet environments
5
5
  Author-email: Fleet AI <nic@fleet.so>
6
6
  License: Apache-2.0
@@ -78,7 +78,7 @@ from . import env
78
78
  from . import global_client as _global_client
79
79
  from ._async import global_client as _async_global_client
80
80
 
81
- __version__ = "0.2.129"
81
+ __version__ = "0.2.130"
82
82
 
83
83
  __all__ = [
84
84
  # Core classes
@@ -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.129"
47
+ __version__ = "0.2.130"
48
48
 
49
49
  __all__ = [
50
50
  # Core classes
@@ -26,7 +26,7 @@ from .exceptions import (
26
26
  try:
27
27
  from .. import __version__
28
28
  except ImportError:
29
- __version__ = "0.2.129"
29
+ __version__ = "0.2.130"
30
30
 
31
31
  logger = logging.getLogger(__name__)
32
32
 
@@ -532,6 +532,7 @@ class AsyncEnv(EnvironmentBase):
532
532
  verifier_runtime_version: Optional[str] = None,
533
533
  async_: bool = False,
534
534
  poll_interval: float = 5.0,
535
+ cost_team_id: Optional[str] = None,
535
536
  ) -> VerifiersExecuteResponse:
536
537
  return await _execute_verifier_remote(
537
538
  self._load_client,
@@ -547,6 +548,7 @@ class AsyncEnv(EnvironmentBase):
547
548
  verifier_runtime_version,
548
549
  async_=async_,
549
550
  poll_interval=poll_interval,
551
+ cost_team_id=cost_team_id,
550
552
  )
551
553
 
552
554
  def __getstate__(self):
@@ -1820,6 +1822,7 @@ async def _execute_verifier_remote(
1820
1822
  verifier_runtime_version: Optional[str] = None,
1821
1823
  async_: bool = False,
1822
1824
  poll_interval: float = 5.0,
1825
+ cost_team_id: Optional[str] = None,
1823
1826
  ) -> VerifiersExecuteResponse:
1824
1827
  # Pickle args and kwargs together
1825
1828
  # The first arg should be None as a placeholder for env
@@ -1847,6 +1850,9 @@ async def _execute_verifier_remote(
1847
1850
  if verifier_runtime_version:
1848
1851
  request_data["verifier_runtime_version"] = verifier_runtime_version
1849
1852
 
1853
+ if cost_team_id is not None:
1854
+ request_data["cost_team_id"] = cost_team_id
1855
+
1850
1856
  # Async submit-and-poll path. When async_ is False the behavior below is
1851
1857
  # identical to the original synchronous request.
1852
1858
  if async_:
@@ -222,6 +222,9 @@ class VerifiersCheckResponse(BaseModel):
222
222
 
223
223
 
224
224
  class VerifiersExecuteRequest(BaseModel):
225
+ cost_team_id: Optional[str] = Field(
226
+ None, description="Team to attribute verifier costs to", title="Cost Team Id"
227
+ )
225
228
  key: Optional[str] = Field(
226
229
  None, description="Key of the verifier artifact", title="Key"
227
230
  )
@@ -85,6 +85,7 @@ class Task(BaseModel):
85
85
  self,
86
86
  env,
87
87
  *args,
88
+ cost_team_id: Optional[str] = None,
88
89
  async_: bool = False,
89
90
  poll_interval: float = 5.0,
90
91
  **kwargs,
@@ -108,7 +109,12 @@ class Task(BaseModel):
108
109
  import inspect
109
110
 
110
111
  result = self.verifier.remote(
111
- env, *args, async_=async_, poll_interval=poll_interval, **kwargs
112
+ env,
113
+ *args,
114
+ cost_team_id=cost_team_id,
115
+ async_=async_,
116
+ poll_interval=poll_interval,
117
+ **kwargs,
112
118
  )
113
119
 
114
120
  # If the result is a coroutine, we need to run it
@@ -130,7 +136,12 @@ class Task(BaseModel):
130
136
  raise ValueError("No verifier function found for this task")
131
137
 
132
138
  async def verify_async(
133
- self, *args, async_: bool = False, poll_interval: float = 5.0, **kwargs
139
+ self,
140
+ *args,
141
+ cost_team_id: Optional[str] = None,
142
+ async_: bool = False,
143
+ poll_interval: float = 5.0,
144
+ **kwargs,
134
145
  ) -> float:
135
146
  """Verify the task using the verifier function (async version).
136
147
 
@@ -148,7 +159,11 @@ class Task(BaseModel):
148
159
 
149
160
  if self.verifier:
150
161
  result = self.verifier.remote(
151
- *args, async_=async_, poll_interval=poll_interval, **kwargs
162
+ *args,
163
+ cost_team_id=cost_team_id,
164
+ async_=async_,
165
+ poll_interval=poll_interval,
166
+ **kwargs,
152
167
  )
153
168
  # If it's a coroutine, await it
154
169
  import inspect
@@ -161,7 +176,12 @@ class Task(BaseModel):
161
176
  raise ValueError("No verifier function found for this task")
162
177
 
163
178
  async def verify_detailed_async(
164
- self, *args, async_: bool = False, poll_interval: float = 5.0, **kwargs
179
+ self,
180
+ *args,
181
+ cost_team_id: Optional[str] = None,
182
+ async_: bool = False,
183
+ poll_interval: float = 5.0,
184
+ **kwargs,
165
185
  ) -> "VerifiersExecuteResponse":
166
186
  """Verify the task and return the full execute response model.
167
187
 
@@ -179,7 +199,11 @@ class Task(BaseModel):
179
199
 
180
200
  if self.verifier:
181
201
  result = self.verifier.remote_with_response(
182
- *args, async_=async_, poll_interval=poll_interval, **kwargs
202
+ *args,
203
+ cost_team_id=cost_team_id,
204
+ async_=async_,
205
+ poll_interval=poll_interval,
206
+ **kwargs,
183
207
  )
184
208
  # If it's a coroutine, await it
185
209
  import inspect
@@ -195,6 +219,7 @@ class Task(BaseModel):
195
219
  self,
196
220
  env,
197
221
  *args,
222
+ cost_team_id: Optional[str] = None,
198
223
  async_: bool = False,
199
224
  poll_interval: float = 5.0,
200
225
  **kwargs,
@@ -219,7 +244,12 @@ class Task(BaseModel):
219
244
 
220
245
  # Check if verifier has remote_with_response method (for decorated verifiers)
221
246
  result = self.verifier.remote_with_response(
222
- env, *args, async_=async_, poll_interval=poll_interval, **kwargs
247
+ env,
248
+ *args,
249
+ cost_team_id=cost_team_id,
250
+ async_=async_,
251
+ poll_interval=poll_interval,
252
+ **kwargs,
223
253
  )
224
254
 
225
255
  # If the result is a coroutine, we need to run it
@@ -158,6 +158,7 @@ class AsyncVerifierFunction:
158
158
  self,
159
159
  env: AsyncEnv,
160
160
  *args,
161
+ cost_team_id: Optional[str] = None,
161
162
  async_: bool = False,
162
163
  poll_interval: float = 5.0,
163
164
  **kwargs,
@@ -171,7 +172,12 @@ class AsyncVerifierFunction:
171
172
  request blocks until the verifier finishes).
172
173
  """
173
174
  response = await self.remote_with_response(
174
- env, *args, async_=async_, poll_interval=poll_interval, **kwargs
175
+ env,
176
+ *args,
177
+ cost_team_id=cost_team_id,
178
+ async_=async_,
179
+ poll_interval=poll_interval,
180
+ **kwargs,
175
181
  )
176
182
 
177
183
  # Handle response
@@ -247,6 +253,7 @@ Remote traceback:
247
253
  self,
248
254
  env: "AsyncEnv",
249
255
  *args,
256
+ cost_team_id: Optional[str] = None,
250
257
  async_: bool = False,
251
258
  poll_interval: float = 5.0,
252
259
  **kwargs,
@@ -281,6 +288,7 @@ Remote traceback:
281
288
  kwargs=kwargs,
282
289
  needs_upload=True,
283
290
  verifier_runtime_version=self.verifier_runtime_version,
291
+ cost_team_id=cost_team_id,
284
292
  async_=async_,
285
293
  poll_interval=poll_interval,
286
294
  )
@@ -300,6 +308,7 @@ Remote traceback:
300
308
  kwargs=kwargs,
301
309
  needs_upload=False,
302
310
  verifier_runtime_version=self.verifier_runtime_version,
311
+ cost_team_id=cost_team_id,
303
312
  async_=async_,
304
313
  poll_interval=poll_interval,
305
314
  )
@@ -323,6 +332,7 @@ Remote traceback:
323
332
  kwargs=kwargs,
324
333
  needs_upload=True,
325
334
  verifier_runtime_version=self.verifier_runtime_version,
335
+ cost_team_id=cost_team_id,
326
336
  async_=async_,
327
337
  poll_interval=poll_interval,
328
338
  )
@@ -27,7 +27,7 @@ from .exceptions import (
27
27
  try:
28
28
  from . import __version__
29
29
  except ImportError:
30
- __version__ = "0.2.129"
30
+ __version__ = "0.2.130"
31
31
 
32
32
  logger = logging.getLogger(__name__)
33
33
 
@@ -545,6 +545,7 @@ class SyncEnv(EnvironmentBase):
545
545
  verifier_runtime_version: Optional[str] = None,
546
546
  async_: bool = False,
547
547
  poll_interval: float = 5.0,
548
+ cost_team_id: Optional[str] = None,
548
549
  ) -> VerifiersExecuteResponse:
549
550
  return _execute_verifier_remote(
550
551
  self._load_client,
@@ -560,6 +561,7 @@ class SyncEnv(EnvironmentBase):
560
561
  verifier_runtime_version,
561
562
  async_=async_,
562
563
  poll_interval=poll_interval,
564
+ cost_team_id=cost_team_id,
563
565
  )
564
566
 
565
567
  def __getstate__(self):
@@ -1940,6 +1942,7 @@ def _execute_verifier_remote(
1940
1942
  verifier_runtime_version: Optional[str] = None,
1941
1943
  async_: bool = False,
1942
1944
  poll_interval: float = 5.0,
1945
+ cost_team_id: Optional[str] = None,
1943
1946
  ) -> VerifiersExecuteResponse:
1944
1947
  # Pickle args and kwargs together
1945
1948
  # The first arg should be None as a placeholder for env
@@ -1967,6 +1970,9 @@ def _execute_verifier_remote(
1967
1970
  if verifier_runtime_version:
1968
1971
  request_data["verifier_runtime_version"] = verifier_runtime_version
1969
1972
 
1973
+ if cost_team_id is not None:
1974
+ request_data["cost_team_id"] = cost_team_id
1975
+
1970
1976
  # Async submit-and-poll path. When async_ is False the behavior below is
1971
1977
  # identical to the original synchronous request.
1972
1978
  if async_:
@@ -230,6 +230,9 @@ class VerifiersCheckResponse(BaseModel):
230
230
 
231
231
 
232
232
  class VerifiersExecuteRequest(BaseModel):
233
+ cost_team_id: Optional[str] = Field(
234
+ None, description="Team to attribute verifier costs to", title="Cost Team Id"
235
+ )
233
236
  key: Optional[str] = Field(
234
237
  None, description="Key of the verifier artifact", title="Key"
235
238
  )
@@ -87,6 +87,7 @@ class Task(BaseModel):
87
87
  self,
88
88
  env,
89
89
  *args,
90
+ cost_team_id: Optional[str] = None,
90
91
  async_: bool = False,
91
92
  poll_interval: float = 5.0,
92
93
  **kwargs,
@@ -110,7 +111,12 @@ class Task(BaseModel):
110
111
 
111
112
  # Check if verifier has remote method (for decorated verifiers)
112
113
  result = self.verifier.remote(
113
- env, *args, async_=async_, poll_interval=poll_interval, **kwargs
114
+ env,
115
+ *args,
116
+ cost_team_id=cost_team_id,
117
+ async_=async_,
118
+ poll_interval=poll_interval,
119
+ **kwargs,
114
120
  )
115
121
 
116
122
  # If the result is a coroutine, we need to run it
@@ -132,7 +138,12 @@ class Task(BaseModel):
132
138
  raise ValueError("No verifier function found for this task")
133
139
 
134
140
  def verify_async(
135
- self, *args, async_: bool = False, poll_interval: float = 5.0, **kwargs
141
+ self,
142
+ *args,
143
+ cost_team_id: Optional[str] = None,
144
+ async_: bool = False,
145
+ poll_interval: float = 5.0,
146
+ **kwargs,
136
147
  ) -> float:
137
148
  """Verify the task using the verifier function (async version).
138
149
 
@@ -150,7 +161,11 @@ class Task(BaseModel):
150
161
 
151
162
  if self.verifier:
152
163
  result = self.verifier.remote(
153
- *args, async_=async_, poll_interval=poll_interval, **kwargs
164
+ *args,
165
+ cost_team_id=cost_team_id,
166
+ async_=async_,
167
+ poll_interval=poll_interval,
168
+ **kwargs,
154
169
  )
155
170
  # If it's a coroutine, await it
156
171
  import inspect
@@ -166,6 +181,7 @@ class Task(BaseModel):
166
181
  self,
167
182
  env,
168
183
  *args,
184
+ cost_team_id: Optional[str] = None,
169
185
  async_: bool = False,
170
186
  poll_interval: float = 5.0,
171
187
  **kwargs,
@@ -189,7 +205,12 @@ class Task(BaseModel):
189
205
 
190
206
  # Check if verifier has remote_with_response method (for decorated verifiers)
191
207
  result = self.verifier.remote_with_response(
192
- env, *args, async_=async_, poll_interval=poll_interval, **kwargs
208
+ env,
209
+ *args,
210
+ cost_team_id=cost_team_id,
211
+ async_=async_,
212
+ poll_interval=poll_interval,
213
+ **kwargs,
193
214
  )
194
215
 
195
216
  # If the result is a coroutine, we need to run it
@@ -211,7 +232,12 @@ class Task(BaseModel):
211
232
  raise ValueError("No verifier function found for this task")
212
233
 
213
234
  def verify_detailed_async(
214
- self, *args, async_: bool = False, poll_interval: float = 5.0, **kwargs
235
+ self,
236
+ *args,
237
+ cost_team_id: Optional[str] = None,
238
+ async_: bool = False,
239
+ poll_interval: float = 5.0,
240
+ **kwargs,
215
241
  ) -> "VerifiersExecuteResponse":
216
242
  """Verify the task and return the full execute response model (async version).
217
243
 
@@ -229,7 +255,11 @@ class Task(BaseModel):
229
255
 
230
256
  if self.verifier:
231
257
  result = self.verifier.remote_with_response(
232
- *args, async_=async_, poll_interval=poll_interval, **kwargs
258
+ *args,
259
+ cost_team_id=cost_team_id,
260
+ async_=async_,
261
+ poll_interval=poll_interval,
262
+ **kwargs,
233
263
  )
234
264
  # Return the result (could be a coroutine or a value)
235
265
  return result
@@ -169,6 +169,7 @@ class SyncVerifierFunction:
169
169
  self,
170
170
  env: "SyncEnv",
171
171
  *args,
172
+ cost_team_id: Optional[str] = None,
172
173
  async_: bool = False,
173
174
  poll_interval: float = 5.0,
174
175
  **kwargs,
@@ -182,7 +183,12 @@ class SyncVerifierFunction:
182
183
  request blocks until the verifier finishes).
183
184
  """
184
185
  response = self.remote_with_response(
185
- env, *args, async_=async_, poll_interval=poll_interval, **kwargs
186
+ env,
187
+ *args,
188
+ cost_team_id=cost_team_id,
189
+ async_=async_,
190
+ poll_interval=poll_interval,
191
+ **kwargs,
186
192
  )
187
193
 
188
194
  # Handle response
@@ -258,6 +264,7 @@ Remote traceback:
258
264
  self,
259
265
  env: "SyncEnv",
260
266
  *args,
267
+ cost_team_id: Optional[str] = None,
261
268
  async_: bool = False,
262
269
  poll_interval: float = 5.0,
263
270
  **kwargs,
@@ -292,6 +299,7 @@ Remote traceback:
292
299
  kwargs=kwargs,
293
300
  needs_upload=True,
294
301
  verifier_runtime_version=self.verifier_runtime_version,
302
+ cost_team_id=cost_team_id,
295
303
  async_=async_,
296
304
  poll_interval=poll_interval,
297
305
  )
@@ -312,6 +320,7 @@ Remote traceback:
312
320
  kwargs=kwargs,
313
321
  needs_upload=False,
314
322
  verifier_runtime_version=self.verifier_runtime_version,
323
+ cost_team_id=cost_team_id,
315
324
  async_=async_,
316
325
  poll_interval=poll_interval,
317
326
  )
@@ -334,6 +343,7 @@ Remote traceback:
334
343
  kwargs=kwargs,
335
344
  needs_upload=True,
336
345
  verifier_runtime_version=self.verifier_runtime_version,
346
+ cost_team_id=cost_team_id,
337
347
  async_=async_,
338
348
  poll_interval=poll_interval,
339
349
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fleet-python
3
- Version: 0.2.129
3
+ Version: 0.2.130
4
4
  Summary: Python SDK for Fleet environments
5
5
  Author-email: Fleet AI <nic@fleet.so>
6
6
  License: Apache-2.0
@@ -121,4 +121,5 @@ tests/test_expect_only.py
121
121
  tests/test_instance_dispatch.py
122
122
  tests/test_sqlite_resource_dual_mode.py
123
123
  tests/test_sqlite_shared_memory_behavior.py
124
+ tests/test_verifier_cost_team.py
124
125
  tests/test_verifier_from_string.py
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "fleet-python"
7
7
 
8
- version = "0.2.129"
8
+ version = "0.2.130"
9
9
  description = "Python SDK for Fleet environments"
10
10
  authors = [
11
11
  {name = "Fleet AI", email = "nic@fleet.so"},
@@ -0,0 +1,198 @@
1
+ from types import SimpleNamespace
2
+
3
+ import pytest
4
+
5
+ from fleet._async.client import _execute_verifier_remote as execute_async
6
+ from fleet._async.verifiers.verifier import AsyncVerifierFunction
7
+ from fleet.client import _execute_verifier_remote as execute_sync
8
+ from fleet.verifiers.verifier import SyncVerifierFunction
9
+
10
+
11
+ TEAM_ID = "11111111-2222-3333-4444-555555555555"
12
+ EXECUTE_RESPONSE = {"success": True, "execution_time_ms": 1}
13
+
14
+
15
+ class AsyncClientStub:
16
+ def __init__(self):
17
+ self.request_json = None
18
+
19
+ async def request(self, method, path, *, json):
20
+ assert (method, path) == ("POST", "/v1/verifiers/execute")
21
+ self.request_json = json
22
+ return SimpleNamespace(json=lambda: EXECUTE_RESPONSE)
23
+
24
+
25
+ class SyncClientStub:
26
+ def __init__(self):
27
+ self.request_json = None
28
+
29
+ def request(self, method, path, *, json):
30
+ assert (method, path) == ("POST", "/v1/verifiers/execute")
31
+ self.request_json = json
32
+ return SimpleNamespace(json=lambda: EXECUTE_RESPONSE)
33
+
34
+
35
+ @pytest.mark.asyncio
36
+ async def test_async_execute_sends_cost_team_id_as_request_metadata():
37
+ client = AsyncClientStub()
38
+
39
+ await execute_async(
40
+ client,
41
+ bundle_data=b"",
42
+ bundle_sha="sha",
43
+ key="key",
44
+ function_name="verify",
45
+ args=(),
46
+ args_array=[],
47
+ kwargs={"final_answer": "done"},
48
+ needs_upload=False,
49
+ cost_team_id=TEAM_ID,
50
+ )
51
+
52
+ assert client.request_json["cost_team_id"] == TEAM_ID
53
+
54
+
55
+ def test_sync_execute_sends_cost_team_id_as_request_metadata():
56
+ client = SyncClientStub()
57
+
58
+ execute_sync(
59
+ client,
60
+ bundle_data=b"",
61
+ bundle_sha="sha",
62
+ key="key",
63
+ function_name="verify",
64
+ args=(),
65
+ args_array=[],
66
+ kwargs={"final_answer": "done"},
67
+ needs_upload=False,
68
+ cost_team_id=TEAM_ID,
69
+ )
70
+
71
+ assert client.request_json["cost_team_id"] == TEAM_ID
72
+
73
+
74
+ @pytest.mark.asyncio
75
+ async def test_async_verifier_keeps_cost_team_id_out_of_function_kwargs(monkeypatch):
76
+ verifier = AsyncVerifierFunction(lambda env, **kwargs: 1.0, key="key")
77
+
78
+ async def bundle_status(_env):
79
+ return "sha", False
80
+
81
+ monkeypatch.setattr(verifier, "_check_bundle_status", bundle_status)
82
+ captured = {}
83
+
84
+ class EnvStub:
85
+ instance_id = "instance"
86
+
87
+ async def execute_verifier_remote(self, **kwargs):
88
+ captured.update(kwargs)
89
+ return EXECUTE_RESPONSE
90
+
91
+ await verifier.remote_with_response(
92
+ EnvStub(), final_answer="done", cost_team_id=TEAM_ID
93
+ )
94
+
95
+ assert captured["cost_team_id"] == TEAM_ID
96
+ assert captured["kwargs"] == {"final_answer": "done"}
97
+
98
+
99
+ def test_sync_verifier_keeps_cost_team_id_out_of_function_kwargs(monkeypatch):
100
+ verifier = SyncVerifierFunction(lambda env, **kwargs: 1.0, key="key")
101
+ monkeypatch.setattr(verifier, "_check_bundle_status", lambda _env: ("sha", False))
102
+ captured = {}
103
+
104
+ class EnvStub:
105
+ instance_id = "instance"
106
+
107
+ def execute_verifier_remote(self, **kwargs):
108
+ captured.update(kwargs)
109
+ return EXECUTE_RESPONSE
110
+
111
+ verifier.remote_with_response(EnvStub(), final_answer="done", cost_team_id=TEAM_ID)
112
+
113
+ assert captured["cost_team_id"] == TEAM_ID
114
+ assert captured["kwargs"] == {"final_answer": "done"}
115
+
116
+
117
+ @pytest.mark.asyncio
118
+ async def test_async_execute_omits_cost_team_id_when_unspecified():
119
+ client = AsyncClientStub()
120
+
121
+ await execute_async(
122
+ client,
123
+ bundle_data=b"",
124
+ bundle_sha="sha",
125
+ key="key",
126
+ function_name="verify",
127
+ args=(),
128
+ args_array=[],
129
+ kwargs={},
130
+ needs_upload=False,
131
+ )
132
+
133
+ assert "cost_team_id" not in client.request_json
134
+
135
+
136
+ def test_sync_execute_omits_cost_team_id_when_unspecified():
137
+ client = SyncClientStub()
138
+
139
+ execute_sync(
140
+ client,
141
+ bundle_data=b"",
142
+ bundle_sha="sha",
143
+ key="key",
144
+ function_name="verify",
145
+ args=(),
146
+ args_array=[],
147
+ kwargs={},
148
+ needs_upload=False,
149
+ )
150
+
151
+ assert "cost_team_id" not in client.request_json
152
+
153
+
154
+ @pytest.mark.asyncio
155
+ async def test_async_execute_preserves_existing_positional_async_arguments():
156
+ client = AsyncClientStub()
157
+
158
+ await execute_async(
159
+ client,
160
+ b"",
161
+ "sha",
162
+ "key",
163
+ "verify",
164
+ (),
165
+ [],
166
+ {},
167
+ 30,
168
+ False,
169
+ None,
170
+ True,
171
+ 0.01,
172
+ )
173
+
174
+ assert client.request_json["async"] is True
175
+ assert "cost_team_id" not in client.request_json
176
+
177
+
178
+ def test_sync_execute_preserves_existing_positional_async_arguments():
179
+ client = SyncClientStub()
180
+
181
+ execute_sync(
182
+ client,
183
+ b"",
184
+ "sha",
185
+ "key",
186
+ "verify",
187
+ (),
188
+ [],
189
+ {},
190
+ 30,
191
+ False,
192
+ None,
193
+ True,
194
+ 0.01,
195
+ )
196
+
197
+ assert client.request_json["async"] is True
198
+ assert "cost_team_id" not in client.request_json
File without changes
File without changes
File without changes