blob: 0bf8fbb4fe78bb3ee040c6ec1adcf2d39ab0d33e [file] [log] [blame]
Earl Lee2e463fb2025-04-17 11:22:22 -07001package loop
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7
Josh Bleecher Snyderf4047bb2025-05-05 23:02:56 +00008 "sketch.dev/claudetool/codereview"
Josh Bleecher Snyder4f84ab72025-04-22 16:40:54 -07009 "sketch.dev/llm"
Earl Lee2e463fb2025-04-17 11:22:22 -070010)
11
12// makeDoneTool creates a tool that provides a checklist to the agent. There
13// are some duplicative instructions here and in the system prompt, and it's
14// not as reliable as it could be. Historically, we've found that Claude ignores
15// the tool results here, so we don't tell the tool to say "hey, really check this"
16// at the moment, though we've tried.
Josh Bleecher Snyder93202652025-05-08 02:05:57 +000017func makeDoneTool(codereview *codereview.CodeReviewer) *llm.Tool {
Josh Bleecher Snyder4f84ab72025-04-22 16:40:54 -070018 return &llm.Tool{
Earl Lee2e463fb2025-04-17 11:22:22 -070019 Name: "done",
Josh Bleecher Snyder220a36d2025-05-08 19:06:26 +000020 Description: doneDescription,
21 InputSchema: json.RawMessage(doneChecklistJSONSchema),
Philip Zeyliger72252cb2025-05-10 17:00:08 -070022 Run: func(ctx context.Context, input json.RawMessage) ([]llm.Content, error) {
Earl Lee2e463fb2025-04-17 11:22:22 -070023 // Cannot be done with a messy git.
24 if err := codereview.RequireNormalGitState(ctx); err != nil {
Philip Zeyliger72252cb2025-05-10 17:00:08 -070025 return nil, err
Earl Lee2e463fb2025-04-17 11:22:22 -070026 }
27 if err := codereview.RequireNoUncommittedChanges(ctx); err != nil {
Philip Zeyliger72252cb2025-05-10 17:00:08 -070028 return nil, err
Earl Lee2e463fb2025-04-17 11:22:22 -070029 }
30 // Ensure that the current commit has been reviewed.
31 head, err := codereview.CurrentCommit(ctx)
32 if err == nil {
33 needsReview := !codereview.IsInitialCommit(head) && !codereview.HasReviewed(head)
34 if needsReview {
Philip Zeyliger72252cb2025-05-10 17:00:08 -070035 return nil, fmt.Errorf("codereview tool has not been run for commit %v", head)
Earl Lee2e463fb2025-04-17 11:22:22 -070036 }
37 }
Philip Zeyliger72252cb2025-05-10 17:00:08 -070038 return llm.TextContent("Please ask the user to review your work. Be concise - users are more likely to read shorter comments."), nil
Earl Lee2e463fb2025-04-17 11:22:22 -070039 },
40 }
41}
42
Earl Lee2e463fb2025-04-17 11:22:22 -070043// TODO: this is ugly, maybe JSON-encode a deeply nested map[string]any instead? also ugly.
44const (
Josh Bleecher Snyder93202652025-05-08 02:05:57 +000045 doneDescription = `Use this tool when you have achieved the user's goal. The parameters form a checklist which you should evaluate.`
46 doneChecklistJSONSchema = `{
Earl Lee2e463fb2025-04-17 11:22:22 -070047 "$schema": "http://json-schema.org/draft-07/schema#",
48 "title": "Checklist",
49 "description": "A schema for tracking checklist items with status and comments",
50 "type": "object",
51 "required": ["checklist_items"],
52 "properties": {
53 "checklist_items": {
54 "type": "object",
55 "description": "Collection of checklist items",
56 "properties": {
Josh Bleecher Snyder8dff12f2025-05-12 19:48:36 +000057 "checked_guidance": {
58 "$ref": "#/definitions/checklistItem",
59 "description": "I checked for and followed any directory-specific guidance files for all modified files."
60 },
Earl Lee2e463fb2025-04-17 11:22:22 -070061 "wrote_tests": {
62 "$ref": "#/definitions/checklistItem",
63 "description": "If code was changed, tests were written or updated."
64 },
65 "passes_tests": {
66 "$ref": "#/definitions/checklistItem",
67 "description": "If any commits were made, tests pass."
68 },
69 "code_reviewed": {
70 "$ref": "#/definitions/checklistItem",
71 "description": "If any commits were made, the codereview tool was run and its output was addressed."
72 },
73 "git_commit": {
74 "$ref": "#/definitions/checklistItem",
Josh Bleecher Snyder039fc342025-05-14 21:24:12 +000075 "description": "Create git commits for any code changes you made. A git hook will add Co-Authored-By and Change-ID trailers. The git user is already configured correctly."
Josh Bleecher Snyderc6a2c242025-04-22 18:04:16 -070076 }
Earl Lee2e463fb2025-04-17 11:22:22 -070077 },
78 "additionalProperties": {
79 "$ref": "#/definitions/checklistItem"
80 }
81 }
82 },
83 "definitions": {
84 "checklistItem": {
85 "type": "object",
86 "required": ["status"],
87 "properties": {
88 "status": {
89 "type": "string",
90 "description": "Current status of the checklist item",
91 "enum": ["yes", "no", "not applicable", "other"]
92 },
93 "description": {
94 "type": "string",
95 "description": "Description of what this checklist item verifies"
96 },
97 "comments": {
98 "type": "string",
99 "description": "Additional comments or context for this checklist item"
100 }
101 }
102 }
103 }
104}`
105)