Skip to content

Commit f64b9af

Browse files
authored
fix(cua): switch anthropic computer-use defaults to claude-sonnet-4-6 (#130)
## Summary - update the TypeScript anthropic computer-use template to use `claude-sonnet-4-6` as the default model - update the Python anthropic computer-use template to use `claude-sonnet-4-6` as the default model - remove the dated model suffix from new template defaults so generated apps use the stable alias ## Test plan - [x] `make test` Made with [Cursor](https://cursor.com) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it changes generated template behavior (default model selection and Anthropic tool version/beta flags) and adjusts TypeScript SDK typings, which could break newly scaffolded apps if versions drift. > > **Overview** > Switches the Anthropic Computer Use templates (Python + TypeScript) to default to the stable `claude-sonnet-4-6` model alias and introduces a new `computer_use_20251124` tool version (with corresponding `computer_20251124` tool) that is auto-selected for newer Claude models unless explicitly overridden. > > Cleans up the TypeScript template by removing `luxon` (using `Intl.DateTimeFormat` instead), updating `@onkernel/sdk` to `^0.35.0`, tightening tool param types to Anthropic SDK-provided unions, and making browser `liveViewUrl`/`replayViewUrl` explicitly nullable. > > Updates the scaffolding copier (`CopyTemplateFiles`) to skip common artifact directories (`node_modules`, `.venv`, `__pycache__`) during template copy, with a new test to enforce this behavior. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 6bde8ec. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 5b12089 commit f64b9af

17 files changed

Lines changed: 175 additions & 120 deletions

File tree

pkg/create/copy.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"io/fs"
66
"os"
77
"path/filepath"
8+
"strings"
89

910
"github.com/kernel/cli/pkg/templates"
1011
)
@@ -14,6 +15,25 @@ const (
1415
FILE_PERM = 0644 // rw-r--r--
1516
)
1617

18+
var skippedTemplateDirs = map[string]struct{}{
19+
"node_modules": {},
20+
".venv": {},
21+
"__pycache__": {},
22+
}
23+
24+
func shouldSkipTemplatePath(relPath string) bool {
25+
if relPath == "." {
26+
return false
27+
}
28+
parts := strings.Split(filepath.ToSlash(relPath), "/")
29+
for _, part := range parts {
30+
if _, ok := skippedTemplateDirs[part]; ok {
31+
return true
32+
}
33+
}
34+
return false
35+
}
36+
1737
// CopyTemplateFiles copies all files and directories from the specified embedded template
1838
// into the target application path. It uses the given language and template names
1939
// to locate the template inside the embedded filesystem.
@@ -57,6 +77,14 @@ func CopyTemplateFiles(appPath, language, template string) error {
5777
return nil
5878
}
5979

80+
// Skip environment/build artifacts that should never be scaffolded.
81+
if shouldSkipTemplatePath(relPath) {
82+
if d.IsDir() {
83+
return fs.SkipDir
84+
}
85+
return nil
86+
}
87+
6088
destPath := filepath.Join(appPath, relPath)
6189

6290
if d.IsDir() {

pkg/create/copy_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,21 @@ func TestCopyTemplateFiles_PreservesDirectoryStructure(t *testing.T) {
189189
}
190190
}
191191

192+
func TestCopyTemplateFiles_SkipsArtifactDirectories(t *testing.T) {
193+
tmpDir := t.TempDir()
194+
appPath := filepath.Join(tmpDir, "test-app")
195+
196+
err := os.MkdirAll(appPath, testDirPerm)
197+
require.NoError(t, err)
198+
199+
err = CopyTemplateFiles(appPath, LanguageTypeScript, TemplateAnthropicComputerUse)
200+
require.NoError(t, err)
201+
202+
assert.NoDirExists(t, filepath.Join(appPath, "node_modules"))
203+
assert.NoDirExists(t, filepath.Join(appPath, ".venv"))
204+
assert.NoDirExists(t, filepath.Join(appPath, "__pycache__"))
205+
}
206+
192207
func TestCopyTemplateFiles_OverwritesExistingFiles(t *testing.T) {
193208
tmpDir := t.TempDir()
194209
appPath := filepath.Join(tmpDir, "test-app")

pkg/templates/python/anthropic-computer-use/loop.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ async def sampling_loop(
7676
system_prompt_suffix: str = "",
7777
only_n_most_recent_images: int | None = None,
7878
max_tokens: int = 4096,
79-
tool_version: ToolVersion = "computer_use_20250124",
79+
tool_version: ToolVersion | None = None,
8080
thinking_budget: int | None = None,
8181
token_efficient_tools_beta: bool = False,
8282
viewport_width: int = 1280,
@@ -95,11 +95,12 @@ async def sampling_loop(
9595
system_prompt_suffix: Additional system prompt text (defaults to empty string)
9696
only_n_most_recent_images: Optional limit on number of recent images to keep
9797
max_tokens: Maximum tokens for the response (defaults to 4096)
98-
tool_version: Version of tools to use (defaults to V20250124)
98+
tool_version: Optional explicit tool version override
9999
thinking_budget: Optional token budget for thinking
100100
token_efficient_tools_beta: Whether to use token efficient tools beta
101101
"""
102-
tool_group = TOOL_GROUPS_BY_VERSION[tool_version]
102+
selected_tool_version = tool_version or _tool_version_for_model(model)
103+
tool_group = TOOL_GROUPS_BY_VERSION[selected_tool_version]
103104
tool_collection = ToolCollection(
104105
*(
105106
ToolCls(kernel=kernel, session_id=session_id, width=viewport_width, height=viewport_height) if ToolCls.__name__.startswith("ComputerTool") else ToolCls()
@@ -194,6 +195,16 @@ async def sampling_loop(
194195
messages.append({"content": tool_result_content, "role": "user"})
195196

196197

198+
def _tool_version_for_model(model: str) -> ToolVersion:
199+
if (
200+
"claude-sonnet-4-6" in model
201+
or "claude-opus-4-6" in model
202+
or "claude-opus-4-5" in model
203+
):
204+
return "computer_use_20251124"
205+
return "computer_use_20250124"
206+
207+
197208
def _maybe_filter_to_n_most_recent_images(
198209
messages: list[BetaMessageParam],
199210
images_to_keep: int,

pkg/templates/python/anthropic-computer-use/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ async def cua_task(
5555
print("Kernel browser live view url:", session.live_view_url)
5656

5757
final_messages = await sampling_loop(
58-
model="claude-sonnet-4-5-20250929",
58+
model="claude-sonnet-4-6",
5959
messages=[
6060
{
6161
"role": "user",

pkg/templates/python/anthropic-computer-use/tools/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from .base import ToolResult
22
from .collection import ToolCollection
3-
from .computer import ComputerTool20241022, ComputerTool20250124
3+
from .computer import ComputerTool20241022, ComputerTool20250124, ComputerTool20251124
44
from .groups import TOOL_GROUPS_BY_VERSION, ToolVersion
55

66
__ALL__ = [
77
ComputerTool20241022,
88
ComputerTool20250124,
9+
ComputerTool20251124,
910
ToolCollection,
1011
ToolResult,
1112
ToolVersion,

pkg/templates/python/anthropic-computer-use/tools/computer.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
"triple_click",
9191
]
9292
)
93+
Action_20251124 = Action_20250124
9394

9495
ScrollDirection = Literal["up", "down", "left", "right"]
9596

@@ -476,3 +477,13 @@ async def __call__(
476477
return await super().__call__(
477478
action=action, text=text, coordinate=coordinate, key=key, **kwargs
478479
)
480+
481+
482+
class ComputerTool20251124(ComputerTool20250124):
483+
api_type: Literal["computer_20251124"] = "computer_20251124"
484+
485+
def to_params(self):
486+
return cast(
487+
BetaToolUnionParam,
488+
{"name": self.name, "type": self.api_type, **self.options},
489+
)

pkg/templates/python/anthropic-computer-use/tools/groups.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
from typing import Literal
88

99
from .base import BaseAnthropicTool
10-
from .computer import ComputerTool20241022, ComputerTool20250124
10+
from .computer import ComputerTool20241022, ComputerTool20250124, ComputerTool20251124
1111

1212
ToolVersion = Literal[
13-
"computer_use_20250124", "computer_use_20241022", "computer_use_20250429"
13+
"computer_use_20250124", "computer_use_20241022", "computer_use_20250429", "computer_use_20251124"
1414
]
1515
BetaFlag = Literal[
16-
"computer-use-2024-10-22", "computer-use-2025-01-24", "computer-use-2025-04-29"
16+
"computer-use-2024-10-22", "computer-use-2025-01-24", "computer-use-2025-04-29", "computer-use-2025-11-24"
1717
]
1818

1919

@@ -35,6 +35,11 @@ class ToolGroup:
3535
tools=[ComputerTool20250124],
3636
beta_flag="computer-use-2025-01-24",
3737
),
38+
ToolGroup(
39+
version="computer_use_20251124",
40+
tools=[ComputerTool20251124],
41+
beta_flag="computer-use-2025-11-24",
42+
),
3843
ToolGroup(
3944
version="computer_use_20250429",
4045
tools=[ComputerTool20250124],

pkg/templates/typescript/anthropic-computer-use/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ app.action<QueryInput, QueryOutput>(
4444
try {
4545
// Run the sampling loop
4646
const finalMessages = await samplingLoop({
47-
model: 'claude-sonnet-4-5-20250929',
47+
model: 'claude-sonnet-4-6',
4848
messages: [{
4949
role: 'user',
5050
content: payload.query,

pkg/templates/typescript/anthropic-computer-use/loop.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
import { Anthropic } from '@anthropic-ai/sdk';
2-
import { DateTime } from 'luxon';
32
import type { Kernel } from '@onkernel/sdk';
43
import { DEFAULT_TOOL_VERSION, TOOL_GROUPS_BY_VERSION, ToolCollection, type ToolVersion } from './tools/collection';
5-
import { ComputerTool20241022, ComputerTool20250124 } from './tools/computer';
4+
import { ComputerTool20241022, ComputerTool20250124, ComputerTool20251124 } from './tools/computer';
65
import type { ActionParams } from './tools/types/computer';
76
import { Action } from './tools/types/computer';
87
import type { BetaMessageParam, BetaTextBlock } from './types/beta';
98
import { injectPromptCaching, maybeFilterToNMostRecentImages, PROMPT_CACHING_BETA_FLAG, responseToParams } from './utils/message-processing';
109
import { makeApiToolResult } from './utils/tool-results';
1110

11+
const CURRENT_DATE = new Intl.DateTimeFormat('en-US', {
12+
weekday: 'long',
13+
month: 'long',
14+
day: 'numeric',
15+
year: 'numeric',
16+
}).format(new Date());
17+
1218
// System prompt optimized for the environment
1319
const SYSTEM_PROMPT = `<SYSTEM_CAPABILITY>
1420
* You are utilising an Ubuntu virtual machine using ${process.arch} architecture with internet access.
@@ -21,7 +27,7 @@ const SYSTEM_PROMPT = `<SYSTEM_CAPABILITY>
2127
* Scroll action: scroll_amount and the tool result are in wheel units (not pixels).
2228
* When using your computer function calls, they take a while to run and send back to you.
2329
* Where possible/feasible, try to chain multiple of these calls all into one function calls request.
24-
* The current date is ${DateTime.now().toFormat('EEEE, MMMM d, yyyy')}.
30+
* The current date is ${CURRENT_DATE}.
2531
* After each step, take a screenshot and carefully evaluate if you have achieved the right outcome.
2632
* Explicitly show your thinking: "I have evaluated step X..." If not correct, try again.
2733
* Only when you confirm a step was executed correctly should you move on to the next one.
@@ -46,6 +52,17 @@ interface ToolUseInput extends Record<string, unknown> {
4652
action: Action;
4753
}
4854

55+
function getToolVersionForModel(model: string): ToolVersion {
56+
if (
57+
model.includes('claude-sonnet-4-6')
58+
|| model.includes('claude-opus-4-6')
59+
|| model.includes('claude-opus-4-5')
60+
) {
61+
return 'computer_use_20251124';
62+
}
63+
return 'computer_use_20250124';
64+
}
65+
4966
export async function samplingLoop({
5067
model,
5168
systemPromptSuffix,
@@ -75,9 +92,9 @@ export async function samplingLoop({
7592
viewportWidth?: number;
7693
viewportHeight?: number;
7794
}): Promise<BetaMessageParam[]> {
78-
const selectedVersion = toolVersion || DEFAULT_TOOL_VERSION;
95+
const selectedVersion = toolVersion || getToolVersionForModel(model) || DEFAULT_TOOL_VERSION;
7996
const toolGroup = TOOL_GROUPS_BY_VERSION[selectedVersion];
80-
const toolCollection = new ToolCollection(...toolGroup.tools.map((Tool: typeof ComputerTool20241022 | typeof ComputerTool20250124) => new Tool(kernel, sessionId, viewportWidth, viewportHeight)));
97+
const toolCollection = new ToolCollection(...toolGroup.tools.map((Tool: typeof ComputerTool20241022 | typeof ComputerTool20250124 | typeof ComputerTool20251124) => new Tool(kernel, sessionId, viewportWidth, viewportHeight)));
8198

8299
const system: BetaTextBlock = {
83100
type: 'text',

pkg/templates/typescript/anthropic-computer-use/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
"private": true,
66
"dependencies": {
77
"@anthropic-ai/sdk": "^0.71.2",
8-
"@onkernel/sdk": "^0.35.0",
9-
"luxon": "^3.7.2"
8+
"@onkernel/sdk": "^0.35.0"
109
},
1110
"devDependencies": {
1211
"@types/node": "^22.15.17",

0 commit comments

Comments
 (0)