Metadata-Version: 2.4
Name: robot-wrapper-sdk
Version: 0.2.22
Summary: Robot Platform API SDK
Author-email: GH Robot Platform Team <team@ghrobot.com>
License: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: httpx[socks]>=0.24.1

# Robot Platform SDK (Python)

Python SDK for Robot Platform Developer API. Supports app credentials auth, sync/async clients, robot operations, worker task flows, and browser node control.

## Installation

```bash
pip install robot-wrapper-sdk
```

## Quick Start

```python
from robot_sdk import RobotPlatformModule, RobotStatus, RobotAuthStatus

sdk = RobotPlatformModule(
    base_url="http://localhost:8085",
    app_id="your_app_id",
    app_secret="your_app_secret",
)

robot = sdk.get_robot("2047631542552334336")
print(robot.platform if robot else "not found")

sdk.update_status("2047631542552334336", RobotStatus.LIVE)
sdk.update_auth_status("2047631542552334336", RobotAuthStatus.AUTHORIZED)

session = sdk.open_browser(robot_id="2047631542552334336")
cookies = sdk.get_browser_cookies(session.pod_name, robot_id="2047631542552334336")
sdk.navigate_browser(session.pod_name, "https://example.com")
text = sdk.get_browser_clean_text(session.pod_name)
html = sdk.get_browser_html(session.pod_name)
capture = sdk.capture_browser(session.pod_name)
print(session.pod_name, cookies.cookie_count, text.text, html.html[:20], capture.image)
sdk.close_browser(session.pod_name, robot_id="2047631542552334336")

sdk.close()
```

## Async Quick Start

```python
import asyncio
from robot_sdk import AsyncRobotPlatformModule

async def main():
    sdk = AsyncRobotPlatformModule(
        base_url="http://localhost:8085",
        app_id="your_app_id",
        app_secret="your_app_secret",
    )

    session = await sdk.open_browser(robot_id="2047631542552334336")
    cookies = await sdk.get_browser_cookies(session.pod_name, robot_id="2047631542552334336")
    await sdk.navigate_browser(session.pod_name, "https://example.com")
    text = await sdk.get_browser_clean_text(session.pod_name)
    html = await sdk.get_browser_html(session.pod_name)
    capture = await sdk.capture_browser(session.pod_name)
    print(session.pod_name, cookies.cookie_count, text.text, html.html[:20], capture.image)
    await sdk.close_browser(session.pod_name, robot_id="2047631542552334336")

    await sdk.close()

asyncio.run(main())
```

## Features

- Developer App authentication with `app_id` and `app_secret`.
- Sync client: `RobotPlatformModule`.
- Async client: `AsyncRobotPlatformModule`.
- Automatic access token creation and refresh on `401`.
- HTTP/SOCKS proxy support through `httpx[socks]`.
- Robot list/detail/delete/update operations.
- Secrets retrieval.
- Login task acquire/unlock flow.
- Security hardening acquire/unlock flow.
- Browser node open, navigate, clean text, HTML, capture, cookie read, and close flow.

## Configuration

You can pass config directly to the module constructor or use environment variables.

| Variable                    | Required | Description                                       |
| --------------------------- | -------- | ------------------------------------------------- |
| `ROBOT_PLATFORM_BASE_URL`   | Yes      | API server base URL, e.g. `http://localhost:8085` |
| `ROBOT_PLATFORM_APP_ID`     | Yes      | Developer App ID                                  |
| `ROBOT_PLATFORM_APP_SECRET` | Yes      | Developer App secret                              |
| `ROBOT_PLATFORM_PROXY_URL`  | No       | HTTP/SOCKS proxy URL for SDK HTTP calls           |

## Required Developer App Scopes

| SDK method                                                                                                                                  | Required scope            |
| ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
| `list_robots`, `get_robot`                                                                                                                  | `read:robots`             |
| `delete_robot`                                                                                                                              | `delete:robots`           |
| `get_secrets`                                                                                                                               | `read:secrets`            |
| `update_status`                                                                                                                             | `write:status`            |
| `update_auth_status`                                                                                                                        | `write:auth-status`       |
| `update_security_hardened`                                                                                                                  | `write:security-hardened` |
| `acquire_need_login`, `unlock_login_tasks`                                                                                                  | `acquire:login-tasks`     |
| `acquire_unhardened`, `unlock_hardening_tasks`                                                                                              | `acquire:hardening-tasks` |
| `acquire_robots`                                                                                                                            | `acquire:robots`          |
| `open_browser`, `navigate_browser`, `get_browser_clean_text`, `get_browser_html`, `capture_browser`, `get_browser_cookies`, `close_browser` | `open:browser`            |

## Acquire Robots Flow

Acquire authenticated live robots with an acquire lock so concurrent workers do not receive the same robot.

```python
robots = sdk.acquire_robots(
    limit=5,
    lock_minutes=30,
    project_name="Project A",
    platform="facebook",
    environment="chrome",
    metadata={"key": "country_code", "op": "ne", "value": "VN"},
)
```

## Browser Node Flow

If `robot_id` is provided, the backend loads `username`, `proxy/public_proxy`, and `country_code` from the robot record and metadata. Manual overrides are still supported when no robot ID is available.

```python
extra_data = {"job_id": "job-123", "step": "open-browser"}
session = sdk.open_browser(robot_id="2047631542552334336", extra_data=extra_data)
# Manual fallback:
# session = sdk.open_browser(username="example_user", proxy="socks5://127.0.0.1:1080", country_code="VN", extra_data=extra_data)

cookies = sdk.get_browser_cookies(session.pod_name, robot_id="2047631542552334336", extra_data=extra_data)
sdk.navigate_browser(session.pod_name, "https://example.com", extra_data=extra_data)
text = sdk.get_browser_clean_text(session.pod_name, extra_data=extra_data)
html = sdk.get_browser_html(session.pod_name, extra_data=extra_data)
capture = sdk.capture_browser(session.pod_name, extra_data=extra_data)
sdk.close_browser(session.pod_name, robot_id="2047631542552334336", extra_data=extra_data)
```

### Browser response models

`open_browser(...)` returns `BrowserSession`:

```python
BrowserSession(pod_name="selenium-node-abc123", session_id="selenium-node-abc123", status="running", extra_data={"job_id": "job-123"})
```

`get_browser_cookies(...)` returns `BrowserCookies`:

```python
BrowserCookies(
    pod_name="selenium-node-abc123",
    cookie_count=1,
    cookies=[{"name": "c_user", "value": "123", "domain": ".facebook.com"}],
    extra_data={"job_id": "job-123"},
)
```

## Main API

### Sync: `RobotPlatformModule`

- `list_robots(platform=None, status=None, auth_status=None, project_id=None, page=1, limit=20)`
- `get_robot(robot_id)`
- `delete_robot(robot_id)`
- `get_secrets(robot_id)`
- `update_status(robot_id, status)`
- `update_auth_status(robot_id, auth_status)`
- `update_security_hardened(robot_id, security_hardened)`
- `update_metadata(robot_id, metadata)`
- `update_robot(robot_id, payload)`
- `acquire_need_login(limit=20, lock_minutes=30, platforms=None)`
- `unlock_login_tasks(robot_ids)`
- `acquire_unhardened(limit=20, lock_minutes=30, min_age_days=0, platforms=None)`
- `acquire_robots(limit=20, lock_minutes=30, project_name=None, platform=None, environment=None, metadata=None)`
- `unlock_hardening_tasks(robot_ids)`
- `open_browser(robot_id=None, username="", proxy="", country_code="", extra_data=None)`
- `get_browser_cookies(pod_name, robot_id=None, extra_data=None)`
- `navigate_browser(pod_name, url, extra_data=None)`
- `get_browser_clean_text(pod_name, extra_data=None)`
- `get_browser_html(pod_name, extra_data=None)`
- `capture_browser(pod_name, extra_data=None)`
- `close_browser(pod_name, robot_id=None, extra_data=None)`
- `close()`

### Async: `AsyncRobotPlatformModule`

Async equivalents of all sync methods. Use `await sdk.close()` to close the async client.

## Response Shape

All API responses use the backend standard envelope:

```json
{
  "status": "success",
  "code": 200,
  "message": "OK",
  "data": {}
}
```

Browser cookies response example:

```json
{
  "status": "success",
  "code": 200,
  "message": "OK",
  "data": {
    "pod_name": "selenium-node-abc123",
    "cookie_count": 1,
    "cookies": [
      {
        "name": "c_user",
        "value": "123",
        "domain": ".facebook.com",
        "path": "/",
        "expires": 1790000000,
        "httpOnly": true,
        "secure": true,
        "sameSite": "Lax"
      }
    ]
  }
}
```

## Changelog

### [0.2.22]

#### Added

- Added optional `extra_data` passthrough support for browser helpers:
  - `open_browser(..., extra_data=None)`
  - `get_browser_cookies(..., extra_data=None)`
  - `close_browser(..., extra_data=None)`
- Added `extra_data` fields to `BrowserSession` and `BrowserCookies` response models.
- Added browser session action helpers for sync and async clients:
  - `navigate_browser(pod_name, url, extra_data=None)`
  - `get_browser_clean_text(pod_name, extra_data=None)`
  - `get_browser_html(pod_name, extra_data=None)`
  - `capture_browser(pod_name, extra_data=None)`
- Added typed response models for browser clean text, HTML, and capture results.
- Added generic authenticated robot acquire helper for sync and async clients:
  - `acquire_robots(limit=20, lock_minutes=30, project_name=None, platform=None, environment=None, metadata=None)`
- Supports backend `acquire:robots` scope with project, platform, environment, and metadata `eq`/`ne` filters.

### [0.2.20] - 2026-05-25

#### Added

- Added browser cookie helper:
  - `get_browser_cookies(pod_name, robot_id=None)`
- Added sync and async SDK support for `POST /api/v1/developer/browser/cookies`.
- Added `BrowserCookies` response model with `pod_name`, `cookie_count`, and `cookies`.

#### Changed

- README now includes PyPI-visible browser cookies examples and response schema.

### [0.2.19] - 2026-05-25

#### Added

- Added developer browser open/close helpers:
  - `open_browser(robot_id=None, username="", proxy="", country_code="")`
  - `close_browser(pod_name, robot_id=None)`
- Added sync and async SDK support for:
  - `POST /api/v1/developer/browser/open`
  - `DELETE /api/v1/developer/browser/close`
- Added `BrowserSession` response model with `pod_name`, `session_id`, and `status`.

#### Changed

- Browser open can use only `robot_id`; backend resolves username, proxy, and country code from robot data.

### [0.2.5] - 2026-04-24

#### Added

- Added login/hardening worker flows for sync and async clients.
- Added task acquire/unlock methods.
- Added auth status and security hardening update helpers.

#### Changed

- Updated README and guide for Developer App auth and worker task flow.

## Documentation

- Usage guide: [`docs/guide.md`](docs/guide.md)
- Package code: `robot_sdk/`

## Build & Publish

```bash
make venv
make install
make build
make publish
```

Requires valid PyPI credentials for Twine.

## License

MIT
