provider: a Codex warm-up asks the account's cheapest model (#604) — warmModel took a model with mini in its id or else the first listed, and a GPT-6 account lists no mini and starts with the flagship gpt-6.1-sol. warmPick takes the cheapest by list price (the model's own, else models.dev's openai price), and with no price known a mini, then a luna (GPT-6's cheap one), then the first. TestWarmPick.
This commit is contained in:
1 parent
5154df624f
commit
1e80a84fe3
2 files changed
+67
-5
No files matched your search
@@ -350,7 +350,7 @@ func warmCodexLogin(ctx context.Context, user string) error {
|
||||
}
|
||||
|
||||
// warmModel is the model a warm-up asks, and at what effort: the account's
|
||||
// smallest (a mini) or else the first it lists, at low.
|
||||
// cheapest (warmPick), at low.
|
||||
func warmModel(user string) (model, effort string, err error) {
|
||||
ms, _, ok := catalog.Live(accountModels("codex", user))
|
||||
if !ok {
|
||||
@@ -362,10 +362,7 @@ func warmModel(user string) (model, effort string, err error) {
|
||||
if len(ms) == 0 {
|
||||
return "", "", errors.New("no Codex model is known yet")
|
||||
}
|
||||
m := ms[0]
|
||||
if i := slices.IndexFunc(ms, func(m catalog.Model) bool { return strings.Contains(m.ID, "mini") }); i >= 0 {
|
||||
m = ms[i]
|
||||
}
|
||||
m := warmPick(ms, func(id string) (catalog.Price, bool) { return catalog.PricedBy([]string{"openai"}, id) })
|
||||
switch {
|
||||
case slices.Contains(m.Efforts, "low"):
|
||||
effort = "low"
|
||||
@@ -375,6 +372,34 @@ func warmModel(user string) (model, effort string, err error) {
|
||||
return m.ID, effort, nil
|
||||
}
|
||||
|
||||
// warmPick is the cheapest of an account's models, by its list price where
|
||||
// models.dev has one (#604: GPT-6's cheap one is gpt-6-luna; the list
|
||||
// has no mini and starts with the flagship gpt-6.1-sol); with no price
|
||||
// known, a mini, else a luna, else the first it lists.
|
||||
func warmPick(ms []catalog.Model, price func(id string) (catalog.Price, bool)) catalog.Model {
|
||||
best, cost := -1, 0.0
|
||||
for i, m := range ms {
|
||||
p, ok := catalog.Price{}, false
|
||||
if m.Price != nil {
|
||||
p, ok = *m.Price, true
|
||||
} else {
|
||||
p, ok = price(m.ID)
|
||||
}
|
||||
if c := p.Input + p.Output; ok && c > 0 && (best < 0 || c < cost) {
|
||||
best, cost = i, c
|
||||
}
|
||||
}
|
||||
if best >= 0 {
|
||||
return ms[best]
|
||||
}
|
||||
for _, word := range []string{"mini", "luna"} {
|
||||
if i := slices.IndexFunc(ms, func(m catalog.Model) bool { return strings.Contains(m.ID, word) }); i >= 0 {
|
||||
return ms[i]
|
||||
}
|
||||
}
|
||||
return ms[0]
|
||||
}
|
||||
|
||||
// warmCodex sends one "hi" to the ChatGPT backend as a Codex account's
|
||||
// requests go (codexBody: Codex's instructions, not stored), and reads the
|
||||
// reply to its end.
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/yetone/magpie/internal/catalog"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -280,3 +282,38 @@ func TestCodexWarmRequest(t *testing.T) {
|
||||
t.Fatalf("not kept: %v", CodexWarmed())
|
||||
}
|
||||
}
|
||||
|
||||
// #604: the warm-up asks the cheapest model, by price where it is known,
|
||||
// else a mini, else a luna, else the first listed.
|
||||
func TestWarmPick(t *testing.T) {
|
||||
ids := func(ids ...string) []catalog.Model {
|
||||
ms := make([]catalog.Model, len(ids))
|
||||
for i, id := range ids {
|
||||
ms[i] = catalog.Model{ID: id}
|
||||
}
|
||||
return ms
|
||||
}
|
||||
prices := map[string]catalog.Price{
|
||||
"gpt-6.1-sol": {Input: 2, Output: 10}, "gpt-6-astra": {Input: 10, Output: 50},
|
||||
"gpt-6-luna": {Input: 0.1, Output: 0.5}, "gpt-5.6-luna": {Input: 0.2, Output: 1.2},
|
||||
}
|
||||
priced := func(id string) (catalog.Price, bool) { p, ok := prices[id]; return p, ok }
|
||||
none := func(string) (catalog.Price, bool) { return catalog.Price{}, false }
|
||||
gpt6 := ids("gpt-6.1-sol", "gpt-6-astra", "gpt-6-sol", "gpt-6-luna", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-5.5")
|
||||
for _, c := range []struct {
|
||||
name string
|
||||
ms []catalog.Model
|
||||
price func(string) (catalog.Price, bool)
|
||||
want string
|
||||
}{
|
||||
{"priced", gpt6, priced, "gpt-6-luna"},
|
||||
{"no prices: a luna", gpt6, none, "gpt-6-luna"},
|
||||
{"no prices: a mini first", ids("gpt-5-codex", "gpt-5-codex-mini", "gpt-6-luna"), none, "gpt-5-codex-mini"},
|
||||
{"no prices, no cheap name", ids("gpt-6.1-sol", "gpt-6-sol"), none, "gpt-6.1-sol"},
|
||||
{"the model's own price first", []catalog.Model{{ID: "gpt-6.1-sol"}, {ID: "x", Price: &catalog.Price{Input: 0.01, Output: 0.01}}}, priced, "x"},
|
||||
} {
|
||||
if got := warmPick(c.ms, c.price).ID; got != c.want {
|
||||
t.Errorf("%s: %s, want %s", c.name, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user