on main help sign in
feat(ui): allow expanding toolcall names
db8add7Kieran Klukas
internal/ui/chat/agent.go+2−2
@@ -136,7 +136,7 @@ func (r *AgentToolRenderContext) RenderTool(sty *styles.Styles, width int, opts
136 prompt := params.Prompt
136 prompt := params.Prompt
137 prompt = strings.ReplaceAll(prompt, "\n", " ")
137 prompt = strings.ReplaceAll(prompt, "\n", " ")
138
138
139− header := toolHeader(sty, opts.Status, "Agent", cappedWidth, opts.Compact)
139+ header := toolHeader(sty, opts.Status, "Agent", cappedWidth, opts)
140 if opts.Compact {
140 if opts.Compact {
141 return header
141 return header
142 }
142 }
@@ -303,7 +303,7 @@ func (r *AgenticFetchToolRenderContext) RenderTool(sty *styles.Styles, width int
303 toolParams = append(toolParams, params.URL)
303 toolParams = append(toolParams, params.URL)
304 }
304 }
305
305
306− header := toolHeader(sty, opts.Status, "Agentic Fetch", cappedWidth, opts.Compact, toolParams...)
306+ header := toolHeader(sty, opts.Status, "Agentic Fetch", cappedWidth, opts, toolParams...)
307 if opts.Compact {
307 if opts.Compact {
308 return header
308 return header
309 }
309 }
internal/ui/chat/bash.go+1−1
@@ -69,7 +69,7 @@ func (b *BashToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *
69 toolParams = append(toolParams, "background", "true")
69 toolParams = append(toolParams, "background", "true")
70 }
70 }
71
71
72− header := toolHeader(sty, opts.Status, "Bash", cappedWidth, opts.Compact, toolParams...)
72+ header := toolHeader(sty, opts.Status, "Bash", cappedWidth, opts, toolParams...)
73 if opts.Compact {
73 if opts.Compact {
74 return header
74 return header
75 }
75 }
internal/ui/chat/diagnostics.go+1−1
@@ -49,7 +49,7 @@ func (d *DiagnosticsToolRenderContext) RenderTool(sty *styles.Styles, width int,
49 mainParam = fsext.PrettyPath(params.FilePath)
49 mainParam = fsext.PrettyPath(params.FilePath)
50 }
50 }
51
51
52− header := toolHeader(sty, opts.Status, "Diagnostics", cappedWidth, opts.Compact, mainParam)
52+ header := toolHeader(sty, opts.Status, "Diagnostics", cappedWidth, opts, mainParam)
53 if opts.Compact {
53 if opts.Compact {
54 return header
54 return header
55 }
55 }
internal/ui/chat/docker_mcp.go+2−2
@@ -220,7 +220,7 @@ func (d *DockerMCPToolRenderContext) makeHeader(sty *styles.Styles, tool string,
220 icon = sty.Tool.IconPending.Render()
220 icon = sty.Tool.IconPending.Render()
221 }
221 }
222 prefix := fmt.Sprintf("%s %s ", icon, d.formatToolName(sty, tool))
222 prefix := fmt.Sprintf("%s %s ", icon, d.formatToolName(sty, tool))
223− return prefix + toolParamList(sty, params, width-lipgloss.Width(prefix))
223+ return prefix + toolParamList(sty, params, width-lipgloss.Width(prefix), opts)
224}
224}
225
225
226func (d *DockerMCPToolRenderContext) formatToolName(sty *styles.Styles, tool string) string {
226func (d *DockerMCPToolRenderContext) formatToolName(sty *styles.Styles, tool string) string {
@@ -274,7 +274,7 @@ func (d *DockerMCPToolRenderContext) makeCompactHeader(sty *styles.Styles, tool
274 }
274 }
275
275
276 name := fmt.Sprintf("Docker MCP: %s", action)
276 name := fmt.Sprintf("Docker MCP: %s", action)
277− return toolHeader(sty, ToolStatusSuccess, name, width, true, params...)
277+ return toolHeader(sty, ToolStatusSuccess, name, width, &ToolRenderOpts{Compact: true}, params...)
278}
278}
279
279
280// IsDockerMCPTool returns true if the tool name is a Docker MCP tool.
280// IsDockerMCPTool returns true if the tool name is a Docker MCP tool.
internal/ui/chat/fetch.go+3−3
@@ -52,7 +52,7 @@ func (f *FetchToolRenderContext) RenderTool(sty *styles.Styles, width int, opts
52 toolParams = append(toolParams, "timeout", formatTimeout(params.Timeout))
52 toolParams = append(toolParams, "timeout", formatTimeout(params.Timeout))
53 }
53 }
54
54
55− header := toolHeader(sty, opts.Status, "Fetch", cappedWidth, opts.Compact, toolParams...)
55+ header := toolHeader(sty, opts.Status, "Fetch", cappedWidth, opts, toolParams...)
56 if opts.Compact {
56 if opts.Compact {
57 return header
57 return header
58 }
58 }
@@ -120,7 +120,7 @@ func (w *WebFetchToolRenderContext) RenderTool(sty *styles.Styles, width int, op
120 }
120 }
121
121
122 toolParams := []string{params.URL}
122 toolParams := []string{params.URL}
123− header := toolHeader(sty, opts.Status, "Fetch", cappedWidth, opts.Compact, toolParams...)
123+ header := toolHeader(sty, opts.Status, "Fetch", cappedWidth, opts, toolParams...)
124 if opts.Compact {
124 if opts.Compact {
125 return header
125 return header
126 }
126 }
@@ -174,7 +174,7 @@ func (w *WebSearchToolRenderContext) RenderTool(sty *styles.Styles, width int, o
174 }
174 }
175
175
176 toolParams := []string{params.Query}
176 toolParams := []string{params.Query}
177− header := toolHeader(sty, opts.Status, "Search", cappedWidth, opts.Compact, toolParams...)
177+ header := toolHeader(sty, opts.Status, "Search", cappedWidth, opts, toolParams...)
178 if opts.Compact {
178 if opts.Compact {
179 return header
179 return header
180 }
180 }
internal/ui/chat/file.go+5−5
@@ -56,7 +56,7 @@ func (v *ViewToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *
56 toolParams = append(toolParams, "offset", fmt.Sprintf("%d", params.Offset))
56 toolParams = append(toolParams, "offset", fmt.Sprintf("%d", params.Offset))
57 }
57 }
58
58
59− header := toolHeader(sty, opts.Status, "View", cappedWidth, opts.Compact, toolParams...)
59+ header := toolHeader(sty, opts.Status, "View", cappedWidth, opts, toolParams...)
60 if opts.Compact {
60 if opts.Compact {
61 return header
61 return header
62 }
62 }
@@ -134,7 +134,7 @@ func (w *WriteToolRenderContext) RenderTool(sty *styles.Styles, width int, opts
134 }
134 }
135
135
136 file := fsext.PrettyPath(params.FilePath)
136 file := fsext.PrettyPath(params.FilePath)
137− header := toolHeader(sty, opts.Status, "Write", cappedWidth, opts.Compact, file)
137+ header := toolHeader(sty, opts.Status, "Write", cappedWidth, opts, file)
138 if opts.Compact {
138 if opts.Compact {
139 return header
139 return header
140 }
140 }
@@ -203,7 +203,7 @@ func (e *EditToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *
203 }
203 }
204
204
205 file := fsext.PrettyPath(params.FilePath)
205 file := fsext.PrettyPath(params.FilePath)
206− header := toolHeader(sty, opts.Status, "Edit", width, opts.Compact, file)
206+ header := toolHeader(sty, opts.Status, "Edit", width, opts, file)
207 if opts.Compact {
207 if opts.Compact {
208 return header
208 return header
209 }
209 }
@@ -276,7 +276,7 @@ func (m *MultiEditToolRenderContext) RenderTool(sty *styles.Styles, width int, o
276 toolParams = append(toolParams, "edits", fmt.Sprintf("%d", len(params.Edits)))
276 toolParams = append(toolParams, "edits", fmt.Sprintf("%d", len(params.Edits)))
277 }
277 }
278
278
279− header := toolHeader(sty, opts.Status, "Multi-Edit", width, opts.Compact, toolParams...)
279+ header := toolHeader(sty, opts.Status, "Multi-Edit", width, opts, toolParams...)
280 if opts.Compact {
280 if opts.Compact {
281 return header
281 return header
282 }
282 }
@@ -352,7 +352,7 @@ func (d *DownloadToolRenderContext) RenderTool(sty *styles.Styles, width int, op
352 toolParams = append(toolParams, "timeout", formatTimeout(params.Timeout))
352 toolParams = append(toolParams, "timeout", formatTimeout(params.Timeout))
353 }
353 }
354
354
355− header := toolHeader(sty, opts.Status, "Download", cappedWidth, opts.Compact, toolParams...)
355+ header := toolHeader(sty, opts.Status, "Download", cappedWidth, opts, toolParams...)
356 if opts.Compact {
356 if opts.Compact {
357 return header
357 return header
358 }
358 }
internal/ui/chat/generic.go+1−1
@@ -48,7 +48,7 @@ func (g *GenericToolRenderContext) RenderTool(sty *styles.Styles, width int, opt
48 toolParams = append(toolParams, string(parsed))
48 toolParams = append(toolParams, string(parsed))
49 }
49 }
50
50
51− header := toolHeader(sty, opts.Status, name, cappedWidth, opts.Compact, toolParams...)
51+ header := toolHeader(sty, opts.Status, name, cappedWidth, opts, toolParams...)
52 if opts.Compact {
52 if opts.Compact {
53 return header
53 return header
54 }
54 }
internal/ui/chat/lsp_restart.go+1−1
@@ -43,7 +43,7 @@ func (r *LSPRestartToolRenderContext) RenderTool(sty *styles.Styles, width int,
43 toolParams = append(toolParams, params.Name)
43 toolParams = append(toolParams, params.Name)
44 }
44 }
45
45
46− header := toolHeader(sty, opts.Status, "Restart LSP", cappedWidth, opts.Compact, toolParams...)
46+ header := toolHeader(sty, opts.Status, "Restart LSP", cappedWidth, opts, toolParams...)
47 if opts.Compact {
47 if opts.Compact {
48 return header
48 return header
49 }
49 }
internal/ui/chat/mcp.go+1−1
@@ -59,7 +59,7 @@ func (b *MCPToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *T
59 toolParams = append(toolParams, string(parsed))
59 toolParams = append(toolParams, string(parsed))
60 }
60 }
61
61
62− header := toolHeader(sty, opts.Status, name, cappedWidth, opts.Compact, toolParams...)
62+ header := toolHeader(sty, opts.Status, name, cappedWidth, opts, toolParams...)
63 if opts.Compact {
63 if opts.Compact {
64 return header
64 return header
65 }
65 }
internal/ui/chat/references.go+1−1
@@ -44,7 +44,7 @@ func (r *ReferencesToolRenderContext) RenderTool(sty *styles.Styles, width int,
44 toolParams = append(toolParams, "path", fsext.PrettyPath(params.Path))
44 toolParams = append(toolParams, "path", fsext.PrettyPath(params.Path))
45 }
45 }
46
46
47− header := toolHeader(sty, opts.Status, "Find References", cappedWidth, opts.Compact, toolParams...)
47+ header := toolHeader(sty, opts.Status, "Find References", cappedWidth, opts, toolParams...)
48 if opts.Compact {
48 if opts.Compact {
49 return header
49 return header
50 }
50 }
internal/ui/chat/search.go+4−4
@@ -50,7 +50,7 @@ func (g *GlobToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *
50 toolParams = append(toolParams, "path", params.Path)
50 toolParams = append(toolParams, "path", params.Path)
51 }
51 }
52
52
53− header := toolHeader(sty, opts.Status, "Glob", cappedWidth, opts.Compact, toolParams...)
53+ header := toolHeader(sty, opts.Status, "Glob", cappedWidth, opts, toolParams...)
54 if opts.Compact {
54 if opts.Compact {
55 return header
55 return header
56 }
56 }
@@ -115,7 +115,7 @@ func (g *GrepToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *
115 toolParams = append(toolParams, "literal", "true")
115 toolParams = append(toolParams, "literal", "true")
116 }
116 }
117
117
118− header := toolHeader(sty, opts.Status, "Grep", cappedWidth, opts.Compact, toolParams...)
118+ header := toolHeader(sty, opts.Status, "Grep", cappedWidth, opts, toolParams...)
119 if opts.Compact {
119 if opts.Compact {
120 return header
120 return header
121 }
121 }
@@ -175,7 +175,7 @@ func (l *LSToolRenderContext) RenderTool(sty *styles.Styles, width int, opts *To
175 }
175 }
176 path = fsext.PrettyPath(path)
176 path = fsext.PrettyPath(path)
177
177
178− header := toolHeader(sty, opts.Status, "List", cappedWidth, opts.Compact, path)
178+ header := toolHeader(sty, opts.Status, "List", cappedWidth, opts, path)
179 if opts.Compact {
179 if opts.Compact {
180 return header
180 return header
181 }
181 }
@@ -237,7 +237,7 @@ func (s *SourcegraphToolRenderContext) RenderTool(sty *styles.Styles, width int,
237 toolParams = append(toolParams, "context", formatNonZero(params.ContextWindow))
237 toolParams = append(toolParams, "context", formatNonZero(params.ContextWindow))
238 }
238 }
239
239
240− header := toolHeader(sty, opts.Status, "Sourcegraph", cappedWidth, opts.Compact, toolParams...)
240+ header := toolHeader(sty, opts.Status, "Sourcegraph", cappedWidth, opts, toolParams...)
241 if opts.Compact {
241 if opts.Compact {
242 return header
242 return header
243 }
243 }
internal/ui/chat/todos.go+1−1
@@ -119,7 +119,7 @@ func (t *TodosToolRenderContext) RenderTool(sty *styles.Styles, width int, opts
119 }
119 }
120
120
121 toolParams := []string{headerText}
121 toolParams := []string{headerText}
122− header := toolHeader(sty, opts.Status, "To-Do", cappedWidth, opts.Compact, toolParams...)
122+ header := toolHeader(sty, opts.Status, "To-Do", cappedWidth, opts, toolParams...)
123 if opts.Compact {
123 if opts.Compact {
124 return header
124 return header
125 }
125 }
internal/ui/chat/tools.go+20−5
@@ -569,9 +569,9 @@ func toolIcon(sty *styles.Styles, status ToolStatus) string {
569 }
569 }
570}
570}
571
571
572−// toolParamList formats parameters as "main (key=value, ...)" with truncation.
573// toolParamList formats tool parameters as "main (key=value, ...)" with truncation.
572// toolParamList formats tool parameters as "main (key=value, ...)" with truncation.
573+// When opts.ExpandedContent is true, the output wraps instead of truncating.
574−func toolParamList(sty *styles.Styles, params []string, width int) string {
574+func toolParamList(sty *styles.Styles, params []string, width int, opts *ToolRenderOpts) string {
575 // minSpaceForMainParam is the min space required for the main param
575 // minSpaceForMainParam is the min space required for the main param
576 // if this is less that the value set we will only show the main param nothing else
576 // if this is less that the value set we will only show the main param nothing else
577 const minSpaceForMainParam = 30
577 const minSpaceForMainParam = 30
@@ -598,14 +598,18 @@ func toolParamList(sty *styles.Styles, params []string, width int) string {
598 }
598 }
599 }
599 }
600
600
601− if width >= 0 {
601+ if width >= 0 && (opts == nil || !opts.ExpandedContent) {
602 output = ansi.Truncate(output, width, "…")
602 output = ansi.Truncate(output, width, "…")
603+ } else if opts != nil && opts.ExpandedContent && width > 0 && lipgloss.Width(output) > width {
604+ output = ansi.Hardwrap(output, width, false)
603 }
605 }
604 return sty.Tool.ParamMain.Render(output)
606 return sty.Tool.ParamMain.Render(output)
605}
607}
606
608
607// toolHeader builds the tool header line: "● ToolName params..."
609// toolHeader builds the tool header line: "● ToolName params..."
610+// When opts.ExpandedContent is true, long parameters wrap instead of truncating.
608−func toolHeader(sty *styles.Styles, status ToolStatus, name string, width int, nested bool, params ...string) string {
611+func toolHeader(sty *styles.Styles, status ToolStatus, name string, width int, opts *ToolRenderOpts, params ...string) string {
612+ nested := opts != nil && opts.Compact
609 icon := toolIcon(sty, status)
613 icon := toolIcon(sty, status)
610 nameStyle := sty.Tool.NameNormal
614 nameStyle := sty.Tool.NameNormal
611 if nested {
615 if nested {
@@ -615,7 +619,18 @@ func toolHeader(sty *styles.Styles, status ToolStatus, name string, width int, n
615 prefix := fmt.Sprintf("%s %s ", icon, toolName)
619 prefix := fmt.Sprintf("%s %s ", icon, toolName)
616 prefixWidth := lipgloss.Width(prefix)
620 prefixWidth := lipgloss.Width(prefix)
617 remainingWidth := width - prefixWidth
621 remainingWidth := width - prefixWidth
618− paramsStr := toolParamList(sty, params, remainingWidth)
622+ paramsStr := toolParamList(sty, params, remainingWidth, opts)
623+
624+ // When expanded, toolParamList may return multiple lines. Indent
625+ // continuation lines to align with the first line's param text.
626+ if strings.Contains(paramsStr, "\n") {
627+ lines := strings.Split(paramsStr, "\n")
628+ indent := strings.Repeat(" ", prefixWidth)
629+ for i := 1; i < len(lines); i++ {
630+ lines[i] = indent + lines[i]
631+ }
632+ return prefix + strings.Join(lines, "\n")
633+ }
619 return prefix + paramsStr
634 return prefix + paramsStr
620}
635}
621
636