Metadata-Version: 2.4
Name: meteor-ia
Version: 0.6.1
Summary: SDK oficial de Python para la API de Meteor — infraestructura agéntica como servicio.
Project-URL: Homepage, https://developers.meteor.com.co
Project-URL: Documentation, https://developers.meteor.com.co
Project-URL: Repository, https://github.com/met-claude/Met
Author: Meteor
License: MIT
Keywords: agentic,agents,ai,meteor,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# meteor-ia — SDK oficial de Python para Meteor

Infraestructura agéntica como servicio. Ejecutá tus Mets, gestioná el CRM,
integraciones MCP y más, por código.

> Server-side only: tu API key `met_*` es secreta. Nunca la expongas en el browser.

## Instalación

```bash
pip install meteor-ia
```

Sin dependencias de runtime (solo la stdlib).

## Antes de anunciar una versión

Después de publicar, verificá el artefacto desde PyPI —no el código del
workspace— antes de anunciarlo:

```bash
npm run python-sdk:published-check
```

El chequeo instala exactamente la versión declarada en un directorio temporal y
comprueba que importa, que su versión coincide y que expone la superficie mínima
del cliente. Si PyPI todavía sirve una versión anterior, falla de forma explícita.

## Uso

```python
import os
from meteor_ia import Met

met = Met(os.environ["MET_API_KEY"], workspace_id=7)

# Ejecutar un Met y esperar el resultado
run = met.runs.create("Resume los leads de hoy", met="ventas")
print(run["output"])
print(run["energy"])  # breakdown de Energía del run

# Streaming de eventos
for event, data in met.runs.stream("Hola"):
    print(event, data)

# CRM
for contact in met.contacts.iterate():
    print(contact["id"], contact.get("name"))
```

### Manejo de errores

```python
from meteor_ia import MetRateLimitError, MetAuthError

try:
    met.runs.create("...")
except MetRateLimitError as e:
    if e.is_quota:
        # Cupo agotado: no se resuelve reintentando. Frena el lote hasta el reinicio.
        print(e.code, e.message, "se reinicia en", e.retry_after, "segundos")
    else:
        print("límite por minuto: espera", e.retry_after, "segundos")
except MetAuthError:
    print("key inválida")
```

Jerarquía: `MetError` → `MetAuthError` (401), `MetInvalidRequestError`
(400/403/404/409), `MetRateLimitError` (429, con `retry_after` e `is_quota`),
`MetAgentError` (el Met falló), `MetApiError` (5xx).

#### Qué 429 reintenta el SDK

| `code` | Qué es | ¿El SDK reintenta? |
|---|---|---|
| `rate_limited` | Límite de peticiones por minuto | Sí, hasta `max_retries` veces, respetando `Retry-After` |
| `daily_request_limit_exceeded` | Tope diario de peticiones del workspace | No: lanza de una (`Retry-After` = segundos hasta las 00:00 UTC) |
| `quota_exceeded` | Cuota mensual de la API key | No |
| `test_run_daily_cap` | Tope diario de runs con key de prueba | No |
| `budget_exceeded` | Presupuesto de Energía del mes de la key | No |

Un cupo agotado no se arregla esperando unos segundos, así que el SDK no gasta tu
tiempo reintentándolo: te entrega el `MetRateLimitError` con `code`, `message`,
`retry_after` e `is_quota=True`. Tampoco reintenta un 429 cuyo `Retry-After` pase de
60 segundos. La lista está en `QUOTA_ERROR_CODES` y la puedes consultar con
`is_quota_error_code(code)`.

#### Mirar el cupo antes de chocarte con él

`met.billing.limits()` (scope `billing:read`) trae todos los límites del plan en una
llamada: por cada recurso, lo usado, lo incluido, lo que suman tus complementos, el
tope que se aplica hoy (`limit`), qué pasa al llegar (`enforcement`: `hard` bloquea,
`soft` avisa y frena a 3 veces el tope, `none` solo mide) y cuándo se reinicia
(`resets_at`, 00:00 UTC). La respuesta está tipada como `PlanLimits`.

```python
limites = met.billing.limits()
api = next(r for r in limites["resources"] if r["key"] == "api_requests_daily")
if api["limit"] is not None and api["used"] + len(lote) > api["limit"]:
    print("No alcanza: te quedan", api["limit"] - api["used"], "hasta", api["resets_at"])
```

### Webhooks salientes (Meteor → tu servidor)

Verificá la firma HMAC de cada entrega antes de procesarla:

```python
from meteor_ia import construct_event, MetSignatureVerificationError

# En tu handler HTTP (Flask/FastAPI/…):
try:
    event = construct_event(raw_body, signature_header, os.environ["MET_WEBHOOK_SECRET"])
except MetSignatureVerificationError:
    return ("bad signature", 400)

if event["type"] == "run.completed":
    ...
```

### Partners

Con una key de partner (`partner:*`):

```python
met.partner.clients.list()
met.partner.commissions.list(status="PAID")
met.partner.payouts.summary()
```

## Auto-paginación

Los endpoints de lista devuelven `{ "data": [...], "has_more": bool }`. Usá
`.iterate()` para recorrer todo transparentemente (cursor opaco `starting_after`).

## Reintentos

429 y 5xx se reintentan con backoff exponencial (default 2 intentos, respeta
`Retry-After`). Los POST llevan `Idempotency-Key` automático para no duplicar.
