gateway: with "only each model's largest window" on, Claude Desktop shows a model of 1M or more as its 1M entry, "1M context window", not as what looked like the plain model (杰多夫 on Discord)
The cause: under settings.DesktopLongest, /v1/models lists such a model by its "[1m]" id alone (#1272). Claude Desktop 2.7032 (app.asar, read only) marks an entry as the 1M one only on the entry it adds itself: JLt emits `${id}[1m]` with description WLt = "1M context window" and supports_1m_context, and only for a model with supports1m. PIt gives supports1m to a bare id alone (LC(id) === id), and OIt folds a "[1m]" row only into a bare one listed beside it. So the lone "[1m]" row was shown by its name with no description, exactly like the plain entry it replaced: with the switch off the menu had "DeepSeek V4 Pro" plus "DeepSeek V4 Pro · 1M context window"; on, only "DeepSeek V4 Pro". The reporter read that as the switch keeping the plain model and dropping the 1M one. What changed: such a row now carries description "1M context window", the words Desktop gives its own 1M entry, and Desktop shows a row's description (PIt keeps it; JLt prefers it to its fallback). The id is unchanged: the "[1m]" is what gives a Claude Code session the 1M window, and magpie serves it as the plain model. Rows under 1M, and every row with the switch off, are unchanged (no description). What was run: - TestClaudeDesktopLongestOnly now checks each row's description, on and off. With the description line removed it fails: "on: vend/deepseek-v4-pro (...[1m]) described "", want "1M context window"". - Sandbox HOME gateway on 127.0.0.1:3561 with real providers, /v1/models as Claude Desktop asks for it, fed through a script that follows PIt/OIt/JLt: on, each 1M model is one entry "<name> · 1M context window"; off, the plain entry plus Desktop's own 1M one, as before. - gofmt -l; GOOS=linux and GOOS=windows go vet -tags nogui ./internal/gateway; go test -tags nogui ./internal/gateway under a temp HOME: ok. No GUI or string change.
This commit is contained in:
1 parent
d9bf7c1ccf
commit
bb3b3f1486
2 files changed
+33
-3
No files matched your search
@@ -150,10 +150,12 @@ func DesktopID(e provider.Entry) string { return claudeLooking(e) }
|
||||
// picked for it (provider.CatalogFor, the Agents page's model list) by an id
|
||||
// it keeps (claudeLooking), named by its own name alone (蓝猫: "DeepSeek
|
||||
// V4.1 Flash", not with its provider's beside it). Desktop shows the name,
|
||||
// not the id, and its description after it, so none is given; it folds rows
|
||||
// not the id, and its description after it, so none is given but a 1M
|
||||
// entry's (desktop1M); it folds rows
|
||||
// of one name into one entry, so two models of one name keep their
|
||||
// provider's after it (desktopNames). A model of 1M or more is listed by
|
||||
// its "[1m]" id under settings.DesktopLongest (desktop1M).
|
||||
// its "[1m]" id under settings.DesktopLongest, described as Desktop's own
|
||||
// 1M entry is (desktop1M).
|
||||
func desktopModels(entries []provider.Entry) []map[string]any {
|
||||
names := desktopNames(entries)
|
||||
// the tier each model stands in for: the user's pick (a model picked
|
||||
@@ -174,6 +176,7 @@ func desktopModels(entries []provider.Entry) []map[string]any {
|
||||
m["id"] = claudeLooking(e)
|
||||
if longest && e.Context >= desktop1M {
|
||||
m["id"] = m["id"].(string) + "[1m]"
|
||||
m["description"] = desktop1MSaid
|
||||
}
|
||||
if t := tierOf[e.ID]; t != "" {
|
||||
m["anthropic_family_tier"], m["is_family_default"] = t, true
|
||||
@@ -192,8 +195,22 @@ func desktopModels(entries []provider.Entry) []map[string]any {
|
||||
// model is listed by that 1M id alone (#1272), which magpie serves as the
|
||||
// plain one (aliased, provider.Resolve take "[1m]" off), so a session
|
||||
// saved on the plain id still runs.
|
||||
//
|
||||
// Desktop says which entry is the 1M one only on the entry it adds: its
|
||||
// description is "1M context window" (WLt in JLt, 2.7032). A row of
|
||||
// magpie's whose id has "[1m]" gets nothing of that (PIt gives supports1m
|
||||
// to a bare id alone, and OIt folds a "[1m]" row only into a bare one
|
||||
// beside it), so it was shown as the plain model, by name alone, and the
|
||||
// switch read as doing the reverse of what it says (杰多夫 on Discord).
|
||||
// The row is described as Desktop describes its own 1M entry
|
||||
// (desktop1MSaid); its id, which Desktop hands Claude Code, has the "[1m]"
|
||||
// that gives a session the 1M window.
|
||||
const desktop1M = 1_000_000
|
||||
|
||||
// desktop1MSaid is the description Claude Desktop gives the 1M entry it
|
||||
// adds (WLt in its app.asar, 2.7032).
|
||||
const desktop1MSaid = "1M context window"
|
||||
|
||||
// Claude Desktop's Code tab runs Claude Code with ANTHROPIC_DEFAULT_<TIER>_MODEL
|
||||
// set to "" for every tier, unless the gateway's /v1/models tags a model
|
||||
// with anthropic_family_tier (shortnameIdentityOverrides in its app.asar,
|
||||
|
||||
@@ -13,7 +13,9 @@ import (
|
||||
// Claude Desktop shows a gateway model of 1M tokens or more twice, its
|
||||
// plain entry and a "1M context window" one it adds itself (#1272: 21
|
||||
// models made 34 entries). With DesktopLongest on, such a model is listed
|
||||
// by its "[1m]" id alone, so Desktop's menu has one entry per model; one
|
||||
// by its "[1m]" id alone, so Desktop's menu has one entry per model, told
|
||||
// as the 1M one by the "1M context window" Desktop gives its own (a lone
|
||||
// "[1m]" row was shown as the plain model: 杰多夫 on Discord); one
|
||||
// under 1M (872K) keeps its own id and window, and a request on the plain id
|
||||
// a session was saved with is still served.
|
||||
func TestClaudeDesktopLongestOnly(t *testing.T) {
|
||||
@@ -37,6 +39,7 @@ func TestClaudeDesktopLongestOnly(t *testing.T) {
|
||||
type row struct {
|
||||
ID string `json:"id"`
|
||||
MaxInput int `json:"max_input_tokens"`
|
||||
Said string `json:"description"`
|
||||
}
|
||||
list := func() map[string]row {
|
||||
t.Helper()
|
||||
@@ -96,6 +99,16 @@ func TestClaudeDesktopLongestOnly(t *testing.T) {
|
||||
t.Errorf("on: %s listed as %q, want %q", id, r.ID, want)
|
||||
}
|
||||
}
|
||||
for id, r := range on {
|
||||
if want := map[bool]string{true: "1M context window"}[strings.HasSuffix(r.ID, "[1m]")]; r.Said != want {
|
||||
t.Errorf("on: %s (%s) described %q, want %q", id, r.ID, r.Said, want)
|
||||
}
|
||||
}
|
||||
for id, r := range off {
|
||||
if r.Said != "" {
|
||||
t.Errorf("off: %s described %q", id, r.Said)
|
||||
}
|
||||
}
|
||||
if r := on["vend/exo-free"]; r.MaxInput != 872_000 {
|
||||
t.Errorf("exo-free's window told as %d, want its own 872000", r.MaxInput)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user