Repository navigation
Releases: kimnt93/gorouter
Release list
v0.2.6
v0.2.5
- update router ring loop
- add select account to apply (use account)
Full Changelog: v0.2.4...v0.2.5
v0.2.4
v0.2.3
Changes
- OAuth maintenance for idle connected accounts now coordinates token refresh
across replicas (Redis) or locally and shares a lock with request-time
refresh. Grok Build has a weekly credit usage bar. - Added an imported-key Windsurf / Devin Desktop connection with a logo,
mock-tested native chat/stream translation. It is neither Devin CLI (ACP)
nor browser OAuth; no background token renewal is promised for imported keys. - Added a master-only Updates dashboard page and
GET /admin/updates/check. Checking is explicit and reads GitHub's latest
release metadata; released GHCR builds embed their version. The router
does not control the Docker daemon or replace containers: operators
pull a pinned image and recreate their existing deployment without dropping
volumes. GitHub release metadata can appear before the GHCR image is ready.
Full Changelog: v0.2.2...v0.2.3
v0.2.2
GoRouter v0.2.2 — Accounting reports and canonical-key reads
Status: development preview (0.2.2-dev), not a completed accounting release.
Date: 2026-09-14. These notes cover the implemented read-side changes since
v0.2.1. The broader accounting v0.2.2 requirements remain partially implemented;
see remaining gates and design decisions.
The runtime capability endpoint identifies this source as 0.2.2-dev. No v0.2.2
tag, GitHub release, published image or deployment is implied by these notes.
Do not infer accounting guarantees from the version string alone.
Added
GET /admin/capabilities: selected backend and explicit accounting/query
capability flags, with no secrets or request content.GET /admin/usage/report: combined totals, independent agent/model/user
grouping, and hour/day/week/month series from one bounded SQL aggregate.
Authorization and filtering occur before aggregation. Query count does not
grow with the number of selected agents.GET /admin/usage/summary?breakdown=none: one totals aggregate, preserving the
existing response fields with emptyby_modelandby_keyobjects. Omitted
breakdownretains the v0.2.1 default breakdowns.GET /admin/users/{id}/api-key: canonical-key metadata for the owner or
unrestricted master withkeys:manage. Returnskey_id,owner_id,
enabled,scopesand an opaque public-metadatarevision. No plaintext,
hash, ciphertext or key prefix is returned. Organization administration does
not authorize inspection of another user's personal key.- Dashboard Analysis → Accounting report: searchable multi-agent selection,
manual stable/deleted agent IDs, conversation filtering, agent/model/user
stacked charts and grouped totals. Legacy activity/health is a separate mode. - Typed Go/TypeScript contracts, generated Swagger, and a checked-in
synthetic report fixture.
Changed
- Canonical authentication delegates selection to backend queries instead of
materializing every user's keys in the service. Selection still includes
disabled keys and prefers personal context, then creation time and ID.
PostgreSQL and SQLite have targeted lookup indexes. ClickHouse currently uses
server-side filtering over current configuration records withFINAL; its
physical lookup optimization remains outstanding. - SQLite recent/detail/report/summary/weekly queries no longer call the
ledger-wideall()loader. Statistics do not fetch encrypted content.
Legacy health/activity computations read SQL-filtered metadata only. - SQLite timestamp ordering uses fixed-width UTC sort values, preserving
nanoseconds and avoiding variable-length RFC3339 fractional ordering errors. - Multi-select query values are normalized, deduplicated and sorted. Existing
OR-within/AND-between semantics and the 100-value selection bound remain.
Usage
Use the same canonical user key used for inference. Agent, conversation, run,
parent-run, trace and client-request IDs remain correlation—not authentication,
not a payer selector, and not inference idempotency. Supply tracking headers on
Chat Completions, Responses or Messages as documented in
usage tracking. Metadata tracking does not require content
capture; leave ENABLE_STORE_COMPLETIONS=false unless explicitly needed.
The examples below are read-only. Authenticate with a Router user key carrying
usage:read (or an authorized management session); the metadata endpoint also
requires keys:manage. Organization-wide reports require authorized organization
administration. An ordinary member's organization report stays self-scoped.
The same schemas are available through /docs.
1. Check capabilities before using accounting APIs
GET /admin/capabilitiesFor the complete production repository wiring in this development preview:
{
"version": "0.2.2-dev",
"capabilities": {
"usage_report": "gorouter-usage-report-v1",
"user_weekly_usage": "gorouter-user-usage-v1",
"totals_only": true,
"canonical_key_metadata": true,
"durable_acceptance": false,
"usage_receipts": false,
"member_allocations": false,
"atomic_credit_counters": false
}
}This fragment omits the actual response's backend and measurement fields.
Require the individual features your application needs. In particular, a report
capability is not evidence that durable receipts or admission counters exist.
2. Read lightweight conversation totals
GET /admin/usage/summary?range=all&agent_id=client-a/alpha&conversation_id=conv_1&breakdown=noneThis retains legacy completion-time semantics and all-authorized selection.
For explicit personal scope and accounting-time semantics, use the new report:
GET /admin/usage/report?scope=personal&range=30d&agent_id=client-a/alpha&conversation_id=conv_13. Query multiple agents and a stacked chart together
GET /admin/usage/report?scope=all_owned&range=30d&agent_id=client-a/alpha,client-a/beta&group_by=agent&series_by=agent&bucket=dayall_owned includes only the caller's own personal and sponsored activity. Use
personal to exclude organization-charged activity. Repeating agent_id is
also supported. Omitted selections mean all authorized values; unknown or
foreign matching filters cannot broaden access. Use stable client-namespaced
IDs to avoid collisions between applications using the same user key.
4. Inspect organization-charged usage by member
GET /admin/usage/report?scope=organization&organization_id=org_1&range=30d&group_by=user&series_by=user&bucket=dayOnly the selected organization's charged events are visible to its admin, not
members' unrelated personal usage or credentials. Existing View As context
continues to narrow authority.
5. Set exact UTC bounds or inspect canonical-key metadata
GET /admin/usage/report?scope=personal&since=2026-09-01T00:00:00Z&until=2026-09-03T00:00:00Z&time_basis=accounting&group_by=model&series_by=model&bucket=day
GET /admin/users/usr_1/api-keyReport bounds are half-open [since, until). Explicit bounds replace the
corresponding preset bounds. The default is range=24h and
time_basis=accounting; completion is available explicitly. Weeks use UTC
WEEK_START; months use calendar boundaries, not folded weekly buckets.
The key metadata revision fingerprints the returned public fields; it is not
an authentication watermark and need not change when only the secret rotates.
Interpret cost and coverage correctly
- Report token totals add four disjoint components:
input_tokens + cache_read_tokens + cache_write_tokens + output_tokens.
Reasoning subsets are not added again. - Provider cache-read ratio is
cache_read_tokens / (input_tokens + cache_read_tokens); zero denominator
means undefined. Router response-cache hits are separate. Replayed token
metadata is excluded from new report incurred-token totals, while legacy
summary behavior remains compatible. - Missing prices retain the existing Free/zero policy. Stored cost is
historical Router-priced USD, not a provider invoice; old events are not
repriced by the report. - Reports currently say
coverage.state=unknownand
freshness.state=stored_only.as_ofis query observation time, not a durable
acceptance watermark. Unknown measurement is counted explicitly. Empty or
zero-shaped results do not prove that all inference was free or settled. - Reports are uncached and must not be used as reservation authority. A report
GET followed by inference is not an atomic credit check.
Report limits: five × 366 days, 100 groups and series IDs, 2,000 time buckets,
20,000 joint aggregate/potential series cells and 16 MiB encoded output. Limit
violations return 400 usage_report_limit; service failures return 503
usage_unavailable. No rows are silently truncated. Narrow the query rather
than treating errors as zero.
See the full report usage contract for details.
Upgrade and rollback
Exactly one durable backend remains selected per process; no dual-write or
fallback store is introduced.
| Backend | Additive migration | Operational impact |
|---|---|---|
| PostgreSQL | 0031_canonical_key_lookup.sql |
Canonical owner/order index; existing transactional runner, not concurrent index creation. Plan a write-lock window proportional to key count. |
| SQLite | 004_usage_read_projections.sql |
Virtual hot fields, fixed-precision time projections and three indexes. Index creation scans retained records; JSON and content remain intact. |
| ClickHouse | None for this read slice | Existing schema supports reporting; time-first usage and FINAL configuration reads remain. |
Do not rewrite applied migrations. PostgreSQL's duplicate-0023 repair remains
in 0028; history, money, IDs and correlation are retained without guessed
owner backfills. SQLite's projections assume existing Go-written UTC records;
validate/normalize foreign offset-formatted imports before cutover.
Back up the selected store and schedule normal startup migrations through the
owner's upgrade workflow. Large-scale migration duration, index size and write
cost are not measured. v0.2.1 rollback can leave the additive columns/indexes
installed; first disable consumer use of the new endpoints. No production
migration or deployment was performed for this source change.
Verification and known limitations
- Shared populated contracts ran against real disposable PostgreSQL 17,
ClickHouse 25.8 + Redis 7.4, and file/WAL SQLite. - Live-enabled Go suite: 675 tests/subtests passed with two explicitly
excluded baseline failures, both also re...
v0.2.1
GoRouter v0.2.1 — User access, organization models and tracking
User-first aliases and assignment limits (final contract)
- One canonical key per user; agent IDs are request correlation, not principals.
- One-to-one unique aliases:
org/<org>/<alias>and<username>/<alias>. - A personal alias replaces its source in listings; both remain callable by the
owner. Recipients can call only their assigned public aliases. - Groups are bulk-assignment packages only: no group entries in
/v1/models,
no group inference route and no shared group spending limit. - Per-recipient, per-model weekly limits: 0 = unlimited (default).
Different users can have different limits on the same model. - Recipients may add a separate personal cap, never override their assigner's cap.
- Org admins and personal model owners can grant/revoke access without creating
additional user keys. Dashboard includes organization assignment packages,
personal aliases/sharing and self-limit controls. - Serialized alias/source uniqueness and durable assignment budget reservations
across PostgreSQL, ClickHouse/Redis and local SQLite.
See user model access and REST examples. The earlier
callable-group draft was replaced before deployment to the target server.
Added
X-GoRouter-Trace-Id→ persistedtrace_idon inference usage records.- Query filters for parent run and trace IDs, alongside agent, user, logical
request, run, and session/conversation IDs. - CSV and repeated-parameter multi-selection with OR within each filter and AND
across filters; omitted selections mean all authorized values. - Tracking headers documented in Swagger for Chat Completions, Responses, and
Messages, streaming and non-streaming. X-GoRouter-Request-Idresponse header exposes the accepted/generated logical
request ID. Missing trace/run/conversation IDs are not fabricated.- Integration guide: Usage tracking API.
Fixed
- PostgreSQL workload migration could be skipped because two migrations used
version 0023. A later idempotent repair migration installs missing columns. - PostgreSQL's empty/nil agent-filter predicate could exclude records; batch
agent filters could select unbound records. All backends now share filter
semantics with independent authorization constraints. - ClickHouse usage cursor comparisons now preserve subsecond precision, avoiding
skipped records at tied timestamps. - Trace and existing attribution metadata are returned consistently by usage
list/detail paths, including PostgreSQL legacy recent helpers. - Workload-bound keys cannot broaden queries to other workload namespaces.
Organization and user View As context constrain aggregation and detail reads. - Tracking header strings are owned by the request's accounting state so Fiber
buffer reuse cannot corrupt delayed streaming/queued records.
Upgrade
Apply new migrations through the normal selected-backend startup process:
PostgreSQL 0028/0029; ClickHouse 009. SQLite stores trace IDs in its existing
JSON ledger payload and requires no new column. No extra tracking flag or
prompt/completion capture is required. Existing API paths and weekly capability
marker stay compatible; see the guide for exact defaults and query examples.
Scope and limitations
This release adds tracking and filtering, not an exactly-once accounting engine
or strict agent budgets. Existing persistence/in-flight/failed-attempt accounting
limitations remain; a successful chat is not a durable accounting receipt.
The weekly endpoint now uses user/org authority; general authorized multi-agent
queries also use summary, activity, and recent APIs.
Verification and delivery
go test ./...andgo vet ./...: passed.- Race tests: handlers, usage service, entities, SQLite repositories passed.
- Shared tracking/query contract and full repository suites passed against
disposable PostgreSQL 17, ClickHouse 25.8, and real temporary SQLite.
No tests were skipped in the targeted PostgreSQL/ClickHouse repository runs. - Inference tests cover all three protocol endpoints, stream/non-stream, bound
and unbound callers, cache hits, retries, failed streams, header isolation,
generated IDs, invalid IDs, and unchanged authenticated agent/user identity. - Filter tests cover OR/AND selection, omitted filters, all seven requested
dimensions, user/organization/workload isolation, weekly filters and outage,
half-open windows, tied/subsecond cursor timestamps, and legacy metadata. - Frontend tests: 15 files, 50 tests passed; embedded SPA regenerated.
- Swagger generation/drift and
git diff --check: passed.
No production migration, real-provider quota, multi-replica HA test, release
publication, push, or deployment is included in this source change. The two
isolated test database containers were removed after verification; existing
application/database containers and their volumes were not modified.
Continued v0.2.1 user-model verification
- User-first personal/group inference, grants/revocation, duplicate-key rejection,
per-agent correlation, and no agent-ID quota bypass: unit/integration tested. - Concurrent budget and primary-key contracts: SQLite/PostgreSQL/ClickHouse.
- Two ClickHouse repository instances sharing real Redis: serialized admission
and Redis outage fail-closed behavior tested. - Desktop Chrome 1440×900: organization models/limits modal, displayed shared and
per-user limits, revocation request, no horizontal overflow or JS errors. - Frontend: 17 files / 52 tests. Go/vet/race and Swagger checks run for this update.
Final one-to-one alias clarification — verification
/v1/modelslists assigned aliases and unrenamed personal sources, never
package names. Own raw and aliased names both work; grantees cannot use raw
private sources or republish received aliases.- All three inference protocols tested streaming/non-streaming with assignment
limits, zero/unlimited, self caps, revocation, and agent-ID changes. - Shared backend tests cover concurrent alias/source uniqueness, globally
conflicting public names, separate user budgets, and adding a limit after
unlimited spend. PostgreSQL, ClickHouse and SQLite suites passed. - Final frontend: 17 test files, 52 tests; regenerated SPA and Swagger.
- Desktop browser smoke verified the assignment-package display and revoke API.
Full Changelog: v0.2.0...v0.2.1
v0.2.0
GoRouter v0.2.0 — Authoritative workload usage accounting
Overview
Adds application-neutral, authoritative Router accounting for services, agents,
workspaces, automation workers, and other workloads. GoRouter records request,
token, cache, cost, owner, workload, conversation, run, and provider-attempt
attribution without requiring prompt or completion storage.
Highlights
-
Immutable API-key workload binding with application, optional environment,
workspace, and agent identities. -
Dedicated request correlation headers for conversation, run, parent run, and
logical request IDs. -
New authoritative current-week endpoint:
GET /admin/usage/workloads/weekly
-
Capability marker:
gorouter-workload-usage-v1. -
Weekly windows follow configured
WEEK_STARTand use an exclusive period end. -
Separate accounting for input, output, provider cache-read, provider
cache-write, and GoRouter response-cache use. -
Synchronous durable handoff and idempotent persistence for workload-bound
accounting events. -
Workload, agent, conversation, run, provider, credential, and logical-request
filters on usage queries. -
PostgreSQL, ClickHouse, and SQLite schema support.
-
General integration reference:
docs/workload-usage-contract.md.
Compatibility and security
- Existing unbound API keys remain compatible and explicitly unattributed.
- Inference callers cannot assign or mutate their workload authority.
- Rotation retains workload identity and deletion does not remove history.
- Existing user and organization authorization applies before aggregation.
- No keys, tokens, prompts, completions, or raw upstream failures are exposed.
Limitations
- Weekly usage is suitable for soft admission decisions, not strict concurrent
per-workload budget enforcement. - Provider invoice totals can remain unknown when an upstream does not report
usage after failure. - Legacy unbound records retain the existing asynchronous queue behavior.
- Live PostgreSQL/ClickHouse and multi-replica HA suites require configured test
environments and were not executed for the source implementation.
Verification
go test ./...passed.go vet ./...passed.- Frontend tests passed: 15 files, 49 tests.
- Frontend build passed.
- Swagger generation/drift and
git diff --checkpassed.
Upgrade notes
- Run the new workload-usage migrations before enabling workload-bound keys.
- Update clients from the earlier draft
/admin/usage/agents/weeklyroute to
/admin/usage/workloads/weekly. - Negotiate the final
gorouter-workload-usage-v1capability marker. - Existing unbound keys require no migration and continue to work normally.
Delivery status
- Target release:
v0.2.0. - Source implementation: complete.
- Unit and SQLite integration coverage: complete.
- Release publication and deployment: pending.
Full Changelog: v0.1.1...v0.2.0
v0.1.1
v0.1.0
v0.0.22
v0.0.22 — Stream routing reliability
- Prevent transient accepted-stream failures from banning all Codex credentials.
- Continue advancing the distributed account checkpoint after a failed partial stream.
- Retry failures that happen before output using the configured per-account retry budget.
- Avoid replaying requests after output or tool activity has reached the client.
- Fix intermittent 503 no healthy credentials available errors after repeated stream failures.
Full Changelog: v0.0.21...v0.0.22