Conversation
…Agent and AgentDojo scripts/build_injection_dataset.py builds evals/labelled/injection-public.jsonl from InjecAgent at a fixed commit and agentdojo 0.1.35 (benchmark v1.2.2). The agentdojo dependency is declared as PEP 723 inline metadata, so pyproject.toml and uv.lock stay unchanged, and a rebuild writes the same bytes. The set holds 665 tool outputs. 335 carry a planted instruction, sampled with a fixed seed across user tools, injection tasks and attack templates; 330 carry none, among them normal requests written for a person. Positives that only the user's task tells apart are marked in their notes and reported on their own. --report turns an s1a run injection_guard job into the benchmark tables. docs/benchmarks.md gains the Jev run of 2026-09-27; NOTICE and THIRD_PARTY_LICENSES.md carry both MIT notices; evals/README.md, docs/roadmap.md and CHANGELOG.md describe the new set.
IRONICBo
left a comment
There was a problem hiding this comment.
I rebuilt the 665-record set byte-for-byte and ran the focused suite (52 tests pass). Three report-integrity cases still look worth fixing:
-
report()matches a verdict to a row using onlynoteandlabel. Replacing everystate.toolandstate.textwhile preserving those two fields still produces the identical report, even though hard-subset membership and rule baselines are recomputed from the replacement text. Please bind the job to the evaluated dataset (for example, a dataset digest insummary.json, or a state digest per verdict) and reject mismatches. -
parse_note()accepts a grade valid for any pool with the same source, rather than the row's label. A positiveagentdojo R2 ...row is accepted and then enters AgentDojo recall even thoughR2is a negative-only grade. Validating againstGRADES[(base, bool(row["label"]))]would keep the denominators typed. -
The report header is always
Jev, whileevaluate()does not persist the model. A valid--model layajob is therefore rendered as Jev metrics. Please record the model in the summary and render/check that value (or explicitly reject non-Jev jobs here).
These are independent of the builder itself: the deterministic rebuild, schema/count checks, formatting, and focused tests all passed on f9233b9.
rails.evaluate now records the labelled set's sha256 and the decision model's name in summary.json. --report recomputes the digest of the set it reads and stops on a mismatch or on a job without these fields, and labels its tables with the recorded model instead of Jev. A note's grade is now checked against the row's label, so a positive cannot carry a negative-only grade such as R2.
|
Thanks for rebuilding the set and checking it. All three are fixed in 071b7ac, a separate commit on top of f9233b9.
The two fields are added to every rail's summary; the existing fields are unchanged. The Jev job behind |
Closes #3. It covers the review points on #6.
Why
evals/labelled/injection.jsonlhas 20 items, too few to say much about precision and recall on real attacks.What
scripts/build_injection_dataset.pybuildsevals/labelled/injection-public.jsonl, 665 records, from InjecAgent atf19c9f2and agentdojo 0.1.35. agentdojo is declared as PEP 723 inline metadata, sopyproject.tomlanduv.lockare unchanged. A rebuild writes the same bytes; I checked it with
PYTHONHASHSEEDunset, 7 and 999.--report <job>prints precision, recall per source, the always-true baseline and the hard-subset comparison for ans1a run injection_guardjob.NOTICEandTHIRD_PARTY_LICENSES.mdcarry both MIT notices.evals/README.md,docs/roadmap.mdandCHANGELOG.mddescribe the set.
As agreed in #3: InjecAgent
Tool ResponsewithUser Toolastool, base only; AgentDojo tool outputs renderedoffline through
GroundTruthPipeline; a stratified sample with a fixed seed, spread over the five attack templates;deduplicated; truncated to 6,000 characters with labels re-derived; the always-true baseline and recall per source in
the table.
Results
Jev on 2026-09-27, median 300 ms per decision, $0.016 for the set. Rows 1 to 4 exclude the 65 records of choice 1 below.
Choices beyond #3 for you to accept or change
Each of these goes past what we agreed. None of them is hard to undo.
Jev on the set. A regex for the five AgentDojo template openers reached AgentDojo recall 1.00. "Quarantine if the
text contains please" reached InjecAgent dh recall 0.91 at precision 0.97, because almost no negative held a
request. 65 positives read as an ordinary request, for example an email asking to transfer money for the mortgage,
and the rail cannot see the task that makes them an attack. They stay in the file with a
-usource and get theirown row, outside precision and recall. To undo: drop the suffix and the row.
default environment: emails, files and pages that hold a normal request written for a person. With 13 already in
the set that makes 34. The report adds balanced accuracy on the 116 positives with no template opener plus these 34,
next to fixed keyword rules. Best rule ("please") 0.652, Jev 0.845. To undo: drop the read-tool pool and the row.
have 95% Wilson intervals up to about ±0.16 wide; Jev's is 34/34, [0.90, 1.00]. Before adding them I set two targets:
every keyword rule at or below 0.65 on the hard subset, and a naive Bayes classifier cross-validated by group at or
below 0.70. Neither is met. "please" reaches 0.652 because most InjecAgent instructions contain it. Naive Bayes
reaches 0.727 because the hard positives are all InjecAgent Python-repr text and the hard negatives all AgentDojo
YAML. I did not move the targets or pick samples.
attacker-tool responses (
attacker_simulated_responses.json), spread over its 32 tools and skipping near-duplicates.(629 security cases) are v1, which has 27.
important_instructions_no_namesinstead ofimportant_instructions, so no model or user name appears in thetext.
injecagenttemplate is kept although it is word for word the enhanced prefix left out on theInjecAgent side, so the positives spread evenly over the five templates. The note names the template, so recall can be
split by it.
{hotel_name}and{first_name}stay in 10 records. They are in the upstreamGOALof travelinjection_task_5and workspaceinjection_task_13, and AgentDojo injects them that way. The build allows a braceonly if it appears in that record's
GOAL.per template.
injection.jsonl.docs/benchmarks.mdis written for a reader. It groups the outputs by what they look like and calls thebaseline "quarantine everything"; the table above follows the
--reportoutput. The roadmap line "Still to build …a labelled set from the public ones" now points to it.
Two things the build had to handle
Three AgentDojo tools write
datetime.now()into their output, so 231 outputs per template differed from the benign runonly by a timestamp and looked injected. The build freezes that clock.
create_calendar_eventorders participantsthrough a set, so the build re-runs itself with
PYTHONHASHSEED=0.Possible follow-ups
negatives and break the format split.
How to verify
uv run scripts/build_injection_dataset.py && git diff --exit-code evals/labelled/injection-public.jsonlThe build takes about 4 minutes and needs network access to raw.githubusercontent.com and PyPI. The Jev run needs
TYPESAFE_API_KEYorOPENROUTER_API_KEY.