@@ -2,6 +2,7 @@ package chat
4 "encoding/json"
4 "encoding/json"
7 tea "charm.land/bubbletea/v2"
8 tea "charm.land/bubbletea/v2"
@@ -24,6 +25,18 @@ type NestedToolContainer interface {
24 AddNestedTool(tool ToolMessageItem)
25 AddNestedTool(tool ToolMessageItem)
28+// collapsedNestedHint is the affordance shown under a collapsed sub-agent
29+// card, indicating its nested tool calls can be revealed with space.
30+const collapsedNestedHint = " ▸ space to expand"
32+// toolCountLabel renders a "N tools" summary for a sub-agent header line.
33+func toolCountLabel(n int) string {
37+ return fmt.Sprintf("%d tools", n)
27// AgentToolMessageItem is a message item that represents an agent tool call.
40// AgentToolMessageItem is a message item that represents an agent tool call.
28type AgentToolMessageItem struct {
41type AgentToolMessageItem struct {
29 *baseToolMessageItem
42 *baseToolMessageItem
@@ -139,6 +152,10 @@ func (r *AgentToolRenderContext) RenderTool(sty *styles.Styles, width int, opts
141 header := toolHeader(sty, opts.Status, "Agent", cappedWidth, opts)
154 header := toolHeader(sty, opts.Status, "Agent", cappedWidth, opts)
155+ nestedCount := len(r.agent.nestedTools)
156+ if nestedCount > 0 {
157+ header += " " + sty.Tool.ParamMain.Render(toolCountLabel(nestedCount))
142 if opts.Compact {
159 if opts.Compact {
143 return header
160 return header
@@ -164,17 +181,22 @@ func (r *AgentToolRenderContext) RenderTool(sty *styles.Styles, width int, opts
167− // Build tree with nested tool calls.
184+ // Nested tool calls are collapsed by default to keep the conversation
168− childTools := tree.Root(header)
185+ // readable; press space to expand the full call tree.
170− for _, nestedTool := range r.agent.nestedTools {
171− childView := nestedTool.Render(remainingWidth)
172− childTools.Child(childView)
176 var parts []string
186 var parts []string
187+ if opts.ExpandedContent {
188+ childTools := tree.Root(header)
189+ for _, nestedTool := range r.agent.nestedTools {
190+ childView := nestedTool.Render(remainingWidth)
191+ childTools.Child(childView)
177− parts = append(parts, childTools.Enumerator(roundedEnumerator(2, taskTagWidth-5)).String())
193+ parts = append(parts, childTools.Enumerator(roundedEnumerator(2, taskTagWidth-5)).String())
195+ parts = append(parts, header)
196+ if nestedCount > 0 {
197+ parts = append(parts, sty.Tool.AgentPrompt.Render(collapsedNestedHint))
179 // Show animation if still running.
201 // Show animation if still running.
180 if !opts.HasResult() && !opts.IsCanceled() {
202 if !opts.HasResult() && !opts.IsCanceled() {
@@ -308,6 +330,10 @@ func (r *AgenticFetchToolRenderContext) RenderTool(sty *styles.Styles, width int
310 header := toolHeader(sty, opts.Status, "Agentic Fetch", cappedWidth, opts, toolParams...)
332 header := toolHeader(sty, opts.Status, "Agentic Fetch", cappedWidth, opts, toolParams...)
333+ nestedCount := len(r.fetch.nestedTools)
334+ if nestedCount > 0 {
335+ header += " " + sty.Tool.ParamMain.Render(toolCountLabel(nestedCount))
311 if opts.Compact {
337 if opts.Compact {
312 return header
338 return header
@@ -333,17 +359,22 @@ func (r *AgenticFetchToolRenderContext) RenderTool(sty *styles.Styles, width int
336− // Build tree with nested tool calls.
362+ // Nested tool calls are collapsed by default to keep the conversation
337− childTools := tree.Root(header)
363+ // readable; press space to expand the full call tree.
339− for _, nestedTool := range r.fetch.nestedTools {
340− childView := nestedTool.Render(remainingWidth)
341− childTools.Child(childView)
345 var parts []string
364 var parts []string
365+ if opts.ExpandedContent {
366+ childTools := tree.Root(header)
367+ for _, nestedTool := range r.fetch.nestedTools {
368+ childView := nestedTool.Render(remainingWidth)
369+ childTools.Child(childView)
346− parts = append(parts, childTools.Enumerator(roundedEnumerator(2, promptTagWidth-5)).String())
371+ parts = append(parts, childTools.Enumerator(roundedEnumerator(2, promptTagWidth-5)).String())
373+ parts = append(parts, header)
374+ if nestedCount > 0 {
375+ parts = append(parts, sty.Tool.AgentPrompt.Render(collapsedNestedHint))
348 // Show animation if still running.
379 // Show animation if still running.
349 if !opts.HasResult() && !opts.IsCanceled() {
380 if !opts.HasResult() && !opts.IsCanceled() {