Compare commits

...

1 Commits

Author SHA1 Message Date
Jiang Bohan
eba8ad6dfe fix(agent): expose Gemini 3 + CLI aliases in Gemini runtime model list
Gemini CLI has no `models list` subcommand, so Multica can't do real
dynamic discovery. Instead, swap the static catalog from fixed version
names (2.0/2.5 only) to the CLI's own aliases (`auto`, `pro`, `flash`,
`flash-lite`, `auto-gemini-2.5`) plus explicit pins for Gemini 3
preview and 2.5 variants. Aliases are resolved inside the Gemini CLI
per user entitlement + quota, so new model releases light up without
a Multica redeploy. Default is `auto`, matching Google's recommended
selection.

Fixes multica-ai/multica#1503.
2026-04-22 18:28:44 +08:00
2 changed files with 50 additions and 2 deletions

View File

@@ -155,11 +155,28 @@ func codexStaticModels() []Model {
}
}
// geminiStaticModels lists the values we pass via `gemini -m`. Gemini
// CLI has no `models list` subcommand, so dynamic discovery isn't
// possible; the next best thing is to expose the CLI's own aliases
// (auto / pro / flash / flash-lite and the `auto-gemini-*` family)
// alongside a few explicit version pins. Aliases track whatever the
// installed CLI considers current (see `resolveModel` in the CLI's
// packages/core/src/config/models.ts), so new Gemini releases light
// up without a Multica redeploy. Default is `auto` to match Google's
// recommendation — the CLI picks Pro vs Flash per task and falls back
// when quota is exhausted.
func geminiStaticModels() []Model {
return []Model{
{ID: "gemini-2.5-pro", Label: "Gemini 2.5 Pro", Provider: "google", Default: true},
{ID: "auto", Label: "Auto (Gemini 3)", Provider: "google", Default: true},
{ID: "auto-gemini-2.5", Label: "Auto (Gemini 2.5)", Provider: "google"},
{ID: "pro", Label: "Pro", Provider: "google"},
{ID: "flash", Label: "Flash", Provider: "google"},
{ID: "flash-lite", Label: "Flash Lite", Provider: "google"},
{ID: "gemini-3-pro-preview", Label: "Gemini 3 Pro (preview)", Provider: "google"},
{ID: "gemini-3-flash-preview", Label: "Gemini 3 Flash (preview)", Provider: "google"},
{ID: "gemini-2.5-pro", Label: "Gemini 2.5 Pro", Provider: "google"},
{ID: "gemini-2.5-flash", Label: "Gemini 2.5 Flash", Provider: "google"},
{ID: "gemini-2.0-flash", Label: "Gemini 2.0 Flash", Provider: "google"},
{ID: "gemini-2.5-flash-lite", Label: "Gemini 2.5 Flash Lite", Provider: "google"},
}
}

View File

@@ -27,6 +27,37 @@ func TestListModelsStaticProviders(t *testing.T) {
}
}
func TestGeminiStaticModelsExposesAliasesAndGemini3(t *testing.T) {
// Gemini CLI has no `models list` subcommand, so we expose the
// CLI's own aliases (auto / pro / flash / flash-lite) plus
// explicit version pins including Gemini 3. Regression guard
// for multica-ai/multica#1503 — Gemini 3 must be selectable.
models := geminiStaticModels()
ids := map[string]Model{}
for _, m := range models {
ids[m.ID] = m
}
for _, want := range []string{
"auto", "auto-gemini-2.5",
"pro", "flash", "flash-lite",
"gemini-3-pro-preview", "gemini-3-flash-preview",
"gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.5-flash-lite",
} {
if _, ok := ids[want]; !ok {
t.Errorf("missing expected Gemini model %q in: %+v", want, models)
}
}
auto, ok := ids["auto"]
if !ok || !auto.Default {
t.Errorf("expected `auto` to be the default Gemini entry, got %+v", auto)
}
for _, m := range models {
if m.Provider != "google" {
t.Errorf("all Gemini entries must carry Provider=google, got %+v", m)
}
}
}
func TestListModelsHermesWithoutBinary(t *testing.T) {
// With no `hermes` binary on PATH the discovery fast-paths to
// an empty list (the UI then falls back to creatable manual