feat: update model version from claude-sonnet-4-5 to claude-sonnet-4-6 and related adjustments
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 428 KiB After Width: | Height: | Size: 432 KiB |
@@ -102,7 +102,7 @@ def onboard(
|
|||||||
workspace settings, and agent parameters.
|
workspace settings, and agent parameters.
|
||||||
|
|
||||||
Any answer can be pre-set via a flag (``--provider anthropic
|
Any answer can be pre-set via a flag (``--provider anthropic
|
||||||
--model claude-sonnet-4-5 ...``); prompts for unset answers stay
|
--model claude-sonnet-4-6 ...``); prompts for unset answers stay
|
||||||
interactive unless ``--non-interactive`` is passed, in which case any
|
interactive unless ``--non-interactive`` is passed, in which case any
|
||||||
missing required answer aborts the wizard.
|
missing required answer aborts the wizard.
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -572,7 +572,7 @@ def run_onboard(
|
|||||||
# leaves a stale ``--model`` / ``--api-key`` that would
|
# leaves a stale ``--model`` / ``--api-key`` that would
|
||||||
# be re-applied under a different provider, producing
|
# be re-applied under a different provider, producing
|
||||||
# an invalid pair (e.g. ``provider=openai`` +
|
# an invalid pair (e.g. ``provider=openai`` +
|
||||||
# ``model=claude-sonnet-4-5``).
|
# ``model=claude-sonnet-4-6``).
|
||||||
for field_name in vars(loop_snapshot):
|
for field_name in vars(loop_snapshot):
|
||||||
setattr(
|
setattr(
|
||||||
config, field_name, getattr(loop_snapshot, field_name)
|
config, field_name, getattr(loop_snapshot, field_name)
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class EvoScientistConfig:
|
|||||||
|
|
||||||
# LLM Settings
|
# LLM Settings
|
||||||
provider: str = "anthropic"
|
provider: str = "anthropic"
|
||||||
model: str = "claude-sonnet-4-5"
|
model: str = "claude-sonnet-4-6"
|
||||||
model_fallbacks: str = "" # "model:provider,model:provider" fallback chain
|
model_fallbacks: str = "" # "model:provider,model:provider" fallback chain
|
||||||
|
|
||||||
# Async Sub-agent Settings
|
# Async Sub-agent Settings
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ _KNOWN_MODEL_CONTEXT_WINDOWS: dict[str, int] = {
|
|||||||
# Qwen 3.6 open-source variants — exceptions to the ``qwen3.6`` family.
|
# Qwen 3.6 open-source variants — exceptions to the ``qwen3.6`` family.
|
||||||
"qwen3.6-27b": 262_000,
|
"qwen3.6-27b": 262_000,
|
||||||
"qwen3.6-35b-a3b": 262_000,
|
"qwen3.6-35b-a3b": 262_000,
|
||||||
|
# Qwen 3.7 Max — closed-source flagship (1M).
|
||||||
|
"qwen3.7-max": 1_000_000,
|
||||||
|
# xAI Grok — per-model windows (build-0.1: 256K, 4.3: 1M).
|
||||||
|
"grok-build-0.1": 256_000,
|
||||||
|
"grok-4.3": 1_000_000,
|
||||||
# Claude Haiku 4.5 — exception to the ``claude-`` family (200K, not 1M).
|
# Claude Haiku 4.5 — exception to the ``claude-`` family (200K, not 1M).
|
||||||
"claude-haiku-4-5": 200_000,
|
"claude-haiku-4-5": 200_000,
|
||||||
}
|
}
|
||||||
@@ -29,6 +34,8 @@ _KNOWN_MODEL_FAMILIES: list[tuple[str, int]] = [
|
|||||||
("claude-", 1_000_000),
|
("claude-", 1_000_000),
|
||||||
# OpenAI GPT-5.5 family — base, pro, future variants
|
# OpenAI GPT-5.5 family — base, pro, future variants
|
||||||
("gpt-5.5", 1_050_000),
|
("gpt-5.5", 1_050_000),
|
||||||
|
# Google Gemini 3.x family — flash, flash-lite, pro (1.05M). Excludes 2.5.
|
||||||
|
("gemini-3", 1_050_000),
|
||||||
# Moonshot Kimi K2 family — k2.5, k2.6, k2-thinking, k2-thinking-turbo
|
# Moonshot Kimi K2 family — k2.5, k2.6, k2-thinking, k2-thinking-turbo
|
||||||
("kimi-k2", 262_000),
|
("kimi-k2", 262_000),
|
||||||
# Zhipu GLM-5 family — base, 5.1, 5-turbo, 5v-turbo, etc.
|
# Zhipu GLM-5 family — base, 5.1, 5-turbo, 5v-turbo, etc.
|
||||||
|
|||||||
+16
-15
@@ -66,10 +66,9 @@ _THINKING_CAPABLE_PROVIDERS: set[str] = {"minimax"}
|
|||||||
# Model registry: list of (short_name, model_id, provider)
|
# Model registry: list of (short_name, model_id, provider)
|
||||||
# Allows same short_name across different providers.
|
# Allows same short_name across different providers.
|
||||||
_MODEL_ENTRIES: list[tuple[str, str, str]] = [
|
_MODEL_ENTRIES: list[tuple[str, str, str]] = [
|
||||||
# Custom Anthropic (third-party Claude-compatible endpoints, 3 defaults)
|
# Custom Anthropic (third-party Claude-compatible endpoints, current-gen defaults)
|
||||||
# Listed BEFORE native anthropic so MODELS dict defaults to native provider
|
# Listed BEFORE native anthropic so MODELS dict defaults to native provider
|
||||||
("claude-sonnet-4-6", "claude-sonnet-4-6", "custom-anthropic"),
|
("claude-sonnet-4-6", "claude-sonnet-4-6", "custom-anthropic"),
|
||||||
("claude-sonnet-4-5", "claude-sonnet-4-5", "custom-anthropic"),
|
|
||||||
("claude-haiku-4-5", "claude-haiku-4-5", "custom-anthropic"),
|
("claude-haiku-4-5", "claude-haiku-4-5", "custom-anthropic"),
|
||||||
# Custom OpenAI (third-party OpenAI-compatible endpoints, 3 defaults)
|
# Custom OpenAI (third-party OpenAI-compatible endpoints, 3 defaults)
|
||||||
# Listed BEFORE native openai so MODELS dict defaults to native provider
|
# Listed BEFORE native openai so MODELS dict defaults to native provider
|
||||||
@@ -78,12 +77,9 @@ _MODEL_ENTRIES: list[tuple[str, str, str]] = [
|
|||||||
("gpt-5.4", "gpt-5.4", "custom-openai"),
|
("gpt-5.4", "gpt-5.4", "custom-openai"),
|
||||||
("gpt-5.3-codex", "gpt-5.3-codex", "custom-openai"),
|
("gpt-5.3-codex", "gpt-5.3-codex", "custom-openai"),
|
||||||
("gpt-5-mini", "gpt-5-mini", "custom-openai"),
|
("gpt-5-mini", "gpt-5-mini", "custom-openai"),
|
||||||
# Anthropic (ordered by capability)
|
# Anthropic (current generation)
|
||||||
("claude-opus-4-7", "claude-opus-4-7", "anthropic"),
|
("claude-opus-4-8", "claude-opus-4-8", "anthropic"),
|
||||||
("claude-opus-4-6", "claude-opus-4-6", "anthropic"),
|
|
||||||
("claude-sonnet-4-6", "claude-sonnet-4-6", "anthropic"),
|
("claude-sonnet-4-6", "claude-sonnet-4-6", "anthropic"),
|
||||||
("claude-opus-4-5", "claude-opus-4-5", "anthropic"),
|
|
||||||
("claude-sonnet-4-5", "claude-sonnet-4-5", "anthropic"),
|
|
||||||
("claude-haiku-4-5", "claude-haiku-4-5", "anthropic"),
|
("claude-haiku-4-5", "claude-haiku-4-5", "anthropic"),
|
||||||
# OpenAI
|
# OpenAI
|
||||||
("gpt-5.5-pro", "gpt-5.5-pro", "openai"),
|
("gpt-5.5-pro", "gpt-5.5-pro", "openai"),
|
||||||
@@ -99,6 +95,7 @@ _MODEL_ENTRIES: list[tuple[str, str, str]] = [
|
|||||||
("gpt-5-mini", "gpt-5-mini", "openai"),
|
("gpt-5-mini", "gpt-5-mini", "openai"),
|
||||||
("gpt-5-nano", "gpt-5-nano", "openai"),
|
("gpt-5-nano", "gpt-5-nano", "openai"),
|
||||||
# Google GenAI
|
# Google GenAI
|
||||||
|
("gemini-3.5-flash", "gemini-3.5-flash", "google-genai"),
|
||||||
("gemini-3.1-pro", "gemini-3.1-pro-preview", "google-genai"),
|
("gemini-3.1-pro", "gemini-3.1-pro-preview", "google-genai"),
|
||||||
(
|
(
|
||||||
"gemini-3.1-pro-customtools",
|
"gemini-3.1-pro-customtools",
|
||||||
@@ -133,13 +130,14 @@ _MODEL_ENTRIES: list[tuple[str, str, str]] = [
|
|||||||
("kimi-k2.5", "Pro/moonshotai/Kimi-K2.5", "siliconflow"),
|
("kimi-k2.5", "Pro/moonshotai/Kimi-K2.5", "siliconflow"),
|
||||||
("glm-4.7", "Pro/zai-org/GLM-4.7", "siliconflow"),
|
("glm-4.7", "Pro/zai-org/GLM-4.7", "siliconflow"),
|
||||||
# OpenRouter
|
# OpenRouter
|
||||||
("claude-opus-4.7", "anthropic/claude-opus-4.7", "openrouter"),
|
("claude-opus-4.8", "anthropic/claude-opus-4.8", "openrouter"),
|
||||||
("claude-opus-4.6", "anthropic/claude-opus-4.6", "openrouter"),
|
("claude-opus-4.8-fast", "anthropic/claude-opus-4.8-fast", "openrouter"),
|
||||||
("claude-sonnet-4.6", "anthropic/claude-sonnet-4.6", "openrouter"),
|
("claude-sonnet-4.6", "anthropic/claude-sonnet-4.6", "openrouter"),
|
||||||
("gpt-5.5-pro", "openai/gpt-5.5-pro", "openrouter"),
|
("gpt-5.5-pro", "openai/gpt-5.5-pro", "openrouter"),
|
||||||
("gpt-5.5", "openai/gpt-5.5", "openrouter"),
|
("gpt-5.5", "openai/gpt-5.5", "openrouter"),
|
||||||
("gpt-5.4", "openai/gpt-5.4", "openrouter"),
|
("gpt-5.4", "openai/gpt-5.4", "openrouter"),
|
||||||
("gpt-5.3-codex", "openai/gpt-5.3-codex", "openrouter"),
|
("gpt-5.3-codex", "openai/gpt-5.3-codex", "openrouter"),
|
||||||
|
("gemini-3.5-flash", "google/gemini-3.5-flash", "openrouter"),
|
||||||
("gemini-3.1-pro", "google/gemini-3.1-pro-preview", "openrouter"),
|
("gemini-3.1-pro", "google/gemini-3.1-pro-preview", "openrouter"),
|
||||||
("gemini-3-flash", "google/gemini-3-flash-preview", "openrouter"),
|
("gemini-3-flash", "google/gemini-3-flash-preview", "openrouter"),
|
||||||
("kimi-k2.6", "moonshotai/kimi-k2.6", "openrouter"),
|
("kimi-k2.6", "moonshotai/kimi-k2.6", "openrouter"),
|
||||||
@@ -147,7 +145,10 @@ _MODEL_ENTRIES: list[tuple[str, str, str]] = [
|
|||||||
("minimax-m2.7", "minimax/minimax-m2.7", "openrouter"),
|
("minimax-m2.7", "minimax/minimax-m2.7", "openrouter"),
|
||||||
("mimo-v2.5-pro", "xiaomi/mimo-v2.5-pro", "openrouter"),
|
("mimo-v2.5-pro", "xiaomi/mimo-v2.5-pro", "openrouter"),
|
||||||
("mimo-v2.5", "xiaomi/mimo-v2.5", "openrouter"),
|
("mimo-v2.5", "xiaomi/mimo-v2.5", "openrouter"),
|
||||||
("grok-4.1-fast", "x-ai/grok-4.1-fast", "openrouter"),
|
("grok-build-0.1", "x-ai/grok-build-0.1", "openrouter"),
|
||||||
|
("grok-4.3", "x-ai/grok-4.3", "openrouter"),
|
||||||
|
("qwen3.7-max", "qwen/qwen3.7-max", "openrouter"),
|
||||||
|
("qwen3.6-flash", "qwen/qwen3.6-flash", "openrouter"),
|
||||||
("qwen3.5-122b", "qwen/qwen3.5-122b-a10b", "openrouter"),
|
("qwen3.5-122b", "qwen/qwen3.5-122b-a10b", "openrouter"),
|
||||||
("deepseek-v4-pro", "deepseek/deepseek-v4-pro", "openrouter"),
|
("deepseek-v4-pro", "deepseek/deepseek-v4-pro", "openrouter"),
|
||||||
("deepseek-v4-flash", "deepseek/deepseek-v4-flash", "openrouter"),
|
("deepseek-v4-flash", "deepseek/deepseek-v4-flash", "openrouter"),
|
||||||
@@ -246,7 +247,7 @@ def _apply_auto_config(
|
|||||||
_is_proxy = False
|
_is_proxy = False
|
||||||
if _is_proxy or (is_third_party and not _supports_thinking):
|
if _is_proxy or (is_third_party and not _supports_thinking):
|
||||||
pass
|
pass
|
||||||
elif model_id.endswith(("4-6", "4-7")):
|
elif model_id.endswith(("4-6", "4-7", "4-8")):
|
||||||
kwargs["thinking"] = {"type": "adaptive"}
|
kwargs["thinking"] = {"type": "adaptive"}
|
||||||
kwargs.setdefault("effort", "max")
|
kwargs.setdefault("effort", "max")
|
||||||
else:
|
else:
|
||||||
@@ -282,8 +283,8 @@ def get_chat_model(
|
|||||||
"""Get a chat model instance.
|
"""Get a chat model instance.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
model: Model name (short name like 'claude-sonnet-4-5' or full ID
|
model: Model name (short name like 'claude-sonnet-4-6' or full ID
|
||||||
like 'claude-sonnet-4-5-20250929'). Defaults to DEFAULT_MODEL.
|
like 'claude-sonnet-4-6-20250929'). Defaults to DEFAULT_MODEL.
|
||||||
provider: Override the provider (e.g., 'anthropic', 'openai').
|
provider: Override the provider (e.g., 'anthropic', 'openai').
|
||||||
If not specified, inferred from model name or defaults to 'anthropic'.
|
If not specified, inferred from model name or defaults to 'anthropic'.
|
||||||
**kwargs: Additional arguments passed to init_chat_model (e.g., temperature).
|
**kwargs: Additional arguments passed to init_chat_model (e.g., temperature).
|
||||||
@@ -292,8 +293,8 @@ def get_chat_model(
|
|||||||
A LangChain chat model instance.
|
A LangChain chat model instance.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
>>> model = get_chat_model() # Uses default (claude-sonnet-4-5)
|
>>> model = get_chat_model() # Uses default (claude-sonnet-4-6)
|
||||||
>>> model = get_chat_model("claude-opus-4-5") # Use short name
|
>>> model = get_chat_model("claude-opus-4-8") # Use short name
|
||||||
>>> model = get_chat_model("gpt-4o") # OpenAI model
|
>>> model = get_chat_model("gpt-4o") # OpenAI model
|
||||||
>>> model = get_chat_model("claude-3-opus-20240229", provider="anthropic") # Full ID
|
>>> model = get_chat_model("claude-3-opus-20240229", provider="anthropic") # Full ID
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class TestEvoScientistConfig:
|
|||||||
assert config.openai_api_key == ""
|
assert config.openai_api_key == ""
|
||||||
assert config.tavily_api_key == ""
|
assert config.tavily_api_key == ""
|
||||||
assert config.provider == "anthropic"
|
assert config.provider == "anthropic"
|
||||||
assert config.model == "claude-sonnet-4-5"
|
assert config.model == "claude-sonnet-4-6"
|
||||||
assert config.default_mode == "daemon"
|
assert config.default_mode == "daemon"
|
||||||
assert config.default_workdir == ""
|
assert config.default_workdir == ""
|
||||||
assert config.show_thinking is True
|
assert config.show_thinking is True
|
||||||
@@ -157,7 +157,7 @@ class TestLoadSaveReset:
|
|||||||
"""Test that load returns defaults when config file doesn't exist."""
|
"""Test that load returns defaults when config file doesn't exist."""
|
||||||
config = load_config()
|
config = load_config()
|
||||||
assert config.provider == "anthropic"
|
assert config.provider == "anthropic"
|
||||||
assert config.model == "claude-sonnet-4-5"
|
assert config.model == "claude-sonnet-4-6"
|
||||||
|
|
||||||
def test_save_creates_file(self, temp_config_dir, clean_env):
|
def test_save_creates_file(self, temp_config_dir, clean_env):
|
||||||
"""Test that save creates the config file."""
|
"""Test that save creates the config file."""
|
||||||
@@ -350,8 +350,8 @@ class TestPriorityChain:
|
|||||||
"""Test CLI arguments override file config."""
|
"""Test CLI arguments override file config."""
|
||||||
save_config(EvoScientistConfig(model="gpt-4o"))
|
save_config(EvoScientistConfig(model="gpt-4o"))
|
||||||
|
|
||||||
config = get_effective_config(cli_overrides={"model": "claude-opus-4-5"})
|
config = get_effective_config(cli_overrides={"model": "claude-opus-4-8"})
|
||||||
assert config.model == "claude-opus-4-5"
|
assert config.model == "claude-opus-4-8"
|
||||||
|
|
||||||
def test_env_ui_backend_override(self, temp_config_dir, monkeypatch):
|
def test_env_ui_backend_override(self, temp_config_dir, monkeypatch):
|
||||||
"""UI backend can be selected via environment variable."""
|
"""UI backend can be selected via environment variable."""
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ class TestModelOverride:
|
|||||||
|
|
||||||
with (
|
with (
|
||||||
_patched_config(
|
_patched_config(
|
||||||
{"model": "claude-opus-4-7", "model_provider": "anthropic"}
|
{"model": "claude-opus-4-8", "model_provider": "anthropic"}
|
||||||
),
|
),
|
||||||
patch(
|
patch(
|
||||||
"EvoScientist.llm.get_chat_model", return_value=new_model
|
"EvoScientist.llm.get_chat_model", return_value=new_model
|
||||||
@@ -205,7 +205,7 @@ class TestModelOverride:
|
|||||||
result = _run(mw.awrap_model_call(req, handler))
|
result = _run(mw.awrap_model_call(req, handler))
|
||||||
|
|
||||||
assert result == "ok"
|
assert result == "ok"
|
||||||
mock_get.assert_called_once_with(model="claude-opus-4-7", provider="anthropic")
|
mock_get.assert_called_once_with(model="claude-opus-4-8", provider="anthropic")
|
||||||
|
|
||||||
def test_provider_omitted_passed_as_none(self):
|
def test_provider_omitted_passed_as_none(self):
|
||||||
mw = ConfigurableModelMiddleware()
|
mw = ConfigurableModelMiddleware()
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ def test_resolve_context_window_falls_back_when_missing():
|
|||||||
|
|
||||||
|
|
||||||
def test_patch_table_resolves_known_model_name():
|
def test_patch_table_resolves_known_model_name():
|
||||||
model = SimpleNamespace(model_name="claude-opus-4.7", profile=None)
|
model = SimpleNamespace(model_name="claude-opus-4.8", profile=None)
|
||||||
|
|
||||||
assert get_context_window(model) == 1_000_000
|
assert get_context_window(model) == 1_000_000
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ def test_patch_table_strips_provider_prefix():
|
|||||||
|
|
||||||
def test_real_attribute_beats_patch_table():
|
def test_real_attribute_beats_patch_table():
|
||||||
model = SimpleNamespace(
|
model = SimpleNamespace(
|
||||||
model_name="claude-opus-4.7",
|
model_name="claude-opus-4.8",
|
||||||
context_window=500_000,
|
context_window=500_000,
|
||||||
profile=None,
|
profile=None,
|
||||||
)
|
)
|
||||||
@@ -95,10 +95,10 @@ def test_unknown_model_falls_through_to_fallback():
|
|||||||
|
|
||||||
def test_claude_family_pattern_covers_all_variants():
|
def test_claude_family_pattern_covers_all_variants():
|
||||||
# Native Anthropic (dash form)
|
# Native Anthropic (dash form)
|
||||||
native = SimpleNamespace(model_name="claude-opus-4-7", profile=None)
|
native = SimpleNamespace(model_name="claude-opus-4-8", profile=None)
|
||||||
# OpenRouter (dot form, with vendor prefix)
|
# OpenRouter (dot form, with vendor prefix)
|
||||||
openrouter = SimpleNamespace(model_name="anthropic/claude-sonnet-4.6", profile=None)
|
openrouter = SimpleNamespace(model_name="anthropic/claude-sonnet-4.6", profile=None)
|
||||||
sonnet = SimpleNamespace(model_name="claude-sonnet-4-5", profile=None)
|
sonnet = SimpleNamespace(model_name="claude-sonnet-4-6", profile=None)
|
||||||
# Haiku 4.5 is a dict-level exception (200K, not 1M).
|
# Haiku 4.5 is a dict-level exception (200K, not 1M).
|
||||||
haiku = SimpleNamespace(model_name="claude-haiku-4-5", profile=None)
|
haiku = SimpleNamespace(model_name="claude-haiku-4-5", profile=None)
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ def test_claude_3x_matches_family_but_upstream_profile_wins_in_practice():
|
|||||||
|
|
||||||
|
|
||||||
def test_apply_injects_into_empty_profile():
|
def test_apply_injects_into_empty_profile():
|
||||||
model = SimpleNamespace(model_name="claude-opus-4-7", profile=None)
|
model = SimpleNamespace(model_name="claude-opus-4-8", profile=None)
|
||||||
|
|
||||||
apply_known_context_window(model)
|
apply_known_context_window(model)
|
||||||
|
|
||||||
@@ -164,7 +164,7 @@ def test_apply_preserves_existing_profile_keys():
|
|||||||
|
|
||||||
def test_apply_does_not_overwrite_existing_max_input_tokens():
|
def test_apply_does_not_overwrite_existing_max_input_tokens():
|
||||||
model = SimpleNamespace(
|
model = SimpleNamespace(
|
||||||
model_name="claude-opus-4-7",
|
model_name="claude-opus-4-8",
|
||||||
profile={"max_input_tokens": 500_000},
|
profile={"max_input_tokens": 500_000},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -185,7 +185,7 @@ def test_apply_handles_non_dict_profile_safely():
|
|||||||
# Non-dict profile (e.g. namespace from a future langchain version) must
|
# Non-dict profile (e.g. namespace from a future langchain version) must
|
||||||
# not raise — fall back to a fresh dict so deepagents can still read it.
|
# not raise — fall back to a fresh dict so deepagents can still read it.
|
||||||
model = SimpleNamespace(
|
model = SimpleNamespace(
|
||||||
model_name="claude-opus-4-7",
|
model_name="claude-opus-4-8",
|
||||||
profile=SimpleNamespace(name="opaque object"),
|
profile=SimpleNamespace(name="opaque object"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+21
-9
@@ -137,7 +137,7 @@ class TestListModels:
|
|||||||
class TestGetModelInfo:
|
class TestGetModelInfo:
|
||||||
def test_returns_tuple_for_valid_model(self):
|
def test_returns_tuple_for_valid_model(self):
|
||||||
"""Test that get_model_info returns tuple for valid model."""
|
"""Test that get_model_info returns tuple for valid model."""
|
||||||
result = get_model_info("claude-sonnet-4-5")
|
result = get_model_info("claude-sonnet-4-6")
|
||||||
assert result is not None
|
assert result is not None
|
||||||
assert isinstance(result, tuple)
|
assert isinstance(result, tuple)
|
||||||
assert len(result) == 2
|
assert len(result) == 2
|
||||||
@@ -179,10 +179,10 @@ class TestGetChatModel:
|
|||||||
"""Test that get_chat_model resolves short names correctly."""
|
"""Test that get_chat_model resolves short names correctly."""
|
||||||
mock_init.return_value = "mock_model"
|
mock_init.return_value = "mock_model"
|
||||||
|
|
||||||
get_chat_model("claude-opus-4-5")
|
get_chat_model("claude-opus-4-8")
|
||||||
|
|
||||||
call_kwargs = mock_init.call_args[1]
|
call_kwargs = mock_init.call_args[1]
|
||||||
assert call_kwargs["model"] == "claude-opus-4-5"
|
assert call_kwargs["model"] == "claude-opus-4-8"
|
||||||
assert call_kwargs["model_provider"] == "anthropic"
|
assert call_kwargs["model_provider"] == "anthropic"
|
||||||
|
|
||||||
@patch("EvoScientist.llm.models.init_chat_model")
|
@patch("EvoScientist.llm.models.init_chat_model")
|
||||||
@@ -213,7 +213,7 @@ class TestGetChatModel:
|
|||||||
"""Test that provider can be overridden."""
|
"""Test that provider can be overridden."""
|
||||||
mock_init.return_value = "mock_model"
|
mock_init.return_value = "mock_model"
|
||||||
|
|
||||||
get_chat_model("claude-sonnet-4-5", provider="custom_provider")
|
get_chat_model("claude-sonnet-4-6", provider="custom_provider")
|
||||||
|
|
||||||
call_kwargs = mock_init.call_args[1]
|
call_kwargs = mock_init.call_args[1]
|
||||||
assert call_kwargs["model_provider"] == "custom_provider"
|
assert call_kwargs["model_provider"] == "custom_provider"
|
||||||
@@ -403,7 +403,7 @@ class TestThirdPartyRouting:
|
|||||||
mock_init.return_value = "mock_model"
|
mock_init.return_value = "mock_model"
|
||||||
monkeypatch.setenv("OPENROUTER_API_KEY", "or-key-456")
|
monkeypatch.setenv("OPENROUTER_API_KEY", "or-key-456")
|
||||||
|
|
||||||
get_chat_model("x-ai/grok-4.1-fast", provider="openrouter")
|
get_chat_model("x-ai/grok-4.3", provider="openrouter")
|
||||||
|
|
||||||
call_kwargs = mock_init.call_args[1]
|
call_kwargs = mock_init.call_args[1]
|
||||||
assert call_kwargs["model_provider"] == "openrouter"
|
assert call_kwargs["model_provider"] == "openrouter"
|
||||||
@@ -417,7 +417,7 @@ class TestThirdPartyRouting:
|
|||||||
monkeypatch.setenv("OPENROUTER_API_KEY", "or-key")
|
monkeypatch.setenv("OPENROUTER_API_KEY", "or-key")
|
||||||
|
|
||||||
get_chat_model(
|
get_chat_model(
|
||||||
"x-ai/grok-4.1-fast",
|
"x-ai/grok-4.3",
|
||||||
provider="openrouter",
|
provider="openrouter",
|
||||||
reasoning={"effort": "low"},
|
reasoning={"effort": "low"},
|
||||||
)
|
)
|
||||||
@@ -432,7 +432,7 @@ class TestThirdPartyRouting:
|
|||||||
monkeypatch.setenv("OPENROUTER_API_KEY", "or-key")
|
monkeypatch.setenv("OPENROUTER_API_KEY", "or-key")
|
||||||
monkeypatch.setenv("EVOSCIENTIST_REASONING_EFFORT", "medium")
|
monkeypatch.setenv("EVOSCIENTIST_REASONING_EFFORT", "medium")
|
||||||
|
|
||||||
get_chat_model("x-ai/grok-4.1-fast", provider="openrouter")
|
get_chat_model("x-ai/grok-4.3", provider="openrouter")
|
||||||
|
|
||||||
call_kwargs = mock_init.call_args[1]
|
call_kwargs = mock_init.call_args[1]
|
||||||
assert call_kwargs["reasoning"] == {"effort": "medium", "summary": "disabled"}
|
assert call_kwargs["reasoning"] == {"effort": "medium", "summary": "disabled"}
|
||||||
@@ -1176,7 +1176,7 @@ class TestAutoConfig:
|
|||||||
mock_init.return_value = "mock_model"
|
mock_init.return_value = "mock_model"
|
||||||
monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
|
monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
|
||||||
|
|
||||||
get_chat_model("claude-sonnet-4-5")
|
get_chat_model("claude-haiku-4-5")
|
||||||
|
|
||||||
call_kwargs = mock_init.call_args[1]
|
call_kwargs = mock_init.call_args[1]
|
||||||
assert call_kwargs["thinking"] == {"type": "enabled", "budget_tokens": 10000}
|
assert call_kwargs["thinking"] == {"type": "enabled", "budget_tokens": 10000}
|
||||||
@@ -1193,6 +1193,18 @@ class TestAutoConfig:
|
|||||||
assert call_kwargs["thinking"] == {"type": "adaptive"}
|
assert call_kwargs["thinking"] == {"type": "adaptive"}
|
||||||
assert call_kwargs["effort"] == "max"
|
assert call_kwargs["effort"] == "max"
|
||||||
|
|
||||||
|
@patch("EvoScientist.llm.models.init_chat_model")
|
||||||
|
def test_anthropic_4_8_adaptive_thinking(self, mock_init, monkeypatch):
|
||||||
|
"""Anthropic 4-8 models get adaptive thinking with max effort."""
|
||||||
|
mock_init.return_value = "mock_model"
|
||||||
|
monkeypatch.delenv("ANTHROPIC_BASE_URL", raising=False)
|
||||||
|
|
||||||
|
get_chat_model("claude-opus-4-8")
|
||||||
|
|
||||||
|
call_kwargs = mock_init.call_args[1]
|
||||||
|
assert call_kwargs["thinking"] == {"type": "adaptive"}
|
||||||
|
assert call_kwargs["effort"] == "max"
|
||||||
|
|
||||||
@patch("EvoScientist.llm.models.init_chat_model")
|
@patch("EvoScientist.llm.models.init_chat_model")
|
||||||
def test_anthropic_4_6_proxy_no_thinking(self, mock_init, monkeypatch):
|
def test_anthropic_4_6_proxy_no_thinking(self, mock_init, monkeypatch):
|
||||||
"""Anthropic 4-6 models via proxy skip thinking (history round-trip 422)."""
|
"""Anthropic 4-6 models via proxy skip thinking (history round-trip 422)."""
|
||||||
@@ -1213,7 +1225,7 @@ class TestAutoConfig:
|
|||||||
monkeypatch.setenv("ANTHROPIC_BASE_URL", "http://127.0.0.1:8000")
|
monkeypatch.setenv("ANTHROPIC_BASE_URL", "http://127.0.0.1:8000")
|
||||||
monkeypatch.setenv("ANTHROPIC_API_KEY", "ccproxy-oauth")
|
monkeypatch.setenv("ANTHROPIC_API_KEY", "ccproxy-oauth")
|
||||||
|
|
||||||
get_chat_model("claude-sonnet-4-5")
|
get_chat_model("claude-haiku-4-5")
|
||||||
|
|
||||||
call_kwargs = mock_init.call_args[1]
|
call_kwargs = mock_init.call_args[1]
|
||||||
assert "thinking" not in call_kwargs
|
assert "thinking" not in call_kwargs
|
||||||
|
|||||||
@@ -158,10 +158,10 @@ class TestModelCommandSwitch:
|
|||||||
return_value=new_agent,
|
return_value=new_agent,
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
_run(cmd.execute(ctx, ["claude-opus-4-6"]))
|
_run(cmd.execute(ctx, ["claude-opus-4-8"]))
|
||||||
|
|
||||||
# Config should be updated
|
# Config should be updated
|
||||||
assert cfg.model == "claude-opus-4-6"
|
assert cfg.model == "claude-opus-4-8"
|
||||||
assert cfg.provider == "anthropic"
|
assert cfg.provider == "anthropic"
|
||||||
|
|
||||||
# Agent should be replaced on context
|
# Agent should be replaced on context
|
||||||
@@ -170,7 +170,7 @@ class TestModelCommandSwitch:
|
|||||||
# Success message shown
|
# Success message shown
|
||||||
ui.append_system.assert_called_once()
|
ui.append_system.assert_called_once()
|
||||||
msg = ui.append_system.call_args[0][0]
|
msg = ui.append_system.call_args[0][0]
|
||||||
assert "claude-opus-4-6" in msg
|
assert "claude-opus-4-8" in msg
|
||||||
assert "anthropic" in msg
|
assert "anthropic" in msg
|
||||||
|
|
||||||
def test_switch_with_save_flag(self):
|
def test_switch_with_save_flag(self):
|
||||||
@@ -198,10 +198,10 @@ class TestModelCommandSwitch:
|
|||||||
),
|
),
|
||||||
patch("EvoScientist.config.settings.set_config_value") as mock_save,
|
patch("EvoScientist.config.settings.set_config_value") as mock_save,
|
||||||
):
|
):
|
||||||
_run(cmd.execute(ctx, ["claude-opus-4-6", "--save"]))
|
_run(cmd.execute(ctx, ["claude-opus-4-8", "--save"]))
|
||||||
|
|
||||||
# Config file should be updated
|
# Config file should be updated
|
||||||
mock_save.assert_any_call("model", "claude-opus-4-6")
|
mock_save.assert_any_call("model", "claude-opus-4-8")
|
||||||
mock_save.assert_any_call("provider", "anthropic")
|
mock_save.assert_any_call("provider", "anthropic")
|
||||||
|
|
||||||
# Success message should mention save
|
# Success message should mention save
|
||||||
@@ -233,7 +233,7 @@ class TestModelCommandSwitch:
|
|||||||
),
|
),
|
||||||
patch("EvoScientist.config.settings.set_config_value") as mock_save,
|
patch("EvoScientist.config.settings.set_config_value") as mock_save,
|
||||||
):
|
):
|
||||||
_run(cmd.execute(ctx, ["claude-opus-4-6"]))
|
_run(cmd.execute(ctx, ["claude-opus-4-8"]))
|
||||||
|
|
||||||
# Config file should NOT be updated
|
# Config file should NOT be updated
|
||||||
mock_save.assert_not_called()
|
mock_save.assert_not_called()
|
||||||
@@ -273,7 +273,7 @@ class TestModelCommandFailure:
|
|||||||
side_effect=RuntimeError("API key missing"),
|
side_effect=RuntimeError("API key missing"),
|
||||||
) as mock_set,
|
) as mock_set,
|
||||||
):
|
):
|
||||||
_run(cmd.execute(ctx, ["claude-opus-4-6"]))
|
_run(cmd.execute(ctx, ["claude-opus-4-8"]))
|
||||||
|
|
||||||
mock_set.assert_called_once()
|
mock_set.assert_called_once()
|
||||||
ui.append_system.assert_called_once()
|
ui.append_system.assert_called_once()
|
||||||
@@ -558,7 +558,7 @@ class TestModelCommandLoadAgentFailure:
|
|||||||
# Pass ``--save`` to strengthen the assertion: if the ordering
|
# Pass ``--save`` to strengthen the assertion: if the ordering
|
||||||
# ever regresses, ``set_config_value`` would be called with
|
# ever regresses, ``set_config_value`` would be called with
|
||||||
# stale data.
|
# stale data.
|
||||||
_run(cmd.execute(ctx, ["claude-opus-4-6", "--save"]))
|
_run(cmd.execute(ctx, ["claude-opus-4-8", "--save"]))
|
||||||
|
|
||||||
# _load_agent was attempted (transactional first step).
|
# _load_agent was attempted (transactional first step).
|
||||||
mock_load.assert_called_once()
|
mock_load.assert_called_once()
|
||||||
|
|||||||
@@ -373,10 +373,10 @@ class TestStepModel:
|
|||||||
config = EvoScientistConfig()
|
config = EvoScientistConfig()
|
||||||
|
|
||||||
with patch("EvoScientist.config.onboard.steps.questionary") as mock_q:
|
with patch("EvoScientist.config.onboard.steps.questionary") as mock_q:
|
||||||
mock_q.select.return_value.ask.return_value = "claude-sonnet-4-5"
|
mock_q.select.return_value.ask.return_value = "claude-sonnet-4-6"
|
||||||
result = _step_model(config, "anthropic")
|
result = _step_model(config, "anthropic")
|
||||||
|
|
||||||
assert result == "claude-sonnet-4-5"
|
assert result == "claude-sonnet-4-6"
|
||||||
|
|
||||||
def test_raises_keyboard_interrupt_on_cancel(self):
|
def test_raises_keyboard_interrupt_on_cancel(self):
|
||||||
"""Test that _step_model raises KeyboardInterrupt on cancel."""
|
"""Test that _step_model raises KeyboardInterrupt on cancel."""
|
||||||
@@ -1142,7 +1142,7 @@ class TestRunOnboard:
|
|||||||
"tui", # UI backend
|
"tui", # UI backend
|
||||||
"anthropic", # Provider
|
"anthropic", # Provider
|
||||||
"api_key", # Anthropic auth mode (API key, not OAuth)
|
"api_key", # Anthropic auth mode (API key, not OAuth)
|
||||||
"claude-sonnet-4-5", # Model
|
"claude-sonnet-4-6", # Model
|
||||||
"daemon", # Workspace mode
|
"daemon", # Workspace mode
|
||||||
True, # Show thinking
|
True, # Show thinking
|
||||||
]
|
]
|
||||||
@@ -1168,7 +1168,7 @@ class TestRunOnboard:
|
|||||||
# downstream prompts to consume the wrong values.
|
# downstream prompts to consume the wrong values.
|
||||||
final_config = mock_save.call_args_list[-1].args[0]
|
final_config = mock_save.call_args_list[-1].args[0]
|
||||||
assert final_config.provider == "anthropic"
|
assert final_config.provider == "anthropic"
|
||||||
assert final_config.model == "claude-sonnet-4-5"
|
assert final_config.model == "claude-sonnet-4-6"
|
||||||
assert final_config.anthropic_auth_mode == "api_key"
|
assert final_config.anthropic_auth_mode == "api_key"
|
||||||
assert final_config.ui_backend == "tui"
|
assert final_config.ui_backend == "tui"
|
||||||
assert final_config.default_mode == "daemon"
|
assert final_config.default_mode == "daemon"
|
||||||
@@ -1217,7 +1217,7 @@ class TestRunOnboard:
|
|||||||
"tui", # UI backend
|
"tui", # UI backend
|
||||||
"anthropic", # Provider
|
"anthropic", # Provider
|
||||||
"api_key", # Anthropic auth mode
|
"api_key", # Anthropic auth mode
|
||||||
"claude-sonnet-4-5", # Model
|
"claude-sonnet-4-6", # Model
|
||||||
"daemon", # Workspace mode
|
"daemon", # Workspace mode
|
||||||
True, # Show thinking
|
True, # Show thinking
|
||||||
]
|
]
|
||||||
@@ -1287,7 +1287,7 @@ class TestRunOnboard:
|
|||||||
"tui",
|
"tui",
|
||||||
"anthropic",
|
"anthropic",
|
||||||
"api_key",
|
"api_key",
|
||||||
"claude-sonnet-4-5",
|
"claude-sonnet-4-6",
|
||||||
"daemon",
|
"daemon",
|
||||||
True,
|
True,
|
||||||
]
|
]
|
||||||
@@ -1334,7 +1334,7 @@ class TestRunOnboard:
|
|||||||
"tui",
|
"tui",
|
||||||
"anthropic",
|
"anthropic",
|
||||||
"api_key",
|
"api_key",
|
||||||
"claude-sonnet-4-5",
|
"claude-sonnet-4-6",
|
||||||
"daemon",
|
"daemon",
|
||||||
True,
|
True,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ class TestUpdateStatusHook:
|
|||||||
|
|
||||||
def test_no_op(self):
|
def test_no_op(self):
|
||||||
ui, console = _make_ui()
|
ui, console = _make_ui()
|
||||||
ui.update_status_after_model_change("claude-opus-4-6", "anthropic")
|
ui.update_status_after_model_change("claude-opus-4-8", "anthropic")
|
||||||
console.print.assert_not_called()
|
console.print.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ class TestThreadFunctions(unittest.TestCase):
|
|||||||
"agent_name": AGENT_NAME,
|
"agent_name": AGENT_NAME,
|
||||||
"updated_at": f"2025-01-{15 + i}T10:00:00+00:00",
|
"updated_at": f"2025-01-{15 + i}T10:00:00+00:00",
|
||||||
"workspace_dir": f"/tmp/ws_{tid}",
|
"workspace_dir": f"/tmp/ws_{tid}",
|
||||||
"model": "claude-sonnet-4-5",
|
"model": "claude-sonnet-4-6",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
await conn.execute(
|
await conn.execute(
|
||||||
@@ -272,7 +272,7 @@ class TestThreadFunctions(unittest.TestCase):
|
|||||||
meta = _run(get_thread_metadata("abc12345"))
|
meta = _run(get_thread_metadata("abc12345"))
|
||||||
assert meta is not None
|
assert meta is not None
|
||||||
assert meta["workspace_dir"] == "/tmp/ws_abc12345"
|
assert meta["workspace_dir"] == "/tmp/ws_abc12345"
|
||||||
assert meta["model"] == "claude-sonnet-4-5"
|
assert meta["model"] == "claude-sonnet-4-6"
|
||||||
|
|
||||||
def test_get_thread_metadata_missing(self):
|
def test_get_thread_metadata_missing(self):
|
||||||
meta = _run(get_thread_metadata("nonexist"))
|
meta = _run(get_thread_metadata("nonexist"))
|
||||||
|
|||||||
Reference in New Issue
Block a user