Repository navigation
feat(evals): Record and replay eval model calls with Roach - #1972
Open
sentry-junior[bot] wants to merge 2 commits into
Open
sentry-junior[bot] wants to merge 2 commits into
sentry-junior[bot] wants to merge 2 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
dcramer
approved these changes
Nov 5, 2026
dcramer
approved these changes
Nov 5, 2026
dcramer
marked this pull request as ready for review
November 5, 2026 02:51
dcramer
added a commit
that referenced
this pull request
Nov 5, 2026
The Eval workflow on `main` reports green, but no evals have run. `eval:ci` fails at startup: ``` Failed to load custom Reporter from vitest-evals/reporter cause: Package subpath './reporters' is not defined by "exports" (ERR_PACKAGE_PATH_NOT_EXPORTED) ``` The cause is that vitest-evals 0.4.0 imports `vitest/reporters`, which vitest 5 removed. `continue-on-error` on "Run evals" hides the failure, so no `eval-results.json` gets written and the status check step throws. Example run: https://github.com/getsentry/toolkit/actions/runs/41951775819 This PR moves the eval package to vitest-evals 0.18.0, which supports vitest 5 (getsentry/vitest-evals#113, peer range `vitest >=5 <6`). The whole repo stays on vitest 5; there is no vitest 4 pin. ## Changes - **Bump `vitest-evals` to `^0.18.0`.** I added `vitest-evals@0.18.0` and its `@vitest-evals/core@0.18.0` and `@vitest-evals/report-ui@0.18.0` dependencies to `minimumReleaseAgeExclude`, because they were published today. Drop those entries once they are past the 24h window. - **Import from `vitest-evals/legacy`.** 0.18 keeps the scorer-first API (`describeEval` with `data`/`task`/`scorers`, `ToolCallScorer`, `Score`, `ScoreFn`, `BaseScorerOptions`) under `vitest-evals/legacy`. This is an import-path change only, in the 33 eval imports and the example in `docs/testing/overview.md`. The eval code is unchanged. - **Remove the unused root `vitest-evals` dev dependency.** Nothing at the root imports it. - **Set `SENTRY_CLI_NO_TELEMETRY=1` for the scorer's `sentry mcp` process.** - `ToolPredictionScorer` starts `pnpm --dir packages/cli run cli mcp` from source. On `main`, that process exits immediately with ``Package subpath './client' is not defined by "exports"``, and every scorer then fails with `MCPClientError: Connection closed`. - The exit comes from `lazyTelemetry()` in `src/lib/db/index.ts`. It loads `../telemetry.js` with `createRequire`, so its imports resolve `@sentry/api/client` under the `require` condition, but `@sentry/api` exports `./client` only for `import`. - Evals shouldn't send CLI telemetry anyway. The CLI bug itself is not fixed here: `pnpm --filter sentry run cli help` also fails from source. It needs its own CLI fix. `continue-on-error` and the eval status check are unchanged. ## Verification - **Local, no LLM key:** with no key in the sandbox, `pnpm eval:ci` on vitest 5.0.5 loads the reporter, collects and runs all 27 files and 121 evals, and writes `eval-results.json`. On `main` it stops at startup. Every eval failed, and the only cause was the missing provider key. No `Connection closed` errors. - **Checks:** `pnpm run tsc`, `pnpm run lint`, and `pnpm install --frozen-lockfile` pass. The full `pnpm run test` didn't finish inside my sandbox's time limit, so I'm relying on CI for it. ## Related - #1132 (draft, "Migrate to vitest-evals harness") moves these evals to the harness API. It touches the same eval files, so expect import conflicts there. This PR keeps the current scorer-first suite running until then. - #1972 (Roach recordings for evals) depends on this, because Roach records nothing while the suite doesn't run. Both PRs change `pnpm-lock.yaml` and `pnpm-workspace.yaml`, so #1972 needs a rebase after this merges. <!-- junior-request-attribution:start --> via @dcramer. <!-- junior-request-attribution:end --> <!-- junior-session-footer:start --> <!-- junior-conversation-id:agent%3A1de0f02c391e347294cc7ce28353bcfe --> -- [View Session](https://junior-prod.sentry.dev/conversations/agent%3A1de0f02c391e347294cc7ce28353bcfe) [[Sentry]](https://sentry.sentry.io/explore/conversations/agent%3A1de0f02c391e347294cc7ce28353bcfe/?project=4510944073809921) <!-- junior-session-footer:end --> Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: David Cramer <23610+dcramer@users.noreply.github.com>
The MCP evals call OpenRouter on every run. Roach, Sentry's shared recording proxy, now sits in front of those calls: it replays a call it has a recording for, and records the rest when the run has ROACH_TOKEN. The setup is config only: roach.json names the OpenRouter host and one rule for its API, vitest.config.ts adds the Roach global setup and setup file, and the Eval workflow passes ROACH_TOKEN and moves to Node 24, which Roach needs. Fork PRs get no secrets, so they only replay. The Roach setup file loads before setup-env.ts so that MSW does not catch Roach's own control calls. That needs getsentry/roach#30. Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
Point @sentry/roach at getsentry/roach@efa6885 (packages/roach) through a pnpm git dependency, so CI can test record and replay before the next Roach release. pnpm runs the package's prepack for git dependencies, so allowBuilds lists the exact tarball. Drop this commit and set the catalog to the released version before merging. Co-Authored-By: David Cramer <23610+dcramer@users.noreply.github.com>
sentry-junior
Bot
force-pushed
the
feat/roach-evals
branch
from
November 5, 2026 04:47
c44947f to
bbc5c92
Compare
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The MCP evals (
packages/mcp-server-evals) call OpenRouter on every run. This sends those calls through Roach, Sentry's shared record/replay proxy. CI replays recorded calls and records only the new ones.The change is config only, in the same shape as getsentry/warden#564:
roach.jsonsets tenantgetsentry/toolkit, allowshttps://openrouter.ai, and has onemodelrule forPOST https://openrouter.ai/api/v1/. It has novaluespatterns. Through a local Roach, I sent the requests the evals build twice: twosearch_eventsembedded-agent calls and the first call ofMcpToolCallTaskRunner. Both runs gave byte-identical bodies and the same keys, and the second run replayed all of them. The tool outputs that feed later steps (get_issue_details,get_trace_detailsfrom the MSW fixtures) were also identical when I called them a minute apart. I could not capture the tool-prediction scorer's request, because its tool discovery crashes locally (see below). Its prompt comes from the static tool list. The API key travels inAuthorization, which Roach redacts on its own, so there is nosecretEnv.vitest.config.tsadds the Roach global setup and setup file. The Roach setup file goes beforesrc/setup-env.ts, so MSW, which throws on unhandled requests, does not catch Roach's own session calls.eval.ymlpassesROACH_TOKENto the eval step and moves the job to Node 24, because Roach needs 24.14+. The workflow runs onpull_request, notpull_request_target, so fork PRs get no secrets and stay replay-only. The fork policy does not change.@sentry/roach0.2.0 is in the catalog, and inminimumReleaseAgeExcludebecause it was published today. Theagentspeer line in the lockfile is pnpm 11.8.0's own output after adding the package.docs/testing/overview.mdhas a short "Eval Recordings" section.Blockers before merge
Roach POST session failed with HTTP 500: Unhandled request. I reproduced this against the live service. With that fix applied locally, a replay run with no token against the live service fails cleanly with 412 misses, as expected. After the release, bump the catalog entry and drop theminimumReleaseAgeExcludeline. fix(vitest): Allow off mode on Node before 24.14 roach#31, which letsROACH_MODE=offrun on Node 22, is a nice-to-have for local runs on toolkit's Node 22 minimum.ROACH_TOKENaccess.getsentry/toolkitmust be added to the selected repositories of theROACH_TOKENorg secret, and an org admin has to do that. Without it, CI runs replay-only and records nothing.main.vitest-evals0.4.0 does not work with vitest 5. The reporter fails to load (Package subpath './reporters' is not defined), anddescribeEvalthrows at collection. The latestvitest-evalsstill peersvitest <5.continue-on-errorhides this, and the Eval run onmainreports success with no results file. Roach records nothing until the evals run again; test(evals): Migrate to vitest-evals harness #1132 may be the path. Also,ToolPredictionScorer's tool discovery (sentry mcpunder tsx) crashes locally withPackage subpath './client' is not defined by "exports"from@sentry/api. That happens with and without Roach.via @dcramer.
--
View Session [Sentry]