Metadata-Version: 2.4
Name: argorix-guardrails
Version: 0.3.0
Summary: Official Argorix SDK for Python runtimes and guardrails instrumentation
Author: Argorix
License-Expression: MIT
Project-URL: Homepage, https://argorix.com
Project-URL: Documentation, https://github.com/argorixlabs/argorix-python#readme
Project-URL: Repository, https://github.com/argorixlabs/argorix-python
Project-URL: Issues, https://github.com/argorixlabs/argorix-python/issues
Project-URL: Changelog, https://github.com/argorixlabs/argorix-python/blob/main/CHANGELOG.md
Keywords: argorix,ai,sdk,guardrails,security,ai-governance
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Operating System :: OS Independent
Classifier: Topic :: Security
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# Argorix SDK for Python

SDK oficial de Python para integrar aplicaciones de IA con el **Argorix Guardrails Runtime**.

```bash
pip install argorix-guardrails
```

> **Rebranding.** Este paquete se llamaba `governanceai`. El nombre `governanceai` sigue
> publicado como shim de compatibilidad (depende de `argorix-guardrails` y lo reexporta), pero ya no
> recibe features. Ver [Migración desde `governanceai`](#migración-desde-governanceai).

## API cubierta

| Endpoint | Método del SDK |
| --- | --- |
| `POST /v1/guardrails/install` | `install()` |
| `POST /v1/guardrails/heartbeat` | `heartbeat()` |
| `POST /v1/guardrails/evaluate` | `evaluate()` (alias: `apply()`) |
| `POST /v1/guardrails/evaluate/stream` | `evaluate_stream()`, `evaluate_streamed_decision()` |
| `POST /v1/guardrails/events` | `record_event()`, `report_redteam_probe()` |

Los guardrails de agentes (`/v1/agent-guardrails/runtime/*`) viven en el paquete
[`argorix-guardrails-agent`](../python-agents/README.md).

`base_url` acepta tanto `https://api.argorix.com` como `https://api.argorix.com/v1`: el
sufijo `/v1` se normaliza para no duplicar el prefijo.

## Autenticación

- `app_number` en el body de cada request
- `Authorization: Bearer <APP_API_KEY>` en cada header

Ambos valores salen de `Application Settings > API Keys` en la consola.

## Quick start

```python
from argorix import ArgorixClient, ArgorixError

client = ArgorixClient(
    base_url="https://api.argorix.com",
    app_number=123456,
    app_api_key="ax_live_replace_me",
    timeout_seconds=10,
    max_retries=2,
)

try:
    state = client.install(mode="monitor", metadata={"environment": "production"})
    print(state.mode, state.selected_validators)

    decision = client.evaluate("Summarize this support ticket", stage="input")
    print(decision.allowed, decision.findings, decision.selected_validators)
except ArgorixError as exc:
    print(exc.status_code, exc)
```

### Configuración por entorno

```python
client = ArgorixClient.from_env()
```

| Variable | Uso | Fallback legado |
| --- | --- | --- |
| `ARGORIX_API_URL` | `base_url` | `ARGORIX_BASE_URL`, `GOVERNANCE_AI_URL` |
| `ARGORIX_APP_NUMBER` | `app_number` | `APP_NUMBER` |
| `ARGORIX_APP_API_KEY` | `app_api_key` | `APP_API_KEY` |
| `ARGORIX_POLICY_ID` | `default_policy_id` | — |

Los argumentos explícitos siempre ganan sobre el entorno.

## Flujo runtime clásico

```python
decision_in = client.evaluate(user_prompt, stage="input")
if decision_in.blocked:
    raise RuntimeError(decision_in.findings)

model_reply = llm.invoke(user_prompt)

decision_out = client.evaluate(model_reply, stage="output")
if decision_out.blocked:
    raise RuntimeError(decision_out.findings)
```

### Tool calls

```python
decision = client.evaluate(
    "Open the customer export",
    stage="tool",
    tool_calls=[
        {"tool_name": "browser.fetch", "url": "https://example.com/private-report"}
    ],
)
```

Si el dominio no está permitido por la configuración de la aplicación, el backend puede
responder bloqueando la operación.

## Streaming (SSE)

`evaluate_stream()` consume `POST /v1/guardrails/evaluate/stream` y emite los eventos
`start`, `result`, `end` — o `error` si la evaluación falla en el servidor.

```python
for event in client.evaluate_stream(user_prompt, stage="input"):
    if event.event == "result":
        print("allowed:", event.data["allowed"])
    elif event.event == "error":
        print("guardrail error:", event.data["detail"])
```

Si solo te interesa la decisión final:

```python
decision = client.evaluate_streamed_decision(user_prompt, stage="input")
```

Levanta `ArgorixError` si el servidor emite `error` o si el stream cierra sin `result`.
El stream es perezoso: no se envía nada hasta que empiezas a iterar. Los reintentos
cubren la conexión y el status inicial; una vez abierto el stream no se reintenta.

## Modelos de respuesta

`evaluate()` devuelve `GuardrailsDecision`:

| Campo | Tipo |
| --- | --- |
| `allowed` / `blocked` | `bool` |
| `output_text` | `str` |
| `mode` | `"monitor"` \| `"enforce"` |
| `findings` | `list[GuardrailsFinding]` |
| `evaluations` | `list[GuardrailsEvaluation]` |
| `selected_validators` | `list[str]` |
| `effective_scope`, `guardrails_config` | `dict` |
| `guardrails_engine`, `stage`, `application_id`, `app_number`, `repository`, `server_time` | metadatos del control plane |
| `highest_severity` | severidad máxima entre los findings |
| `raw` | payload JSON sin tocar |

`install()` y `heartbeat()` devuelven `GuardrailsState` (`application_id`, `app_number`,
`repository`, `installation_connected`, `guardrails_config`, `effective_scope`,
`selected_validators`, `mode`, `enabled`, `raw`).

Ambos objetos aceptan acceso tipo diccionario (`decision["repository"]`,
`state.get("app_number")`) que lee directo de `raw`, así que campos nuevos del control
plane quedan accesibles sin actualizar el SDK.

## Telemetría

El cliente acumula `requests_total`, `blocked_total` y `avg_latency_ms`, y los adjunta a
`evaluate()` y `heartbeat()` salvo que pases `include_telemetry=False`.

```python
print(client.telemetry)
client.reset_telemetry()
```

## Errores, timeout y retry

`ArgorixClient` expone `timeout_seconds`, `max_retries`, `retry_backoff_seconds` y
`retry_status_codes`. Los errores levantan `ArgorixError` con `status_code` y
`response_body`. Se reintentan errores de red y respuestas `408`, `429`, `500`, `502`,
`503`, `504` con backoff exponencial.

## Cómo se refleja en la consola

Los eventos y evaluaciones de este SDK alimentan `AI Applications`, `Guardrails Log`,
`Risk & Governance` y `AI Compliance`. En la consola:

- `AI Applications`: inventario resumido
- `AI Application Profile`: postura, evidencia y modelos/tools
- `Application Settings`: `Installation`, `API Keys`, `Guardrails`
- `AI Workbench`: validación de prompts y matriz TRUE/FALSE por control

## AI-BOM CLI

```bash
argorix-bom --base-url https://api.argorix.com --cookie "argorix_session=..." generate --application-id travel-assistant --force
argorix-bom --base-url https://api.argorix.com --cookie "argorix_session=..." export --document-id bom-123 --format cyclonedx --output ai-bom.json
argorix-bom --base-url https://api.argorix.com --cookie "argorix_session=..." scan ./my-agent-repo --application-id my-agent-repo
argorix-bom --base-url https://api.argorix.com --cookie "argorix_session=..." scan ./my-agent-repo --format cyclonedx --output ai-bom-cyclonedx.json
argorix-bom --base-url https://api.argorix.com --cookie "argorix_session=..." scan ./my-agent-repo --watch --interval-seconds 3
```

Formatos: `cyclonedx`, `spdx`, `sarif`, `markdown`, `html`.

El flujo `scan` ejecuta `POST /v1/scans/local`, refresca el AI-BOM activo con
`POST /v1/ai-bom/applications/{application_id}/generate` y opcionalmente exporta el
documento. Sin `--application-id`, la CLI infiere un slug desde el nombre de la carpeta.
En `--watch` no vuelve a pegarle al backend hasta detectar un cambio local.

Credencial: `--cookie "argorix_session=..."`, `ARGORIX_SESSION_COOKIE`, o el legado
`GOVERNANCEAI_SESSION_COOKIE`. Sigue siendo cookie de sesión del control-plane; migrarla
a un token específico queda pendiente.

## Migración desde `governanceai`

```bash
pip uninstall governanceai
pip install argorix-guardrails
```

| Antes | Ahora |
| --- | --- |
| `from governanceai import GovernanceAIClient` | `from argorix import ArgorixClient` |
| `GovernanceAIError` | `ArgorixError` |
| `client.apply(...)` | `client.evaluate(...)` (`apply` sigue funcionando) |
| `governanceai-bom` | `argorix-bom` |
| `GOVERNANCEAI_SESSION_COOKIE` | `ARGORIX_SESSION_COOKIE` |

Los nombres viejos siguen exportados desde `argorix` como alias, así que un cambio de
import alcanza para arrancar. Cambios de comportamiento a revisar:

- `install()` y `heartbeat()` devuelven `GuardrailsState` en vez de `dict`. El acceso por
  clave sigue funcionando (`state["application_id"]`).
- `decision.findings` ahora son dataclasses `GuardrailsFinding`. `finding["severity"]`
  sigue funcionando; `finding.severity` es la forma recomendada.

## Desarrollo

```bash
pip install -e ./sdk/python
python -m pytest ./sdk/python/tests
python -m build ./sdk/python
```

## Semver y changelog

- Versión actual: `0.2.0`
- Historial: [`CHANGELOG.md`](./CHANGELOG.md)
- Licencia: [`LICENSE`](./LICENSE)

## Referencias

- [`sdk/README.md`](../README.md)
- [`sdk/javascript/README.md`](../javascript/README.md)
- [`sdk/python-agents/README.md`](../python-agents/README.md)
- [`example_usage.py`](./example_usage.py)
