feat(providers): enable OpenRouter response caching with per-epoch salts - #24
feat(providers): enable OpenRouter response caching with per-epoch salts#24abhinav-pola wants to merge 7 commits into
Conversation
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:
|
…ource generation ids Co-Authored-By: Abhinav Pola <abhinav.pola@openrouter.ai>
Co-Authored-By: Abhinav Pola <abhinav.pola@openrouter.ai>
…e recording Co-Authored-By: Abhinav Pola <abhinav.pola@openrouter.ai>
Co-Authored-By: Abhinav Pola <abhinav.pola@openrouter.ai>
…stay independent Co-Authored-By: Abhinav Pola <abhinav.pola@openrouter.ai>
Co-Authored-By: Abhinav Pola <abhinav.pola@openrouter.ai>
TL;DR
Every OpenRouter request now opts into response caching with a per-epoch cache salt, so Temporal activity restarts replay cached responses instead of paying for regeneration, and parquets record only real generation IDs (cache-hit dummies are resolved back to their source generation).
What changed?
src/runtime/response-cache.ts: harness-wide constants and salt plumbingx-openrouter-cache: truecache_salt="<sessionId>:epoch-<N>[:attempt-<K>]"(unknown fields are hashed into the cache key server-side but stripped before the provider)withRetryAttemptSaltappends:attempt-<K>for in-process retries only, so a cached response the harness rejects (e.g. invalid user-sim content) is not replayed on retry, while attempt 0 stays deterministic for Temporal restartssrc/runtime/generation-ids.ts: the collector now flags IDs whose response carriedx-openrouter-cache-status: HITsrc/runtime/generation-resolver.ts(new): on cache hits, the recorded dummy generation ID is resolved to the original viaGET /api/v1/generation?id=<dummy>→data.response_cache_source_id, polling (default 12 × 5s) because the dummy row lands asynchronously; on timeout/failure the dummy ID is kept and a warning is loggedsrc/harness/run.tsresolves collected IDs before building the sample score, so parquetgeneration_idscontain only real/original generation IDssrc/runner/run-by-id.tsprovides the resolver layer from the run'sapiKey/baseUrl; the resolver is an optional service, so library consumers without it keep current behaviorWhy?
Benchmark activities restart under Temporal and previously re-generated every completed sample at full cost. Response caching makes restarts free, the epoch salt keeps epochs from sharing cache entries without touching
x-session-id, and resolvingresponse_cache_source_idkeeps parquets pointing at real generations (cache-hit rows are zeroed dummies withendpoint_idniled out).How to test
bun run format:check && bun run check && bun run typecheck && bun test && bun run build(all green, 1209 tests)src/runtime/generation-resolver.test.ts(endpoint lookup, polling until row lands, failure fallback, hit-only resolution),src/runtime/response-cache.test.ts,src/runtime/generation-ids.test.tsBenchmark impact
Reviewer focus
src/runtime/response-cache.tssrc/runtime/generation-resolver.ts(keeps the dummy ID if the source never resolves)Checklist
Link to Devin session: https://openrouter.devinenterprise.com/sessions/627adb18f0f54821b186e701d6b7fa22
Requested by: @abhinav-pola