Skip to content

feat(verifiers): give verifiers the run's conversation and trigger firing logs - #241

Open
sarah-chitty-1 wants to merge 5 commits into
mainfrom
sarahchitty/verifier-run-context
Open

sarah-chitty-1 wants to merge 5 commits into
mainfrom
sarahchitty/verifier-run-context

Conversation

@sarah-chitty-1

@sarah-chitty-1 sarah-chitty-1 commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

What

Give verifiers the run's conversation, including the user sim's turns, and the trigger firing logs, in a general way.

Today env_outcome_verifier gets only the MCP URL. A task with triggers or a user sim can't grade "noticed the change", "asked before acting" or "didn't leak the answer" without pulling those records itself.

  • run_context.load_run_context builds a RunContext from what the run recorded:
    • The stored conversation, with every user-side turn: the prompt, then each user-sim or human message. Each user message is marked with the agent triggers that wrote it (fired) and the user sim's extra fields.
    • Each env's gateway firing log, and the user agent's own firing log.
    • Anything it couldn't read is listed in unavailable, so a missing log isn't mistaken for an empty one.
  • as_of_turn(k) cuts it the way feat(rubrics_verifier): grade a multi-turn run as of turn k #222 grades "as of turn k": messages up to turn k's reply, and events from before turn k+1's message.
  • rubrics_verifier: a new run_context_for_judge: ["conversation", "trigger_log"] adds Conversation and Trigger firings sections to the judge prompt, cut at grade_up_to_turn. Size is capped: 4000 characters per message, the latest 200 events per log.
  • env_outcome_verifier: a script whose verify names a run parameter is called as verify(mcp_url, run=...). Every other script, one with an unrelated second parameter included, is called exactly as before. prompt_id picks which prompt, defaulting to the run's last one.

Worth a look

  1. Opt-in only: the run context reaches a verify that names run, and the judge only when run_context_for_judge is set. Nothing changes for existing tasks or scripts.
  2. Multi-prompt runs: the env firing log comes from the capture prompt_agent stores at the end of a prompt. The latest capture is the env's whole log, so in a task with several prompts it can include events from later prompts. It's cut by turn, not by prompt.
  3. Not covered: agent_prompt_response_verifier doesn't get the run context. Should it get criteria like "trigger X fired"?
  4. feat(rubrics_verifier): grade a multi-turn run as of turn k #222's rule: feat(rubrics_verifier): grade a multi-turn run as of turn k #222 refuses grade_up_to_turn with use_trajectory=False. With the conversation shown to the judge, that could be allowed; the rule is left unchanged here.
  5. When the user agent's log counts as missing: prompt_agent only logs a warning when it can't read the user agent's firing log back, so the loader infers that a log was expected. It was if the step recorded a trigger firing or the prompt's user agent had registered triggers. If the conversation can't be read, any registered agent trigger counts.
  6. A turn cut without the conversation: when as_of_turn can't find when turn k+1 began, it withholds every firing log and marks each one unavailable, so an early grade never sees later events.
  7. Follow-up: once "who changed what" (feat(gateway): name the role and call behind each change to an env's state #240) lands, add an "env_changes" part.

Tests

  • Unit: tst/unit/task_step/verifiers/test_run_context.py, 26 new tests against the real local conversation and object stores: the loader, the turn cut, missing records (a user-agent log that wasn't read back, and a turn cut with no conversation to cut by), the judge prompt sections, size caps and option validation, and which scripts get run (a run parameter does; one, two-with-another-name don't).
  • Integration: test_verifier_run_context_local.py runs a real two-turn conversation, with the echo agent as both solver and user sim, and reads it back through load_run_context.
  • Results: unit suite 8623 passed, 20 skipped; ruff, plugin-api (no break against the merge base) and uv lock --check pass; the local integration test passes. The branch still merges cleanly with current main.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; the previous requirement is satisfied and no new blocking issue was found.

Summary

Gives verifiers optional access to the recorded conversation and trigger firing logs.

  • Verifiers can read a run’s conversation and trigger records.
  • Outcome scripts can inspect the run behind a prompt.
  • Rubric judges can see selected conversation and trigger logs.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Conversation[Stored conversation] --> Context[RunContext]
  Logs[Saved trigger logs] --> Context
  Context --> Script[Script that requests run]
  Context --> Cut[Optional turn cutoff]
  Cut --> Render[Selected sections and size limits]
  Render --> Judge[Rubric judge]
Loading

Reviews (3) · Last reviewed commit: "review: the judge's run-context limits a..." · Reviewed by Greptile

sarah-chitty-1 and others added 3 commits October 16, 2026 14:14
…ring logs

`run_context.load_run_context` reads what a run recorded about the prompt a
verifier grades into a `RunContext`: the stored conversation, every
user-side turn included (the prompt, then the user-sim's or a human's
messages), each user message marked with the agent triggers that wrote it
and the extra fields the user-sim returned; each env's gateway firing log,
from the envelope prompt_agent captures; and the user agent's own firing
log. What the run meant to record but can't be read is named in
`unavailable`, so a missing log is not read as an empty one.
`RunContext.as_of_turn(k)` cuts it the way `grade_up_to_turn` cuts the
trajectory: the messages up to turn k's reply and the events from before
turn k+1's message.

rubrics_verifier: `run_context_for_judge` (["conversation", "trigger_log"])
appends a Conversation and a Trigger firings section to the judge prompt,
cut at `grade_up_to_turn`; messages and logs are bounded.

env_outcome_verifier: a script whose `verify` takes two parameters is called
`verify(mcp_url, run)`; `prompt_id` picks the prompt, the run's last one by
default. A one-parameter `verify` is called as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e-line comments

- env_outcome_verifier calls `verify(mcp_url, run=...)` only when the script
  names a `run` parameter; a script with any other second parameter is
  called exactly as before (new test).
- Every added comment and docstring is one line; pre-existing ones are as
  they were.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sarah-chitty-1
sarah-chitty-1 marked this pull request as ready for review October 19, 2026 19:42
@sarah-chitty-1
sarah-chitty-1 requested a review from a team as a code owner October 19, 2026 19:42
Comment thread src/agent_env/task_step/task_steps/verifiers/run_context.py Outdated
Comment thread src/agent_env/task_step/task_steps/verifiers/run_context.py Outdated
Comment thread src/agent_env/task_step/task_steps/verifiers/run_context.py Outdated
… not empty; a turn cut without the conversation withholds the logs

- load_run_context marks agent_trigger_events unavailable when the prompt's user agent had triggers
  (a firing recorded for the step, or a registration for its user agent; any registration when the
  conversation can't be read) but prompt_agent stored no firing log. The judge's Trigger firings
  section now lists every unavailable log, not only the env ones.
- as_of_turn withholds the firing logs, and marks each unavailable, when it can't find when the next
  turn began (no conversation was read), instead of returning them uncut.
- The 200-character cap on a read error's message is RunContext.ERROR_MAX_CHARS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread src/agent_env/task_step/task_steps/verifiers/rubrics_verifier.py Outdated
…ass variables

RUN_CONTEXT_MESSAGE_MAX_CHARS (4000) and RUN_CONTEXT_EVENTS_MAX (200) move from module level onto
RubricsVerifierTaskStep as ClassVars, beside its other limits; render_run_context reads them there.
Same values, same rendering.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant