mirror of
https://github.com/charmbracelet/crush.git
synced 2026-05-30 18:47:33 +00:00
For example, the GitHub MCP server can fetch diffs. This makes those diffs render as such, rather than just showing their raw output.
74 lines
2.2 KiB
Go
74 lines
2.2 KiB
Go
package chat
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/crush/internal/message"
|
|
"github.com/charmbracelet/crush/internal/ui/styles"
|
|
)
|
|
|
|
// GenericToolMessageItem is a message item that represents an unknown tool call.
|
|
type GenericToolMessageItem struct {
|
|
*baseToolMessageItem
|
|
}
|
|
|
|
var _ ToolMessageItem = (*GenericToolMessageItem)(nil)
|
|
|
|
// NewGenericToolMessageItem creates a new [GenericToolMessageItem].
|
|
func NewGenericToolMessageItem(
|
|
sty *styles.Styles,
|
|
toolCall message.ToolCall,
|
|
result *message.ToolResult,
|
|
canceled bool,
|
|
) ToolMessageItem {
|
|
return newBaseToolMessageItem(sty, toolCall, result, &GenericToolRenderContext{}, canceled)
|
|
}
|
|
|
|
// GenericToolRenderContext renders unknown/generic tool messages.
|
|
type GenericToolRenderContext struct{}
|
|
|
|
// RenderTool implements the [ToolRenderer] interface.
|
|
func (g *GenericToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *ToolRenderOpts) string {
|
|
cappedWidth := cappedMessageWidth(width)
|
|
name := humanizedToolName(opts.ToolCall.Name)
|
|
|
|
if opts.IsPending() {
|
|
return pendingTool(sty, name, opts.Anim, opts.Compact)
|
|
}
|
|
|
|
var params map[string]any
|
|
if err := json.Unmarshal([]byte(opts.ToolCall.Input), ¶ms); err != nil {
|
|
return toolErrorContent(sty, &message.ToolResult{Content: "Invalid parameters"}, cappedWidth)
|
|
}
|
|
|
|
var toolParams []string
|
|
if len(params) > 0 {
|
|
parsed, _ := json.Marshal(params)
|
|
toolParams = append(toolParams, string(parsed))
|
|
}
|
|
|
|
header := toolHeader(sty, opts.Status, name, cappedWidth, opts.Compact, toolParams...)
|
|
if opts.Compact {
|
|
return header
|
|
}
|
|
|
|
if earlyState, ok := toolEarlyStateContent(sty, opts, cappedWidth); ok {
|
|
return joinToolParts(header, earlyState)
|
|
}
|
|
|
|
if !opts.HasResult() || opts.Result.Content == "" {
|
|
return header
|
|
}
|
|
|
|
bodyWidth := cappedWidth - toolBodyLeftPaddingTotal
|
|
|
|
if opts.Result.Data != "" && strings.HasPrefix(opts.Result.MIMEType, "image/") {
|
|
body := sty.Tool.Body.Render(toolOutputImageContent(sty, opts.Result.Data, opts.Result.MIMEType))
|
|
return joinToolParts(header, body)
|
|
}
|
|
|
|
body := renderToolResultTextContent(sty, opts.Result.Content, toolResultContentWidths{Body: bodyWidth, Diff: cappedWidth}, opts.ExpandedContent)
|
|
return joinToolParts(header, body)
|
|
}
|