<?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: Assili Salim</title>
    <description>The latest articles on DEV Community by Assili Salim (@assili_salim_e3c07f9954de).</description>
    <link>https://dev.to/assili_salim_e3c07f9954de</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%2F3976311%2F67c79ee9-ba0f-4524-b372-e3e745e4dab4.png</url>
      <title>DEV Community: Assili Salim</title>
      <link>https://dev.to/assili_salim_e3c07f9954de</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/assili_salim_e3c07f9954de"/>
    <language>en</language>
    <item>
      <title>A 256-Token Prompt Just Became a $0.58 Bomb. Here's the Fix.</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Tue, 18 Aug 2026 04:33:50 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/a-256-token-prompt-just-became-a-058-bomb-heres-the-fix-20cp</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/a-256-token-prompt-just-became-a-058-bomb-heres-the-fix-20cp</guid>
      <description>&lt;p&gt;I was reading through the CCS 2026 accepted papers when one stopped me cold.&lt;/p&gt;

&lt;p&gt;The paper is called &lt;strong&gt;ReasoningBomb&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The premise: craft a prompt short enough to look completely harmless — under 256 tokens — and it drives a reasoning model into a pathologically long chain of thought. Not occasionally. Consistently. Across commercial models. With a &lt;strong&gt;286.7× input-to-output amplification ratio&lt;/strong&gt; and a &lt;strong&gt;98.4% bypass rate&lt;/strong&gt; against dual-stage detection systems built specifically to catch it.&lt;/p&gt;

&lt;p&gt;The security community is calling this a DoS attack. That framing is correct.&lt;/p&gt;

&lt;p&gt;But there's a second attack happening at the same time that nobody's writing about: the financial one.&lt;/p&gt;




&lt;h2&gt;
  
  
  Run the math. It's worse than you think.
&lt;/h2&gt;

&lt;p&gt;GPT-5.6 Sol pricing: $5/M input, $30/M output. Reasoning tokens bill as output.&lt;/p&gt;

&lt;p&gt;One triggered call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input:   256 tokens  × $5/M   =  $0.00128
Output: 19,263 tokens × $30/M =  $0.57789
Total:                          $0.579 per call
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;452× cost amplification.&lt;/strong&gt; On a single request. Not because the model failed — because it succeeded at generating the longest possible reasoning trace.&lt;/p&gt;

&lt;p&gt;On Claude Opus 4.8 ($15/$75 per million): &lt;strong&gt;$1.44 per triggered call.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now think about what your agent processes every day. Customer support tickets. Document ingestion. Code review tools reading PR descriptions. Web browsing agents fetching arbitrary URLs. Any external content flowing through a reasoning model on metered API is a potential trigger surface.&lt;/p&gt;

&lt;p&gt;The attack doesn't need a malicious user at a keyboard. A crafted document in your RAG pipeline, a poisoned page your agent scrapes, a tampered issue in your ticketing system — all of them can carry it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why your existing controls won't catch this
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Rate limits&lt;/strong&gt; cap requests per minute, not cost per request. ReasoningBomb firing once a minute is fully within rate limits — billing $0.578 per call, continuously.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spending alerts&lt;/strong&gt; fire after the cost is incurred. By the time your 80% budget alert triggers, the session is already over budget. The alert is accurate and completely useless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Monthly caps&lt;/strong&gt; — you find out next month.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No &lt;code&gt;max_completion_tokens&lt;/code&gt; set&lt;/strong&gt; — most frameworks don't set this by default on reasoning models. The model decides how long to think. The attack exploits exactly this gap.&lt;/p&gt;




&lt;h2&gt;
  
  
  The only intervention point that matters: before the call
&lt;/h2&gt;

&lt;p&gt;Two defenses. They work best together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First: always set &lt;code&gt;max_completion_tokens&lt;/code&gt; on reasoning model calls.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the minimum viable defense. Set a ceiling that covers your legitimate use cases — with room to spare, but not 19,000 tokens of room:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-5.6-sol&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userInput&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="na"&gt;max_completion_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// hard ceiling — tune for your task&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A task that legitimately needs 800 output tokens isn't affected by a 2,000-token ceiling. A ReasoningBomb trying to generate 19,263 tokens gets cut off at 2,000 — and your bill reflects that, not the attack's intent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second: make the ceiling dynamic based on remaining session budget.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A static ceiling protects individual calls. A budget-aware ceiling protects the entire session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MODEL_PRICES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;inputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;outputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-5.6-sol&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;inputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;5.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="na"&gt;outputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;30.00&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-5.6-terra&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;inputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="na"&gt;outputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;12.00&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-5.6-luna&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;inputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="na"&gt;outputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;1.20&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;claude-opus-4-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;inputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;15.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;outputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;75.00&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;guardWithOutputCeiling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;spentCents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;reservedCents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;limitCents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MODEL_PRICES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unregistered model: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;remainingCents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limitCents&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spentCents&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reservedCents&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;remainingCents&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Session budget exhausted`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;affordableTokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;remainingCents&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputPerM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TASK_MAX_OUTPUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;affordableTokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;TASK_MAX_OUTPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Before every reasoning model call:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxTokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;guardWithOutputCeiling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-5.6-sol&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gpt-5.6-sol&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;max_completion_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;maxTokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does: a ReasoningBomb targeting a session with $0.10 remaining gets capped at 3,333 output tokens — the maximum $0.10 buys at Sol pricing.&lt;/p&gt;

&lt;p&gt;The attack still fires. But its cost is bounded by what the session can actually afford — not by what the attack is trying to spend.&lt;/p&gt;

&lt;p&gt;That's the distinction that matters: &lt;strong&gt;"attack succeeded"&lt;/strong&gt; versus &lt;strong&gt;"attack controlled your bill."&lt;/strong&gt; The ceiling doesn't prevent the trigger. It prevents the trigger from determining the cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  The threat model to carry into production
&lt;/h2&gt;

&lt;p&gt;ReasoningBomb isn't a theoretical edge case. It's accepted at a top-tier security conference. The code is published on GitHub. It achieves near-perfect detection bypass on commercial models including GPT-5.6.&lt;/p&gt;

&lt;p&gt;Any agent processing external content through a reasoning model on metered API is currently exposed.&lt;/p&gt;

&lt;p&gt;The fix costs you one parameter per API call. The dynamic version costs you one function. Neither requires infrastructure changes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@salimassili/ai-costguard&lt;/code&gt; implements this as &lt;code&gt;maxOutputTokens&lt;/code&gt; enforcement in the session guard — the ceiling is calculated from remaining budget before each call and set automatically. The underlying pattern is always the same: compute the maximum output tokens your remaining budget can afford, set it explicitly, let the provider enforce it at the API level.&lt;/p&gt;

&lt;p&gt;The bill for a ReasoningBomb call arrives before you can stop it.&lt;/p&gt;

&lt;p&gt;The ceiling is the only defense positioned in the right place.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>typescript</category>
      <category>agents</category>
    </item>
    <item>
      <title>Two Billing Clocks, One Session Budget: How to Guard Costs When Your Agent Runs in a Metered Sandbox</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Mon, 17 Aug 2026 04:40:44 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/two-billing-clocks-one-session-budget-how-to-guard-costs-when-your-agent-runs-in-a-metered-sandbox-3a4a</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/two-billing-clocks-one-session-budget-how-to-guard-costs-when-your-agent-runs-in-a-metered-sandbox-3a4a</guid>
      <description>&lt;p&gt;Docker Sandboxes launched this week — purpose-built microVMs for coding agents running Claude Code, Codex, and Gemini. Isolated daemon, filesystem, network. Metered compute.&lt;/p&gt;

&lt;p&gt;Right architecture for agent isolation. Wrong assumption for most cost guards.&lt;/p&gt;




&lt;h2&gt;
  
  
  The model most guards assume — and when it breaks
&lt;/h2&gt;

&lt;p&gt;Local agent execution has a simple cost model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Session cost = tokens × model rate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sandbox is your machine. &lt;br&gt;
Compute is free.&lt;/p&gt;

&lt;p&gt;Move to Docker Sandboxes, E2B, Daytona, or Modal — and you now have two meters running simultaneously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Token cost:    tokens × model rate       ← your guard probably tracks this
Compute cost:  uptime × compute rate     ← your guard probably doesn't
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A retry loop that runs 45 minutes doesn't just burn token budget. &lt;br&gt;
It keeps a metered microVM alive for 45 minutes. &lt;br&gt;
At E2B's standard rate of ~$0.083/hour, that loop adds $0.062 in compute on top of whatever tokens it consumed.&lt;/p&gt;

&lt;p&gt;Small in isolation. &lt;br&gt;
Fatal to a session budget calibrated on token costs alone.&lt;/p&gt;


&lt;h2&gt;
  
  
  What a real overrun looks like
&lt;/h2&gt;

&lt;p&gt;A production coding agent, $0.50 session budget, GPT-5.6 Terra pricing ($2/$12 per million):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expected:
  5 agent turns × ~3,000 tokens
  Token cost:    ~$0.050
  Sandbox uptime: ~8 minutes
  Compute cost:  ~$0.011
  Projected:     ~$0.061 — well within budget

A tool call fails. 
Agent retries. 
Gets confused. 
Loops.

Actual:
  80+ tool calls, ~50,000 tokens
  Token cost:    ~$0.710
  Compute cost:  ~$0.065  (47 min × $0.083/hr)
  Actual total:  ~$0.775
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The token guard would have eventually blocked on token spend. &lt;br&gt;
The compute cost was accruing from the moment the sandbox spawned , no token-level guard can touch it. &lt;br&gt;
Only a compute budget check or a lifetime limit can stop it.&lt;/p&gt;


&lt;h2&gt;
  
  
  The unified session model
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;SandboxSession&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;sandboxId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;startedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;computeRatePerHour&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nl"&gt;spentTokenCents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;reservedTokenCents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;totalLimitCents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;currentComputeCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SandboxSession&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uptimeHours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startedAt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="nx"&gt;_600_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;uptimeHours&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;computeRatePerHour&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// cents&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;totalCurrentCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SandboxSession&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spentTokenCents&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;currentComputeCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Pre-call guard checks the combined total before every model call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;guardCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;estimatedInputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;estimatedOutputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;estimatedCallMinutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SandboxSession&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;MODEL_PRICES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Unregistered model: "&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokenCost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;estimatedInputTokens&lt;/span&gt;  &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inputPerM&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;estimatedOutputTokens&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputPerM&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;additionalCompute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;estimatedCallMinutes&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;computeRatePerHour&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectedTotal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;totalCurrentCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reservedTokenCents&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="nx"&gt;tokenCost&lt;/span&gt;                  &lt;span class="o"&gt;+&lt;/span&gt;
    &lt;span class="nx"&gt;additionalCompute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;projectedTotal&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalLimitCents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BudgetExceededError&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;sandboxId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sandboxId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;projectedTotal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;limitCents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalLimitCents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;breakdown&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;currentTokenSpend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spentTokenCents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;currentComputeCost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;currentComputeCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;thisCallTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="nx"&gt;tokenCost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;thisCallCompute&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="nx"&gt;additionalCompute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spentTokenCents&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;tokenCost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;projectedTotal&lt;/code&gt; includes already-accrued compute. &lt;br&gt;
If the session has been running 20 minutes, &lt;code&gt;currentComputeCost&lt;/code&gt; reflects that before the guard evaluates the next call. &lt;br&gt;
The guard sees the real cost trajectory , not just forward token spend.&lt;/p&gt;


&lt;h2&gt;
  
  
  The simpler version: just cap sandbox lifetime
&lt;/h2&gt;

&lt;p&gt;Per-call compute modeling too granular for your workload? A lifetime limit gets you most of the protection with a fraction of the complexity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;guardSandboxLifetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SandboxSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;maxLifetimeMinutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uptimeMinutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startedAt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uptimeMinutes&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;maxLifetimeMinutes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SandboxLifetimeExceededError&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;sandboxId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sandboxId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;uptimeMinutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;limitMinutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;maxLifetimeMinutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Call at the start of every agent turn — before any tool calls&lt;/span&gt;
&lt;span class="nf"&gt;guardSandboxLifetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 30-minute hard cap is a compute ceiling without exact rate modeling. &lt;br&gt;
It also directly kills the loop scenario , the agent can't run for 47 minutes if the session terminates at 30.&lt;/p&gt;

&lt;p&gt;One important detail: call this at the start of every agent turn, not just on LLM calls. &lt;br&gt;
Compute billing accrues during tool execution, file I/O, and idle waiting , not just during inference.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before you move to metered sandboxes
&lt;/h2&gt;

&lt;p&gt;If your agents run locally today and you're planning the move to Docker Sandboxes or any metered provider, expand the budget model before you flip the switch.&lt;/p&gt;

&lt;p&gt;Token-only cost modeling that was accurate locally becomes structurally incomplete on metered infrastructure. &lt;br&gt;
A session you budgeted at $0.06 in token costs becomes $0.12 once compute time is included , before any overruns. &lt;br&gt;
That gap isn't an edge case. &lt;br&gt;
It's the baseline.&lt;/p&gt;

&lt;p&gt;The two invoices are real. The guard needs to see both.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>docker</category>
      <category>tools</category>
    </item>
    <item>
      <title>GPT-5.6 Puts Reasoning in Every Tier. Your Cost Estimator Isn't Ready.</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Sun, 16 Aug 2026 03:54:24 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/gpt-56-puts-reasoning-in-every-tier-your-cost-estimator-isnt-ready-3lf3</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/gpt-56-puts-reasoning-in-every-tier-your-cost-estimator-isnt-ready-3lf3</guid>
      <description>&lt;p&gt;OpenAI's GPT-5.6 ships reasoning across the entire production family. Sol, Terra, Luna — all of them reason before responding.&lt;/p&gt;

&lt;p&gt;That's a capability upgrade. It's also a billing problem most teams haven't hit yet — but will.&lt;/p&gt;




&lt;h2&gt;
  
  
  The invisible tokens eating your budget
&lt;/h2&gt;

&lt;p&gt;Reasoning tokens are billed as output tokens. They just never appear in the response.&lt;/p&gt;

&lt;p&gt;So the model returns a short answer while consuming substantially more billed tokens internally. Your estimator sees the visible output. The invoice sees everything.&lt;/p&gt;

&lt;p&gt;Concrete example — a Sol request returning 200 visible tokens with 600 reasoning tokens underneath:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Visible output:    200 tokens
Reasoning:         600 tokens
Billed output:     800 tokens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At $30 per million output tokens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Estimated (visible only):   200 / 1M × $30 = $0.006
Actual:                     800 / 1M × $30 = $0.024
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4× off. Not because the math was wrong. Because the estimator measured the wrong thing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why a point estimate breaks here
&lt;/h2&gt;

&lt;p&gt;Most pre-call cost guards look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;estimatedCost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inputTokens&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;inputPrice&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;expectedOutputTokens&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;outputPrice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's fine when visible output length is a reasonable proxy for billed output. For reasoning models, it isn't.&lt;/p&gt;

&lt;p&gt;A simple formatting task and a complex architectural problem can return similarly-sized responses while generating completely different reasoning-token counts internally. Same output length, wildly different cost.&lt;/p&gt;

&lt;p&gt;The guard needs to account for that uncertainty — not pretend it doesn't exist.&lt;/p&gt;




&lt;h2&gt;
  
  
  Use a range, not a number
&lt;/h2&gt;

&lt;p&gt;Instead of estimating a single cost figure, estimate a range:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ModelPricing&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;inputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;outputPerM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;thinkingMultiplierRange&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shift the question from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What will this call cost?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What's the plausible cost ceiling — and can the session afford it?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the worst-case estimate exceeds the remaining budget, block the call before it leaves your process. That's the only point where you still have control.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reconcile after execution
&lt;/h2&gt;

&lt;p&gt;Once the provider responds, replace the reservation with reality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Before call:
  estimate range
  reserve against ceiling
  block if ceiling is unaffordable

After call:
  read actual token usage
  release reservation
  record actual spend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a standard reservation pattern. The key property is unchanged: &lt;strong&gt;the budget decision happens before the request goes out.&lt;/strong&gt; Actual usage just closes the loop.&lt;/p&gt;




&lt;h2&gt;
  
  
  Let your own workload calibrate the range
&lt;/h2&gt;

&lt;p&gt;A generic multiplier is a starting point, not an answer.&lt;/p&gt;

&lt;p&gt;Once you have production data, track the ratio of reasoning tokens to visible output tokens per model per workload type. Over time, your registry moves from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"reasoning might add 0.5–4×"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"for this workload, observed range is 1.2–1.8×"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The guard gets sharper without pretending reasoning cost is predictable before execution.&lt;/p&gt;




&lt;h2&gt;
  
  
  Caching creates the opposite failure
&lt;/h2&gt;

&lt;p&gt;Reasoning inflates actual cost above estimate. Caching deflates it.&lt;/p&gt;

&lt;p&gt;A simplistic guard fails in both directions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning:&lt;/strong&gt; actual cost &amp;gt; estimate → you underreserved, overspent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching:&lt;/strong&gt; actual cost &amp;lt; estimate → you overreserved, blocked calls unnecessarily&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The fix is the same either way: model the provider's actual billing mechanics, not just &lt;code&gt;input × price + output × price&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The bigger shift
&lt;/h2&gt;

&lt;p&gt;As models get more sophisticated, token count alone stops being a sufficient cost model.&lt;/p&gt;

&lt;p&gt;A production cost guard needs to account for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model-specific pricing tiers&lt;/li&gt;
&lt;li&gt;Cached input discounts&lt;/li&gt;
&lt;li&gt;Reasoning output ranges&lt;/li&gt;
&lt;li&gt;Retries and partial failures&lt;/li&gt;
&lt;li&gt;Session-level budgets across multiple agents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of those variables are only fully known after execution. That's not a limitation to work around — it's the architecture to design for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Estimate and reserve before the call. Reconcile against actual usage afterward.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The estimate isn't wrong. It's just not the whole bill anymore.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>agents</category>
      <category>tools</category>
    </item>
    <item>
      <title>Multi-Agent Systems Share Context. They Should Share Budgets Too.</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Wed, 12 Aug 2026 04:23:48 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/multi-agent-systems-share-context-they-should-share-budgets-too-kfd</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/multi-agent-systems-share-context-they-should-share-budgets-too-kfd</guid>
      <description>&lt;p&gt;This week, researchers introduced AgentRadio — an async messaging layer that lets coding agents exchange information between execution steps without burning an extra turn.&lt;/p&gt;

&lt;p&gt;The headline was performance: agent teams using AgentRadio nearly doubled results on long-horizon software engineering tasks versus isolated agents.&lt;/p&gt;

&lt;p&gt;The part I found more interesting was cost.&lt;/p&gt;




&lt;h2&gt;
  
  
  Better coordination already reduces waste
&lt;/h2&gt;

&lt;p&gt;Traditional multi-agent systems sync at fixed checkpoints. So if Agent A figures out halfway through that the team is going in the wrong direction, Agents B, C, and D keep running until the next sync point.&lt;/p&gt;

&lt;p&gt;Every one of those calls is still billed.&lt;/p&gt;

&lt;p&gt;AgentRadio cuts that waste. Agents receive updates asynchronously and adjust at their next step — no waiting for a scheduled checkpoint. Less duplicated work means fewer wasted model calls.&lt;/p&gt;

&lt;p&gt;Better coordination isn't just faster. It's cheaper.&lt;/p&gt;

&lt;p&gt;But that's the easy part.&lt;/p&gt;




&lt;h2&gt;
  
  
  The real problem: per-agent budgets don't compose
&lt;/h2&gt;

&lt;p&gt;The harder problem shows up once multiple agents share the same objective.&lt;/p&gt;

&lt;p&gt;Most budget guards look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AgentBudgetGuard&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;spent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spent&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;LIMIT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Budget exceeded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spent&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect for one agent. Completely blind to the others.&lt;/p&gt;

&lt;p&gt;Now imagine four agents sharing the same task:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;Spent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;$0.42&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;$0.39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;$0.47&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;$0.44&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Every individual guard says: &lt;em&gt;still within budget.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Combined, the task has nearly blown its limit.&lt;/p&gt;

&lt;p&gt;Nobody knows. Nothing stops.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fix: budget belongs to the task, not the agent
&lt;/h2&gt;

&lt;p&gt;Stop tracking spend per agent. Track it once — at the task level — and make every agent check the same pool before each call.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Every agent checks the shared task budget before calling a model&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;taskBudget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;agentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;estimatedCost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One line change. Every agent now knows what the &lt;em&gt;team&lt;/em&gt; has left, not just what it has spent.&lt;/p&gt;

&lt;p&gt;The implementation is straightforward. The critical detail is atomicity.&lt;/p&gt;

&lt;p&gt;If two agents simultaneously read the same remaining balance and both decide to proceed, they'll both overspend — together, instantly. Whether you use Redis, PostgreSQL, or DynamoDB, the check-and-update must be a single atomic operation. Read-then-write doesn't cut it here.&lt;/p&gt;




&lt;h2&gt;
  
  
  Shared budgets unlock team-level controls
&lt;/h2&gt;

&lt;p&gt;Once your agents share a budget, threshold-based policies actually make sense:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;THRESHOLDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;NOTIFY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="mf"&gt;0.60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// alert the orchestrator&lt;/span&gt;
  &lt;span class="na"&gt;DOWNGRADE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;0.80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// switch all agents to a cheaper model&lt;/span&gt;
  &lt;span class="na"&gt;HALT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;        &lt;span class="mf"&gt;1.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// stop all new model calls&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what changes: the decision applies to the entire team. Not whichever agent happened to cross the threshold first. Everyone degrades together, everyone stops together, everyone operates under the same budget policy.&lt;/p&gt;

&lt;p&gt;That's coherent cost governance. Per-agent guards can't give you that.&lt;/p&gt;




&lt;h2&gt;
  
  
  The principle AgentRadio proves, applied to money
&lt;/h2&gt;

&lt;p&gt;AgentRadio's core insight is that agents perform better when they share information.&lt;/p&gt;

&lt;p&gt;The same is true for financial state.&lt;/p&gt;

&lt;p&gt;Sharing context without sharing budgets creates a strange situation: every agent makes a locally correct decision while the team collectively burns through money nobody is watching.&lt;/p&gt;

&lt;p&gt;As multi-agent architectures get more common, shared budgets need to be treated as seriously as shared memory.&lt;/p&gt;

&lt;p&gt;Capability scales through coordination. Cost control has to scale with it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>node</category>
      <category>agents</category>
    </item>
    <item>
      <title>Article 50 Is Live. Your Compliance Logs and Your Debug Logs Should Be the Same Thing.</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Tue, 11 Aug 2026 03:32:47 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/article-50-is-live-your-compliance-logs-and-your-debug-logs-should-be-the-same-thing-84j</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/article-50-is-live-your-compliance-logs-and-your-debug-logs-should-be-the-same-thing-84j</guid>
      <description>&lt;p&gt;Most teams responded to Article 50 of the EU AI Act with a disclosure banner.&lt;/p&gt;

&lt;p&gt;That's fine. Do that. But it's not enough.&lt;/p&gt;

&lt;p&gt;Because if a regulator ever investigates a specific interaction, "we always show a disclosure" won't cut it. You need evidence tied to that exact session — a record you can point to and say: here's what happened, when it happened, and to whom.&lt;/p&gt;

&lt;p&gt;That's a logging problem. And if you're already building AI agents, you're probably 80% of the way there — you just haven't connected the dots yet.&lt;/p&gt;

&lt;p&gt;What compliance actually requires&lt;/p&gt;

&lt;p&gt;Article 50 doesn't define a logging schema. But in practice, answering a regulatory inquiry means being able to reconstruct:&lt;/p&gt;

&lt;p&gt;When did this session start?&lt;br&gt;
Which model generated the response?&lt;br&gt;
Was the AI disclosure shown — and how?&lt;br&gt;
What output did the user receive?&lt;br&gt;
Which user or tenant does this belong to?&lt;/p&gt;

&lt;p&gt;Policy documents don't answer those questions. Session records do.&lt;/p&gt;

&lt;p&gt;The overlap with what engineering already needs&lt;/p&gt;

&lt;p&gt;Here's the part worth paying attention to: the data compliance needs is mostly the same data your engineers already want for debugging, routing analysis, and cost attribution.&lt;/p&gt;

&lt;p&gt;ts&lt;br&gt;
interface AgentSessionRecord {&lt;br&gt;
  sessionId: string;&lt;br&gt;
  userId?: string;&lt;br&gt;
  startedAt: Date;&lt;/p&gt;

&lt;p&gt;calls: {&lt;br&gt;
    timestamp: Date;&lt;br&gt;
    model: string;&lt;br&gt;
    estimatedInputTokens: number;&lt;br&gt;
    estimatedOutputTokens: number;&lt;br&gt;
    estimatedCost: number;&lt;br&gt;
  }[];&lt;/p&gt;

&lt;p&gt;disclosures: {&lt;br&gt;
    timestamp: Date;&lt;br&gt;
    method: "message" | "ui";&lt;br&gt;
  }[];&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Same structure. Different consumers.&lt;/p&gt;

&lt;p&gt;Engineering asks: why was this session expensive? why did model routing change?&lt;br&gt;
Compliance asks: was a disclosure shown? which system generated this output?&lt;/p&gt;

&lt;p&gt;You don't need two separate systems for those questions. You need one well-designed session record.&lt;/p&gt;

&lt;p&gt;What to build first&lt;/p&gt;

&lt;p&gt;If you're shipping AI agents today, start here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Generate a unique session ID for every interaction.&lt;br&gt;
Don't reconstruct sessions from logs after the fact. Assign the ID upfront and thread it through everything.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Record which model handled each request.&lt;br&gt;
Not just the provider — the exact model. Models change, routing changes, costs change. You need the audit trail.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Log disclosure events explicitly.&lt;br&gt;
Don't assume you can infer them later from UI behavior. An explicit disclosures[] array is a first-class field, not an afterthought.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Associate records with users or tenants where appropriate.&lt;br&gt;
This matters for both cost attribution and regulatory traceability.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Record enough metadata to trace outputs without storing every response.&lt;br&gt;
You don't necessarily need to store full completions — but you need enough to reconstruct what happened.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The real takeaway&lt;/p&gt;

&lt;p&gt;The interesting thing about Article 50 isn't the transparency requirement itself.&lt;/p&gt;

&lt;p&gt;It's that compliance now depends on operational evidence — not policy documents, not promises, not architecture diagrams.&lt;/p&gt;

&lt;p&gt;Teams that have already invested in structured session-level observability will find themselves ahead. Not just for cost control and debugging — but for being able to demonstrate, concretely, how their AI systems behaved.&lt;/p&gt;

&lt;p&gt;Session records aren't a compliance feature bolted on top of your system.&lt;/p&gt;

&lt;p&gt;They're just good engineering — that also happens to keep you accountable.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>typescript</category>
      <category>node</category>
    </item>
    <item>
      <title>Alert-Based vs. Threshold-Based: Why Monitoring Isn't the Same as Cost Control</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Sun, 09 Aug 2026 03:33:38 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/alert-based-vs-threshold-based-why-monitoring-isnt-the-same-as-cost-control-370o</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/alert-based-vs-threshold-based-why-monitoring-isnt-the-same-as-cost-control-370o</guid>
      <description>&lt;p&gt;A recent OpenAI update caught my attention—not because of the model itself, but because of the control architecture behind it.&lt;/p&gt;

&lt;p&gt;According to OpenAI, parts of Astra's development were paused after internal evaluations crossed a predefined threshold under its Preparedness Framework.&lt;/p&gt;

&lt;p&gt;The important engineering pattern isn't the safety policy.&lt;/p&gt;

&lt;p&gt;It's that &lt;strong&gt;crossing a threshold triggered an automatic response&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;No one had to notice a dashboard first.&lt;/p&gt;

&lt;p&gt;That distinction applies far beyond AI safety.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring tells you what happened
&lt;/h2&gt;

&lt;p&gt;Most AI cost systems look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;callProvider&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spent&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;cost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spent&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;notifySlack&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful.&lt;/p&gt;

&lt;p&gt;You know exactly when the budget was exceeded.&lt;/p&gt;

&lt;p&gt;The problem is obvious:&lt;/p&gt;

&lt;p&gt;The expensive request has already happened.&lt;/p&gt;

&lt;p&gt;For interactive applications, that's often acceptable.&lt;/p&gt;

&lt;p&gt;For autonomous agents running overnight, it usually isn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Control happens before the request
&lt;/h2&gt;

&lt;p&gt;A runtime guard works differently.&lt;/p&gt;

&lt;p&gt;Instead of reacting to completed requests, it evaluates the &lt;strong&gt;next&lt;/strong&gt; request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;estimatedCost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;estimateCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spent&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;estimatedCost&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BudgetExceededError&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;callProvider&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key difference isn't the calculation.&lt;/p&gt;

&lt;p&gt;It's &lt;strong&gt;when&lt;/strong&gt; the calculation happens.&lt;/p&gt;

&lt;p&gt;One architecture observes.&lt;/p&gt;

&lt;p&gt;The other controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thresholds can trigger different actions
&lt;/h2&gt;

&lt;p&gt;Blocking isn't the only possible response.&lt;/p&gt;

&lt;p&gt;A production system can define multiple thresholds with predefined behavior:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Budget usage&lt;/th&gt;
&lt;th&gt;Response&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;Log or notify&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;80%&lt;/td&gt;
&lt;td&gt;Route to a cheaper model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100%&lt;/td&gt;
&lt;td&gt;Block additional requests&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That creates deterministic behavior instead of relying on humans to intervene.&lt;/p&gt;

&lt;p&gt;The system already knows what to do before the threshold is reached.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters for agents
&lt;/h2&gt;

&lt;p&gt;Traditional chat applications naturally include a human feedback loop.&lt;/p&gt;

&lt;p&gt;Agents don't.&lt;/p&gt;

&lt;p&gt;A coding agent, research workflow, or CI automation might execute hundreds of requests without anyone watching.&lt;/p&gt;

&lt;p&gt;In those systems, an alert that arrives after spending has already occurred is useful for reporting—but it cannot prevent additional spend.&lt;/p&gt;

&lt;p&gt;That's why autonomous systems benefit from &lt;strong&gt;runtime guardrails&lt;/strong&gt; rather than monitoring alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring and control solve different problems
&lt;/h2&gt;

&lt;p&gt;This isn't an argument against dashboards, telemetry, or alerts.&lt;/p&gt;

&lt;p&gt;Those remain essential.&lt;/p&gt;

&lt;p&gt;But they're answering a different question.&lt;/p&gt;

&lt;p&gt;Monitoring asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What happened?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Runtime control asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Should the next request be allowed?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those are complementary systems—not interchangeable ones.&lt;/p&gt;

&lt;p&gt;As more software becomes agent-driven, I expect this distinction to become increasingly important. The most effective cost-control architectures won't simply report threshold crossings—they'll define, in advance, exactly how the system responds when those thresholds are reached.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Spot-priced LLM inference changes how runtime budget guards should work</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Thu, 06 Aug 2026 05:30:46 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/spot-priced-llm-inference-changes-how-runtime-budget-guards-should-work-4n29</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/spot-priced-llm-inference-changes-how-runtime-budget-guards-should-work-4n29</guid>
      <description>&lt;p&gt;Most AI cost guards assume one thing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You know the price before you make the request.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's been true for most LLM APIs.&lt;/p&gt;

&lt;p&gt;It's becoming less true as inference marketplaces introduce &lt;strong&gt;dynamic pricing&lt;/strong&gt;, where providers compete for requests and the final price is determined at runtime.&lt;/p&gt;

&lt;p&gt;That creates an interesting engineering problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Traditional budget guards
&lt;/h2&gt;

&lt;p&gt;A typical pre-call budget check is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Look up the model price.&lt;/li&gt;
&lt;li&gt;Estimate token usage.&lt;/li&gt;
&lt;li&gt;Estimate request cost.&lt;/li&gt;
&lt;li&gt;Compare against the remaining session budget.&lt;/li&gt;
&lt;li&gt;Allow or block the request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That works well when prices are fixed.&lt;/p&gt;

&lt;p&gt;It doesn't work as well when the final price isn't known until the request completes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong solutions
&lt;/h2&gt;

&lt;p&gt;There are two obvious approaches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ignore pricing uncertainty&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This removes one of the main reasons the guard exists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Always assume list price&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Safe, but often overly conservative. You end up rejecting requests that would have cleared well within budget.&lt;/p&gt;

&lt;p&gt;Neither is ideal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reserve a maximum, settle the actual
&lt;/h2&gt;

&lt;p&gt;A pattern borrowed from cloud infrastructure works much better.&lt;/p&gt;

&lt;p&gt;Instead of estimating the exact cost, reserve the &lt;strong&gt;maximum amount you're willing to spend&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;SpotRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;maxBidPerMillion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;estimatedInputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;estimatedOutputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before the request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reserve the worst-case spend.&lt;/li&gt;
&lt;li&gt;Reject the request if that reservation exceeds the session budget.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace the reservation with the actual amount charged.&lt;/li&gt;
&lt;li&gt;Release any unused budget back to the session.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important property is that your budget is never temporarily overstated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Budget enforcement becomes deterministic
&lt;/h2&gt;

&lt;p&gt;With this approach, the guard doesn't ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;How much will this request cost?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, it asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Can this session afford the maximum amount we're willing to pay?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's a question you &lt;strong&gt;can&lt;/strong&gt; answer before the request leaves your process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bid ceilings become another optimization tool
&lt;/h2&gt;

&lt;p&gt;Once you introduce a maximum acceptable price, that ceiling can become part of your routing strategy.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;low-value classification → low bid ceiling&lt;/li&gt;
&lt;li&gt;code review → medium ceiling&lt;/li&gt;
&lt;li&gt;architecture tasks → higher ceiling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As the session budget decreases, those ceilings can become more conservative.&lt;/p&gt;

&lt;p&gt;Instead of simply rejecting requests when money runs low, your system can automatically become more selective about what it's willing to pay for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters
&lt;/h2&gt;

&lt;p&gt;Today it's spot-priced inference.&lt;/p&gt;

&lt;p&gt;Tomorrow it may be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dynamic provider marketplaces,&lt;/li&gt;
&lt;li&gt;region-specific pricing,&lt;/li&gt;
&lt;li&gt;time-based pricing,&lt;/li&gt;
&lt;li&gt;SLA-based pricing,&lt;/li&gt;
&lt;li&gt;or real-time routing across multiple providers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common pattern is the same:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The exact price is no longer guaranteed before the request is sent.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That means runtime cost controls need to evolve as well.&lt;/p&gt;

&lt;p&gt;Rather than assuming every request has a fixed price, they should be designed to operate under uncertainty—enforcing budgets using &lt;strong&gt;maximum acceptable cost&lt;/strong&gt;, then reconciling against the actual price afterward.&lt;/p&gt;

&lt;p&gt;That's a much more flexible architecture for the direction AI infrastructure appears to be heading.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Model selection isn't just an AI decision. It's a cost decision.</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Wed, 05 Aug 2026 04:25:50 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/model-selection-isnt-just-an-ai-decision-its-a-cost-decision-1075</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/model-selection-isnt-just-an-ai-decision-its-a-cost-decision-1075</guid>
      <description>&lt;p&gt;A lot of AI teams optimize prompts, workflows, and infrastructure.&lt;/p&gt;

&lt;p&gt;Far fewer treat &lt;strong&gt;model selection&lt;/strong&gt; as a runtime cost-control problem.&lt;/p&gt;

&lt;p&gt;That's becoming a mistake.&lt;/p&gt;

&lt;p&gt;A recent example is Cursor. Switching to a more capable model can dramatically increase API usage costs, even though the only thing a developer changed was a dropdown in their editor.&lt;/p&gt;

&lt;p&gt;Nothing else changed.&lt;/p&gt;

&lt;p&gt;No deployment.&lt;/p&gt;

&lt;p&gt;No architecture change.&lt;/p&gt;

&lt;p&gt;Just a different model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real problem
&lt;/h2&gt;

&lt;p&gt;Most agent systems treat model choice as a preference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_MODEL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In reality, it should be treated as a decision constrained by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;task complexity,&lt;/li&gt;
&lt;li&gt;remaining session budget,&lt;/li&gt;
&lt;li&gt;latency requirements,&lt;/li&gt;
&lt;li&gt;and expected ROI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of asking &lt;em&gt;"What's the best model?"&lt;/em&gt;, production systems should ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"What's the cheapest model that can successfully complete this task?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. Route models by task
&lt;/h2&gt;

&lt;p&gt;Not every request needs your most capable—and most expensive—model.&lt;/p&gt;

&lt;p&gt;A simple router is often enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;selectModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;complexity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;low&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cheap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;medium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;standard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;high&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;frontier&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Classification, formatting, and summarization rarely need frontier models.&lt;/p&gt;

&lt;p&gt;Save those for the problems that actually benefit from them.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Make budget part of routing
&lt;/h2&gt;

&lt;p&gt;Routing shouldn't depend only on the task.&lt;/p&gt;

&lt;p&gt;It should also depend on &lt;strong&gt;how much budget remains&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;remainingBudget&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cheap&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That allows an agent to degrade gracefully instead of exhausting its budget on the last few requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Validate before the call
&lt;/h2&gt;

&lt;p&gt;Every provider request should pass through a budget check.&lt;/p&gt;

&lt;p&gt;That check should answer questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this model registered?&lt;/li&gt;
&lt;li&gt;Do we know its pricing?&lt;/li&gt;
&lt;li&gt;Can this session afford another request?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the answer is no, the request shouldn't leave your process.&lt;/p&gt;

&lt;p&gt;Failing early is much cheaper than discovering the problem in next month's invoice.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Don't let context grow forever
&lt;/h2&gt;

&lt;p&gt;Long-running agents become expensive because every request carries more history.&lt;/p&gt;

&lt;p&gt;A sliding context window plus pinned instructions often reduces token usage without affecting output quality.&lt;/p&gt;

&lt;p&gt;Keeping &lt;em&gt;all&lt;/em&gt; history is usually the easiest implementation—not the cheapest one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bigger shift
&lt;/h2&gt;

&lt;p&gt;The industry talks a lot about observability.&lt;/p&gt;

&lt;p&gt;Observability tells you what happened.&lt;/p&gt;

&lt;p&gt;Cost governance decides what is allowed to happen.&lt;/p&gt;

&lt;p&gt;That's an important distinction.&lt;/p&gt;

&lt;p&gt;As models become more numerous—and pricing changes more frequently—the most effective cost optimization won't come from better dashboards.&lt;/p&gt;

&lt;p&gt;It will come from making &lt;strong&gt;model selection a guarded runtime decision instead of a static configuration value&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's the architectural direction I'm exploring with AI CostGuard, but the principle applies regardless of the framework or provider you're using.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>agents</category>
      <category>node</category>
    </item>
    <item>
      <title>Migrating from Bedrock Agents Classic to AgentCore? Audit your cost model first.</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Tue, 04 Aug 2026 04:43:45 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/migrating-from-bedrock-agents-classic-to-agentcore-audit-your-cost-model-first-5d9b</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/migrating-from-bedrock-agents-classic-to-agentcore-audit-your-cost-model-first-5d9b</guid>
      <description>&lt;p&gt;Amazon has closed &lt;strong&gt;Bedrock Agents Classic&lt;/strong&gt; to new customers. Existing agents continue to run, and there's no announced end-of-life—but if you're planning a move to &lt;strong&gt;AgentCore&lt;/strong&gt;, there's one migration step that deserves more attention:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review your cost model before you migrate your code.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Your billing model has changed
&lt;/h2&gt;

&lt;p&gt;With Bedrock Agents Classic, most teams only needed to think about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Model inference&lt;/li&gt;
&lt;li&gt;Lambda&lt;/li&gt;
&lt;li&gt;Knowledge Base queries&lt;/li&gt;
&lt;li&gt;Other AWS resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The orchestration layer itself wasn't a separate billable service.&lt;/p&gt;

&lt;p&gt;AgentCore changes that.&lt;/p&gt;

&lt;p&gt;In addition to inference costs, you now have &lt;strong&gt;platform-level charges&lt;/strong&gt; such as agent invocations and gateway requests. That means your total cost is no longer driven only by tokens.&lt;/p&gt;

&lt;h2&gt;
  
  
  Token tracking is no longer enough
&lt;/h2&gt;

&lt;p&gt;Many internal cost dashboards look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;SessionCost&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;inputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;outputTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;estimatedCost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That worked well when inference represented almost the entire bill.&lt;/p&gt;

&lt;p&gt;After migrating, your total session cost may also include platform activity that token-based tracking never sees.&lt;/p&gt;

&lt;p&gt;The result isn't an incorrect calculation—it's an incomplete one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Think in two cost layers
&lt;/h2&gt;

&lt;p&gt;Instead of treating "AI cost" as a single number, separate it into two categories:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inference costs&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input tokens&lt;/li&gt;
&lt;li&gt;Output tokens&lt;/li&gt;
&lt;li&gt;Model pricing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Platform costs&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent invocations&lt;/li&gt;
&lt;li&gt;Gateway requests&lt;/li&gt;
&lt;li&gt;Other orchestration charges&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tracking both independently makes it much easier to understand why costs change over time.&lt;/p&gt;

&lt;p&gt;A prompt optimization affects inference.&lt;/p&gt;

&lt;p&gt;An orchestration redesign might barely change tokens while significantly increasing platform activity.&lt;/p&gt;

&lt;p&gt;Those are different engineering problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before migrating
&lt;/h2&gt;

&lt;p&gt;A migration is a good opportunity to validate your assumptions.&lt;/p&gt;

&lt;p&gt;I'd recommend comparing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Estimated inference cost&lt;/li&gt;
&lt;li&gt;Platform charges&lt;/li&gt;
&lt;li&gt;Combined session cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;for the same workload before rolling changes into production.&lt;/p&gt;

&lt;p&gt;That baseline makes future regressions much easier to spot.&lt;/p&gt;

&lt;h2&gt;
  
  
  The broader trend
&lt;/h2&gt;

&lt;p&gt;AgentCore isn't unique here.&lt;/p&gt;

&lt;p&gt;Across the industry, agent platforms are becoming more opinionated and more capable—and that often means &lt;strong&gt;more of the bill moves into the orchestration layer instead of the model layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For years, tracking tokens was enough.&lt;/p&gt;

&lt;p&gt;Going forward, teams will increasingly need to treat &lt;strong&gt;model costs&lt;/strong&gt; and &lt;strong&gt;platform costs&lt;/strong&gt; as separate budgets.&lt;/p&gt;

&lt;p&gt;The sooner your observability reflects that split, the easier future migrations will be.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>typescript</category>
      <category>agents</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>GPT-5.6 Luna dropped 80% in three weeks. Here's the pricing bug it can introduce into your agent stack.</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Mon, 03 Aug 2026 05:11:54 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/gpt-56-luna-dropped-80-in-three-weeks-heres-the-pricing-bug-it-can-introduce-into-your-agent-5cnn</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/gpt-56-luna-dropped-80-in-three-weeks-heres-the-pricing-bug-it-can-introduce-into-your-agent-5cnn</guid>
      <description>&lt;p&gt;OpenAI recently cut &lt;strong&gt;GPT-5.6 Luna&lt;/strong&gt; from &lt;strong&gt;$1.00 → $0.20 per million input tokens&lt;/strong&gt;—an 80% price reduction just three weeks after launch.&lt;/p&gt;

&lt;p&gt;Cheaper models are great.&lt;/p&gt;

&lt;p&gt;But they expose a problem many agent systems quietly have: &lt;strong&gt;pricing logic that assumes model costs never change.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The stale-pricing bug
&lt;/h2&gt;

&lt;p&gt;A lot of cost controls look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LUNA_INPUT_PER_M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.00&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;estimateCost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;LUNA_INPUT_PER_M&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That worked when Luna launched.&lt;/p&gt;

&lt;p&gt;After the price cut, it doesn't.&lt;/p&gt;

&lt;p&gt;If your session budget is based on those constants, your guardrails are now enforcing assumptions that no longer match reality.&lt;/p&gt;

&lt;p&gt;Nothing crashes.&lt;/p&gt;

&lt;p&gt;Nothing throws an error.&lt;/p&gt;

&lt;p&gt;Your budgeting logic simply becomes stale.&lt;/p&gt;

&lt;p&gt;The fix isn't just updating one constant—it's avoiding hardcoded pricing throughout the codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unknown model variants are another hidden risk
&lt;/h2&gt;

&lt;p&gt;Price changes often arrive alongside new model variants.&lt;/p&gt;

&lt;p&gt;If your routing layer starts sending traffic to a model that isn't registered in your pricing table, you have another problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MODEL_REGISTRY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-5.6-luna&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-5.6-terra&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-5.6-sol&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a request targets an unknown variant, the safest behavior is to &lt;strong&gt;fail before the request is sent&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Unknown pricing should never silently become zero pricing.&lt;/p&gt;

&lt;p&gt;A centralized model registry makes this much easier to manage than scattered constants across multiple services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat pricing as configuration, not code
&lt;/h2&gt;

&lt;p&gt;Provider pricing changes more often than most engineering teams expect.&lt;/p&gt;

&lt;p&gt;That means model prices should be treated like any other operational configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep pricing in one registry.&lt;/li&gt;
&lt;li&gt;Validate model IDs before requests.&lt;/li&gt;
&lt;li&gt;Update pricing independently of application logic.&lt;/li&gt;
&lt;li&gt;Fail loudly when pricing is missing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That approach makes repricing events predictable instead of surprising.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bigger lesson
&lt;/h2&gt;

&lt;p&gt;The real issue isn't that GPT-5.6 Luna became cheaper.&lt;/p&gt;

&lt;p&gt;It's that &lt;strong&gt;pricing is no longer static enough to hardcode&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As providers continue adding models, variants, and promotional pricing, cost controls need to adapt just as quickly.&lt;/p&gt;

&lt;p&gt;If your pricing lives in code, every provider announcement becomes a deployment.&lt;/p&gt;

&lt;p&gt;If your pricing lives in a validated registry, it's just another configuration update.&lt;br&gt;
&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Supabase's new agent benchmark reveals 3 lessons production AI agents still ignore</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Sun, 02 Aug 2026 04:25:59 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/supabases-new-agent-benchmark-reveals-3-lessons-production-ai-agents-still-ignore-4hil</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/supabases-new-agent-benchmark-reveals-3-lessons-production-ai-agents-still-ignore-4hil</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz0hppt3pozha2viv7uot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fz0hppt3pozha2viv7uot.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Supabase just open-sourced &lt;strong&gt;supabase/evals&lt;/strong&gt;, a benchmark that runs Claude Code, Codex, and OpenCode against real-world Supabase tasks using containerized environments, MCP servers, and live CLI tools.&lt;/p&gt;

&lt;p&gt;The scores are interesting.&lt;/p&gt;

&lt;p&gt;The engineering decisions behind the benchmark are even more valuable.&lt;/p&gt;

&lt;p&gt;Here are three choices that stood out—and why they matter if you're building AI agents in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. They capped retries
&lt;/h2&gt;

&lt;p&gt;Supabase allows &lt;strong&gt;one retry&lt;/strong&gt; before grading a task.&lt;/p&gt;

&lt;p&gt;The reason is simple: more retries reduce false negatives, but they also make evaluations more expensive. At some point, the benchmark stops being practical.&lt;/p&gt;

&lt;p&gt;Production agents usually don't have this discipline.&lt;/p&gt;

&lt;p&gt;Most frameworks let you cap total iterations, but that's different from limiting retries of the same failed action. An agent can fail several times, eventually succeed, and still burn far more tokens than expected.&lt;/p&gt;

&lt;p&gt;Success doesn't always mean efficiency.&lt;/p&gt;

&lt;p&gt;If you're running agents at scale, retry budgets deserve to be treated as first-class limits—not just an implementation detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Tool usage matters as much as accuracy
&lt;/h2&gt;

&lt;p&gt;One benchmark result caught my attention:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude Code averaged roughly &lt;strong&gt;2 documentation reads&lt;/strong&gt; per scenario.&lt;/li&gt;
&lt;li&gt;Codex averaged roughly &lt;strong&gt;8&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both may solve the task.&lt;/p&gt;

&lt;p&gt;One simply consumes much more context along the way.&lt;/p&gt;

&lt;p&gt;Accuracy leaderboards rarely show this, but production bills certainly do.&lt;/p&gt;

&lt;p&gt;When comparing models, measuring &lt;strong&gt;tool calls, token usage, and cost per completed task&lt;/strong&gt; is often more useful than looking at completion rate alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Better descriptions changed agent behavior dramatically
&lt;/h2&gt;

&lt;p&gt;Supabase noticed one internal skill was only activating about &lt;strong&gt;10%&lt;/strong&gt; of the time.&lt;/p&gt;

&lt;p&gt;They rewrote its description.&lt;/p&gt;

&lt;p&gt;Activation jumped to around &lt;strong&gt;60%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Nothing about the underlying capability changed—only how the agent understood when to use it.&lt;/p&gt;

&lt;p&gt;That's an important reminder that prompts, skill descriptions, and routing logic are part of your system design. If you only measure task success, you'll miss whether your agents are actually using the components you built.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bigger lesson
&lt;/h2&gt;

&lt;p&gt;None of these decisions were made because they're academically interesting.&lt;/p&gt;

&lt;p&gt;They were made because Supabase runs these evaluations every day, and daily benchmarks need predictable cost and reliability.&lt;/p&gt;

&lt;p&gt;Production agents face the same constraints.&lt;/p&gt;

&lt;p&gt;The difference is that benchmark designers build those limits in from day one, while production systems often discover them only after expensive failures.&lt;/p&gt;

&lt;p&gt;If I had to copy one idea immediately, it would be the retry cap.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/salimassili62-afk/ai-costguard" rel="noopener noreferrer"&gt;https://github.com/salimassili62-afk/ai-costguard&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Two Claude network failures this week. Here's the retry-logic bug they exposed.</title>
      <dc:creator>Assili Salim</dc:creator>
      <pubDate>Fri, 31 Jul 2026 11:34:29 +0000</pubDate>
      <link>https://dev.to/assili_salim_e3c07f9954de/two-claude-network-failures-this-week-heres-the-retry-logic-bug-they-exposed-33pa</link>
      <guid>https://dev.to/assili_salim_e3c07f9954de/two-claude-network-failures-this-week-heres-the-retry-logic-bug-they-exposed-33pa</guid>
      <description>&lt;p&gt;Over about 36 hours spanning July 29 to 31, Claude's serving infrastructure had four distinct incidents. Not one outage — four, each a different shape, each hitting a different scope.&lt;/p&gt;

&lt;p&gt;Per independent status tracking: a 40-minute drop across all models the evening of the 29th, a four-hour-plus window of elevated errors the next morning, a 40-minute "degraded performance" period on Claude Opus 4.8 that afternoon, and a shorter 9-minute degraded-performance blip on Claude Sonnet 5 the morning of the 31st. Anthropic's own statement named the mechanism for the first two: multiple separate network failures cut into serving capacity, and the reroute response itself caused some requests to fail.&lt;/p&gt;

&lt;p&gt;That last detail is the one worth building around. The fix caused failures of its own. If your circuit breaker only knows how to detect "down," this entire window looks like something else: flaky.&lt;/p&gt;

&lt;p&gt;Two failure shapes, two very different bills&lt;/p&gt;

&lt;p&gt;Hard failure. The provider returns a fast, clean error: connection refused, a 503, a timeout. Every reasonable retry library detects this on the first or second attempt and either backs off hard or opens a circuit. This is the failure mode most agent frameworks are built around, and it's genuinely the easy case.&lt;/p&gt;

&lt;p&gt;Capacity-shaped failure. This is what "elevated errors" and "reduced availability" actually mean in practice: some calls succeed, some time out, some fail, mixed together over hours, because the provider is serving from reduced capacity rather than serving nothing. A naive consecutive-failure breaker was never designed to catch this:&lt;/p&gt;

&lt;p&gt;typescript&lt;br&gt;
// Trips only on N &lt;em&gt;consecutive&lt;/em&gt; failures.&lt;br&gt;
// A capacity-shaped incident rarely produces&lt;br&gt;
// five failures in a row — it produces five failures&lt;br&gt;
// spread across forty successful calls.&lt;br&gt;
class NaiveBreaker {&lt;br&gt;
  private consecutiveFailures = 0;&lt;br&gt;
  private readonly threshold = 5;&lt;/p&gt;

&lt;p&gt;recordResult(ok: boolean) {&lt;br&gt;
    this.consecutiveFailures = ok ? 0 : this.consecutiveFailures + 1;&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;isOpen() {&lt;br&gt;
    return this.consecutiveFailures &amp;gt;= this.threshold;&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Every interspersed success resets the counter. The breaker never opens. Your retry logic keeps sampling a flaky distribution for four hours, and every sample is a billed call.&lt;/p&gt;

&lt;p&gt;The fix is to stop counting streaks and start tracking a rate over a window:&lt;/p&gt;

&lt;p&gt;typescript&lt;br&gt;
// Trips on error RATE over a rolling window,&lt;br&gt;
// regardless of whether failures are consecutive.&lt;br&gt;
class RollingRateBreaker {&lt;br&gt;
  private window: boolean[] = []; // true = success&lt;br&gt;
  private readonly windowSize = 20;&lt;br&gt;
  private readonly errorRateThreshold = 0.3;&lt;/p&gt;

&lt;p&gt;recordResult(ok: boolean) {&lt;br&gt;
    this.window.push(ok);&lt;br&gt;
    if (this.window.length &amp;gt; this.windowSize) this.window.shift();&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;isOpen() {&lt;br&gt;
    if (this.window.length &amp;lt; this.windowSize) return false;&lt;br&gt;
    const errorRate = this.window.filter((r) =&amp;gt; !r).length / this.window.length;&lt;br&gt;
    return errorRate &amp;gt;= this.errorRateThreshold;&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Twenty calls, six or more failures anywhere in the window, and it trips, whether those failures are clustered or scattered. That matches how capacity-shaped incidents actually behave.&lt;/p&gt;

&lt;p&gt;The bill waiting on the other side of recovery&lt;/p&gt;

&lt;p&gt;Here's the second cost, and it only shows up if your agent has a fallback provider configured. Say your harness fell back to a second model mid-incident. The task keeps running there. Then the primary recovers, and if nothing tracked which provider actually finished the job, you risk redoing the same work on both — paying twice for one logical task.&lt;/p&gt;

&lt;p&gt;This isn't hypothetical. It's specific enough that incident write-ups from this week explicitly warned people not to duplicate work across harnesses once the primary provider came back.&lt;/p&gt;

&lt;p&gt;The fix is a small reservation ledger keyed on the logical task, not the provider:&lt;/p&gt;

&lt;p&gt;typescript&lt;br&gt;
interface TaskAttempt {&lt;br&gt;
  taskId: string;&lt;br&gt;
  provider: string;&lt;br&gt;
  status: 'in_flight' | 'completed';&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const attempts = new Map();&lt;/p&gt;

&lt;p&gt;function beforeCall(taskId: string, provider: string) {&lt;br&gt;
  const existing = attempts.get(taskId) ?? [];&lt;br&gt;
  const doneElsewhere = existing.find(&lt;br&gt;
    (a) =&amp;gt; a.status === 'completed' &amp;amp;&amp;amp; a.provider !== provider&lt;br&gt;
  );&lt;/p&gt;

&lt;p&gt;if (doneElsewhere) {&lt;br&gt;
    throw new Error(&lt;br&gt;
      &lt;code&gt;Task ${taskId} already completed on ${doneElsewhere.provider}&lt;/code&gt;&lt;br&gt;
    );&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;existing.push({ taskId, provider, status: 'in_flight' });&lt;br&gt;
  attempts.set(taskId, existing);&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;One map. One check before the call goes out. It's the difference between "the outage cost us four hours of degraded service" and "the outage cost us four hours of degraded service, plus a duplicate invoice from the fallback provider we forgot was still running."&lt;/p&gt;

&lt;p&gt;What to actually change this week&lt;br&gt;
Replace consecutive-failure breakers with rolling-rate breakers, at least for provider calls.&lt;br&gt;
If you run a fallback provider, key task completion by task ID, not by provider, and check it before every call, not just the first one.&lt;br&gt;
Treat "degraded performance" status entries as a distinct alert category from "down." They're not lower priority. They're the ones your retry logic is least equipped to handle.&lt;/p&gt;

&lt;p&gt;None of this prevents a network failure. It's the layer that decides what a network failure costs you afterward.&lt;/p&gt;

&lt;p&gt;This is the exact class of failure AI CostGuard checks for before a call executes: not whether the provider is up, but whether the call about to go out is one your session has already paid for somewhere else.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>llm</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
