fleet-python 0.2.29__tar.gz → 0.2.34__tar.gz
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.
- {fleet_python-0.2.29/fleet_python.egg-info → fleet_python-0.2.34}/PKG-INFO +9 -9
- {fleet_python-0.2.29 → fleet_python-0.2.34}/README.md +8 -8
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/diff_example.py +30 -20
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/dsl_example.py +12 -7
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/example.py +4 -4
- fleet_python-0.2.34/examples/exampleResume.py +191 -0
- fleet_python-0.2.34/examples/example_account.py +8 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/example_action_log.py +2 -2
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/example_client.py +2 -2
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/example_mcp_anthropic.py +8 -5
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/example_mcp_openai.py +2 -2
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/example_sync.py +4 -4
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/example_task.py +16 -6
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/example_tasks.py +3 -6
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/example_verifier.py +16 -3
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/gemini_example.py +6 -6
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/json_tasks_example.py +2 -2
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/nova_act_example.py +2 -2
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/openai_example.py +3 -3
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/openai_simple_example.py +3 -3
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/query_builder_example.py +11 -7
- fleet_python-0.2.34/examples/test_cdp_logging.py +80 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/__init__.py +60 -5
- fleet_python-0.2.34/fleet/_async/__init__.py +258 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/base.py +2 -1
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/client.py +164 -144
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/env/client.py +2 -0
- fleet_python-0.2.34/fleet/_async/global_client.py +43 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/instance/client.py +1 -1
- fleet_python-0.2.34/fleet/_async/models.py +344 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/resources/base.py +1 -1
- {fleet_python-0.2.29/fleet → fleet_python-0.2.34/fleet/_async}/resources/mcp.py +7 -12
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/resources/sqlite.py +141 -130
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/tasks.py +69 -16
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/verifiers/__init__.py +2 -2
- {fleet_python-0.2.29/fleet → fleet_python-0.2.34/fleet/_async}/verifiers/bundler.py +18 -14
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/verifiers/verifier.py +77 -71
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/base.py +2 -1
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/client.py +162 -148
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/config.py +3 -2
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/env/__init__.py +9 -1
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/env/client.py +4 -1
- fleet_python-0.2.34/fleet/global_client.py +43 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/instance/__init__.py +1 -1
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/instance/client.py +1 -1
- fleet_python-0.2.34/fleet/models.py +344 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/resources/base.py +1 -1
- fleet_python-0.2.34/fleet/resources/mcp.py +55 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/resources/sqlite.py +141 -130
- fleet_python-0.2.34/fleet/tasks.py +155 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/types.py +1 -1
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/verifiers/__init__.py +2 -2
- {fleet_python-0.2.29/fleet/_async → fleet_python-0.2.34/fleet}/verifiers/bundler.py +18 -14
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/verifiers/code.py +1 -1
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/verifiers/decorator.py +25 -34
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/verifiers/parse.py +98 -68
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/verifiers/verifier.py +77 -71
- {fleet_python-0.2.29 → fleet_python-0.2.34/fleet_python.egg-info}/PKG-INFO +9 -9
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet_python.egg-info/SOURCES.txt +6 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/pyproject.toml +1 -1
- fleet_python-0.2.34/scripts/fix_sync_imports.py +162 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/scripts/unasync.py +10 -9
- fleet_python-0.2.29/fleet/_async/__init__.py +0 -1
- fleet_python-0.2.29/fleet/_async/models.py +0 -343
- fleet_python-0.2.29/fleet/models.py +0 -343
- fleet_python-0.2.29/fleet/tasks.py +0 -84
- fleet_python-0.2.29/scripts/fix_sync_imports.py +0 -134
- {fleet_python-0.2.29 → fleet_python-0.2.34}/LICENSE +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/examples/quickstart.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/env/__init__.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/exceptions.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/instance/__init__.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/instance/base.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/resources/__init__.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/_async/resources/browser.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/exceptions.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/instance/base.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/instance/models.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/resources/__init__.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/resources/browser.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/verifiers/db.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet/verifiers/sql_differ.py +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet_python.egg-info/dependency_links.txt +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet_python.egg-info/requires.txt +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/fleet_python.egg-info/top_level.txt +0 -0
- {fleet_python-0.2.29 → fleet_python-0.2.34}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fleet-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.34
|
|
4
4
|
Summary: Python SDK for Fleet environments
|
|
5
5
|
Author-email: Fleet AI <nic@fleet.so>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -65,11 +65,11 @@ export FLEET_API_KEY="sk_your_key_here"
|
|
|
65
65
|
## Basic Usage
|
|
66
66
|
|
|
67
67
|
```python
|
|
68
|
-
import fleet
|
|
68
|
+
import fleet
|
|
69
69
|
import datetime
|
|
70
70
|
|
|
71
71
|
# Create environment by key
|
|
72
|
-
env =
|
|
72
|
+
env = fleet.env.make("fira")
|
|
73
73
|
|
|
74
74
|
# Reset environment with seed and options
|
|
75
75
|
env.reset(
|
|
@@ -91,10 +91,10 @@ env.close()
|
|
|
91
91
|
|
|
92
92
|
```python
|
|
93
93
|
# Create environment instance with explicit version
|
|
94
|
-
env =
|
|
94
|
+
env = fleet.env.make("fira:v1.2.5")
|
|
95
95
|
|
|
96
96
|
# Create environment instance with default (latest) version
|
|
97
|
-
env =
|
|
97
|
+
env = fleet.env.make("fira")
|
|
98
98
|
|
|
99
99
|
```
|
|
100
100
|
|
|
@@ -102,18 +102,18 @@ env = flt.env.make("fira")
|
|
|
102
102
|
|
|
103
103
|
```python
|
|
104
104
|
# Connect to a running instance
|
|
105
|
-
env =
|
|
105
|
+
env = fleet.env.get("env_instance_id")
|
|
106
106
|
|
|
107
107
|
# List all running instances
|
|
108
|
-
instances =
|
|
108
|
+
instances = fleet.env.list_instances()
|
|
109
109
|
for instance in instances:
|
|
110
110
|
print(f"Instance: {instance.instance_id}")
|
|
111
111
|
print(f"Type: {instance.environment_type}")
|
|
112
112
|
print(f"Status: {instance.status}")
|
|
113
113
|
|
|
114
114
|
# Filter instances by status (running, pending, stopped, error)
|
|
115
|
-
running_instances =
|
|
115
|
+
running_instances = fleet.env.list_instances(status_filter="running")
|
|
116
116
|
|
|
117
117
|
# List available environment types
|
|
118
|
-
available_envs =
|
|
118
|
+
available_envs = fleet.env.list_envs()
|
|
119
119
|
```
|
|
@@ -23,11 +23,11 @@ export FLEET_API_KEY="sk_your_key_here"
|
|
|
23
23
|
## Basic Usage
|
|
24
24
|
|
|
25
25
|
```python
|
|
26
|
-
import fleet
|
|
26
|
+
import fleet
|
|
27
27
|
import datetime
|
|
28
28
|
|
|
29
29
|
# Create environment by key
|
|
30
|
-
env =
|
|
30
|
+
env = fleet.env.make("fira")
|
|
31
31
|
|
|
32
32
|
# Reset environment with seed and options
|
|
33
33
|
env.reset(
|
|
@@ -49,10 +49,10 @@ env.close()
|
|
|
49
49
|
|
|
50
50
|
```python
|
|
51
51
|
# Create environment instance with explicit version
|
|
52
|
-
env =
|
|
52
|
+
env = fleet.env.make("fira:v1.2.5")
|
|
53
53
|
|
|
54
54
|
# Create environment instance with default (latest) version
|
|
55
|
-
env =
|
|
55
|
+
env = fleet.env.make("fira")
|
|
56
56
|
|
|
57
57
|
```
|
|
58
58
|
|
|
@@ -60,18 +60,18 @@ env = flt.env.make("fira")
|
|
|
60
60
|
|
|
61
61
|
```python
|
|
62
62
|
# Connect to a running instance
|
|
63
|
-
env =
|
|
63
|
+
env = fleet.env.get("env_instance_id")
|
|
64
64
|
|
|
65
65
|
# List all running instances
|
|
66
|
-
instances =
|
|
66
|
+
instances = fleet.env.list_instances()
|
|
67
67
|
for instance in instances:
|
|
68
68
|
print(f"Instance: {instance.instance_id}")
|
|
69
69
|
print(f"Type: {instance.environment_type}")
|
|
70
70
|
print(f"Status: {instance.status}")
|
|
71
71
|
|
|
72
72
|
# Filter instances by status (running, pending, stopped, error)
|
|
73
|
-
running_instances =
|
|
73
|
+
running_instances = fleet.env.list_instances(status_filter="running")
|
|
74
74
|
|
|
75
75
|
# List available environment types
|
|
76
|
-
available_envs =
|
|
76
|
+
available_envs = fleet.env.list_envs()
|
|
77
77
|
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import fleet
|
|
2
|
+
import fleet
|
|
3
3
|
from fleet.verifiers import IgnoreConfig
|
|
4
4
|
from dotenv import load_dotenv
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@ load_dotenv()
|
|
|
9
9
|
async def main():
|
|
10
10
|
# Create a new instance
|
|
11
11
|
print("Creating new Hubspot instance...")
|
|
12
|
-
env = await
|
|
12
|
+
env = await fleet.env.make_async("hubspot:v1.2.7")
|
|
13
13
|
print(f"New Instance: {env.instance_id}")
|
|
14
14
|
|
|
15
15
|
try:
|
|
@@ -24,14 +24,14 @@ async def main():
|
|
|
24
24
|
print("\n=== Taking Initial Snapshot ===")
|
|
25
25
|
snapshot1 = await db.snapshot("initial_state")
|
|
26
26
|
print(f"Snapshot created: {snapshot1.name}")
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
# Show current entries
|
|
29
29
|
entries_count = await db.table("entries").count()
|
|
30
30
|
print(f"Initial entry count: {entries_count}")
|
|
31
31
|
|
|
32
32
|
# Make some changes
|
|
33
33
|
print("\n=== Making Database Changes ===")
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
# 1. Insert a new deal
|
|
36
36
|
print("\n1. Inserting new deal...")
|
|
37
37
|
await db.exec("""
|
|
@@ -48,7 +48,7 @@ async def main():
|
|
|
48
48
|
'{}'
|
|
49
49
|
)
|
|
50
50
|
""")
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
# 2. Update an existing entry
|
|
53
53
|
print("2. Updating existing entry...")
|
|
54
54
|
await db.exec("""
|
|
@@ -56,7 +56,7 @@ async def main():
|
|
|
56
56
|
SET name = 'Updated Contact Name'
|
|
57
57
|
WHERE id = 1
|
|
58
58
|
""")
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
# 3. Insert another entry
|
|
61
61
|
print("3. Inserting another deal...")
|
|
62
62
|
await db.exec("""
|
|
@@ -78,21 +78,26 @@ async def main():
|
|
|
78
78
|
print("\n=== Taking Second Snapshot ===")
|
|
79
79
|
snapshot2 = await db.snapshot("after_changes")
|
|
80
80
|
print(f"Snapshot created: {snapshot2.name}")
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
new_entries_count = await db.table("entries").count()
|
|
83
83
|
print(f"New entry count: {new_entries_count}")
|
|
84
84
|
|
|
85
85
|
# Compare snapshots
|
|
86
86
|
print("\n=== Comparing Snapshots ===")
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
# Configure what to ignore in diff
|
|
89
89
|
ignore_config = IgnoreConfig(
|
|
90
90
|
tables={"pageviews"}, # Ignore entire pageviews table
|
|
91
|
-
fields={
|
|
91
|
+
fields={
|
|
92
|
+
"createdDate",
|
|
93
|
+
"lastModifiedDate",
|
|
94
|
+
"createdAt",
|
|
95
|
+
"updatedAt",
|
|
96
|
+
}, # Ignore timestamp fields
|
|
92
97
|
)
|
|
93
|
-
|
|
98
|
+
|
|
94
99
|
diff = await snapshot1.diff(snapshot2, ignore_config)
|
|
95
|
-
|
|
100
|
+
|
|
96
101
|
# Test 1: Validate all expected changes
|
|
97
102
|
print("\nTest 1: Validating expected changes...")
|
|
98
103
|
expected_changes = [
|
|
@@ -100,9 +105,14 @@ async def main():
|
|
|
100
105
|
{"table": "entries", "pk": 99001, "field": None, "after": "__added__"},
|
|
101
106
|
{"table": "entries", "pk": 99002, "field": None, "after": "__added__"},
|
|
102
107
|
# Name updated
|
|
103
|
-
{
|
|
108
|
+
{
|
|
109
|
+
"table": "entries",
|
|
110
|
+
"pk": 1,
|
|
111
|
+
"field": "name",
|
|
112
|
+
"after": "Updated Contact Name",
|
|
113
|
+
},
|
|
104
114
|
]
|
|
105
|
-
|
|
115
|
+
|
|
106
116
|
try:
|
|
107
117
|
await diff.expect_only(expected_changes)
|
|
108
118
|
print("✓ All changes validated successfully!")
|
|
@@ -115,7 +125,7 @@ async def main():
|
|
|
115
125
|
{"table": "entries", "pk": 99001, "field": None, "after": "__added__"},
|
|
116
126
|
# Missing the second insert and the update
|
|
117
127
|
]
|
|
118
|
-
|
|
128
|
+
|
|
119
129
|
try:
|
|
120
130
|
await diff.expect_only(incorrect_changes)
|
|
121
131
|
print("✗ This should have failed!")
|
|
@@ -125,29 +135,29 @@ async def main():
|
|
|
125
135
|
|
|
126
136
|
# Test 3: Query snapshot data directly
|
|
127
137
|
print("\n=== Querying Snapshot Data ===")
|
|
128
|
-
|
|
138
|
+
|
|
129
139
|
# Query from first snapshot
|
|
130
140
|
print("\nQuerying from initial snapshot:")
|
|
131
141
|
initial_entry = await snapshot1.table("entries").eq("id", 1).first()
|
|
132
142
|
if initial_entry:
|
|
133
143
|
print(f"Entry 1 name in snapshot1: {initial_entry['name']}")
|
|
134
|
-
|
|
144
|
+
|
|
135
145
|
# Query from second snapshot
|
|
136
146
|
print("\nQuerying from second snapshot:")
|
|
137
147
|
updated_entry = await snapshot2.table("entries").eq("id", 1).first()
|
|
138
148
|
if updated_entry:
|
|
139
149
|
print(f"Entry 1 name in snapshot2: {updated_entry['name']}")
|
|
140
|
-
|
|
150
|
+
|
|
141
151
|
# Count deals in each snapshot
|
|
142
152
|
deals_before = await snapshot1.table("entries").eq("type", "deal").all()
|
|
143
153
|
deals_after = await snapshot2.table("entries").eq("type", "deal").all()
|
|
144
154
|
print(f"\nDeals in snapshot1: {len(deals_before)}")
|
|
145
155
|
print(f"Deals in snapshot2: {len(deals_after)}")
|
|
146
|
-
|
|
156
|
+
|
|
147
157
|
# Show new deals
|
|
148
158
|
print("\nNew deals added:")
|
|
149
159
|
for deal in deals_after:
|
|
150
|
-
if deal[
|
|
160
|
+
if deal["id"] in [99001, 99002]:
|
|
151
161
|
print(f" - {deal['name']} (id: {deal['id']})")
|
|
152
162
|
|
|
153
163
|
finally:
|
|
@@ -158,4 +168,4 @@ async def main():
|
|
|
158
168
|
|
|
159
169
|
|
|
160
170
|
if __name__ == "__main__":
|
|
161
|
-
asyncio.run(main())
|
|
171
|
+
asyncio.run(main())
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import fleet
|
|
2
|
+
import fleet
|
|
3
3
|
from fleet.verifiers import DatabaseSnapshot, IgnoreConfig, TASK_SUCCESSFUL_SCORE
|
|
4
4
|
from dotenv import load_dotenv
|
|
5
5
|
|
|
@@ -68,7 +68,7 @@ def validate_new_deal_creation(
|
|
|
68
68
|
async def main():
|
|
69
69
|
# Create a new instance
|
|
70
70
|
print("Creating new Hubspot instance...")
|
|
71
|
-
env = await
|
|
71
|
+
env = await fleet.env.make_async("hubspot")
|
|
72
72
|
print(f"New Instance: {env.instance_id}")
|
|
73
73
|
|
|
74
74
|
try:
|
|
@@ -87,7 +87,7 @@ async def main():
|
|
|
87
87
|
# Get the database resource
|
|
88
88
|
await env.instance.load()
|
|
89
89
|
db = env.db()
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
# Take a snapshot before insertion
|
|
92
92
|
print("\nTaking snapshot before insertion...")
|
|
93
93
|
snapshot_before = await db.snapshot("before_insertion")
|
|
@@ -139,12 +139,17 @@ async def main():
|
|
|
139
139
|
ignore_config = IgnoreConfig(
|
|
140
140
|
tables={"pageviews"},
|
|
141
141
|
table_fields={
|
|
142
|
-
"entries": {
|
|
142
|
+
"entries": {
|
|
143
|
+
"createdDate",
|
|
144
|
+
"lastModifiedDate",
|
|
145
|
+
"createdAt",
|
|
146
|
+
"updatedAt",
|
|
147
|
+
},
|
|
143
148
|
},
|
|
144
149
|
)
|
|
145
|
-
|
|
150
|
+
|
|
146
151
|
diff = await snapshot_before.diff(snapshot_after, ignore_config)
|
|
147
|
-
|
|
152
|
+
|
|
148
153
|
# Check diff results
|
|
149
154
|
print("\nDiff validation:")
|
|
150
155
|
expected_changes = [
|
|
@@ -155,7 +160,7 @@ async def main():
|
|
|
155
160
|
"after": "__added__",
|
|
156
161
|
}
|
|
157
162
|
]
|
|
158
|
-
|
|
163
|
+
|
|
159
164
|
try:
|
|
160
165
|
await diff.expect_only(expected_changes)
|
|
161
166
|
print("✓ Diff validation passed - only expected changes detected")
|
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
"""Example demonstrating browser control with Fleet Manager Client."""
|
|
3
3
|
|
|
4
4
|
import asyncio
|
|
5
|
-
import fleet
|
|
5
|
+
import fleet
|
|
6
6
|
from dotenv import load_dotenv
|
|
7
7
|
|
|
8
8
|
load_dotenv()
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
async def main():
|
|
12
|
-
regions = await
|
|
12
|
+
regions = await fleet.env.list_regions_async()
|
|
13
13
|
print("Regions:", regions)
|
|
14
14
|
|
|
15
|
-
environments = await
|
|
15
|
+
environments = await fleet.env.list_envs_async()
|
|
16
16
|
print("Environments:", len(environments))
|
|
17
17
|
|
|
18
18
|
# Create a new instance
|
|
19
|
-
env = await
|
|
19
|
+
env = await fleet.env.make_async("hubspot")
|
|
20
20
|
print(f"New Instance: {env.instance_id} ({env.region})")
|
|
21
21
|
|
|
22
22
|
response = await env.reset(seed=42)
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Interactive Browser Snapshot/Resume Example
|
|
4
|
+
|
|
5
|
+
This script:
|
|
6
|
+
1. Creates an environment and browser
|
|
7
|
+
2. Lets you interact with it manually
|
|
8
|
+
3. Takes a snapshot when you type 'close'
|
|
9
|
+
4. Resumes from the snapshot with a new environment
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
|
|
17
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
|
18
|
+
|
|
19
|
+
from fleet import Fleet
|
|
20
|
+
|
|
21
|
+
def main():
|
|
22
|
+
# Initialize Fleet client
|
|
23
|
+
api_key = os.getenv("FLEET_API_KEY")
|
|
24
|
+
if not api_key:
|
|
25
|
+
print("Error: FLEET_API_KEY environment variable not set")
|
|
26
|
+
sys.exit(1)
|
|
27
|
+
|
|
28
|
+
fleet = Fleet(api_key=api_key)
|
|
29
|
+
|
|
30
|
+
# Initialize environment variables
|
|
31
|
+
env = None
|
|
32
|
+
new_env = None
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
# Step 1: Create environment and browser
|
|
36
|
+
print("🚀 Creating new environment...")
|
|
37
|
+
env_key = "fira:v1.3.2"
|
|
38
|
+
|
|
39
|
+
env = fleet.make(env_key)
|
|
40
|
+
print(f"✅ Environment created: {env.instance_id}")
|
|
41
|
+
print(f"📝 Session ID: {env.session_id}")
|
|
42
|
+
|
|
43
|
+
# Start browser
|
|
44
|
+
print("\n🌐 Starting browser...")
|
|
45
|
+
browser = env.browser()
|
|
46
|
+
browser.start(width=1920, height=1080)
|
|
47
|
+
|
|
48
|
+
# Get browser URLs with session ID for automatic logging
|
|
49
|
+
cdp_page_url = browser.cdp_page_url()
|
|
50
|
+
cdp_browser_url = browser.cdp_browser_url()
|
|
51
|
+
devtools_url = browser.devtools_url()
|
|
52
|
+
|
|
53
|
+
print(f"✅ Browser started!")
|
|
54
|
+
print(f"🔗 CDP Page URL: {cdp_page_url}")
|
|
55
|
+
print(f"🔗 CDP Browser URL: {cdp_browser_url}")
|
|
56
|
+
print(f"🔗 DevTools URL: {devtools_url}")
|
|
57
|
+
|
|
58
|
+
# Show connection info for debugging
|
|
59
|
+
conn_info = browser.get_connection_info()
|
|
60
|
+
print(f"📊 Logging enabled: {conn_info['logging_enabled']}")
|
|
61
|
+
if conn_info['logging_enabled']:
|
|
62
|
+
print(f"📝 All CDP actions will be automatically logged to session: {env.session_id}")
|
|
63
|
+
|
|
64
|
+
# Step 2: Wait for user interaction
|
|
65
|
+
print("\n" + "="*60)
|
|
66
|
+
print("🎮 INTERACTIVE MODE")
|
|
67
|
+
print("="*60)
|
|
68
|
+
print("You can now interact with the browser manually.")
|
|
69
|
+
print("Open the DevTools URL in Chrome to see and control the browser.")
|
|
70
|
+
print("\nType 'close' and press Enter when you're done to save a snapshot.")
|
|
71
|
+
print("="*60 + "\n")
|
|
72
|
+
|
|
73
|
+
while True:
|
|
74
|
+
user_input = input(">>> ").strip().lower()
|
|
75
|
+
|
|
76
|
+
if user_input == "close":
|
|
77
|
+
break
|
|
78
|
+
elif user_input == "status":
|
|
79
|
+
print(f"Environment: {env.instance_id}")
|
|
80
|
+
print(f"Session: {env.session_id}")
|
|
81
|
+
else:
|
|
82
|
+
print("Type 'close' to save snapshot and exit, or 'status' to see current info")
|
|
83
|
+
|
|
84
|
+
# Step 3: Take snapshot
|
|
85
|
+
print("\n📸 Taking snapshot...")
|
|
86
|
+
snapshot = env.get_snapshot(browser)
|
|
87
|
+
|
|
88
|
+
# Save snapshot to file
|
|
89
|
+
snapshot_file = f"snapshot_{env.session_id}_{int(datetime.now().timestamp())}.json"
|
|
90
|
+
with open(snapshot_file, "w") as f:
|
|
91
|
+
json.dump(snapshot.model_dump(), f, indent=2)
|
|
92
|
+
|
|
93
|
+
print(f"✅ Snapshot saved to: {snapshot_file}")
|
|
94
|
+
print(f" - Tool logs: {len(snapshot.tool_logs)} entries")
|
|
95
|
+
print(f" - Action logs: {len(snapshot.action_logs)} entries")
|
|
96
|
+
print(f" - Page URL: {snapshot.page_url}")
|
|
97
|
+
print(f" - Viewport: {snapshot.viewport_size}")
|
|
98
|
+
|
|
99
|
+
# Close original environment
|
|
100
|
+
print("\n🏁 Closing original environment...")
|
|
101
|
+
env.close()
|
|
102
|
+
env = None # Mark as closed
|
|
103
|
+
|
|
104
|
+
# Step 4: Resume from snapshot
|
|
105
|
+
print("\n" + "="*60)
|
|
106
|
+
print("🔄 RESUMING FROM SNAPSHOT")
|
|
107
|
+
print("="*60)
|
|
108
|
+
|
|
109
|
+
input("\nPress Enter to resume from snapshot...")
|
|
110
|
+
|
|
111
|
+
print("\n🚀 Creating new environment from snapshot...")
|
|
112
|
+
new_env, validation = fleet.resume(
|
|
113
|
+
snapshot,
|
|
114
|
+
validate=True,
|
|
115
|
+
playback_speed=2.0 # Replay at 2x speed
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
print(f"✅ Environment resumed: {new_env.instance_id}")
|
|
119
|
+
print(f"📝 New session ID: {new_env.session_id}")
|
|
120
|
+
|
|
121
|
+
# Show validation results
|
|
122
|
+
print(f"\n📊 Validation Results:")
|
|
123
|
+
print(f" - Success: {validation.success}")
|
|
124
|
+
print(f" - Page match: {validation.page_match}")
|
|
125
|
+
print(f" - Action log match: {validation.action_log_match}")
|
|
126
|
+
|
|
127
|
+
if validation.discrepancies:
|
|
128
|
+
print(f" - Discrepancies ({len(validation.discrepancies)}):")
|
|
129
|
+
for disc in validation.discrepancies[:5]: # Show first 5
|
|
130
|
+
print(f" • {disc}")
|
|
131
|
+
if len(validation.discrepancies) > 5:
|
|
132
|
+
print(f" • ... and {len(validation.discrepancies) - 5} more")
|
|
133
|
+
|
|
134
|
+
# Get new browser reference
|
|
135
|
+
new_browser = new_env.browser()
|
|
136
|
+
print(f"\n🌐 New browser ready!")
|
|
137
|
+
print(f"🔗 CDP Page URL: {new_browser.cdp_page_url()}")
|
|
138
|
+
print(f"🔗 DevTools URL: {new_browser.devtools_url()}")
|
|
139
|
+
print(f"📝 Resume session logging to: {new_env.session_id}")
|
|
140
|
+
|
|
141
|
+
# Step 5: Keep new environment open for inspection
|
|
142
|
+
print("\n" + "="*60)
|
|
143
|
+
print("🎮 RESUMED ENVIRONMENT READY")
|
|
144
|
+
print("="*60)
|
|
145
|
+
print("The resumed environment is now ready. You can inspect it to verify")
|
|
146
|
+
print("it matches your original state.")
|
|
147
|
+
print("\nType 'done' when finished to close the resumed environment.")
|
|
148
|
+
print("="*60 + "\n")
|
|
149
|
+
|
|
150
|
+
while True:
|
|
151
|
+
user_input = input(">>> ").strip().lower()
|
|
152
|
+
|
|
153
|
+
if user_input == "done":
|
|
154
|
+
break
|
|
155
|
+
elif user_input == "status":
|
|
156
|
+
print(f"Environment: {new_env.instance_id}")
|
|
157
|
+
print(f"Session: {new_env.session_id}")
|
|
158
|
+
else:
|
|
159
|
+
print("Type 'done' to close the environment, or 'status' to see current info")
|
|
160
|
+
|
|
161
|
+
# Clean up
|
|
162
|
+
print("\n🏁 Closing resumed environment...")
|
|
163
|
+
new_env.close()
|
|
164
|
+
new_env = None # Mark as closed
|
|
165
|
+
print("✅ All done!")
|
|
166
|
+
|
|
167
|
+
except KeyboardInterrupt:
|
|
168
|
+
print("\n\n⚠️ Interrupted by user")
|
|
169
|
+
except Exception as e:
|
|
170
|
+
print(f"\n❌ Error: {e}")
|
|
171
|
+
finally:
|
|
172
|
+
# Always clean up environments
|
|
173
|
+
if env is not None:
|
|
174
|
+
try:
|
|
175
|
+
print("\n🧹 Cleaning up original environment...")
|
|
176
|
+
env.close()
|
|
177
|
+
print("✅ Original environment closed")
|
|
178
|
+
except Exception as e:
|
|
179
|
+
print(f"⚠️ Failed to close original environment: {e}")
|
|
180
|
+
|
|
181
|
+
if new_env is not None:
|
|
182
|
+
try:
|
|
183
|
+
print("\n🧹 Cleaning up resumed environment...")
|
|
184
|
+
new_env.close()
|
|
185
|
+
print("✅ Resumed environment closed")
|
|
186
|
+
except Exception as e:
|
|
187
|
+
print(f"⚠️ Failed to close resumed environment: {e}")
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
if __name__ == "__main__":
|
|
191
|
+
main()
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"""Example demonstrating browser control with Fleet Manager Client."""
|
|
3
3
|
|
|
4
4
|
import asyncio
|
|
5
|
-
import fleet
|
|
5
|
+
import fleet
|
|
6
6
|
from dotenv import load_dotenv
|
|
7
7
|
|
|
8
8
|
load_dotenv()
|
|
@@ -10,7 +10,7 @@ load_dotenv()
|
|
|
10
10
|
|
|
11
11
|
async def main():
|
|
12
12
|
# Create a new instance
|
|
13
|
-
env = await
|
|
13
|
+
env = await fleet.env.make_async("fira:v1.3.2")
|
|
14
14
|
print(f"New Instance: {env.instance_id} ({env.region})")
|
|
15
15
|
print("URL:", env.urls.app)
|
|
16
16
|
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
"""Example demonstrating browser control with Fleet Manager Client."""
|
|
3
3
|
|
|
4
4
|
import asyncio
|
|
5
|
-
import fleet
|
|
5
|
+
import fleet
|
|
6
6
|
from dotenv import load_dotenv
|
|
7
7
|
|
|
8
8
|
load_dotenv()
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
async def main():
|
|
12
|
-
fleet =
|
|
12
|
+
fleet = fleet.AsyncFleet()
|
|
13
13
|
|
|
14
14
|
environments = await fleet.list_envs()
|
|
15
15
|
print("Environments:", len(environments))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import fleet
|
|
2
|
+
import fleet
|
|
3
3
|
from anthropic import AsyncAnthropic
|
|
4
4
|
from mcp import ClientSession
|
|
5
5
|
from mcp.client.streamable_http import streamablehttp_client
|
|
@@ -11,12 +11,14 @@ client = AsyncAnthropic()
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
async def main():
|
|
14
|
-
env =
|
|
14
|
+
env = fleet.env.make("fira")
|
|
15
15
|
print("Created environment:", env.urls.app)
|
|
16
16
|
print("MCP URL:", env.mcp.url)
|
|
17
17
|
|
|
18
18
|
async with streamablehttp_client(url=env.mcp.url) as streams:
|
|
19
|
-
async with ClientSession(
|
|
19
|
+
async with ClientSession(
|
|
20
|
+
read_stream=streams[0], write_stream=streams[1]
|
|
21
|
+
) as session:
|
|
20
22
|
await session.initialize()
|
|
21
23
|
|
|
22
24
|
list_tools = await session.list_tools()
|
|
@@ -29,7 +31,6 @@ async def main():
|
|
|
29
31
|
for tool in list_tools.tools
|
|
30
32
|
]
|
|
31
33
|
|
|
32
|
-
|
|
33
34
|
messages = [
|
|
34
35
|
{
|
|
35
36
|
"role": "user",
|
|
@@ -54,7 +55,9 @@ async def main():
|
|
|
54
55
|
|
|
55
56
|
result = await session.call_tool(tool_name, tool_args)
|
|
56
57
|
tool_results.append({"call": tool_name, "result": result})
|
|
57
|
-
output_text.append(
|
|
58
|
+
output_text.append(
|
|
59
|
+
f"[Calling tool {tool_name} with args {tool_args}]"
|
|
60
|
+
)
|
|
58
61
|
|
|
59
62
|
if hasattr(content, "text") and content.text:
|
|
60
63
|
messages.append({"role": "assistant", "content": content.text})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import fleet
|
|
1
|
+
import fleet
|
|
2
2
|
from openai import OpenAI
|
|
3
3
|
from dotenv import load_dotenv
|
|
4
4
|
|
|
@@ -8,7 +8,7 @@ client = OpenAI()
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def main():
|
|
11
|
-
env =
|
|
11
|
+
env = fleet.env.make("fira")
|
|
12
12
|
print("Created environment:", env.urls.app)
|
|
13
13
|
print("MCP URL:", env.mcp.url)
|
|
14
14
|
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Example demonstrating browser control with Fleet Manager Client."""
|
|
3
3
|
|
|
4
|
-
import fleet
|
|
4
|
+
import fleet
|
|
5
5
|
from dotenv import load_dotenv
|
|
6
6
|
|
|
7
7
|
load_dotenv()
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def main():
|
|
11
|
-
environments =
|
|
11
|
+
environments = fleet.env.list_envs()
|
|
12
12
|
print("Environments:", len(environments))
|
|
13
13
|
|
|
14
|
-
instances =
|
|
14
|
+
instances = fleet.env.list_instances(status="running")
|
|
15
15
|
print("Instances:", len(instances))
|
|
16
16
|
|
|
17
17
|
# Create a new instance
|
|
18
|
-
env =
|
|
18
|
+
env = fleet.env.make("hubspot")
|
|
19
19
|
print("New Instance:", env.instance_id)
|
|
20
20
|
|
|
21
21
|
response = env.reset(seed=42)
|