1414from contextlib import contextmanager
1515from datetime import datetime
1616from pathlib import Path
17- from typing import Any
17+ from typing import Any , Literal , cast
1818
1919from sqlalchemy import Boolean , Column , DateTime , Integer , String , create_engine , text
2020from sqlalchemy .orm import DeclarativeBase , sessionmaker
@@ -46,14 +46,17 @@ def _migrate_registry_dir() -> None:
4646# Available models with display names
4747# To add a new model: add an entry here with {"id": "model-id", "name": "Display Name"}
4848AVAILABLE_MODELS = [
49- {"id" : "claude-opus-4-6 " , "name" : "Claude Opus" },
50- {"id" : "claude-sonnet-4-5-20250929 " , "name" : "Claude Sonnet" },
49+ {"id" : "claude-opus-4-7 " , "name" : "Claude Opus" },
50+ {"id" : "claude-sonnet-4-6 " , "name" : "Claude Sonnet" },
5151]
5252
5353# Map legacy model IDs to their current replacements.
5454# Used by get_all_settings() to auto-migrate stale values on first read after upgrade.
5555LEGACY_MODEL_MAP = {
56- "claude-opus-4-5-20251101" : "claude-opus-4-6" ,
56+ "claude-opus-4-5-20251101" : "claude-opus-4-7" ,
57+ "claude-opus-4-6" : "claude-opus-4-7" ,
58+ "claude-sonnet-4-5" : "claude-sonnet-4-6" ,
59+ "claude-sonnet-4-5-20250929" : "claude-sonnet-4-6" ,
5760}
5861
5962# List of valid model IDs (derived from AVAILABLE_MODELS)
@@ -65,7 +68,15 @@ def _migrate_registry_dir() -> None:
6568_env_default_model = os .getenv ("ANTHROPIC_DEFAULT_OPUS_MODEL" )
6669if _env_default_model is not None :
6770 _env_default_model = _env_default_model .strip ()
68- DEFAULT_MODEL = _env_default_model or "claude-opus-4-6"
71+ # Auto-remap stale env-provided values (e.g. user's .env still pins 4.6)
72+ if _env_default_model and _env_default_model in LEGACY_MODEL_MAP :
73+ logging .getLogger (__name__ ).warning (
74+ "ANTHROPIC_DEFAULT_OPUS_MODEL=%s is legacy; remapping to %s. "
75+ "Update your .env to silence this warning." ,
76+ _env_default_model , LEGACY_MODEL_MAP [_env_default_model ],
77+ )
78+ _env_default_model = LEGACY_MODEL_MAP [_env_default_model ]
79+ DEFAULT_MODEL = _env_default_model or "claude-opus-4-7"
6980
7081# Ensure env-provided DEFAULT_MODEL is in VALID_MODELS for validation consistency
7182# (idempotent: only adds if missing, doesn't alter AVAILABLE_MODELS semantics)
@@ -671,6 +682,28 @@ def get_setting(key: str, default: str | None = None) -> str | None:
671682 return default
672683
673684
685+ # Valid Claude Code reasoning/effort levels. Must match the CLI's --effort
686+ # choices (low, medium, high, xhigh, max) — note: the SDK's Literal type at
687+ # 0.1.61 omits "xhigh", but the string is forwarded to the CLI as-is and
688+ # accepted there.
689+ EffortLevel = Literal ["low" , "medium" , "high" , "xhigh" , "max" ]
690+ VALID_EFFORT_LEVELS : tuple [EffortLevel , ...] = ("low" , "medium" , "high" , "xhigh" , "max" )
691+ DEFAULT_EFFORT : EffortLevel = "xhigh"
692+
693+
694+ def get_effort_setting () -> EffortLevel :
695+ """
696+ Read the global reasoning-effort setting, falling back to ``xhigh``.
697+
698+ Unknown/invalid stored values are treated as missing so a DB corruption or
699+ schema drift can't force the CLI into an unsupported mode.
700+ """
701+ value = get_setting ("effort" )
702+ if value in VALID_EFFORT_LEVELS :
703+ return cast (EffortLevel , value )
704+ return DEFAULT_EFFORT
705+
706+
674707def set_setting (key : str , value : str ) -> None :
675708 """
676709 Set a setting value (creates or updates).
@@ -699,7 +732,7 @@ def get_all_settings() -> dict[str, str]:
699732 """
700733 Get all settings as a dictionary.
701734
702- Automatically migrates legacy model IDs (e.g. claude-opus-4-5-20251101 -> claude-opus-4-6 )
735+ Automatically migrates legacy model IDs (e.g. claude-opus-4-6 -> claude-opus-4-7 )
703736 on first read after upgrade. This is a one-time silent migration.
704737
705738 Returns:
@@ -747,10 +780,10 @@ def get_all_settings() -> dict[str, str]:
747780 "base_url" : None ,
748781 "requires_auth" : False ,
749782 "models" : [
750- {"id" : "claude-opus-4-6 " , "name" : "Claude Opus" },
751- {"id" : "claude-sonnet-4-5-20250929 " , "name" : "Claude Sonnet" },
783+ {"id" : "claude-opus-4-7 " , "name" : "Claude Opus" },
784+ {"id" : "claude-sonnet-4-6 " , "name" : "Claude Sonnet" },
752785 ],
753- "default_model" : "claude-opus-4-6 " ,
786+ "default_model" : "claude-opus-4-7 " ,
754787 },
755788 "kimi" : {
756789 "name" : "Kimi K2.5 (Moonshot)" ,
@@ -778,11 +811,11 @@ def get_all_settings() -> dict[str, str]:
778811 "requires_auth" : True ,
779812 "auth_env_var" : "ANTHROPIC_API_KEY" ,
780813 "models" : [
781- {"id" : "claude-opus-4-6 " , "name" : "Claude Opus" },
782- {"id" : "claude-sonnet-4-5 " , "name" : "Claude Sonnet" },
814+ {"id" : "claude-opus-4-7 " , "name" : "Claude Opus" },
815+ {"id" : "claude-sonnet-4-6 " , "name" : "Claude Sonnet" },
783816 {"id" : "claude-haiku-4-5" , "name" : "Claude Haiku" },
784817 ],
785- "default_model" : "claude-opus-4-6 " ,
818+ "default_model" : "claude-opus-4-7 " ,
786819 },
787820 "ollama" : {
788821 "name" : "Ollama (Local)" ,
0 commit comments