chore: bump model defaults to Opus 4.7, Sonnet 4.6
Build Nanobot OAuth / build (pull_request) Successful in 7m4s
Build Nanobot OAuth / cleanup (pull_request) Has been skipped
Build Nanobot OAuth / build (push) Successful in 2m48s
Build Nanobot OAuth / cleanup (push) Successful in 1s

- Default model: anthropic/claude-opus-4-5 → anthropic/claude-opus-4-7
- Quota switcher: claude-opus-4-6 → claude-opus-4-7
- Update all provider defaults and test fixtures
- Update comments/docstrings referencing old model names
- Claude Opus 4.7 released 2026-04-16, same pricing as 4.6
This commit is contained in:
2026-04-17 02:53:08 +02:00
parent 71e65052d1
commit 59b4abaa14
12 changed files with 25 additions and 25 deletions
+1 -1
View File
@@ -143,7 +143,7 @@ Add or merge these **two parts** into your config (other options have defaults).
{
"agents": {
"defaults": {
"model": "anthropic/claude-opus-4-5",
"model": "anthropic/claude-opus-4-7",
"provider": "openrouter"
}
}
+1 -1
View File
@@ -221,7 +221,7 @@ class AgentLoop:
return self._quota_cache["model"]
# Default models
OPUS = "claude-opus-4-6"
OPUS = "claude-opus-4-7"
SONNET = "claude-sonnet-4-6"
TOLERANCE = 1.17 # 17% overage triggers downgrade
+1 -1
View File
@@ -220,7 +220,7 @@ class AgentDefaults(Base):
"""Default agent configuration."""
workspace: str = "~/.nanobot/workspace"
model: str = "anthropic/claude-opus-4-5"
model: str = "anthropic/claude-opus-4-7"
provider: str = "auto" # Provider name (e.g. "anthropic", "openrouter") or "auto" for auto-detection
max_tokens: int = 8192
temperature: float = 0.1
+4 -4
View File
@@ -27,7 +27,7 @@ class AnthropicOAuthProvider(LLMProvider):
def __init__(
self,
oauth_token: str,
default_model: str = "claude-opus-4-5",
default_model: str = "claude-opus-4-7",
api_base: str | None = None,
thinking_budget: int = 0,
):
@@ -51,8 +51,8 @@ class AnthropicOAuthProvider(LLMProvider):
def _normalize_model(model: str) -> str:
"""Normalize model name for the Anthropic API.
Anthropic model IDs use hyphens (claude-sonnet-4-5), but users often
write dots (claude-sonnet-4.5). Normalize so both work.
Anthropic model IDs use hyphens (claude-sonnet-4-6), but users often
write dots (claude-sonnet-4.6). Normalize so both work.
"""
return model.replace(".", "-")
@@ -557,7 +557,7 @@ class AnthropicOAuthProvider(LLMProvider):
if "/" in model:
model = model.split("/")[-1]
# Normalize dots to hyphens (claude-sonnet-4.5 -> claude-sonnet-4-5)
# Normalize dots to hyphens (claude-sonnet-4.6 -> claude-sonnet-4-6)
model = self._normalize_model(model)
system, prepared_messages = self._prepare_messages(messages)
+2 -2
View File
@@ -37,7 +37,7 @@ class LiteLLMProvider(LLMProvider):
self,
api_key: str | None = None,
api_base: str | None = None,
default_model: str = "anthropic/claude-opus-4-5",
default_model: str = "anthropic/claude-opus-4-7",
extra_headers: dict[str, str] | None = None,
provider_name: str | None = None,
):
@@ -187,7 +187,7 @@ class LiteLLMProvider(LLMProvider):
Args:
messages: List of message dicts with 'role' and 'content'.
tools: Optional list of tool definitions in OpenAI format.
model: Model identifier (e.g., 'anthropic/claude-sonnet-4-5').
model: Model identifier (e.g., 'anthropic/claude-sonnet-4-6').
max_tokens: Maximum tokens in response.
temperature: Sampling temperature.
+2 -2
View File
@@ -10,14 +10,14 @@ def provider():
"""Create provider with test OAuth token."""
return AnthropicOAuthProvider(
oauth_token="sk-ant-oat01-test-token",
default_model="claude-opus-4-5"
default_model="claude-opus-4-7"
)
def test_provider_init(provider):
"""Provider should initialize with OAuth token."""
assert provider.oauth_token == "sk-ant-oat01-test-token"
assert provider.default_model == "claude-opus-4-5"
assert provider.default_model == "claude-opus-4-7"
def test_provider_uses_bearer_auth(provider):
+1 -1
View File
@@ -13,7 +13,7 @@ def test_oauth_token_injected_into_config(tmp_path, monkeypatch):
# Create a minimal config file (no api key set)
config_path = tmp_path / "config.json"
config_path.write_text(json.dumps({
"agents": {"defaults": {"model": "anthropic/claude-opus-4-5"}},
"agents": {"defaults": {"model": "anthropic/claude-opus-4-7"}},
"providers": {"anthropic": {"apiKey": ""}}
}))
+2 -2
View File
@@ -20,7 +20,7 @@ async def test_provider_raises_long_context_error_on_long_context_429():
provider = AnthropicOAuthProvider(
oauth_token="sk-ant-oat01-test-token",
default_model="claude-sonnet-4-5",
default_model="claude-sonnet-4-6",
)
mock_response = MagicMock()
@@ -48,7 +48,7 @@ async def test_provider_retries_normal_429():
provider = AnthropicOAuthProvider(
oauth_token="sk-ant-oat01-test-token",
default_model="claude-sonnet-4-5",
default_model="claude-sonnet-4-6",
)
rate_limit_response = MagicMock()
+4 -4
View File
@@ -52,7 +52,7 @@ async def test_extract_facts_passes_thinking_budget_zero(mock_provider):
{"role": "assistant", "content": "That's great! Python is versatile."},
]
facts = await store.extract_facts(messages, mock_provider, "claude-sonnet-4-5")
facts = await store.extract_facts(messages, mock_provider, "claude-sonnet-4-6")
# Verify provider.chat was called with thinking_budget=0
mock_provider.chat.assert_called_once()
@@ -75,7 +75,7 @@ async def test_extract_facts_returns_parsed_facts(mock_provider):
{"role": "user", "content": "I like Python programming"},
]
facts = await store.extract_facts(messages, mock_provider, "claude-sonnet-4-5")
facts = await store.extract_facts(messages, mock_provider, "claude-sonnet-4-6")
assert facts == ["user likes Python", "user works on nanobot"]
@@ -99,7 +99,7 @@ async def test_extract_facts_handles_empty_response():
messages = [{"role": "user", "content": "Hello there"}]
facts = await store.extract_facts(messages, provider, "claude-sonnet-4-5")
facts = await store.extract_facts(messages, provider, "claude-sonnet-4-6")
assert facts == []
@@ -122,7 +122,7 @@ async def test_extract_facts_skips_empty_messages():
{"role": "assistant", "content": ""},
]
facts = await store.extract_facts(messages, provider, "claude-sonnet-4-5")
facts = await store.extract_facts(messages, provider, "claude-sonnet-4-6")
assert facts == []
# Provider should not be called when there's no content
+1 -1
View File
@@ -16,7 +16,7 @@ IDENTITY_TEXT = get_claude_code_system_prefix()
def provider():
return AnthropicOAuthProvider(
oauth_token="sk-ant-oat01-test-token",
default_model="claude-opus-4-5",
default_model="claude-opus-4-7",
)
+3 -3
View File
@@ -9,7 +9,7 @@ def test_create_provider_oauth_token():
"""OAuth tokens should create AnthropicOAuthProvider."""
provider = create_provider(
api_key="sk-ant-oat01-test-token",
model="anthropic/claude-opus-4-5"
model="anthropic/claude-opus-4-7"
)
assert isinstance(provider, AnthropicOAuthProvider)
@@ -18,7 +18,7 @@ def test_create_provider_regular_key():
"""Regular API keys should create LiteLLMProvider."""
provider = create_provider(
api_key="sk-ant-api03-regular-key",
model="anthropic/claude-opus-4-5"
model="anthropic/claude-opus-4-7"
)
assert isinstance(provider, LiteLLMProvider)
@@ -27,6 +27,6 @@ def test_create_provider_openrouter():
"""OpenRouter keys should create LiteLLMProvider."""
provider = create_provider(
api_key="sk-or-v1-xxx",
model="anthropic/claude-opus-4-5"
model="anthropic/claude-opus-4-7"
)
assert isinstance(provider, LiteLLMProvider)
+3 -3
View File
@@ -5,14 +5,14 @@ from nanobot.providers.registry import should_use_oauth_provider
def test_should_use_oauth_for_oat_token():
"""OAuth provider should be used for sk-ant-oat tokens."""
assert should_use_oauth_provider("sk-ant-oat01-xxx", "anthropic/claude-opus-4-5") is True
assert should_use_oauth_provider("sk-ant-oat01-xxx", "anthropic/claude-opus-4-7") is True
assert should_use_oauth_provider("sk-ant-oat01-xxx", "claude-sonnet-4") is True
def test_should_not_use_oauth_for_regular_key():
"""Regular API keys should not use OAuth provider."""
assert should_use_oauth_provider("sk-ant-api03-xxx", "claude-opus-4-5") is False
assert should_use_oauth_provider("sk-or-v1-xxx", "anthropic/claude-opus-4-5") is False
assert should_use_oauth_provider("sk-ant-api03-xxx", "claude-opus-4-7") is False
assert should_use_oauth_provider("sk-or-v1-xxx", "anthropic/claude-opus-4-7") is False
def test_should_not_use_oauth_for_non_anthropic():