Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Release

# Push a tag like v4.2.0 to build binaries for Linux, macOS and Windows and
# attach them to a GitHub Release. Publishing to crates.io stays manual.
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
# Build-only dry run when this workflow itself changes (nothing is released).
pull_request:
paths:
- ".github/workflows/release.yml"
workflow_dispatch:
inputs:
tag:
description: "Existing tag to (re)build, e.g. v4.2.0"
required: true

permissions:
contents: write

env:
CARGO_TERM_COLOR: always
TAG: ${{ github.event_name == 'pull_request' && 'pr-test' || github.event.inputs.tag || github.ref_name }}

jobs:
build:
name: Build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
target: x86_64-unknown-linux-gnu
- os: macos-latest
target: aarch64-apple-darwin
- os: macos-latest
target: x86_64-apple-darwin
- os: windows-latest
target: x86_64-pc-windows-msvc
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event_name == 'pull_request' && github.sha || env.TAG }}

- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}

- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}

- name: Build
run: cargo build --release --locked --target ${{ matrix.target }}

- name: Package (Unix)
if: runner.os != 'Windows'
shell: bash
run: |
name="every-other-token-${TAG}-${{ matrix.target }}"
mkdir "$name"
cp "target/${{ matrix.target }}/release/every-other-token" README.md LICENSE "$name/"
tar czf "$name.tar.gz" "$name"
shasum -a 256 "$name.tar.gz" > "$name.tar.gz.sha256"

- name: Package (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
$name = "every-other-token-$env:TAG-${{ matrix.target }}"
New-Item -ItemType Directory $name | Out-Null
Copy-Item "target/${{ matrix.target }}/release/every-other-token.exe", README.md, LICENSE $name
Compress-Archive -Path $name -DestinationPath "$name.zip"
$hash = (Get-FileHash "$name.zip" -Algorithm SHA256).Hash.ToLower()
"$hash $name.zip" | Out-File -Encoding ascii "$name.zip.sha256"

- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.target }}
path: |
every-other-token-*.tar.gz*
every-other-token-*.zip*

release:
name: Publish GitHub Release
needs: build
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true

- name: Create or update release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
ls -l dist
if gh release view "$TAG" >/dev/null 2>&1; then
gh release upload "$TAG" dist/* --clobber
else
gh release create "$TAG" dist/* --title "every-other-token $TAG" \
--notes "Prebuilt binaries are attached below. See CHANGELOG.md for what changed."
fi
39 changes: 36 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [4.2.0] - 2026-09-25

First release since 4.1.2. It carries the library modules added since then
(divergence detection, logit lens, activation patching, circuit discovery,
Thompson-sampling bandit, checkpointing, SSE backpressure, batch research mode
and the many analysis modules added in rounds 3 to 32; see `git log v4.1.2..v4.2.0`),
plus the fixes below.

### Added

- `examples/mock_stream.rs`: `cargo run --example mock_stream` runs the real
interceptor against the mock provider (no API key) and prints a per-token
table of original and intercepted text, confidence and perplexity.
- `.github/workflows/release.yml`: pushing a `vX.Y.Z` tag builds binaries for
Linux x86_64, macOS arm64 and x86_64, and Windows x86_64 and attaches them,
with SHA-256 checksums, to a GitHub Release. crates.io publishing is manual.

### Fixed

- Mock provider no longer panics on prompts whose 20th byte falls inside a
multi-byte UTF-8 character.
- Mock provider in terminal mode counted every token twice, so the CLI
transformed every token instead of every other one.
- Terminal output now keeps the spaces between words (whitespace tokens were
dropped, so words ran together).
- `StanceClassifier` matched keywords as substrings, so "disagree" counted as
support; it now matches words.
- `NgramModel::generate` is reproducible for a given seed and no longer stops
early at a context with no observed continuation.
- `SimilarityEngine` uses smoothed IDF, so terms present in every document
(including any term of a one-document corpus) no longer get zero weight.
- Test suite compiles and passes again (stale `cli::Args` literals, doctests
referencing APIs that did not exist, wrong expectations in two tests).

## Earlier unreleased notes (included in 4.2.0)

### Added

- Module-level `//!` doc comments on all previously undocumented public modules
Expand All @@ -29,9 +65,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Async unit tests for `run_research_headless` using the Mock provider (no API
key required): empty-prompt error path, multi-run accumulation, vocab
diversity bounds, and citation string format.
- `.github/workflows/release.yml`: release workflow that triggers on `v*.*.*`
tags, builds release binaries for Linux (musl), macOS, and Windows, publishes
a GitHub Release with attached binaries, and publishes to crates.io.
- `EotConfig` struct and all its fields now carry `///` doc comments explaining
each configuration option and its valid range.
- `make_test_interceptor` helper added to the `research_tests` module so
Expand Down
33 changes: 24 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ This project is primarily a research tool for token-level LLM analysis. Contribu

## What we want

- **New providers** — Mistral, Gemini, local Ollama with logprob support
- **New transforms** — semantically interesting token mutation strategies
- **Research features** — new metrics, export formats, comparison modes
- **Web UI improvements** — new visualization modes, better diff views
- **Bug fixes** — especially anything that breaks the token confidence pipeline
- **New providers**: Mistral, Gemini, local Ollama with logprob support
- **New transforms**: semantically interesting token mutation strategies
- **Research features**: new metrics, export formats, comparison modes
- **Web UI improvements**: new visualization modes, better diff views
- **Bug fixes**: especially anything that breaks the token confidence pipeline

## What we don't want

Expand All @@ -18,10 +18,25 @@ This project is primarily a research tool for token-level LLM analysis. Contribu

## How to contribute

1. Fork and clone
2. `cargo test --all-features` — must pass
3. `cargo clippy -- -D warnings` — zero warnings
4. Open a PR with a clear description of the research motivation
1. Fork and clone.
2. Try it without an API key: `cargo run --example mock_stream`, or
`cargo run -- "hello" --provider mock --visual`.
3. `cargo test` must pass (this is what CI runs). If you touch a feature-gated
module, also run `cargo check --no-default-features --features self-improving`
(or the feature you changed).
4. `cargo clippy` should not report new warnings in the code you changed. The
codebase has existing warnings, so `-D warnings` is not enforced yet;
cleaning some up is a welcome first PR.
5. New behaviour needs a test; bug fixes need a regression test.
6. Open a PR with a clear description of what changed and why.

Issues labelled [good first issue](https://github.com/Mattbusel/Every-Other-Token/labels/good%20first%20issue) are small, self-contained starting points.

## Releases

Maintainers bump `version` in `Cargo.toml`, add a `CHANGELOG.md` entry, merge,
then push a tag such as `v4.2.0`. `.github/workflows/release.yml` builds the
Linux, macOS and Windows binaries and attaches them to the GitHub Release.

## Research ideas

Expand Down
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,25 @@ You normally see a model's answer only as finished text. `every-other-token` sit

## Install

**Prebuilt binaries** (no Rust toolchain needed): download the archive for your platform from the [latest release](https://github.com/Mattbusel/Every-Other-Token/releases/latest). Builds are provided for Linux x86_64, macOS (Apple Silicon and Intel) and Windows x86_64.

```bash
# Linux example; adjust the file name for your platform and version
curl -LO https://github.com/Mattbusel/Every-Other-Token/releases/download/v4.2.0/every-other-token-v4.2.0-x86_64-unknown-linux-gnu.tar.gz
tar xzf every-other-token-v4.2.0-x86_64-unknown-linux-gnu.tar.gz
./every-other-token-v4.2.0-x86_64-unknown-linux-gnu/every-other-token "hello" --provider mock
```

**With Cargo:**

```bash
cargo install every-other-token # crates.io release (4.1.2)
# or the latest code (4.2.0)
cargo install every-other-token
# or the latest unreleased code
cargo install --git https://github.com/Mattbusel/Every-Other-Token
```

The Linux binary links the system OpenSSL (libssl3, present on Ubuntu 22.04+ and most current distros).

## Unique capabilities vs. standard LLM clients

| Capability | Standard clients | every-other-token |
Expand Down
Loading