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.
- {fleet_python-0.2.129/fleet_python.egg-info → fleet_python-0.2.130}/PKG-INFO +1 -1
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/__init__.py +1 -1
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/__init__.py +1 -1
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/base.py +1 -1
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/client.py +6 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/models.py +3 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/tasks.py +36 -6
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/verifiers/verifier.py +11 -1
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/base.py +1 -1
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/client.py +6 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/models.py +3 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/tasks.py +36 -6
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/verifier.py +11 -1
- {fleet_python-0.2.129 → fleet_python-0.2.130/fleet_python.egg-info}/PKG-INFO +1 -1
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet_python.egg-info/SOURCES.txt +1 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/pyproject.toml +1 -1
- fleet_python-0.2.130/tests/test_verifier_cost_team.py +198 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/LICENSE +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/README.md +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/diff_example.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/dsl_example.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/exampleResume.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_account.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_action_log.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_client.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_mcp_anthropic.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_mcp_openai.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_sync.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_task.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_tasks.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/example_verifier.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/export_tasks.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/export_tasks_filtered.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/fetch_tasks.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/gemini_example.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/import_tasks.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/iterate_verifiers.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/json_tasks_example.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/nova_act_example.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/openai_example.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/openai_simple_example.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/query_builder_example.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/quickstart.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/examples/test_cdp_logging.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/browser.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/env/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/env/client.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/exceptions.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/global_client.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/instance/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/instance/base.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/instance/client.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/judge.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/api.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/base.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/browser.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/filesystem.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/mcp.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/resources/sqlite.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/verifiers/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/_async/verifiers/bundler.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/Dockerfile +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/agent.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/mcp/main.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/mcp_server/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/mcp_server/main.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/mcp_server/tools.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/requirements.txt +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/gemini_cua/start.sh +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/orchestrator.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/types.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/agent/utils.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/browser.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/cli.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/config.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/env/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/env/client.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/eval/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/eval/uploader.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/exceptions.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/global_client.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/instance/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/instance/base.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/instance/client.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/instance/models.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/judge.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/proxy/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/proxy/proxy.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/proxy/whitelist.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/api.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/base.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/browser.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/filesystem.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/mcp.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/resources/sqlite.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/types.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/utils/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/utils/http_logging.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/utils/logging.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/utils/playwright.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/bundler.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/code.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/db.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/decorator.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/parse.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet/verifiers/sql_differ.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet_python.egg-info/dependency_links.txt +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet_python.egg-info/entry_points.txt +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet_python.egg-info/requires.txt +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/fleet_python.egg-info/top_level.txt +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/scripts/fix_sync_imports.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/scripts/unasync.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/setup.cfg +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/__init__.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_app_method.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_expect_exactly.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_expect_only.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_instance_dispatch.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_sqlite_resource_dual_mode.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_sqlite_shared_memory_behavior.py +0 -0
- {fleet_python-0.2.129 → fleet_python-0.2.130}/tests/test_verifier_from_string.py +0 -0
|
@@ -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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
)
|
|
@@ -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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
)
|
|
@@ -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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|