Documentation
¶
Overview ¶
Package tools provides the tool system for extending Hex with external capabilities. ABOUTME: AskUserQuestion tool for interactive decision-making ABOUTME: Presents multiple-choice questions to users and collects answers
Example ¶
Example demonstrates the complete tool system workflow
package main
import (
"context"
"fmt"
"github.com/2389-research/hex/internal/tools"
)
func main() {
// 1. Create a registry
registry := tools.NewRegistry()
// 2. Create and register a safe tool (no approval needed)
safeTool := &tools.MockTool{
NameValue: "echo",
DescriptionValue: "Echoes back the input",
RequiresApprovalValue: false,
ExecuteFunc: func(_ context.Context, params map[string]interface{}) (*tools.Result, error) {
message := params["message"].(string)
return &tools.Result{
ToolName: "echo",
Success: true,
Output: message,
}, nil
},
}
_ = registry.Register(safeTool)
// 3. Create and register a dangerous tool (requires approval)
dangerousTool := &tools.MockTool{
NameValue: "delete_file",
DescriptionValue: "Deletes a file",
RequiresApprovalValue: true,
ExecuteFunc: func(_ context.Context, params map[string]interface{}) (*tools.Result, error) {
path := params["path"].(string)
return &tools.Result{
ToolName: "delete_file",
Success: true,
Output: fmt.Sprintf("Deleted %s", path),
}, nil
},
}
_ = registry.Register(dangerousTool)
// 4. Create an executor with approval function
approvalFunc := func(toolName string, params map[string]interface{}) bool {
// In a real application, this would prompt the user
// For this example, we'll approve delete operations on /tmp
if toolName == "delete_file" {
path := params["path"].(string)
return path == "/tmp/test.txt"
}
return true
}
executor := tools.NewExecutor(registry, approvalFunc)
// 5. Execute the safe tool (no approval needed)
ctx := context.Background()
result1, _ := executor.Execute(ctx, "echo", map[string]interface{}{
"message": "Hello, World!",
})
fmt.Printf("Echo result: %s\n", result1.Output)
// 6. Execute dangerous tool with approved path
result2, _ := executor.Execute(ctx, "delete_file", map[string]interface{}{
"path": "/tmp/test.txt",
})
fmt.Printf("Delete result (approved): %s\n", result2.Output)
// 7. Execute dangerous tool with denied path
result3, _ := executor.Execute(ctx, "delete_file", map[string]interface{}{
"path": "/etc/passwd",
})
fmt.Printf("Delete result (denied): success=%v, error=%s\n", result3.Success, result3.Error)
// 8. List all registered tools
tools := registry.List()
fmt.Printf("Registered tools: %v\n", tools)
}
Output: Echo result: Hello, World! Delete result (approved): Deleted /tmp/test.txt Delete result (denied): success=false, error=user denied permission Registered tools: [delete_file echo]
Example (CompleteWorkflow) ¶
Example_completeWorkflow demonstrates a complete tool system workflow
package main
import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/2389-research/hex/internal/tools"
)
func main() {
// Simulate a simple file system tool
type FileSystemTool struct {
name string
}
readTool := &FileSystemTool{name: "read_file"}
writeTool := &FileSystemTool{name: "write_file"}
// Implement Tool interface for FileSystemTool
getName := func(t *FileSystemTool) string { return t.name }
getDesc := func(t *FileSystemTool) string { return fmt.Sprintf("Tool: %s", t.name) }
requiresApproval := func(t *FileSystemTool, _ map[string]interface{}) bool {
// Write operations require approval
return t.name == "write_file"
}
execute := func(t *FileSystemTool, _ context.Context, params map[string]interface{}) (*tools.Result, error) {
path := params["path"].(string)
if t.name == "read_file" {
return &tools.Result{
ToolName: t.name,
Success: true,
Output: fmt.Sprintf("Contents of %s", path),
Metadata: map[string]interface{}{"path": path},
}, nil
}
// write_file
content := params["content"].(string)
return &tools.Result{
ToolName: t.name,
Success: true,
Output: fmt.Sprintf("Wrote %d bytes to %s", len(content), path),
Metadata: map[string]interface{}{"path": path, "bytes": len(content)},
}, nil
}
// Wrap in MockTool for demonstration
readMock := &tools.MockTool{
NameValue: getName(readTool),
DescriptionValue: getDesc(readTool),
ExecuteFunc: func(ctx context.Context, params map[string]interface{}) (*tools.Result, error) {
return execute(readTool, ctx, params)
},
}
writeMock := &tools.MockTool{
NameValue: getName(writeTool),
DescriptionValue: getDesc(writeTool),
RequiresApprovalValue: requiresApproval(writeTool, nil),
ExecuteFunc: func(ctx context.Context, params map[string]interface{}) (*tools.Result, error) {
return execute(writeTool, ctx, params)
},
}
// 1. Setup: Create registry and register tools
registry := tools.NewRegistry()
_ = registry.Register(readMock)
_ = registry.Register(writeMock)
// 2. Create executor with approval logic
approvalFunc := func(toolName string, params map[string]interface{}) bool {
// Approve writes to /tmp, deny others
if toolName == "write_file" {
path := params["path"].(string)
return strings.HasPrefix(path, "/tmp/")
}
return true
}
executor := tools.NewExecutor(registry, approvalFunc)
// 3. Simulate API request (read_file)
apiRequest1 := `{
"type": "tool_use",
"id": "toolu_read_123",
"name": "read_file",
"input": {
"path": "/tmp/config.json"
}
}`
var toolUse1 tools.ToolUse
_ = json.Unmarshal([]byte(apiRequest1), &toolUse1)
// 4. Execute tool
ctx := context.Background()
result1, _ := executor.Execute(ctx, toolUse1.Name, toolUse1.Input)
// 5. Convert to API response
toolResult1 := tools.ResultToToolResult(result1, toolUse1.ID)
fmt.Printf("Read operation: success=%v\n", !toolResult1.IsError)
// 6. Simulate API request (write_file with approval)
apiRequest2 := `{
"type": "tool_use",
"id": "toolu_write_456",
"name": "write_file",
"input": {
"path": "/tmp/output.txt",
"content": "Hello, World!"
}
}`
var toolUse2 tools.ToolUse
_ = json.Unmarshal([]byte(apiRequest2), &toolUse2)
result2, _ := executor.Execute(ctx, toolUse2.Name, toolUse2.Input)
toolResult2 := tools.ResultToToolResult(result2, toolUse2.ID)
fmt.Printf("Write operation (approved): success=%v\n", !toolResult2.IsError)
// 7. Simulate denied write operation
apiRequest3 := `{
"type": "tool_use",
"id": "toolu_write_789",
"name": "write_file",
"input": {
"path": "/etc/passwd",
"content": "malicious"
}
}`
var toolUse3 tools.ToolUse
_ = json.Unmarshal([]byte(apiRequest3), &toolUse3)
result3, _ := executor.Execute(ctx, toolUse3.Name, toolUse3.Input)
toolResult3 := tools.ResultToToolResult(result3, toolUse3.ID)
fmt.Printf("Write operation (denied): success=%v\n", !toolResult3.IsError)
// 8. List all available tools
availableTools := registry.List()
fmt.Printf("Available tools: %v\n", availableTools)
}
Output: Read operation: success=true Write operation (approved): success=true Write operation (denied): success=false Available tools: [read_file write_file]
Index ¶
- Constants
- func GetBackgroundProcess(shellID string) *os.Process
- func GetToolSchema(toolName string) map[string]interface{}
- func IsCacheable(toolName string) bool
- func ListBackgroundProcesses() []string
- func RegisterBackgroundProcess(shellID string, process *os.Process)
- func UnregisterBackgroundProcess(shellID string)
- type ApprovalFunc
- type AskUserQuestionTool
- type BackgroundProcess
- func (bp *BackgroundProcess) AppendStderr(line string)
- func (bp *BackgroundProcess) AppendStdout(line string)
- func (bp *BackgroundProcess) GetExitCode() int
- func (bp *BackgroundProcess) GetNewOutput() (stdout []string, stderr []string)
- func (bp *BackgroundProcess) IsDone() bool
- func (bp *BackgroundProcess) MarkDone(exitCode int)
- type BackgroundProcessRegistry
- type BashOutputTool
- type BashTool
- type CacheEntry
- type CacheStats
- type EditTool
- type Executor
- func (e *Executor) DisableCache()
- func (e *Executor) EnableCache(capacity int, ttl time.Duration)
- func (e *Executor) Execute(ctx context.Context, toolName string, params map[string]interface{}) (*Result, error)
- func (e *Executor) GetCacheStats() *CacheStats
- func (e *Executor) GetPermissionChecker() *permissions.Checker
- func (e *Executor) SetHookEngine(engine *hooks.Engine)
- func (e *Executor) SetPermissionChecker(checker *permissions.Checker)
- func (e *Executor) SetPermissionHook(hook PermissionHook)
- type GlobTool
- type GrepTool
- type KillShellTool
- type MockTool
- type MuxAgentRunner
- type MuxConfig
- type PermissionHook
- type ReadTool
- type Registry
- type Result
- type ResultCache
- type SearchResult
- type TaskTool
- func (t *TaskTool) Description() string
- func (t *TaskTool) Execute(ctx context.Context, params map[string]interface{}) (*Result, error)
- func (t *TaskTool) ExecuteStreaming(ctx context.Context, params map[string]interface{}) (<-chan *Result, error)
- func (t *TaskTool) Name() string
- func (t *TaskTool) RequiresApproval(_ map[string]interface{}) bool
- func (t *TaskTool) SetMuxRunner(runner MuxAgentRunner)
- type TodoWriteTool
- type Tool
- type ToolResult
- type ToolUse
- type WebFetchTool
- type WebSearchTool
- type WriteTool
Examples ¶
Constants ¶
const ( // DefaultCommandTimeout is the default timeout for command execution DefaultCommandTimeout = 30 * time.Second // MaxCommandTimeout is the maximum allowed timeout (5 minutes) MaxCommandTimeout = 5 * time.Minute // MaxOutputSize is the maximum combined output size (1MB) MaxOutputSize = 1024 * 1024 )
const ( // DefaultTaskTimeout is the default timeout for task execution DefaultTaskTimeout = 5 * time.Minute // MaxTaskTimeout is the maximum allowed timeout (30 minutes) MaxTaskTimeout = 30 * time.Minute // DefaultMaxAgentDepth is the default maximum recursion depth for sub-agents DefaultMaxAgentDepth = 5 )
const ( // DefaultMaxContentSize is the default maximum content size to write (10MB) DefaultMaxContentSize = 10 * 1024 * 1024 // ModeCreate creates a new file, failing if it already exists ModeCreate = "create" // ModeOverwrite overwrites an existing file or creates a new one ModeOverwrite = "overwrite" // ModeAppend appends to an existing file or creates a new one ModeAppend = "append" )
const (
// DefaultMaxFileSize is the default maximum file size to read (1MB)
DefaultMaxFileSize = 1024 * 1024
)
Variables ¶
This section is empty.
Functions ¶
func GetBackgroundProcess ¶
GetBackgroundProcess retrieves a process from the global registry (legacy)
func GetToolSchema ¶ added in v1.7.0
GetToolSchema returns the JSON Schema for a specific tool's input parameters. Exported for use by the mux adapter to implement SchemaProvider.
func IsCacheable ¶ added in v1.6.0
IsCacheable determines if a tool's results should be cached
func ListBackgroundProcesses ¶
func ListBackgroundProcesses() []string
ListBackgroundProcesses returns a list of all registered shell IDs (legacy)
func RegisterBackgroundProcess ¶
RegisterBackgroundProcess adds a process to the global registry (legacy)
func UnregisterBackgroundProcess ¶
func UnregisterBackgroundProcess(shellID string)
UnregisterBackgroundProcess removes a process from the global registry (legacy)
Types ¶
type ApprovalFunc ¶
ApprovalFunc is called when a tool needs user approval Returns true if approved, false if denied
type AskUserQuestionTool ¶
type AskUserQuestionTool struct{}
AskUserQuestionTool prompts users with multiple-choice questions
func (*AskUserQuestionTool) Description ¶
func (t *AskUserQuestionTool) Description() string
Description returns what the tool does
func (*AskUserQuestionTool) Execute ¶
func (t *AskUserQuestionTool) Execute(_ context.Context, params map[string]interface{}) (*Result, error)
Execute runs the tool with the given parameters
func (*AskUserQuestionTool) Name ¶
func (t *AskUserQuestionTool) Name() string
Name returns the tool's identifier
func (*AskUserQuestionTool) RequiresApproval ¶
func (t *AskUserQuestionTool) RequiresApproval(_ map[string]interface{}) bool
RequiresApproval returns whether this tool needs user confirmation
type BackgroundProcess ¶
type BackgroundProcess struct {
ID string // Unique identifier for the process
Command string // The command being executed
StartTime time.Time // When the process started
Stdout []string // Lines of stdout output
Stderr []string // Lines of stderr output
ReadOffset int // Number of lines already read by BashOutput
Done bool // Whether the process has finished
ExitCode int // Exit code (valid only if Done is true)
Process *os.Process // The actual OS process
// contains filtered or unexported fields
}
BackgroundProcess represents a running or completed background bash process
func (*BackgroundProcess) AppendStderr ¶
func (bp *BackgroundProcess) AppendStderr(line string)
AppendStderr adds a line to stderr in a thread-safe manner
func (*BackgroundProcess) AppendStdout ¶
func (bp *BackgroundProcess) AppendStdout(line string)
AppendStdout adds a line to stdout in a thread-safe manner
func (*BackgroundProcess) GetExitCode ¶
func (bp *BackgroundProcess) GetExitCode() int
GetExitCode returns the exit code (only valid if Done is true)
func (*BackgroundProcess) GetNewOutput ¶
func (bp *BackgroundProcess) GetNewOutput() (stdout []string, stderr []string)
GetNewOutput returns output since the last read and updates the read offset
func (*BackgroundProcess) IsDone ¶
func (bp *BackgroundProcess) IsDone() bool
IsDone returns whether the process has finished
func (*BackgroundProcess) MarkDone ¶
func (bp *BackgroundProcess) MarkDone(exitCode int)
MarkDone marks the process as completed with the given exit code
type BackgroundProcessRegistry ¶
type BackgroundProcessRegistry struct {
// contains filtered or unexported fields
}
BackgroundProcessRegistry stores running background processes
func GetBackgroundRegistry ¶
func GetBackgroundRegistry() *BackgroundProcessRegistry
GetBackgroundRegistry returns the global background process registry
func (*BackgroundProcessRegistry) Get ¶
func (r *BackgroundProcessRegistry) Get(id string) (*BackgroundProcess, error)
Get retrieves a background process by ID
func (*BackgroundProcessRegistry) List ¶
func (r *BackgroundProcessRegistry) List() []string
List returns all background process IDs
func (*BackgroundProcessRegistry) Register ¶
func (r *BackgroundProcessRegistry) Register(proc *BackgroundProcess) error
Register adds a background process to the registry
func (*BackgroundProcessRegistry) Remove ¶
func (r *BackgroundProcessRegistry) Remove(id string) error
Remove removes a background process from the registry
type BashOutputTool ¶
type BashOutputTool struct{}
BashOutputTool retrieves output from background bash processes
func NewBashOutputTool ¶
func NewBashOutputTool() *BashOutputTool
NewBashOutputTool creates a new bash output tool
func (*BashOutputTool) Description ¶
func (t *BashOutputTool) Description() string
Description returns the tool description
func (*BashOutputTool) RequiresApproval ¶
func (t *BashOutputTool) RequiresApproval(_ map[string]interface{}) bool
RequiresApproval always returns false - this is a read-only tool
type BashTool ¶
type BashTool struct {
DefaultTimeout time.Duration // Default timeout for commands
MaxOutputSize int // Maximum output size (bytes)
}
BashTool implements shell command execution functionality
Example ¶
// Create a new Bash tool
bashTool := NewBashTool()
// Execute a simple command
result, err := bashTool.Execute(context.Background(), map[string]interface{}{
"command": "echo 'Hello from Bash tool!'",
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Success:", result.Success)
fmt.Println("Exit Code:", result.Metadata["exit_code"])
Output: Success: true Exit Code: 0
Example (RequiresApproval) ¶
bashTool := NewBashTool()
// ALL bash commands require approval for safety
params := map[string]interface{}{
"command": "ls /",
}
requiresApproval := bashTool.RequiresApproval(params)
fmt.Println("Requires approval:", requiresApproval)
Output: Requires approval: true
Example (WithExecutor) ¶
// Create a registry and register the bash tool
registry := NewRegistry()
bashTool := NewBashTool()
_ = registry.Register(bashTool)
// Create an executor with approval function
approvalFunc := func(_ string, params map[string]interface{}) bool {
// In real use, prompt the user for approval
command := params["command"].(string)
fmt.Printf("Approve command '%s'? ", command)
return true // Auto-approve for demo
}
executor := NewExecutor(registry, approvalFunc)
// Execute the tool through the executor
result, err := executor.Execute(context.Background(), "bash", map[string]interface{}{
"command": "echo 'Executed via executor'",
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Success:", result.Success)
Output: Approve command 'echo 'Executed via executor''? Success: true
Example (WithTimeout) ¶
bashTool := NewBashTool()
// Execute command with custom timeout (2 seconds)
result, err := bashTool.Execute(context.Background(), map[string]interface{}{
"command": "sleep 1; echo 'Done sleeping'",
"timeout": float64(2),
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Success:", result.Success)
Output: Success: true
Example (WithWorkingDirectory) ¶
bashTool := NewBashTool()
// Execute command in a specific directory
result, err := bashTool.Execute(context.Background(), map[string]interface{}{
"command": "pwd",
"working_dir": "/tmp",
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Working directory set:", result.Metadata["working_dir"])
Output: Working directory set: /tmp
func NewBashTool ¶
func NewBashTool() *BashTool
NewBashTool creates a new bash tool with default settings
func (*BashTool) Description ¶
Description returns the tool description
func (*BashTool) RequiresApproval ¶
RequiresApproval always returns true for command execution
type CacheEntry ¶ added in v1.6.0
CacheEntry represents a cached tool result
func (*CacheEntry) IsExpired ¶ added in v1.6.0
func (e *CacheEntry) IsExpired() bool
IsExpired checks if the cache entry has expired
type CacheStats ¶ added in v1.6.0
type CacheStats struct {
Hits int64
Misses int64
Evictions int64
Size int
Capacity int
HitRate float64
}
CacheStats contains cache statistics
type EditTool ¶
type EditTool struct{}
EditTool performs exact string replacements in files
func (*EditTool) Description ¶
Description returns the tool's purpose
func (*EditTool) RequiresApproval ¶
RequiresApproval always returns true - editing files is destructive
type Executor ¶
type Executor struct {
// contains filtered or unexported fields
}
Executor runs tools with permission management
func NewExecutor ¶
func NewExecutor(registry *Registry, approvalFunc ApprovalFunc) *Executor
NewExecutor creates a new tool executor
func (*Executor) DisableCache ¶ added in v1.6.0
func (e *Executor) DisableCache()
DisableCache disables result caching
func (*Executor) EnableCache ¶ added in v1.6.0
EnableCache enables result caching with custom capacity and TTL
func (*Executor) Execute ¶
func (e *Executor) Execute(ctx context.Context, toolName string, params map[string]interface{}) (*Result, error)
Execute runs a tool by name with given parameters
func (*Executor) GetCacheStats ¶ added in v1.6.0
func (e *Executor) GetCacheStats() *CacheStats
GetCacheStats returns cache statistics
func (*Executor) GetPermissionChecker ¶
func (e *Executor) GetPermissionChecker() *permissions.Checker
GetPermissionChecker returns the current permission checker (may be nil)
func (*Executor) SetHookEngine ¶
SetHookEngine sets the hook engine for this executor
func (*Executor) SetPermissionChecker ¶
func (e *Executor) SetPermissionChecker(checker *permissions.Checker)
SetPermissionChecker sets the permission checker for this executor
func (*Executor) SetPermissionHook ¶
func (e *Executor) SetPermissionHook(hook PermissionHook)
SetPermissionHook sets a hook that fires before permission checking
type GlobTool ¶
type GlobTool struct{}
GlobTool finds files matching glob patterns
func (*GlobTool) Description ¶
Description returns the tool's purpose
func (*GlobTool) RequiresApproval ¶
RequiresApproval returns false (glob is read-only)
type GrepTool ¶
type GrepTool struct{}
GrepTool searches code using ripgrep patterns
func (*GrepTool) Description ¶
Description returns the tool's purpose
func (*GrepTool) RequiresApproval ¶
RequiresApproval returns false for normal paths (grep is read-only)
type KillShellTool ¶
type KillShellTool struct{}
KillShellTool implements background process termination
func NewKillShellTool ¶
func NewKillShellTool() *KillShellTool
NewKillShellTool creates a new kill shell tool
func (*KillShellTool) Description ¶
func (t *KillShellTool) Description() string
Description returns the tool description
func (*KillShellTool) RequiresApproval ¶
func (t *KillShellTool) RequiresApproval(_ map[string]interface{}) bool
RequiresApproval always returns true (killing processes is destructive)
type MockTool ¶
type MockTool struct {
NameValue string
DescriptionValue string
RequiresApprovalValue bool
ExecuteFunc func(context.Context, map[string]interface{}) (*Result, error)
}
MockTool is a simple tool for testing
func (*MockTool) Description ¶
Description returns the tool description
func (*MockTool) RequiresApproval ¶
RequiresApproval returns whether approval is needed
type MuxAgentRunner ¶ added in v1.10.0
type MuxAgentRunner interface {
// RunAgent executes a subagent with the given configuration and returns the output.
RunAgent(ctx context.Context, agentID, prompt, systemPrompt string, allowedTools []string) (output string, err error)
}
MuxAgentRunner is an interface for running a mux agent. This interface breaks the import cycle between tools and adapter packages.
type MuxConfig ¶ added in v1.10.0
type MuxConfig struct {
AgentRunner MuxAgentRunner // Runner that creates and executes mux agents
}
MuxConfig holds configuration for spawning mux agents
type PermissionHook ¶
type PermissionHook func(toolName string, params map[string]interface{}, checkResult permissions.CheckResult)
PermissionHook is called before permission check, allowing external systems to intercept
type ReadTool ¶
type ReadTool struct {
MaxFileSize int64 // Maximum file size to read (bytes)
}
ReadTool implements file reading functionality
Example ¶
ExampleReadTool demonstrates basic file reading
package main
import (
"context"
"fmt"
"os"
"github.com/2389-research/hex/internal/tools"
)
func main() {
// Create a test file
tmpFile, _ := os.CreateTemp("", "example-*.txt")
defer func() { _ = os.Remove(tmpFile.Name()) }()
_, _ = tmpFile.WriteString("Hello, World!")
_ = tmpFile.Close()
// Create and use the Read tool
tool := tools.NewReadTool()
result, _ := tool.Execute(context.Background(), map[string]interface{}{
"path": tmpFile.Name(),
})
fmt.Println("Success:", result.Success)
fmt.Println("Output:", result.Output)
}
Output: Success: true Output: Hello, World!
Example (RequiresApproval) ¶
ExampleReadTool_requiresApproval demonstrates approval checking
package main
import (
"fmt"
"github.com/2389-research/hex/internal/tools"
)
func main() {
tool := tools.NewReadTool()
// Sensitive path requires approval
sensitive := tool.RequiresApproval(map[string]interface{}{
"path": "/etc/passwd",
})
fmt.Println("Sensitive path:", sensitive)
// Regular path does not require approval
regular := tool.RequiresApproval(map[string]interface{}{
"path": "/tmp/test.txt",
})
fmt.Println("Regular path:", regular)
}
Output: Sensitive path: true Regular path: false
Example (WithExecutor) ¶
ExampleReadTool_withExecutor demonstrates using the Read tool with Executor
package main
import (
"context"
"fmt"
"os"
"github.com/2389-research/hex/internal/tools"
)
func main() {
tmpFile, _ := os.CreateTemp("", "example-*.txt")
defer func() { _ = os.Remove(tmpFile.Name()) }()
_, _ = tmpFile.WriteString("Hello from Executor!")
_ = tmpFile.Close()
// Create registry and register the Read tool
registry := tools.NewRegistry()
_ = registry.Register(tools.NewReadTool())
// Create executor with auto-approval
executor := tools.NewExecutor(registry, func(_ string, _ map[string]interface{}) bool {
return true // Auto-approve for this example
})
// Execute the tool through the executor
result, _ := executor.Execute(context.Background(), "read_file", map[string]interface{}{
"path": tmpFile.Name(),
})
fmt.Println("Success:", result.Success)
fmt.Println("Output:", result.Output)
}
Output: Success: true Output: Hello from Executor!
Example (WithLimit) ¶
ExampleReadTool_withLimit demonstrates reading with a limit
package main
import (
"context"
"fmt"
"os"
"github.com/2389-research/hex/internal/tools"
)
func main() {
tmpFile, _ := os.CreateTemp("", "example-*.txt")
defer func() { _ = os.Remove(tmpFile.Name()) }()
_, _ = tmpFile.WriteString("0123456789")
_ = tmpFile.Close()
tool := tools.NewReadTool()
result, _ := tool.Execute(context.Background(), map[string]interface{}{
"path": tmpFile.Name(),
"limit": float64(5),
})
fmt.Println(result.Output)
}
Output: 01234
Example (WithOffset) ¶
ExampleReadTool_withOffset demonstrates reading with an offset
package main
import (
"context"
"fmt"
"os"
"github.com/2389-research/hex/internal/tools"
)
func main() {
tmpFile, _ := os.CreateTemp("", "example-*.txt")
defer func() { _ = os.Remove(tmpFile.Name()) }()
_, _ = tmpFile.WriteString("0123456789")
_ = tmpFile.Close()
tool := tools.NewReadTool()
result, _ := tool.Execute(context.Background(), map[string]interface{}{
"path": tmpFile.Name(),
"offset": float64(5),
})
fmt.Println(result.Output)
}
Output: 56789
func NewReadTool ¶
func NewReadTool() *ReadTool
NewReadTool creates a new read tool with default settings
func (*ReadTool) Description ¶
Description returns the tool description
func (*ReadTool) RequiresApproval ¶
RequiresApproval returns true if the path is sensitive
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry manages available tools
func (*Registry) GetDefinitions ¶
func (r *Registry) GetDefinitions() []core.ToolDefinition
GetDefinitions returns tool definitions for all registered tools in API format
type Result ¶
type Result struct {
ToolName string // Tool that was executed
Success bool // Did it succeed?
Output string // Standard output/result
Error string // Error message if failed
Metadata map[string]interface{} // Additional metadata (file path, exit code, etc.)
}
Result represents the output of a tool execution
type ResultCache ¶ added in v1.6.0
type ResultCache struct {
// contains filtered or unexported fields
}
ResultCache is an LRU cache for tool results
func NewResultCache ¶ added in v1.6.0
func NewResultCache(capacity int, ttl time.Duration) *ResultCache
NewResultCache creates a new LRU cache with the given capacity and TTL
func (*ResultCache) Clear ¶ added in v1.6.0
func (c *ResultCache) Clear()
Clear removes all entries from the cache
func (*ResultCache) Get ¶ added in v1.6.0
func (c *ResultCache) Get(toolName string, params map[string]interface{}) (*Result, bool)
Get retrieves a cached result if available and not expired
func (*ResultCache) Set ¶ added in v1.6.0
func (c *ResultCache) Set(toolName string, params map[string]interface{}, result *Result)
Set stores a result in the cache
func (*ResultCache) Stats ¶ added in v1.6.0
func (c *ResultCache) Stats() CacheStats
Stats returns cache statistics
type SearchResult ¶
SearchResult represents a single web search result
type TaskTool ¶
type TaskTool struct {
DefaultTimeout time.Duration // Default timeout for tasks
HexBinPath string // Path to hex binary (empty = search PATH)
Executor *subagents.Executor // Legacy subagent executor
UseFramework bool // If true, use new subagent framework instead of direct subprocess
UseMux bool // If true, use mux agents (Phase 2)
MuxConfig *MuxConfig // Configuration for mux agents
}
TaskTool implements sub-agent task delegation functionality
func NewTaskTool ¶
func NewTaskTool() *TaskTool
NewTaskTool creates a new task tool with default settings
func NewTaskToolWithFramework ¶
func NewTaskToolWithFramework() *TaskTool
NewTaskToolWithFramework creates a task tool that uses the subagent framework
func NewTaskToolWithMux ¶ added in v1.10.0
func NewTaskToolWithMux(runner MuxAgentRunner) *TaskTool
NewTaskToolWithMux creates a task tool that uses mux agents (in-process)
func (*TaskTool) Description ¶
Description returns the tool description
func (*TaskTool) ExecuteStreaming ¶
func (t *TaskTool) ExecuteStreaming(ctx context.Context, params map[string]interface{}) (<-chan *Result, error)
ExecuteStreaming launches a sub-agent and streams incremental output updates. Returns a channel that emits Result objects as output becomes available. The channel is closed when execution completes or fails.
func (*TaskTool) RequiresApproval ¶
RequiresApproval always returns true for task execution
func (*TaskTool) SetMuxRunner ¶ added in v1.10.0
func (t *TaskTool) SetMuxRunner(runner MuxAgentRunner)
SetMuxRunner enables mux agent execution with the given runner. This allows setting mux config after construction (useful when tools have circular dependencies).
type TodoWriteTool ¶
type TodoWriteTool struct {
// contains filtered or unexported fields
}
TodoWriteTool implements the todo_write tool for managing todo lists
func (*TodoWriteTool) Description ¶
func (t *TodoWriteTool) Description() string
Description returns a human-readable description
func (*TodoWriteTool) RequiresApproval ¶
func (t *TodoWriteTool) RequiresApproval(_ map[string]interface{}) bool
RequiresApproval returns false (TodoWrite is read-only display)
type Tool ¶
type Tool interface {
// Name returns the unique identifier for this tool (e.g., "read_file", "bash")
Name() string
// Description returns a human-readable description of what this tool does
Description() string
// RequiresApproval returns true if this specific tool invocation needs user approval.
// The decision can be based on the parameters (e.g., writing to /etc requires approval).
// params is guaranteed to be non-nil but may be empty or have unexpected types.
RequiresApproval(params map[string]interface{}) bool
// Execute runs the tool with the given parameters.
// Implementations must:
// - Validate required parameters exist
// - Type assert parameters safely (return error on wrong type)
// - Respect context cancellation
// - Return a Result (not error) for expected failures like "file not found"
// - Return an error only for unexpected/catastrophic failures
// params is guaranteed to be non-nil but may be empty.
Execute(ctx context.Context, params map[string]interface{}) (*Result, error)
}
Tool represents an executable tool that can be invoked by the assistant. Implementations must:
- Validate their own parameters in Execute() and return appropriate errors
- Handle type assertions safely (params may have incorrect types)
- Be safe for concurrent execution from multiple goroutines
func NewAskUserQuestionTool ¶
func NewAskUserQuestionTool() Tool
NewAskUserQuestionTool creates a new AskUserQuestion tool instance
func NewTodoWriteTool ¶
func NewTodoWriteTool() Tool
NewTodoWriteTool creates a new TodoWrite tool instance
func NewTodoWriteToolWithDB ¶
NewTodoWriteToolWithDB creates a new TodoWrite tool with database persistence
func NewWebFetchTool ¶
func NewWebFetchTool() Tool
NewWebFetchTool creates a new WebFetch tool instance
func NewWebSearchTool ¶
func NewWebSearchTool() Tool
NewWebSearchTool creates a new web search tool instance
type ToolResult ¶
type ToolResult struct {
Type string `json:"type"` // Always "tool_result"
ToolUseID string `json:"tool_use_id"` // ID from the ToolUse request
Content string `json:"content"` // Tool output or error message
IsError bool `json:"is_error"` // true if this represents an error
}
ToolResult represents a tool execution result to send back to the Anthropic API. This is sent as a content block in a user message after tool execution completes. See: https://docs.anthropic.com/claude/docs/tool-use#returning-tool-results
func ResultToToolResult ¶
func ResultToToolResult(result *Result, toolUseID string) ToolResult
ResultToToolResult converts an internal Result to a ToolResult for the API
Example ¶
ExampleResultToToolResult demonstrates converting internal results to API format
package main
import (
"fmt"
"github.com/2389-research/hex/internal/tools"
)
func main() {
// Success result
successResult := &tools.Result{
ToolName: "read_file",
Success: true,
Output: "file contents",
}
apiResult1 := tools.ResultToToolResult(successResult, "toolu_123")
fmt.Printf("API result 1: type=%s, error=%v\n", apiResult1.Type, apiResult1.IsError)
// Error result
errorResult := &tools.Result{
ToolName: "write_file",
Success: false,
Error: "permission denied",
}
apiResult2 := tools.ResultToToolResult(errorResult, "toolu_456")
fmt.Printf("API result 2: type=%s, error=%v, content=%s\n",
apiResult2.Type, apiResult2.IsError, apiResult2.Content)
}
Output: API result 1: type=tool_result, error=false API result 2: type=tool_result, error=true, content=Error: permission denied
type ToolUse ¶
ToolUse is an alias for core.ToolUse for convenience Use core.ToolUse directly in new code
type WebFetchTool ¶
type WebFetchTool struct {
// contains filtered or unexported fields
}
WebFetchTool fetches content from a URL and optionally processes it
func (*WebFetchTool) Description ¶
func (t *WebFetchTool) Description() string
Description returns the tool description
func (*WebFetchTool) RequiresApproval ¶
func (t *WebFetchTool) RequiresApproval(_ map[string]interface{}) bool
RequiresApproval always returns true since this makes network requests
type WebSearchTool ¶
type WebSearchTool struct {
// contains filtered or unexported fields
}
WebSearchTool searches the web using DuckDuckGo and returns formatted results
func (*WebSearchTool) Description ¶
func (t *WebSearchTool) Description() string
Description returns a human-readable description of the tool
func (*WebSearchTool) Execute ¶
func (t *WebSearchTool) Execute(ctx context.Context, params map[string]interface{}) (*Result, error)
Execute performs the web search and returns formatted results
func (*WebSearchTool) Name ¶
func (t *WebSearchTool) Name() string
Name returns the tool's identifier
func (*WebSearchTool) RequiresApproval ¶
func (t *WebSearchTool) RequiresApproval(_ map[string]interface{}) bool
RequiresApproval returns true since this tool makes network requests
type WriteTool ¶
type WriteTool struct {
MaxContentSize int64 // Maximum content size to write (bytes)
}
WriteTool implements file writing functionality
func NewWriteTool ¶
func NewWriteTool() *WriteTool
NewWriteTool creates a new write tool with default settings
func (*WriteTool) Description ¶
Description returns the tool description
func (*WriteTool) RequiresApproval ¶
RequiresApproval always returns true for write operations