think.go
1 package tools 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 8 "github.com/Kocoro-lab/ShanClaw/internal/agent" 9 ) 10 11 // ThinkTool lets the model reason or plan before acting. The model calls this 12 // tool instead of outputting plan text, giving the loop an explicit continuation 13 // signal (stop_reason: tool_use) rather than relying on text heuristics. 14 type ThinkTool struct{} 15 16 type thinkArgs struct { 17 Thought string `json:"thought"` 18 } 19 20 func (t *ThinkTool) Info() agent.ToolInfo { 21 return agent.ToolInfo{ 22 Name: "think", 23 Description: "Use this to plan or reason through complex multi-step tasks before acting. Always use this instead of outputting plans as plain text.", 24 Parameters: map[string]any{ 25 "type": "object", 26 "properties": map[string]any{ 27 "thought": map[string]any{"type": "string", "description": "Your reasoning or plan"}, 28 }, 29 }, 30 Required: []string{"thought"}, 31 } 32 } 33 34 func (t *ThinkTool) Run(ctx context.Context, argsJSON string) (agent.ToolResult, error) { 35 var args thinkArgs 36 if err := json.Unmarshal([]byte(argsJSON), &args); err != nil { 37 return agent.ToolResult{Content: fmt.Sprintf("invalid arguments: %v", err), IsError: true}, nil 38 } 39 if args.Thought == "" { 40 return agent.ToolResult{Content: "thought is required", IsError: true}, nil 41 } 42 return agent.ToolResult{Content: args.Thought}, nil 43 } 44 45 func (t *ThinkTool) RequiresApproval() bool { return false } 46 47 func (t *ThinkTool) IsReadOnlyCall(string) bool { return true }