inference: declare Gemini 3.7 Flash published rates (refs OpenAgentsInc/openagents#262)

258a25250208 · AtlantisPleb · · parent 52a9102bcbd6

inference: declare Gemini 3.7 Flash published rates (refs OpenAgentsInc/openagents#262)

Replace the placeholder Gemini rates with Google's Standard paid-tier table.
List rates apply from 2027-01-01; the introductory promotion is half those
rates through that exclusive UTC cutoff. Only declared rates bill (METER-001).

Deploy story

What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.

pushed
by user · WAL seq 474 · 2026-08-28T05:14:13.798481Z

Changed files

  • modified config/config.exs
  • modified lib/openagents_web/live/model_catalog_live.ex
  • modified test/openagents/inference/models_test.exs
  • modified test/openagents/inference/pricing_test.exs
  • modified test/openagents_web/controllers/inference_proxy_fallback_test.exs
  • modified test/openagents_web/controllers/model_catalog_controller_test.exs
  • modified test/openagents_web/live/model_catalog_live_test.exs

Diff

7 files changed, +85 -51

config/config.exs modified +21 -21

@@ -139,19 +139,10 @@ config :openagents,

139 139
  # (including omitting it) for a working figure. `OpenAgents.Inference.Pricing`
140 140
  # reads that word, and only `:declared` is billable (METER-001).
141 141
  #
142
  # Every rate below is a placeholder: no operator has declared any of them, so
143
  # all of them say `:placeholder` and nothing may bill from a cost they
144
  # produced. Replacing them is an owner action: enter the provider's rates and
145
  # set `source: :declared` in the same edit.
146
  #
147
  # The GLM 5.3 Flash figures are the ones to be careful with. Its posted rates
148
  # on 2026-08-26 were $0.075 in, $0.25 out, and $0.015 cached in per million
149
  # tokens — a limited-time half-price offer that ends 2026-09-09 16:00 UTC,
150
  # after which list price is $0.15, $0.50, and $0.03. The entry carries list
151
  # price, because a figure that silently doubles in two weeks is worse than
152
  # one that is honestly high, and because neither figure is declared either
153
  # way. The Gemini figures were written to make the system run and were not
154
  # read off any price page.
142
  # Declared rates are the provider's published table, entered here so a call
143
  # can be billed (METER-001). A time-bounded `promotion` replaces that table
144
  # until its exclusive UTC cutoff, then the regular table applies without
145
  # another deployment.
155 146
  #
156 147
  # A model with no `pricing` key records no estimated cost at all — not a zero
157 148
  # — and its usage records stamp `pricing_id: "unpriced"`. No entry below is in

@@ -251,15 +242,24 @@ config :openagents,

251 242
      provider_model: "google/gemini-3.7-flash",
252 243
      context_window: 1_048_576,
253 244
      max_output: 65_536,
254
      # Placeholder: the operator must set real provider rates and flip `source`
255
      # to `:declared` before anything bills from this. The cached-input rate is
256
      # optional and should be omitted if the provider does not offer one.
245
      # Google's published Standard paid-tier table for Gemini 3.7 Flash
246
      # (https://ai.google.dev/gemini-api/docs/pricing). List rates apply from
247
      # 2027-01-01; the introductory promotion is half those rates through the
248
      # exclusive UTC cutoff, the same shape as GLM's promotion.
257 249
      pricing: %{
258
        id: "placeholder.gemini-3.7-flash.v1",
259
        source: :placeholder,
260
        input_per_million_tokens: 1_250_000,
261
        output_per_million_tokens: 10_000_000,
262
        cached_input_per_million_tokens: 100_000
250
        id: "declared.gemini-3.7-flash.v1",
251
        source: :declared,
252
        input_per_million_tokens: 1_500_000,
253
        output_per_million_tokens: 7_500_000,
254
        cached_input_per_million_tokens: 150_000,
255
        promotion: %{
256
          id: "declared.gemini-3.7-flash.intro-through-2026-12-31.v1",
257
          source: :declared,
258
          ends_at: ~U[2027-01-01 00:00:00Z],
259
          input_per_million_tokens: 750_000,
260
          output_per_million_tokens: 3_750_000,
261
          cached_input_per_million_tokens: 75_000
262
        }
263 263
      }
264 264
    },
265 265
    %{
lib/openagents_web/live/model_catalog_live.ex modified +2 -1

@@ -21,7 +21,8 @@ defmodule OpenAgentsWeb.ModelCatalogLive do

21 21
  different fact from the call having cost nothing. And a rate this deployment
22 22
  wrote to make itself run is labelled `provisional`, so nobody reads a working
23 23
  figure as a price. The Coder Free lane declares zero rates because its router
24
  only selects free models; the other listed rates remain provisional.
24
  only selects free models; GLM 5.3 Flash and Gemini 3.7 Flash declare the
25
  provider's published rates, including any active promotion.
25 26
26 27
  Availability is `Models.availability/1`, the same word the endpoint
27 28
  publishes, refreshed on a slow tick: a page about what a lane costs that
test/openagents/inference/models_test.exs modified +7 -3

@@ -152,9 +152,13 @@ defmodule OpenAgents.Inference.ModelsTest do

152 152
      gemini = Enum.find(Models.catalog(), &(&1["id"] == "gemini-3.7-flash"))
153 153
154 154
      assert %{"pricing" => pricing} = gemini
155
      assert pricing["input_per_million_tokens"] == 1_250_000
156
      assert pricing["output_per_million_tokens"] == 10_000_000
157
      assert pricing["cached_input_per_million_tokens"] == 100_000
155
      assert pricing["id"] == "declared.gemini-3.7-flash.intro-through-2026-12-31.v1"
156
      assert pricing["basis"] == "declared"
157
      assert pricing["input_per_million_tokens"] == 750_000
158
      assert pricing["output_per_million_tokens"] == 3_750_000
159
      assert pricing["cached_input_per_million_tokens"] == 75_000
160
      assert gemini["pricing_promotion"]["ends_at"] == "2027-01-01T00:00:00Z"
161
      assert gemini["pricing_promotion"]["active"]
158 162
    end
159 163
160 164
    test "the default publishes its currently effective rate table" do
test/openagents/inference/pricing_test.exs modified +40 -15

@@ -43,7 +43,8 @@ defmodule OpenAgents.Inference.PricingTest do

43 43
    end
44 44
45 45
    test "a lane with rates publishes the table those rates came from" do
46
      assert Pricing.pricing_id_for("gemini-3.7-flash") == "placeholder.gemini-3.7-flash.v1"
46
      assert Pricing.pricing_id_for("gemini-3.7-flash") ==
47
               "declared.gemini-3.7-flash.intro-through-2026-12-31.v1"
47 48
    end
48 49
49 50
    test "rates without a table name are unattributed rather than silently accepted" do

@@ -88,6 +89,30 @@ defmodule OpenAgents.Inference.PricingTest do

88 89
    end
89 90
  end
90 91
92
  describe "the Gemini 3.7 Flash published rates" do
93
    test "uses intro rates before the cutoff and list rates at the cutoff" do
94
      {:ok, gemini} = OpenAgents.Inference.Models.fetch("gemini-3.7-flash")
95
96
      introductory = Pricing.effective_pricing(gemini, ~U[2026-12-31 23:59:59.999999Z])
97
      list = Pricing.effective_pricing(gemini, ~U[2027-01-01 00:00:00Z])
98
99
      assert introductory.id == "declared.gemini-3.7-flash.intro-through-2026-12-31.v1"
100
      assert introductory.source == :declared
101
      assert introductory.input_per_million_tokens == 750_000
102
      assert introductory.output_per_million_tokens == 3_750_000
103
      assert introductory.cached_input_per_million_tokens == 75_000
104
      assert Pricing.promotion_active?(gemini, ~U[2026-12-31 23:59:59Z])
105
106
      assert list.id == "declared.gemini-3.7-flash.v1"
107
      assert list.source == :declared
108
      assert list.input_per_million_tokens == 1_500_000
109
      assert list.output_per_million_tokens == 7_500_000
110
      assert list.cached_input_per_million_tokens == 150_000
111
      refute Pricing.promotion_active?(gemini, ~U[2027-01-01 00:00:00Z])
112
      assert Pricing.promotion_ends_at(gemini) == ~U[2027-01-01 00:00:00Z]
113
    end
114
  end
115
91 116
  describe "pricing one usage record" do
92 117
    test "an unpriced model writes no cost key — not a zero" do
93 118
      priced =

@@ -104,9 +129,10 @@ defmodule OpenAgents.Inference.PricingTest do

104 129
      priced =
105 130
        Pricing.price(%{"input_tokens" => 1_000_000, "output_tokens" => 0}, "gemini-3.7-flash")
106 131
107
      assert priced["estimated_cost_microusd"] == 1_250_000
108
      assert priced["pricing_id"] == "placeholder.gemini-3.7-flash.v1"
109
      assert Pricing.cost(priced) == 1_250_000
132
      # Test `pricing_now` is 2026-09-01, inside the introductory promotion.
133
      assert priced["estimated_cost_microusd"] == 750_000
134
      assert priced["pricing_id"] == "declared.gemini-3.7-flash.intro-through-2026-12-31.v1"
135
      assert Pricing.cost(priced) == 750_000
110 136
    end
111 137
112 138
    test "cached reads are charged at the cached rate and cache writes at the input rate" do

@@ -121,19 +147,19 @@ defmodule OpenAgents.Inference.PricingTest do

121 147
          "gemini-3.7-flash"
122 148
        )
123 149
124
      # 600k uncached input + 100k cache write at $1.25/M, 400k cached read at
125
      # $0.10/M: 700_000 * 1.25 + 400_000 * 0.10, in microUSD.
126
      assert priced["estimated_cost_microusd"] == 875_000 + 40_000
150
      # 600k uncached input + 100k cache write at $0.75/M, 400k cached read at
151
      # $0.075/M: 700_000 * 0.75 + 400_000 * 0.075, in microUSD.
152
      assert priced["estimated_cost_microusd"] == 525_000 + 30_000
127 153
    end
128 154
  end
129 155
130 156
  describe "reading a stored record back" do
131
    test "a placeholder-priced record carries a cost but is not billable" do
157
    test "a declared Gemini record carries a cost and is billable" do
132 158
      priced = Pricing.price(%{"input_tokens" => 1_000_000}, "gemini-3.7-flash")
133 159
134 160
      assert Pricing.priced?(priced)
135
      assert Pricing.usage_basis(priced) == "provisional"
136
      refute Pricing.billable?(priced)
161
      assert Pricing.usage_basis(priced) == "declared"
162
      assert Pricing.billable?(priced)
137 163
    end
138 164
139 165
    test "an unpriced record is never billable" do

@@ -176,8 +202,7 @@ defmodule OpenAgents.Inference.PricingTest do

176 202
177 203
      glm = Enum.find(OpenAgents.Inference.Models.catalog(), &(&1["id"] == "glm-5.3-flash"))
178 204
179
      assert Enum.count(bases, &(&1 == "declared")) >= 2
180
      assert "provisional" in bases
205
      assert Enum.all?(bases, &(&1 == "declared"))
181 206
      assert free_router["pricing"]["input_per_million_tokens"] == 0
182 207
      assert free_router["pricing"]["output_per_million_tokens"] == 0
183 208
      assert glm["pricing"]["input_per_million_tokens"] == 150_000

@@ -196,9 +221,9 @@ defmodule OpenAgents.Inference.PricingTest do

196 221
        OpenAgents.Inference.Models.catalog()
197 222
        |> Enum.find(&(&1["id"] == "gemini-3.7-flash"))
198 223
199
      assert gemini["pricing"]["id"] == "placeholder.gemini-3.7-flash.v1"
200
      assert gemini["pricing"]["basis"] == "provisional"
201
      assert gemini["pricing_basis"] == "provisional"
224
      assert gemini["pricing"]["id"] == "declared.gemini-3.7-flash.intro-through-2026-12-31.v1"
225
      assert gemini["pricing"]["basis"] == "declared"
226
      assert gemini["pricing_basis"] == "declared"
202 227
    end
203 228
  end
204 229
end
test/openagents_web/controllers/inference_proxy_fallback_test.exs modified +4 -1

@@ -261,7 +261,10 @@ defmodule OpenAgentsWeb.InferenceProxyFallbackTest do

261 261
262 262
      metered = Repo.get(Grant, grant.id)
263 263
      assert metered.usage["served_model"] == @gemini
264
      assert metered.usage["pricing_id"] == "placeholder.gemini-3.7-flash.v1"
264
265
      assert metered.usage["pricing_id"] ==
266
               "declared.gemini-3.7-flash.intro-through-2026-12-31.v1"
267
265 268
      assert Pricing.cost(metered.usage) > 0
266 269
      assert Health.status(@gemini) == {:healthy, nil}
267 270
    end
test/openagents_web/controllers/model_catalog_controller_test.exs modified +6 -6

@@ -110,9 +110,9 @@ defmodule OpenAgentsWeb.ModelCatalogControllerTest do

110 110
111 111
      assert %{
112 112
               "pricing" => %{
113
                 "input_per_million_tokens" => 1_250_000,
114
                 "output_per_million_tokens" => 10_000_000,
115
                 "cached_input_per_million_tokens" => 100_000
113
                 "input_per_million_tokens" => 750_000,
114
                 "output_per_million_tokens" => 3_750_000,
115
                 "cached_input_per_million_tokens" => 75_000
116 116
               }
117 117
             } = gemini
118 118
    end

@@ -151,9 +151,9 @@ defmodule OpenAgentsWeb.ModelCatalogControllerTest do

151 151
               "unpriced"
152 152
153 153
      gemini = Enum.find(body["models"], &(&1["id"] == "gemini-3.7-flash"))
154
      assert gemini["pricing_basis"] == "provisional"
155
      assert gemini["pricing"]["basis"] == "provisional"
156
      assert gemini["pricing"]["id"] == "placeholder.gemini-3.7-flash.v1"
154
      assert gemini["pricing_basis"] == "declared"
155
      assert gemini["pricing"]["basis"] == "declared"
156
      assert gemini["pricing"]["id"] == "declared.gemini-3.7-flash.intro-through-2026-12-31.v1"
157 157
    end
158 158
  end
159 159
end
test/openagents_web/live/model_catalog_live_test.exs modified +5 -4

@@ -55,12 +55,13 @@ defmodule OpenAgentsWeb.ModelCatalogLiveTest do

55 55
  test "a lane with rates publishes them and names the table they came from", %{conn: conn} do
56 56
    {:ok, view, _html} = live(reader(conn, "model-catalog-priced"), ~p"/models")
57 57
58
    # 1_250_000 microUSD per million tokens is $1.25 per million tokens.
59
    assert view |> element(~s([id="model-input-rate-gemini-3.7-flash"])) |> render() =~ "$1.25"
60
    assert view |> element(~s([id="model-basis-gemini-3.7-flash"])) |> render() =~ "provisional"
58
    # 750_000 microUSD per million tokens is $0.75 per million tokens, the
59
    # introductory Standard paid-tier rate still in force at test `pricing_now`.
60
    assert view |> element(~s([id="model-input-rate-gemini-3.7-flash"])) |> render() =~ "$0.75"
61
    assert view |> element(~s([id="model-basis-gemini-3.7-flash"])) |> render() =~ "declared"
61 62
62 63
    assert view |> element(~s([id="model-pricing-id-gemini-3.7-flash"])) |> render() =~
63
             "placeholder.gemini-3.7-flash.v1"
64
             "declared.gemini-3.7-flash.intro-through-2026-12-31.v1"
64 65
  end
65 66
66 67
  test "the declared free router is billable at zero", %{conn: conn} do

This page updates live while a promote is in flight · changelog