Metadata-Version: 2.4
Name: visus-sdk-runpilot
Version: 0.1.1
Summary: In-process Python SDK for the RunPilot RPA orchestrator (the client bots use to talk back to the server).
Author-email: Matheus Pereira <matheuszwilkdev@gmail.com>
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/botvisus/visus-sdk-runpilot
Project-URL: Repository, https://github.com/botvisus/visus-sdk-runpilot.git
Project-URL: Documentation, https://github.com/botvisus/visus-sdk-runpilot#readme
Project-URL: Bug Tracker, https://github.com/botvisus/visus-sdk-runpilot/issues
Keywords: rpa,orchestrator,automation,runpilot,sdk,bot,workflow
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
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
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Office/Business
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: requests>=2.25
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Dynamic: license-file

# runpilot — Python SDK

In-process Python SDK for the [RunPilot](https://github.com/runpilot/runpilot) RPA
orchestrator. This is the library your bot imports to talk back to the RunPilot
server from *inside* a run: report progress, stream logs, fetch credentials,
upload artifacts, poll interrupt/kill signals and pull DataPool items.

Think of it as the runtime bridge between an RPA script and the orchestrator that
scheduled it. The runner injects the connection details as environment variables;
the SDK reads them and gives you a single `Orchestrator` object.

## Installation

```sh
pip install runpilot
```

Requires Python 3.9+. The only runtime dependency is `requests`.

## Quick start

Inside a run, build the client from the environment the runner injected:

```python
from runpilot import Orchestrator

bot = Orchestrator.from_env()          # reads RUNPILOT_SERVER + run token / api key

ctx = bot.get_run()                    # the run + task context
bot.report_progress(10, "starting")

api_key = bot.get_credential("stripe", "SECRET_KEY")

pool = bot.datapool("invoices")        # claim-and-report DataPool items
while (item := pool.next_item()) is not None:
    process(item.data)
    item.report_done()                 # or item.report_error(business=True, message=...)

art = bot.upload_artifact("out/report.pdf")

signals = bot.get_signals()            # cooperative interrupt / kill
if signals.kill_requested or signals.interrupt_requested:
    bot.finish("failure", "interrupted")
    raise SystemExit(0)

bot.finish("success", "processed 42 rows")   # canonical: success | failure
```

### Environment variables

`Orchestrator.from_env()` reads:

| Variable | Purpose |
|----------|---------|
| `RUNPILOT_SERVER` | Base URL of the orchestrator (no path), e.g. `https://api.runpilot.dev` |
| `RUNPILOT_RUN_TOKEN` | Per-run token (RUN_TOKEN mode — the in-run path) |
| `RUNPILOT_RUN_ID` | Run ID that accompanies the run token |
| `RUNPILOT_API_KEY` | Organization API key (management mode) |

RUN_TOKEN mode is what you get inside a run; the in-run methods
(`report_progress`, `get_credential`, `datapool`, `upload_artifact`, `finish`, …)
require it.

## Testing your bot — fully offline

`Orchestrator.mock()` returns a client that never performs a network request.
Every in-run call is recorded on `.calls` and returns a sensible canned value, so
you can unit-test a bot without a live server:

```python
from runpilot import Orchestrator

bot = Orchestrator.mock(
    run={"run": {"id": "run_1"}, "task": {"name": "demo"}},
    credentials={("stripe", "SECRET_KEY"): "sk_test_123"},
    datapool={"invoices": [{"id": "inv_1", "data": {"amount": 10}}]},
)

bot.report_progress(50, "halfway")
assert bot.get_credential("stripe", "SECRET_KEY") == "sk_test_123"
assert bot.calls[-1]["method"] == "get_credential"
```

## API surface

`from runpilot import ...`

| Export | What it is |
|--------|-----------|
| `Orchestrator` | The client. `from_env()`, `mock()`, `get_run()`, `report_progress()`, `log()`, `get_credential()`, `upload_artifact()`, `get_signals()`, `datapool()`, `finish()` |
| `DataPool`, `DataPoolItem` | Claim-and-report work queue; `pool.next_item()`, then `item.report_done()` / `item.report_error()` |
| `Run`, `RunContext`, `Task`, `Artifact`, `Signals` | Typed models returned by the client |
| `RunPilotError` and subclasses | `ConfigurationError`, `AuthModeError`, `AuthenticationError`, `NotFoundError`, `ApiError`, `RunAlreadyFinishedError`, `RunTerminalError` |

## License

MIT
