llm: make Tool.Run return ToolOut

This is preliminary work towards
allowing tools to add additional information.
No functional changes (at least, that's the intent).
diff --git a/claudetool/codereview/codereview_test.go b/claudetool/codereview/codereview_test.go
index f9d240e..4bba851 100644
--- a/claudetool/codereview/codereview_test.go
+++ b/claudetool/codereview/codereview_test.go
@@ -234,10 +234,11 @@
 // runDifferentialTest runs the code review tool on the repository and returns the result.
 func runDifferentialTest(reviewer *CodeReviewer) (string, error) {
 	ctx := context.Background()
-	result, err := reviewer.Run(ctx, nil)
-	if err != nil {
-		return "", fmt.Errorf("error running code review: %w", err)
+	toolOut := reviewer.Run(ctx, nil)
+	if toolOut.Error != nil {
+		return "", fmt.Errorf("error running code review: %w", toolOut.Error)
 	}
+	result := toolOut.LLMContent
 
 	// Normalize paths in the result
 	resultStr := ""
diff --git a/claudetool/codereview/differential.go b/claudetool/codereview/differential.go
index 764f000..6c29d06 100644
--- a/claudetool/codereview/differential.go
+++ b/claudetool/codereview/differential.go
@@ -48,14 +48,14 @@
 	return spec
 }
 
-func (r *CodeReviewer) Run(ctx context.Context, m json.RawMessage) ([]llm.Content, error) {
+func (r *CodeReviewer) Run(ctx context.Context, m json.RawMessage) llm.ToolOut {
 	// Parse input to get timeout
 	var input struct {
 		Timeout string `json:"timeout"`
 	}
 	if len(m) > 0 {
 		if err := json.Unmarshal(m, &input); err != nil {
-			return nil, fmt.Errorf("failed to parse input: %w", err)
+			return llm.ErrorfToolOut("failed to parse input: %w", err)
 		}
 	}
 	if input.Timeout == "" {
@@ -65,7 +65,7 @@
 	// Parse timeout duration
 	timeout, err := time.ParseDuration(input.Timeout)
 	if err != nil {
-		return nil, fmt.Errorf("invalid timeout duration %q: %w", input.Timeout, err)
+		return llm.ErrorfToolOut("invalid timeout duration %q: %w", input.Timeout, err)
 	}
 
 	// Create timeout context
@@ -76,22 +76,22 @@
 	// webui/src/web-components/sketch-tool-card.ts (SketchToolCardCodeReview.getStatusIcon)
 	if err := r.RequireNormalGitState(timeoutCtx); err != nil {
 		slog.DebugContext(ctx, "CodeReviewer.Run: failed to check for normal git state", "err", err)
-		return nil, err
+		return llm.ErrorToolOut(err)
 	}
 	if err := r.RequireNoUncommittedChanges(timeoutCtx); err != nil {
 		slog.DebugContext(ctx, "CodeReviewer.Run: failed to check for uncommitted changes", "err", err)
-		return nil, err
+		return llm.ErrorToolOut(err)
 	}
 
 	// Check that the current commit is not the initial commit
 	currentCommit, err := r.CurrentCommit(timeoutCtx)
 	if err != nil {
 		slog.DebugContext(ctx, "CodeReviewer.Run: failed to get current commit", "err", err)
-		return nil, err
+		return llm.ErrorToolOut(err)
 	}
 	if r.IsInitialCommit(currentCommit) {
 		slog.DebugContext(ctx, "CodeReviewer.Run: current commit is initial commit, nothing to review")
-		return nil, fmt.Errorf("no new commits have been added, nothing to review")
+		return llm.ErrorToolOut(fmt.Errorf("no new commits have been added, nothing to review"))
 	}
 
 	// No matter what failures happen from here out, we will declare this to have been reviewed.
@@ -101,7 +101,7 @@
 	changedFiles, err := r.changedFiles(timeoutCtx, r.sketchBaseRef, currentCommit)
 	if err != nil {
 		slog.DebugContext(ctx, "CodeReviewer.Run: failed to get changed files", "err", err)
-		return nil, err
+		return llm.ErrorToolOut(err)
 	}
 
 	// Prepare to analyze before/after for the impacted files.
@@ -113,7 +113,7 @@
 	if err != nil {
 		// TODO: log and skip to stuff that doesn't require packages
 		slog.DebugContext(ctx, "CodeReviewer.Run: failed to get packages for files", "err", err)
-		return nil, err
+		return llm.ErrorToolOut(err)
 	}
 	allPkgList := slices.Collect(maps.Keys(allPkgs))
 
@@ -152,7 +152,7 @@
 	testMsg, err := r.checkTests(timeoutCtx, allPkgList)
 	if err != nil {
 		slog.DebugContext(ctx, "CodeReviewer.Run: failed to check tests", "err", err)
-		return nil, err
+		return llm.ErrorToolOut(err)
 	}
 	if testMsg != "" {
 		errorMessages = append(errorMessages, testMsg)
@@ -161,7 +161,7 @@
 	goplsMsg, err := r.checkGopls(timeoutCtx, changedFiles) // includes vet checks
 	if err != nil {
 		slog.DebugContext(ctx, "CodeReviewer.Run: failed to check gopls", "err", err)
-		return nil, err
+		return llm.ErrorToolOut(err)
 	}
 	if goplsMsg != "" {
 		errorMessages = append(errorMessages, goplsMsg)
@@ -183,7 +183,7 @@
 	if buf.Len() == 0 {
 		buf.WriteString("OK")
 	}
-	return llm.TextContent(buf.String()), nil
+	return llm.ToolOut{LLMContent: llm.TextContent(buf.String())}
 }
 
 func (r *CodeReviewer) initializeInitialCommitWorktree(ctx context.Context) error {