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 }