fix(bench): record the effective search request body - #114
jamespsterling wants to merge 2 commits into
Conversation
…effective search request Move stripVariantSuffix into an Effect-free module so BenchmarkRunConfigSchema can load inside the Temporal workflow sandbox, which rejects the frozen-global write effect/Context performs on import. Persist the switchyard plugin in the search solver's recorded requestBody so the stored request matches what was sent. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
I'll fix CI failures and address comments from users with write access that start with 'DevinAI' or '@devin'.
Original prompt from James
|
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
There was a problem hiding this comment.
⚠️ The maintainer app is not installed onOpenRouterTeam, so Perry cannot post an APPROVE. This review is a COMMENT with a full LGTM assessment — a human should approve.
Perry's Review
Verdict: ✅ LGTM
Risk: 🟢 Low
Risk assessment
| Dimension | Severity | Risk | Reasoning |
|---|---|---|---|
| Implementation risk | 🟩 | Low | One-line addition: completedState spreads extraBody into requestBody, matching how mergeExtraBody applies it on the wire. Test verifies the stored body equals the sent body plus extraBody. |
| Premise risk | 🟩 | Low | The premise — stored runs should reflect what was actually sent, including the Switchyard plugin — is correct and well-motivated by the linked openrouter-web review. |
| Estimated impact | 🟩 | Low | Only affects the stored requestBody field; the wire request is unchanged. Worst case is a stale requestBody that omits plugins, which was the pre-PR state. |
| Risk Factor | Severity | Risk | Reasoning |
|---|---|---|---|
| Reversibility | 🟩 | Low | The previous state can be fully restored by reverting the one line. |
| Detectability | 🟩 | Low | Tests assert the new behavior; any regression would fail the test suite. |
| Blast radius | 🟩 | Low | Affects only the search solver's requestBody storage field. |
| Data integrity | 🟩 | Low | No persisted data is corrupted; requestBody is a diagnostic record. |
| Financial exposure | None | No billing or payment paths touched. | |
| Security and privacy exposure | None | No credentials or sensitive data in requestBody. |
|
| Propagation | 🟩 | Low | Downstream consumers of requestBody (parquet export, run results) read it as opaque JSON. |
| Availability | None | The change cannot affect serving. | |
| Recovery cost | 🟩 | Low | Reverting restores the prior behavior with no data migration. |
| Time to correct | 🟩 | Low | A one-line revert if needed. |
Analysis
The fix is clean and correct. searchSolver builds extraBody containing the Switchyard router plugin via switchyardExtraBody(), passes it to responses.send() as options.extraBody, and mergeExtraBody in the responses client spreads it into the wire request. However, completedState was recording requestBody: { ...request } — without extraBody — so stored runs lost the plugins field. This PR threads extraBody through to completedState and spreads it after request, so requestBody now matches the effective sent body.
When extraBody is undefined (no Switchyard algorithm set), { ...request, ...undefined } is identical to { ...request } — so non-Switchyard runs are byte-identical. When extraBody has a plugins key, it correctly overrides request.plugins because switchyardExtraBody already includes the existing wire plugins (extracted via responsesRequestToJSON) plus the Switchyard plugin, so nothing is lost.
The test captures the sent body and asserts state.requestBody equals { ...sent, ...sentOptions?.extraBody }, which directly verifies the fix.
CI
All checks pass — validate (CI), CodeQL (actions + javascript-typescript), and Devin Review.
TL;DR
The search solver's recorded
requestBodynow includes the Switchyard plugin it sent, so stored runs show which algorithm was requested.What changed?
src/benchmarks/search/core/solver.ts:completedStatepersists{ ...request, ...extraBody }asrequestBody; the request handed toresponses.sendis unchanged.src/benchmarks/search/core/solver.test.ts: the plugin-order test also assertsstate.requestBodyequals the sent body plusextraBody.The
effect/Contextfix this PR originally carried (movingstripVariantSuffixinto an Effect-free module) landed onmainin #116 (stripVariantSuffixnow lives inharness/constants.ts), so the merge ofmain(72f82c9) dropped this branch'smodel-slug.tscopy and its./model-slugpackage export.Why?
Follow-up to #109 found in review of openrouter-web#46340:
searchSolversent the Switchyard plugin throughextraBodybut recordedrequestBodywithout it, so stored runs did not show which algorithm was requested.How to test
bun test src/benchmarks/search/core/solver.test.tsExpected: all pass, including
state.requestBodyequal to the sent body plusextraBody.How to test in prod
This repo ships to production through the openrouter-web subtree copy (
packages/bench-harness) and the benchmark worker deploy, so verify after the next subtree pull and worker deploy.switchyardAlgorithmset storesplugins: [{ "id": "switchyard-router", "algorithm": "<algorithm>" }]in each sample'srequestBody; a run without it stores nopluginskey.search_hlerun withmodel: "nvidia/switchyard",models: ["openai/gpt-6-astra", "google/gemini-3.1-pro"],switchyardAlgorithm: "stage",limit: 2through the benchmark start endpoint or thebench runCLI.requestBody.pluginson any sample.requestBody.pluginscontains theswitchyard-routerentry withalgorithm: "stage"; the scored answer and cost fields are unchanged from a run on the previous commit.requestBody.pluginsmissing on a Switchyard run, or any search run failing atcompletedStatewith a serialization error.Benchmark impact
None to scores. Search runs now store the
pluginsarray inrequestBodywhen aswitchyardAlgorithmor web-search plugin is set; runs with neither are byte-identical.Reviewer focus
completedStatespreadsextraBodyafterrequest, matching how the SDK appliesextraBodyon send.mainis the two solver files only.Checklist
Link to Devin session: https://openrouter.devinenterprise.com/sessions/37ef700865744be284bb0127c4f6a8d0
Open in Devin Desktop: https://openrouter.devinenterprise.com/desktop/session/37ef700865744be284bb0127c4f6a8d0?variant=devin
Requested by: @jamespsterling