blob: e044f3beb1fe178a91ac7292810564f2eaa628d4 [file] [log] [blame]
Earl Lee2e463fb2025-04-17 11:22:22 -07001package loop
2
3import (
4 "context"
5 "encoding/json"
Earl Lee2e463fb2025-04-17 11:22:22 -07006
Josh Bleecher Snyderf4047bb2025-05-05 23:02:56 +00007 "sketch.dev/claudetool/codereview"
Josh Bleecher Snyder4f84ab72025-04-22 16:40:54 -07008 "sketch.dev/llm"
Earl Lee2e463fb2025-04-17 11:22:22 -07009)
10
11// makeDoneTool creates a tool that provides a checklist to the agent. There
12// are some duplicative instructions here and in the system prompt, and it's
13// not as reliable as it could be. Historically, we've found that Claude ignores
14// the tool results here, so we don't tell the tool to say "hey, really check this"
15// at the moment, though we've tried.
Josh Bleecher Snyder93202652025-05-08 02:05:57 +000016func makeDoneTool(codereview *codereview.CodeReviewer) *llm.Tool {
Josh Bleecher Snyder4f84ab72025-04-22 16:40:54 -070017 return &llm.Tool{
Earl Lee2e463fb2025-04-17 11:22:22 -070018 Name: "done",
Josh Bleecher Snyder220a36d2025-05-08 19:06:26 +000019 Description: doneDescription,
20 InputSchema: json.RawMessage(doneChecklistJSONSchema),
Josh Bleecher Snyder43b60b92025-07-21 14:57:10 -070021 Run: func(ctx context.Context, input json.RawMessage) llm.ToolOut {
Earl Lee2e463fb2025-04-17 11:22:22 -070022 // Cannot be done with a messy git.
23 if err := codereview.RequireNormalGitState(ctx); err != nil {
Josh Bleecher Snyder43b60b92025-07-21 14:57:10 -070024 return llm.ErrorToolOut(err)
Earl Lee2e463fb2025-04-17 11:22:22 -070025 }
26 if err := codereview.RequireNoUncommittedChanges(ctx); err != nil {
Josh Bleecher Snyder43b60b92025-07-21 14:57:10 -070027 return llm.ErrorToolOut(err)
Earl Lee2e463fb2025-04-17 11:22:22 -070028 }
29 // Ensure that the current commit has been reviewed.
30 head, err := codereview.CurrentCommit(ctx)
31 if err == nil {
32 needsReview := !codereview.IsInitialCommit(head) && !codereview.HasReviewed(head)
33 if needsReview {
Josh Bleecher Snyder43b60b92025-07-21 14:57:10 -070034 return llm.ErrorfToolOut("codereview tool has not been run for commit %v", head)
Earl Lee2e463fb2025-04-17 11:22:22 -070035 }
36 }
Josh Bleecher Snyder43b60b92025-07-21 14:57:10 -070037 return llm.ToolOut{LLMContent: llm.TextContent("Please ask the user to review your work. Be concise - users are more likely to read shorter comments.")}
Earl Lee2e463fb2025-04-17 11:22:22 -070038 },
39 }
40}
41
Earl Lee2e463fb2025-04-17 11:22:22 -070042// TODO: this is ugly, maybe JSON-encode a deeply nested map[string]any instead? also ugly.
43const (
Josh Bleecher Snyder93202652025-05-08 02:05:57 +000044 doneDescription = `Use this tool when you have achieved the user's goal. The parameters form a checklist which you should evaluate.`
45 doneChecklistJSONSchema = `{
Earl Lee2e463fb2025-04-17 11:22:22 -070046 "type": "object",
Earl Lee2e463fb2025-04-17 11:22:22 -070047 "properties": {
Josh Bleecher Snyder9c74cb92025-07-24 12:52:04 -070048 "checked_guidance": {
Earl Lee2e463fb2025-04-17 11:22:22 -070049 "type": "object",
50 "required": ["status"],
51 "properties": {
Josh Bleecher Snyder9c74cb92025-07-24 12:52:04 -070052 "status": {"type": "string", "enum": ["yes", "no", "n/a"]},
53 "comments": {"type": "string"}
54 },
55 "description": "Checked for and followed any directory-specific guidance files for all modified files."
56 },
57 "tested": {
58 "type": "object",
59 "required": ["status"],
60 "properties": {
61 "status": {"type": "string", "enum": ["yes", "no", "n/a"]},
62 "comments": {"type": "string"}
63 },
64 "description": "If code was changed, tests were written or updated, and all tests pass."
65 },
66 "code_reviewed": {
67 "type": "object",
68 "required": ["status"],
69 "properties": {
70 "status": {"type": "string", "enum": ["yes", "no", "n/a"]},
71 "comments": {"type": "string"}
72 },
73 "description": "If any commits were made, the codereview tool was run and its output addressed."
74 },
75 "git_commit": {
76 "type": "object",
77 "required": ["status"],
78 "properties": {
79 "status": {"type": "string", "enum": ["yes", "no", "n/a"]},
80 "comments": {"type": "string"}
81 },
82 "description": "All code changes were committed. A git hook adds Co-Authored-By and Change-ID trailers. The git user is already configured correctly."
Earl Lee2e463fb2025-04-17 11:22:22 -070083 }
84 }
85}`
86)