Skip to content

Eval: Stop a run at a matching tool call, and add skill routing cases - #5287

Merged
chubes4 merged 2 commits into
trunkfrom
studio-code/eval-stop-at
Oct 22, 2026
Merged

chubes4 merged 2 commits into
trunkfrom
studio-code/eval-stop-at

Conversation

@chubes4

@chubes4 chubes4 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Related issues

How AI was used in this PR

Claude (via the Pi coding agent in a Roadie session) wrote the runner change, the check, the cases and their tests, and ran them. I reviewed the diff and the runs.

Proposed Changes

  • stopAt in the eval runner. It takes a list of rules, each a tool name with optional regexes for the tool's input fields. The run ends at the first tool call that matches a rule, and the result's stoppedAt names that call. The matcher is generic data (apps/cli/ai/eval-stop.ts), so it covers any tool, including new or plugin-provided ones, without changes to the runner.
  • skillsLoadedFirst in outcome.mjs: the skills named in a case's skills var were loaded before the run's stop call. This is the one check judged on the route, not the outcome, because which runbook the agent read is the thing under test. The README says so.
  • 15 routing-* cases, each stopped at the agent's first call that does the work: Write, Edit, generate_images, or a wp_cli create/update/install. The new-site cases also stop at site_create and scaffold_theme. They cover new sites, plugin features (forms, carousels, newsletters, polls, events), typography and redesigns, sections and template parts, imagery, a layout complaint on a seeded broken homepage, and a plan question. A run costs about 100k tokens and 30 seconds, instead of a full build.

Testing Instructions

  • npx vitest run apps/cli/ai/tests/eval-stop.test.ts scripts/eval/outcome.test.mjs

  • npm run eval -- --filter-pattern "^routing:" runs the routing cases.

  • Baseline: trunk (f60de7f0f) passes 69/75, from five runs of each case. Median 116k tokens and about a minute per run, against several minutes and 0.5–3M tokens for a full build case.

    Cases Trunk
    New site (make, contact form, slideshow) 15/15
    Plugin features (form, carousel, newsletter, poll) 20/20
    Events page (plugin-recommendations) 1/5
    Typography (visual-design) 3/5
    Redesign, section, template part, hero image, layout complaint, plan question 30/30

    The two weak cases are known gaps on trunk, kept so a fix shows up in the suite.

  • On Studio Code: List the skills from their own descriptions instead of hand-written routing #5265, these cases showed it wasn't ready: 62/75, mostly runs that loaded neither entry skill (build-site, edit-manage-site). It also found a skill still pointing at the prompt section Studio Code: List the skills from their own descriptions instead of hand-written routing #5265 removes.

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?

A stopAt var ends the run at the first tool call matching a rule (a tool
name and optional regexes for its input fields), so a case can judge what
the agent did before starting the work without paying for the work. The
routing cases use it with a skillsLoadedFirst check: the named skills were
loaded before the agent's first call that does the work.
@chubes4
chubes4 marked this pull request as ready for review October 22, 2026 15:03
@wpmobilebot

wpmobilebot commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

📊 Performance Test Results

Comparing f132f9a vs trunk

app-size

Metric trunk f132f9a Diff Change
App Size (Mac) 940.62 MB 945.21 MB +4.58 MB 🔴 0.5%

site-editor

Metric trunk f132f9a Diff Change
load 1236 ms 1276 ms +40 ms ⚪ 0.0%

site-startup

Metric trunk f132f9a Diff Change
siteCreation 7556 ms 7554 ms 2 ms ⚪ 0.0%
siteStartup 4389 ms 4374 ms 15 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

@chubes4
chubes4 force-pushed the studio-code/eval-stop-at branch from 8fed58b to f132f9a Compare October 22, 2026 16:33
@chubes4
chubes4 merged commit ea50488 into trunk Oct 22, 2026
12 checks passed
@chubes4
chubes4 deleted the studio-code/eval-stop-at branch October 22, 2026 16:54
@youknowriad

Copy link
Copy Markdown
Contributor

The routing cases fail on trunk with (vars.skills || []).filter is not a function. promptfoo expands an array var into one test per element, so skills reaches skillsLoadedFirst as a string, and [build-site, plugin-recommendations] runs as two separate tests. The unit test passes the array in directly, so it doesn't catch this.

Using objects the way followUps and answers do should fix it: skills: [{ name: hosting-plans-helper }], mapped to names in the check. The agent itself was fine in my run, it loaded hosting-plans-helper first.

chubes4 added a commit that referenced this pull request Oct 23, 2026
## Related issues

- Fixes the routing cases added in #5287, reported by @youknowriad in
#5287 (comment).

## Proposed Changes

promptfoo expands a var that is an array of plain values into one test
per element. The routing cases listed their skills as `skills:
[build-site, plugin-recommendations]`, so each ran as one test per
skill, and `skillsLoadedFirst` got a string and crashed on `.filter`.
Every `routing-*` case failed under `npm run eval`.

- `skills` is now a list of objects, `skills: [{ name: build-site }]`,
the same shape `followUps`, `answers` and `stopAt` already use, and
`skillsLoadedFirst` reads each entry's `name`.
- A new test in `outcome.test.mjs` fails when any list var in
`promptfoo.config.yaml` holds plain values, so this can't come back for
`skills` or a future var. It fails on trunk's config and passes here.
- The README documents the shape.

A correction to #5287: its testing instructions said `npm run eval --
--filter-pattern "^routing:"` runs the routing cases, and its 69/75
baseline could not have come from that command, since every case crashed
under it. The unit test passed the array to the check directly, so it
never saw promptfoo's expansion.

## Testing Instructions

- `npx vitest run scripts/eval/outcome.test.mjs`: 25 passed.
- `STUDIO_EVAL_MODEL=fast npm run eval -- --filter-pattern "^routing:"`:
15 test cases (one per routing case), 14 passed, 8m 34s. The one failure
is a real routing miss, not the harness: on `routing-events` the agent
loaded `edit-manage-site` and `block-content`, then created the page
with plain blocks without loading `plugin-recommendations`.
`routing-plan-question` loaded `hosting-plans-helper` first, as in the
run on #5287.

## Pre-merge Checklist

- [x] Have you checked for TypeScript, React or other console errors?

---

AI disclosure: Claude (Anthropic) in the Pi coding agent, via a Roadie
session directed by @chubes4, made the change, added the test and ran
the evals. @chubes4 reviewed the diff and the run.
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.

3 participants