Skip to content

Commit 444e74f

Browse files
Append [1m] to Opus >=4.6 and Sonnet 4.6 model for 1m context length support (#118)
* claude: append [1m] to Opus >=4.6 and Sonnet 4.6 model ids when writing settings.json; update tests * claude: allow opus 4.8 discovery * chore: format databricks * claude: apply 1m suffix to future sonnet models
1 parent aefbd11 commit 444e74f

4 files changed

Lines changed: 63 additions & 18 deletions

File tree

src/ucode/agents/claude.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import os
6+
import re
67
import shutil
78
from pathlib import Path
89

@@ -58,6 +59,7 @@ def _resolve_web_search_model(state: dict) -> str | None:
5859

5960

6061
WEB_SEARCH_MCP_NAME = "web_search"
62+
_CLAUDE_MODEL_RE = re.compile(r"^databricks-claude-(opus|sonnet)-(\d+)-(\d+)(.*)$")
6163

6264

6365
def _web_search_mcp_entry(workspace: str, search_model: str, profile: str | None = None) -> dict:
@@ -103,17 +105,17 @@ def render_overlay(
103105
]
104106
)
105107
env: dict[str, str] = {
106-
"ANTHROPIC_MODEL": model,
108+
"ANTHROPIC_MODEL": _maybe_add_1m_suffix(model),
107109
"ANTHROPIC_BASE_URL": base_url,
108110
"ANTHROPIC_CUSTOM_HEADERS": custom_headers,
109111
"CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS": "1",
110112
"CLAUDE_CODE_API_KEY_HELPER_TTL_MS": "900000",
111113
}
112114
if claude_models:
113115
if claude_models.get("opus"):
114-
env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = claude_models["opus"]
116+
env["ANTHROPIC_DEFAULT_OPUS_MODEL"] = _maybe_add_1m_suffix(claude_models["opus"])
115117
if claude_models.get("sonnet"):
116-
env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = claude_models["sonnet"]
118+
env["ANTHROPIC_DEFAULT_SONNET_MODEL"] = _maybe_add_1m_suffix(claude_models["sonnet"])
117119
if claude_models.get("haiku"):
118120
env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] = claude_models["haiku"]
119121
overlay: dict = {"apiKeyHelper": build_auth_shell_command(workspace, profile), "env": env}
@@ -129,6 +131,22 @@ def render_overlay(
129131
return overlay, keys
130132

131133

134+
def _maybe_add_1m_suffix(model: str) -> str:
135+
if model.endswith("[1m]"):
136+
return model
137+
match = _CLAUDE_MODEL_RE.match(model)
138+
if not match:
139+
return model
140+
141+
family, major_raw, minor_raw, _ = match.groups()
142+
major = int(major_raw)
143+
minor = int(minor_raw)
144+
should_suffix = (family == "opus" and (major, minor) >= (4, 6)) or (
145+
family == "sonnet" and (major, minor) >= (4, 6)
146+
)
147+
return f"{model}[1m]" if should_suffix else model
148+
149+
132150
def _register_web_search_mcp(workspace: str, search_model: str, profile: str | None = None) -> bool:
133151
"""Register (or replace) the web_search MCP server in Claude Code's user
134152
scope via `claude mcp add-json`. Removes any prior entry first so re-runs

src/ucode/databricks.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -804,14 +804,6 @@ def build_auth_shell_command(workspace: str, profile: str | None = None) -> str:
804804
)
805805

806806

807-
# Model ids the AI Gateway advertises but currently rejects at launch with
808-
# "The provided model identifier is invalid." Filter them out at discovery so
809-
# agent harnesses don't try to boot with them.
810-
_CLAUDE_MODEL_DISCOVERY_DENYLIST = {
811-
"databricks-claude-opus-4-8",
812-
}
813-
814-
815807
def discover_claude_models(workspace: str, token: str) -> tuple[dict[str, str], str | None]:
816808
"""Discover Claude families on this workspace's AI Gateway.
817809
@@ -828,9 +820,7 @@ def discover_claude_models(workspace: str, token: str) -> tuple[dict[str, str],
828820
raw_ids = [
829821
m["id"]
830822
for m in data.get("data", [])
831-
if isinstance(m.get("id"), str)
832-
and not m["id"].endswith("-anthropic")
833-
and m["id"] not in _CLAUDE_MODEL_DISCOVERY_DENYLIST
823+
if isinstance(m.get("id"), str) and not m["id"].endswith("-anthropic")
834824
]
835825

836826
result: dict[str, str] = {}

tests/test_agent_claude.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,22 @@ def test_sets_anthropic_model(self):
2525
overlay, _ = claude.render_overlay(WS, "databricks-claude-sonnet-4")
2626
assert overlay["env"]["ANTHROPIC_MODEL"] == "databricks-claude-sonnet-4"
2727

28+
def test_adds_1m_suffix_for_opus_4_6_and_later(self):
29+
overlay, _ = claude.render_overlay(WS, "databricks-claude-opus-4-7")
30+
assert overlay["env"]["ANTHROPIC_MODEL"] == "databricks-claude-opus-4-7[1m]"
31+
32+
def test_adds_1m_suffix_for_sonnet_4_6_and_later(self):
33+
overlay, _ = claude.render_overlay(WS, "databricks-claude-sonnet-4-7")
34+
assert overlay["env"]["ANTHROPIC_MODEL"] == "databricks-claude-sonnet-4-7[1m]"
35+
36+
def test_does_not_add_1m_suffix_for_other_models(self):
37+
overlay, _ = claude.render_overlay(WS, "databricks-claude-haiku-4-6")
38+
assert overlay["env"]["ANTHROPIC_MODEL"] == "databricks-claude-haiku-4-6"
39+
40+
def test_does_not_duplicate_1m_suffix(self):
41+
overlay, _ = claude.render_overlay(WS, "databricks-claude-opus-4-7[1m]")
42+
assert overlay["env"]["ANTHROPIC_MODEL"] == "databricks-claude-opus-4-7[1m]"
43+
2844
def test_sets_anthropic_base_url(self):
2945
overlay, _ = claude.render_overlay(WS, "s4")
3046
assert overlay["env"]["ANTHROPIC_BASE_URL"] == f"{WS}/ai-gateway/anthropic"
@@ -43,12 +59,16 @@ def test_sets_api_key_helper(self):
4359
assert WS in overlay["apiKeyHelper"]
4460

4561
def test_model_overrides_when_all_provided(self):
46-
models = {"sonnet": "s4", "opus": "o4", "haiku": "h4"}
62+
models = {
63+
"sonnet": "databricks-claude-sonnet-4-6",
64+
"opus": "databricks-claude-opus-4-7",
65+
"haiku": "databricks-claude-haiku-4-6",
66+
}
4767
overlay, _ = claude.render_overlay(WS, "s4", claude_models=models)
4868
env = overlay["env"]
49-
assert env["ANTHROPIC_DEFAULT_SONNET_MODEL"] == "s4"
50-
assert env["ANTHROPIC_DEFAULT_OPUS_MODEL"] == "o4"
51-
assert env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] == "h4"
69+
assert env["ANTHROPIC_DEFAULT_SONNET_MODEL"] == "databricks-claude-sonnet-4-6[1m]"
70+
assert env["ANTHROPIC_DEFAULT_OPUS_MODEL"] == "databricks-claude-opus-4-7[1m]"
71+
assert env["ANTHROPIC_DEFAULT_HAIKU_MODEL"] == "databricks-claude-haiku-4-6"
5272

5373
def test_model_overrides_partial(self):
5474
models = {"sonnet": "s4"}

tests/test_databricks.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,23 @@ def test_codex_url_format(self):
114114
assert urls["codex"] == f"{WS}/ai-gateway/codex/v1"
115115

116116

117+
class TestDiscoverClaudeModels:
118+
def test_selects_opus_4_8_when_advertised(self, monkeypatch):
119+
payload = {
120+
"data": [
121+
{"id": "databricks-claude-opus-4-7"},
122+
{"id": "databricks-claude-opus-4-8"},
123+
{"id": "databricks-claude-sonnet-4-6"},
124+
]
125+
}
126+
monkeypatch.setattr(db_mod, "_http_get_json", lambda url, token: (payload, None))
127+
128+
models, reason = db_mod.discover_claude_models(WS, "token")
129+
130+
assert reason is None
131+
assert models["opus"] == "databricks-claude-opus-4-8"
132+
133+
117134
class TestBuildAuthShellCommand:
118135
def test_contains_workspace(self):
119136
cmd = build_auth_shell_command(WS)

0 commit comments

Comments
 (0)