Minimal, deterministic reproduction — no network call, no API key. It shows that the
OpenRouter adapter's function-tool converter discards a tool's metadata.cacheControl, so
Anthropic prompt caching of tool definitions can never reach the wire.
npm install
node repro.mjs1) converter output: {"type":"function","function":{...}} <- no cacheControl (BUG)
2) serialized wire tool: {"function":{...},"type":"function"} <- no cache_control (consequence)
3) wire tool WITH forward: {"cache_control":{"type":"ephemeral"},"function":{...}} <- present once forwarded
- (1)
convertToolsToProviderFormatnever readstool.metadata.cacheControl, so the marker is gone before serialization. - (2) Running the request through the SDK's
ChatRequest$outboundSchemaconfirms nothing reaches the wire. - (3) Manually adding
cacheControl(camelCase) to the converter output makes the SDK emitcache_control— proving the@openrouter/sdkalready supports it and the converter is the only gap. (Snake_casecache_controlis stripped by the SDK's outbound schema, so the camelCase key is required.)
@tanstack/ai-anthropic's convertCustomToolToAdapterFormat already forwards metadata.cacheControl; ai-openrouter should match.
@tanstack/ai 0.34.0 · @tanstack/ai-openrouter 0.14.2 · @openrouter/sdk 0.12.35 · Node v24