diagnostics.go

 1package chat
 2
 3import (
 4	"encoding/json"
 5
 6	"github.com/charmbracelet/crush/internal/agent/tools"
 7	"github.com/charmbracelet/crush/internal/fsext"
 8	"github.com/charmbracelet/crush/internal/message"
 9	"github.com/charmbracelet/crush/internal/ui/styles"
10)
11
12// -----------------------------------------------------------------------------
13// Diagnostics Tool
14// -----------------------------------------------------------------------------
15
16// DiagnosticsToolMessageItem is a message item that represents a diagnostics tool call.
17type DiagnosticsToolMessageItem struct {
18	*baseToolMessageItem
19}
20
21var _ ToolMessageItem = (*DiagnosticsToolMessageItem)(nil)
22
23// NewDiagnosticsToolMessageItem creates a new [DiagnosticsToolMessageItem].
24func NewDiagnosticsToolMessageItem(
25	sty *styles.Styles,
26	toolCall message.ToolCall,
27	result *message.ToolResult,
28	canceled bool,
29) ToolMessageItem {
30	return newBaseToolMessageItem(sty, toolCall, result, &DiagnosticsToolRenderContext{}, canceled)
31}
32
33// DiagnosticsToolRenderContext renders diagnostics tool messages.
34type DiagnosticsToolRenderContext struct{}
35
36// RenderTool implements the [ToolRenderer] interface.
37func (d *DiagnosticsToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *ToolRenderOpts) string {
38	cappedWidth := cappedMessageWidth(width)
39	if opts.IsPending() {
40		return pendingTool(sty, "Diagnostics", opts.Anim)
41	}
42
43	var params tools.DiagnosticsParams
44	_ = json.Unmarshal([]byte(opts.ToolCall.Input), &params)
45
46	// Show "project" if no file path, otherwise show the file path.
47	mainParam := "project"
48	if params.FilePath != "" {
49		mainParam = fsext.PrettyPath(params.FilePath)
50	}
51
52	header := toolHeader(sty, opts.Status, "Diagnostics", cappedWidth, opts.Compact, mainParam)
53	if opts.Compact {
54		return header
55	}
56
57	if earlyState, ok := toolEarlyStateContent(sty, opts, cappedWidth); ok {
58		return joinToolParts(header, earlyState)
59	}
60
61	if opts.HasEmptyResult() {
62		return header
63	}
64
65	bodyWidth := cappedWidth - toolBodyLeftPaddingTotal
66	body := sty.Tool.Body.Render(toolOutputPlainContent(sty, opts.Result.Content, bodyWidth, opts.ExpandedContent))
67	return joinToolParts(header, body)
68}