/ internal / tools / think.go
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 }