Skip to content

Commit 413a87f

Browse files
authored
fix(pricing): price StepFun step-5-preview from the supplemental set (#1874)
Sessions that persist the model `step-5-preview` come back unpriced. The pinned LiteLLM snapshot (`litellm-6417938744b4`) has no `stepfun` entries, and the periodic refresh can't fix it until upstream lists the model, so I added a curated supplemental row in `internal/pricing/supplemental.go` following the existing `kimi-k3` rows. Both `step-5-preview` and `stepfun/step-5-preview` resolve to it through the canonical fallback. Like the other supplemental rows it's a fallback rather than a pin, so a later LiteLLM refresh replaces it once upstream publishes the model. The rates are the published USD list prices from StepFun's Open Platform rate card, <https://platform.stepfun.ai/docs/en/guides/pricing/details>, which I read on 2026-09-21: input $1.00 per MTok on a cache miss, cache read $0.05, output $2.70. The same page notes the cache-miss input price includes writing new content to the cache, so cache creation uses the input rate instead of a separate number. StepFun also publishes a CNY card at `platform.stepfun.com`; I used the international USD card because the catalog is denominated in dollars. A row added to `supplementalPricing` alone wouldn't reach archives that are already seeded, because `supplementalVersion` is folded into `pricing.SeedVersion` and the startup seed skips when the stored `_fallback_version` matches. I bumped it from 4 to 5 so the mismatch makes `SeedFallback` upsert the fallback set and pick up the new row without a resync. The regression tests fail before the change: `Resolve` finds no pricing for either spelling, and a database holding `+supplemental-4` doesn't gain the row. Reviewer focus is the rate mapping in `supplemental.go` and the version bump. Fixes #1862 Co-authored-by: Tung Lam <[email protected]>
1 parent 13ec495 commit 413a87f

4 files changed

Lines changed: 84 additions & 2 deletions

File tree

‎cmd/agentsview/pricing_seed_test.go‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,29 @@ func TestSeedFallbackPricing_UpgradesExistingDBWithSupplementals(t *testing.T) {
6565
assert.Equal(t, pricing.SeedVersion, meta)
6666
}
6767

68+
// TestSeedFallbackPricing_UpgradesExistingDBWithStepFunRow proves the
69+
// supplemental bump reaches databases seeded by the previous binary: a
70+
// DB whose meta holds the prior seed version re-seeds on startup and
71+
// gains the step-5-preview row without a resync.
72+
func TestSeedFallbackPricing_UpgradesExistingDBWithStepFunRow(t *testing.T) {
73+
database := newTestDB(t)
74+
require.NoError(t, database.SetPricingMeta("_fallback_version",
75+
pricing.FallbackVersion+"+supplemental-4"))
76+
77+
require.NoError(t, pricingrefresh.SeedFallback(database))
78+
79+
row, err := database.GetModelPricing("step-5-preview")
80+
require.NoError(t, err)
81+
require.NotNil(t, row, "step-5-preview must be seeded after the version bump")
82+
assert.Equal(t, money.MustParseDollars("1.00"), row.InputPerMTok)
83+
assert.Equal(t, money.MustParseDollars("2.70"), row.OutputPerMTok)
84+
assert.Equal(t, money.MustParseDollars("0.05"), row.CacheReadPerMTok)
85+
86+
meta, err := database.GetPricingMeta("_fallback_version")
87+
require.NoError(t, err)
88+
assert.Equal(t, pricing.SeedVersion, meta)
89+
}
90+
6891
// TestSeedFallbackPricing_DeletesStaleDateAliasRows proves the
6992
// supplemental-v2 upgrade deletes the flat K2.6 rows older binaries
7093
// seeded for the date-ambiguous aliases: an exact-match row would

‎docs/changelog.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ The latest published release is
3333
`originator=codex_exec`. Sessions tagged `thread_source=roborev` keep that
3434
more specific kind so roborev reviews are identifiable as code review.
3535
Restart or run `agentsview sync` so existing exec sessions reparse.
36+
- Price StepFun `step-5-preview` sessions from the supplemental rates instead of
37+
leaving them unpriced. The pinned LiteLLM snapshot has no `stepfun` rows, so
38+
existing databases reseed the new row on startup.
3639

3740
## 0.43.0
3841

‎internal/pricing/supplemental.go‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ import (
1717
// deletes their stale rows) and k3/k3-agent moved from K2.6 to K3
1818
// rates. Version 3 removed moonshot/kimi-k3 after LiteLLM added it.
1919
// Version 4 adds namespaced Codex mappings and a temporary Bedrock Astra
20-
// fallback until the pinned LiteLLM snapshot includes it.
21-
const supplementalVersion = "4"
20+
// fallback until the pinned LiteLLM snapshot includes it. Version 5 adds
21+
// a StepFun step-5-preview row, which the pinned snapshot lacks.
22+
const supplementalVersion = "5"
2223

2324
// Canonical pricing models runtime aliases resolve to.
2425
// KimiK26Canonical exists in the embedded LiteLLM snapshot;
@@ -228,6 +229,17 @@ var supplementalPricing = []ModelPricing{
228229
CacheCreationPerMTok: money.Money{},
229230
CacheReadPerMTok: money.MustParseDollars("0.30"),
230231
},
232+
{
233+
// StepFun publishes step-5-preview at input 1.00 (cache miss,
234+
// which includes writing new content to the cache), cache read
235+
// 0.05, and output 2.70 USD per MTok; read 2026-09-21 from
236+
// https://platform.stepfun.ai/docs/en/guides/pricing/details.
237+
ModelPattern: "step-5-preview",
238+
InputPerMTok: money.MustParseDollars("1.00"),
239+
OutputPerMTok: money.MustParseDollars("2.70"),
240+
CacheCreationPerMTok: money.MustParseDollars("1.00"),
241+
CacheReadPerMTok: money.MustParseDollars("0.05"),
242+
},
231243
}
232244

233245
// SupplementalPricing returns the curated fallback set, copied for caller

‎internal/pricing/supplemental_test.go‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,50 @@ func TestSupplementalPricing_KimiK3StaticAliases(t *testing.T) {
5252
GPT56LunaCanonical)
5353
}
5454

55+
// TestSupplementalPricing_StepFunStep5Preview pins the curated StepFun
56+
// row. The pinned LiteLLM snapshot has no stepfun entries at all, so a
57+
// step-5-preview session otherwise reports unpriced. Rates are
58+
// StepFun's published USD list prices, read 2026-09-21 from
59+
// <https://platform.stepfun.ai/docs/en/guides/pricing/details>. That
60+
// page notes the cache-miss input price includes writing new content
61+
// to the cache, so cache creation bills at the input rate.
62+
func TestSupplementalPricing_StepFunStep5Preview(t *testing.T) {
63+
fallback := requireEmbeddedFallbackPricing(t)
64+
byPattern := make(map[string]ModelPricing, len(fallback))
65+
for _, p := range fallback {
66+
byPattern[p.ModelPattern] = p
67+
}
68+
69+
want := ModelPricing{
70+
ModelPattern: "step-5-preview",
71+
InputPerMTok: money.MustParseDollars("1.00"),
72+
OutputPerMTok: money.MustParseDollars("2.70"),
73+
CacheCreationPerMTok: money.MustParseDollars("1.00"),
74+
CacheReadPerMTok: money.MustParseDollars("0.05"),
75+
}
76+
// The bare name and the provider-qualified spelling both resolve to
77+
// the same curated row.
78+
for _, model := range []string{"step-5-preview", "stepfun/step-5-preview"} {
79+
got, ok := Resolve(byPattern, model)
80+
require.True(t, ok, "Resolve(%q) found no pricing", model)
81+
assertFlatPricing(t, want, got)
82+
}
83+
84+
// An unrelated model keeps resolving to its own catalog row.
85+
var unrelated ModelPricing
86+
for _, p := range requireEmbeddedFallbackSnapshot(t).Models {
87+
if p.ModelPattern == "claude-opus-4-6" {
88+
unrelated = p
89+
break
90+
}
91+
}
92+
require.NotEmpty(t, unrelated.ModelPattern)
93+
got, ok := Resolve(byPattern, unrelated.ModelPattern)
94+
require.True(t, ok, "unrelated model %q should still resolve",
95+
unrelated.ModelPattern)
96+
assert.Equal(t, unrelated, got)
97+
}
98+
5599
func TestDateAliasedModels(t *testing.T) {
56100
assert.Equal(t, []string{
57101
"daimon-kimi-code",

0 commit comments

Comments
 (0)