<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: DHPP</title>
    <description>The latest articles on DEV Community by DHPP (@dhpp).</description>
    <link>https://dev.to/dhpp</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2207535%2Fd5f493e8-3734-4e7e-aca1-fc32040c191a.png</url>
      <title>DEV Community: DHPP</title>
      <link>https://dev.to/dhpp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dhpp"/>
    <language>en</language>
    <item>
      <title>Saving 50-70% on Coding Agent Bills: Protecting Prompt Cache Affinity with VMR</title>
      <dc:creator>DHPP</dc:creator>
      <pubDate>Tue, 18 Aug 2026 16:19:17 +0000</pubDate>
      <link>https://dev.to/dhpp/saving-50-70-on-coding-agent-bills-protecting-prompt-cache-affinity-with-vmr-3d2j</link>
      <guid>https://dev.to/dhpp/saving-50-70-on-coding-agent-bills-protecting-prompt-cache-affinity-with-vmr-3d2j</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — With per-token pricing now the default everywhere, the biggest line item in a coding-agent bill is usually not "smart model" but &lt;strong&gt;repetition bought at full price&lt;/strong&gt;. Modern providers (Anthropic, DeepSeek, OpenAI) charge 10-20% for a cache hit on a repeated input prefix. The winning move is not making your prompts smaller — it's making sure your multi-turn session never leaves the upstream endpoint where its cache is warm. In our long-session load tests (150 req/s), pinning sessions with sticky routing took cache-hit rate from "luck" to 80-95% and cut the bill 50-70% (self-observed, not third-party audited).&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem: your router is the reason your cache is cold
&lt;/h2&gt;

&lt;p&gt;Here's the counterintuitive part. If you run a coding agent (Claude Code, Cursor, OpenClaw — anything with long multi-turn context), and you configured &lt;strong&gt;multiple API keys or providers&lt;/strong&gt; for resilience, your gateway is very likely &lt;strong&gt;killing your cache on every round&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Prompt cache is &lt;strong&gt;isolated per upstream endpoint&lt;/strong&gt; — per account, per physical node. When your load balancer round-robins request #1 to account A, #2 to account B, #3 back to A, every round looks like a brand-new session to every account. Nothing ever hits. Everything is billed at full price, including the 90% of tokens that were already computed in earlier rounds.&lt;/p&gt;

&lt;p&gt;Worse: the classic gateway scheduling algorithms — smooth weighted round-robin, greedy quota balancing — are &lt;em&gt;designed&lt;/em&gt; to spread traffic evenly. Cache locality wants the exact opposite: &lt;strong&gt;traffic pinned&lt;/strong&gt;. In long sessions, "fair" and "cheap" are mutually exclusive.&lt;/p&gt;

&lt;h2&gt;
  
  
  The insight: cache economics beats token compression
&lt;/h2&gt;

&lt;p&gt;Two routes dominate the "make agents cheaper" space, and they rest on opposite assumptions about how upstream billing works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local compression (e.g. OpenProxy's RTK)&lt;/strong&gt;: assumes upstream is stateless and bills everything full-price, so shrink the payload — re-encode tables, inject terse-output instructions, prune tool schemas. Claims 20-40% savings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache-affinity protection (VMR)&lt;/strong&gt;: assumes upstream is stateful — that 90% of long-session cost is determined by prompt cache. So touch nothing, keep the byte prefix identical, and pin the session to one endpoint so the repeated prefix &lt;em&gt;keeps&lt;/em&gt; hitting the discounted tier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The conflict is structural: &lt;strong&gt;every compression "help" breaks the cache&lt;/strong&gt;. Dynamic re-encoding, injected instructions, schema pruning — each change invalidates the prefix hash from token zero. In a 30-round session, compressing 30% of tokens doesn't compensate for re-paying the full price of 29 rounds of accumulated context. The mechanism-level conclusion: in cache-enabled 2026, compression can make you &lt;em&gt;more&lt;/em&gt; expensive.&lt;/p&gt;

&lt;p&gt;(To be fair: OpenProxy is a genuinely broader tool — OAuth subscription pooling for ChatGPT/Codex/Gemini, a real web UI, hedging and fusion scheduling, MCP/multimodal extensions. The critique above is specifically about RTK compression in long sessions, not the project as a whole.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: session-sticky routing, in two layers
&lt;/h2&gt;

&lt;p&gt;VMR's sticky registry (&lt;code&gt;internal/sticky/sticky.go&lt;/code&gt;) is an in-memory map from a session fingerprint to the endpoint that last served it. The fingerprint is a hash of &lt;strong&gt;system prompt + first user message&lt;/strong&gt; — deliberately not the client session ID, because clients (especially agent frameworks) regenerate IDs on restart while the cache prefix is determined by content.&lt;/p&gt;

&lt;p&gt;Routing has two layers, highest priority first:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Sticky Pin&lt;/strong&gt; — if the fingerprint is in the registry and the endpoint is healthy, force the request back to it. This outranks &lt;em&gt;all&lt;/em&gt; quota scheduling. Even if that account's quota is exhausted, we keep the session pinned and eat the overage, because switching mid-session zeroes the cache and the recompute cost of tens of rounds is an order of magnitude larger than a short overage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New-session spread&lt;/strong&gt; — only sessions with no sticky binding participate in scheduling. After &lt;code&gt;priority&lt;/code&gt; sorting ties, assign greedily by quota slack. Notably, we do &lt;strong&gt;not&lt;/strong&gt; use SWRR: it needs a persistent accumulator, and spreading traffic is itself anti-cache-locality. A fresh session picks an endpoint once; layer 1 holds it there.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two engineering details worth stealing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TTL is tiered.&lt;/strong&gt; Global &lt;code&gt;sticky_ttl&lt;/code&gt; defaults to 10m (fine for Anthropic/OpenAI memory caches), hard-capped at 24h by a memory-eviction backstop so the registry can't grow unbounded. Disk-cached providers like DeepSeek keep caches for hours-to-days — override per-endpoint (&lt;code&gt;sticky_ttl: 2h&lt;/code&gt;) to match cache lifetime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry sweep is opportunistic&lt;/strong&gt;, not a ticker goroutine — event-triggered and throttled, avoiding a global lock walk on every call.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What it looks like
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;models&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;coding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;tools&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;max_context_tokens&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;256000&lt;/span&gt;
    &lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openai&lt;/span&gt;
        &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deepseek&lt;/span&gt;
        &lt;span class="na"&gt;models&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;deepseek-v4-flash&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;sticky_ttl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2h&lt;/span&gt;   &lt;span class="c1"&gt;# disk cache lives hours-to-days; match it&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anthropic&lt;/span&gt;
        &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anthropic&lt;/span&gt;
        &lt;span class="na"&gt;models&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;claude-sonnet-5&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# sticky_ttl: 10m (default)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Client points at &lt;code&gt;http://localhost:8080/v1&lt;/code&gt; (or &lt;code&gt;/v1/messages&lt;/code&gt; for the Anthropic protocol), model name = your virtual model. Same session, same endpoint, every round.&lt;/p&gt;

&lt;p&gt;Same-session trace before → after (illustrative micro-numbers within realistic ranges):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;before  req#0127  endpoint=deepseek-01   cache_hit=0    input=185K  cost=$0.41
before  req#0128  endpoint=anthropic-02  cache_hit=0    input=199K  cost=$1.86
before  req#0129  endpoint=deepseek-01   cache_hit=0    input=213K  cost=$0.47

after   req#0127  endpoint=deepseek-01   cache_hit=182K  input=185K  cost=$0.03
after   req#0128  endpoint=deepseek-01   cache_hit=195K  input=199K  cost=$0.04
after   req#0129  endpoint=deepseek-01   cache_hit=208K  input=213K  cost=$0.04
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pin the session, and the accumulated context stops being re-bought at full price.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-offs we accepted
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No global quota-optimal scheduling.&lt;/strong&gt; A perfect scheduler that preserves cache &lt;em&gt;and&lt;/em&gt; shuffles quota between sessions is possible in theory, but needs persistent state and prediction. For an individual developer, the complexity-to-bug ratio isn't worth it. Session-local lock + inter-session greedy is the pragmatic optimum.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No hedging.&lt;/strong&gt; Firing the same request at two providers and taking the faster one adds latency insurance but doubles full-price consumption and breaks the cache. Negative expected value for personal use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TTL granularity is coarse.&lt;/strong&gt; 10m is conservative for very long sessions; we ship per-endpoint overrides instead of adaptive TTLs. Known future work.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A 3-step checklist for your setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check your cache-hit rate first.&lt;/strong&gt; Look at &lt;code&gt;cache_read&lt;/code&gt; vs &lt;code&gt;fresh&lt;/code&gt; in your billing/status output. Below ~50% on long sessions means your config is leaking money — fix that before any other optimization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop spreading sessions across keys.&lt;/strong&gt; If your tool supports session affinity, turn it on. If not, assign one key per long session manually and let failover handle only real outages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the system prompt byte-stable.&lt;/strong&gt; Dynamic injection (timestamps, random vars) invalidates the prefix on every request. And if you use a "compressing" proxy, know that it's trading cache hits for shorter payloads — usually a bad trade in long sessions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Self-hosted, zero-database, one static binary (~15MB, Go). If that sounds like your kind of tool, VMR is open source at &lt;a href="https://github.com/bigfatsea/vmr" rel="noopener noreferrer"&gt;https://github.com/bigfatsea/vmr&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Data caveat: the 50-70% figure is from our own long-session load tests and project records, not third-party audited. Actual savings depend on provider cache pricing — DeepSeek-class disk caches give the biggest wins.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>openclaw</category>
      <category>apigateway</category>
    </item>
    <item>
      <title>Why Your Coding Agent Doesn't Need an Electron App: A Minimalist LLM Proxy in Go</title>
      <dc:creator>DHPP</dc:creator>
      <pubDate>Tue, 18 Aug 2026 08:21:35 +0000</pubDate>
      <link>https://dev.to/dhpp/why-your-coding-agent-doesnt-need-an-electron-app-a-minimalist-llm-proxy-in-go-4hpg</link>
      <guid>https://dev.to/dhpp/why-your-coding-agent-doesnt-need-an-electron-app-a-minimalist-llm-proxy-in-go-4hpg</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR (the bottom line, up front)
&lt;/h2&gt;

&lt;p&gt;Your coding agent (Claude Code, Cursor, Codex, ...) doesn't need a dashboard. It needs a &lt;strong&gt;transparent, self-healing, low-overhead pipe&lt;/strong&gt; between its SDK and a pool of LLM providers — because at 3 AM, when the agent is running unattended, nobody is there to click a button.&lt;/p&gt;

&lt;p&gt;That's why we built &lt;a href="https://github.com/bigfatsea/vmr" rel="noopener noreferrer"&gt;VMR&lt;/a&gt;: a local, single-binary LLM router in Go.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;~31K lines of Go, 4 direct dependencies&lt;/strong&gt;, ships as one static binary (~12–15MB)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero database, zero web UI, zero Node/Python runtime&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Byte-faithful pass-through&lt;/strong&gt;: requests arrive upstream byte-identical to a direct connection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Session-sticky cache affinity&lt;/strong&gt;: keeps long conversations on the same endpoint, protecting upstream Prompt Cache (we observe 85–95% hit rates, ~50–70% cost reduction on cache discounts — self-measured, not third-party audited)&lt;/li&gt;
&lt;li&gt;From our benchmark (Apple M1): routing overhead &lt;strong&gt;+0.3–0.9ms p50&lt;/strong&gt;; RSS &lt;strong&gt;15MB&lt;/strong&gt;; cold start &lt;strong&gt;~60ms&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post is the design reasoning behind the minimalist bet. No hype, just the decision chain.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. The problem: agent traffic is server traffic, not desktop traffic
&lt;/h2&gt;

&lt;p&gt;Two nights pushed us here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Night one was the bill.&lt;/strong&gt; After wiring Claude Code / Cursor to multiple providers (Anthropic, DeepSeek, MiniMax, OpenRouter...), I started with the naive approach — hardcode different Base URLs per provider. It fell apart fast. Agent sessions are long-context, high-frequency round-trips. The moment a subagent switch slightly perturbs the request body, the provider's Prompt Cache key misses, and the cost climbs visibly. I was bouncing between "one provider's bill" and "another provider's queue time."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Night two was the outage.&lt;/strong&gt; A batch refactor was supposed to run for ~an hour unattended. An upstream key hit 429, the proxy wedged, and by morning the task had died with progress lost.&lt;/p&gt;

&lt;p&gt;Both nights pointed the same direction: &lt;strong&gt;the proxy layer has to be designed for unattended operation&lt;/strong&gt; — self-healing, self-retrying, and always leaving evidence — not for human dashboard-watching.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. What we looked at (and why we walked away)
&lt;/h2&gt;

&lt;p&gt;I'm not going to pretend we didn't consider "fuller" solutions. We did, and they're genuinely good at what they do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LiteLLM-class translation gateways&lt;/strong&gt;: huge coverage, but also huge complexity. The "all protocols → internal format → target protocol" translation layer is something you maintain forever as upstream event formats evolve. For a solo maintainer, that's a real tax.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Electron/desktop control planes (e.g. Claude Code Router)&lt;/strong&gt;: deep, well-made — agent profiles, tool markets, Web UI. For our use case it was a drinking fountain built to get a glass of water. We wanted the invisible, non-invasive layer only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardcoded Base URLs + manual switching&lt;/strong&gt;: simplest, but no failover, no health probing, no audit trail. At 3 AM nobody is switching anything manually.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They serve different audiences. The question we kept asking, which became VMR's standing review rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every new feature, ask: does this add capability, or does it add complexity?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By that test, dashboards, user management, billing, prompt management, plugin systems, and MCP frameworks all got rejected at the door. Useful? Yes. Complexity-adders for the "be a transparent base for coding agents" mission? Also yes.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Three constraints that pushed us to Go + a single binary
&lt;/h2&gt;

&lt;p&gt;Not "Go for the sake of Go." Three constraints stacked:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Unattended = server-traffic semantics.&lt;/strong&gt; High concurrency, long sessions, zero supervision. The proxy must be low-latency, high-throughput, and self-healing. This workload is closer to a reverse proxy / load balancer than a desktop GUI. Go's goroutine model, its server-grade GC behavior, and single-file cross-compilation make it the cheapest fit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Byte-level fidelity keeps you compatible with upstream.&lt;/strong&gt; LLM providers ship new params and event types fast. If your proxy does &lt;code&gt;JSON.parse → mutate → stringify&lt;/code&gt; on every request, any unknown field is theoretically at risk of being reordered, escaped, or dropped. The only way to make "new upstream features work the day they ship, without waiting for a VMR release" is to &lt;strong&gt;not touch any byte we don't need to touch&lt;/strong&gt;. Go's &lt;code&gt;json.RawMessage&lt;/code&gt; makes this clean.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Solo maintenance = fewer dependencies = safer.&lt;/strong&gt; Four Go module deps vs a 50+ npm package tree + Electron + React. Supply-chain surface, audit cost, build time — all orders of magnitude apart. For a solo project, "I can write this with only the standard library" is a survival advantage.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Byte-faithful pass-through (not "good-enough" pass-through)
&lt;/h2&gt;

&lt;p&gt;"Byte-faithful" is not marketing copy in VMR. Three concrete mechanisms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// 1) json.RawMessage: keep the whole request body raw; parse only model/stream&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;CanonicalRequest&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Model&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Stream&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;Raw&lt;/span&gt;    &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RawMessage&lt;/span&gt; &lt;span class="c"&gt;// every other byte passes through untouched&lt;/span&gt;
    &lt;span class="n"&gt;Header&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;
    &lt;span class="n"&gt;Facts&lt;/span&gt;  &lt;span class="n"&gt;RequestFacts&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// 2) MarshalNoEscape: refuse Go's default HTML escaping.&lt;/span&gt;
&lt;span class="c"&gt;// Default json.Marshal turns "&amp;lt;div&amp;gt;" into "\u003Cdiv\u003E" — semantically&lt;/span&gt;
&lt;span class="c"&gt;// equal, byte-different. VMR cares about bytes.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;MarshalNoEscape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffer&lt;/span&gt;
    &lt;span class="n"&gt;enc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetEscapeHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;enc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TrimSuffix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// 3) Byte-level model rewrite: scan bytes, replace the "model" key's value.&lt;/span&gt;
&lt;span class="c"&gt;// No JSON unmarshal, no object round-trip. Key order, whitespace, unknown&lt;/span&gt;
&lt;span class="c"&gt;// fields stay exactly as the client sent them.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;RewriteModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;realModel&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;/* byte-level state machine */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VMR never unpacks the request body into an object. &lt;code&gt;json.RawMessage&lt;/code&gt; is a zero-copy byte container; the &lt;code&gt;model&lt;/code&gt; substitution is pure string manipulation. That's why &lt;code&gt;go.mod&lt;/code&gt; stays at four deps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;github.com/fsnotify/fsnotify  → config hot-reload
github.com/klauspost/compress → zstd audit-log compression
golang.org/x/image            → image downscale
gopkg.in/yaml.v3              → config parsing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No ORM, no web framework, no DI container, no logging library. HTTP uses &lt;code&gt;net/http&lt;/code&gt;; logging uses &lt;code&gt;log&lt;/code&gt;. ~31K lines of Go, one static binary.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Why we refuse cross-protocol translation
&lt;/h2&gt;

&lt;p&gt;VMR exposes both an OpenAI and an Anthropic entrance, but routes each &lt;strong&gt;within its own protocol family&lt;/strong&gt; — it never translates between them. This is a stance, not a gap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SSE event semantics can't be losslessly mapped.&lt;/strong&gt; Anthropic's &lt;code&gt;message_start&lt;/code&gt;/&lt;code&gt;content_block_delta&lt;/code&gt;/&lt;code&gt;tool_use&lt;/code&gt; stream vs OpenAI's &lt;code&gt;choices[0].delta.tool_calls[]&lt;/code&gt; chunks — every new event type upstream adds is another patch to the translation layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forward compatibility breaks.&lt;/strong&gt; New upstream event type → translation layer doesn't know it → dropped or error. Byte pass-through is natively forward-compatible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mainstream providers already expose both faces.&lt;/strong&gt; MiniMax, DeepSeek, OpenRouter offer OpenAI and Anthropic compatible surfaces. The translation layer no longer creates value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We could do it — we've tested both protocol faces against real providers. We just think the complexity isn't worth it. (This is also the crux of the difference from LiteLLM-class gateways, where the translation layer is a core feature.)&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Agent-first, not human-first
&lt;/h2&gt;

&lt;p&gt;Two design decisions that only make sense if the user is an agent, not a person:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Session-Sticky affinity&lt;/strong&gt;: keep a long conversation pinned to one physical endpoint so the provider's Prompt Cache stays warm. Observed hit rates 85–95%, ~50–70% cost reduction on cache discounts (self-measured).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error-class-aware cooldowns&lt;/strong&gt;: rate-limit (429) honors &lt;code&gt;Retry-After&lt;/code&gt;; auth failure (401) gets a long cooldown; content-filter rejection (403) &lt;strong&gt;switches provider without penalizing the endpoint&lt;/strong&gt; — the provider is healthy, it's just doing its compliance job; 5xx gets exponential backoff. Most gateways treat all failures the same. VMR doesn't.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus the flight recorder: per-request JSONL audit (client↔VMR, VMR↔upstream) grouped by &lt;code&gt;Session → Task → Turn&lt;/code&gt; — built to answer "which model did this agent session use, for how many tokens, and where did it go off the rails," not "what does this chat look like in a table."&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Honest tradeoffs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No dashboard, no web UI.&lt;/strong&gt; Observability is &lt;code&gt;vmr report&lt;/code&gt; / &lt;code&gt;vmr story&lt;/code&gt; on the CLI. Deliberate, but it does filter out users who want a graphical view.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Providers are config, not built-in.&lt;/strong&gt; Currently validated: MiniMax, DeepSeek, OpenRouter. Adding one is near-zero code (a config block), but you verify compatibility yourself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strategy dimensions are partial.&lt;/strong&gt; &lt;code&gt;priority&lt;/code&gt; works; &lt;code&gt;weight&lt;/code&gt;/&lt;code&gt;round_robin&lt;/code&gt; are "in progress."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two known architectural tradeoffs&lt;/strong&gt;: image downscaling happens at the server layer (can't be un-done after failover), and the concurrency gate is global, not per-model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The real one&lt;/strong&gt;: the project is young and small (community, iteration velocity are nothing like CCR's). If you pick it, accept you may write your own provider configs and verify compatibility. The upside: 4 deps and 31K lines mean even if development stalled, handover cost is low.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. Try it
&lt;/h2&gt;

&lt;p&gt;If you're running your own coding agents and want a transparent, self-healing, evidence-keeping data plane between them and your LLM providers, the code is on GitHub: &lt;a href="https://github.com/bigfatsea/vmr" rel="noopener noreferrer"&gt;github.com/bigfatsea/vmr&lt;/a&gt;. We're actively working on the scheduling dimensions (&lt;code&gt;weight&lt;/code&gt;/&lt;code&gt;round_robin&lt;/code&gt;) and the &lt;code&gt;vmr story&lt;/code&gt; diff-and-replay tooling. Issues and PRs welcome.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>go</category>
      <category>llm</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
