fleet-python 0.2.66b2__py3-none-any.whl → 0.2.105__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- examples/export_tasks.py +16 -5
- examples/export_tasks_filtered.py +245 -0
- examples/fetch_tasks.py +230 -0
- examples/import_tasks.py +140 -8
- examples/iterate_verifiers.py +725 -0
- fleet/__init__.py +128 -5
- fleet/_async/__init__.py +27 -3
- fleet/_async/base.py +24 -9
- fleet/_async/client.py +938 -41
- fleet/_async/env/client.py +60 -3
- fleet/_async/instance/client.py +52 -7
- fleet/_async/models.py +15 -0
- fleet/_async/resources/api.py +200 -0
- fleet/_async/resources/sqlite.py +1801 -46
- fleet/_async/tasks.py +122 -25
- fleet/_async/verifiers/bundler.py +22 -21
- fleet/_async/verifiers/verifier.py +25 -19
- fleet/agent/__init__.py +32 -0
- fleet/agent/gemini_cua/Dockerfile +45 -0
- fleet/agent/gemini_cua/__init__.py +10 -0
- fleet/agent/gemini_cua/agent.py +759 -0
- fleet/agent/gemini_cua/mcp/main.py +108 -0
- fleet/agent/gemini_cua/mcp_server/__init__.py +5 -0
- fleet/agent/gemini_cua/mcp_server/main.py +105 -0
- fleet/agent/gemini_cua/mcp_server/tools.py +178 -0
- fleet/agent/gemini_cua/requirements.txt +5 -0
- fleet/agent/gemini_cua/start.sh +30 -0
- fleet/agent/orchestrator.py +854 -0
- fleet/agent/types.py +49 -0
- fleet/agent/utils.py +34 -0
- fleet/base.py +34 -9
- fleet/cli.py +1061 -0
- fleet/client.py +1060 -48
- fleet/config.py +1 -1
- fleet/env/__init__.py +16 -0
- fleet/env/client.py +60 -3
- fleet/eval/__init__.py +15 -0
- fleet/eval/uploader.py +231 -0
- fleet/exceptions.py +8 -0
- fleet/instance/client.py +53 -8
- fleet/instance/models.py +1 -0
- fleet/models.py +303 -0
- fleet/proxy/__init__.py +25 -0
- fleet/proxy/proxy.py +453 -0
- fleet/proxy/whitelist.py +244 -0
- fleet/resources/api.py +200 -0
- fleet/resources/sqlite.py +1845 -46
- fleet/tasks.py +113 -20
- fleet/utils/__init__.py +7 -0
- fleet/utils/http_logging.py +178 -0
- fleet/utils/logging.py +13 -0
- fleet/utils/playwright.py +440 -0
- fleet/verifiers/bundler.py +22 -21
- fleet/verifiers/db.py +985 -1
- fleet/verifiers/decorator.py +1 -1
- fleet/verifiers/verifier.py +25 -19
- {fleet_python-0.2.66b2.dist-info → fleet_python-0.2.105.dist-info}/METADATA +28 -1
- fleet_python-0.2.105.dist-info/RECORD +115 -0
- {fleet_python-0.2.66b2.dist-info → fleet_python-0.2.105.dist-info}/WHEEL +1 -1
- fleet_python-0.2.105.dist-info/entry_points.txt +2 -0
- tests/test_app_method.py +85 -0
- tests/test_expect_exactly.py +4148 -0
- tests/test_expect_only.py +2593 -0
- tests/test_instance_dispatch.py +607 -0
- tests/test_sqlite_resource_dual_mode.py +263 -0
- tests/test_sqlite_shared_memory_behavior.py +117 -0
- fleet_python-0.2.66b2.dist-info/RECORD +0 -81
- tests/test_verifier_security.py +0 -427
- {fleet_python-0.2.66b2.dist-info → fleet_python-0.2.105.dist-info}/licenses/LICENSE +0 -0
- {fleet_python-0.2.66b2.dist-info → fleet_python-0.2.105.dist-info}/top_level.txt +0 -0
examples/import_tasks.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import argparse
|
|
3
3
|
import json
|
|
4
|
+
import os
|
|
4
5
|
import sys
|
|
6
|
+
import tempfile
|
|
5
7
|
from collections import defaultdict
|
|
6
8
|
from typing import Dict, List, Tuple
|
|
7
9
|
import fleet
|
|
@@ -183,7 +185,6 @@ async def run_verifier_sanity_check(
|
|
|
183
185
|
print(f" - {task_key}: {error_msg}")
|
|
184
186
|
if len(errors) > 10:
|
|
185
187
|
print(f" ... and {len(errors) - 10} more")
|
|
186
|
-
print("\nFix the verifiers and try again.")
|
|
187
188
|
return False, errors
|
|
188
189
|
else:
|
|
189
190
|
print("✓ All verifiers passed!")
|
|
@@ -210,9 +211,18 @@ async def main():
|
|
|
210
211
|
action="store_true",
|
|
211
212
|
help="Skip the verifier sanity check (not recommended)",
|
|
212
213
|
)
|
|
214
|
+
parser.add_argument(
|
|
215
|
+
"--sanity-check-only",
|
|
216
|
+
action="store_true",
|
|
217
|
+
help="Only run the sanity check without importing tasks",
|
|
218
|
+
)
|
|
213
219
|
|
|
214
220
|
args = parser.parse_args()
|
|
215
221
|
|
|
222
|
+
# Validate conflicting flags
|
|
223
|
+
if args.skip_sanity_check and args.sanity_check_only:
|
|
224
|
+
parser.error("Cannot use --skip-sanity-check and --sanity-check-only together")
|
|
225
|
+
|
|
216
226
|
# Load and parse the JSON file
|
|
217
227
|
try:
|
|
218
228
|
with open(args.json_file, "r", encoding="utf-8") as f:
|
|
@@ -228,6 +238,7 @@ async def main():
|
|
|
228
238
|
task_count = len(tasks_data)
|
|
229
239
|
task_keys = []
|
|
230
240
|
missing_verifier = []
|
|
241
|
+
tasks_with_output_schema = []
|
|
231
242
|
for task_data in tasks_data:
|
|
232
243
|
task_key = task_data.get("key") or task_data.get("id")
|
|
233
244
|
if task_key:
|
|
@@ -240,6 +251,10 @@ async def main():
|
|
|
240
251
|
if not verifier_code:
|
|
241
252
|
missing_verifier.append(task_key or "(no key)")
|
|
242
253
|
|
|
254
|
+
# Check for output_json_schema
|
|
255
|
+
if task_data.get("output_json_schema"):
|
|
256
|
+
tasks_with_output_schema.append(task_key or "(no key)")
|
|
257
|
+
|
|
243
258
|
# Validate all tasks have verifier_func
|
|
244
259
|
if missing_verifier:
|
|
245
260
|
print(f"✗ Error: {len(missing_verifier)} task(s) missing verifier_func:")
|
|
@@ -282,15 +297,64 @@ async def main():
|
|
|
282
297
|
print(f"✓ Loaded {len(tasks)} tasks")
|
|
283
298
|
|
|
284
299
|
# Run sanity check (unless skipped)
|
|
300
|
+
already_confirmed = False # Track if user already confirmed import
|
|
285
301
|
if not args.skip_sanity_check:
|
|
286
302
|
success, errors = await run_verifier_sanity_check(tasks, client)
|
|
303
|
+
|
|
304
|
+
# If only doing sanity check, exit here
|
|
305
|
+
if args.sanity_check_only:
|
|
306
|
+
if success:
|
|
307
|
+
print("\n✓ Sanity check complete! (--sanity-check-only)")
|
|
308
|
+
print("Tasks are ready to import.")
|
|
309
|
+
sys.exit(0)
|
|
310
|
+
else:
|
|
311
|
+
print("\n✗ Sanity check failed (--sanity-check-only)")
|
|
312
|
+
print("Fix the verifiers and try again.")
|
|
313
|
+
sys.exit(1)
|
|
314
|
+
|
|
315
|
+
# Handle partial failures
|
|
287
316
|
if not success:
|
|
288
|
-
|
|
317
|
+
# Filter out failed tasks
|
|
318
|
+
failed_keys = set(errors.keys())
|
|
319
|
+
passed_tasks = [t for t in tasks if t.key not in failed_keys]
|
|
320
|
+
|
|
321
|
+
print("\n" + "=" * 60)
|
|
322
|
+
print("SANITY CHECK RESULTS")
|
|
323
|
+
print("=" * 60)
|
|
324
|
+
print(f"Passed: {len(passed_tasks)}/{len(tasks)} tasks")
|
|
325
|
+
print(f"Failed: {len(failed_keys)}/{len(tasks)} tasks")
|
|
326
|
+
|
|
327
|
+
if len(passed_tasks) == 0:
|
|
328
|
+
print("\n✗ No tasks passed the sanity check.")
|
|
329
|
+
print("Fix the verifiers and try again.")
|
|
330
|
+
sys.exit(1)
|
|
331
|
+
|
|
332
|
+
# Prompt user to import only passed tasks
|
|
333
|
+
if not args.yes:
|
|
334
|
+
print("\nWould you like to import only the tasks that passed?")
|
|
335
|
+
response = input("Type 'YES' to import passed tasks only: ")
|
|
336
|
+
if response != "YES":
|
|
337
|
+
print("Import cancelled.")
|
|
338
|
+
sys.exit(0)
|
|
339
|
+
already_confirmed = True # User already confirmed import
|
|
340
|
+
else:
|
|
341
|
+
print("\n⚠️ Auto-importing only tasks that passed (--yes flag)")
|
|
342
|
+
|
|
343
|
+
# Update tasks list and tasks_data to only include passed tasks
|
|
344
|
+
tasks = passed_tasks
|
|
345
|
+
passed_keys = {t.key for t in passed_tasks}
|
|
346
|
+
tasks_data = [td for td in tasks_data if td.get("key") in passed_keys]
|
|
347
|
+
# Also filter tasks_with_output_schema
|
|
348
|
+
tasks_with_output_schema = [
|
|
349
|
+
k for k in tasks_with_output_schema if k in passed_keys
|
|
350
|
+
]
|
|
351
|
+
|
|
352
|
+
print(f"\nProceeding with {len(tasks)} tasks that passed sanity check")
|
|
289
353
|
else:
|
|
290
354
|
print("\n⚠️ Skipping sanity check (--skip-sanity-check)")
|
|
291
355
|
|
|
292
|
-
# Confirmation prompt (unless --yes flag is provided)
|
|
293
|
-
if not args.yes:
|
|
356
|
+
# Confirmation prompt (unless --yes flag is provided or already confirmed)
|
|
357
|
+
if not args.yes and not already_confirmed:
|
|
294
358
|
print("\n" + "=" * 60)
|
|
295
359
|
response = input("Type 'YES' to proceed with import: ")
|
|
296
360
|
if response != "YES":
|
|
@@ -300,10 +364,78 @@ async def main():
|
|
|
300
364
|
# Import tasks
|
|
301
365
|
print("\nImporting tasks...")
|
|
302
366
|
try:
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
367
|
+
# If tasks were filtered, write to a temporary file for import
|
|
368
|
+
if len(tasks_data) < task_count:
|
|
369
|
+
# Create temporary file with filtered tasks
|
|
370
|
+
with tempfile.NamedTemporaryFile(
|
|
371
|
+
mode="w", suffix=".json", delete=False, encoding="utf-8"
|
|
372
|
+
) as temp_file:
|
|
373
|
+
json.dump(tasks_data, temp_file, indent=2, ensure_ascii=False)
|
|
374
|
+
temp_filename = temp_file.name
|
|
375
|
+
|
|
376
|
+
try:
|
|
377
|
+
results = await fleet.import_tasks_async(
|
|
378
|
+
temp_filename, project_key=args.project_key
|
|
379
|
+
)
|
|
380
|
+
finally:
|
|
381
|
+
# Clean up temporary file
|
|
382
|
+
os.unlink(temp_filename)
|
|
383
|
+
else:
|
|
384
|
+
# Import from original file if no filtering occurred
|
|
385
|
+
results = await fleet.import_tasks_async(
|
|
386
|
+
args.json_file, project_key=args.project_key
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
# Print success summary
|
|
390
|
+
print("\n" + "=" * 60)
|
|
391
|
+
print("IMPORT COMPLETE")
|
|
392
|
+
print("=" * 60)
|
|
393
|
+
print(f"✓ Successfully imported {len(results)} task(s)")
|
|
394
|
+
|
|
395
|
+
if args.project_key:
|
|
396
|
+
print(f"✓ Associated with project: {args.project_key}")
|
|
397
|
+
|
|
398
|
+
print(f"✓ Team: {account.team_name}")
|
|
399
|
+
|
|
400
|
+
# Print HUGE warning if any tasks have output_json_schema
|
|
401
|
+
if tasks_with_output_schema:
|
|
402
|
+
print("\n")
|
|
403
|
+
print("!" * 80)
|
|
404
|
+
print("!" * 80)
|
|
405
|
+
print("!" * 80)
|
|
406
|
+
print(
|
|
407
|
+
"!!! !!!"
|
|
408
|
+
)
|
|
409
|
+
print(
|
|
410
|
+
"!!! ⚠️ WARNING WARNING WARNING ⚠️ !!!"
|
|
411
|
+
)
|
|
412
|
+
print(
|
|
413
|
+
"!!! !!!"
|
|
414
|
+
)
|
|
415
|
+
print(
|
|
416
|
+
f"!!! {len(tasks_with_output_schema)} TASK(S) HAVE OUTPUT_JSON_SCHEMA THAT NEED MANUAL COPYING! !!!"
|
|
417
|
+
)
|
|
418
|
+
print(
|
|
419
|
+
"!!! !!!"
|
|
420
|
+
)
|
|
421
|
+
print(
|
|
422
|
+
"!!! The output_json_schema field is NOT automatically imported! !!!"
|
|
423
|
+
)
|
|
424
|
+
print(
|
|
425
|
+
"!!! You MUST manually copy the output schemas to each task! !!!"
|
|
426
|
+
)
|
|
427
|
+
print(
|
|
428
|
+
"!!! !!!"
|
|
429
|
+
)
|
|
430
|
+
print("!" * 80)
|
|
431
|
+
print("!" * 80)
|
|
432
|
+
print("!" * 80)
|
|
433
|
+
print("\nTasks with output_json_schema:")
|
|
434
|
+
for i, key in enumerate(tasks_with_output_schema[:20], 1):
|
|
435
|
+
print(f" {i}. {key}")
|
|
436
|
+
if len(tasks_with_output_schema) > 20:
|
|
437
|
+
print(f" ... and {len(tasks_with_output_schema) - 20} more")
|
|
438
|
+
print("\n⚠️ REMEMBER TO MANUALLY COPY OUTPUT SCHEMAS! ⚠️\n")
|
|
307
439
|
except Exception as e:
|
|
308
440
|
print(f"\n✗ Error importing tasks: {e}")
|
|
309
441
|
sys.exit(1)
|