Metadata-Version: 2.4
Name: treval
Version: 0.2.0
Summary: Traza, evalúa y mejora agentes de IA desde la terminal
Author: Treval Contributors
License: MIT
Project-URL: Homepage, https://github.com/amorfeu86/treval
Project-URL: Repository, https://github.com/amorfeu86/treval
Project-URL: Documentation, https://treval.dev
Keywords: ai,agents,observability,tracing,evaluation,llm,monitoring
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: openai>=1.0.0
Requires-Dist: rich>=13.0.0

# treval ⚡

<p align="center">
  <picture>
    <img alt="treval logo" src="treval_logo_2.png" width="200" height="200">
  </picture>
</p>

> Traza, evalúa y mejora agentes de IA desde la terminal.

Treval es un framework de observabilidad y evaluación para agentes de IA. Con una línea (`import treval; treval.instrument()`) obtienes trazado completo de cada llamada LLM, tool y operación. Además: evaluación LLM-as-judge, comparación multi-modelo con estadísticas, costes desde API, replay de spans, tests nativos para agentes, dashboard web, exportación OpenTelemetry y reportes HTML standalone.

---

## Instalación

```bash
git clone <tu-repo>
cd treval
python -m venv .venv
source .venv/bin/activate
pip install -e .

**Dependencias:** `openai`, `rich` (el resto son stdlib de Python 3.11+).

Necesitas una API key de [OpenRouter](https://openrouter.ai/keys) (o de OpenAI si usas OpenAI directo).

```bash
# En tu ~/.bashrc o antes de ejecutar treval
export OPENROUTER_API_KEY=sk-or-v1-...
```

```bash
# Verificar instalación
treval --help           # 15 comandos disponibles
treval prices           # Precios actualizados de OpenRouter
```

---

## Trazado básico

### Auto-instrumentación (una línea)

```python
import treval

treval.instrument()   # Parchea OpenAI sync/async → spans LLM automáticos

# A partir de aquí, TODAS las llamadas a OpenAI se trazan solas
```

### Decorador @agent

```python
from treval import agent, operation, tool

@agent(name="WeatherBot")
class WeatherAgent:
    def __init__(self, api_key: str):
        from openai import OpenAI
        # OpenRouter como provider por defecto
        self.client = OpenAI(api_key=api_key, base_url="https://openrouter.ai/api/v1")

    @operation
    def get_forecast(self, city: str) -> str:
        """Cada llamada @operation se registra como span hijo del agente."""
        return self._call_llm(f"clima en {city}")

    @operation(name="call_llm")
    def _call_llm(self, prompt: str) -> str:
        """Las llamadas LLM via OpenAI se trazan solas si llamaste instrument()."""
        resp = self.client.chat.completions.create(
            model="deepseek/deepseek-v4-flash",
            messages=[{"role": "user", "content": prompt}],
        )
        return resp.choices[0].message.content
```

### Decorador @tool

```python
@tool(name="get_weather")
def get_weather(city: str) -> str:
    """Cada tool se registra como span TOOL."""
    return f"28°C, soleado en {city}"
```

### Ver spans

```bash
treval spans                # Lista los 20 spans más recientes
treval spans -t LLM         # Solo spans LLM
treval spans -l 50          # 50 spans
treval span 42              # Detalle completo de un span (input, output, hijos)
treval metrics              # Métricas agregadas por tipo
treval count                # Total de spans almacenados
treval clear                # Borra todos los spans
```

Los spans tienen 4 tipos, representados como badges de colores en el dashboard:

| Tipo | Color | Significado |
|------|-------|-------------|
| **AGENT** | 🔵 Azul | Instancia completa de un agente |
| **OPERATION** | 🟢 Verde | Operación dentro del agente |
| **TOOL** | 🟡 Amarillo | Tool o función ejecutada |
| **LLM** | 🟣 Púrpura | Llamada a modelo de lenguaje |

Los spans se organizan en jerarquía padre → hijo automáticamente mediante `parent_id`.

---

## Evaluación LLM-as-judge

```bash
# Evaluar spans recientes con DeepSeek como juez
treval eval                             # Default: correctness
treval eval -c conciseness              # Concisión
treval eval -c helpfulness              # Utilidad
treval eval -t LLM -c correctness       # Solo spans LLM
treval evals                            # Historial de evaluaciones
```

También desde Python:

```python
from treval import LLMEvaluator, EvalStore

evaluator = LLMEvaluator(
    model="deepseek/deepseek-v4-flash",
    criteria="La respuesta debe ser correcta y útil",
)
results = evaluator.evaluate(spans)

store = EvalStore()
store.save(results[0])
stats = store.get_stats()  # media, min, max
```

El juez usa un parser JSON tolerante que maneja JSON mal formado (strings sin cerrar, markdown, texto extra). Si falla, reintenta automáticamente hasta 2 veces.

---

## Comparación de modelos (`treval compare`)

Compara **N modelos** sobre el **mismo prompt**, cada uno ejecutado **M veces**, con estadísticas (media σ) y costes reales desde la API de OpenRouter.

```bash
# 2 modelos, 3 ejecuciones cada uno
treval compare \
  -p "Explica la diferencia entre CNN y Transformer" \
  -m deepseek/deepseek-v4-flash,deepseek/deepseek-v4-pro \
  -r 3

# 4 modelos, 5 ejecuciones, exportar a HTML
treval compare \
  -p "¿qué es el fine-tuning?" \
  -m deepseek/deepseek-v4-flash,deepseek/deepseek-v4-pro,anthropic/claude-sonnet-4,xiaomi/mimo-v2.5-pro \
  -r 5 \
  -o comparacion.html

# Con criterio personalizado
treval compare -p "resume esto" -m m1,m2 -c conciseness
```

**Output en terminal:** tabla con #, modelo, score medio, σ, duración, coste/ejec, tokens, runs. Ganador marcado con 🏆.

**HTML exportado** incluye:
- Banner del ganador con score
- Tabla resumen ordenable
- Detalle por modelo con cada run individual
- Output expandible por run
- **Árbol de trazas** (modo agente): jerarquía completa de spans con tipos coloreados

### Modo agente

Compara ejecuciones completas de un script de agente que esté instrumentado con treval:

```bash
treval compare --agent "python mi_agente.py 'pregunta'" -r 5 -o agentes.html
```

Cada ejecución:
1. Corre el script como subprocess
2. Captura stdout (como output)
3. Lee los spans nuevos que el agente guardó en la BD
4. Evalúa el output con LLM-as-judge
5. Renderiza el **árbol jerárquico de trazas** en el HTML

---

## Replay (`treval replay`)

Re-ejecuta un span guardado cambiando modelo, temperatura o input:

```bash
treval replay 42                          # Re-ejecutar con mismos params
treval replay 42 --model anthropic/claude-sonnet-4  # Cambiar modelo
treval replay 42 --input "nueva pregunta"            # Cambiar input
treval replay 42 --temperature 0.5                   # Cambiar temperatura
```

Muestra tabla comparativa: output original vs nuevo, duración, y uso de tokens.

---

## Testing de agentes

Define tests para agentes usando LLM-as-judge:

```python
# tests/test_mi_agente.py
from treval.testing import case, TestSuite

suite = TestSuite(name="WeatherTests")

@case(suite,
      input="qué clima hace en Madrid?",
      criteria="La respuesta debe mencionar el clima de Madrid")
def test_madrid(response: str) -> None:
    assert "Madrid" in response
    assert "28" in response or "soleado" in response
```

```bash
treval test run tests/test_mi_agente.py
```

Cada test ejecuta el agente, evalúa el output con LLM-as-judge, y muestra ✅/❌ con score y razón.

---

## Dashboard

```bash
treval dashboard                     # Servidor web en http://127.0.0.1:8080
treval dashboard --port 3000         # Puerto personalizado
treval dashboard --no-open           # Sin abrir navegador
treval dashboard --export reporte.html  # HTML standalone (funciona desde file://)
```

El dashboard exportado es 100% standalone (sin servidor), responsive, con:
- Stats (total, agentes, operaciones, tools, LLMs, errores)
- Tabla ordenable por cualquier columna
- Panel de detalle con input/output y jerarquía de hijos
- Barras de duración codificadas por color
- Leyenda de tipos de span
- Diseño dark mode mobile-friendly

---

## Gateway proxy

Intercepta tráfico LLM para trazarlo sin modificar código:

```bash
treval gateway                       # Proxy en :9090 → OpenRouter
treval gateway --port 9090 --upstream openai   # → OpenAI
```

Útil para agentes que no puedes modificar: apunta sus llamadas al gateway y treval registra todo.

---

## Exportación OpenTelemetry

```bash
treval export --console              # Exporta spans a consola (formato OTEL)
treval export --endpoint http://localhost:4317  # Envía a collector OTEL
```

---

## Comparación A/B (legacy)

```bash
treval ab "mi pregunta" --model-a flash --model-b pro
```

Comparación simple de 2 modelos sobre el mismo input. Recomendado usar `treval compare` para 2+ modelos con estadísticas.

---

## Precios en tiempo real (`treval prices`)

Obtiene los precios actualizados de OpenRouter API automáticamente, sin hardcode:

```bash
treval prices                          # Todos los modelos disponibles
treval prices --search flash           # Filtra por nombre
treval prices --search deepseek        # Solo modelos DeepSeek
treval prices --search xiaomi          # Solo Xiaomi MiMo
```

Los precios se cachean 1 hora en memoria. Si la API no responde, se usa un fallback local con ~20 modelos comunes. Los costes en `treval compare` usan estos precios automáticamente.

---

## API pública (Python)

```python
import treval

# Decoradores
treval.instrument()               # Auto-instrumentación OpenAI
treval.agent                      # @treval.agent — marca una clase como agente
treval.operation                  # @treval.operation — marca un método como operación
treval.tool                       # @treval.tool — marca una función como tool
treval.wrap(client)               # Envuelve un cliente OpenAI ya existente
treval.wrap_anthropic(client)     # Envuelve un cliente Anthropic ya existente

# Evaluación
treval.LLMEvaluator               # Evaluador LLM-as-judge
treval.EvalStore                  # Almacén de evaluaciones en SQLite

# Callbacks
treval.trace                      # Callback de trazado
treval.on_tool_start / on_tool_end
treval.on_llm_start / on_llm_end

# Comparación (desde Python)
from treval.compare import compare_models, compare_agents, build_report_html
results = compare_models(prompt="...", models=["m1", "m2"], runs=3)
html = build_report_html(results, prompt="...", criteria="correctness")
```

---

## Demo: Agente ReAct

```bash
export OPENROUTER_API_KEY=sk-or-...
cd py
python demo_react.py "qué clima hace en Madrid?"
python demo_react.py "3 * 7 + 12"
python demo_react.py "cuál es la capital de España?"
```

Demo funcional de un agente ReAct con 3 tools (clima, calculadora, búsqueda) instrumentado con treval. Después de ejecutarlo:

```bash
treval spans         # Ver todos los spans generados
treval span 1        # Detalle del agente
treval eval          # Evaluar con LLM-as-judge
```

---

## Comandos (13)

| Comando | Descripción |
|---------|-------------|
| `treval spans` | Lista spans recientes (filtro por tipo) |
| `treval span <id>` | Detalle de un span con hijos |
| `treval count` | Total de spans almacenados |
| `treval clear` | Borra todos los spans |
| `treval eval` | Evalúa spans con LLM-as-judge |
| `treval evals` | Historial de evaluaciones |
| `treval compare` | Compara N modelos × M ejecuciones |
| `treval ab` | Comparación A/B simple (legacy) |
| `treval replay <id>` | Re-ejecuta un span con nuevos params |
| `treval test run <file>` | Ejecuta tests de agente |
| `treval dashboard` | Dashboard web / export HTML |
| `treval metrics` | Métricas agregadas |
| `treval prices` | Precios de OpenRouter API |
| `treval export` | Exporta spans a OTEL |
| `treval gateway` | Proxy para interceptar tráfico LLM |

---

## Almacenamiento

Todo se guarda localmente en `~/.treval/`:

```
~/.treval/
├── spans.db       # Trazas (spans con jerarquía padre→hijo)
└── evals.db       # Evaluaciones LLM-as-judge
```

SQLite, thread-safe, sin servidor. Puedes borrar los archivos en cualquier momento o usar `treval clear` (solo borra spans; las evaluaciones están en `evals.db` aparte).

---

## Arquitectura

```
treval/
├── py/
│   ├── treval/
│   │   ├── __init__.py    # API pública (decoradores + instrument + eval)
│   │   ├── agent.py       # @agent — decorador para clases agente
│   │   ├── operation.py   # @operation — decorador para métodos
│   │   ├── tool.py        # @tool — decorador para funciones
│   │   ├── instrument.py  # Auto-instrumentación OpenAI sync/async
│   │   ├── wrap.py        # Wrappers para clientes existentes
│   │   ├── context.py     # Stack thread-local de span_ids
│   │   ├── db.py          # SQLite local (~/.treval/spans.db)
│   │   ├── eval.py        # LLM-as-judge (parser JSON tolerante) + EvalStore
│   │   ├── compare.py     # Comparación multi-modelo + agente + HTML report
│   │   ├── replay.py      # Re-ejecutar spans con params modificados
│   │   ├── testing.py     # TestRunner nativo con @case y TestSuite
│   │   ├── callbacks.py   # Callbacks de trazado (LangChain compatible)
│   │   ├── otel.py        # Exportador OpenTelemetry
│   │   ├── gateway.py     # Proxy HTTP para interceptar tráfico LLM
│   │   ├── dashboard.py   # Dashboard web + export HTML standalone
│   │   └── cli.py         # CLI con Rich (13 comandos)
│   ├── tests/             # 88 tests, todos pasando
│   └── demo_react.py      # Demo: agente ReAct funcional con 3 tools
├── ts/                    # Esqueleto TypeScript (futuro)
└── pyproject.toml         # Configuración del paquete
```

### Flujo de datos

```
LLM call
  │
  ├─ instrument() parchea OpenAI → span LLM guardado en SpanStore
  ├─ @agent / @operation / @tool → span AGENT/OPERATION/TOOL
  │
  ▼
SpanStore (SQLite) ─→ CLI (treval spans / span / metrics)
                  ─→ Dashboard (localhost:8080 o HTML standalone)
                  ─→ LLM-as-judge → EvalStore
                  ─→ compare_models() → HTML report con stats y costes
                  ─→ OTEL export (console o collector)
                  ─→ Replay (re-ejecutar con nuevos params)
```

---

## Tests

```bash
cd py
python -m pytest tests/ -v
```

**88 tests**, todos pasando. Desarrollo con TDD estricto: cada feature nueva empieza con un test en ROJO, luego implementación en VERDE, luego refactor.

Cobertura: decoradores (`@agent`, `@operation`, `@tool`), auto-instrumentación, almacenamiento, evaluación, comparación (modelos + agente + precios API), replay, testing, generación HTML, parser JSON tolerante.

---

## Licencia

MIT
