From eb98ff4c308eadd523857d60e391de00081fb71d Mon Sep 17 00:00:00 2001 From: "seahaven-openswe[bot]" <296972425+seahaven-openswe[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 15:31:22 -0400 Subject: [PATCH] feat: add 3 verified Fireworks models to selectable set (#79) * Add 10 Fireworks models to selectable set Surface additional Fireworks-served models in the profile editor so they can be chosen per-thread, per-profile, and as team defaults. Each entry carries its recommended efforts and image support; only MiniMax M3 is multimodal. Refs: #78 * Suppress reasoning_effort on non-reasoning models Instruct-only Fireworks ids (kimi-k2-instruct-0905, mistral-large-3-fp8, qwen3-30b-a3b-instruct-2507) don't reason, so sending reasoning_effort either 400s (unusable at default effort) or is a silent no-op. Add a per-model reasoning flag (default True) and omit the param entirely for ids marked non-reasoning. Refs: #78 * Gate out 7 undeployed Fireworks models Account serverless probe returned 404 for 7 of the 10 proposed ids, so only minimax-m3, gpt-oss-120b, and deepseek-v4-flash are callable. Keep those 3 and drop the rest. All 3 survivors are reasoning-capable, so the per-model reasoning-effort suppression added earlier is no longer needed and is reverted. Refs: #78 --------- Co-authored-by: amoussa1229 <166072409+amoussa1229@users.noreply.github.com> --- agent/dashboard/options.py | 21 ++++++++++++ tests/test_fireworks_model.py | 61 ++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/agent/dashboard/options.py b/agent/dashboard/options.py index bc26cc01..3d21fec5 100644 --- a/agent/dashboard/options.py +++ b/agent/dashboard/options.py @@ -42,6 +42,27 @@ SUPPORTED_MODELS: list[ModelOption] = [ "default_effort": "high", "supports_images": False, }, + { + "id": "fireworks:accounts/fireworks/models/minimax-m3", + "label": "MiniMax M3", + "efforts": ["medium", "high"], + "default_effort": "high", + "supports_images": True, + }, + { + "id": "fireworks:accounts/fireworks/models/gpt-oss-120b", + "label": "gpt-oss-120b", + "efforts": ["low", "medium", "high"], + "default_effort": "medium", + "supports_images": False, + }, + { + "id": "fireworks:accounts/fireworks/models/deepseek-v4-flash", + "label": "DeepSeek V4 Flash", + "efforts": ["none", "medium", "high"], + "default_effort": "high", + "supports_images": False, + }, ] SUPPORTED_MODEL_IDS: frozenset[str] = frozenset(m["id"] for m in SUPPORTED_MODELS) diff --git a/tests/test_fireworks_model.py b/tests/test_fireworks_model.py index 368f31ca..096a8085 100644 --- a/tests/test_fireworks_model.py +++ b/tests/test_fireworks_model.py @@ -1,12 +1,27 @@ import pytest -from agent.dashboard.options import SUPPORTED_MODELS +from agent.dashboard.options import ( + SUPPORTED_MODEL_IDS, + SUPPORTED_MODELS, + model_supports_effort, + model_supports_images, +) from agent.utils.model import ( fallback_model_id_for, fireworks_reasoning_effort_for, provider_model_kwargs, ) +_FIREWORKS_PREFIX = "fireworks:accounts/fireworks/models/" + +NEW_FIREWORKS_MODELS = { + "minimax-m3": (["medium", "high"], "high", True), + "gpt-oss-120b": (["low", "medium", "high"], "medium", False), + "deepseek-v4-flash": (["none", "medium", "high"], "high", False), +} + +_ALL_EFFORTS = ("none", "low", "medium", "high", "xhigh", "max") + def test_fireworks_reasoning_effort_maps_effort() -> None: for effort in ("none", "low", "medium", "high", "xhigh", "max"): @@ -56,6 +71,50 @@ def test_provider_model_kwargs_for_fireworks_unknown_effort_omits_reasoning() -> assert "model_kwargs" not in kwargs +@pytest.mark.parametrize("slug", sorted(NEW_FIREWORKS_MODELS)) +def test_new_fireworks_model_is_supported(slug: str) -> None: + model_id = _FIREWORKS_PREFIX + slug + assert model_id in SUPPORTED_MODEL_IDS + model = next(m for m in SUPPORTED_MODELS if m["id"] == model_id) + efforts, default_effort, supports_images = NEW_FIREWORKS_MODELS[slug] + assert model["efforts"] == efforts + assert model["default_effort"] == default_effort + assert model["supports_images"] is supports_images + + +@pytest.mark.parametrize("slug", sorted(NEW_FIREWORKS_MODELS)) +def test_new_fireworks_model_supports_only_listed_efforts(slug: str) -> None: + model_id = _FIREWORKS_PREFIX + slug + efforts = NEW_FIREWORKS_MODELS[slug][0] + for effort in efforts: + assert model_supports_effort(model_id, effort) is True + for effort in _ALL_EFFORTS: + if effort not in efforts: + assert model_supports_effort(model_id, effort) is False + + +@pytest.mark.parametrize( + "slug", + [ + "qwen3-coder-480b-a35b-instruct", + "kimi-k2-thinking", + "kimi-k2-instruct-0905", + "glm-4p6", + "mistral-large-3-fp8", + "deepseek-v3p2", + "qwen3-30b-a3b-instruct-2507", + ], +) +def test_unavailable_fireworks_models_are_gated_out(slug: str) -> None: + assert _FIREWORKS_PREFIX + slug not in SUPPORTED_MODEL_IDS + + +@pytest.mark.parametrize("slug", sorted(NEW_FIREWORKS_MODELS)) +def test_only_minimax_m3_supports_images(slug: str) -> None: + model_id = _FIREWORKS_PREFIX + slug + assert model_supports_images(model_id) is (slug == "minimax-m3") + + def test_fireworks_falls_back_to_bedrock() -> None: assert ( fallback_model_id_for("fireworks:accounts/fireworks/models/deepseek-v4-pro")