| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- package chat
- import (
- "encoding/json"
- "github.com/charmbracelet/crush/internal/agent/tools"
- "github.com/charmbracelet/crush/internal/message"
- "github.com/charmbracelet/crush/internal/ui/styles"
- )
- // -----------------------------------------------------------------------------
- // Fetch Tool
- // -----------------------------------------------------------------------------
- // FetchToolMessageItem is a message item that represents a fetch tool call.
- type FetchToolMessageItem struct {
- *baseToolMessageItem
- }
- var _ ToolMessageItem = (*FetchToolMessageItem)(nil)
- // NewFetchToolMessageItem creates a new [FetchToolMessageItem].
- func NewFetchToolMessageItem(
- sty *styles.Styles,
- toolCall message.ToolCall,
- result *message.ToolResult,
- canceled bool,
- ) ToolMessageItem {
- return newBaseToolMessageItem(sty, toolCall, result, &FetchToolRenderContext{}, canceled)
- }
- // FetchToolRenderContext renders fetch tool messages.
- type FetchToolRenderContext struct{}
- // RenderTool implements the [ToolRenderer] interface.
- func (f *FetchToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *ToolRenderOpts) string {
- cappedWidth := cappedMessageWidth(width)
- if opts.IsPending() {
- return pendingTool(sty, "Fetch", opts.Anim, opts.Compact)
- }
- var params tools.FetchParams
- if err := json.Unmarshal([]byte(opts.ToolCall.Input), ¶ms); err != nil {
- return toolErrorContent(sty, &message.ToolResult{Content: "Invalid parameters"}, cappedWidth)
- }
- toolParams := []string{params.URL}
- if params.Format != "" {
- toolParams = append(toolParams, "format", params.Format)
- }
- if params.Timeout != 0 {
- toolParams = append(toolParams, "timeout", formatTimeout(params.Timeout))
- }
- header := toolHeader(sty, opts.Status, "Fetch", cappedWidth, opts.Compact, toolParams...)
- if opts.Compact {
- return header
- }
- if earlyState, ok := toolEarlyStateContent(sty, opts, cappedWidth); ok {
- return joinToolParts(header, earlyState)
- }
- if opts.HasEmptyResult() {
- return header
- }
- // Determine file extension for syntax highlighting based on format.
- file := getFileExtensionForFormat(params.Format)
- body := toolOutputCodeContent(sty, file, opts.Result.Content, 0, cappedWidth, opts.ExpandedContent)
- return joinToolParts(header, body)
- }
- // getFileExtensionForFormat returns a filename with appropriate extension for syntax highlighting.
- func getFileExtensionForFormat(format string) string {
- switch format {
- case "text":
- return "fetch.txt"
- case "html":
- return "fetch.html"
- default:
- return "fetch.md"
- }
- }
- // -----------------------------------------------------------------------------
- // WebFetch Tool
- // -----------------------------------------------------------------------------
- // WebFetchToolMessageItem is a message item that represents a web_fetch tool call.
- type WebFetchToolMessageItem struct {
- *baseToolMessageItem
- }
- var _ ToolMessageItem = (*WebFetchToolMessageItem)(nil)
- // NewWebFetchToolMessageItem creates a new [WebFetchToolMessageItem].
- func NewWebFetchToolMessageItem(
- sty *styles.Styles,
- toolCall message.ToolCall,
- result *message.ToolResult,
- canceled bool,
- ) ToolMessageItem {
- return newBaseToolMessageItem(sty, toolCall, result, &WebFetchToolRenderContext{}, canceled)
- }
- // WebFetchToolRenderContext renders web_fetch tool messages.
- type WebFetchToolRenderContext struct{}
- // RenderTool implements the [ToolRenderer] interface.
- func (w *WebFetchToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *ToolRenderOpts) string {
- cappedWidth := cappedMessageWidth(width)
- if opts.IsPending() {
- return pendingTool(sty, "Fetch", opts.Anim, opts.Compact)
- }
- var params tools.WebFetchParams
- if err := json.Unmarshal([]byte(opts.ToolCall.Input), ¶ms); err != nil {
- return toolErrorContent(sty, &message.ToolResult{Content: "Invalid parameters"}, cappedWidth)
- }
- toolParams := []string{params.URL}
- header := toolHeader(sty, opts.Status, "Fetch", cappedWidth, opts.Compact, toolParams...)
- if opts.Compact {
- return header
- }
- if earlyState, ok := toolEarlyStateContent(sty, opts, cappedWidth); ok {
- return joinToolParts(header, earlyState)
- }
- if opts.HasEmptyResult() {
- return header
- }
- body := toolOutputMarkdownContent(sty, opts.Result.Content, cappedWidth, opts.ExpandedContent)
- return joinToolParts(header, body)
- }
- // -----------------------------------------------------------------------------
- // WebSearch Tool
- // -----------------------------------------------------------------------------
- // WebSearchToolMessageItem is a message item that represents a web_search tool call.
- type WebSearchToolMessageItem struct {
- *baseToolMessageItem
- }
- var _ ToolMessageItem = (*WebSearchToolMessageItem)(nil)
- // NewWebSearchToolMessageItem creates a new [WebSearchToolMessageItem].
- func NewWebSearchToolMessageItem(
- sty *styles.Styles,
- toolCall message.ToolCall,
- result *message.ToolResult,
- canceled bool,
- ) ToolMessageItem {
- return newBaseToolMessageItem(sty, toolCall, result, &WebSearchToolRenderContext{}, canceled)
- }
- // WebSearchToolRenderContext renders web_search tool messages.
- type WebSearchToolRenderContext struct{}
- // RenderTool implements the [ToolRenderer] interface.
- func (w *WebSearchToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *ToolRenderOpts) string {
- cappedWidth := cappedMessageWidth(width)
- if opts.IsPending() {
- return pendingTool(sty, "Search", opts.Anim, opts.Compact)
- }
- var params tools.WebSearchParams
- if err := json.Unmarshal([]byte(opts.ToolCall.Input), ¶ms); err != nil {
- return toolErrorContent(sty, &message.ToolResult{Content: "Invalid parameters"}, cappedWidth)
- }
- toolParams := []string{params.Query}
- header := toolHeader(sty, opts.Status, "Search", cappedWidth, opts.Compact, toolParams...)
- if opts.Compact {
- return header
- }
- if earlyState, ok := toolEarlyStateContent(sty, opts, cappedWidth); ok {
- return joinToolParts(header, earlyState)
- }
- if opts.HasEmptyResult() {
- return header
- }
- body := toolOutputMarkdownContent(sty, opts.Result.Content, cappedWidth, opts.ExpandedContent)
- return joinToolParts(header, body)
- }
|