Token counting, model quotas, and sliding window rate limiter
Find a file
Snider 4bb1cb96d4
All checks were successful
Security Scan / security (push) Successful in 8s
Test / test (push) Successful in 1m7s
refactor(ratelimit): replace all fmt.Errorf with coreerr.E from go-log
Replace all 41 remaining fmt.Errorf calls in production code (ratelimit.go
and sqlite.go) with coreerr.E() from forge.lthn.ai/core/go-log. Promotes
go-log from indirect to direct dependency in go.mod.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-16 20:38:06 +00:00
.core chore: add .core/ build and release configs 2026-03-06 18:52:37 +00:00
.forgejo/workflows ci: add Forgejo Actions test and security scan workflows 2026-02-23 03:28:08 +00:00
docs docs: add human-friendly documentation 2026-03-11 13:02:40 +00:00
.editorconfig chore: add Go repo norms (badges, contributing, lint, taskfile, editorconfig) 2026-02-23 06:45:45 +00:00
.gitignore chore: add .core/ and .idea/ to .gitignore 2026-03-15 10:17:50 +00:00
.golangci.yml chore: add Go repo norms (badges, contributing, lint, taskfile, editorconfig) 2026-02-23 06:45:45 +00:00
CLAUDE.md docs: add CLAUDE.md project instructions 2026-03-13 13:38:02 +00:00
CONTRIBUTING.md chore: add Go repo norms (badges, contributing, lint, taskfile, editorconfig) 2026-02-23 06:45:45 +00:00
error_test.go test: add error handling and iterator coverage tests 2026-03-09 08:33:00 +00:00
go.mod refactor(ratelimit): replace all fmt.Errorf with coreerr.E from go-log 2026-03-16 20:38:06 +00:00
go.sum refactor(ratelimit): replace os.ReadFile/WriteFile/MkdirAll with go-io 2026-03-16 18:31:35 +00:00
iter_test.go test: add error handling and iterator coverage tests 2026-03-09 08:33:00 +00:00
ratelimit.go refactor(ratelimit): replace all fmt.Errorf with coreerr.E from go-log 2026-03-16 20:38:06 +00:00
ratelimit_test.go fix: improve error handling and test coverage 2026-03-09 08:30:03 +00:00
README.md chore: add Go repo norms (badges, contributing, lint, taskfile, editorconfig) 2026-02-23 06:45:45 +00:00
sqlite.go refactor(ratelimit): replace all fmt.Errorf with coreerr.E from go-log 2026-03-16 20:38:06 +00:00
sqlite_test.go feat: modernise to Go 1.26 — slices.DeleteFunc, iterators, range 2026-02-23 05:14:19 +00:00

Go Reference License: EUPL-1.2 Go Version

go-ratelimit

Provider-agnostic sliding window rate limiter for LLM API calls. Enforces requests per minute (RPM), tokens per minute (TPM), and requests per day (RPD) quotas per model using an in-memory sliding window. Ships with default quota profiles for Gemini, OpenAI, Anthropic, and a local inference provider. State persists across process restarts via YAML (single-process) or SQLite (multi-process, WAL mode). Includes a Gemini-specific token counting helper and a YAML-to-SQLite migration path.

Module: forge.lthn.ai/core/go-ratelimit Licence: EUPL-1.2 Language: Go 1.25

Quick Start

import "forge.lthn.ai/core/go-ratelimit"

// YAML backend (default, single-process)
rl, err := ratelimit.New()

// SQLite backend (multi-process)
rl, err := ratelimit.NewWithSQLite("~/.core/ratelimits.db")
defer rl.Close()

ok, reason := rl.CanSend("gemini-2.0-flash", 1500)
if ok {
    rl.RecordUsage("gemini-2.0-flash", 1500)
}

Documentation

  • Architecture — sliding window algorithm, provider quotas, YAML and SQLite backends
  • Development Guide — prerequisites, test patterns, coding standards
  • Project History — completed phases with commit hashes, known limitations

Build & Test

go test ./...
go test -race ./...
go vet ./...
go build ./...

Licence

European Union Public Licence 1.2 — see LICENCE for details.