diff --git a/README.md b/README.md index 251181b..b782293 100644 --- a/README.md +++ b/README.md @@ -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" } } diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index 6a4d240..fa56c7b 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -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 diff --git a/nanobot/config/schema.py b/nanobot/config/schema.py index f22a21b..e1d8e14 100644 --- a/nanobot/config/schema.py +++ b/nanobot/config/schema.py @@ -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 diff --git a/nanobot/providers/anthropic_oauth.py b/nanobot/providers/anthropic_oauth.py index b1fcfb2..ab46bb5 100644 --- a/nanobot/providers/anthropic_oauth.py +++ b/nanobot/providers/anthropic_oauth.py @@ -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) diff --git a/nanobot/providers/litellm_provider.py b/nanobot/providers/litellm_provider.py index 1fd7b90..fa37658 100644 --- a/nanobot/providers/litellm_provider.py +++ b/nanobot/providers/litellm_provider.py @@ -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. diff --git a/tests/test_anthropic_oauth.py b/tests/test_anthropic_oauth.py index 9217d95..b4da26d 100644 --- a/tests/test_anthropic_oauth.py +++ b/tests/test_anthropic_oauth.py @@ -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): diff --git a/tests/test_config_oauth_integration.py b/tests/test_config_oauth_integration.py index 8ef6f1a..cbfe4a1 100644 --- a/tests/test_config_oauth_integration.py +++ b/tests/test_config_oauth_integration.py @@ -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": ""}} })) diff --git a/tests/test_long_context_recovery.py b/tests/test_long_context_recovery.py index 1673924..aa4f3c2 100644 --- a/tests/test_long_context_recovery.py +++ b/tests/test_long_context_recovery.py @@ -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() diff --git a/tests/test_mem0_extract_facts.py b/tests/test_mem0_extract_facts.py index 5a8b875..4119114 100644 --- a/tests/test_mem0_extract_facts.py +++ b/tests/test_mem0_extract_facts.py @@ -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 diff --git a/tests/test_oauth_identity_block.py b/tests/test_oauth_identity_block.py index 98b17c7..d46f448 100644 --- a/tests/test_oauth_identity_block.py +++ b/tests/test_oauth_identity_block.py @@ -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", ) diff --git a/tests/test_provider_factory.py b/tests/test_provider_factory.py index 4d25979..6aabafe 100644 --- a/tests/test_provider_factory.py +++ b/tests/test_provider_factory.py @@ -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) diff --git a/tests/test_registry_oauth.py b/tests/test_registry_oauth.py index 30948d7..4f77ca2 100644 --- a/tests/test_registry_oauth.py +++ b/tests/test_registry_oauth.py @@ -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():