Skip to content

feat(usage): per-request token ledger and measured bucket capacity (2.5.0) - #74

Merged
JoshRob297 merged 1 commit into
mainfrom
feat/usage-ledger
Oct 31, 2026
Merged

JoshRob297 merged 1 commit into
mainfrom
feat/usage-ledger

Conversation

@JoshRob297

Copy link
Copy Markdown
Owner

Responde a "cuanto ofrece Google por cuenta", que no tiene cifra oficial: lo mide.

Que hace

  • Libro mayor por peticion. Cada respuesta en streaming agrega una linea a antigravity-usage.jsonl con cuenta, modelo, variante y los conteos de usageMetadata (entrada, salida, razonamiento, lectura de cache). Append-only, sin prompts.
  • Snapshots de cuota. Cada antigravity-quota agrega sus porcentajes a antigravity-quota-history.jsonl.
  • Capacidad medida. Cruzando ambos: TOKENS/1%, CALLS/1% y la proporcion MOVED de ventanas donde el bucket realmente bajo.
  • Tool antigravity_usage y comando /antigravity-usage, con days (7 por defecto, tope 90).

Lo que se midio (y por que el reporte no afirma una capacidad)

Argon, 2026-10-31, tres ventanas consecutivas:

Ventana Tokens Llamadas Caida del bucket
1 10 095 2 1.0133 puntos
2 0 0 0.0000
3 14 910 2 0.0000

Dos llamadas de 32k movieron 1.01 puntos; dos llamadas de 15k no movieron nada. El consumo no es proporcional a los tokens, asi que la estimacion lineal se publica como informativa y se muestra MOVED 1/3 para que la incertidumbre sea visible. Ese es exactamente el dato que no existe en ningun lado.

Salida real:

ANTIGRAVITY TOKEN USAGE (last 7 days)
Requests: 4 | input 25.0k | output 27 | cache read 0 | total 25.0k

BUCKET CAPACITY (measured per 1% of the bucket)
ACCOUNT                    BUCKET         TOKENS/1%  CALLS/1%   MOVED EST. (linear)   BASIS
joshuaadair.hr@gmail.com   argon:weekly       10.0k      1.97     1/3        996.2k   mixed

Limites declarados

  • Solo cuenta la ruta de streaming (usageMetadata en SSE); una peticion sin streaming no se registra.
  • El snapshot lo dispara una consulta de cuota, no un temporizador: sin consultas no hay ventanas.
  • usageMetadata es lo que el backend declara por respuesta; si no lo manda, no hay fila.

Verificacion

  • npx tsc --noEmit limpio.
  • npx vitest run: 44 archivos, 1161 tests, 25 todo (+7 nuevos: clasificacion por familia, normalizacion de usage, IO del ledger, agregados, capacidad con caida real, ventana con reset cambiado sin trafico, formato del reporte).
  • npm run build y dist/ regenerado.
  • Prueba en vivo con las tres cuentas: la peticion a Argon escribio dos filas y el reporte las agrupo por cuenta y modelo.
  • Docs EN/ES con la tabla medida y la advertencia de no linealidad.

….5.0)

Google publishes no token allowance per bucket, so measure it: every streaming
response appends one JSONL row with account, model and usageMetadata, every
quota check appends its percentages, and pairing both yields tokens and calls
per percentage point.

Measured on Argon 2026-10-31: two 32k-token calls moved the bucket 1.01 points,
two 15k-token calls moved it 0.00. Consumption is not linear in tokens, so the
report shows TOKENS/1%, CALLS/1% and the MOVED ratio of windows, and labels the
linear estimate as informational instead of asserting an allowance.

Adds antigravity_usage tool and /antigravity-usage command.
@github-actions

Copy link
Copy Markdown

Automated verification

Check Result
typecheck success
tests success
build + dist success
branch clean
typecheck

> opencode-antigravity-auth@2.5.0 typecheck
> tsc --noEmit

tests

> opencode-antigravity-auth@2.5.0 test
> vitest run


�[1m�[30m�[46m RUN �[49m�[39m�[22m �[36mv5.0.5 �[39m�[90m/home/runner/work/opencode-antigravity-auth/opencode-antigravity-auth�[39m

 �[32m✓�[39m src/plugin/transform/gemini.test.ts �[2m(�[22m�[2m130 tests�[22m�[2m)�[22m�[32m 30�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/request-helpers.test.ts �[2m(�[22m�[2m152 tests�[22m�[2m)�[22m�[32m 54�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/accounts.test.ts �[2m(�[22m�[2m110 tests�[22m�[2m)�[22m�[32m 60�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/transform/claude.test.ts �[2m(�[22m�[2m67 tests�[22m�[2m)�[22m�[32m 14�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/quota.test.ts �[2m(�[22m�[2m23 tests�[22m�[2m)�[22m�[32m 47�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/request.test.ts �[2m(�[22m�[2m110 tests�[22m�[2m)�[22m�[32m 76�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/transform/cross-model-sanitizer.test.ts �[2m(�[22m�[2m28 tests�[22m�[2m)�[22m�[32m 9�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/rotation.test.ts �[2m(�[22m�[2m59 tests�[22m�[2m)�[22m�[32m 43�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/transform/model-resolver.test.ts �[2m(�[22m�[2m55 tests�[22m�[2m)�[22m�[32m 15�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/storage.test.ts �[2m(�[22m�[2m22 tests�[22m�[2m)�[22m�[32m 17�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/config/updater.test.ts �[2m(�[22m�[2m18 tests�[22m�[2m)�[22m�[32m 64�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/cross-model-integration.test.ts �[2m(�[22m�[2m14 tests�[22m�[2m)�[22m�[32m 8�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/persist-account-pool.test.ts �[2m(�[22m�[2m38 tests�[22m�[2m | �[22m�[90m25 todo�[39m�[2m)�[22m�[32m 14�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/thinking-recovery.test.ts �[2m(�[22m�[2m29 tests�[22m�[2m)�[22m�[32m 8�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/stores/signature-store.test.ts �[2m(�[22m�[2m30 tests�[22m�[2m)�[22m�[32m 11�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/config/model-discovery.test.ts �[2m(�[22m�[2m44 tests�[22m�[2m)�[22m�[32m 10�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/cache.test.ts �[2m(�[22m�[2m25 tests�[22m�[2m)�[22m�[32m 13�[2mms�[22m�[39m
 �[32m✓�[39m src/hooks/auto-update-checker/index.test.ts �[2m(�[22m�[2m11 tests�[22m�[2m)�[22m�[32m 18�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/antigravity-first-fallback.test.ts �[2m(�[22m�[2m8 tests�[22m�[2m)�[22m�[32m 12�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/usage-ledger.test.ts �[2m(�[22m�[2m7 tests�[22m�[2m)�[22m�[32m 11�[2mms�[22m�[39m
 �[32m✓�[39m src/v2/adapter.test.ts �[2m(�[22m�[2m7 tests�[22m�[2m)�[22m�[32m 27�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/version.test.ts �[2m(�[22m�[2m15 tests�[22m�[2m)�[22m�[32m 51�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/recovery.test.ts �[2m(�[22m�[2m30 tests�[22m�[2m)�[22m�[32m 8�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/model-entitlements.test.ts �[2m(�[22m�[2m9 tests�[22m�[2m)�[22m�[32m 7�[2mms�[22m�[39m
 �[32m✓�[39m src/hooks/auto-update-checker/checker.test.ts �[2m(�[22m�[2m12 tests�[22m�[2m)�[22m�[32m 35�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/auth.test.ts �[2m(�[22m�[2m19 tests�[22m�[2m)�[22m�[32m 9�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/refresh-queue.test.ts �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[32m 6�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/quota-fallback.test.ts �[2m(�[22m�[2m10 tests�[22m�[2m)�[22m�[32m 174�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/debug.test.ts �[2m(�[22m�[2m6 tests�[22m�[2m)�[22m�[32m 20�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/search.test.ts �[2m(�[22m�[2m8 tests�[22m�[2m)�[22m�[32m 9�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/errors.test.ts �[2m(�[22m�[2m16 tests�[22m�[2m)�[22m�[32m 6�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/stats.test.ts �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[32m 57�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/safety.test.ts �[2m(�[22m�[2m5 tests�[22m�[2m)�[22m�[32m 28�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/ui/auth-menu.test.ts �[2m(�[22m�[2m12 tests�[22m�[2m)�[22m�[32m 25�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/logging-utils.test.ts �[2m(�[22m�[2m7 tests�[22m�[2m)�[22m�[32m 27�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/model-specific-quota.test.ts �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[32m 21�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/core/streaming/safety-shield.test.ts �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[32m 12�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/ui/ansi.test.ts �[2m(�[22m�[2m13 tests�[22m�[2m)�[22m�[32m 4�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/historical-pruning.test.ts �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[32m 4�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/token.test.ts �[2m(�[22m�[2m3 tests�[22m�[2m)�[22m�[32m 27�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/config/models.test.ts �[2m(�[22m�[2m5 tests�[22m�[2m)�[22m�[32m 8�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/logger.test.ts �[2m(�[22m�[2m2 tests�[22m�[2m)�[22m�[32m 17�[2mms�[22m�[39m
 �[32m✓�[39m src/plugin/config/schema.test.ts �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[32m 6�[2mms�[22m�[39m
 �[32m✓�[39m src/constants.test.ts �[2m(�[22m�[2m4 tests�[22m�[2m)�[22m�[32m 3�[2mms�[22m�[39m

�[2m Test Files �[22m �[1m�[32m44 passed�[39m�[22m�[90m (44)�[39m
�[2m      Tests �[22m �[1m�[32m1161 passed�[39m�[22m�[2m | �[22m�[90m25 todo�[39m�[90m (1186)�[39m
�[2m   Start at �[22m 16:50:08
�[2m   Duration �[22m 3.37s�[2m (import 37%, transform 34%, tests 23%, worker 6%)�[22m

�[2m    Isolate �[22m �[33m44 workers spawned�[39m�[2m · ~100ms startup each (spawn + environment, per file)�[22m
�[2m            �[22m �[2mat least ~1.37s faster with �[22m�[33misolate: false�[39m�[2m — reuses workers across files instead of one per file�[22m

build

> opencode-antigravity-auth@2.5.0 build
> tsc -p tsconfig.build.json

@JoshRob297
JoshRob297 marked this pull request as ready for review October 31, 2026 16:50
@JoshRob297
JoshRob297 merged commit a3ea1ec into main Oct 31, 2026
1 check passed
@JoshRob297
JoshRob297 deleted the feat/usage-ledger branch October 31, 2026 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant