fleet-python 0.1.0__py3-none-any.whl → 0.2.0__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/browser_control_example.py +51 -0
- fleet/__init__.py +4 -16
- fleet/base.py +74 -0
- fleet/client.py +115 -279
- fleet/env/__init__.py +3 -25
- fleet/env/base.py +50 -318
- fleet/env/client.py +241 -0
- fleet/env/models.py +127 -0
- fleet/models.py +109 -0
- fleet/resources/base.py +23 -0
- fleet/resources/browser.py +18 -0
- fleet/resources/sqlite.py +41 -0
- {fleet_python-0.1.0.dist-info → fleet_python-0.2.0.dist-info}/METADATA +2 -1
- fleet_python-0.2.0.dist-info/RECORD +19 -0
- fleet/config.py +0 -125
- fleet/env/factory.py +0 -446
- fleet/facets/__init__.py +0 -7
- fleet/facets/base.py +0 -223
- fleet/facets/factory.py +0 -29
- fleet/manager_client.py +0 -177
- fleet_python-0.1.0.dist-info/RECORD +0 -17
- {fleet_python-0.1.0.dist-info → fleet_python-0.2.0.dist-info}/WHEEL +0 -0
- {fleet_python-0.1.0.dist-info → fleet_python-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {fleet_python-0.1.0.dist-info → fleet_python-0.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Example demonstrating browser control with Fleet Manager Client."""
|
|
3
|
+
|
|
4
|
+
import asyncio
|
|
5
|
+
import fleet as flt
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def main():
|
|
9
|
+
fleet = flt.AsyncFleet()
|
|
10
|
+
|
|
11
|
+
environments = await fleet.list_envs()
|
|
12
|
+
print("Environments:", len(environments))
|
|
13
|
+
|
|
14
|
+
instances = await fleet.instances(status="running")
|
|
15
|
+
print("Instances:", len(instances))
|
|
16
|
+
|
|
17
|
+
instance = await fleet.instance("16fdbc96")
|
|
18
|
+
print("Instance:", instance.instance_id)
|
|
19
|
+
print("Instance Environment:", instance.env_key)
|
|
20
|
+
|
|
21
|
+
environment = await fleet.environment(instance.env_key)
|
|
22
|
+
print("Environment Default Version:", environment.default_version)
|
|
23
|
+
|
|
24
|
+
response = await instance.env.reset()
|
|
25
|
+
print("Reset response:", response)
|
|
26
|
+
|
|
27
|
+
print(await instance.env.resources())
|
|
28
|
+
|
|
29
|
+
sqlite = instance.env.sqlite("current")
|
|
30
|
+
print("SQLite:", await sqlite.describe())
|
|
31
|
+
|
|
32
|
+
print("Query:", await sqlite.query("SELECT * FROM users"))
|
|
33
|
+
|
|
34
|
+
sqlite = await instance.env.state("sqlite://current").describe()
|
|
35
|
+
print("SQLite:", sqlite)
|
|
36
|
+
|
|
37
|
+
browser = await instance.env.browser("cdp").describe()
|
|
38
|
+
print("CDP URL:", browser.url)
|
|
39
|
+
print("CDP Devtools URL:", browser.devtools_url)
|
|
40
|
+
|
|
41
|
+
# Create a new instance
|
|
42
|
+
instance = await fleet.make(flt.InstanceRequest(env_key=instance.env_key))
|
|
43
|
+
print("New Instance:", instance.instance_id)
|
|
44
|
+
|
|
45
|
+
# Delete the instance
|
|
46
|
+
instance = await fleet.delete(instance.instance_id)
|
|
47
|
+
print("Instance deleted:", instance.terminated_at)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
asyncio.run(main())
|
fleet/__init__.py
CHANGED
|
@@ -14,29 +14,17 @@
|
|
|
14
14
|
|
|
15
15
|
"""Fleet Python SDK - Environment-based AI agent interactions."""
|
|
16
16
|
|
|
17
|
-
from . import env
|
|
18
17
|
from .exceptions import FleetError, FleetAPIError, FleetTimeoutError, FleetConfigurationError
|
|
19
|
-
from .
|
|
20
|
-
from .client import FleetAPIClient, InstanceRequest, InstanceResponse, EnvDetails as APIEnvironment, HealthResponse, ManagerURLs, InstanceURLs
|
|
21
|
-
from .manager_client import FleetManagerClient, ManagerHealthResponse, TimestampResponse
|
|
18
|
+
from .client import Fleet, AsyncFleet, InstanceRequest
|
|
22
19
|
|
|
23
|
-
__version__ = "0.1.
|
|
20
|
+
__version__ = "0.1.1"
|
|
24
21
|
__all__ = [
|
|
25
22
|
"env",
|
|
26
23
|
"FleetError",
|
|
27
24
|
"FleetAPIError",
|
|
28
25
|
"FleetTimeoutError",
|
|
29
26
|
"FleetConfigurationError",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"FleetAPIClient",
|
|
27
|
+
"Fleet",
|
|
28
|
+
"AsyncFleet",
|
|
33
29
|
"InstanceRequest",
|
|
34
|
-
"InstanceResponse",
|
|
35
|
-
"APIEnvironment",
|
|
36
|
-
"HealthResponse",
|
|
37
|
-
"ManagerURLs",
|
|
38
|
-
"InstanceURLs",
|
|
39
|
-
"FleetManagerClient",
|
|
40
|
-
"ManagerHealthResponse",
|
|
41
|
-
"TimestampResponse",
|
|
42
30
|
]
|
fleet/base.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
from typing import Dict, Any, Optional
|
|
3
|
+
|
|
4
|
+
from .models import InstanceResponse
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class InstanceBase(InstanceResponse):
|
|
8
|
+
@property
|
|
9
|
+
def manager_url(self) -> str:
|
|
10
|
+
return f"{self.urls.manager.api}"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BaseWrapper:
|
|
14
|
+
def __init__(self, *, api_key: Optional[str], base_url: Optional[str]):
|
|
15
|
+
if api_key is None:
|
|
16
|
+
raise ValueError("api_key is required")
|
|
17
|
+
self.api_key = api_key
|
|
18
|
+
if base_url is None:
|
|
19
|
+
base_url = "https://fleet.new"
|
|
20
|
+
self.base_url = base_url
|
|
21
|
+
|
|
22
|
+
def get_headers(self) -> Dict[str, str]:
|
|
23
|
+
headers: Dict[str, str] = {
|
|
24
|
+
"X-Fleet-SDK-Language": "Python",
|
|
25
|
+
"X-Fleet-SDK-Version": "1.0.0",
|
|
26
|
+
}
|
|
27
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
28
|
+
return headers
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class SyncWrapper(BaseWrapper):
|
|
32
|
+
def __init__(self, *, httpx_client: httpx.Client, **kwargs):
|
|
33
|
+
super().__init__(**kwargs)
|
|
34
|
+
self.httpx_client = httpx_client
|
|
35
|
+
|
|
36
|
+
def request(
|
|
37
|
+
self,
|
|
38
|
+
method: str,
|
|
39
|
+
url: str,
|
|
40
|
+
params: Optional[Dict[str, Any]] = None,
|
|
41
|
+
json: Optional[Any] = None,
|
|
42
|
+
**kwargs,
|
|
43
|
+
) -> httpx.Response:
|
|
44
|
+
return self.httpx_client.request(
|
|
45
|
+
method,
|
|
46
|
+
f"{self.base_url}{url}",
|
|
47
|
+
headers=self.get_headers(),
|
|
48
|
+
params=params,
|
|
49
|
+
json=json,
|
|
50
|
+
**kwargs,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class AsyncWrapper(BaseWrapper):
|
|
55
|
+
def __init__(self, *, httpx_client: httpx.AsyncClient, **kwargs):
|
|
56
|
+
super().__init__(**kwargs)
|
|
57
|
+
self.httpx_client = httpx_client
|
|
58
|
+
|
|
59
|
+
async def request(
|
|
60
|
+
self,
|
|
61
|
+
method: str,
|
|
62
|
+
url: str,
|
|
63
|
+
params: Optional[Dict[str, Any]] = None,
|
|
64
|
+
json: Optional[Any] = None,
|
|
65
|
+
**kwargs,
|
|
66
|
+
) -> httpx.Response:
|
|
67
|
+
return await self.httpx_client.request(
|
|
68
|
+
method,
|
|
69
|
+
f"{self.base_url}{url}",
|
|
70
|
+
headers=self.get_headers(),
|
|
71
|
+
params=params,
|
|
72
|
+
json=json,
|
|
73
|
+
**kwargs,
|
|
74
|
+
)
|
fleet/client.py
CHANGED
|
@@ -15,304 +15,140 @@
|
|
|
15
15
|
"""Fleet API Client for making HTTP requests to Fleet services."""
|
|
16
16
|
|
|
17
17
|
import asyncio
|
|
18
|
+
import os
|
|
19
|
+
import httpx
|
|
18
20
|
import logging
|
|
19
|
-
from typing import
|
|
20
|
-
from datetime import datetime
|
|
21
|
-
import aiohttp
|
|
22
|
-
from pydantic import BaseModel, Field
|
|
21
|
+
from typing import Optional, List
|
|
23
22
|
|
|
24
|
-
from .
|
|
25
|
-
from .
|
|
26
|
-
FleetAPIError,
|
|
27
|
-
FleetAuthenticationError,
|
|
28
|
-
FleetRateLimitError,
|
|
29
|
-
FleetTimeoutError,
|
|
30
|
-
FleetError,
|
|
31
|
-
)
|
|
23
|
+
from .base import InstanceBase, AsyncWrapper, SyncWrapper
|
|
24
|
+
from .models import InstanceRequest, InstanceRecord, Environment as EnvironmentModel
|
|
32
25
|
|
|
26
|
+
from .env import Environment, AsyncEnvironment
|
|
33
27
|
|
|
34
28
|
logger = logging.getLogger(__name__)
|
|
35
29
|
|
|
36
30
|
|
|
37
|
-
class
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
region: Optional[str] = Field("us-west-1", description="AWS region")
|
|
43
|
-
seed: Optional[int] = Field(None, description="Random seed for deterministic behavior")
|
|
44
|
-
timestamp: Optional[int] = Field(None, description="Timestamp for environment state")
|
|
45
|
-
p_error: Optional[float] = Field(None, description="Error probability")
|
|
46
|
-
avg_latency: Optional[float] = Field(None, description="Average latency")
|
|
47
|
-
run_id: Optional[str] = Field(None, description="Run ID for tracking")
|
|
48
|
-
task_id: Optional[str] = Field(None, description="Task ID for tracking")
|
|
31
|
+
class Instance(InstanceBase):
|
|
32
|
+
def __init__(self, httpx_client: Optional[httpx.Client] = None, **kwargs):
|
|
33
|
+
super().__init__(**kwargs)
|
|
34
|
+
self._httpx_client = httpx_client or httpx.Client()
|
|
35
|
+
self._env: Optional[Environment] = None
|
|
49
36
|
|
|
37
|
+
@property
|
|
38
|
+
def env(self) -> Environment:
|
|
39
|
+
if self._env is None:
|
|
40
|
+
self._env = Environment(self.manager_url, self._httpx_client)
|
|
41
|
+
return self._env
|
|
50
42
|
|
|
51
|
-
class ManagerURLs(BaseModel):
|
|
52
|
-
"""Model for manager API URLs."""
|
|
53
|
-
|
|
54
|
-
api: str = Field(..., description="Manager API URL")
|
|
55
|
-
docs: str = Field(..., description="Manager docs URL")
|
|
56
|
-
reset: str = Field(..., description="Reset URL")
|
|
57
|
-
diff: str = Field(..., description="Diff URL")
|
|
58
|
-
snapshot: str = Field(..., description="Snapshot URL")
|
|
59
|
-
execute_verifier_function: str = Field(..., description="Execute verifier function URL")
|
|
60
|
-
execute_verifier_function_with_upload: str = Field(..., description="Execute verifier function with upload URL")
|
|
61
43
|
|
|
44
|
+
class AsyncInstance(InstanceBase):
|
|
45
|
+
def __init__(self, httpx_client: Optional[httpx.AsyncClient] = None, **kwargs):
|
|
46
|
+
super().__init__(**kwargs)
|
|
47
|
+
self._httpx_client = httpx_client or httpx.AsyncClient()
|
|
48
|
+
self._env: Optional[AsyncEnvironment] = None
|
|
62
49
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
api: Optional[str] = Field(None, description="API URL")
|
|
69
|
-
health: Optional[str] = Field(None, description="Health check URL")
|
|
70
|
-
api_docs: Optional[str] = Field(None, description="API documentation URL")
|
|
71
|
-
manager: ManagerURLs = Field(..., description="Manager API URLs")
|
|
50
|
+
@property
|
|
51
|
+
def env(self) -> AsyncEnvironment:
|
|
52
|
+
if self._env is None:
|
|
53
|
+
self._env = AsyncEnvironment(self.manager_url, self._httpx_client)
|
|
54
|
+
return self._env
|
|
72
55
|
|
|
73
56
|
|
|
74
|
-
class
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
57
|
+
class Fleet:
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
api_key: Optional[str] = os.getenv("FLEET_API_KEY"),
|
|
61
|
+
base_url: Optional[str] = None,
|
|
62
|
+
httpx_client: Optional[httpx.Client] = None,
|
|
63
|
+
):
|
|
64
|
+
self._httpx_client = httpx_client or httpx.Client(timeout=60.0)
|
|
65
|
+
self.client = SyncWrapper(
|
|
66
|
+
api_key=api_key,
|
|
67
|
+
base_url=base_url,
|
|
68
|
+
httpx_client=self._httpx_client,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
def environments(self) -> List[EnvironmentModel]:
|
|
72
|
+
response = self.client.request("GET", "/v1/env/")
|
|
73
|
+
return [EnvironmentModel(**env_data) for env_data in response.json()]
|
|
74
|
+
|
|
75
|
+
def environment(self, env_key: str) -> EnvironmentModel:
|
|
76
|
+
response = self.client.request("GET", f"/v1/env/{env_key}")
|
|
77
|
+
return EnvironmentModel(**response.json())
|
|
78
|
+
|
|
79
|
+
def make(self, request: InstanceRequest) -> Instance:
|
|
80
|
+
response = self.client.request(
|
|
81
|
+
"POST", "/v1/env/instances", json=request.model_dump()
|
|
82
|
+
)
|
|
83
|
+
return Instance(**response.json())
|
|
84
|
+
|
|
85
|
+
def instances(self, status: Optional[str] = None) -> List[Instance]:
|
|
86
|
+
params = {}
|
|
87
|
+
if status:
|
|
88
|
+
params["status"] = status
|
|
90
89
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
env_key: str = Field(..., description="Environment key")
|
|
95
|
-
name: str = Field(..., description="Environment name")
|
|
96
|
-
description: Optional[str] = Field(..., description="Environment description")
|
|
97
|
-
default_version: Optional[str] = Field(..., description="Default version")
|
|
98
|
-
versions: Dict[str, str] = Field(..., description="Available versions")
|
|
90
|
+
response = self.client.request("GET", "/v1/env/instances", params=params)
|
|
91
|
+
return [Instance(**instance_data) for instance_data in response.json()]
|
|
99
92
|
|
|
93
|
+
def instance(self, instance_id: str) -> Instance:
|
|
94
|
+
response = self.client.request("GET", f"/v1/env/instances/{instance_id}")
|
|
95
|
+
return Instance(**response.json())
|
|
100
96
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
status: str = Field(..., description="Health status")
|
|
105
|
-
timestamp: str = Field(..., description="Timestamp")
|
|
106
|
-
mode: str = Field(..., description="Operation mode")
|
|
107
|
-
region: str = Field(..., description="AWS region")
|
|
108
|
-
docker_status: str = Field(..., description="Docker status")
|
|
109
|
-
docker_error: Optional[str] = Field(None, description="Docker error if any")
|
|
110
|
-
instances: int = Field(..., description="Number of instances")
|
|
111
|
-
regions: Optional[Dict[str, "HealthResponse"]] = Field(None, description="Regional health info")
|
|
97
|
+
def delete(self, instance_id: str) -> InstanceRecord:
|
|
98
|
+
response = self.client.request("DELETE", f"/v1/env/instances/{instance_id}")
|
|
99
|
+
return InstanceRecord(**response.json())
|
|
112
100
|
|
|
113
101
|
|
|
114
|
-
class
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def __init__(self, config: FleetConfig):
|
|
118
|
-
"""Initialize the Fleet API client.
|
|
119
|
-
|
|
120
|
-
Args:
|
|
121
|
-
config: Fleet configuration with API key and base URL
|
|
122
|
-
"""
|
|
123
|
-
self.config = config
|
|
124
|
-
self._session: Optional[aiohttp.ClientSession] = None
|
|
125
|
-
self._base_url = config.base_url
|
|
126
|
-
|
|
127
|
-
async def __aenter__(self):
|
|
128
|
-
"""Async context manager entry."""
|
|
129
|
-
await self._ensure_session()
|
|
130
|
-
return self
|
|
131
|
-
|
|
132
|
-
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
133
|
-
"""Async context manager exit."""
|
|
134
|
-
await self.close()
|
|
135
|
-
|
|
136
|
-
async def _ensure_session(self):
|
|
137
|
-
"""Ensure HTTP session is created."""
|
|
138
|
-
if self._session is None or self._session.closed:
|
|
139
|
-
headers = {}
|
|
140
|
-
if self.config.api_key:
|
|
141
|
-
headers["Authorization"] = f"Bearer {self.config.api_key}"
|
|
142
|
-
|
|
143
|
-
timeout = aiohttp.ClientTimeout(total=60)
|
|
144
|
-
self._session = aiohttp.ClientSession(
|
|
145
|
-
headers=headers,
|
|
146
|
-
timeout=timeout,
|
|
147
|
-
connector=aiohttp.TCPConnector(limit=100),
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
async def close(self):
|
|
151
|
-
"""Close the HTTP session."""
|
|
152
|
-
if self._session and not self._session.closed:
|
|
153
|
-
await self._session.close()
|
|
154
|
-
self._session = None
|
|
155
|
-
|
|
156
|
-
async def _request(
|
|
102
|
+
class AsyncFleet:
|
|
103
|
+
def __init__(
|
|
157
104
|
self,
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
url = f"{self._base_url}{path}"
|
|
187
|
-
request_headers = headers or {}
|
|
188
|
-
|
|
189
|
-
try:
|
|
190
|
-
logger.debug(f"Making {method} request to {url}")
|
|
191
|
-
|
|
192
|
-
async with self._session.request(
|
|
193
|
-
method=method,
|
|
194
|
-
url=url,
|
|
195
|
-
json=data,
|
|
196
|
-
params=params,
|
|
197
|
-
headers=request_headers,
|
|
198
|
-
timeout=aiohttp.ClientTimeout(total=timeout or 60),
|
|
199
|
-
) as response:
|
|
200
|
-
response_data = await response.json() if response.content_type == "application/json" else {}
|
|
201
|
-
|
|
202
|
-
if response.status == 200:
|
|
203
|
-
logger.debug(f"Request successful: {response.status}")
|
|
204
|
-
return response_data
|
|
205
|
-
|
|
206
|
-
elif response.status == 401:
|
|
207
|
-
raise FleetAuthenticationError("Authentication failed - check your API key")
|
|
208
|
-
|
|
209
|
-
elif response.status == 429:
|
|
210
|
-
raise FleetRateLimitError("Rate limit exceeded - please retry later")
|
|
211
|
-
|
|
212
|
-
else:
|
|
213
|
-
error_message = response_data.get("detail", f"API request failed with status {response.status}")
|
|
214
|
-
raise FleetAPIError(
|
|
215
|
-
error_message,
|
|
216
|
-
status_code=response.status,
|
|
217
|
-
response_data=response_data,
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
except asyncio.TimeoutError:
|
|
221
|
-
raise FleetTimeoutError(f"Request to {url} timed out")
|
|
222
|
-
|
|
223
|
-
except aiohttp.ClientError as e:
|
|
224
|
-
raise FleetAPIError(f"HTTP client error: {e}")
|
|
225
|
-
|
|
226
|
-
# Environment operations
|
|
227
|
-
async def list_environments(self) -> List[EnvDetails]:
|
|
228
|
-
"""List all available environments.
|
|
229
|
-
|
|
230
|
-
Returns:
|
|
231
|
-
List of EnvDetails objects
|
|
232
|
-
"""
|
|
233
|
-
response = await self._request("GET", "/v1/env/")
|
|
234
|
-
return [EnvDetails(**env_data) for env_data in response]
|
|
235
|
-
|
|
236
|
-
async def get_environment(self, env_key: str) -> EnvDetails:
|
|
237
|
-
"""Get details for a specific environment.
|
|
238
|
-
|
|
239
|
-
Args:
|
|
240
|
-
env_key: Environment key
|
|
241
|
-
|
|
242
|
-
Returns:
|
|
243
|
-
EnvDetails object
|
|
244
|
-
"""
|
|
245
|
-
response = await self._request("GET", f"/v1/env/{env_key}")
|
|
246
|
-
return EnvDetails(**response)
|
|
247
|
-
|
|
248
|
-
# Instance operations
|
|
249
|
-
async def create_instance(self, request: InstanceRequest) -> InstanceResponse:
|
|
250
|
-
"""Create a new environment instance.
|
|
251
|
-
|
|
252
|
-
Args:
|
|
253
|
-
request: Instance creation request
|
|
254
|
-
|
|
255
|
-
Returns:
|
|
256
|
-
InstanceResponse object
|
|
257
|
-
"""
|
|
258
|
-
response = await self._request("POST", "/v1/env/instances", data=request.model_dump(exclude_none=True))
|
|
259
|
-
return InstanceResponse(**response)
|
|
260
|
-
|
|
261
|
-
async def list_instances(self, status: Optional[str] = None) -> List[InstanceResponse]:
|
|
262
|
-
"""List all instances, optionally filtered by status.
|
|
263
|
-
|
|
264
|
-
Args:
|
|
265
|
-
status: Optional status filter (pending, running, stopped, error)
|
|
266
|
-
|
|
267
|
-
Returns:
|
|
268
|
-
List of InstanceResponse objects
|
|
269
|
-
"""
|
|
105
|
+
api_key: Optional[str] = os.getenv("FLEET_API_KEY"),
|
|
106
|
+
base_url: Optional[str] = None,
|
|
107
|
+
httpx_client: Optional[httpx.AsyncClient] = None,
|
|
108
|
+
):
|
|
109
|
+
self._httpx_client = httpx_client or httpx.AsyncClient(timeout=60.0)
|
|
110
|
+
self.client = AsyncWrapper(
|
|
111
|
+
api_key=api_key,
|
|
112
|
+
base_url=base_url,
|
|
113
|
+
httpx_client=self._httpx_client,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
async def list_envs(self) -> List[EnvironmentModel]:
|
|
117
|
+
response = await self.client.request("GET", "/v1/env/")
|
|
118
|
+
return [EnvironmentModel(**env_data) for env_data in response.json()]
|
|
119
|
+
|
|
120
|
+
async def environment(self, env_key: str) -> EnvironmentModel:
|
|
121
|
+
response = await self.client.request("GET", f"/v1/env/{env_key}")
|
|
122
|
+
return EnvironmentModel(**response.json())
|
|
123
|
+
|
|
124
|
+
async def make(self, request: InstanceRequest) -> AsyncInstance:
|
|
125
|
+
response = await self.client.request(
|
|
126
|
+
"POST", "/v1/env/instances", json=request.model_dump()
|
|
127
|
+
)
|
|
128
|
+
instance = AsyncInstance(**response.json())
|
|
129
|
+
await instance.env.load()
|
|
130
|
+
return instance
|
|
131
|
+
|
|
132
|
+
async def instances(self, status: Optional[str] = None) -> List[AsyncInstance]:
|
|
270
133
|
params = {}
|
|
271
134
|
if status:
|
|
272
135
|
params["status"] = status
|
|
273
|
-
|
|
274
|
-
response = await self.
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
Args:
|
|
293
|
-
instance_id: Instance ID
|
|
294
|
-
|
|
295
|
-
Returns:
|
|
296
|
-
Deletion response data
|
|
297
|
-
"""
|
|
298
|
-
response = await self._request("DELETE", f"/v1/env/instances/{instance_id}")
|
|
299
|
-
return response
|
|
300
|
-
|
|
301
|
-
# Health check operations
|
|
302
|
-
async def health_check(self) -> HealthResponse:
|
|
303
|
-
"""Check the health of the Fleet API.
|
|
304
|
-
|
|
305
|
-
Returns:
|
|
306
|
-
HealthResponse object
|
|
307
|
-
"""
|
|
308
|
-
response = await self._request("GET", "/health")
|
|
309
|
-
return HealthResponse(**response)
|
|
310
|
-
|
|
311
|
-
async def health_check_simple(self) -> HealthResponse:
|
|
312
|
-
"""Simple health check without authentication.
|
|
313
|
-
|
|
314
|
-
Returns:
|
|
315
|
-
HealthResponse object
|
|
316
|
-
"""
|
|
317
|
-
response = await self._request("GET", "/health-check")
|
|
318
|
-
return HealthResponse(**response)
|
|
136
|
+
|
|
137
|
+
response = await self.client.request("GET", "/v1/env/instances", params=params)
|
|
138
|
+
instances = [
|
|
139
|
+
AsyncInstance(**instance_data) for instance_data in response.json()
|
|
140
|
+
]
|
|
141
|
+
await asyncio.gather(*[instance.env.load() for instance in instances])
|
|
142
|
+
return instances
|
|
143
|
+
|
|
144
|
+
async def instance(self, instance_id: str) -> AsyncInstance:
|
|
145
|
+
response = await self.client.request("GET", f"/v1/env/instances/{instance_id}")
|
|
146
|
+
instance = AsyncInstance(**response.json())
|
|
147
|
+
await instance.env.load()
|
|
148
|
+
return instance
|
|
149
|
+
|
|
150
|
+
async def delete(self, instance_id: str) -> InstanceRecord:
|
|
151
|
+
response = await self.client.request(
|
|
152
|
+
"DELETE", f"/v1/env/instances/{instance_id}"
|
|
153
|
+
)
|
|
154
|
+
return InstanceRecord(**response.json())
|
fleet/env/__init__.py
CHANGED
|
@@ -1,30 +1,8 @@
|
|
|
1
1
|
"""Fleet SDK Environment Module."""
|
|
2
2
|
|
|
3
|
-
from .
|
|
4
|
-
from .factory import (
|
|
5
|
-
make,
|
|
6
|
-
get,
|
|
7
|
-
list_instances,
|
|
8
|
-
list_envs,
|
|
9
|
-
list_environments,
|
|
10
|
-
list_categories,
|
|
11
|
-
list_names,
|
|
12
|
-
list_versions,
|
|
13
|
-
is_environment_supported,
|
|
14
|
-
EnvironmentInstance
|
|
15
|
-
)
|
|
3
|
+
from .client import Environment, AsyncEnvironment
|
|
16
4
|
|
|
17
5
|
__all__ = [
|
|
18
6
|
"Environment",
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
"make",
|
|
22
|
-
"get",
|
|
23
|
-
"list_instances",
|
|
24
|
-
"list_envs",
|
|
25
|
-
"list_environments",
|
|
26
|
-
"list_categories",
|
|
27
|
-
"list_names",
|
|
28
|
-
"list_versions",
|
|
29
|
-
"is_environment_supported",
|
|
30
|
-
]
|
|
7
|
+
"AsyncEnvironment",
|
|
8
|
+
]
|