refactor(providers): drop the chat-completions client - #55
Conversation
Co-Authored-By: Abhinav Pola <abhinav.pola@openrouter.ai>
Co-Authored-By: Abhinav Pola <abhinav.pola@openrouter.ai>
Original prompt from Abhinav
|
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Co-Authored-By: Abhinav Pola <abhinav.pola@openrouter.ai>
Co-Authored-By: Abhinav Pola <abhinav.pola@openrouter.ai>
Co-Authored-By: Abhinav Pola <abhinav.pola@openrouter.ai>
|
All six affected benchmarks complete against real OpenRouter at Each ran in CLI mode with one sample and no inference flags, through a logging forwarding proxy so request bodies could be read off the wire. 19 requests total, all on
ProofObserved — vision request body, showing {"path":"/api/v1/responses","model":"openai/gpt-4o-mini","stream":true,
"cache_control":{"type":"ephemeral"},
"input":[{"type":"message","role":"system","content":"You are a helpful assistant."},
{"type":"message","role":"user","content":[
{"type":"input_text","text":"Answer the following multiple choice question..."},
{"type":"input_image","detail":"auto","image_url":"https://datasets-server.huggingface.co/cached-assets/MMMU/MMMU_Pro/..."}]}]}Observed — tau3 banking, third Opus solver turn, showing chat-format tool definitions converted and the prior turn's call and result replayed as Responses items with matching {"path":"/api/v1/responses","model":"anthropic/claude-opus-4.8","stream":true,
"cache_control":{"type":"ephemeral"},"tool_count":16,
"input_item_types":["message","message","message","message","function_call","function_call_output"],
"function_call":{"type":"function_call","name":"KB_search","call_id":"toolu_014frKwSLWmj2S2SHZsz4vFo",
"arguments":"{\"query\": \"personal credit card cash back rewards no annual fee\"}"},
"function_call_output":{"type":"function_call_output","call_id":"toolu_014frKwSLWmj2S2SHZsz4vFo",
"output":"1. Business Gold Rewards Card: Premium Business Credit Card Overview..."}}Observed — airline produced 9 requests alternating solver (14 tools) and user simulator (0 tools), input items growing 2, 3, 4, 5, 7, 9, 11, with call and output items from turn 5 on. Banking produced 3 Opus solver calls and 3 Boundary — one sample per benchmark, so the scores are anecdotal, and the vision 0/1 is a wrong model answer rather than a harness error. This establishes that the harness sends the breakpoint, not that OpenRouter registered a cache hit, since the runs were cold and single-sample. The other Responses-backed benchmarks (terminal_bench, vgi_bench, search_*, swe_atlas, deep_swe, draco, wandr) were untouched by this change and were not rerun. |
Post-merge re-verification on
|
| benchmark | model | result |
|---|---|---|
| gpqa_diamond | openai/gpt-4o-mini | completed, accuracy 1.0 |
| mmlu_pro | openai/gpt-4o-mini | completed, accuracy 1.0 |
| mmmu_pro_vision | openai/gpt-4o-mini | completed (image sent, 25.7k input tokens); answered A vs target B → 0/1 |
| ifstruct | openai/gpt-4o-mini | completed, accuracy 1.0, schema match 100% |
| tau_bench_verified_airline | openai/gpt-4o-mini | completed, accuracy 0.0 (db_match=false) — model variance, see below |
| tau3_bench_banking | anthropic/claude-opus-4.8 | completed, accuracy 1.0, db+action+communicate all 1 |
Wire evidence — vision detail and Opus tool-calling
{"path":"/api/v1/responses","model":"openai/gpt-4o-mini","stream":true,"cache_control":{"type":"ephemeral"}}
{"type":"input_image","detail":"auto","image_url":"https://datasets-server.huggingface.co/cached-assets/MMMU/MMMU_Pro/..."}{"path":"/api/v1/responses","model":"anthropic/claude-opus-4.8","stream":true,
"cache_control":{"type":"ephemeral"},"tool_count":16,
"item_types":["message","message","message","message","function_call","function_call_output"],
"fc":{"name":"KB_search","call_id":"toolu_01UCMca9Qmov96yr8soe3AqA",
"arguments":"{\"query\": \"personal credit card cash back rewards annual fee\"}"},
"fco":{"type":"function_call_output","call_id":"toolu_01UCMca9Qmov96yr8soe3AqA",
"output":"1. Business Gold Rewards Card: Premium Business Credit Card Overview..."}}Why the airline score differs from the pre-merge run (not a regression)
The airline sample is the "agent must refuse a disallowed cancellation" task. In this run gpt-4o-mini actually called cancel_reservation, so db_match=false; in the earlier passing run it only called get_reservation_details + transfer_to_human_agents. A retry on main failed the same way, and running the pre-merge commit 3f771a4 as a control today also produced db_match=false, communicate_met=true, termination=USER_STOP. git diff 3f771a4 76ceb1a is 2 added package.json export lines and nothing else, and #53 was already an ancestor of the branch tip. So this is single-sample model nondeterminism on an adversarial task, not code. The request shapes were correct in all attempts.
Caveats
One sample per benchmark, so scores are anecdotal (the airline flake demonstrates this). Verified the harness sends cache_control; did not verify OpenRouter registered a cache hit. terminal_bench, vgi_bench, search_*, swe_atlas, deep_swe, draco, and wandr were not exercised.
TL;DR
The harness now speaks one wire protocol,
/v1/responses, so benchmark requests carry the ephemeralcache_controlbreakpoint the Responses client already sets, and the chat-shaped naming that outlived the chat transport is gone.What changed?
makeOpenRouterModelLayerkeeps its name and public export path, but is now an adapter overResponsesModel, so every solver reaches OpenRouter on/v1/responseswithstream: true.src/providers/messages-to-responses.ts, a pure mapper with no I/O, turning the harness's message history and chat-format tool definitions into Responses input items and mapping aResponsesTurnback toModelOutput. Tool-call identity is preserved by keying oncall_idrather than the Responses item id.responseItemsto the harness message type. Assistant items, including encrypted reasoning, replay verbatim on later turns instead of being flattened back into chat fields.ResponsesModelService, mapping their histories throughmessagesToResponsesso tool results go out asfunction_call_output. Airline's fallback, retry, and auxiliary usage behavior is unchanged.ResponsesRequestschema requiresdetailon aninput_imageitem, so the mapper now defaults it to"auto"when a content part doesn't specify one. Omitting it rejected every multimodal request client-side.ChatMessagetoModelMessage,chatMessagesToResponsestomessagesToResponses,defineChatBenchmarktodefineSingleTurnBenchmark,chatMessageToPojotomessageToPojo, plus the corresponding files. Parquet column keys and the pojo projection are untouched, so result files keep their existing shape.Why?
The
benchmark-always-opusarm oftau3-bench-bankingwas getting zero cached prompt tokens: 674 requests and 19,063,190 prompt tokens withnative_tokens_cachedat 0, about $103 burned in six hours. The harness called Switchyard on/chat/completions, and that chat-to-Responses translation dropped the caller's top-levelcache_control, while the same Opus endpoint caches at roughly 56% on Responses traffic generally. Routing the harness onto Responses keeps the breakpoint on the wire end to end rather than patching one route's config.How to test
Each run should reach
POST /api/v1/responseswithstream: trueandcache_control: {"type": "ephemeral"}in the body, and the vision run should senddetailon every image part.src/providers/responses-wire.test.tsvalidates the mapper's output against the SDK's outboundResponsesRequestschema through the same conversion production uses, covering text, vision with and without explicit detail, video, and a function-call cycle. That is the check the earlier source-text grep test failed to provide.Benchmark impact
Every previously chat-shaped benchmark changes wire shape, so its numbers are not strictly comparable to past runs. Those requests now stream and carry the default ephemeral
cache_control. Chat-shapedreasoning_detailsare no longer populated, since reasoning replays as Responses items instead. Affected:gpqa,mmlu_pro,mmmu_pro_vision,ifstruct,vgi_bench,tau_bench_verified_airline,tau3_bench_banking. Datasets, solvers, and scorers are otherwise unchanged.Reviewer focus
messages-to-responses.ts: whether the assistant branch's precedence of verbatimresponseItemsover synthesized content is right for multi-turn replay.call_idmatching across the mapped history.detailto"auto"is acceptable, given the chat path previously omitted it and let the API default.Checklist
Link to Devin session: https://openrouter.devinenterprise.com/sessions/f34bd5c90a0742829720956f5bb07bbe
Requested by: @abhinav-pola