fleet-python 0.2.29__py3-none-any.whl → 0.2.34__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.
Potentially problematic release.
This version of fleet-python might be problematic. Click here for more details.
- examples/diff_example.py +30 -20
- examples/dsl_example.py +12 -7
- examples/example.py +4 -4
- examples/exampleResume.py +191 -0
- examples/example_account.py +8 -0
- examples/example_action_log.py +2 -2
- examples/example_client.py +2 -2
- examples/example_mcp_anthropic.py +8 -5
- examples/example_mcp_openai.py +2 -2
- examples/example_sync.py +4 -4
- examples/example_task.py +16 -6
- examples/example_tasks.py +3 -6
- examples/example_verifier.py +16 -3
- examples/gemini_example.py +6 -6
- examples/json_tasks_example.py +2 -2
- examples/nova_act_example.py +2 -2
- examples/openai_example.py +3 -3
- examples/openai_simple_example.py +3 -3
- examples/query_builder_example.py +11 -7
- examples/test_cdp_logging.py +80 -0
- fleet/__init__.py +60 -5
- fleet/_async/__init__.py +258 -1
- fleet/_async/base.py +2 -1
- fleet/_async/client.py +164 -144
- fleet/_async/env/client.py +2 -0
- fleet/_async/global_client.py +43 -0
- fleet/_async/instance/client.py +1 -1
- fleet/_async/models.py +172 -171
- fleet/_async/resources/base.py +1 -1
- fleet/_async/resources/mcp.py +55 -0
- fleet/_async/resources/sqlite.py +141 -130
- fleet/_async/tasks.py +69 -16
- fleet/_async/verifiers/__init__.py +2 -2
- fleet/_async/verifiers/bundler.py +18 -14
- fleet/_async/verifiers/verifier.py +77 -71
- fleet/base.py +2 -1
- fleet/client.py +162 -148
- fleet/config.py +3 -2
- fleet/env/__init__.py +9 -1
- fleet/env/client.py +4 -1
- fleet/global_client.py +43 -0
- fleet/instance/__init__.py +1 -1
- fleet/instance/client.py +1 -1
- fleet/models.py +172 -171
- fleet/resources/base.py +1 -1
- fleet/resources/mcp.py +11 -16
- fleet/resources/sqlite.py +141 -130
- fleet/tasks.py +86 -15
- fleet/types.py +1 -1
- fleet/verifiers/__init__.py +2 -2
- fleet/verifiers/bundler.py +18 -14
- fleet/verifiers/code.py +1 -1
- fleet/verifiers/decorator.py +25 -34
- fleet/verifiers/parse.py +98 -68
- fleet/verifiers/verifier.py +77 -71
- {fleet_python-0.2.29.dist-info → fleet_python-0.2.34.dist-info}/METADATA +9 -9
- fleet_python-0.2.34.dist-info/RECORD +76 -0
- scripts/fix_sync_imports.py +87 -59
- scripts/unasync.py +10 -9
- fleet_python-0.2.29.dist-info/RECORD +0 -70
- {fleet_python-0.2.29.dist-info → fleet_python-0.2.34.dist-info}/WHEEL +0 -0
- {fleet_python-0.2.29.dist-info → fleet_python-0.2.34.dist-info}/licenses/LICENSE +0 -0
- {fleet_python-0.2.29.dist-info → fleet_python-0.2.34.dist-info}/top_level.txt +0 -0
examples/example_verifier.py
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import fleet
|
|
1
|
+
import fleet
|
|
2
2
|
from fleet.verifiers.verifier import verifier
|
|
3
3
|
from fleet.verifiers.db import IgnoreConfig
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
@verifier(key="validate_finish_blue_green_deployment")
|
|
7
7
|
def validate_finish_blue_green_deployment(
|
|
8
|
-
env
|
|
8
|
+
env, final_answer: str | None = None
|
|
9
9
|
) -> int:
|
|
10
10
|
"""Validate that DEBT-722 and DEBT-720 are marked as Done"""
|
|
11
|
+
# Ensure resources are loaded for remote execution
|
|
12
|
+
env.instance.load()
|
|
11
13
|
before = env.db("seed")
|
|
12
14
|
after = env.db("current")
|
|
13
15
|
|
|
16
|
+
print("test")
|
|
17
|
+
|
|
14
18
|
# Check final state
|
|
15
19
|
try:
|
|
16
20
|
after.table("issues").eq("id", "DEBT-722").assert_eq("board_list", "Done")
|
|
@@ -58,8 +62,17 @@ def validate_finish_blue_green_deployment(
|
|
|
58
62
|
|
|
59
63
|
|
|
60
64
|
def main():
|
|
61
|
-
env =
|
|
65
|
+
env = fleet.env.make("fira")
|
|
62
66
|
print(f"New Instance: {env.instance_id}")
|
|
67
|
+
|
|
68
|
+
# Check available resources
|
|
69
|
+
try:
|
|
70
|
+
resources = env.instance.resources()
|
|
71
|
+
print("Available resources:")
|
|
72
|
+
for resource in resources:
|
|
73
|
+
print(f" - {resource.type}: {resource.name}")
|
|
74
|
+
except Exception as e:
|
|
75
|
+
print(f"Could not list resources: {e}")
|
|
63
76
|
|
|
64
77
|
print(validate_finish_blue_green_deployment(env))
|
|
65
78
|
print(validate_finish_blue_green_deployment.remote(env))
|
examples/gemini_example.py
CHANGED
|
@@ -5,7 +5,7 @@ from typing import List, Dict, Any, Optional, Tuple, TypedDict
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from google import genai
|
|
7
7
|
from google.genai import types
|
|
8
|
-
import fleet
|
|
8
|
+
import fleet
|
|
9
9
|
from dotenv import load_dotenv
|
|
10
10
|
import base64
|
|
11
11
|
import re
|
|
@@ -30,7 +30,7 @@ class Problem(TypedDict):
|
|
|
30
30
|
class GeminiAgent:
|
|
31
31
|
def __init__(
|
|
32
32
|
self,
|
|
33
|
-
browser:
|
|
33
|
+
browser: fleet.FleetPlaywrightWrapper,
|
|
34
34
|
model: str = MODEL,
|
|
35
35
|
print_steps: bool = True,
|
|
36
36
|
debug: bool = False,
|
|
@@ -262,13 +262,13 @@ def evaluate_problem(
|
|
|
262
262
|
|
|
263
263
|
try:
|
|
264
264
|
# Create environment
|
|
265
|
-
env =
|
|
265
|
+
env = fleet.env.make(env_key)
|
|
266
266
|
print(
|
|
267
267
|
f"[Problem {problem_idx + 1}/{total_problems}] Created environment for {problem['id']}: {env.urls.app}"
|
|
268
268
|
)
|
|
269
269
|
|
|
270
270
|
# Create browser wrapper
|
|
271
|
-
browser =
|
|
271
|
+
browser = fleet.FleetPlaywrightWrapper(env)
|
|
272
272
|
browser.start()
|
|
273
273
|
|
|
274
274
|
# Create agent
|
|
@@ -314,10 +314,10 @@ def evaluate_problem(
|
|
|
314
314
|
|
|
315
315
|
def interactive_mode():
|
|
316
316
|
# Create a Fleet environment instance
|
|
317
|
-
instance =
|
|
317
|
+
instance = fleet.env.make("hubspot")
|
|
318
318
|
|
|
319
319
|
# Create the browser wrapper
|
|
320
|
-
browser =
|
|
320
|
+
browser = fleet.FleetPlaywrightWrapper(instance)
|
|
321
321
|
browser.start()
|
|
322
322
|
|
|
323
323
|
try:
|
examples/json_tasks_example.py
CHANGED
|
@@ -4,7 +4,7 @@ import argparse
|
|
|
4
4
|
import json
|
|
5
5
|
from typing import TypedDict, List, Optional, Tuple
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
import fleet
|
|
7
|
+
import fleet
|
|
8
8
|
from nova_act import NovaAct, ActResult
|
|
9
9
|
from dotenv import load_dotenv
|
|
10
10
|
|
|
@@ -36,7 +36,7 @@ async def process_problem(
|
|
|
36
36
|
env = None
|
|
37
37
|
try:
|
|
38
38
|
# Create a new environment instance for this problem
|
|
39
|
-
env = await
|
|
39
|
+
env = await fleet.env.make_async(env_key)
|
|
40
40
|
print(
|
|
41
41
|
f"[Problem {problem_idx + 1}/{total_problems}] Created environment for {problem['id']}: {env.urls.app}"
|
|
42
42
|
)
|
examples/nova_act_example.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import fleet
|
|
2
|
+
import fleet
|
|
3
3
|
from nova_act import NovaAct, ActResult
|
|
4
4
|
from dotenv import load_dotenv
|
|
5
5
|
|
|
@@ -7,7 +7,7 @@ load_dotenv()
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
async def main():
|
|
10
|
-
instance = await
|
|
10
|
+
instance = await fleet.env.make_async("hubspot:v1.2.7")
|
|
11
11
|
cdp_url = await instance.browser().cdp_url()
|
|
12
12
|
|
|
13
13
|
loop = asyncio.get_event_loop()
|
examples/openai_example.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from openai import OpenAI
|
|
2
|
-
import fleet
|
|
2
|
+
import fleet
|
|
3
3
|
import json
|
|
4
4
|
from typing import Callable
|
|
5
5
|
from dotenv import load_dotenv
|
|
@@ -191,10 +191,10 @@ tools = []
|
|
|
191
191
|
|
|
192
192
|
def main():
|
|
193
193
|
# Create a Fleet environment instance
|
|
194
|
-
instance =
|
|
194
|
+
instance = fleet.env.make("hubspot")
|
|
195
195
|
|
|
196
196
|
# Create the Playwright wrapper
|
|
197
|
-
browser =
|
|
197
|
+
browser = fleet.FleetPlaywrightWrapper(instance)
|
|
198
198
|
browser.start()
|
|
199
199
|
|
|
200
200
|
try:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from openai import OpenAI
|
|
2
|
-
import fleet
|
|
2
|
+
import fleet
|
|
3
3
|
from dotenv import load_dotenv
|
|
4
4
|
|
|
5
5
|
load_dotenv()
|
|
@@ -8,9 +8,9 @@ client = OpenAI()
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def main():
|
|
11
|
-
instance =
|
|
11
|
+
instance = fleet.env.make("hubspot")
|
|
12
12
|
|
|
13
|
-
browser =
|
|
13
|
+
browser = fleet.FleetPlaywrightWrapper(instance)
|
|
14
14
|
browser.start()
|
|
15
15
|
|
|
16
16
|
try:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import fleet
|
|
2
|
+
import fleet
|
|
3
3
|
from dotenv import load_dotenv
|
|
4
4
|
|
|
5
5
|
load_dotenv()
|
|
@@ -8,7 +8,7 @@ load_dotenv()
|
|
|
8
8
|
async def main():
|
|
9
9
|
# Create a new instance
|
|
10
10
|
print("Creating new Hubspot instance...")
|
|
11
|
-
env = await
|
|
11
|
+
env = await fleet.env.make_async("hubspot:v1.2.7")
|
|
12
12
|
print(f"New Instance: {env.instance_id}")
|
|
13
13
|
|
|
14
14
|
try:
|
|
@@ -21,7 +21,7 @@ async def main():
|
|
|
21
21
|
|
|
22
22
|
# Example 1: Query with the builder pattern
|
|
23
23
|
print("\n=== Query Builder Examples ===")
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
# Find all entries of type 'deal'
|
|
26
26
|
print("\n1. Finding all deals:")
|
|
27
27
|
deals = await db.table("entries").eq("type", "deal").all()
|
|
@@ -86,14 +86,18 @@ async def main():
|
|
|
86
86
|
)
|
|
87
87
|
"""
|
|
88
88
|
await db.exec(insert_query)
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
# Verify insertion with query builder
|
|
91
91
|
new_deal = await db.table("entries").eq("id", 99999).first()
|
|
92
92
|
if new_deal:
|
|
93
93
|
print(f"✓ Successfully inserted: {new_deal['name']}")
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
# Assert specific field value
|
|
96
|
-
await
|
|
96
|
+
await (
|
|
97
|
+
db.table("entries")
|
|
98
|
+
.eq("id", 99999)
|
|
99
|
+
.assert_eq("name", "Test Deal via Query Builder")
|
|
100
|
+
)
|
|
97
101
|
print("✓ Name assertion passed")
|
|
98
102
|
|
|
99
103
|
# Using IN clause
|
|
@@ -114,4 +118,4 @@ async def main():
|
|
|
114
118
|
|
|
115
119
|
|
|
116
120
|
if __name__ == "__main__":
|
|
117
|
-
asyncio.run(main())
|
|
121
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Test CDP Logging Example
|
|
4
|
+
|
|
5
|
+
This script demonstrates the new automatic CDP logging functionality.
|
|
6
|
+
All CDP commands and events are now logged automatically at the proxy level.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
|
|
13
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
|
14
|
+
|
|
15
|
+
from fleet import Fleet
|
|
16
|
+
|
|
17
|
+
def main():
|
|
18
|
+
# Initialize Fleet client
|
|
19
|
+
api_key = os.getenv("FLEET_API_KEY")
|
|
20
|
+
if not api_key:
|
|
21
|
+
print("Error: FLEET_API_KEY environment variable not set")
|
|
22
|
+
sys.exit(1)
|
|
23
|
+
|
|
24
|
+
fleet = Fleet(api_key=api_key)
|
|
25
|
+
env = None
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
# Create environment
|
|
29
|
+
print("🚀 Creating new environment...")
|
|
30
|
+
env_key = "fira:v1.3.2" # Replace with your actual environment key
|
|
31
|
+
|
|
32
|
+
env = fleet.make(env_key)
|
|
33
|
+
print(f"✅ Environment created: {env.instance_id}")
|
|
34
|
+
print(f"📝 Session ID: {env.session_id}")
|
|
35
|
+
|
|
36
|
+
# Start browser
|
|
37
|
+
print("\n🌐 Starting browser with automatic CDP logging...")
|
|
38
|
+
browser = env.browser()
|
|
39
|
+
browser.start(width=1920, height=1080)
|
|
40
|
+
|
|
41
|
+
# Show connection information
|
|
42
|
+
conn_info = browser.get_connection_info()
|
|
43
|
+
print("\n📊 Connection Information:")
|
|
44
|
+
print(f" Session ID: {conn_info['session_id']}")
|
|
45
|
+
print(f" CDP Page URL: {conn_info['cdp_page_url']}")
|
|
46
|
+
print(f" CDP Browser URL: {conn_info['cdp_browser_url']}")
|
|
47
|
+
print(f" Logging Enabled: {conn_info['logging_enabled']}")
|
|
48
|
+
|
|
49
|
+
if conn_info['logging_enabled']:
|
|
50
|
+
print(f"\n✅ All CDP actions will be automatically logged!")
|
|
51
|
+
print(f" - Connect any CDP client to: {conn_info['cdp_page_url']}")
|
|
52
|
+
print(f" - All commands and events will be logged to session: {env.session_id}")
|
|
53
|
+
print(f" - Use DevTools at: {conn_info['devtools_url']}")
|
|
54
|
+
else:
|
|
55
|
+
print(f"\n⚠️ Logging not enabled - no session ID available")
|
|
56
|
+
|
|
57
|
+
print("\n" + "="*60)
|
|
58
|
+
print("🎯 LOGGING TEST COMPLETE")
|
|
59
|
+
print("="*60)
|
|
60
|
+
print("The browser is ready with automatic CDP logging enabled.")
|
|
61
|
+
print("Connect any CDP client or Playwright to the URLs above.")
|
|
62
|
+
print("All actions will be automatically captured in the tool_log table.")
|
|
63
|
+
print("\nPress Enter to close the environment...")
|
|
64
|
+
print("="*60 + "\n")
|
|
65
|
+
|
|
66
|
+
input()
|
|
67
|
+
|
|
68
|
+
except Exception as e:
|
|
69
|
+
print(f"\n❌ Error: {e}")
|
|
70
|
+
finally:
|
|
71
|
+
if env is not None:
|
|
72
|
+
try:
|
|
73
|
+
print("\n🧹 Cleaning up environment...")
|
|
74
|
+
env.close()
|
|
75
|
+
print("✅ Environment closed")
|
|
76
|
+
except Exception as e:
|
|
77
|
+
print(f"⚠️ Failed to close environment: {e}")
|
|
78
|
+
|
|
79
|
+
if __name__ == "__main__":
|
|
80
|
+
main()
|
fleet/__init__.py
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
"""Fleet Python SDK - Environment-based AI agent interactions."""
|
|
16
16
|
|
|
17
|
+
from typing import Optional, List
|
|
18
|
+
|
|
17
19
|
from .exceptions import (
|
|
18
20
|
FleetError,
|
|
19
21
|
FleetAPIError,
|
|
@@ -52,6 +54,8 @@ from .types import VerifierFunction
|
|
|
52
54
|
|
|
53
55
|
# Create a module-level env attribute for convenient access
|
|
54
56
|
from . import env
|
|
57
|
+
from . import global_client as _global_client
|
|
58
|
+
from ._async import global_client as _async_global_client
|
|
55
59
|
|
|
56
60
|
__version__ = "0.1.0"
|
|
57
61
|
|
|
@@ -63,7 +67,7 @@ __all__ = [
|
|
|
63
67
|
"AsyncEnv",
|
|
64
68
|
# Models
|
|
65
69
|
"InstanceResponse",
|
|
66
|
-
"SyncEnv",
|
|
70
|
+
"SyncEnv",
|
|
67
71
|
"Resource",
|
|
68
72
|
"ResetResponse",
|
|
69
73
|
# Task models
|
|
@@ -71,21 +75,72 @@ __all__ = [
|
|
|
71
75
|
"VerifierFunction",
|
|
72
76
|
# Exceptions
|
|
73
77
|
"FleetError",
|
|
74
|
-
"FleetAPIError",
|
|
78
|
+
"FleetAPIError",
|
|
75
79
|
"FleetTimeoutError",
|
|
76
80
|
"FleetConfigurationError",
|
|
77
81
|
# Verifiers (async is default)
|
|
78
82
|
"verifier",
|
|
79
|
-
"verifier_sync",
|
|
83
|
+
"verifier_sync",
|
|
80
84
|
"AsyncVerifierFunction",
|
|
81
85
|
"SyncVerifierFunction",
|
|
82
86
|
"DatabaseSnapshot",
|
|
83
|
-
"IgnoreConfig",
|
|
87
|
+
"IgnoreConfig",
|
|
84
88
|
"SnapshotDiff",
|
|
85
89
|
"TASK_FAILED_SCORE",
|
|
86
90
|
"TASK_SUCCESSFUL_SCORE",
|
|
87
91
|
# Environment module
|
|
88
92
|
"env",
|
|
93
|
+
# Global client helpers
|
|
94
|
+
"configure",
|
|
95
|
+
"get_client",
|
|
96
|
+
"reset_client",
|
|
89
97
|
# Version
|
|
90
98
|
"__version__",
|
|
91
|
-
]
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def load_tasks(env_key: Optional[str] = None) -> List[Task]:
|
|
103
|
+
"""Load tasks without explicitly creating a client.
|
|
104
|
+
|
|
105
|
+
Example:
|
|
106
|
+
tasks = fleet.load_tasks(env_key="fira")
|
|
107
|
+
"""
|
|
108
|
+
# Use global client by default so users can configure once
|
|
109
|
+
return _global_client.get_client().load_tasks(env_key=env_key)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def configure(
|
|
113
|
+
api_key: Optional[str] = None,
|
|
114
|
+
base_url: Optional[str] = None,
|
|
115
|
+
max_retries: int | None = None,
|
|
116
|
+
timeout: float | None = None,
|
|
117
|
+
):
|
|
118
|
+
"""Configure global clients (sync and async) once per process.
|
|
119
|
+
|
|
120
|
+
Both sync and async default clients will be (re)created with the provided settings.
|
|
121
|
+
"""
|
|
122
|
+
if max_retries is None:
|
|
123
|
+
from .config import DEFAULT_MAX_RETRIES as _MR
|
|
124
|
+
|
|
125
|
+
max_retries = _MR
|
|
126
|
+
if timeout is None:
|
|
127
|
+
from .config import DEFAULT_TIMEOUT as _TO
|
|
128
|
+
|
|
129
|
+
timeout = _TO
|
|
130
|
+
_global_client.configure(
|
|
131
|
+
api_key=api_key, base_url=base_url, max_retries=max_retries, timeout=timeout
|
|
132
|
+
)
|
|
133
|
+
_async_global_client.configure(
|
|
134
|
+
api_key=api_key, base_url=base_url, max_retries=max_retries, timeout=timeout
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def get_client() -> Fleet:
|
|
139
|
+
"""Get the global sync client."""
|
|
140
|
+
return _global_client.get_client()
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def reset_client():
|
|
144
|
+
"""Reset both sync and async global clients."""
|
|
145
|
+
_global_client.reset_client()
|
|
146
|
+
_async_global_client.reset_client()
|
fleet/_async/__init__.py
CHANGED
|
@@ -1 +1,258 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Copyright 2025 Fleet AI
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Fleet Python SDK - Async Environment-based AI agent interactions."""
|
|
16
|
+
|
|
17
|
+
from typing import Optional, List
|
|
18
|
+
|
|
19
|
+
from ..exceptions import (
|
|
20
|
+
FleetError,
|
|
21
|
+
FleetAPIError,
|
|
22
|
+
FleetTimeoutError,
|
|
23
|
+
FleetRateLimitError,
|
|
24
|
+
FleetInstanceLimitError,
|
|
25
|
+
FleetConfigurationError,
|
|
26
|
+
)
|
|
27
|
+
from .client import AsyncFleet, AsyncEnv
|
|
28
|
+
from ..models import InstanceResponse, Environment, AccountResponse
|
|
29
|
+
from ..instance.models import Resource, ResetResponse
|
|
30
|
+
|
|
31
|
+
# Import async verifiers
|
|
32
|
+
from .verifiers import (
|
|
33
|
+
verifier,
|
|
34
|
+
AsyncVerifierFunction,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Import async tasks
|
|
38
|
+
from .tasks import Task
|
|
39
|
+
|
|
40
|
+
# Import shared types
|
|
41
|
+
from ..types import VerifierFunction
|
|
42
|
+
|
|
43
|
+
# Create a module-level env attribute for convenient access
|
|
44
|
+
from .. import env
|
|
45
|
+
from . import global_client as _async_global_client
|
|
46
|
+
|
|
47
|
+
__version__ = "0.1.0"
|
|
48
|
+
|
|
49
|
+
__all__ = [
|
|
50
|
+
# Core classes
|
|
51
|
+
"AsyncFleet",
|
|
52
|
+
"AsyncEnv",
|
|
53
|
+
# Models
|
|
54
|
+
"InstanceResponse",
|
|
55
|
+
"Resource",
|
|
56
|
+
"ResetResponse",
|
|
57
|
+
# Task models
|
|
58
|
+
"Task",
|
|
59
|
+
"VerifierFunction",
|
|
60
|
+
# Exceptions
|
|
61
|
+
"FleetError",
|
|
62
|
+
"FleetAPIError",
|
|
63
|
+
"FleetTimeoutError",
|
|
64
|
+
"FleetConfigurationError",
|
|
65
|
+
# Verifiers
|
|
66
|
+
"verifier",
|
|
67
|
+
"AsyncVerifierFunction",
|
|
68
|
+
# Environment module
|
|
69
|
+
"env",
|
|
70
|
+
# Global client helpers
|
|
71
|
+
"configure",
|
|
72
|
+
"get_client",
|
|
73
|
+
"reset_client",
|
|
74
|
+
# Module-level functions
|
|
75
|
+
"load_tasks",
|
|
76
|
+
"list_envs",
|
|
77
|
+
"list_regions",
|
|
78
|
+
"environment",
|
|
79
|
+
"make",
|
|
80
|
+
"make_for_task",
|
|
81
|
+
"instances",
|
|
82
|
+
"instance",
|
|
83
|
+
"delete",
|
|
84
|
+
"load_tasks_from_file",
|
|
85
|
+
"load_task_array_from_string",
|
|
86
|
+
"load_task_from_string",
|
|
87
|
+
"load_task_from_json",
|
|
88
|
+
"export_tasks",
|
|
89
|
+
"import_tasks",
|
|
90
|
+
"account",
|
|
91
|
+
# Version
|
|
92
|
+
"__version__",
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
async def load_tasks(
|
|
97
|
+
env_key: Optional[str] = None,
|
|
98
|
+
keys: Optional[List[str]] = None,
|
|
99
|
+
version: Optional[str] = None,
|
|
100
|
+
team_id: Optional[str] = None
|
|
101
|
+
) -> List[Task]:
|
|
102
|
+
"""Load tasks with optional filtering.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
env_key: Optional environment key to filter tasks by
|
|
106
|
+
keys: Optional list of task keys to filter by
|
|
107
|
+
version: Optional version to filter tasks by
|
|
108
|
+
|
|
109
|
+
Examples:
|
|
110
|
+
tasks = await fleet.load_tasks(env_key="fira")
|
|
111
|
+
tasks = await fleet.load_tasks(keys=["task1", "task2"])
|
|
112
|
+
tasks = await fleet.load_tasks(env_key="fira", version="v1.0")
|
|
113
|
+
"""
|
|
114
|
+
# Use global client by default so users can configure once
|
|
115
|
+
return await _async_global_client.get_client().load_tasks(
|
|
116
|
+
env_key=env_key,
|
|
117
|
+
keys=keys,
|
|
118
|
+
version=version,
|
|
119
|
+
team_id=team_id
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
async def list_envs() -> List[Environment]:
|
|
124
|
+
"""List all available environments."""
|
|
125
|
+
return await _async_global_client.get_client().list_envs()
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
async def list_regions() -> List[str]:
|
|
129
|
+
"""List all available regions."""
|
|
130
|
+
return await _async_global_client.get_client().list_regions()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
async def environment(env_key: str) -> Environment:
|
|
134
|
+
"""Get environment details by key."""
|
|
135
|
+
return await _async_global_client.get_client().environment(env_key)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
async def make(env_key: str, region: Optional[str] = None) -> AsyncEnv:
|
|
139
|
+
"""Create a new environment instance.
|
|
140
|
+
|
|
141
|
+
Example:
|
|
142
|
+
env = await fleet.make("fira")
|
|
143
|
+
"""
|
|
144
|
+
return await _async_global_client.get_client().make(env_key, region)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
async def make_for_task(task: Task) -> AsyncEnv:
|
|
148
|
+
"""Create an environment instance for a specific task."""
|
|
149
|
+
return await _async_global_client.get_client().make_for_task(task)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
async def instances(status: Optional[str] = None, region: Optional[str] = None) -> List[AsyncEnv]:
|
|
153
|
+
"""List existing environment instances."""
|
|
154
|
+
return await _async_global_client.get_client().instances(status, region)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
async def instance(instance_id: str) -> AsyncEnv:
|
|
158
|
+
"""Get an existing environment instance by ID."""
|
|
159
|
+
return await _async_global_client.get_client().instance(instance_id)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
async def delete(instance_id: str) -> InstanceResponse:
|
|
163
|
+
"""Delete an environment instance."""
|
|
164
|
+
return await _async_global_client.get_client().delete(instance_id)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
async def load_tasks_from_file(filename: str) -> List[Task]:
|
|
168
|
+
"""Load tasks from a JSON file.
|
|
169
|
+
|
|
170
|
+
Example:
|
|
171
|
+
tasks = await fleet.load_tasks_from_file("my_tasks.json")
|
|
172
|
+
"""
|
|
173
|
+
return await _async_global_client.get_client().load_tasks_from_file(filename)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
async def load_task_array_from_string(serialized_tasks: str) -> List[Task]:
|
|
177
|
+
"""Load tasks from a JSON string containing an array of tasks.
|
|
178
|
+
|
|
179
|
+
Example:
|
|
180
|
+
tasks = await fleet.load_task_array_from_string(json_string)
|
|
181
|
+
"""
|
|
182
|
+
return await _async_global_client.get_client().load_task_array_from_string(serialized_tasks)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
async def load_task_from_string(task_string: str) -> Task:
|
|
186
|
+
"""Load a single task from a JSON string.
|
|
187
|
+
|
|
188
|
+
Example:
|
|
189
|
+
task = await fleet.load_task_from_string(task_json_string)
|
|
190
|
+
"""
|
|
191
|
+
return await _async_global_client.get_client().load_task_from_string(task_string)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
async def load_task_from_json(task_json: dict) -> Task:
|
|
195
|
+
"""Load a single task from a dictionary.
|
|
196
|
+
|
|
197
|
+
Example:
|
|
198
|
+
task = await fleet.load_task_from_json(task_dict)
|
|
199
|
+
"""
|
|
200
|
+
return await _async_global_client.get_client().load_task_from_json(task_json)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
async def export_tasks(env_key: Optional[str] = None, filename: Optional[str] = None) -> Optional[str]:
|
|
204
|
+
"""Export tasks to a JSON file.
|
|
205
|
+
|
|
206
|
+
Example:
|
|
207
|
+
await fleet.export_tasks("fira", "fira_tasks.json")
|
|
208
|
+
"""
|
|
209
|
+
return await _async_global_client.get_client().export_tasks(env_key, filename)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
async def import_tasks(filename: str):
|
|
213
|
+
"""Import tasks from a JSON file.
|
|
214
|
+
|
|
215
|
+
Example:
|
|
216
|
+
await fleet.import_tasks("tasks.json")
|
|
217
|
+
"""
|
|
218
|
+
return await _async_global_client.get_client().import_tasks(filename)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
async def account() -> AccountResponse:
|
|
222
|
+
"""Get account information including instance limits and usage."""
|
|
223
|
+
return await _async_global_client.get_client().account()
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def configure(
|
|
227
|
+
api_key: Optional[str] = None,
|
|
228
|
+
base_url: Optional[str] = None,
|
|
229
|
+
max_retries: int | None = None,
|
|
230
|
+
timeout: float | None = None,
|
|
231
|
+
):
|
|
232
|
+
"""Configure global async client once per process.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
api_key: API key for authentication
|
|
236
|
+
base_url: Base URL for the API
|
|
237
|
+
max_retries: Maximum number of retries
|
|
238
|
+
timeout: Request timeout in seconds
|
|
239
|
+
"""
|
|
240
|
+
if max_retries is None:
|
|
241
|
+
from ..config import DEFAULT_MAX_RETRIES as _MR
|
|
242
|
+
max_retries = _MR
|
|
243
|
+
if timeout is None:
|
|
244
|
+
from ..config import DEFAULT_TIMEOUT as _TO
|
|
245
|
+
timeout = _TO
|
|
246
|
+
_async_global_client.configure(
|
|
247
|
+
api_key=api_key, base_url=base_url, max_retries=max_retries, timeout=timeout
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def get_client() -> AsyncFleet:
|
|
252
|
+
"""Get the global async client."""
|
|
253
|
+
return _async_global_client.get_client()
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def reset_client():
|
|
257
|
+
"""Reset the async global client."""
|
|
258
|
+
_async_global_client.reset_client()
|
fleet/_async/base.py
CHANGED
|
@@ -46,6 +46,7 @@ class BaseWrapper:
|
|
|
46
46
|
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
47
47
|
# Debug log
|
|
48
48
|
import logging
|
|
49
|
+
|
|
49
50
|
logger = logging.getLogger(__name__)
|
|
50
51
|
logger.debug(f"Headers being sent: {headers}")
|
|
51
52
|
return headers
|
|
@@ -89,7 +90,7 @@ class AsyncWrapper(BaseWrapper):
|
|
|
89
90
|
def _handle_error_response(self, response: httpx.Response) -> None:
|
|
90
91
|
"""Handle HTTP error responses and convert to appropriate Fleet exceptions."""
|
|
91
92
|
status_code = response.status_code
|
|
92
|
-
|
|
93
|
+
|
|
93
94
|
# Debug log 500 errors
|
|
94
95
|
if status_code == 500:
|
|
95
96
|
logger.error(f"Got 500 error from {response.url}")
|