Commit Graph
13 Commits
Author SHA1 Message Date
Jay Hemnani 17f8dff09f fix: escape prompts and responses printed with print_responses (#482)
Text such as `[/INST]` in a prompt or response was parsed as Rich markup, which crashed the run with a MarkupError. Other bracketed text like `[bird migration]` was silently removed from the output.
2026-10-06 13:08:04 +05:30
benthecarman 8ae8526c9d fix: prevent empty layer range and too many neighbors in ARA (#478)
* Cap ARA's neighbor count at the number of prompts

The nearest neighbors are selected from the outputs for the good and
bad prompts, which have one row per prompt. With fewer than 15 prompts
in either dataset, the optimizer could pick a neighbor count larger
than that, and torch.topk would crash with "selected index k out of
range". Bounding the search range instead of clamping the value keeps
the optimizer from wasting trials on counts that would all behave the
same.

* Render chat templates with a fixed date

Some chat templates, including gpt-oss's, put the current date in the
system prompt. That makes the residuals, and with them the modified
model, depend on the day Heretic runs, so a model could not be
reproduced on a different day. It also made the gpt-oss test's hash
change daily once ARA started modifying the model.

Prompts used for computing residuals and for evaluation are now
rendered with a fixed date. Interactive chat keeps the real one.

* Prevent ARA from sampling an empty layer range

The start index was sampled from [0, L//2] and the exclusive end index
from [L//2, L], so both could land on L//2 and leave no layers to
modify, wasting the trial. Starting the end range at L//2 + 1 rules
this out while keeping the bounds fixed, as multivariate TPE requires.

On the 2-layer test models, every ARA trial had picked this empty
range, so the seed-oss and gpt-oss tests never ran the optimization.
They now modify layer 1, which changes their expected hashes. The
seed-oss output also differs between the CPUs of GitHub's runners,
because L-BFGS amplifies small floating-point differences, so it gets
CI hashes as well.
2026-10-06 12:40:51 +05:30
Vinay Umrethe a09b4eae07 chore: add new Windows test hashes (#470) 2026-10-02 15:00:57 +05:30
Philipp Emanuel Weidmann c121a4ba41 chore: update dependencies (#469)
* chore: update dependencies

* chore: add new CI test hashes

* chore: add yet more CI test hashes
2026-10-02 14:49:47 +05:30
662e4ba27e feat: modifier plugins + ARA (#446)
* feat: add modifier base class

* feat: re-implement abliteration as a modifier plugin

* fix: adjust good/bad prompts hack to match tests

* feat: support dataset specifications containing multiple individual datasets

* feat: re-implement ARA as a modifier plugin

Arbitrary-Rank Ablation (ARA) (Weidmann 2026) was originally introduced by @p-e-w in #211

Co-authored-by: kabachuha <artemkhrapov2001@yandex.ru>
Co-authored-by: joninco <joninco@bullpoint.org>
Co-authored-by: Ashar <coder3101@users.noreply.github.com>

* feat: add tests for ARA

* feat: reduce default number of trials

* ci: remove broken "semantic-pull-request" workflow

* ci: add yet another alternative model hash

---------

Co-authored-by: kabachuha <artemkhrapov2001@yandex.ru>
Co-authored-by: joninco <joninco@bullpoint.org>
Co-authored-by: Ashar <coder3101@users.noreply.github.com>
2026-10-01 14:30:07 +05:30
Vinay Umrethe 3521f8648a feat: A better logic for detecting the thinking prefix in the response. (#423)
* fix: Check response prefix.

In case if the model adds <think> at the end of user prompt and only generates </think> end, then the detection goes wrong.

* fix: Handle whitespace in CoT, remove redundant checks

* fix: Type checker

* fix: try looking at tag positions, not text end

regex

* ruff, fix import sorting

* fix: rich markup

* fix: I missed other ones

* feat: Update SHA256SUMS file hashes in the tests.

A major change that affects reproducibility.

* fix: It is now sensible to also update the extra SHA256SUMS.ci2 file.

* fix: Only consider whitespace, no other text or instructions.

because mistral-3 as additional reasoning instructions in its chat template. And I suppose many other models can have it too.

* fix: Update windows hashes.

* fix: Update CI hashes too

* as always update case two of mistral-3 (ci2 hash)

* docs: update comment

* feat: Handle the edge case for models having additional instructions.

* fix: Update windows hash for mistral-3

* docs: remove a line from the comments

because I'm not sure about GPT-OSS models' thinking tags and it cannot be confirmed using an untrained tiny GPT-OSS model. And inference fallback would of course generate gibberish as the model cannot understand additional instructions about 'how to generate response and how to think' from the chat_template.

* fix: a few things.

* fix: Update hash for qwen3.5 after the whitespace fix for its response prefix.

* docs: Update comment

* fix: Update qwen3.5 hash for CI

* fix: Remove Case 2 which only serves tests

unnecessary

* fix: Hash

* fix: concern is valid enough, so we use a small text.

add a comment too

* docs: minor
2026-09-05 21:41:52 +05:30
Philipp Emanuel Weidmann 95dda4c4db feat: add benchmark scorer (#444)
* fix: improve print output of scorers

* feat: add benchmark scorer
2026-09-03 17:49:46 +05:30
Vinay Umrethe bedb94ef11 feat: Show a summary at end of tests (#425)
* feat: Show a summary at end of tests.

* fix: unnecessary
2026-08-17 22:27:44 +05:30
Vinay Umrethe 02ebf7a751 feat: Add alternate CI hash in the valid list (for qwen2.5) (#412)
* feat: Add alternate CI hash in the valid list (for qwen2.5)

* ruff
2026-07-16 18:58:48 +05:30
Andrew Barnes e7b783ed85 fix: validate scorer instance names in config (#407)
* fix: validate scorer instance names in config

* fix: run scorer config tests in CI

* fix: drop redundant UV_PYTHON env and quote unittest pattern

* fix: report precise scorer name validation errors
2026-07-15 20:28:10 +05:30
c8a254b825 feat: generic plugin system (#53)
* style: ruff

* feat(wip): populate metadata fields and allow plugins to declare what they need

* refactor: extract metadata logic to separate module

* style: placate ruff

* chore: use eos token for inferring finish reason with fallback

* fix: handle empty responses better

* style: ruff

* refactor: combine response text and metadata into single object

* refactor: clean up tagger and scorer usage

* style: ruff

* chore: remove is_refusal

* style: ruff import ordering

* feat: remove embeddings and generation traces

* feat: return all hidden states instead of just last ones

* chore: remove testing changes

* style: ruff format

* fix: mismatching stop reason identifier

* chore: update default config ordering

* chore: fix merge

* feat: allow external plugin imports

* feat: add good_residuals and bad_residuals to context metadata

* style: ruff

* chore: remove unnecessary allow extra

* chore: remove unnecessary system prompt and model name

* style: ruff

* perf: clear residuals from memory if plugin doesn't need them

* feat: support external filepaths and clean up import logic

* style: ruff

* refactor: consolidate tagger and scorer functionality into a single scorer plugin

* refactor: parent Plugin class for all plugins

* feat: support multiple scorer plugins

* refactor: type fixes

* style: satisfy ruff

* refactor: centralize scorer dataclasses

* refactor: rename MetricResult to Score

* feat: simplify plugin loading

* feat: split response metadata objects and access in evaluationContext

* style: ruff

* style: ruff

* chore: remove old tagger code

* refactor: scorer settings inherit directly from Pydantic

* refactor: move eval prompts and settings to CountRefusals and KLDivergence

* feat: move scorer config to top level and add support for scale factor

* fix: missing config for scorers

* style: ruff

* fix: scale type error

* docs: fix misleading docstring

* fix: clean up old fields

* refactor: use BaseModel for scorer settings

* chore: make scale default to 1 for safety

* refactor: get metadata dynamically through EvaluationContext

* refactor: rename CountRefusals to RefusalRate

* chore: remove unused kl_divergence config fields

* docs: restore missing comment

* refactor: remove unused code

* chore: specify settings and model field types

* refactor: rename to prompts

* refactor: move load_plugin to plugin

* style: ruff

* refactor: update optimization direction config to use StudyDirection directly

* fix: missing TypeVar

* fix: missing imports

* fix: use OptimizationDirection peoperly

* chore: remove names

* chore: remove unecessary future import

* chore: remove unused scorer imports

* refactor: objective should only return tuple of floats

* refactor: use dataclass for scorer config

* feat: support multiple instances of the same scorer

* style: ruff

* fix: nonexistent name attribute in scorer

* refactor: clear residuals and analyser

* docs: MetricResult -> Score

* fix: clean up default toml

* fix: missed renaming to RefusalRate

* chore: missing return ModuleType

* docs: add SPDX header

* docs: add SPDX header

* docs: add SPDX header

* chore: fix misleading field description leftover from old code

* chore: add newline

* chore: unused settings class

* fix: bad import

* refactor: rename ResponseText -> TextCompletion

* feat: simplify api

* refactor: rename to get_score

* feat: namespace scorer configs

* style: ruff

* fix: genericize readme intro

* chore: move init to scorer base class

* refactor: handle direction and scale outside scorer

* chore: use underscore for instance names

* fix: add scorer instance name to scores

* refactor: create structured api for scorers to access model

* refactor: rename plugin-specific Settings to PluginSettings

* feat: add instance name to plugin load logging

* style: ruff

* chore: allow extra fields for plugins

* fix: improve plugin loading logic

* chore: undo change fixed in master

* chore: remove old code

* docs: adjust docstring

* chore: cleanup import

* refactor: unnest plugin settings class and detect from type annotation

* refactor: use plain str instead of Response object with metadata

* refactor: move non evaluator-specific methods out

* refactor: use enum for StudyDirection

* refactor: no strings as type annotations

* chore: let evaluator blow up on error

* refactor: rename metrics to scores globally

* feat: separate cli and hf score displays and clean up readme logic

* fix: direction serialization ValidationError when restoring from save

* refactor: rename scorer start() to setup()

* style: ruff

* fix: remove external plugin test

* refactor: rename setup to init

* docs: formatting

* refactor: move scorers location in config

* docs: add comment describing return tensor shape

* style: ruff

* refactor: simplify scorer setting logic

* refactor: clarify plugin loading logic

* refactor: remove unnecessary hashing and inline import_module

* style: ruff

* fix: don't use classnames for readme

* refactor: don't expose heretic settings to scorer

* fix: adjust print responses logic and move to scorer config level

* refactor: separate baseline score computation

* refactor: rename hf_display to md_display

* style: ruff

* Update src/heretic/scorer.py

Co-authored-by: Philipp Emanuel Weidmann <pew@worldwidemann.com>

* Update src/heretic/scorer.py

Co-authored-by: Philipp Emanuel Weidmann <pew@worldwidemann.com>

* style: ruff

* fix: ty error

* refactor: bind Score names to parent Scorers as class property

* docs: fix doc

* docs: update comment

* style: remove changes

* chore: define default refusal markers

* style: ruff

* style: remove whitespace changes

* docs: tweak docs

* chore: cleanup from merge

* style: ruff

* fix: handle negative floating point kld

* style: formatting

* chore: remove unused code

* chore: ruff

* style: undo line removal

* style: update formatting and remove old comment

* docs: undo style change

* docs: update field description

* docs: tweak docstring

* chore: revert kld absolute value forcing

* style: ruff

* chore: cleanup

* docs: update header

* docs: update header

* refactor: remove unnecessary conditional imports

* fix: apply review omments on refusalrate

* refactor: move contract validation to plugin

* refactor: move Context to Plugin

* refactor: move init to plugin level

* refactor: move init() to plugin

* style: ruff

* docs: update SPDX header

* refactor: derive score name from scorer.score_name

* chore: no None option for baseline_score_displays

* fix: show CLI formatted metrics in trial selection

* fix: sort trials by scores

* chore: remove unnecessary from future import

* chore: remove scorer scale field

* refactor: import Context from plugin

* docs: add quote to direction

* refactor: move model_config to the end of the class

* refactor: use dataclass for consistency

* refactor: use BaseModel and store study direction as str

* docs: move docstring location

* refactor: combine scorer load and init

* refactor: use best_trials for single and multi-objective

* refactor: remove all .get()

* refactor: remove unused dataclass

* refactor: use ScorerEntry dataclass for improved code quality

* style: ruff

* chore: adapt reproducibility to plugin architecture

* chore: address PR comments

* chore: make `ScorerConfig` fields full `Field()`

* chore: address pr comments

* feat: bump to version 3 of reproduce json

* refactor: rename direction to optimization

* refactor: rename loop var

* feat: pin to dataset commit sha for reproducibility

* style: ruff

* feat: show metric as list instead of table

* chore: remove stale comment

* chore: resync with upstream

* fix: trial title formatting

* chore: single source of truth for optimization objective ordering

* feat: fail-fast when there are no optimization objectives

* chore: remove dead `verify_hashes`

* refactor: pair scores with baselines everywhere

* fix: bug

* chore: add recommendation to install heretic 1.4 for older reproduce files

* chore: adapt nohumor and noslop config files to new format

* refactor: rename refusals to residuals everywhere

* fix: merge issues

* fix: fix test configs

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Apply suggestion from @gemini-code-assist[bot]

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* style: ruff

* chore: validate `instance_name` early

* chore: add return type for `load_prompts`

* docs: comment typo

* docs: comments

* docs: comments

* chore: comments and spacing

* docs: comments

* Update src/heretic/evaluator.py

Co-authored-by: Vinay Umrethe <umrethevinay@gmail.com>

* refactor: rename `cli_display` to `rich_display`

* style: ruff

* fix: don't repro external plugins or local datasets

* test: adapt minicpm5 to scorer-based format

* test: adapt qwen2.5 to scorer based format

* chore: restore comment

* chore: address pr comments

* chore: remove stale `keyword_markers`

* chore: string

* style: ruff

* refactor: make KLD and keyword rate scorers default

---------

Co-authored-by: mad-cat-lon <113548315+mad-cat-lon@users.noreply.github.com>
Co-authored-by: Philipp Emanuel Weidmann <pew@worldwidemann.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Vinay Umrethe <umrethevinay@gmail.com>
2026-07-07 14:34:33 +05:30
Vinay Umrethe 7470dfd7af fix: use W_org matrix only where needed (#398)
* fix: minor change

use `W_org` matrix where needed...

* Update model.py

* Update model.py

* fix: Windows hash, remove BOM marker

* docs: Add info about test cases

* feat: Tests for row_normalization PRE & NONE

* feat: CI hash files for row_normalization PRE & NONE models

* feat: Documentation instructions about test suite

* add recommendation
2026-07-01 16:13:14 +05:30
Philipp Emanuel WeidmannandVinay Umrethe 0146b2760f feat: headless operation + end-to-end tests (#392)
* fix: remove notebook input shims

Closes #280

* feat: support headless operation (no interactive input)

* fix: prevent infinite loops

* feat: add end-to-end tests

* ci: run tests in CI

* ci: fix test output ordering

* fix: replace home-cooked `set_seed` function with Transformers builtin

* feat: print PyTorch config when running tests

* feat: print additional information

* experiment: try to standardize test environment

* fix: revert environment changes

* feat: support multiple valid hashes for each output file

* feat: add test output hashes for CI

* feat: add test output hashes for CI (alternative environment)

* feat: add hashes for Windows (#394)

* fix: Hash on windows

* trigger ci

* fix: prefer .yaml (used widely than .toml for model configs)

* use removeprefix

* docs: restore commet

* use removeprefix again

* tests: Add windows hash files for all test models

* trigger ci

* fix: minor cleanup

* clean merge mismatch

* remove unnecessary CRLF replace, now that we support more SUMS files

* fix: use binary mode for hashes everywhere

---------

Co-authored-by: Vinay Umrethe <umrethevinay@gmail.com>
2026-06-27 13:41:48 +05:30