v0.50.0 c4ec31f

schema_compat_test.go RawHistoryFolder

1package tools
2
3import (
4	"encoding/json"
5	"testing"
6)
7
8// TestToolSchemasAnthropicCompatible guards the wire contract with the
9// Claude API: recent models (Opus 5.5, Fable 5.1) reject composition
10// keywords (oneOf/anyOf/allOf) at the root of a tool input_schema with a
11// 400. Every built-in schema must keep a plain object root.
12func TestToolSchemasAnthropicCompatible(t *testing.T) {
13	schemas := map[string]json.RawMessage{
14		"ast":                 (&ASTTool{}).Schema(),
15		"bash":                (&BashTool{}).Schema(),
16		"create_worktree":     (&CreateWorktreeTool{}).Schema(),
17		"edit":                (&EditTool{}).Schema(),
18		"glob":                (&GlobTool{}).Schema(),
19		"grep":                (&GrepTool{}).Schema(),
20		"lsp":                 (&LSPTool{}).Schema(),
21		"manage_worktrees":    (&ManageWorktreesTool{}).Schema(),
22		"plan":                (&PlanTool{}).Schema(),
23		"python":              (&PythonTool{}).Schema(),
24		"read":                (&ReadTool{}).Schema(),
25		"schedule":            (&ScheduleTool{}).Schema(),
26		"subagent":            (&SubagentTool{}).Schema(),
27		"telegram_send_file":  (&TelegramSendFileTool{}).Schema(),
28		"telegram_send_image": (&TelegramSendImageTool{}).Schema(),
29		"update_goal":         (&UpdateGoalTool{}).Schema(),
30		"web_click":           (&WebClickTool{}).Schema(),
31		"web_find":            (&WebFindTool{}).Schema(),
32		"web_open":            (&WebOpenTool{}).Schema(),
33		"web_search":          (&WebSearchTool{}).Schema(),
34		"worktree":            (&WorktreeTool{}).Schema(),
35		"write":               (&WriteTool{}).Schema(),
36	}
37	for name, raw := range schemas {
38		var schema map[string]any
39		if err := json.Unmarshal(raw, &schema); err != nil {
40			t.Fatalf("%s: invalid JSON schema: %v", name, err)
41		}
42		for _, key := range []string{"oneOf", "anyOf", "allOf"} {
43			if _, ok := schema[key]; ok {
44				t.Errorf("%s: top-level %q rejected by Claude API", name, key)
45			}
46		}
47		if schema["type"] != "object" {
48			t.Errorf("%s: root type = %v, want object", name, schema["type"])
49		}
50	}
51}
52
53// TestWebOpenExactlyOneRefOrURL keeps the exactly-one-of contract after
54// the oneOf keyword was removed from the web_open schema (Claude API
55// rejects top-level composition). parseWebOpenArgs remains the enforcer.
56func TestWebOpenExactlyOneRefOrURL(t *testing.T) {
57	for _, tc := range []struct {
58		name  string
59		raw   string
60		want  bool
61		refID string
62		url   string
63	}{
64		{"ref only", `{"ref_id":"web-1"}`, true, "web-1", ""},
65		{"url only", `{"url":"https://example.com"}`, true, "", "https://example.com"},
66		{"both", `{"ref_id":"web-1","url":"https://example.com"}`, false, "", ""},
67		{"neither", `{}`, false, "", ""},
68	} {
69		t.Run(tc.name, func(t *testing.T) {
70			args, ok := parseWebOpenArgs(json.RawMessage(tc.raw))
71			if ok != tc.want {
72				t.Fatalf("ok = %v, want %v", ok, tc.want)
73			}
74			if ok && (args.refID != tc.refID || args.url != tc.url) {
75				t.Fatalf("args = %+v", args)
76			}
77		})
78	}
79}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 477

↑↓ moveenter openesc close