feat: initial release of llm-fingerprint-detector

TypeScript library + CLI implementing single-token behavioral
fingerprinting of LLMs behind OpenAI-compatible APIs, per
'One Token Is Enough' (Bruckner, arXiv:2607.10252).

- Zero runtime dependencies (Node >= 18.17 built-in fetch)
- fingerprint / compare / verify API + llm-fingerprint CLI
- Jensen-Shannon divergence over per-cell answer distributions
- Reasoning-model aware (auto-disables hidden thinking channels)
- Bundled sample references for 11 popular models (CC-BY-4.0,
  derived from the paper's public Zenodo dataset)
- Unit + integration tests via node --test

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Deng-m1
2026-07-21 16:58:00 +08:00
co-authored by Cursor
commit 232fbc6dd8
32 changed files with 5676 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
import assert from 'node:assert/strict'
import { test } from 'node:test'
import {
JSD_MATCH_THRESHOLD,
JSD_MISMATCH_THRESHOLD,
MIN_COMPARABLE_CELLS,
} from '../dist/constants.js'
import { buildComparisonResult, decideVerdict } from '../dist/verdict.js'
test('verdict thresholds: match / uncertain / mismatch bands', () => {
const cells = MIN_COMPARABLE_CELLS
assert.equal(decideVerdict(0.0, cells), 'match')
assert.equal(decideVerdict(JSD_MATCH_THRESHOLD, cells), 'match')
assert.equal(decideVerdict(JSD_MATCH_THRESHOLD + 1e-9, cells), 'uncertain')
assert.equal(decideVerdict(JSD_MISMATCH_THRESHOLD, cells), 'uncertain')
assert.equal(decideVerdict(JSD_MISMATCH_THRESHOLD + 1e-9, cells), 'mismatch')
assert.equal(decideVerdict(0.9, cells), 'mismatch')
})
test('verdict: too few comparable cells → insufficient', () => {
assert.equal(decideVerdict(0.1, MIN_COMPARABLE_CELLS - 1), 'insufficient')
assert.equal(decideVerdict(null, 10), 'insufficient')
})
test('buildComparisonResult carries thresholds, baselines and per-cell details', () => {
const entries = [
{ cellId: 'random-number-1-100:en', jsd: 0.5, validA: 25, validB: 30 },
{ cellId: 'random-color:en', jsd: 0.1, validA: 25, validB: 30 },
{ cellId: 'coin-flip:en', jsd: 0.2, validA: 25, validB: 30 },
{ cellId: 'random-animal:en', jsd: 0.2, validA: 25, validB: 30 },
]
const result = buildComparisonResult(entries, 0.25, false)
assert.equal(result.verdict, 'match')
assert.equal(result.comparableCellCount, 4)
assert.equal(result.cells.length, 4)
assert.equal(result.protocolMismatch, false)
assert.equal(result.thresholds.match, JSD_MATCH_THRESHOLD)
assert.equal(result.baselines.differentModel, 0.463)
})