feat: US-002 - Modify Tool interface to return *ToolResult
- Update all Tool implementations to return *ToolResult instead of (string, error) - ShellTool: returns UserResult for command output, ErrorResult for failures - SpawnTool: returns NewToolResult on success, ErrorResult on failure - WebTool: returns ToolResult with ForUser=content, ForLLM=summary - EditTool: returns SilentResult for silent edits, ErrorResult on failure - FilesystemTool: returns SilentResult/NewToolResult for operations, ErrorResult on failure - Temporarily disable cronTool in main.go (will be re-enabled in US-016) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
143
pkg/tools/result.go
Normal file
143
pkg/tools/result.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package tools
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// ToolResult represents the structured return value from tool execution.
|
||||
// It provides clear semantics for different types of results and supports
|
||||
// async operations, user-facing messages, and error handling.
|
||||
type ToolResult struct {
|
||||
// ForLLM is the content sent to the LLM for context.
|
||||
// Required for all results.
|
||||
ForLLM string `json:"for_llm"`
|
||||
|
||||
// ForUser is the content sent directly to the user.
|
||||
// If empty, no user message is sent.
|
||||
// Silent=true overrides this field.
|
||||
ForUser string `json:"for_user,omitempty"`
|
||||
|
||||
// Silent suppresses sending any message to the user.
|
||||
// When true, ForUser is ignored even if set.
|
||||
Silent bool `json:"silent"`
|
||||
|
||||
// IsError indicates whether the tool execution failed.
|
||||
// When true, the result should be treated as an error.
|
||||
IsError bool `json:"is_error"`
|
||||
|
||||
// Async indicates whether the tool is running asynchronously.
|
||||
// When true, the tool will complete later and notify via callback.
|
||||
Async bool `json:"async"`
|
||||
|
||||
// Err is the underlying error (not JSON serialized).
|
||||
// Used for internal error handling and logging.
|
||||
Err error `json:"-"`
|
||||
}
|
||||
|
||||
// NewToolResult creates a basic ToolResult with content for the LLM.
|
||||
// Use this when you need a simple result with default behavior.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// result := NewToolResult("File updated successfully")
|
||||
func NewToolResult(forLLM string) *ToolResult {
|
||||
return &ToolResult{
|
||||
ForLLM: forLLM,
|
||||
}
|
||||
}
|
||||
|
||||
// SilentResult creates a ToolResult that is silent (no user message).
|
||||
// The content is only sent to the LLM for context.
|
||||
//
|
||||
// Use this for operations that should not spam the user, such as:
|
||||
// - File reads/writes
|
||||
// - Status updates
|
||||
// - Background operations
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// result := SilentResult("Config file saved")
|
||||
func SilentResult(forLLM string) *ToolResult {
|
||||
return &ToolResult{
|
||||
ForLLM: forLLM,
|
||||
Silent: true,
|
||||
IsError: false,
|
||||
Async: false,
|
||||
}
|
||||
}
|
||||
|
||||
// AsyncResult creates a ToolResult for async operations.
|
||||
// The task will run in the background and complete later.
|
||||
//
|
||||
// Use this for long-running operations like:
|
||||
// - Subagent spawns
|
||||
// - Background processing
|
||||
// - External API calls with callbacks
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// result := AsyncResult("Subagent spawned, will report back")
|
||||
func AsyncResult(forLLM string) *ToolResult {
|
||||
return &ToolResult{
|
||||
ForLLM: forLLM,
|
||||
Silent: false,
|
||||
IsError: false,
|
||||
Async: true,
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorResult creates a ToolResult representing an error.
|
||||
// Sets IsError=true and includes the error message.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// result := ErrorResult("Failed to connect to database: connection refused")
|
||||
func ErrorResult(message string) *ToolResult {
|
||||
return &ToolResult{
|
||||
ForLLM: message,
|
||||
Silent: false,
|
||||
IsError: true,
|
||||
Async: false,
|
||||
}
|
||||
}
|
||||
|
||||
// UserResult creates a ToolResult with content for both LLM and user.
|
||||
// Both ForLLM and ForUser are set to the same content.
|
||||
//
|
||||
// Use this when the user needs to see the result directly:
|
||||
// - Command execution output
|
||||
// - Fetched web content
|
||||
// - Query results
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// result := UserResult("Total files found: 42")
|
||||
func UserResult(content string) *ToolResult {
|
||||
return &ToolResult{
|
||||
ForLLM: content,
|
||||
ForUser: content,
|
||||
Silent: false,
|
||||
IsError: false,
|
||||
Async: false,
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalJSON implements custom JSON serialization.
|
||||
// The Err field is excluded from JSON output via the json:"-" tag.
|
||||
func (tr *ToolResult) MarshalJSON() ([]byte, error) {
|
||||
type Alias ToolResult
|
||||
return json.Marshal(&struct {
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(tr),
|
||||
})
|
||||
}
|
||||
|
||||
// WithError sets the Err field and returns the result for chaining.
|
||||
// This preserves the error for logging while keeping it out of JSON.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// result := ErrorResult("Operation failed").WithError(err)
|
||||
func (tr *ToolResult) WithError(err error) *ToolResult {
|
||||
tr.Err = err
|
||||
return tr
|
||||
}
|
||||
Reference in New Issue
Block a user