tokentoll

Escaneia bases de código em busca de chamadas de API de LLM e estima custos mensais. Compara custos entre referências do git para detectar regressões de custo durante a revisão de código.

Documentação

tokentoll

Evite regressões de custo de LLM antes da produção.

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

tokentoll é um gate de CI para custo de LLM. Ele analisa estaticamente Python, JavaScript e TypeScript para chamadas de API de LLM, pontua cada pull request contra uma política que você controla e publica um veredito PASS/WARN/FAIL diretamente no PR. Opcionalmente, ele falha o workflow quando a política é violada, para que regressões de custo não possam ser mescladas.

tokentoll demo

Demonstração ao vivo

Jwrede/tokentoll-demo é um pequeno aplicativo LLM poliglota (Python + TypeScript) conectado ao gate de custo do tokentoll. Dois PRs já estão abertos contra ele:

Abra a aba de conversa de cada PR para ver o comentário de veredito que o tokentoll realmente publica.

O comentário de veredito

Quando um PR viola sua política, o tokentoll comenta com um veredito e uma lista de descobertas bloqueantes, e então sai com código não zero para que a verificação falhe. Exemplo:

## 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.

Quando o PR está limpo, o veredito é PASS e o comentário mostra apenas a tabela de delta de custo. Quando nenhuma política está configurada, o tokentoll publica um comentário informativo de delta sem veredito.

Início rápido (60 segundos)

Adicione .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

Em seguida, adicione .tokentoll.yml à raiz do seu repositório:

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

PRs futuros recebem um comentário de veredito. PRs que excedem os limites falham o workflow.

Para instalações com SHA fixado e configurações de permissões mínimas, veja docs/github-action.md. Para o esquema completo de política, veja docs/policy.md. Para a postura de segurança, veja docs/security.md.

O que ele detecta

Python

SDKPadrões
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 (analisado via tree-sitter, lida com .js, .jsx, .ts, .tsx)

SDKPadrões
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, ...
OpenAI-compatiblemesma forma que o OpenAI Node SDK, detectado automaticamente

Regras de política

O bloco de política em .tokentoll.yml controla quando um PR falha:

RegraGatilho
budgets.max_monthly_delta_usddelta mensal estimado total excede o limite
budgets.max_callsite_monthly_usdqualquer ponto de chamada novo ou alterado excede o limite
budgets.max_relative_increasecusto por chamada para qualquer ponto de chamada modificado cresce mais do que este multiplicador
policies.block_unknown_modelsqualquer ponto de chamada novo ou modificado usa um modelo sem preço ou não resolvido
policies.fail_on_policy_violationtokentoll diff sai com 1 em FAIL (comportamento de gate de CI)

Cada regra é independente. Deixe um campo não definido para desabilitar essa regra. Referência completa em 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

Configuração

.tokentoll.yml fica na raiz do repositório e é descoberto automaticamente. Além do bloco 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

Ordem de resolução para padrões de modelo dinâmicos: default_models (por SDK) > default_model (genérico) > padrões integrados do SDK.

Segurança

tokentoll não requer chaves de API, não envia telemetria e roda inteiramente dentro do seu ambiente de CI. Os dados de preços acompanham o pacote e são atualizados do LiteLLM sob demanda. Para o conjunto de permissões recomendado, fixação de SHA e risco de PR de fork, veja docs/security.md.

Servidor MCP

tokentoll MCP server

tokentoll inclui um servidor MCP (Model Context Protocol) para que o Claude Code e outros hosts MCP possam verificar o impacto de custo de mudanças de código LLM de dentro de uma conversa de agente:

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

Duas ferramentas são expostas: scan (estimar custos em um caminho) e diff (comparar dois refs). Ambas retornam JSON.

Como 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           |
                       +------------------+

Um mecanismo de propagação de constantes em múltiplas passagens resolve nomes de modelos através de atribuições de variáveis, fallbacks de os.getenv() / process.env.X, padrões de função, atributos de classe, argumentos de construtor, literais de dict e objeto, desempacotamento de **kwargs e wrappers de provedor do Vercel AI SDK (openai("gpt-4o")), para que código do mundo real com indireção ainda produza estimativas úteis.

Dados de preços

Os preços são incluídos e funcionam offline. Para atualizar do LiteLLM:

tokentoll update

Cobertura: mais de 300 modelos em OpenAI, Anthropic, Google, AWS Bedrock, Azure e outros, além de mais de 2200 entradas do catálogo combinado do LiteLLM.

Limitações

  • Apenas análise estática. Modelos carregados de bancos de dados ou configuração remota não podem ser resolvidos; tokentoll recorre ao padrão por SDK configurado e marca o ponto de chamada como (default).
  • As estimativas de tokens usam uma heurística de caracteres/4, a menos que tiktoken esteja instalado (pip install tokentoll[tiktoken]).
  • As estimativas mensais assumem volume de chamadas uniforme por ponto de chamada. Substitua por projeto com calls_per_month ou por caminho com overrides.
  • A resolução JS/TS é apenas no mesmo arquivo. Importar um nome de modelo de outro módulo produz um ponto de chamada dinâmico em vez de um valor resolvido.

Roadmap

  • v0.9: Repositório de demonstração público com um PR com falha conhecida, estudo de caso gpt-researcher, seção de adoção expandida
  • Futuro: Inferência de frequência de chamadas sensível ao contexto (rotas FastAPI versus scripts versus loops); resolução de importação entre arquivos para JS/TS

Licença

MIT