tokentoll

Escanea bases de código en busca de llamadas a la API de LLM y estima los costos mensuales. Compara costos entre referencias de git para detectar regresiones de costos durante la revisión de código.

Documentación

tokentoll

Evita regresiones de costos de LLM antes de producción.

CI PyPI version GitHub Marketplace License: MIT Python 3.10+ tokentoll MCP server

tokentoll es una puerta de CI para el costo de LLM. Analiza estáticamente Python, JavaScript y TypeScript en busca de llamadas a la API de LLM, evalúa cada pull request contra una política que tú controlas y publica un veredicto de PASS/WARN/FAIL directamente en el PR. Opcionalmente, hace fallar el flujo de trabajo cuando se viola la política, de modo que las regresiones de costos no puedan fusionarse.

tokentoll demo

Demo en vivo

Jwrede/tokentoll-demo es una pequeña aplicación LLM políglota (Python + TypeScript) conectada a la puerta de costos de tokentoll. Ya hay dos PRs abiertos contra ella:

Abre la pestaña de conversación de cada PR para ver el comentario de veredicto que tokentoll realmente publica.

El comentario de veredicto

Cuando un PR viola tu política, tokentoll comenta con un veredicto y una lista de hallazgos bloqueantes, luego sale con código distinto de cero para que la verificación falle. Ejemplo:

## tokentoll verdict: FAIL

**Blocking findings (2):**

- `src/agent.py:42` - per-call cost grew 15.0x (threshold 5x)
- total monthly delta +$812.00 exceeds budget $250.00

> Required action: revert the regression, raise the threshold in `.tokentoll.yml`, or add an exemption.

Cuando el PR está limpio, el veredicto es PASS y el comentario muestra solo la tabla de delta de costos. Cuando no hay política configurada, tokentoll publica un comentario informativo de delta sin veredicto.

Inicio rápido (60 segundos)

Añade .github/workflows/tokentoll.yml:

name: tokentoll
on:
  pull_request:
    paths:
      - "**.py"
      - "**.ts"
      - "**.tsx"
      - "**.js"
      - "**.jsx"

permissions:
  contents: read
  pull-requests: write

jobs:
  cost-gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: Jwrede/tokentoll@v0.7.0
        with:
          fail-on-policy-violation: true

Luego añade .tokentoll.yml a la raíz de tu repositorio:

budgets:
  max_monthly_delta_usd: 250
  max_callsite_monthly_usd: 100
  max_relative_increase: 5.0

policies:
  block_unknown_models: true
  fail_on_policy_violation: true

Los PRs futuros reciben un comentario de veredicto. Los PRs que superen los umbrales hacen fallar el flujo de trabajo.

Para instalaciones con pin de SHA y configuraciones de permisos mínimos, consulta docs/github-action.md. Para el esquema completo de política, consulta docs/policy.md. Para la postura de seguridad, consulta docs/security.md.

Qué detecta

Python

SDKPatrones
OpenAIchat.completions.create, responses.create
Anthropicmessages.create, messages.stream
Google GenAImodels.generate_content
LiteLLMcompletion, acompletion
LangChainChatOpenAI, ChatAnthropic, init_chat_model
Zhipu AIZhipuAiClient, ZhipuAI (modelos GLM)

JavaScript / TypeScript (analizado mediante tree-sitter, maneja .js, .jsx, .ts, .tsx)

SDKPatrones
OpenAI Node SDKclient.chat.completions.create, client.responses.create, client.embeddings.create
Anthropic SDKclient.messages.create, client.messages.stream
Vercel AI SDKgenerateText, streamText, generateObject, streamObject, embed, embedMany
LangChain.jsnew ChatOpenAI, new ChatAnthropic, new ChatGoogleGenerativeAI, ...
Compatible con OpenAImisma forma que OpenAI Node SDK, detectado automáticamente

Reglas de política

El bloque de política en .tokentoll.yml controla cuándo falla un PR:

ReglaDisparador
budgets.max_monthly_delta_usdel delta mensual total estimado supera el umbral
budgets.max_callsite_monthly_usdcualquier punto de llamada nuevo o modificado supera el umbral
budgets.max_relative_increaseel costo por llamada de cualquier punto de llamada modificado crece más que este multiplicador
policies.block_unknown_modelscualquier punto de llamada nuevo o modificado usa un modelo sin precio o sin resolver
policies.fail_on_policy_violationtokentoll diff sale con 1 en FAIL (comportamiento de puerta de CI)

Cada regla es independiente. Deja un campo sin configurar para deshabilitar esa regla. Referencia completa en docs/policy.md.

CLI

pip install tokentoll

# Scan current directory for LLM API calls and their costs
tokentoll scan .

# Show cost impact of your last commit
tokentoll diff HEAD~1

# Compare two refs and fail on policy violation
tokentoll diff main..HEAD --fail-on-policy-violation

Subcomandos:

tokentoll scan [PATH...] [--format table|json|markdown] [--calls-per-month N] [--config PATH]
tokentoll diff [REF] [--base REF] [--head REF] [--format table|json|markdown|github-comment]
               [--config PATH] [--fail-on-policy-violation]
tokentoll update    # refresh bundled pricing data from LiteLLM

Configuración

.tokentoll.yml vive en la raíz del repositorio y se descubre automáticamente. Más allá del bloque de política:

# Per-SDK defaults for dynamic (runtime-resolved) model names
default_models:
  openai: gpt-4o-mini
  anthropic: claude-haiku-3-20240307

# Assumed monthly call volume per call site (used for dollar estimates)
calls_per_month: 5000

# Skip cost estimation for dynamic models entirely.
# Default false: dynamic calls are priced against the per-SDK default.
skip_dynamic_models: false

# Default excludes (tests/, examples/, docs/, cookbook/, benchmarks/, evals/,
# scripts/, notebooks/) are applied automatically. Opt out with:
use_default_excludes: false

# Additional excludes (prefix or glob)
exclude:
  - "*_test.py"
  - vendor/

# Per-path overrides (longest prefix match)
overrides:
  - path: src/agents/
    default_model: gpt-4o
    calls_per_month: 10000
  - path: src/azure/
    skip_dynamic_models: true

Orden de resolución para valores predeterminados dinámicos de modelos: default_models (por SDK) > default_model (genérico) > valores predeterminados integrados del SDK.

Seguridad

tokentoll no requiere claves de API, no envía telemetría y se ejecuta completamente dentro de tu entorno de CI. Los datos de precios se incluyen con el paquete y se actualizan desde LiteLLM bajo demanda. Para el conjunto de permisos recomendado, el pin de SHA y el riesgo de PR de fork, consulta docs/security.md.

Servidor MCP

tokentoll MCP server

tokentoll incluye un servidor MCP (Model Context Protocol) para que Claude Code y otros hosts MCP puedan verificar el impacto en costos de los cambios de código LLM desde dentro de una conversación de agente:

pip install tokentoll[mcp]
claude mcp add --transport stdio tokentoll -- tokentoll-mcp

Se exponen dos herramientas: scan (estimar costos en una ruta) y diff (comparar dos refs). Ambas devuelven JSON.

Cómo funciona

  Source code (.py, .ts, .tsx, .js, .jsx)
        |
        v
  +----------------+   +------------------+
  | AST scanners   |-->| SDK detectors    |
  | ast (Python) + |   | OpenAI, Anthropic|
  | tree-sitter    |   | Google, LiteLLM, |
  | (JS/TS)        |   | LangChain, Zhipu,|
  +----------------+   | Vercel AI SDK    |
                       +------------------+
                              |
                              v
                       +------------------+
                       | Pricing engine   |
                       | 2200+ models     |
                       +------------------+
                              |
                              v
                       +------------------+
                       | Diff engine      |
                       | (old vs new)     |
                       +------------------+
                              |
                              v
                       +------------------+
                       | Policy evaluator |
                       | PASS/WARN/FAIL   |
                       +------------------+
                              |
                              v
                       +------------------+
                       | PR comment / CLI |
                       | output           |
                       +------------------+

Un motor de propagación constante de múltiples pasadas resuelve nombres de modelos a través de asignaciones de variables, respaldos de os.getenv() / process.env.X, valores predeterminados de funciones, atributos de clases, argumentos de constructores, literales de diccionarios y objetos, desempaquetado de **kwargs y envoltorios de proveedores de Vercel AI SDK (openai("gpt-4o")), de modo que el código del mundo real con indirección aún produzca estimaciones útiles.

Datos de precios

Los precios están incluidos y funcionan sin conexión. Para actualizar desde LiteLLM:

tokentoll update

Cobertura: más de 300 modelos en OpenAI, Anthropic, Google, AWS Bedrock, Azure y más, además de más de 2200 entradas del catálogo combinado de LiteLLM.

Limitaciones

  • Solo análisis estático. Los modelos cargados desde bases de datos o configuración remota no se pueden resolver; tokentoll recurre al valor predeterminado configurado por SDK y marca el punto de llamada como (default).
  • Las estimaciones de tokens usan una heurística de caracteres/4 a menos que tiktoken esté instalado (pip install tokentoll[tiktoken]).
  • Las estimaciones mensuales asumen un volumen de llamadas uniforme por punto de llamada. Anula por proyecto con calls_per_month o por ruta con overrides.
  • La resolución JS/TS es solo dentro del mismo archivo. Importar un nombre de modelo desde otro módulo produce un punto de llamada dinámico en lugar de un valor resuelto.

Hoja de ruta

  • v0.9: Repositorio de demostración público con un PR que falla conocido, estudio de caso de gpt-researcher, sección de adopción ampliada
  • Futuro: Inferencia de frecuencia de llamadas consciente del contexto (rutas FastAPI frente a scripts frente a bucles); resolución de importaciones entre archivos para JS/TS

Licencia

MIT