Skip to content

fix(bench): record the effective search request body - #114

Open
jamespsterling wants to merge 2 commits into
mainfrom
devin/1790265311-workflow-safe-variant-strip
Open

jamespsterling wants to merge 2 commits into
mainfrom
devin/1790265311-workflow-safe-variant-strip

Conversation

@jamespsterling

@jamespsterling jamespsterling commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR

The search solver's recorded requestBody now includes the Switchyard plugin it sent, so stored runs show which algorithm was requested.

What changed?

  • src/benchmarks/search/core/solver.ts: completedState persists { ...request, ...extraBody } as requestBody; the request handed to responses.send is unchanged.
  • src/benchmarks/search/core/solver.test.ts: the plugin-order test also asserts state.requestBody equals the sent body plus extraBody.

The effect/Context fix this PR originally carried (moving stripVariantSuffix into an Effect-free module) landed on main in #116 (stripVariantSuffix now lives in harness/constants.ts), so the merge of main (72f82c9) dropped this branch's model-slug.ts copy and its ./model-slug package export.

Why?

Follow-up to #109 found in review of openrouter-web#46340: searchSolver sent the Switchyard plugin through extraBody but recorded requestBody without it, so stored runs did not show which algorithm was requested.

How to test

bun test src/benchmarks/search/core/solver.test.ts

Expected: all pass, including state.requestBody equal to the sent body plus extraBody.

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.

  • What to verify: a search benchmark run with switchyardAlgorithm set stores plugins: [{ "id": "switchyard-router", "algorithm": "<algorithm>" }] in each sample's requestBody; a run without it stores no plugins key.
  • Steps:
    1. Start a search_hle run with model: "nvidia/switchyard", models: ["openai/gpt-6-astra", "google/gemini-3.1-pro"], switchyardAlgorithm: "stage", limit: 2 through the benchmark start endpoint or the bench run CLI.
    2. Open the run's sample results and read requestBody.plugins on any sample.
  • Expected: requestBody.plugins contains the switchyard-router entry with algorithm: "stage"; the scored answer and cost fields are unchanged from a run on the previous commit.
  • Rollback signal: requestBody.plugins missing on a Switchyard run, or any search run failing at completedState with a serialization error.

Benchmark impact

None to scores. Search runs now store the plugins array in requestBody when a switchyardAlgorithm or web-search plugin is set; runs with neither are byte-identical.

Reviewer focus

  • completedState spreads extraBody after request, matching how the SDK applies extraBody on send.
  • Net diff against main is the two solver files only.

Checklist

  • Tests cover changed behavior
  • Public API or configuration changes are backward compatible, or the break is documented
  • Benchmark changes document dataset provenance and licensing (n/a)
  • No credentials, private results, or restricted dataset contents are included
  • Documentation is updated where needed (n/a)

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


Devin Review

…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>
@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access that start with 'DevinAI' or '@devin'.

  • Disable automatic comment, CI, and merge conflict monitoring

Original prompt from James

Analyze this session: @devin-session:devin-9b303b51c68b4f74a224b28cefa855ae

@devin-ai-integration
devin-ai-integration Bot marked this pull request as ready for review September 25, 2026 03:43
@devin-ai-integration
devin-ai-integration Bot requested a review from a team as a code owner September 25, 2026 03:43

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Devin Review

perry-the-pr-reviewer[bot]

This comment was marked as resolved.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration devin-ai-integration Bot changed the title fix(bench): keep effect/Context out of config schemas and record the effective search request fix(bench): record the effective search request body Sep 25, 2026

@perry-the-pr-reviewer perry-the-pr-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ The maintainer app is not installed on OpenRouterTeam, 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.

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