fleet-python 0.2.119__tar.gz → 0.2.120__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.
- fleet_python-0.2.120/PKG-INFO +336 -0
- fleet_python-0.2.120/README.md +285 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/example_task.py +1 -1
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/export_tasks.py +32 -10
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/import_tasks.py +1 -49
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/iterate_verifiers.py +2 -2
- fleet_python-0.2.120/examples/task_bundle_editing/download_task.py +178 -0
- fleet_python-0.2.120/examples/task_bundle_editing/launch_job.py +160 -0
- fleet_python-0.2.120/examples/task_bundle_editing/upload_task.py +333 -0
- fleet_python-0.2.120/examples/task_bundle_editing/validate_task.py +267 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/__init__.py +1 -16
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/__init__.py +2 -2
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/base.py +1 -1
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/client.py +128 -111
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/instance/client.py +0 -14
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/models.py +55 -3
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/resources/sqlite.py +4 -9
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/tasks.py +74 -21
- fleet_python-0.2.120/fleet/_supabase.py +6 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/gemini_cua/agent.py +377 -159
- fleet_python-0.2.120/fleet/auth.py +101 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/base.py +19 -6
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/cli.py +160 -9
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/client.py +126 -105
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/instance/client.py +0 -14
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/instance/models.py +0 -75
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/models.py +69 -4
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/resources/sqlite.py +7 -12
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/tasks.py +66 -17
- fleet_python-0.2.120/fleet/track/__init__.py +1 -0
- fleet_python-0.2.120/fleet/track/api.py +101 -0
- fleet_python-0.2.120/fleet/track/cli.py +171 -0
- fleet_python-0.2.120/fleet/track/daemon.py +340 -0
- fleet_python-0.2.120/fleet/track/install.py +157 -0
- fleet_python-0.2.120/fleet/track/merkle.py +167 -0
- fleet_python-0.2.120/fleet/track/queue.py +158 -0
- fleet_python-0.2.120/fleet/track/scrubber.py +60 -0
- fleet_python-0.2.120/fleet/track/sources.py +95 -0
- fleet_python-0.2.120/fleet/track/status.py +83 -0
- fleet_python-0.2.120/fleet/track/uploader.py +119 -0
- fleet_python-0.2.120/fleet/track/watcher.py +108 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/verifiers/__init__.py +0 -4
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/verifiers/db.py +0 -429
- fleet_python-0.2.120/fleet_python.egg-info/PKG-INFO +336 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet_python.egg-info/SOURCES.txt +18 -7
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet_python.egg-info/requires.txt +1 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/pyproject.toml +7 -1
- {fleet_python-0.2.119 → fleet_python-0.2.120}/tests/test_expect_only.py +15 -15
- fleet_python-0.2.119/PKG-INFO +0 -145
- fleet_python-0.2.119/README.md +0 -95
- fleet_python-0.2.119/examples/export_tasks_filtered.py +0 -245
- fleet_python-0.2.119/fleet/_async/judge.py +0 -152
- fleet_python-0.2.119/fleet/_async/resources/filesystem.py +0 -378
- fleet_python-0.2.119/fleet/judge.py +0 -1014
- fleet_python-0.2.119/fleet/resources/filesystem.py +0 -378
- fleet_python-0.2.119/fleet/verifiers/local_executor.py +0 -371
- fleet_python-0.2.119/fleet_python.egg-info/PKG-INFO +0 -145
- fleet_python-0.2.119/tests/test_judge_criteria_markers.py +0 -192
- {fleet_python-0.2.119 → fleet_python-0.2.120}/LICENSE +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/diff_example.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/dsl_example.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/example.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/exampleResume.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/example_account.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/example_action_log.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/example_client.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/example_mcp_anthropic.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/example_mcp_openai.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/example_sync.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/example_tasks.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/example_verifier.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/fetch_tasks.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/gemini_example.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/json_tasks_example.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/nova_act_example.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/openai_example.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/openai_simple_example.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/query_builder_example.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/quickstart.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/examples/test_cdp_logging.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/env/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/env/client.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/exceptions.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/global_client.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/instance/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/instance/base.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/resources/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/resources/api.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/resources/base.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/resources/browser.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/resources/mcp.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/verifiers/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/verifiers/bundler.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/_async/verifiers/verifier.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/gemini_cua/Dockerfile +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/gemini_cua/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/gemini_cua/mcp/main.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/gemini_cua/mcp_server/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/gemini_cua/mcp_server/main.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/gemini_cua/mcp_server/tools.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/gemini_cua/requirements.txt +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/gemini_cua/start.sh +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/orchestrator.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/types.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/agent/utils.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/config.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/env/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/env/client.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/eval/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/eval/uploader.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/exceptions.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/global_client.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/instance/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/instance/base.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/proxy/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/proxy/proxy.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/proxy/whitelist.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/resources/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/resources/api.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/resources/base.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/resources/browser.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/resources/mcp.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/types.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/utils/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/utils/http_logging.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/utils/logging.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/utils/playwright.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/verifiers/bundler.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/verifiers/code.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/verifiers/decorator.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/verifiers/parse.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/verifiers/sql_differ.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet/verifiers/verifier.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet_python.egg-info/dependency_links.txt +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet_python.egg-info/entry_points.txt +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/fleet_python.egg-info/top_level.txt +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/scripts/fix_sync_imports.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/scripts/unasync.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/setup.cfg +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/tests/__init__.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/tests/test_app_method.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/tests/test_expect_exactly.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/tests/test_instance_dispatch.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/tests/test_sqlite_resource_dual_mode.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/tests/test_sqlite_shared_memory_behavior.py +0 -0
- {fleet_python-0.2.119 → fleet_python-0.2.120}/tests/test_verifier_from_string.py +0 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fleet-python
|
|
3
|
+
Version: 0.2.120
|
|
4
|
+
Summary: Python SDK for Fleet environments
|
|
5
|
+
Author-email: Fleet AI <nic@fleet.so>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://fleetai.com
|
|
8
|
+
Project-URL: Documentation, https://docs.fleetai.com
|
|
9
|
+
Project-URL: Repository, https://github.com/fleet-ai/fleet-sdk
|
|
10
|
+
Project-URL: Issues, https://github.com/fleet-ai/fleet-sdk/issues
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Requires-Dist: httpx>=0.27.0
|
|
25
|
+
Requires-Dist: httpx-retries>=0.4.0
|
|
26
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
27
|
+
Requires-Dist: modulegraph2>=0.2.0
|
|
28
|
+
Requires-Dist: cloudpickle==3.1.1
|
|
29
|
+
Provides-Extra: cli
|
|
30
|
+
Requires-Dist: typer>=0.9.0; extra == "cli"
|
|
31
|
+
Requires-Dist: rich>=10.0.0; extra == "cli"
|
|
32
|
+
Requires-Dist: watchdog>=4.0.0; extra == "cli"
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
36
|
+
Requires-Dist: black>=22.0.0; extra == "dev"
|
|
37
|
+
Requires-Dist: isort>=5.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
40
|
+
Requires-Dist: unasync>=0.6.0; extra == "dev"
|
|
41
|
+
Requires-Dist: python-dotenv>=1.1.1; extra == "dev"
|
|
42
|
+
Requires-Dist: typer>=0.9.0; extra == "dev"
|
|
43
|
+
Requires-Dist: rich>=10.0.0; extra == "dev"
|
|
44
|
+
Provides-Extra: playwright
|
|
45
|
+
Requires-Dist: playwright>=1.40.0; extra == "playwright"
|
|
46
|
+
Provides-Extra: eval
|
|
47
|
+
Requires-Dist: aiohttp>=3.9.0; extra == "eval"
|
|
48
|
+
Requires-Dist: google-genai>=1.0.0; extra == "eval"
|
|
49
|
+
Requires-Dist: mcp==1.24.0; python_version >= "3.10" and extra == "eval"
|
|
50
|
+
Dynamic: license-file
|
|
51
|
+
|
|
52
|
+
# Fleet SDK
|
|
53
|
+
|
|
54
|
+
[](https://pypi.org/project/fleet-python/)
|
|
55
|
+
[](https://pypi.org/project/fleet-python/)
|
|
56
|
+
[](https://pypi.org/project/fleet-python/)
|
|
57
|
+
|
|
58
|
+
The Fleet Python SDK provides programmatic access to Fleet's environment infrastructure.
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install fleet-python
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## API Key Setup
|
|
67
|
+
|
|
68
|
+
Get your API key from the [Fleet Dashboard](https://fleetai.com/dashboard/api-keys), then set it as an environment variable:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
export FLEET_API_KEY="sk_your_key_here"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Tasks
|
|
75
|
+
|
|
76
|
+
A **Task** represents a unit of work for an agent to complete within an environment. Each task combines:
|
|
77
|
+
|
|
78
|
+
- **Prompt**: Instructions describing what needs to be done
|
|
79
|
+
- **Environment**: The environment configuration (`env_key`, `data_key`, `env_variables`)
|
|
80
|
+
- **Verifier**: Code that validates task completion and returns a score (0.0 to 1.0)
|
|
81
|
+
|
|
82
|
+
Tasks provide all the configuration needed to spin up an environment and verify an agent's work.
|
|
83
|
+
|
|
84
|
+
### Task Properties
|
|
85
|
+
|
|
86
|
+
| Property | Description |
|
|
87
|
+
| --------------- | ----------------------------------------------------- |
|
|
88
|
+
| `key` | Unique task identifier |
|
|
89
|
+
| `prompt` | Instructions for the agent |
|
|
90
|
+
| `env_key` | Environment identifier (e.g., `"hubspot:v1.2"`) |
|
|
91
|
+
| `data_key` | Data configuration identifier |
|
|
92
|
+
| `env_variables` | Environment variables for the task |
|
|
93
|
+
| `metadata` | Additional info (e.g., `avg_steps` for task difficulty) |
|
|
94
|
+
|
|
95
|
+
## Quick Start
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
import fleet
|
|
99
|
+
|
|
100
|
+
async def main():
|
|
101
|
+
# Load a task
|
|
102
|
+
tasks = await fleet.load_tasks_async(
|
|
103
|
+
keys=["task_abcdef"]
|
|
104
|
+
)
|
|
105
|
+
task = tasks[0]
|
|
106
|
+
|
|
107
|
+
# Create an environment from the task
|
|
108
|
+
env = await fleet.env.make_async(
|
|
109
|
+
env_key=task.env_key,
|
|
110
|
+
data_key=task.data_key,
|
|
111
|
+
env_variables=task.env_variables,
|
|
112
|
+
ttl_seconds=7200,
|
|
113
|
+
run_id="run-123",
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Access the environment URL
|
|
117
|
+
print(env.urls.app[0])
|
|
118
|
+
|
|
119
|
+
# ... interact with the environment ...
|
|
120
|
+
|
|
121
|
+
# Verify task completion
|
|
122
|
+
result = await task.verify_detailed_async(env.instance_id)
|
|
123
|
+
print(result)
|
|
124
|
+
|
|
125
|
+
# Clean up
|
|
126
|
+
await env.close()
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Loading Tasks
|
|
130
|
+
|
|
131
|
+
### By Task Keys
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
tasks = await fleet.load_tasks_async(
|
|
135
|
+
keys=["task_abcdef"]
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### By Project Key
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
tasks = await fleet.load_tasks_async(project_key="my-project")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Creating Environments
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
env = await fleet.env.make_async(
|
|
149
|
+
env_key=task.env_key,
|
|
150
|
+
data_key=task.data_key,
|
|
151
|
+
env_variables=task.env_variables,
|
|
152
|
+
ttl_seconds=7200,
|
|
153
|
+
run_id="run-123",
|
|
154
|
+
)
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### With Heartbeats (Optional)
|
|
158
|
+
|
|
159
|
+
Optionally enable heartbeats to keep environments alive during long-running operations:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
env = await fleet.env.make_async(
|
|
163
|
+
env_key=task.env_key,
|
|
164
|
+
data_key=task.data_key,
|
|
165
|
+
env_variables=task.env_variables,
|
|
166
|
+
ttl_seconds=10800,
|
|
167
|
+
heartbeat_interval=30, # seconds
|
|
168
|
+
)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Send heartbeats to keep the environment alive:
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
# Via the environment object
|
|
175
|
+
await env.heartbeat()
|
|
176
|
+
|
|
177
|
+
# Or via instance ID
|
|
178
|
+
await fleet.env.heartbeat_async(instance_id)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Heartbeats are optional. If `heartbeat_interval` is not set, the instance lifetime is controlled solely by `ttl_seconds`. If heartbeats are enabled and missed 3 consecutive times, the instance will be terminated. Heartbeats take precedence over the TTL.
|
|
182
|
+
|
|
183
|
+
## Instance Management
|
|
184
|
+
|
|
185
|
+
### List Instances
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
# List all instances for a run
|
|
189
|
+
instances = await fleet.env.list_instances_async(run_id="run-123")
|
|
190
|
+
|
|
191
|
+
# List all instances for your profile
|
|
192
|
+
instances = await fleet.env.list_instances_async(profile_id="self")
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Close Instances
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
# Close all instances for a run
|
|
199
|
+
await fleet.env.close_all_async(run_id="run-123")
|
|
200
|
+
|
|
201
|
+
# Close all instances for your profile
|
|
202
|
+
await fleet.env.close_all_async(profile_id="self")
|
|
203
|
+
|
|
204
|
+
# Close a specific instance by ID
|
|
205
|
+
await fleet.env.close_async("bc8954c2")
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
`"self"` is an alias for the profile associated with your `FLEET_API_KEY`.
|
|
209
|
+
|
|
210
|
+
## Account Information
|
|
211
|
+
|
|
212
|
+
View your current account details including team info, instance limits, and profile ID:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
account = await fleet.env.account_async()
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"team_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
|
|
223
|
+
"team_name": "My Team",
|
|
224
|
+
"instance_limit": 32000,
|
|
225
|
+
"instance_count": 924,
|
|
226
|
+
"profile_id": "11111111-2222-3333-4444-555555555555",
|
|
227
|
+
"profile_name": "Jane Doe"
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Run Tracking
|
|
232
|
+
|
|
233
|
+
Track active and past runs:
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
# List active runs
|
|
237
|
+
runs = await fleet.env.list_runs_async()
|
|
238
|
+
|
|
239
|
+
# List all runs (active and inactive)
|
|
240
|
+
runs = await fleet.env.list_runs_async(status="all")
|
|
241
|
+
|
|
242
|
+
# Filter by profile
|
|
243
|
+
runs = await fleet.env.list_runs_async(profile_id="self")
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Returns:
|
|
247
|
+
|
|
248
|
+
```json
|
|
249
|
+
[
|
|
250
|
+
{
|
|
251
|
+
"run_id": "run-123",
|
|
252
|
+
"running_count": 0,
|
|
253
|
+
"total_count": 4,
|
|
254
|
+
"first_created_at": "2025-10-24T09:48:47.152387",
|
|
255
|
+
"last_created_at": "2025-10-24T09:55:19.284294",
|
|
256
|
+
"profile_id": "11111111-2222-3333-4444-555555555555"
|
|
257
|
+
}
|
|
258
|
+
]
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Task Verification
|
|
262
|
+
|
|
263
|
+
Verify task completion and get detailed results:
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
result = await task.verify_detailed_async(env.instance_id)
|
|
267
|
+
print(result)
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
{
|
|
274
|
+
"key": "task_abcdef",
|
|
275
|
+
"version": 4,
|
|
276
|
+
"success": true,
|
|
277
|
+
"result": 1.0,
|
|
278
|
+
"error": null,
|
|
279
|
+
"execution_time_ms": 2291,
|
|
280
|
+
"stdout": ""
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
On failure, `stdout` contains detailed verification errors:
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"key": "task_abcdef",
|
|
289
|
+
"version": 4,
|
|
290
|
+
"success": true,
|
|
291
|
+
"result": 0,
|
|
292
|
+
"error": null,
|
|
293
|
+
"execution_time_ms": 2291,
|
|
294
|
+
"stdout": "Verification errors: [\"Expected field to be 'value', got None\", \"Form not marked as complete\"]"
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Complete Example
|
|
299
|
+
|
|
300
|
+
```python
|
|
301
|
+
import fleet
|
|
302
|
+
import asyncio
|
|
303
|
+
|
|
304
|
+
async def main():
|
|
305
|
+
# Load tasks from a project
|
|
306
|
+
tasks = await fleet.load_tasks_async(project_key="my-project")
|
|
307
|
+
|
|
308
|
+
for task in tasks:
|
|
309
|
+
# Create environment
|
|
310
|
+
env = await fleet.env.make_async(
|
|
311
|
+
env_key=task.env_key,
|
|
312
|
+
data_key=task.data_key,
|
|
313
|
+
env_variables=task.env_variables,
|
|
314
|
+
ttl_seconds=7200,
|
|
315
|
+
run_id="my-evaluation-run",
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
try:
|
|
319
|
+
# Access the environment URL
|
|
320
|
+
print(env.urls.app[0])
|
|
321
|
+
|
|
322
|
+
# ... run your agent ...
|
|
323
|
+
|
|
324
|
+
# Verify task completion
|
|
325
|
+
result = await task.verify_detailed_async(env.instance_id)
|
|
326
|
+
print(f"Task {task.key}: score={result['result']}")
|
|
327
|
+
|
|
328
|
+
finally:
|
|
329
|
+
await env.close()
|
|
330
|
+
|
|
331
|
+
# Clean up all instances from this run
|
|
332
|
+
await fleet.env.close_all_async(run_id="my-evaluation-run")
|
|
333
|
+
|
|
334
|
+
if __name__ == "__main__":
|
|
335
|
+
asyncio.run(main())
|
|
336
|
+
```
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# Fleet SDK
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/fleet-python/)
|
|
4
|
+
[](https://pypi.org/project/fleet-python/)
|
|
5
|
+
[](https://pypi.org/project/fleet-python/)
|
|
6
|
+
|
|
7
|
+
The Fleet Python SDK provides programmatic access to Fleet's environment infrastructure.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install fleet-python
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## API Key Setup
|
|
16
|
+
|
|
17
|
+
Get your API key from the [Fleet Dashboard](https://fleetai.com/dashboard/api-keys), then set it as an environment variable:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
export FLEET_API_KEY="sk_your_key_here"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Tasks
|
|
24
|
+
|
|
25
|
+
A **Task** represents a unit of work for an agent to complete within an environment. Each task combines:
|
|
26
|
+
|
|
27
|
+
- **Prompt**: Instructions describing what needs to be done
|
|
28
|
+
- **Environment**: The environment configuration (`env_key`, `data_key`, `env_variables`)
|
|
29
|
+
- **Verifier**: Code that validates task completion and returns a score (0.0 to 1.0)
|
|
30
|
+
|
|
31
|
+
Tasks provide all the configuration needed to spin up an environment and verify an agent's work.
|
|
32
|
+
|
|
33
|
+
### Task Properties
|
|
34
|
+
|
|
35
|
+
| Property | Description |
|
|
36
|
+
| --------------- | ----------------------------------------------------- |
|
|
37
|
+
| `key` | Unique task identifier |
|
|
38
|
+
| `prompt` | Instructions for the agent |
|
|
39
|
+
| `env_key` | Environment identifier (e.g., `"hubspot:v1.2"`) |
|
|
40
|
+
| `data_key` | Data configuration identifier |
|
|
41
|
+
| `env_variables` | Environment variables for the task |
|
|
42
|
+
| `metadata` | Additional info (e.g., `avg_steps` for task difficulty) |
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import fleet
|
|
48
|
+
|
|
49
|
+
async def main():
|
|
50
|
+
# Load a task
|
|
51
|
+
tasks = await fleet.load_tasks_async(
|
|
52
|
+
keys=["task_abcdef"]
|
|
53
|
+
)
|
|
54
|
+
task = tasks[0]
|
|
55
|
+
|
|
56
|
+
# Create an environment from the task
|
|
57
|
+
env = await fleet.env.make_async(
|
|
58
|
+
env_key=task.env_key,
|
|
59
|
+
data_key=task.data_key,
|
|
60
|
+
env_variables=task.env_variables,
|
|
61
|
+
ttl_seconds=7200,
|
|
62
|
+
run_id="run-123",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
# Access the environment URL
|
|
66
|
+
print(env.urls.app[0])
|
|
67
|
+
|
|
68
|
+
# ... interact with the environment ...
|
|
69
|
+
|
|
70
|
+
# Verify task completion
|
|
71
|
+
result = await task.verify_detailed_async(env.instance_id)
|
|
72
|
+
print(result)
|
|
73
|
+
|
|
74
|
+
# Clean up
|
|
75
|
+
await env.close()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Loading Tasks
|
|
79
|
+
|
|
80
|
+
### By Task Keys
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
tasks = await fleet.load_tasks_async(
|
|
84
|
+
keys=["task_abcdef"]
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### By Project Key
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
tasks = await fleet.load_tasks_async(project_key="my-project")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Creating Environments
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
env = await fleet.env.make_async(
|
|
98
|
+
env_key=task.env_key,
|
|
99
|
+
data_key=task.data_key,
|
|
100
|
+
env_variables=task.env_variables,
|
|
101
|
+
ttl_seconds=7200,
|
|
102
|
+
run_id="run-123",
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### With Heartbeats (Optional)
|
|
107
|
+
|
|
108
|
+
Optionally enable heartbeats to keep environments alive during long-running operations:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
env = await fleet.env.make_async(
|
|
112
|
+
env_key=task.env_key,
|
|
113
|
+
data_key=task.data_key,
|
|
114
|
+
env_variables=task.env_variables,
|
|
115
|
+
ttl_seconds=10800,
|
|
116
|
+
heartbeat_interval=30, # seconds
|
|
117
|
+
)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Send heartbeats to keep the environment alive:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# Via the environment object
|
|
124
|
+
await env.heartbeat()
|
|
125
|
+
|
|
126
|
+
# Or via instance ID
|
|
127
|
+
await fleet.env.heartbeat_async(instance_id)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Heartbeats are optional. If `heartbeat_interval` is not set, the instance lifetime is controlled solely by `ttl_seconds`. If heartbeats are enabled and missed 3 consecutive times, the instance will be terminated. Heartbeats take precedence over the TTL.
|
|
131
|
+
|
|
132
|
+
## Instance Management
|
|
133
|
+
|
|
134
|
+
### List Instances
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
# List all instances for a run
|
|
138
|
+
instances = await fleet.env.list_instances_async(run_id="run-123")
|
|
139
|
+
|
|
140
|
+
# List all instances for your profile
|
|
141
|
+
instances = await fleet.env.list_instances_async(profile_id="self")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Close Instances
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
# Close all instances for a run
|
|
148
|
+
await fleet.env.close_all_async(run_id="run-123")
|
|
149
|
+
|
|
150
|
+
# Close all instances for your profile
|
|
151
|
+
await fleet.env.close_all_async(profile_id="self")
|
|
152
|
+
|
|
153
|
+
# Close a specific instance by ID
|
|
154
|
+
await fleet.env.close_async("bc8954c2")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`"self"` is an alias for the profile associated with your `FLEET_API_KEY`.
|
|
158
|
+
|
|
159
|
+
## Account Information
|
|
160
|
+
|
|
161
|
+
View your current account details including team info, instance limits, and profile ID:
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
account = await fleet.env.account_async()
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"team_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
|
|
172
|
+
"team_name": "My Team",
|
|
173
|
+
"instance_limit": 32000,
|
|
174
|
+
"instance_count": 924,
|
|
175
|
+
"profile_id": "11111111-2222-3333-4444-555555555555",
|
|
176
|
+
"profile_name": "Jane Doe"
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Run Tracking
|
|
181
|
+
|
|
182
|
+
Track active and past runs:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
# List active runs
|
|
186
|
+
runs = await fleet.env.list_runs_async()
|
|
187
|
+
|
|
188
|
+
# List all runs (active and inactive)
|
|
189
|
+
runs = await fleet.env.list_runs_async(status="all")
|
|
190
|
+
|
|
191
|
+
# Filter by profile
|
|
192
|
+
runs = await fleet.env.list_runs_async(profile_id="self")
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
[
|
|
199
|
+
{
|
|
200
|
+
"run_id": "run-123",
|
|
201
|
+
"running_count": 0,
|
|
202
|
+
"total_count": 4,
|
|
203
|
+
"first_created_at": "2025-10-24T09:48:47.152387",
|
|
204
|
+
"last_created_at": "2025-10-24T09:55:19.284294",
|
|
205
|
+
"profile_id": "11111111-2222-3333-4444-555555555555"
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Task Verification
|
|
211
|
+
|
|
212
|
+
Verify task completion and get detailed results:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
result = await task.verify_detailed_async(env.instance_id)
|
|
216
|
+
print(result)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"key": "task_abcdef",
|
|
224
|
+
"version": 4,
|
|
225
|
+
"success": true,
|
|
226
|
+
"result": 1.0,
|
|
227
|
+
"error": null,
|
|
228
|
+
"execution_time_ms": 2291,
|
|
229
|
+
"stdout": ""
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
On failure, `stdout` contains detailed verification errors:
|
|
234
|
+
|
|
235
|
+
```json
|
|
236
|
+
{
|
|
237
|
+
"key": "task_abcdef",
|
|
238
|
+
"version": 4,
|
|
239
|
+
"success": true,
|
|
240
|
+
"result": 0,
|
|
241
|
+
"error": null,
|
|
242
|
+
"execution_time_ms": 2291,
|
|
243
|
+
"stdout": "Verification errors: [\"Expected field to be 'value', got None\", \"Form not marked as complete\"]"
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Complete Example
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
import fleet
|
|
251
|
+
import asyncio
|
|
252
|
+
|
|
253
|
+
async def main():
|
|
254
|
+
# Load tasks from a project
|
|
255
|
+
tasks = await fleet.load_tasks_async(project_key="my-project")
|
|
256
|
+
|
|
257
|
+
for task in tasks:
|
|
258
|
+
# Create environment
|
|
259
|
+
env = await fleet.env.make_async(
|
|
260
|
+
env_key=task.env_key,
|
|
261
|
+
data_key=task.data_key,
|
|
262
|
+
env_variables=task.env_variables,
|
|
263
|
+
ttl_seconds=7200,
|
|
264
|
+
run_id="my-evaluation-run",
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
try:
|
|
268
|
+
# Access the environment URL
|
|
269
|
+
print(env.urls.app[0])
|
|
270
|
+
|
|
271
|
+
# ... run your agent ...
|
|
272
|
+
|
|
273
|
+
# Verify task completion
|
|
274
|
+
result = await task.verify_detailed_async(env.instance_id)
|
|
275
|
+
print(f"Task {task.key}: score={result['result']}")
|
|
276
|
+
|
|
277
|
+
finally:
|
|
278
|
+
await env.close()
|
|
279
|
+
|
|
280
|
+
# Clean up all instances from this run
|
|
281
|
+
await fleet.env.close_all_async(run_id="my-evaluation-run")
|
|
282
|
+
|
|
283
|
+
if __name__ == "__main__":
|
|
284
|
+
asyncio.run(main())
|
|
285
|
+
```
|
|
@@ -112,7 +112,7 @@ async def main():
|
|
|
112
112
|
print(f"Task definition:")
|
|
113
113
|
print(f" Key: {task.key}")
|
|
114
114
|
print(f" Prompt: {task.prompt}")
|
|
115
|
-
print(f" Environment: {task.
|
|
115
|
+
print(f" Environment: {task.env_key}")
|
|
116
116
|
print(
|
|
117
117
|
f" Verifier: {task.verifier.key if hasattr(task.verifier, 'key') else 'create_bug_issue'}"
|
|
118
118
|
)
|
|
@@ -38,6 +38,12 @@ def main():
|
|
|
38
38
|
help="Output JSON filename (defaults to {team_id}.json)",
|
|
39
39
|
default=None,
|
|
40
40
|
)
|
|
41
|
+
parser.add_argument(
|
|
42
|
+
"--skip-missing-verifiers",
|
|
43
|
+
"-s",
|
|
44
|
+
action="store_true",
|
|
45
|
+
help="Skip tasks missing verifier_func instead of erroring",
|
|
46
|
+
)
|
|
41
47
|
|
|
42
48
|
args = parser.parse_args()
|
|
43
49
|
|
|
@@ -91,16 +97,32 @@ def main():
|
|
|
91
97
|
missing_verifier.append(task.key)
|
|
92
98
|
|
|
93
99
|
if missing_verifier:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
if args.skip_missing_verifiers:
|
|
101
|
+
print(
|
|
102
|
+
f"\n⚠ Skipping {len(missing_verifier)} task(s) missing verifier_func:"
|
|
103
|
+
)
|
|
104
|
+
for key in missing_verifier[:10]: # Show first 10
|
|
105
|
+
print(f" - {key}")
|
|
106
|
+
if len(missing_verifier) > 10:
|
|
107
|
+
print(f" ... and {len(missing_verifier) - 10} more")
|
|
108
|
+
# Filter out tasks without verifiers
|
|
109
|
+
tasks = [task for task in tasks if task.verifier_func]
|
|
110
|
+
print(f"\n{len(tasks)} task(s) remaining after filtering")
|
|
111
|
+
if not tasks:
|
|
112
|
+
raise ValueError(
|
|
113
|
+
"No tasks remaining after filtering. Nothing to export."
|
|
114
|
+
)
|
|
115
|
+
else:
|
|
116
|
+
print(f"\n✗ Error: {len(missing_verifier)} task(s) missing verifier_func:")
|
|
117
|
+
for key in missing_verifier[:10]: # Show first 10
|
|
118
|
+
print(f" - {key}")
|
|
119
|
+
if len(missing_verifier) > 10:
|
|
120
|
+
print(f" ... and {len(missing_verifier) - 10} more")
|
|
121
|
+
raise ValueError(
|
|
122
|
+
"All tasks must have a verifier_func. Cannot export tasks without verifiers."
|
|
123
|
+
)
|
|
124
|
+
else:
|
|
125
|
+
print("✓ All tasks have verifier_func")
|
|
104
126
|
|
|
105
127
|
# Determine output filename
|
|
106
128
|
output_file = args.output or f"{account.team_id}.json"
|