fleet-python 0.2.3__py3-none-any.whl → 0.2.4__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/dsl_example.py +2 -1
- examples/example.py +2 -2
- examples/json_tasks_example.py +1 -1
- examples/nova_act_example.py +1 -1
- examples/openai_example.py +17 -24
- examples/openai_simple_example.py +11 -12
- fleet/__init__.py +18 -3
- fleet/_async/base.py +51 -0
- fleet/_async/client.py +133 -0
- fleet/_async/env/__init__.py +0 -0
- fleet/_async/env/client.py +15 -0
- fleet/_async/exceptions.py +73 -0
- fleet/_async/instance/__init__.py +24 -0
- fleet/_async/instance/base.py +37 -0
- fleet/_async/instance/client.py +278 -0
- fleet/_async/instance/models.py +141 -0
- fleet/_async/models.py +109 -0
- fleet/_async/playwright.py +291 -0
- fleet/_async/resources/__init__.py +0 -0
- fleet/_async/resources/base.py +26 -0
- fleet/_async/resources/browser.py +41 -0
- fleet/_async/resources/sqlite.py +41 -0
- fleet/base.py +1 -24
- fleet/client.py +31 -99
- fleet/env/__init__.py +13 -1
- fleet/env/client.py +7 -7
- fleet/instance/__init__.py +3 -2
- fleet/instance/base.py +1 -24
- fleet/instance/client.py +40 -57
- fleet/playwright.py +45 -47
- fleet/resources/__init__.py +0 -0
- fleet/resources/browser.py +14 -14
- fleet/resources/sqlite.py +11 -11
- fleet/verifiers/__init__.py +5 -10
- fleet/verifiers/code.py +1 -132
- {fleet_python-0.2.3.dist-info → fleet_python-0.2.4.dist-info}/METADATA +2 -1
- fleet_python-0.2.4.dist-info/RECORD +48 -0
- {fleet_python-0.2.3.dist-info → fleet_python-0.2.4.dist-info}/top_level.txt +1 -0
- scripts/unasync.py +28 -0
- fleet_python-0.2.3.dist-info/RECORD +0 -31
- {fleet_python-0.2.3.dist-info → fleet_python-0.2.4.dist-info}/WHEEL +0 -0
- {fleet_python-0.2.3.dist-info → fleet_python-0.2.4.dist-info}/licenses/LICENSE +0 -0
examples/dsl_example.py
CHANGED
|
@@ -65,7 +65,7 @@ def validate_new_deal_creation(
|
|
|
65
65
|
async def main():
|
|
66
66
|
# Create a new instance
|
|
67
67
|
print("Creating new Hubspot instance...")
|
|
68
|
-
env = await flt.env.
|
|
68
|
+
env = await flt.env.make_async("hubspot:v1.2.7")
|
|
69
69
|
print(f"New Instance: {env.instance_id}")
|
|
70
70
|
|
|
71
71
|
try:
|
|
@@ -99,6 +99,7 @@ async def main():
|
|
|
99
99
|
)
|
|
100
100
|
"""
|
|
101
101
|
|
|
102
|
+
print("RESOURCES", await env.resources())
|
|
102
103
|
db = env.db()
|
|
103
104
|
insert_result = await db.exec(insert_query)
|
|
104
105
|
print(f"Insert result: {insert_result}")
|
examples/example.py
CHANGED
|
@@ -6,11 +6,11 @@ import fleet as flt
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
async def main():
|
|
9
|
-
environments = await flt.env.
|
|
9
|
+
environments = await flt.env.list_envs_async()
|
|
10
10
|
print("Environments:", len(environments))
|
|
11
11
|
|
|
12
12
|
# Create a new instance
|
|
13
|
-
env = await flt.env.
|
|
13
|
+
env = await flt.env.make_async("hubspot:v1.2.7")
|
|
14
14
|
print("New Instance:", env.instance_id)
|
|
15
15
|
|
|
16
16
|
response = await env.reset(seed=42)
|
examples/json_tasks_example.py
CHANGED
|
@@ -39,7 +39,7 @@ async def main():
|
|
|
39
39
|
if not file_path.exists():
|
|
40
40
|
raise FileNotFoundError(f"Error: File '{args.json_file}' not found")
|
|
41
41
|
|
|
42
|
-
env = await flt.env.
|
|
42
|
+
env = await flt.env.make_async("fira:v1.2.7")
|
|
43
43
|
print(f"New Instance: {env.urls.app}")
|
|
44
44
|
|
|
45
45
|
successes = 0
|
examples/nova_act_example.py
CHANGED
examples/openai_example.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
from openai import AsyncOpenAI
|
|
1
|
+
from openai import OpenAI
|
|
3
2
|
import fleet as flt
|
|
4
3
|
import json
|
|
5
4
|
from typing import Callable
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
client =
|
|
7
|
+
client = OpenAI()
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
def sanitize_message(msg: dict) -> dict:
|
|
@@ -50,7 +49,7 @@ class Agent:
|
|
|
50
49
|
if self.debug:
|
|
51
50
|
print(*args)
|
|
52
51
|
|
|
53
|
-
|
|
52
|
+
def handle_item(self, item):
|
|
54
53
|
"""Handle each item; may cause a computer action + screenshot."""
|
|
55
54
|
if self.debug:
|
|
56
55
|
print(f"Handling item of type: {item.get('type')}")
|
|
@@ -66,7 +65,7 @@ class Agent:
|
|
|
66
65
|
|
|
67
66
|
if hasattr(self.computer, name): # if function exists on computer, call it
|
|
68
67
|
method = getattr(self.computer, name)
|
|
69
|
-
|
|
68
|
+
method(**args)
|
|
70
69
|
return [
|
|
71
70
|
{
|
|
72
71
|
"type": "function_call_output",
|
|
@@ -83,9 +82,9 @@ class Agent:
|
|
|
83
82
|
print(f"{action_type}({action_args})")
|
|
84
83
|
|
|
85
84
|
method = getattr(self.computer, action_type)
|
|
86
|
-
|
|
85
|
+
method(**action_args)
|
|
87
86
|
|
|
88
|
-
screenshot_base64 =
|
|
87
|
+
screenshot_base64 = self.computer.screenshot()
|
|
89
88
|
|
|
90
89
|
# if user doesn't ack all safety checks exit with error
|
|
91
90
|
pending_checks = item.get("pending_safety_checks", [])
|
|
@@ -114,7 +113,7 @@ class Agent:
|
|
|
114
113
|
return [call_output]
|
|
115
114
|
return []
|
|
116
115
|
|
|
117
|
-
|
|
116
|
+
def run_full_turn(
|
|
118
117
|
self, input_items, print_steps=True, debug=False, show_images=False
|
|
119
118
|
):
|
|
120
119
|
self.print_steps = print_steps
|
|
@@ -134,7 +133,7 @@ class Agent:
|
|
|
134
133
|
|
|
135
134
|
clean_input = [_clean_item(m) for m in (input_items + new_items)]
|
|
136
135
|
|
|
137
|
-
response =
|
|
136
|
+
response = client.responses.create(
|
|
138
137
|
model=self.model,
|
|
139
138
|
input=clean_input,
|
|
140
139
|
tools=self.tools,
|
|
@@ -173,7 +172,7 @@ class Agent:
|
|
|
173
172
|
new_items.append(item)
|
|
174
173
|
|
|
175
174
|
# Next, perform any local side-effects (browser actions, etc.).
|
|
176
|
-
handled_items =
|
|
175
|
+
handled_items = self.handle_item(item)
|
|
177
176
|
|
|
178
177
|
# If the handler generated additional items (e.g. computer_call_output)
|
|
179
178
|
# we append those *immediately* so the order remains:
|
|
@@ -187,19 +186,13 @@ class Agent:
|
|
|
187
186
|
tools = []
|
|
188
187
|
|
|
189
188
|
|
|
190
|
-
|
|
191
|
-
"""Async version of input()"""
|
|
192
|
-
loop = asyncio.get_event_loop()
|
|
193
|
-
return await loop.run_in_executor(None, input, prompt)
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
async def main():
|
|
189
|
+
def main():
|
|
197
190
|
# Create a Fleet environment instance
|
|
198
|
-
instance =
|
|
191
|
+
instance = flt.env.make("hubspot")
|
|
199
192
|
|
|
200
193
|
# Create the Playwright wrapper
|
|
201
194
|
browser = flt.FleetPlaywrightWrapper(instance)
|
|
202
|
-
|
|
195
|
+
browser.start()
|
|
203
196
|
|
|
204
197
|
try:
|
|
205
198
|
agent = Agent(browser, model="computer-use-preview", tools=[])
|
|
@@ -212,9 +205,9 @@ async def main():
|
|
|
212
205
|
|
|
213
206
|
while True:
|
|
214
207
|
try:
|
|
215
|
-
user_input =
|
|
208
|
+
user_input = input("> ")
|
|
216
209
|
items.append({"role": "user", "content": user_input})
|
|
217
|
-
output_items =
|
|
210
|
+
output_items = agent.run_full_turn(
|
|
218
211
|
items, show_images=False, debug=False
|
|
219
212
|
)
|
|
220
213
|
items += output_items
|
|
@@ -225,9 +218,9 @@ async def main():
|
|
|
225
218
|
print(f"Error during interaction: {e}")
|
|
226
219
|
# Continue the loop for other errors
|
|
227
220
|
finally:
|
|
228
|
-
|
|
229
|
-
|
|
221
|
+
browser.close()
|
|
222
|
+
instance.close()
|
|
230
223
|
|
|
231
224
|
|
|
232
225
|
if __name__ == "__main__":
|
|
233
|
-
|
|
226
|
+
main()
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
from openai import AsyncOpenAI
|
|
1
|
+
from openai import OpenAI
|
|
3
2
|
import fleet as flt
|
|
4
3
|
|
|
5
|
-
client =
|
|
4
|
+
client = OpenAI()
|
|
6
5
|
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
instance =
|
|
7
|
+
def main():
|
|
8
|
+
instance = flt.env.make("hubspot")
|
|
10
9
|
|
|
11
10
|
browser = flt.FleetPlaywrightWrapper(instance)
|
|
12
|
-
|
|
11
|
+
browser.start()
|
|
13
12
|
|
|
14
13
|
try:
|
|
15
14
|
width, height = browser.get_dimensions()
|
|
@@ -22,7 +21,7 @@ async def main():
|
|
|
22
21
|
}
|
|
23
22
|
]
|
|
24
23
|
|
|
25
|
-
response =
|
|
24
|
+
response = client.responses.create(
|
|
26
25
|
model="computer-use-preview",
|
|
27
26
|
input=[
|
|
28
27
|
{
|
|
@@ -41,21 +40,21 @@ async def main():
|
|
|
41
40
|
if response.output[0].type == "computer_call":
|
|
42
41
|
action = response.output[0].action
|
|
43
42
|
if action.type == "screenshot":
|
|
44
|
-
screenshot_base64 =
|
|
43
|
+
screenshot_base64 = browser.screenshot()
|
|
45
44
|
result = {
|
|
46
45
|
"type": "input_image",
|
|
47
46
|
"image_url": f"data:image/png;base64,{screenshot_base64}",
|
|
48
47
|
"current_url": browser.get_current_url(),
|
|
49
48
|
}
|
|
50
49
|
else:
|
|
51
|
-
result =
|
|
50
|
+
result = browser.execute_computer_action(action)
|
|
52
51
|
|
|
53
52
|
print("Computer action result:")
|
|
54
53
|
print(result)
|
|
55
54
|
finally:
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
browser.close()
|
|
56
|
+
instance.close()
|
|
58
57
|
|
|
59
58
|
|
|
60
59
|
if __name__ == "__main__":
|
|
61
|
-
|
|
60
|
+
main()
|
fleet/__init__.py
CHANGED
|
@@ -20,8 +20,11 @@ from .exceptions import (
|
|
|
20
20
|
FleetTimeoutError,
|
|
21
21
|
FleetConfigurationError,
|
|
22
22
|
)
|
|
23
|
-
from .client import Fleet,
|
|
23
|
+
from .client import Fleet, Environment
|
|
24
|
+
from ._async.client import AsyncFleet, AsyncEnvironment
|
|
25
|
+
from .models import InstanceRequest
|
|
24
26
|
from .instance import (
|
|
27
|
+
InstanceClient,
|
|
25
28
|
AsyncInstanceClient,
|
|
26
29
|
ResetRequest,
|
|
27
30
|
ResetResponse,
|
|
@@ -30,7 +33,12 @@ from .instance import (
|
|
|
30
33
|
ChromeStartResponse,
|
|
31
34
|
ChromeStatusResponse,
|
|
32
35
|
)
|
|
33
|
-
from .verifiers import
|
|
36
|
+
from .verifiers import (
|
|
37
|
+
DatabaseSnapshot,
|
|
38
|
+
IgnoreConfig,
|
|
39
|
+
SnapshotDiff,
|
|
40
|
+
TASK_SUCCESSFUL_SCORE,
|
|
41
|
+
)
|
|
34
42
|
from . import env
|
|
35
43
|
|
|
36
44
|
# Optional playwright integration
|
|
@@ -49,7 +57,10 @@ __all__ = [
|
|
|
49
57
|
"FleetTimeoutError",
|
|
50
58
|
"FleetConfigurationError",
|
|
51
59
|
"Fleet",
|
|
60
|
+
"Environment",
|
|
52
61
|
"AsyncFleet",
|
|
62
|
+
"AsyncEnvironment",
|
|
63
|
+
"InstanceClient",
|
|
53
64
|
"AsyncInstanceClient",
|
|
54
65
|
"InstanceRequest",
|
|
55
66
|
"ResetRequest",
|
|
@@ -58,8 +69,12 @@ __all__ = [
|
|
|
58
69
|
"ChromeStartRequest",
|
|
59
70
|
"ChromeStartResponse",
|
|
60
71
|
"ChromeStatusResponse",
|
|
72
|
+
"DatabaseSnapshot",
|
|
73
|
+
"IgnoreConfig",
|
|
74
|
+
"SnapshotDiff",
|
|
75
|
+
"TASK_SUCCESSFUL_SCORE",
|
|
61
76
|
]
|
|
62
77
|
|
|
63
78
|
# Add playwright wrapper to exports if available
|
|
64
79
|
if _PLAYWRIGHT_AVAILABLE:
|
|
65
|
-
__all__.append("FleetPlaywrightWrapper")
|
|
80
|
+
__all__.append("FleetPlaywrightWrapper")
|
fleet/_async/base.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
from typing import Dict, Any, Optional
|
|
3
|
+
|
|
4
|
+
from .models import InstanceResponse
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class EnvironmentBase(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 AsyncWrapper(BaseWrapper):
|
|
32
|
+
def __init__(self, *, httpx_client: httpx.AsyncClient, **kwargs):
|
|
33
|
+
super().__init__(**kwargs)
|
|
34
|
+
self.httpx_client = httpx_client
|
|
35
|
+
|
|
36
|
+
async 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 await 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
|
+
)
|
fleet/_async/client.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
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 API Client for making HTTP requests to Fleet services."""
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
import httpx
|
|
19
|
+
import logging
|
|
20
|
+
from typing import Optional, List
|
|
21
|
+
|
|
22
|
+
from .base import EnvironmentBase, AsyncWrapper
|
|
23
|
+
from .models import InstanceRequest, InstanceRecord, Environment as EnvironmentModel
|
|
24
|
+
|
|
25
|
+
from .instance import (
|
|
26
|
+
AsyncInstanceClient,
|
|
27
|
+
ResetRequest,
|
|
28
|
+
ResetResponse,
|
|
29
|
+
ValidatorType,
|
|
30
|
+
ExecuteFunctionResponse,
|
|
31
|
+
)
|
|
32
|
+
from .resources.base import Resource
|
|
33
|
+
from .resources.sqlite import AsyncSQLiteResource
|
|
34
|
+
from .resources.browser import AsyncBrowserResource
|
|
35
|
+
|
|
36
|
+
logger = logging.getLogger(__name__)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class AsyncEnvironment(EnvironmentBase):
|
|
40
|
+
def __init__(self, httpx_client: Optional[httpx.AsyncClient] = None, **kwargs):
|
|
41
|
+
super().__init__(**kwargs)
|
|
42
|
+
self._httpx_client = httpx_client or httpx.AsyncClient(timeout=60.0)
|
|
43
|
+
self._instance: Optional[AsyncInstanceClient] = None
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def instance(self) -> AsyncInstanceClient:
|
|
47
|
+
if self._instance is None:
|
|
48
|
+
self._instance = AsyncInstanceClient(self.manager_url, self._httpx_client)
|
|
49
|
+
return self._instance
|
|
50
|
+
|
|
51
|
+
async def reset(
|
|
52
|
+
self, seed: Optional[int] = None, timestamp: Optional[int] = None
|
|
53
|
+
) -> ResetResponse:
|
|
54
|
+
return await self.instance.reset(ResetRequest(seed=seed, timestamp=timestamp))
|
|
55
|
+
|
|
56
|
+
def db(self, name: str = "current") -> AsyncSQLiteResource:
|
|
57
|
+
return self.instance.db(name)
|
|
58
|
+
|
|
59
|
+
def browser(self, name: str = "cdp") -> AsyncBrowserResource:
|
|
60
|
+
return self.instance.browser(name)
|
|
61
|
+
|
|
62
|
+
def state(self, uri: str) -> Resource:
|
|
63
|
+
return self.instance.state(uri)
|
|
64
|
+
|
|
65
|
+
async def resources(self) -> List[Resource]:
|
|
66
|
+
return await self.instance.resources()
|
|
67
|
+
|
|
68
|
+
async def close(self) -> InstanceRecord:
|
|
69
|
+
return await AsyncFleet().delete(self.instance_id)
|
|
70
|
+
|
|
71
|
+
async def verify(self, validator: ValidatorType) -> ExecuteFunctionResponse:
|
|
72
|
+
return await self.instance.verify(validator)
|
|
73
|
+
|
|
74
|
+
async def verify_raw(
|
|
75
|
+
self, function_code: str, function_name: str
|
|
76
|
+
) -> ExecuteFunctionResponse:
|
|
77
|
+
return await self.instance.verify_raw(function_code, function_name)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class AsyncFleet:
|
|
81
|
+
def __init__(
|
|
82
|
+
self,
|
|
83
|
+
api_key: Optional[str] = os.getenv("FLEET_API_KEY"),
|
|
84
|
+
base_url: Optional[str] = None,
|
|
85
|
+
httpx_client: Optional[httpx.AsyncClient] = None,
|
|
86
|
+
):
|
|
87
|
+
self._httpx_client = httpx_client or httpx.AsyncClient(timeout=60.0)
|
|
88
|
+
self.client = AsyncWrapper(
|
|
89
|
+
api_key=api_key,
|
|
90
|
+
base_url=base_url,
|
|
91
|
+
httpx_client=self._httpx_client,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
async def list_envs(self) -> List[EnvironmentModel]:
|
|
95
|
+
response = await self.client.request("GET", "/v1/env/")
|
|
96
|
+
return [EnvironmentModel(**env_data) for env_data in response.json()]
|
|
97
|
+
|
|
98
|
+
async def environment(self, env_key: str) -> EnvironmentModel:
|
|
99
|
+
response = await self.client.request("GET", f"/v1/env/{env_key}")
|
|
100
|
+
return EnvironmentModel(**response.json())
|
|
101
|
+
|
|
102
|
+
async def make(self, env_key: str) -> AsyncEnvironment:
|
|
103
|
+
if ":" in env_key:
|
|
104
|
+
env_key_part, version = env_key.split(":", 1)
|
|
105
|
+
if not version.startswith("v"):
|
|
106
|
+
version = f"v{version}"
|
|
107
|
+
else:
|
|
108
|
+
env_key_part = env_key
|
|
109
|
+
version = None
|
|
110
|
+
|
|
111
|
+
request = InstanceRequest(env_key=env_key_part, version=version)
|
|
112
|
+
response = await self.client.request(
|
|
113
|
+
"POST", "/v1/env/instances", json=request.model_dump()
|
|
114
|
+
)
|
|
115
|
+
instance = AsyncEnvironment(**response.json())
|
|
116
|
+
await instance.instance.load()
|
|
117
|
+
return instance
|
|
118
|
+
|
|
119
|
+
async def instances(self, status: Optional[str] = None) -> List[AsyncEnvironment]:
|
|
120
|
+
params = {}
|
|
121
|
+
if status:
|
|
122
|
+
params["status"] = status
|
|
123
|
+
|
|
124
|
+
response = await self.client.request("GET", "/v1/env/instances", params=params)
|
|
125
|
+
return [AsyncEnvironment(**instance_data) for instance_data in response.json()]
|
|
126
|
+
|
|
127
|
+
async def instance(self, instance_id: str) -> AsyncEnvironment:
|
|
128
|
+
response = await self.client.request("GET", f"/v1/env/instances/{instance_id}")
|
|
129
|
+
return AsyncEnvironment(**response.json())
|
|
130
|
+
|
|
131
|
+
async def delete(self, instance_id: str) -> InstanceRecord:
|
|
132
|
+
response = await self.client.request("DELETE", f"/v1/env/instances/{instance_id}")
|
|
133
|
+
return InstanceRecord(**response.json())
|
|
File without changes
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from ..client import AsyncFleet, AsyncEnvironment
|
|
2
|
+
from ..models import Environment as EnvironmentModel
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
async def make_async(env_key: str) -> AsyncEnvironment:
|
|
7
|
+
return await AsyncFleet().make(env_key)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
async def list_envs_async() -> List[EnvironmentModel]:
|
|
11
|
+
return await AsyncFleet().list_envs()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def get_async(instance_id: str) -> AsyncEnvironment:
|
|
15
|
+
return await AsyncFleet().instance(instance_id)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Fleet SDK Exception Classes."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FleetError(Exception):
|
|
7
|
+
"""Base exception for all Fleet SDK errors."""
|
|
8
|
+
|
|
9
|
+
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
|
|
10
|
+
super().__init__(message)
|
|
11
|
+
self.message = message
|
|
12
|
+
self.details = details or {}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FleetAPIError(FleetError):
|
|
16
|
+
"""Exception raised when Fleet API returns an error."""
|
|
17
|
+
|
|
18
|
+
def __init__(
|
|
19
|
+
self,
|
|
20
|
+
message: str,
|
|
21
|
+
status_code: Optional[int] = None,
|
|
22
|
+
response_data: Optional[Dict[str, Any]] = None,
|
|
23
|
+
details: Optional[Dict[str, Any]] = None,
|
|
24
|
+
):
|
|
25
|
+
super().__init__(message, details)
|
|
26
|
+
self.status_code = status_code
|
|
27
|
+
self.response_data = response_data or {}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class FleetTimeoutError(FleetError):
|
|
31
|
+
"""Exception raised when a Fleet operation times out."""
|
|
32
|
+
|
|
33
|
+
def __init__(self, message: str, timeout_duration: Optional[float] = None):
|
|
34
|
+
super().__init__(message)
|
|
35
|
+
self.timeout_duration = timeout_duration
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class FleetAuthenticationError(FleetAPIError):
|
|
39
|
+
"""Exception raised when authentication fails."""
|
|
40
|
+
|
|
41
|
+
def __init__(self, message: str = "Authentication failed"):
|
|
42
|
+
super().__init__(message, status_code=401)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class FleetRateLimitError(FleetAPIError):
|
|
46
|
+
"""Exception raised when rate limit is exceeded."""
|
|
47
|
+
|
|
48
|
+
def __init__(self, message: str = "Rate limit exceeded"):
|
|
49
|
+
super().__init__(message, status_code=429)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class FleetEnvironmentError(FleetError):
|
|
53
|
+
"""Exception raised when environment operations fail."""
|
|
54
|
+
|
|
55
|
+
def __init__(self, message: str, environment_id: Optional[str] = None):
|
|
56
|
+
super().__init__(message)
|
|
57
|
+
self.environment_id = environment_id
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class FleetFacetError(FleetError):
|
|
61
|
+
"""Exception raised when facet operations fail."""
|
|
62
|
+
|
|
63
|
+
def __init__(self, message: str, facet_type: Optional[str] = None):
|
|
64
|
+
super().__init__(message)
|
|
65
|
+
self.facet_type = facet_type
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class FleetConfigurationError(FleetError):
|
|
69
|
+
"""Exception raised when configuration is invalid."""
|
|
70
|
+
|
|
71
|
+
def __init__(self, message: str, config_key: Optional[str] = None):
|
|
72
|
+
super().__init__(message)
|
|
73
|
+
self.config_key = config_key
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Fleet SDK Environment Module."""
|
|
2
|
+
|
|
3
|
+
from .client import AsyncInstanceClient, ValidatorType
|
|
4
|
+
from .models import (
|
|
5
|
+
ResetRequest,
|
|
6
|
+
ResetResponse,
|
|
7
|
+
CDPDescribeResponse,
|
|
8
|
+
ChromeStartRequest,
|
|
9
|
+
ChromeStartResponse,
|
|
10
|
+
ChromeStatusResponse,
|
|
11
|
+
ExecuteFunctionResponse,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"ValidatorType",
|
|
16
|
+
"AsyncInstanceClient",
|
|
17
|
+
"ResetRequest",
|
|
18
|
+
"ResetResponse",
|
|
19
|
+
"CDPDescribeResponse",
|
|
20
|
+
"ChromeStartRequest",
|
|
21
|
+
"ChromeStartResponse",
|
|
22
|
+
"ChromeStatusResponse",
|
|
23
|
+
"ExecuteFunctionResponse"
|
|
24
|
+
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
from typing import Dict, Any, Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BaseWrapper:
|
|
6
|
+
def __init__(self, *, url: str):
|
|
7
|
+
self.url = url
|
|
8
|
+
|
|
9
|
+
def get_headers(self) -> Dict[str, str]:
|
|
10
|
+
headers: Dict[str, str] = {
|
|
11
|
+
"X-Fleet-SDK-Language": "Python",
|
|
12
|
+
"X-Fleet-SDK-Version": "1.0.0",
|
|
13
|
+
}
|
|
14
|
+
return headers
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AsyncWrapper(BaseWrapper):
|
|
18
|
+
def __init__(self, *, httpx_client: httpx.AsyncClient, **kwargs):
|
|
19
|
+
super().__init__(**kwargs)
|
|
20
|
+
self.httpx_client = httpx_client
|
|
21
|
+
|
|
22
|
+
async def request(
|
|
23
|
+
self,
|
|
24
|
+
method: str,
|
|
25
|
+
path: str,
|
|
26
|
+
params: Optional[Dict[str, Any]] = None,
|
|
27
|
+
json: Optional[Any] = None,
|
|
28
|
+
**kwargs,
|
|
29
|
+
) -> httpx.Response:
|
|
30
|
+
return await self.httpx_client.request(
|
|
31
|
+
method,
|
|
32
|
+
f"{self.url}{path}",
|
|
33
|
+
headers=self.get_headers(),
|
|
34
|
+
params=params,
|
|
35
|
+
json=json,
|
|
36
|
+
**kwargs,
|
|
37
|
+
)
|