Metadata-Version: 2.4
Name: fleet-python
Version: 0.2.121
Summary: Python SDK for Fleet environments
Author-email: Fleet AI <nic@fleet.so>
License: Apache-2.0
Project-URL: Homepage, https://fleetai.com
Project-URL: Documentation, https://docs.fleetai.com
Project-URL: Repository, https://github.com/fleet-ai/fleet-sdk
Project-URL: Issues, https://github.com/fleet-ai/fleet-sdk/issues
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: aiohttp>=3.8.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: httpx-retries>=0.4.0
Requires-Dist: typing-extensions>=4.0.0
Requires-Dist: modulegraph2>=0.2.0
Requires-Dist: cloudpickle==3.1.1
Provides-Extra: cli
Requires-Dist: typer>=0.9.0; extra == "cli"
Requires-Dist: rich>=10.0.0; extra == "cli"
Requires-Dist: watchdog>=4.0.0; extra == "cli"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
Requires-Dist: black>=22.0.0; extra == "dev"
Requires-Dist: isort>=5.0.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: unasync>=0.6.0; extra == "dev"
Requires-Dist: python-dotenv>=1.1.1; extra == "dev"
Requires-Dist: typer>=0.9.0; extra == "dev"
Requires-Dist: rich>=10.0.0; extra == "dev"
Provides-Extra: playwright
Requires-Dist: playwright>=1.40.0; extra == "playwright"
Provides-Extra: eval
Requires-Dist: aiohttp>=3.9.0; extra == "eval"
Requires-Dist: google-genai>=1.0.0; extra == "eval"
Requires-Dist: mcp==1.24.0; python_version >= "3.10" and extra == "eval"
Dynamic: license-file

# Fleet SDK

[![PyPI version](https://img.shields.io/pypi/v/fleet-python.svg)](https://pypi.org/project/fleet-python/)
[![Python versions](https://img.shields.io/pypi/pyversions/fleet-python.svg)](https://pypi.org/project/fleet-python/)
[![License](https://img.shields.io/pypi/l/fleet-python.svg)](https://pypi.org/project/fleet-python/)

The Fleet Python SDK provides programmatic access to Fleet's environment infrastructure.

## Installation

```bash
pip install fleet-python
```

## API Key Setup

Get your API key from the [Fleet Dashboard](https://fleetai.com/dashboard/api-keys), then set it as an environment variable:

```bash
export FLEET_API_KEY="sk_your_key_here"
```

## Tasks

A **Task** represents a unit of work for an agent to complete within an environment. Each task combines:

- **Prompt**: Instructions describing what needs to be done
- **Environment**: The environment configuration (`env_key`, `data_key`, `env_variables`)
- **Verifier**: Code that validates task completion and returns a score (0.0 to 1.0)

Tasks provide all the configuration needed to spin up an environment and verify an agent's work.

### Task Properties

| Property        | Description                                           |
| --------------- | ----------------------------------------------------- |
| `key`           | Unique task identifier                                |
| `prompt`        | Instructions for the agent                            |
| `env_key`       | Environment identifier (e.g., `"hubspot:v1.2"`)       |
| `data_key`      | Data configuration identifier                         |
| `env_variables` | Environment variables for the task                    |
| `metadata`      | Additional info (e.g., `avg_steps` for task difficulty) |

## Quick Start

```python
import fleet

async def main():
    # Load a task
    tasks = await fleet.load_tasks_async(
        keys=["task_abcdef"]
    )
    task = tasks[0]

    # Create an environment from the task
    env = await fleet.env.make_async(
        env_key=task.env_key,
        data_key=task.data_key,
        env_variables=task.env_variables,
        ttl_seconds=7200,
        run_id="run-123",
    )

    # Access the environment URL
    print(env.urls.app[0])

    # ... interact with the environment ...

    # Verify task completion
    result = await task.verify_detailed_async(env.instance_id)
    print(result)

    # Clean up
    await env.close()
```

## Loading Tasks

### By Task Keys

```python
tasks = await fleet.load_tasks_async(
    keys=["task_abcdef"]
)
```

### By Project Key

```python
tasks = await fleet.load_tasks_async(project_key="my-project")
```

## Creating Environments

```python
env = await fleet.env.make_async(
    env_key=task.env_key,
    data_key=task.data_key,
    env_variables=task.env_variables,
    ttl_seconds=7200,
    run_id="run-123",
)
```

### With Heartbeats (Optional)

Optionally enable heartbeats to keep environments alive during long-running operations:

```python
env = await fleet.env.make_async(
    env_key=task.env_key,
    data_key=task.data_key,
    env_variables=task.env_variables,
    ttl_seconds=10800,
    heartbeat_interval=30,  # seconds
)
```

Send heartbeats to keep the environment alive:

```python
# Via the environment object
await env.heartbeat()

# Or via instance ID
await fleet.env.heartbeat_async(instance_id)
```

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.

## Instance Management

### List Instances

```python
# List all instances for a run
instances = await fleet.env.list_instances_async(run_id="run-123")

# List all instances for your profile
instances = await fleet.env.list_instances_async(profile_id="self")
```

### Close Instances

```python
# Close all instances for a run
await fleet.env.close_all_async(run_id="run-123")

# Close all instances for your profile
await fleet.env.close_all_async(profile_id="self")

# Close a specific instance by ID
await fleet.env.close_async("bc8954c2")
```

`"self"` is an alias for the profile associated with your `FLEET_API_KEY`.

## Account Information

View your current account details including team info, instance limits, and profile ID:

```python
account = await fleet.env.account_async()
```

Returns:

```json
{
  "team_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  "team_name": "My Team",
  "instance_limit": 32000,
  "instance_count": 924,
  "profile_id": "11111111-2222-3333-4444-555555555555",
  "profile_name": "Jane Doe"
}
```

## Run Tracking

Track active and past runs:

```python
# List active runs
runs = await fleet.env.list_runs_async()

# List all runs (active and inactive)
runs = await fleet.env.list_runs_async(status="all")

# Filter by profile
runs = await fleet.env.list_runs_async(profile_id="self")
```

Returns:

```json
[
  {
    "run_id": "run-123",
    "running_count": 0,
    "total_count": 4,
    "first_created_at": "2025-10-24T09:48:47.152387",
    "last_created_at": "2025-10-24T09:55:19.284294",
    "profile_id": "11111111-2222-3333-4444-555555555555"
  }
]
```

## Task Verification

Verify task completion and get detailed results:

```python
result = await task.verify_detailed_async(env.instance_id)
print(result)
```

Returns:

```json
{
  "key": "task_abcdef",
  "version": 4,
  "success": true,
  "result": 1.0,
  "error": null,
  "execution_time_ms": 2291,
  "stdout": ""
}
```

On failure, `stdout` contains detailed verification errors:

```json
{
  "key": "task_abcdef",
  "version": 4,
  "success": true,
  "result": 0,
  "error": null,
  "execution_time_ms": 2291,
  "stdout": "Verification errors: [\"Expected field to be 'value', got None\", \"Form not marked as complete\"]"
}
```

## Complete Example

```python
import fleet
import asyncio

async def main():
    # Load tasks from a project
    tasks = await fleet.load_tasks_async(project_key="my-project")
    
    for task in tasks:
        # Create environment
        env = await fleet.env.make_async(
            env_key=task.env_key,
            data_key=task.data_key,
            env_variables=task.env_variables,
            ttl_seconds=7200,
            run_id="my-evaluation-run",
        )
        
        try:
            # Access the environment URL
            print(env.urls.app[0])
            
            # ... run your agent ...
            
            # Verify task completion
            result = await task.verify_detailed_async(env.instance_id)
            print(f"Task {task.key}: score={result['result']}")
            
        finally:
            await env.close()
    
    # Clean up all instances from this run
    await fleet.env.close_all_async(run_id="my-evaluation-run")

if __name__ == "__main__":
    asyncio.run(main())
```
