Metadata-Version: 2.4
Name: invilabs
Version: 0.1.5
Summary: Blocking Python SDK for Invi Labs phone automation
Author: Invi Labs
Project-URL: Homepage, https://invilabs.io
Project-URL: Documentation, https://sdk.invilabs.io
Project-URL: Changelog, https://sdk.invilabs.io/downloads/
Keywords: iphone,automation,sdk,ai-agent,ocr
Classifier: Development Status :: 3 - Alpha
Classifier: Programming Language :: Python :: 3
Classifier: Typing :: Typed
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# Invi Labs Python SDK

Automate real iPhones through the Invi Labs API using your API key and phone ID.
Non-jailbroken iPhones require [Invi Dongle](https://invilabs.io/connect).

## Install

```sh
python -m pip install invilabs
```

Requires Python 3.10 or newer. No third-party runtime dependencies.

## Connect and run an action

Set `INVI_API_KEY` and `INVI_PHONE_ID` in your environment. Keep your API key private.

```python
import os
from invilabs import Client

client = Client(os.environ["INVI_API_KEY"])
phone = client.phone(os.environ["INVI_PHONE_ID"])

print(phone.details())
phone.tap(100, 200)
phone.save_screenshot("screen.png")
```

Coordinates use full-resolution screenshot pixels. Calls block until completion;
the SDK waits and retries when the phone reports `device_busy`. Uncertain execution
is not automatically repeated. Use the operation key to look up its status.

## AI generation

```python
result = client.generate(
    "Generate an email address using example.com",
    result_type="email",
)
print(result["data"]["text"])
print(client.balance())
```

Generation supports text, usernames and email address strings, optionally using a
local PNG/JPEG image. It does not create mailboxes. OCR, AI prompts and generation
use your shared Account AI balance. No AI-provider key is required.

## Features

- Tap, swipe, scroll, type, explicit key presses and opening installed apps.
- Screenshots as PNG bytes or saved to your computer.
- Grouped OCR with text and bounding boxes.
- Single-action AI prompts and structured screen answers.
- Image/video import through Invi Helper on supported dongle phones.
- Device details, balance and operation recovery.

All network operations use the public HTTPS API with your API key. The package
contains client code and response contracts; phone control and AI processing run
on Invi Labs services. API keys remain on your computer and are sent only as an
authentication header to the configured API. HTTP redirects are not followed.

This is an initial release. Device support and feature verification limits are
listed in the [release notes](https://sdk.invilabs.io/downloads/).

[Documentation](https://sdk.invilabs.io/) ·
[Quickstart](https://sdk.invilabs.io/quickstart/) ·
[Generation and outputs](https://sdk.invilabs.io/reference/generation/) ·
[Errors and recovery](https://sdk.invilabs.io/reference/credits-and-recovery/)

## Typing completion

Version 0.1.1 waits for the dongle's final typing acknowledgment. Long typing and
AI actions remain synchronous to Python while the SDK waits for the same server
operation to finish. It never starts a second copy while waiting. Call
`phone.press("enter")` after `phone.type(text)` returns to submit a search.
A lost connection can still produce `ExecutionUncertainError`; inspect the
recorded operation and phone state before deciding on another action.

### Tap text with OCR (0.1.2)

```python
result = phone.tap_text("Add a comment")
result = phone.tap_text(r"^(?:add|write) (?:a )?comment[.…]*$", regex=True)
print(result["point"], result["ocr"]["credits_charged"])
```

Matches the full trimmed OCR block case-insensitively by default; regex uses
`re.search`. The tap lands randomly inside an inset of the block's bounds.
Use `randomize=False` for its center. Multiple matches raise
`AmbiguousTextError` unless a zero-based `occurrence` is supplied; no match raises
`TargetNotFoundError`. Neither error taps. Regex substring matches use the whole
block's box. Keep the screen stable between OCR and tap: these are two operations.

Returns `match` (OCR block), `point` (`x`, `y` pixels), `ocr` (blocks, credit charge,
balance), and `tap` (execution status and coordinates). Only the normal OCR credit
charge applies, including when no match is found. A tap failure retains the OCR
result in `error.details["ocr"]`. This helper makes no VLM request.


### Check text presence with OCR (0.1.2)

```python
check = phone.text_exists("Continue", region="middle")
if check["exists"]:
    print(check["matches"])

check = phone.text_exists(r"^(?:add|write) (?:a )?comment[.…]*$", regex=True, region="bottom")
check = phone.text_exists("Comments", region=(0, 900, 1170, 600))
```

Omit `region` for the full screen. Named regions are full-width horizontal thirds;
custom tuples are `(x,y,width,height)` in original screenshot pixels. A block's
center determines region membership. Literal and regex rules match `tap_text`.
Returns `exists` (bool), `matches` (OCR blocks), `region` (resolved pixel box or
None), and `ocr` (full result with charge and balance). Check `result["exists"]`,
not the dictionary's truthiness. No match is False; OCR failures raise errors.
One billed full-screen OCR request is made regardless of region or match count.
Named regions also read dimensions before and after OCR and reject geometry
changes. This method never taps or calls a VLM.


## Jailbroken-only extensions (0.1.5)

The `phone.jailbroken` namespace is available only for jailbroken iPhones with
our current daemon, UI tweak and container service. Dongle phones reject these
operations; their existing controls and OCR helpers are unchanged.

```python
jb = phone.jailbroken
print(jb.apps())
print(jb.containers.list("com.example.app"))
created = jb.containers.create("com.example.app", "testing")
jb.open_app("com.example.app", cid=created["cid"])
print(jb.containers.active("com.example.app"))
jb.containers.set_active("com.example.app", "default")
jb.containers.delete("com.example.app", created["cid"])
print(jb.ui_dump())
jb.tap_text("Settings")
```

Containers use the account's existing slot pool and appear in the panel. Container
names contain 1–64 letters, digits, underscores or hyphens. The default container
cannot be deleted. Switching stops the app; `open_app(..., cid=...)` switches and
launches under one lease. A lost acknowledgment is never automatically replayed.

`jb.tap_text` uses exact trimmed native UI text and converts point bounds to pixel
coordinates. Matching is case insensitive by default. Duplicate matches require
`occurrence=0` (or another zero-based occurrence, in screen reading order).
Disabled and offscreen elements are excluded. UI dump targeting is unbilled and
has no OCR fallback. Native dumps require the UI tweak in the foreground app;
some custom-rendered content is unavailable. `phone.tap_text` retains its existing
OCR behavior on all phones.

Use the common `phone.upload_media(path)` and `phone.prompt(...)` methods on both
phone types. Jailbroken uploads use an exact native Photos transaction and wait
for its asset acknowledgment before cleaning Library storage. Image/video limits,
permissions, shared credits for AI prompts and operation recovery remain the same.
