mirror of
https://github.com/docker/docker-agent.git
synced 2026-11-04 10:02:15 +00:00
Remove the model allowlist and instead derive the Fast tier premium from matching catalogue entries, falling back to the documented multiplier when metadata is missing or inconsistent. Endpoint and cost-override guards, tests, and docs are preserved. Signed-off-by: David Gageot <david.gageot@docker.com>
107 lines
2.9 KiB
Go
107 lines
2.9 KiB
Go
package modelsdev
|
|
|
|
import (
|
|
"math"
|
|
"slices"
|
|
"time"
|
|
)
|
|
|
|
// ForServiceTier estimates tier pricing from the actual response tier without mutating c.
|
|
// Other providers and unrecognized tiers retain their catalogue pricing.
|
|
func (c *Cost) ForServiceTier(id ID, tier string) *Cost {
|
|
if c == nil || id.Provider != "openai" {
|
|
return c
|
|
}
|
|
// Current tier premiums; models with different rates need a cost override.
|
|
// https://developers.openai.com/api/docs/pricing
|
|
var factor float64
|
|
switch tier {
|
|
case "fast", "priority":
|
|
factor = c.fastMultiplier
|
|
if factor == 0 {
|
|
factor = 2
|
|
}
|
|
case "ultrafast":
|
|
factor = 6
|
|
default:
|
|
return c
|
|
}
|
|
|
|
out := *c
|
|
out.Input *= factor
|
|
out.Output *= factor
|
|
out.CacheRead *= factor
|
|
out.CacheWrite *= factor
|
|
out.Tiers = slices.Clone(c.Tiers)
|
|
for i := range out.Tiers {
|
|
out.Tiers[i].Input *= factor
|
|
out.Tiers[i].Output *= factor
|
|
out.Tiers[i].CacheRead *= factor
|
|
out.Tiers[i].CacheWrite *= factor
|
|
}
|
|
return &out
|
|
}
|
|
|
|
// withFastPricing derives a uniform premium only when gateway and vendor base rates agree.
|
|
func (c *Cost) withFastPricing(db *Database, id ID) *Cost {
|
|
if c == nil || id.Provider != "openai" {
|
|
return c
|
|
}
|
|
models := db.Providers["vercel"].Models
|
|
model := id.Model
|
|
for {
|
|
standard := models["openai/"+model].Cost
|
|
fast := models["openai/"+model+"-fast"].Cost
|
|
if standard != nil && fast != nil && standard.RatesFor(0) == c.RatesFor(0) {
|
|
if factor := uniformPremium(standard, fast); factor > 0 {
|
|
out := *c
|
|
out.fastMultiplier = factor
|
|
return &out
|
|
}
|
|
}
|
|
// Dated models may share the alias's pricing, but never assume its base rates match.
|
|
if len(model) <= len("-2006-01-02") {
|
|
return c
|
|
}
|
|
cut := len(model) - len("2006-01-02")
|
|
if model[cut-1] != '-' {
|
|
return c
|
|
}
|
|
if _, err := time.Parse(time.DateOnly, model[cut:]); err != nil {
|
|
return c
|
|
}
|
|
model = model[:cut-1]
|
|
}
|
|
}
|
|
|
|
func uniformPremium(standard, fast *Cost) float64 {
|
|
factor := fast.Input / standard.Input
|
|
if factor < 1 || math.IsNaN(factor) || math.IsInf(factor, 0) {
|
|
return 0
|
|
}
|
|
matches := func(base, premium Rates) bool {
|
|
return closeRate(base.Input*factor, premium.Input) &&
|
|
closeRate(base.Output*factor, premium.Output) &&
|
|
closeRate(base.CacheRead*factor, premium.CacheRead) &&
|
|
closeRate(base.CacheWrite*factor, premium.CacheWrite)
|
|
}
|
|
if !matches(standard.RatesFor(0), fast.RatesFor(0)) {
|
|
return 0
|
|
}
|
|
for _, tier := range fast.Tiers {
|
|
if tier.Tier.Size < 0 || tier.Tier.Size == math.MaxInt64 || (tier.Tier.Type != "" && tier.Tier.Type != "context") {
|
|
return 0
|
|
}
|
|
// Gateway thresholds may name the first long-context token, rather than the last short one.
|
|
if !matches(standard.RatesFor(tier.Tier.Size+1), tier.Rates) {
|
|
return 0
|
|
}
|
|
}
|
|
return factor
|
|
}
|
|
|
|
func closeRate(a, b float64) bool {
|
|
return !math.IsNaN(a) && !math.IsNaN(b) && !math.IsInf(a, 0) && !math.IsInf(b, 0) &&
|
|
math.Abs(a-b) <= 1e-9*math.Max(1, math.Max(math.Abs(a), math.Abs(b)))
|
|
}
|