Research basis, source attribution and implementation mapping.
A Python tool for running budgeted canary-disclosure experiments, saving distinct prompt patterns and comparing simple defenses.
Requires Python 3.11 or newer.
python -m pip install -e ".[test]"
python -m autoforge.cli run --budget 20
python -m autoforge.cli taxonomy --budget 20
python -m pytestThe default provider is a local simulation. An optional OpenAI-compatible provider accepts a model endpoint through AUTOFORGE_PROVIDER, AUTOFORGE_BASE_URL, AUTOFORGE_MODEL and OPENAI_API_KEY.
The loop proposes variations on a canary task, requests a response, grades disclosure and retains sufficiently different prompts in an archive. Text similarity groups related examples. The report tracks the query budget, first disclosure, retained patterns and defense results.
A refusal that prints the secret still leaks it. Refusal wording is recorded separately and cannot override the disclosure result. The current grader checks literal disclosure with case normalization; it does not detect every encoding or partial disclosure.
The simulation checks the experiment machinery. It is not evidence about a deployed model. Prompt clusters describe text similarity, not independently established vulnerability families. When comparing models, keep the prompt budget and dataset fixed, save raw outputs, and repeat runs.
Curiosity-driven Red-teaming for Large Language Models motivates measuring coverage rather than repeatedly finding the same failure. AUTOFORGE uses a lightweight prompt archive rather than reproducing that paper's reinforcement-learning method.
python -m autoforge.experiment run --database runs.sqlite --budget 60 --seed 0 --strategy ucb --output run.json
python benchmark.pyThe persistent runner is separate from the small discovery demonstration. It reserves every request in SQLite before calling the provider. A failed request consumes budget. An interrupted request stays pending until inspected; it is never silently retried. Repeating the command resumes the same configuration without repeating completed calls.
Configuration, system prompt and candidate templates form a SHA-256 run identity. Each query records its operator, prompt, response, disclosure result, status and elapsed time. Changing a configuration creates a different run. Use one worker per run.
Three selectors are available:
round_robin: equal attention to each operator.uniform: seeded random selection.ucb: explore unused operators, then allocate requests using an upper-confidence-bound score.
To resolve an interrupted request after checking its outcome:
python -m autoforge.experiment resolve-pending --database runs.sqlite --run-id RUN_IDThis marks the unknown outcome as an error without refunding its query. An external provider can have completed a request before a local process crashed, so exactly-once remote execution cannot be guaranteed.
For a real endpoint, set the provider environment variables above and give --provider-id an explicit model revision and configuration. Disable provider-side retries when exact request accounting matters. Saved databases and exports contain full prompts and responses; keep private runs out of Git.
results/simulation.json records 60 runs: 20 seeds per selector, 60 requests per run, 3,600 attempts total. All use six fixed templates and the deterministic MockProvider.
| Selector | Mean disclosure rate | Across-seed standard deviation | Mean queries to first disclosure | Operators with disclosure |
|---|---|---|---|---|
| Round robin | 83.33% | 0.00 percentage points | 1.20 | 5 |
| Uniform | 84.08% | 4.82 percentage points | 1.25 | 5 |
| UCB | 95.00% | 0.00 percentage points | 1.20 | 5 |
UCB spends fewer queries on the one resistant operator, increasing repeated disclosures without discovering additional operator families. This demonstrates why success frequency and coverage need separate reporting. These are measurements of the simulation, not jailbreak rates for a language model.
The Wilson interval in individual reports is descriptive. Repeated prompts and adaptive selection violate independent-sample assumptions; do not use it as a generalization interval for model safety. Across-seed variation is recorded separately. Latency measures local provider calls, not end-to-end serving throughput.
Tests cover resumed versus uninterrupted runs, strict budgets, provider failures, unresolved requests, configuration identity and disclosure inside refusals. GitHub Actions runs tests and saves a fresh benchmark artifact on Python 3.11, 3.12 and 3.13.
loop.py: experiment coordinatorattacker.py: prompt variationstarget.py: local and optional remote providersgrader.py: disclosure checks and calibrationarchive.py: similarity and retained examplesdefense_eval.py: defense comparisons
MIT license. Built by Vishnu Kosuri.
