Metadata-Version: 2.5
Name: polanyi
Version: 0.4.0
Summary: Synthetic shoppers hard-pinned to any website that emit recommendation-system event data.
Project-URL: Homepage, https://github.com/tmoula/polanyi_agent_harness
Project-URL: Repository, https://github.com/tmoula/polanyi_agent_harness
Project-URL: Issues, https://github.com/tmoula/polanyi_agent_harness/issues
Author: Polanyi Labs
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: browser-agents,personas,recommendation-systems,recsys,synthetic-data
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.11
Requires-Dist: browser-use-sdk>=3.11.0
Requires-Dist: datasets>=3.0.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: pandas>=2.2.0
Requires-Dist: pyarrow>=17.0.0
Requires-Dist: pydantic>=2.7.0
Requires-Dist: python-dotenv>=1.0.0
Provides-Extra: dev
Requires-Dist: fastapi>=0.115.0; extra == 'dev'
Requires-Dist: httpx>=0.27.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: uvicorn[standard]>=0.30.0; extra == 'dev'
Provides-Extra: server
Requires-Dist: fastapi>=0.115.0; extra == 'server'
Requires-Dist: uvicorn[standard]>=0.30.0; extra == 'server'
Description-Content-Type: text/markdown

# Polanyi

**Synthetic shoppers hard-pinned to any website → recommendation-system event logs.**

Point Polanyi at a URL. It runs a diverse set of Nemotron personas as on-site shoppers (search, compare, select, stop before PII/payment) and emits privacy-safe `recsys_events` for offline experiments.

## Install

```bash
pip install polanyi
```

From source:

```bash
cd polanyi_agent_harness
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
```

## Colab / product path (`POLANYI_API_KEY`)

1. Sign up at **https://polanyilabs.com/signup**, verify your email, and create a key in the dashboard.
2. In Colab:

```python
!pip install -q "polanyi>=0.4"

import os
os.environ["POLANYI_API_KEY"] = "pk_live_..."  # from your dashboard

from polanyi import Client
result = Client().simulate(site="https://www.nike.com", n=3, concurrency=3)
print(result.summary())
result.to_jsonl("nike_events.jsonl")
```

## Local / power-user path (`BROWSER_USE_API_KEY`)

```bash
cp .env.example .env
# BROWSER_USE_API_KEY=bu_...
```

```python
from polanyi import Client

client = Client()  # uses Browser Use Cloud directly
result = client.simulate(
    site="https://www.expedia.com",
    n=10,
    concurrency=5,
    output_dir="runs/expedia",
)
print(result.summary())
result.to_jsonl("runs/expedia/merged.jsonl")
```

Agents are **hard-pinned**: they start on your site and must not leave that domain. External “Book with…” handoffs stop with `checkout_boundary_stop` (first-party-shaped data).

## Accounts and API keys

Accounts, keys and usage live in Supabase (schema: `supabase/migrations/` in the website repo).

1. Users sign up on the website (email + password with a 6-digit verification code, or Google).
2. In the dashboard they create, name and revoke `pk_live_…` keys. A key is shown once; only its SHA-256 hash is stored.
3. This server authorizes each request with the Supabase service-role key, enforces the user's
   `monthly_persona_limit` (default 100 personas/month), and records every simulation in `usage_records`.
   Simulations are private to the account that created them.

Server env (Fly):

```bash
fly secrets set -a polanyi \
  SUPABASE_URL="https://<project>.supabase.co" \
  SUPABASE_SERVICE_ROLE_KEY="<service_role key>" \
  POLANYI_DAILY_PERSONA_CAP=300
```

`POLANYI_DAILY_PERSONA_CAP` is a global safety limit across all users (optional).
To raise one user's quota, edit `profiles.monthly_persona_limit` in the Supabase table editor.

Legacy: `POLANYI_API_KEYS` (comma-separated) and `POLANYI_ADMIN_TOKEN` + `POST /v1/admin/keys`
still work for internal keys stored in `POLANYI_DATA_DIR/api_keys.json`.

Docker:

```bash
docker build -t polanyi-api .
docker run --rm -p 8080:8080 \
  -e POLANYI_API_KEYS=pk_live_... \
  -e BROWSER_USE_API_KEY=bu_... \
  polanyi-api
```

API surface:

| Method | Path | Purpose |
|--------|------|---------|
| `GET` | `/health` | Liveness |
| `POST` | `/v1/simulations` | Start a job (Bearer `pk_…`) |
| `GET` | `/v1/simulations/{id}` | Poll status + events |

## CLI

```bash
# Any site, N diverse personas
polanyi-sim --site https://www.nike.com --batch 5 --concurrency 5 \
  --output-dir output/nike_run

# Optional journey brief
polanyi-sim --site expedia.com --batch 10 --concurrency 10 \
  --prompt "Browse hotels and flights; pick what fits your budget." \
  --output-dir output/expedia_run

# Dry-run (personas only, no Browser Use)
polanyi-sim --site example.com --batch 3 --dry-run-persona --output-dir output/dry
```

Legacy (no `--site`) still works but is **not** hard-pinned.

## Outputs

Each session directory contains:

| File | Purpose |
|------|---------|
| `persona.json` | Synthetic identity |
| `browser_use_raw.json` | Raw Browser Use run |
| `recsys_events.jsonl` / `.parquet` | Ordered recsys events |
| `simulate_meta.json` | Site + run config (SDK / `--site` runs) |
| `simulate_plan.json` | Inferred vertical + per-persona journey goals |

## How journeys are planned

Live runs (`Client.simulate` / `polanyi-sim --site` without `--dry-run-persona`):

1. **LLM diagnosis** — a Browser Use agent opens the real site and returns an accurate JSON profile (`site_name`, `vertical`, `description`, `journey_templates`)
2. Saved to `simulate_diagnosis.json`
3. Each persona gets a different template from that diagnosis, personalized with their location/budget

Dry-runs skip the LLM and fall back to URL heuristics only.

```python
from polanyi import diagnose_site, plan_journeys
from polanyi.personas import load_personas

diagnosis = diagnose_site("https://www.ticketnetwork.com")
print(diagnosis.site_name, diagnosis.vertical)
print(diagnosis.description)
plan = plan_journeys("https://www.ticketnetwork.com", load_personas(count=3), diagnosis=diagnosis)
```

## Safety

- Synthetic actor IDs only (`syn_nmusa_*`)
- `training_use=offline_sandbox_only`
- Hard stop before identity / payment
- Hard site pin (first-party shaped)

## Publish to PyPI

```bash
pip install build twine
python -m build
twine upload dist/*
```

The `polanyi` name is available on PyPI as of packaging time.

## Roadmap

1. ~~Schema, personas, Cloud runner, batch concurrency~~
2. ~~Python SDK `Client.simulate(site=…)` + hard pin~~
3. ~~LLM site diagnosis → diverse per-persona journeys~~
4. ~~`POLANYI_API_KEY` + self-hostable API wrapping Browser Use~~
5. Parse quality gates + JSON repair for agent output
6. Hosted `api.polanyi.ai` + public PyPI release
