fleet-python 0.2.66b4__tar.gz → 0.2.68__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fleet-python might be problematic. Click here for more details.
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/PKG-INFO +1 -1
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/export_tasks.py +11 -1
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/import_tasks.py +15 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/client.py +36 -3
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/env/client.py +29 -3
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/models.py +3 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/tasks.py +44 -26
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/client.py +36 -3
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/env/__init__.py +8 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/env/client.py +29 -3
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/models.py +5 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/tasks.py +39 -25
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet_python.egg-info/PKG-INFO +1 -1
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet_python.egg-info/SOURCES.txt +1 -3
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/pyproject.toml +1 -1
- fleet_python-0.2.66b4/fleet/verifiers/parsing.py +0 -106
- fleet_python-0.2.66b4/tests/test_verifier_security.py +0 -427
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/LICENSE +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/README.md +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/diff_example.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/dsl_example.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/example.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/exampleResume.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/example_account.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/example_action_log.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/example_client.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/example_mcp_anthropic.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/example_mcp_openai.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/example_sync.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/example_task.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/example_tasks.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/example_verifier.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/gemini_example.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/json_tasks_example.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/nova_act_example.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/openai_example.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/openai_simple_example.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/query_builder_example.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/quickstart.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/examples/test_cdp_logging.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/__init__.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/__init__.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/base.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/env/__init__.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/exceptions.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/global_client.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/instance/__init__.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/instance/base.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/instance/client.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/resources/__init__.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/resources/base.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/resources/browser.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/resources/mcp.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/resources/sqlite.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/verifiers/__init__.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/verifiers/bundler.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/_async/verifiers/verifier.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/base.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/config.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/exceptions.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/global_client.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/instance/__init__.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/instance/base.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/instance/client.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/instance/models.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/resources/__init__.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/resources/base.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/resources/browser.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/resources/mcp.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/resources/sqlite.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/types.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/verifiers/__init__.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/verifiers/bundler.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/verifiers/code.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/verifiers/db.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/verifiers/decorator.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/verifiers/parse.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/verifiers/sql_differ.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet/verifiers/verifier.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet_python.egg-info/dependency_links.txt +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet_python.egg-info/requires.txt +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/fleet_python.egg-info/top_level.txt +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/scripts/fix_sync_imports.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/scripts/unasync.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/setup.cfg +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/tests/__init__.py +0 -0
- {fleet_python-0.2.66b4 → fleet_python-0.2.68}/tests/test_verifier_from_string.py +0 -0
|
@@ -27,6 +27,12 @@ def main():
|
|
|
27
27
|
help="Optional task project key to filter tasks",
|
|
28
28
|
default=None,
|
|
29
29
|
)
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--env-key",
|
|
32
|
+
"-e",
|
|
33
|
+
help="Optional environment key to filter tasks",
|
|
34
|
+
default=None,
|
|
35
|
+
)
|
|
30
36
|
parser.add_argument(
|
|
31
37
|
"--output",
|
|
32
38
|
"-o",
|
|
@@ -42,12 +48,13 @@ def main():
|
|
|
42
48
|
args.project_key is not None,
|
|
43
49
|
args.task_keys is not None,
|
|
44
50
|
args.task_project_key is not None,
|
|
51
|
+
args.env_key is not None,
|
|
45
52
|
]
|
|
46
53
|
)
|
|
47
54
|
|
|
48
55
|
if filters_specified > 1:
|
|
49
56
|
parser.error(
|
|
50
|
-
"Cannot specify multiple filters. Use only one of --project-key, --task-keys,
|
|
57
|
+
"Cannot specify multiple filters. Use only one of --project-key, --task-keys, --task-project-key, or --env-key."
|
|
51
58
|
)
|
|
52
59
|
|
|
53
60
|
# Get account info
|
|
@@ -66,6 +73,9 @@ def main():
|
|
|
66
73
|
elif args.task_project_key:
|
|
67
74
|
print(f"Loading tasks from task project: {args.task_project_key}")
|
|
68
75
|
tasks = fleet.load_tasks(task_project_key=args.task_project_key)
|
|
76
|
+
elif args.env_key:
|
|
77
|
+
print(f"Loading tasks from environment: {args.env_key}")
|
|
78
|
+
tasks = fleet.load_tasks(env_key=args.env_key)
|
|
69
79
|
else:
|
|
70
80
|
print("Loading all tasks")
|
|
71
81
|
tasks = fleet.load_tasks()
|
|
@@ -210,9 +210,18 @@ async def main():
|
|
|
210
210
|
action="store_true",
|
|
211
211
|
help="Skip the verifier sanity check (not recommended)",
|
|
212
212
|
)
|
|
213
|
+
parser.add_argument(
|
|
214
|
+
"--sanity-check-only",
|
|
215
|
+
action="store_true",
|
|
216
|
+
help="Only run the sanity check without importing tasks",
|
|
217
|
+
)
|
|
213
218
|
|
|
214
219
|
args = parser.parse_args()
|
|
215
220
|
|
|
221
|
+
# Validate conflicting flags
|
|
222
|
+
if args.skip_sanity_check and args.sanity_check_only:
|
|
223
|
+
parser.error("Cannot use --skip-sanity-check and --sanity-check-only together")
|
|
224
|
+
|
|
216
225
|
# Load and parse the JSON file
|
|
217
226
|
try:
|
|
218
227
|
with open(args.json_file, "r", encoding="utf-8") as f:
|
|
@@ -286,6 +295,12 @@ async def main():
|
|
|
286
295
|
success, errors = await run_verifier_sanity_check(tasks, client)
|
|
287
296
|
if not success:
|
|
288
297
|
sys.exit(1)
|
|
298
|
+
|
|
299
|
+
# If only doing sanity check, exit successfully here
|
|
300
|
+
if args.sanity_check_only:
|
|
301
|
+
print("\n✓ Sanity check complete! (--sanity-check-only)")
|
|
302
|
+
print("Tasks are ready to import.")
|
|
303
|
+
sys.exit(0)
|
|
289
304
|
else:
|
|
290
305
|
print("\n⚠️ Skipping sanity check (--skip-sanity-check)")
|
|
291
306
|
|
|
@@ -212,6 +212,7 @@ class AsyncFleet:
|
|
|
212
212
|
env_variables: Optional[Dict[str, Any]] = None,
|
|
213
213
|
image_type: Optional[str] = None,
|
|
214
214
|
ttl_seconds: Optional[int] = None,
|
|
215
|
+
run_id: Optional[str] = None,
|
|
215
216
|
) -> AsyncEnv:
|
|
216
217
|
if ":" in env_key:
|
|
217
218
|
env_key_part, env_version = env_key.split(":", 1)
|
|
@@ -247,6 +248,7 @@ class AsyncFleet:
|
|
|
247
248
|
image_type=image_type,
|
|
248
249
|
created_from="sdk",
|
|
249
250
|
ttl_seconds=ttl_seconds,
|
|
251
|
+
run_id=run_id,
|
|
250
252
|
)
|
|
251
253
|
|
|
252
254
|
# Only use region-specific base URL if no custom base URL is set
|
|
@@ -269,13 +271,15 @@ class AsyncFleet:
|
|
|
269
271
|
return await self.make(env_key=f"{task.env_id}:{task.version}")
|
|
270
272
|
|
|
271
273
|
async def instances(
|
|
272
|
-
self, status: Optional[str] = None, region: Optional[str] = None
|
|
274
|
+
self, status: Optional[str] = None, region: Optional[str] = None, run_id: Optional[str] = None
|
|
273
275
|
) -> List[AsyncEnv]:
|
|
274
276
|
params = {}
|
|
275
277
|
if status:
|
|
276
278
|
params["status"] = status
|
|
277
279
|
if region:
|
|
278
280
|
params["region"] = region
|
|
281
|
+
if run_id:
|
|
282
|
+
params["run_id"] = run_id
|
|
279
283
|
|
|
280
284
|
response = await self.client.request("GET", "/v1/env/instances", params=params)
|
|
281
285
|
return [
|
|
@@ -302,6 +306,28 @@ class AsyncFleet:
|
|
|
302
306
|
async def delete(self, instance_id: str) -> InstanceResponse:
|
|
303
307
|
return await _delete_instance(self.client, instance_id)
|
|
304
308
|
|
|
309
|
+
async def close(self, instance_id: str) -> InstanceResponse:
|
|
310
|
+
"""Close (delete) a specific instance by ID.
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
instance_id: The instance ID to close
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
InstanceResponse containing the deleted instance details
|
|
317
|
+
"""
|
|
318
|
+
return await _delete_instance(self.client, instance_id)
|
|
319
|
+
|
|
320
|
+
async def close_all(self, run_id: str) -> List[InstanceResponse]:
|
|
321
|
+
"""Close (delete) all instances associated with a run_id.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
run_id: The run ID whose instances should be closed
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
List[InstanceResponse] containing the deleted instances
|
|
328
|
+
"""
|
|
329
|
+
return await _delete_instances_by_run_id(self.client, run_id)
|
|
330
|
+
|
|
305
331
|
async def load_tasks_from_file(self, filename: str) -> List[Task]:
|
|
306
332
|
with open(filename, "r", encoding="utf-8") as f:
|
|
307
333
|
tasks_data = f.read()
|
|
@@ -553,7 +579,7 @@ class AsyncFleet:
|
|
|
553
579
|
env_variables=task_response.env_variables or {},
|
|
554
580
|
verifier_func=verifier_func, # Set verifier code
|
|
555
581
|
verifier=verifier, # Use created verifier or None
|
|
556
|
-
metadata={},
|
|
582
|
+
metadata=task_response.metadata or {},
|
|
557
583
|
output_json_schema=getattr(task_response, "output_json_schema", None), # Get output_json_schema if available
|
|
558
584
|
)
|
|
559
585
|
tasks.append(task)
|
|
@@ -708,6 +734,7 @@ class AsyncFleet:
|
|
|
708
734
|
task_key: str,
|
|
709
735
|
prompt: Optional[str] = None,
|
|
710
736
|
verifier_code: Optional[str] = None,
|
|
737
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
711
738
|
) -> TaskResponse:
|
|
712
739
|
"""Update an existing task.
|
|
713
740
|
|
|
@@ -715,11 +742,12 @@ class AsyncFleet:
|
|
|
715
742
|
task_key: The key of the task to update
|
|
716
743
|
prompt: New prompt text for the task (optional)
|
|
717
744
|
verifier_code: Python code for task verification (optional)
|
|
745
|
+
metadata: Additional metadata for the task (optional)
|
|
718
746
|
|
|
719
747
|
Returns:
|
|
720
748
|
TaskResponse containing the updated task details
|
|
721
749
|
"""
|
|
722
|
-
payload = TaskUpdateRequest(prompt=prompt, verifier_code=verifier_code)
|
|
750
|
+
payload = TaskUpdateRequest(prompt=prompt, verifier_code=verifier_code, metadata=metadata)
|
|
723
751
|
response = await self.client.request(
|
|
724
752
|
"PUT", f"/v1/tasks/{task_key}", json=payload.model_dump(exclude_none=True)
|
|
725
753
|
)
|
|
@@ -809,6 +837,11 @@ async def _delete_instance(client: AsyncWrapper, instance_id: str) -> InstanceRe
|
|
|
809
837
|
return InstanceResponse(**response.json())
|
|
810
838
|
|
|
811
839
|
|
|
840
|
+
async def _delete_instances_by_run_id(client: AsyncWrapper, run_id: str) -> List[InstanceResponse]:
|
|
841
|
+
response = await client.request("DELETE", f"/v1/env/instances/run/{run_id}")
|
|
842
|
+
return [InstanceResponse(**instance_data) for instance_data in response.json()]
|
|
843
|
+
|
|
844
|
+
|
|
812
845
|
async def _check_bundle_exists(
|
|
813
846
|
client: AsyncWrapper, bundle_hash: str
|
|
814
847
|
) -> VerifiersCheckResponse:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from ..client import AsyncFleet, AsyncEnv, Task
|
|
2
|
-
from ...models import Environment as EnvironmentModel, AccountResponse
|
|
2
|
+
from ...models import Environment as EnvironmentModel, AccountResponse, InstanceResponse
|
|
3
3
|
from typing import List, Optional, Dict, Any
|
|
4
4
|
|
|
5
5
|
|
|
@@ -10,6 +10,7 @@ async def make_async(
|
|
|
10
10
|
env_variables: Optional[Dict[str, Any]] = None,
|
|
11
11
|
image_type: Optional[str] = None,
|
|
12
12
|
ttl_seconds: Optional[int] = None,
|
|
13
|
+
run_id: Optional[str] = None,
|
|
13
14
|
) -> AsyncEnv:
|
|
14
15
|
return await AsyncFleet().make(
|
|
15
16
|
env_key,
|
|
@@ -18,6 +19,7 @@ async def make_async(
|
|
|
18
19
|
env_variables=env_variables,
|
|
19
20
|
image_type=image_type,
|
|
20
21
|
ttl_seconds=ttl_seconds,
|
|
22
|
+
run_id=run_id,
|
|
21
23
|
)
|
|
22
24
|
|
|
23
25
|
|
|
@@ -34,14 +36,38 @@ async def list_regions_async() -> List[str]:
|
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
async def list_instances_async(
|
|
37
|
-
status: Optional[str] = None, region: Optional[str] = None
|
|
39
|
+
status: Optional[str] = None, region: Optional[str] = None, run_id: Optional[str] = None
|
|
38
40
|
) -> List[AsyncEnv]:
|
|
39
|
-
return await AsyncFleet().instances(status=status, region=region)
|
|
41
|
+
return await AsyncFleet().instances(status=status, region=region, run_id=run_id)
|
|
40
42
|
|
|
41
43
|
|
|
42
44
|
async def get_async(instance_id: str) -> AsyncEnv:
|
|
43
45
|
return await AsyncFleet().instance(instance_id)
|
|
44
46
|
|
|
45
47
|
|
|
48
|
+
async def close_async(instance_id: str) -> InstanceResponse:
|
|
49
|
+
"""Close (delete) a specific instance by ID.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
instance_id: The instance ID to close
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
InstanceResponse containing the deleted instance details
|
|
56
|
+
"""
|
|
57
|
+
return await AsyncFleet().close(instance_id)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
async def close_all_async(run_id: str) -> List[InstanceResponse]:
|
|
61
|
+
"""Close (delete) all instances associated with a run_id.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
run_id: The run ID whose instances should be closed
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
List[InstanceResponse] containing the deleted instances
|
|
68
|
+
"""
|
|
69
|
+
return await AsyncFleet().close_all(run_id)
|
|
70
|
+
|
|
71
|
+
|
|
46
72
|
async def account_async() -> AccountResponse:
|
|
47
73
|
return await AsyncFleet().account()
|
|
@@ -155,12 +155,14 @@ class TaskRequest(BaseModel):
|
|
|
155
155
|
verifier_id: Optional[str] = Field(None, title="Verifier Id")
|
|
156
156
|
version: Optional[str] = Field(None, title="Version")
|
|
157
157
|
env_variables: Optional[Dict[str, Any]] = Field(None, title="Env Variables")
|
|
158
|
+
metadata: Optional[Dict[str, Any]] = Field(None, title="Metadata")
|
|
158
159
|
output_json_schema: Optional[Dict[str, Any]] = Field(None, title="Output Json Schema")
|
|
159
160
|
|
|
160
161
|
|
|
161
162
|
class TaskUpdateRequest(BaseModel):
|
|
162
163
|
prompt: Optional[str] = Field(None, title="Prompt")
|
|
163
164
|
verifier_code: Optional[str] = Field(None, title="Verifier Code")
|
|
165
|
+
metadata: Optional[Dict[str, Any]] = Field(None, title="Metadata")
|
|
164
166
|
|
|
165
167
|
|
|
166
168
|
class VerifierData(BaseModel):
|
|
@@ -186,6 +188,7 @@ class TaskResponse(BaseModel):
|
|
|
186
188
|
data_version: Optional[str] = Field(None, title="Data Version")
|
|
187
189
|
env_variables: Optional[Dict[str, Any]] = Field(None, title="Env Variables")
|
|
188
190
|
verifier: Optional[VerifierData] = Field(None, title="Verifier")
|
|
191
|
+
metadata: Optional[Dict[str, Any]] = Field(None, title="Metadata")
|
|
189
192
|
output_json_schema: Optional[Dict[str, Any]] = Field(None, title="Output Json Schema")
|
|
190
193
|
|
|
191
194
|
|
|
@@ -209,23 +209,27 @@ class Task(BaseModel):
|
|
|
209
209
|
)
|
|
210
210
|
self.verifier = verifier
|
|
211
211
|
|
|
212
|
-
async def make_env(
|
|
212
|
+
async def make_env(
|
|
213
|
+
self,
|
|
214
|
+
region: Optional[str] = None,
|
|
215
|
+
image_type: Optional[str] = None,
|
|
216
|
+
ttl_seconds: Optional[int] = None,
|
|
217
|
+
run_id: Optional[str] = None,
|
|
218
|
+
):
|
|
213
219
|
"""Create an environment instance for this task's environment.
|
|
214
220
|
|
|
215
|
-
Uses the task's env_id (and version if present) to create the env.
|
|
221
|
+
Alias for make() method. Uses the task's env_id (and version if present) to create the env.
|
|
216
222
|
"""
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
from .client import AsyncFleet
|
|
221
|
-
|
|
222
|
-
return await AsyncFleet().make(env_key=self.env_key, region=region)
|
|
223
|
+
return await self.make(
|
|
224
|
+
region=region, image_type=image_type, ttl_seconds=ttl_seconds, run_id=run_id
|
|
225
|
+
)
|
|
223
226
|
|
|
224
227
|
async def make(
|
|
225
228
|
self,
|
|
226
229
|
region: Optional[str] = None,
|
|
227
230
|
image_type: Optional[str] = None,
|
|
228
231
|
ttl_seconds: Optional[int] = None,
|
|
232
|
+
run_id: Optional[str] = None,
|
|
229
233
|
):
|
|
230
234
|
"""Create an environment instance with task's configuration.
|
|
231
235
|
|
|
@@ -233,11 +237,13 @@ class Task(BaseModel):
|
|
|
233
237
|
- env_key (env_id + version)
|
|
234
238
|
- data_key (data_id + data_version, if present)
|
|
235
239
|
- env_variables (if present)
|
|
240
|
+
- run_id (if present)
|
|
236
241
|
|
|
237
242
|
Args:
|
|
238
243
|
region: Optional AWS region for the environment
|
|
239
244
|
image_type: Optional image type for the environment
|
|
240
245
|
ttl_seconds: Optional TTL in seconds for the instance
|
|
246
|
+
run_id: Optional run ID to group instances
|
|
241
247
|
|
|
242
248
|
Returns:
|
|
243
249
|
Environment instance configured for this task
|
|
@@ -245,7 +251,7 @@ class Task(BaseModel):
|
|
|
245
251
|
Example:
|
|
246
252
|
task = fleet.Task(key="my-task", prompt="...", env_id="my-env",
|
|
247
253
|
data_id="my-data", data_version="v1.0")
|
|
248
|
-
env = await task.make(region="us-west-2")
|
|
254
|
+
env = await task.make(region="us-west-2", run_id="my-batch-123")
|
|
249
255
|
"""
|
|
250
256
|
if not self.env_id:
|
|
251
257
|
raise ValueError("Task has no env_id defined")
|
|
@@ -260,6 +266,7 @@ class Task(BaseModel):
|
|
|
260
266
|
env_variables=self.env_variables if self.env_variables else None,
|
|
261
267
|
image_type=image_type,
|
|
262
268
|
ttl_seconds=ttl_seconds,
|
|
269
|
+
run_id=run_id,
|
|
263
270
|
)
|
|
264
271
|
|
|
265
272
|
|
|
@@ -279,14 +286,17 @@ def verifier_from_string(
|
|
|
279
286
|
"""
|
|
280
287
|
try:
|
|
281
288
|
import inspect
|
|
289
|
+
import re
|
|
282
290
|
from .verifiers.verifier import AsyncVerifierFunction
|
|
283
291
|
from fleet.verifiers.code import TASK_SUCCESSFUL_SCORE, TASK_FAILED_SCORE
|
|
284
292
|
from fleet.verifiers.db import IgnoreConfig
|
|
285
|
-
from fleet.verifiers.parsing import parse_and_validate_verifier
|
|
286
293
|
|
|
287
|
-
#
|
|
288
|
-
#
|
|
289
|
-
|
|
294
|
+
# Strip @verifier decorator if present to avoid double-wrapping
|
|
295
|
+
# Remove lines like: @verifier(key="...")
|
|
296
|
+
cleaned_code = re.sub(r"@verifier\([^)]*\)\s*\n", "", verifier_func)
|
|
297
|
+
# Also remove the verifier import if present
|
|
298
|
+
cleaned_code = re.sub(r"from fleet import.*verifier.*\n", "", cleaned_code)
|
|
299
|
+
cleaned_code = re.sub(r"import.*verifier.*\n", "", cleaned_code)
|
|
290
300
|
|
|
291
301
|
# Create a local namespace for executing the code
|
|
292
302
|
local_namespace = {
|
|
@@ -296,18 +306,20 @@ def verifier_from_string(
|
|
|
296
306
|
"Environment": object, # Add Environment type if needed
|
|
297
307
|
}
|
|
298
308
|
|
|
299
|
-
# Execute the verifier code in the namespace
|
|
300
|
-
|
|
301
|
-
exec(verifier_func, globals(), local_namespace)
|
|
309
|
+
# Execute the cleaned verifier code in the namespace
|
|
310
|
+
exec(cleaned_code, globals(), local_namespace)
|
|
302
311
|
|
|
303
|
-
#
|
|
304
|
-
|
|
312
|
+
# Find the function that was defined (not imported)
|
|
313
|
+
# Functions defined via exec have co_filename == '<string>'
|
|
314
|
+
# Imported functions have their actual module file path
|
|
315
|
+
func_obj = None
|
|
316
|
+
for name, obj in local_namespace.items():
|
|
317
|
+
if inspect.isfunction(obj) and obj.__code__.co_filename == "<string>":
|
|
318
|
+
func_obj = obj
|
|
319
|
+
break
|
|
305
320
|
|
|
306
321
|
if func_obj is None:
|
|
307
|
-
raise ValueError(
|
|
308
|
-
|
|
309
|
-
if not inspect.isfunction(func_obj):
|
|
310
|
-
raise ValueError(f"'{func_name}' is not a function")
|
|
322
|
+
raise ValueError("No function found in verifier code")
|
|
311
323
|
|
|
312
324
|
# Create an AsyncVerifierFunction instance with raw code
|
|
313
325
|
verifier_instance = AsyncVerifierFunction(
|
|
@@ -381,7 +393,7 @@ async def load_tasks(
|
|
|
381
393
|
|
|
382
394
|
|
|
383
395
|
async def update_task(
|
|
384
|
-
task_key: str, prompt: Optional[str] = None, verifier_code: Optional[str] = None
|
|
396
|
+
task_key: str, prompt: Optional[str] = None, verifier_code: Optional[str] = None, metadata: Optional[Dict[str, Any]] = None
|
|
385
397
|
):
|
|
386
398
|
"""Convenience function to update an existing task.
|
|
387
399
|
|
|
@@ -389,6 +401,7 @@ async def update_task(
|
|
|
389
401
|
task_key: The key of the task to update
|
|
390
402
|
prompt: New prompt text for the task (optional)
|
|
391
403
|
verifier_code: Python code for task verification (optional)
|
|
404
|
+
metadata: Additional metadata for the task (optional)
|
|
392
405
|
|
|
393
406
|
Returns:
|
|
394
407
|
TaskResponse containing the updated task details
|
|
@@ -396,16 +409,19 @@ async def update_task(
|
|
|
396
409
|
Examples:
|
|
397
410
|
response = await fleet.update_task("my-task", prompt="New prompt text")
|
|
398
411
|
response = await fleet.update_task("my-task", verifier_code="def verify(env): return True")
|
|
412
|
+
response = await fleet.update_task("my-task", metadata={"seed": 42, "story": "Updated story"})
|
|
399
413
|
"""
|
|
400
414
|
from .global_client import get_client
|
|
401
415
|
|
|
402
416
|
client = get_client()
|
|
403
417
|
return await client.update_task(
|
|
404
|
-
task_key=task_key, prompt=prompt, verifier_code=verifier_code
|
|
418
|
+
task_key=task_key, prompt=prompt, verifier_code=verifier_code, metadata=metadata
|
|
405
419
|
)
|
|
406
420
|
|
|
407
421
|
|
|
408
|
-
async def get_task(
|
|
422
|
+
async def get_task(
|
|
423
|
+
task_key: str, version_id: Optional[str] = None, team_id: Optional[str] = None
|
|
424
|
+
):
|
|
409
425
|
"""Convenience function to get a task by key and optional version.
|
|
410
426
|
|
|
411
427
|
Args:
|
|
@@ -424,7 +440,9 @@ async def get_task(task_key: str, version_id: Optional[str] = None, team_id: Opt
|
|
|
424
440
|
from .global_client import get_client
|
|
425
441
|
|
|
426
442
|
client = get_client()
|
|
427
|
-
return await client.get_task(
|
|
443
|
+
return await client.get_task(
|
|
444
|
+
task_key=task_key, version_id=version_id, team_id=team_id
|
|
445
|
+
)
|
|
428
446
|
|
|
429
447
|
|
|
430
448
|
async def import_task(task: Task, project_key: Optional[str] = None):
|
|
@@ -212,6 +212,7 @@ class Fleet:
|
|
|
212
212
|
env_variables: Optional[Dict[str, Any]] = None,
|
|
213
213
|
image_type: Optional[str] = None,
|
|
214
214
|
ttl_seconds: Optional[int] = None,
|
|
215
|
+
run_id: Optional[str] = None,
|
|
215
216
|
) -> SyncEnv:
|
|
216
217
|
if ":" in env_key:
|
|
217
218
|
env_key_part, env_version = env_key.split(":", 1)
|
|
@@ -247,6 +248,7 @@ class Fleet:
|
|
|
247
248
|
image_type=image_type,
|
|
248
249
|
created_from="sdk",
|
|
249
250
|
ttl_seconds=ttl_seconds,
|
|
251
|
+
run_id=run_id,
|
|
250
252
|
)
|
|
251
253
|
|
|
252
254
|
# Only use region-specific base URL if no custom base URL is set
|
|
@@ -269,13 +271,15 @@ class Fleet:
|
|
|
269
271
|
return self.make(env_key=f"{task.env_id}:{task.version}")
|
|
270
272
|
|
|
271
273
|
def instances(
|
|
272
|
-
self, status: Optional[str] = None, region: Optional[str] = None
|
|
274
|
+
self, status: Optional[str] = None, region: Optional[str] = None, run_id: Optional[str] = None
|
|
273
275
|
) -> List[SyncEnv]:
|
|
274
276
|
params = {}
|
|
275
277
|
if status:
|
|
276
278
|
params["status"] = status
|
|
277
279
|
if region:
|
|
278
280
|
params["region"] = region
|
|
281
|
+
if run_id:
|
|
282
|
+
params["run_id"] = run_id
|
|
279
283
|
|
|
280
284
|
response = self.client.request("GET", "/v1/env/instances", params=params)
|
|
281
285
|
return [
|
|
@@ -300,6 +304,28 @@ class Fleet:
|
|
|
300
304
|
def delete(self, instance_id: str) -> InstanceResponse:
|
|
301
305
|
return _delete_instance(self.client, instance_id)
|
|
302
306
|
|
|
307
|
+
def close(self, instance_id: str) -> InstanceResponse:
|
|
308
|
+
"""Close (delete) a specific instance by ID.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
instance_id: The instance ID to close
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
InstanceResponse containing the deleted instance details
|
|
315
|
+
"""
|
|
316
|
+
return _delete_instance(self.client, instance_id)
|
|
317
|
+
|
|
318
|
+
def close_all(self, run_id: str) -> List[InstanceResponse]:
|
|
319
|
+
"""Close (delete) all instances associated with a run_id.
|
|
320
|
+
|
|
321
|
+
Args:
|
|
322
|
+
run_id: The run ID whose instances should be closed
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
List[InstanceResponse] containing the deleted instances
|
|
326
|
+
"""
|
|
327
|
+
return _delete_instances_by_run_id(self.client, run_id)
|
|
328
|
+
|
|
303
329
|
def load_tasks_from_file(self, filename: str) -> List[Task]:
|
|
304
330
|
with open(filename, "r", encoding="utf-8") as f:
|
|
305
331
|
tasks_data = f.read()
|
|
@@ -559,7 +585,7 @@ class Fleet:
|
|
|
559
585
|
env_variables=task_response.env_variables or {},
|
|
560
586
|
verifier_func=verifier_func, # Set verifier code
|
|
561
587
|
verifier=verifier, # Use created verifier or None
|
|
562
|
-
metadata={},
|
|
588
|
+
metadata=task_response.metadata or {},
|
|
563
589
|
output_json_schema=getattr(task_response, "output_json_schema", None), # Get output_json_schema if available
|
|
564
590
|
)
|
|
565
591
|
tasks.append(task)
|
|
@@ -706,6 +732,7 @@ class Fleet:
|
|
|
706
732
|
task_key: str,
|
|
707
733
|
prompt: Optional[str] = None,
|
|
708
734
|
verifier_code: Optional[str] = None,
|
|
735
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
709
736
|
) -> TaskResponse:
|
|
710
737
|
"""Update an existing task.
|
|
711
738
|
|
|
@@ -713,11 +740,12 @@ class Fleet:
|
|
|
713
740
|
task_key: The key of the task to update
|
|
714
741
|
prompt: New prompt text for the task (optional)
|
|
715
742
|
verifier_code: Python code for task verification (optional)
|
|
743
|
+
metadata: Additional metadata for the task (optional)
|
|
716
744
|
|
|
717
745
|
Returns:
|
|
718
746
|
TaskResponse containing the updated task details
|
|
719
747
|
"""
|
|
720
|
-
payload = TaskUpdateRequest(prompt=prompt, verifier_code=verifier_code)
|
|
748
|
+
payload = TaskUpdateRequest(prompt=prompt, verifier_code=verifier_code, metadata=metadata)
|
|
721
749
|
response = self.client.request(
|
|
722
750
|
"PUT", f"/v1/tasks/{task_key}", json=payload.model_dump(exclude_none=True)
|
|
723
751
|
)
|
|
@@ -808,6 +836,11 @@ def _delete_instance(client: SyncWrapper, instance_id: str) -> InstanceResponse:
|
|
|
808
836
|
return InstanceResponse(**response.json())
|
|
809
837
|
|
|
810
838
|
|
|
839
|
+
def _delete_instances_by_run_id(client: SyncWrapper, run_id: str) -> List[InstanceResponse]:
|
|
840
|
+
response = client.request("DELETE", f"/v1/env/instances/run/{run_id}")
|
|
841
|
+
return [InstanceResponse(**instance_data) for instance_data in response.json()]
|
|
842
|
+
|
|
843
|
+
|
|
811
844
|
def _check_bundle_exists(
|
|
812
845
|
client: SyncWrapper, bundle_hash: str
|
|
813
846
|
) -> VerifiersCheckResponse:
|
|
@@ -7,6 +7,8 @@ from .client import (
|
|
|
7
7
|
list_regions,
|
|
8
8
|
get,
|
|
9
9
|
list_instances,
|
|
10
|
+
close,
|
|
11
|
+
close_all,
|
|
10
12
|
account,
|
|
11
13
|
)
|
|
12
14
|
|
|
@@ -17,6 +19,8 @@ from .._async.env.client import (
|
|
|
17
19
|
list_regions_async,
|
|
18
20
|
get_async,
|
|
19
21
|
list_instances_async,
|
|
22
|
+
close_async,
|
|
23
|
+
close_all_async,
|
|
20
24
|
account_async,
|
|
21
25
|
)
|
|
22
26
|
|
|
@@ -27,11 +31,15 @@ __all__ = [
|
|
|
27
31
|
"list_regions",
|
|
28
32
|
"list_instances",
|
|
29
33
|
"get",
|
|
34
|
+
"close",
|
|
35
|
+
"close_all",
|
|
30
36
|
"make_async",
|
|
31
37
|
"list_envs_async",
|
|
32
38
|
"list_regions_async",
|
|
33
39
|
"list_instances_async",
|
|
34
40
|
"get_async",
|
|
41
|
+
"close_async",
|
|
42
|
+
"close_all_async",
|
|
35
43
|
"account",
|
|
36
44
|
"account_async",
|
|
37
45
|
]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from ..client import Fleet, SyncEnv, Task
|
|
2
|
-
from ..models import Environment as EnvironmentModel, AccountResponse
|
|
2
|
+
from ..models import Environment as EnvironmentModel, AccountResponse, InstanceResponse
|
|
3
3
|
from typing import List, Optional, Dict, Any
|
|
4
4
|
|
|
5
5
|
|
|
@@ -10,6 +10,7 @@ def make(
|
|
|
10
10
|
env_variables: Optional[Dict[str, Any]] = None,
|
|
11
11
|
image_type: Optional[str] = None,
|
|
12
12
|
ttl_seconds: Optional[int] = None,
|
|
13
|
+
run_id: Optional[str] = None,
|
|
13
14
|
) -> SyncEnv:
|
|
14
15
|
return Fleet().make(
|
|
15
16
|
env_key,
|
|
@@ -18,6 +19,7 @@ def make(
|
|
|
18
19
|
env_variables=env_variables,
|
|
19
20
|
image_type=image_type,
|
|
20
21
|
ttl_seconds=ttl_seconds,
|
|
22
|
+
run_id=run_id,
|
|
21
23
|
)
|
|
22
24
|
|
|
23
25
|
|
|
@@ -34,14 +36,38 @@ def list_regions() -> List[str]:
|
|
|
34
36
|
|
|
35
37
|
|
|
36
38
|
def list_instances(
|
|
37
|
-
status: Optional[str] = None, region: Optional[str] = None
|
|
39
|
+
status: Optional[str] = None, region: Optional[str] = None, run_id: Optional[str] = None
|
|
38
40
|
) -> List[SyncEnv]:
|
|
39
|
-
return Fleet().instances(status=status, region=region)
|
|
41
|
+
return Fleet().instances(status=status, region=region, run_id=run_id)
|
|
40
42
|
|
|
41
43
|
|
|
42
44
|
def get(instance_id: str) -> SyncEnv:
|
|
43
45
|
return Fleet().instance(instance_id)
|
|
44
46
|
|
|
45
47
|
|
|
48
|
+
def close(instance_id: str) -> InstanceResponse:
|
|
49
|
+
"""Close (delete) a specific instance by ID.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
instance_id: The instance ID to close
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
InstanceResponse containing the deleted instance details
|
|
56
|
+
"""
|
|
57
|
+
return Fleet().close(instance_id)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def close_all(run_id: str) -> List[InstanceResponse]:
|
|
61
|
+
"""Close (delete) all instances associated with a run_id.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
run_id: The run ID whose instances should be closed
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
List[InstanceResponse] containing the deleted instances
|
|
68
|
+
"""
|
|
69
|
+
return Fleet().close_all(run_id)
|
|
70
|
+
|
|
71
|
+
|
|
46
72
|
def account() -> AccountResponse:
|
|
47
73
|
return Fleet().account()
|
|
@@ -51,6 +51,7 @@ 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
|
+
run_id: Optional[str] = Field(None, title="Run Id")
|
|
54
55
|
|
|
55
56
|
|
|
56
57
|
class InstanceRequest(BaseModel):
|
|
@@ -158,6 +159,7 @@ class TaskRequest(BaseModel):
|
|
|
158
159
|
verifier_id: Optional[str] = Field(None, title="Verifier Id")
|
|
159
160
|
version: Optional[str] = Field(None, title="Version")
|
|
160
161
|
env_variables: Optional[Dict[str, Any]] = Field(None, title="Env Variables")
|
|
162
|
+
metadata: Optional[Dict[str, Any]] = Field(None, title="Metadata")
|
|
161
163
|
output_json_schema: Optional[Dict[str, Any]] = Field(
|
|
162
164
|
None, title="Output Json Schema"
|
|
163
165
|
)
|
|
@@ -166,6 +168,7 @@ class TaskRequest(BaseModel):
|
|
|
166
168
|
class TaskUpdateRequest(BaseModel):
|
|
167
169
|
prompt: Optional[str] = Field(None, title="Prompt")
|
|
168
170
|
verifier_code: Optional[str] = Field(None, title="Verifier Code")
|
|
171
|
+
metadata: Optional[Dict[str, Any]] = Field(None, title="Metadata")
|
|
169
172
|
|
|
170
173
|
|
|
171
174
|
class VerifierData(BaseModel):
|
|
@@ -191,6 +194,7 @@ class TaskResponse(BaseModel):
|
|
|
191
194
|
data_version: Optional[str] = Field(None, title="Data Version")
|
|
192
195
|
env_variables: Optional[Dict[str, Any]] = Field(None, title="Env Variables")
|
|
193
196
|
verifier: Optional[VerifierData] = Field(None, title="Verifier")
|
|
197
|
+
metadata: Optional[Dict[str, Any]] = Field(None, title="Metadata")
|
|
194
198
|
output_json_schema: Optional[Dict[str, Any]] = Field(
|
|
195
199
|
None, title="Output Json Schema"
|
|
196
200
|
)
|
|
@@ -360,6 +364,7 @@ class InstanceResponse(BaseModel):
|
|
|
360
364
|
data_version: Optional[str] = Field(None, title="Data Version")
|
|
361
365
|
urls: Optional[InstanceURLs] = Field(None, title="Urls")
|
|
362
366
|
health: Optional[bool] = Field(None, title="Health")
|
|
367
|
+
run_id: Optional[str] = Field(None, title="Run Id")
|
|
363
368
|
|
|
364
369
|
|
|
365
370
|
class AccountResponse(BaseModel):
|