diff --git a/agent/models.json b/agent/models.json index 67b9c1e4..91b609aa 100644 --- a/agent/models.json +++ b/agent/models.json @@ -55,7 +55,8 @@ }, "image_models": { "NANO_BANANA_PRO": "GEM_PIX_2", - "NANO_BANANA_2": "NARWHAL", + "NANO_BANANA_2_1": "BELUGA", + "NANO_BANANA_2": "BELUGA", "NANO_BANANA_2_LITE": "HARBOR_SEAL" }, "default_image_model": "NANO_BANANA_PRO", diff --git a/agent/services/flow_batch.py b/agent/services/flow_batch.py index 1262966d..852478ec 100644 --- a/agent/services/flow_batch.py +++ b/agent/services/flow_batch.py @@ -59,13 +59,22 @@ #: ids are accepted by ``resolve_image_model`` instead of being silently #: replaced by the default, so callers can opt into a newly exposed model #: before Flow Kit itself ships another release. -IMAGE_MODELS = {"GEM_PIX_2", "NARWHAL", "HARBOR_SEAL"} +#: +#: BELUGA is Nano Banana 2.1 (the UI's `beluga_display`); the THINKING +#: variants are values 37-39 of the same enum in the Flow bundle. Banana 2 +#: (`NARWHAL`) has answered `[5]` NOT_FOUND in every project since early +#: October 2026, so the NANO_BANANA_2 nickname now lands on its successor. +IMAGE_MODELS = { + "GEM_PIX_2", "NARWHAL", "HARBOR_SEAL", + "BELUGA", "BELUGA_THINKING_LOW", "BELUGA_THINKING_MED", "BELUGA_THINKING_HIGH", +} IMAGE_MODEL = "GEM_PIX_2" #: Friendly aliases. Exact Flow wire ids work too. IMAGE_MODEL_BY_NICKNAME = { "NANO_BANANA_PRO": "GEM_PIX_2", - "NANO_BANANA_2": "NARWHAL", + "NANO_BANANA_2_1": "BELUGA", + "NANO_BANANA_2": "BELUGA", "NANO_BANANA_2_LITE": "HARBOR_SEAL", "NANO_BANANA_LITE": "HARBOR_SEAL", } diff --git a/skills/fk-change-model.md b/skills/fk-change-model.md index 5cba5f6b..d0a777ef 100644 --- a/skills/fk-change-model.md +++ b/skills/fk-change-model.md @@ -29,9 +29,11 @@ So changing a Landscape vs Portrait key has **no effect** on the batch path — only the quality tier survives the fold. `r2v` and `start_end` keys are moot there too: both are unported. -Image models are unaffected: `GEM_PIX_2` (Nano Banana Pro) and `NARWHAL` -(Banana 2) are both accepted, and `default_image_model` in `models.json` picks -which nickname is used. +Image models are unaffected: `GEM_PIX_2` (Nano Banana Pro), `BELUGA` +(Nano Banana 2.1, plus `BELUGA_THINKING_LOW/MED/HIGH`) and `HARBOR_SEAL` +(2 Lite) are accepted, and `default_image_model` in `models.json` picks which +nickname is used. `NARWHAL` (Banana 2) answers `[5]` NOT_FOUND since October +2026; the `NANO_BANANA_2` nickname now maps to `BELUGA`. ## Step 1: Show Current Models @@ -57,7 +59,9 @@ Display in a readable table: | Key | Model | |-----|-------| | NANO_BANANA_PRO | `GEM_PIX_2` | -| NANO_BANANA_2 | `NARWHAL` | +| NANO_BANANA_2_1 | `BELUGA` | +| NANO_BANANA_2 | `BELUGA` (was `NARWHAL`, retired) | +| NANO_BANANA_2_LITE | `HARBOR_SEAL` | ### Upscale Models @@ -82,7 +86,8 @@ After user picks, apply the matching preset from the Quick Switch Presets sectio **For image model:** Use `AskUserQuestion` with options: - label: "GEM_PIX_2 (Recommended)", description: "Gemini Pix 2 · current default" -- label: "NARWHAL", description: "Alternative image model" +- label: "BELUGA", description: "Nano Banana 2.1" +- label: "HARBOR_SEAL", description: "Nano Banana 2 Lite" ## Step 3: Change a Model (Manual) @@ -231,7 +236,10 @@ curl -s -X PATCH http://127.0.0.1:8100/api/models \ | Key | Description | |-----|-------------| | `GEM_PIX_2` | Gemini Pix 2 (current default) | -| `NARWHAL` | Narwhal model | +| `BELUGA` | Nano Banana 2.1 | +| `BELUGA_THINKING_LOW` / `_MED` / `_HIGH` | Nano Banana 2.1 with thinking | +| `HARBOR_SEAL` | Nano Banana 2 Lite | +| `NARWHAL` | Nano Banana 2 — retired, answers `[5]` NOT_FOUND | ### Upscale | Key | Description | diff --git a/tests/unit/test_flow_batch.py b/tests/unit/test_flow_batch.py index 98d72fd4..fb48f08e 100644 --- a/tests/unit/test_flow_batch.py +++ b/tests/unit/test_flow_batch.py @@ -330,11 +330,16 @@ def test_an_unknown_aspect_name_raises_rather_than_defaulting(self): def test_nicknames_resolve_to_wire_names(self): assert fb.resolve_image_model("NANO_BANANA_PRO") == "GEM_PIX_2" - assert fb.resolve_image_model("NANO_BANANA_2") == "NARWHAL" + assert fb.resolve_image_model("NANO_BANANA_2_1") == "BELUGA" assert fb.resolve_image_model("NANO_BANANA_2_LITE") == "HARBOR_SEAL" + def test_nano_banana_2_lands_on_its_successor_not_the_retired_narwhal(self): + assert fb.resolve_image_model("NANO_BANANA_2") == "BELUGA" + def test_wire_names_and_future_model_ids_pass_through(self): assert fb.resolve_image_model("NARWHAL") == "NARWHAL" + assert fb.resolve_image_model("BELUGA") == "BELUGA" + assert fb.resolve_image_model("beluga_thinking_high") == "BELUGA_THINKING_HIGH" assert fb.resolve_image_model("harbor_seal") == "HARBOR_SEAL" assert fb.resolve_image_model("FUTURE_BANANA_3") == "FUTURE_BANANA_3"