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.
Files changed (70) hide show
  1. examples/export_tasks.py +16 -5
  2. examples/export_tasks_filtered.py +245 -0
  3. examples/fetch_tasks.py +230 -0
  4. examples/import_tasks.py +140 -8
  5. examples/iterate_verifiers.py +725 -0
  6. fleet/__init__.py +128 -5
  7. fleet/_async/__init__.py +27 -3
  8. fleet/_async/base.py +24 -9
  9. fleet/_async/client.py +938 -41
  10. fleet/_async/env/client.py +60 -3
  11. fleet/_async/instance/client.py +52 -7
  12. fleet/_async/models.py +15 -0
  13. fleet/_async/resources/api.py +200 -0
  14. fleet/_async/resources/sqlite.py +1801 -46
  15. fleet/_async/tasks.py +122 -25
  16. fleet/_async/verifiers/bundler.py +22 -21
  17. fleet/_async/verifiers/verifier.py +25 -19
  18. fleet/agent/__init__.py +32 -0
  19. fleet/agent/gemini_cua/Dockerfile +45 -0
  20. fleet/agent/gemini_cua/__init__.py +10 -0
  21. fleet/agent/gemini_cua/agent.py +759 -0
  22. fleet/agent/gemini_cua/mcp/main.py +108 -0
  23. fleet/agent/gemini_cua/mcp_server/__init__.py +5 -0
  24. fleet/agent/gemini_cua/mcp_server/main.py +105 -0
  25. fleet/agent/gemini_cua/mcp_server/tools.py +178 -0
  26. fleet/agent/gemini_cua/requirements.txt +5 -0
  27. fleet/agent/gemini_cua/start.sh +30 -0
  28. fleet/agent/orchestrator.py +854 -0
  29. fleet/agent/types.py +49 -0
  30. fleet/agent/utils.py +34 -0
  31. fleet/base.py +34 -9
  32. fleet/cli.py +1061 -0
  33. fleet/client.py +1060 -48
  34. fleet/config.py +1 -1
  35. fleet/env/__init__.py +16 -0
  36. fleet/env/client.py +60 -3
  37. fleet/eval/__init__.py +15 -0
  38. fleet/eval/uploader.py +231 -0
  39. fleet/exceptions.py +8 -0
  40. fleet/instance/client.py +53 -8
  41. fleet/instance/models.py +1 -0
  42. fleet/models.py +303 -0
  43. fleet/proxy/__init__.py +25 -0
  44. fleet/proxy/proxy.py +453 -0
  45. fleet/proxy/whitelist.py +244 -0
  46. fleet/resources/api.py +200 -0
  47. fleet/resources/sqlite.py +1845 -46
  48. fleet/tasks.py +113 -20
  49. fleet/utils/__init__.py +7 -0
  50. fleet/utils/http_logging.py +178 -0
  51. fleet/utils/logging.py +13 -0
  52. fleet/utils/playwright.py +440 -0
  53. fleet/verifiers/bundler.py +22 -21
  54. fleet/verifiers/db.py +985 -1
  55. fleet/verifiers/decorator.py +1 -1
  56. fleet/verifiers/verifier.py +25 -19
  57. {fleet_python-0.2.66b2.dist-info → fleet_python-0.2.105.dist-info}/METADATA +28 -1
  58. fleet_python-0.2.105.dist-info/RECORD +115 -0
  59. {fleet_python-0.2.66b2.dist-info → fleet_python-0.2.105.dist-info}/WHEEL +1 -1
  60. fleet_python-0.2.105.dist-info/entry_points.txt +2 -0
  61. tests/test_app_method.py +85 -0
  62. tests/test_expect_exactly.py +4148 -0
  63. tests/test_expect_only.py +2593 -0
  64. tests/test_instance_dispatch.py +607 -0
  65. tests/test_sqlite_resource_dual_mode.py +263 -0
  66. tests/test_sqlite_shared_memory_behavior.py +117 -0
  67. fleet_python-0.2.66b2.dist-info/RECORD +0 -81
  68. tests/test_verifier_security.py +0 -427
  69. {fleet_python-0.2.66b2.dist-info → fleet_python-0.2.105.dist-info}/licenses/LICENSE +0 -0
  70. {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
- sys.exit(1)
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
- results = await fleet.import_tasks_async(
304
- args.json_file, project_key=args.project_key
305
- )
306
- print(f"\n✓ Successfully imported {len(results)} task(s)")
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)