Skip to content

ThinkWatch Core 0.48.0

Choose a tag to compare

@github-actions github-actions released this 25 Sep 04:41
· 120 commits to main since this release
44e4a6f

This release reports more of what core knows about each request: the session and the route from the moment a request starts, a snapshot of running requests that a client can replay, and how often each route and rule was used. It also names the account signed in on a ChatGPT account upstream, counts the requests in each cost group that have no price or no usage, and gives the security log totals for the whole window.

Upgrade notes

  • The control-plane protocol version (CONTROL_API_VERSION) is now 21. ThinkWatch Lite connects only to a core with the same protocol version, so a server has to run the core version that the app includes. ThinkWatch Lite 2026.9.16 includes 0.47.0 (protocol 20) and does not connect to 0.48.0: a server used with it stays on 0.47.0 until the app is updated to a release that includes 0.48.0. sudo twcore upgrade --version 0.47.0 --restart switches a server back to 0.47.0.
  • The format of the request history changed (request store schema 20). On its first start, 0.48.0 replaces the request history and the stored request and response bodies of an earlier version with an empty store; the configuration is kept. Switching back to an earlier version empties it again.
  • GET /in-flight returns an object, InFlight { now_ms, requests: [{ id, events }] }, instead of an array of start events. RequestStarted.session_fp is replaced by session. ChatgptUsage.email and ChatgptUsage.plan are removed; the signed-in account is in ProviderView.oauth.account.

Session and route from the start. The gateway assigns a request to a session when the request starts (the same conversation, within 30 minutes of its previous request), and RequestStarted carries that session id, the one the request is stored under. The first routing phase now finishes before the start event, so RequestStarted also carries the route, the rule, the strategy group and the rules that rewrote the request. RequestRouted carries the final record, including rewrites from the second phase and denied_by for a rule that denied the request there. The stored routing record has the same fields and is written from the start event, so a request that ends before routing completes still shows the route and rule it matched.

Requests a rule decided. A request that a rule denies in the first routing phase, or that none of the upstreams a rule chose can serve, used to produce no events and no stored row. It now produces start, routed and failed events and a row, and counts among the requests and failures in /summary; a denial in the second phase now also produces the routed event. Requests that fail before a rule decides (authentication, model admission, no matching rule) are still not recorded.

Live views. GET /in-flight returns core's clock and, for each running request, the events seen so far in order, so that a client connecting while requests are running can replay them and compute elapsed time from core's timestamps. The running requests in GET /live add elapsed_ms, session, route, rule, group and upstream.

Rule hit counts. GET /summary/routes reports, for a time window (today by default), each route's requests, failures and last request, and for each rule the requests it decided, the requests it applied to, their failures and the last one. The counts come from the stored routing records, not from the current configuration.

Cost groups and the security log. Every group returned by GET /summary/buckets/by reports unpriced_requests and no_usage_requests, so a group with no cost can be told apart as unpriced, missing usage or free. GET /security/events adds total and by_outcome (recorded, replaced, cut, blocked): the counts for everything the query's guard and time window match, the same on every page.

ChatGPT account upstreams. ProviderView.oauth.account gives the email and plan of the account signed in on a ChatGPT account upstream. Both are read from the access token core already keeps with the credential: nothing is requested from the network, nothing new is stored, and the account and user ids in the token are not exposed. The plan is reported as the backend names it, including plans that core does not list.

Releases. A release is now published by a single job once every platform has been built and each file matches its SHA-256. Previously the first platform to finish created the release, and made it the latest, while the others were still building, and each build job added another copy of the release notes. The server guide, docs/server.md, states that ThinkWatch Lite keeps a remote connection's key in a private file in its data directory, and applies to the app on macOS, Windows and Linux. The crates carry homepage and documentation links, and twcore --help begins with the binary's description.

Tests. Tests no longer hand core a port that was just released, which could make tests that bind ports, such as those of the remote control port, fail intermittently on Linux.

Downloads

Platform Binary Archive for server installation
Linux, x86_64 twcore-x86_64-unknown-linux-gnu twcore-x86_64-unknown-linux-gnu.tar.gz
Linux, aarch64 twcore-aarch64-unknown-linux-gnu twcore-aarch64-unknown-linux-gnu.tar.gz
macOS, Apple silicon twcore-aarch64-apple-darwin —
Windows, x64 twcore-x86_64-pc-windows-msvc.exe —
Windows, ARM64 twcore-aarch64-pc-windows-msvc.exe —

Each file is published with a .sha256 file beside it. A Linux archive contains twcore, the systemd unit twcore.service and LICENSE. ThinkWatch Lite includes its own copy of twcore; the files here are for running core separately, such as on a server.

Server installation

On Linux (x86_64 or aarch64), the install script sets up twcore as a systemd service. This installs 0.48.0:

curl -fsSL https://raw.githubusercontent.com/ThinkWatchProject/ThinkWatch-Core/main/scripts/install.sh | sudo sh -s -- --version 0.48.0

An installation made with the script switches to 0.48.0 with:

sudo twcore upgrade --version 0.48.0 --restart

Configuration, the remote control port and connecting ThinkWatch Lite are described in docs/server.md.

Verifying a download

A .sha256 file holds the SHA-256 of the file followed by its name. With both files in the current directory, on Linux:

sha256sum -c twcore-x86_64-unknown-linux-gnu.tar.gz.sha256

On macOS:

shasum -a 256 -c twcore-aarch64-apple-darwin.sha256

On Windows, in PowerShell, the following prints True when the binary matches:

(Get-FileHash .\twcore-x86_64-pc-windows-msvc.exe).Hash -eq (Get-Content .\twcore-x86_64-pc-windows-msvc.exe.sha256).Split()[0]

The install script and twcore upgrade check the SHA-256 themselves.

What's Changed

  • Publish releases from one job; correct the server docs and crate metadata by @fylorn in #191
  • Tests: stop handing core ports that were just released by @fylorn in #192
  • feat(stats): per-group missing-money counts and security log totals by @fylorn in #193
  • feat(api): say who is signed in on a ChatGPT account upstream, read from its own token by @fylorn in #195
  • feat(api): session and route at request start, a replayable in-flight snapshot, rule hit counts by @fylorn in #197
  • chore: v0.48.0 by @fylorn in #198

Full Changelog: v0.47.0...v0.48.0