on main help sign in
feat(ui): indicate when skills are loaded
c1d294dChristian Rocha
internal/agent/tools/view.go+27−6
@@ -17,6 +17,7 @@ import (
17 "github.com/charmbracelet/crush/internal/filetracker"
17 "github.com/charmbracelet/crush/internal/filetracker"
18 "github.com/charmbracelet/crush/internal/lsp"
18 "github.com/charmbracelet/crush/internal/lsp"
19 "github.com/charmbracelet/crush/internal/permission"
19 "github.com/charmbracelet/crush/internal/permission"
20+ "github.com/charmbracelet/crush/internal/skills"
20)
21)
21
22
22//go:embed view.md
23//go:embed view.md
@@ -34,9 +35,19 @@ type ViewPermissionsParams struct {
34 Limit int `json:"limit"`
35 Limit int `json:"limit"`
35}
36}
36
37
38+type ViewResourceType string
39+
40+const (
41+ ViewResourceUnset ViewResourceType = ""
42+ ViewResourceSkill ViewResourceType = "skill"
43+)
44+
37type ViewResponseMetadata struct {
45type ViewResponseMetadata struct {
38− FilePath string `json:"file_path"`
46+ FilePath string `json:"file_path"`
39− Content string `json:"content"`
47+ Content string `json:"content"`
48+ ResourceType ViewResourceType `json:"resource_type,omitempty"`
49+ ResourceName string `json:"resource_name,omitempty"`
50+ ResourceDescription string `json:"resource_description,omitempty"`
40}
51}
41
52
42const (
53const (
@@ -196,12 +207,22 @@ func NewViewTool(
196 output += "\n</file>\n"
207 output += "\n</file>\n"
197 output += getDiagnostics(filePath, lspManager)
208 output += getDiagnostics(filePath, lspManager)
198 filetracker.RecordRead(ctx, sessionID, filePath)
209 filetracker.RecordRead(ctx, sessionID, filePath)
210+
211+ meta := ViewResponseMetadata{
212+ FilePath: filePath,
213+ Content: content,
214+ }
215+ if isSkillFile {
216+ if skill, err := skills.Parse(filePath); err == nil {
217+ meta.ResourceType = ViewResourceSkill
218+ meta.ResourceName = skill.Name
219+ meta.ResourceDescription = skill.Description
220+ }
221+ }
222+
199 return fantasy.WithResponseMetadata(
223 return fantasy.WithResponseMetadata(
200 fantasy.NewTextResponse(output),
224 fantasy.NewTextResponse(output),
201− ViewResponseMetadata{
225+ meta,
202− FilePath: filePath,
203− Content: content,
204− },
205 ), nil
226 ), nil
206 })
227 })
207}
228}
internal/ui/chat/file.go+6
@@ -82,6 +82,12 @@ func (v *ViewToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *
82 content = meta.Content
82 content = meta.Content
83 }
83 }
84
84
85+ // Handle skill content.
86+ if meta.ResourceType == tools.ViewResourceSkill {
87+ body := toolOutputSkillContent(sty, meta.ResourceName, meta.ResourceDescription)
88+ return joinToolParts(header, body)
89+ }
90+
85 if content == "" {
91 if content == "" {
86 return header
92 return header
87 }
93 }
internal/ui/chat/tools.go+15−4
@@ -625,10 +625,21 @@ func toolOutputImageContent(sty *styles.Styles, data, mediaType string) string {
625
625
626 return sty.Tool.Body.Render(fmt.Sprintf(
626 return sty.Tool.Body.Render(fmt.Sprintf(
627 "%s %s %s %s",
627 "%s %s %s %s",
628− sty.Tool.ResourceLoadedText.String(),
628+ sty.Tool.ResourceLoadedText.Render("Loaded Image"),
629− sty.Tool.ResourceLoadedIndicator.String(),
629+ sty.Tool.ResourceLoadedIndicator.Render(styles.ArrowRightIcon),
630− sty.Base.Render(mediaType),
630+ sty.Tool.MediaType.Render(mediaType),
631− sty.Subtle.Render(sizeStr),
631+ sty.Tool.ResourceSize.Render(sizeStr),
632+ ))
633+}
634+
635+// toolOutputSkillContent renders a skill loaded indicator.
636+func toolOutputSkillContent(sty *styles.Styles, name, description string) string {
637+ return sty.Tool.Body.Render(fmt.Sprintf(
638+ "%s %s %s %s",
639+ sty.Tool.ResourceLoadedText.Render("Loaded Skill"),
640+ sty.Tool.ResourceLoadedIndicator.Render(styles.ArrowRightIcon),
641+ sty.Tool.ResourceName.Render(name),
642+ sty.Tool.ResourceSize.Render(description),
632 ))
643 ))
633}
644}
634
645
internal/ui/styles/styles.go+4−2
@@ -325,6 +325,7 @@ type Styles struct {
325 // Images and external resources
325 // Images and external resources
326 ResourceLoadedText lipgloss.Style
326 ResourceLoadedText lipgloss.Style
327 ResourceLoadedIndicator lipgloss.Style
327 ResourceLoadedIndicator lipgloss.Style
328+ ResourceName lipgloss.Style
328 ResourceSize lipgloss.Style
329 ResourceSize lipgloss.Style
329 MediaType lipgloss.Style
330 MediaType lipgloss.Style
330 }
331 }
@@ -1175,8 +1176,9 @@ func DefaultStyles() Styles {
1175 s.Tool.MCPArrow = base.Foreground(blue).SetString(ArrowRightIcon)
1176 s.Tool.MCPArrow = base.Foreground(blue).SetString(ArrowRightIcon)
1176
1177
1177 // Loading indicators for images, skills
1178 // Loading indicators for images, skills
1178− s.Tool.ResourceLoadedText = base.Foreground(green).SetString("Loaded")
1179+ s.Tool.ResourceLoadedText = base.Foreground(green)
1179− s.Tool.ResourceLoadedIndicator = base.Foreground(greenDark).SetString(ArrowRightIcon)
1180+ s.Tool.ResourceLoadedIndicator = base.Foreground(greenDark)
1181+ s.Tool.ResourceName = base
1180 s.Tool.MediaType = base
1182 s.Tool.MediaType = base
1181 s.Tool.ResourceSize = base.Foreground(fgMuted)
1183 s.Tool.ResourceSize = base.Foreground(fgMuted)
1182
1184