@@ -111,8 +111,18 @@ func (br baseRenderer) unmarshalParams(input string, target any) error {
111 return json.Unmarshal([]byte(input), target)
111 return json.Unmarshal([]byte(input), target)
114+// makeHeader builds the tool call header with status icon and parameters for a nested tool call.
115+func (br baseRenderer) makeNestedHeader(v *toolCallCmp, tool string, width int, params ...string) string {
116+ t := styles.CurrentTheme()
117+ tool = t.S().Base.Foreground(t.FgHalfMuted).Render(tool) + " "
118+ return tool + renderParamList(true, width-lipgloss.Width(tool), params...)
114// makeHeader builds "<Tool>: param (key=value)" and truncates as needed.
121// makeHeader builds "<Tool>: param (key=value)" and truncates as needed.
115func (br baseRenderer) makeHeader(v *toolCallCmp, tool string, width int, params ...string) string {
122func (br baseRenderer) makeHeader(v *toolCallCmp, tool string, width int, params ...string) string {
124+ return br.makeNestedHeader(v, tool, width, params...)
116 t := styles.CurrentTheme()
126 t := styles.CurrentTheme()
117 icon := t.S().Base.Foreground(t.GreenDark).Render(styles.ToolPending)
127 icon := t.S().Base.Foreground(t.GreenDark).Render(styles.ToolPending)
118 if v.result.ToolCallID != "" {
128 if v.result.ToolCallID != "" {
@@ -126,7 +136,7 @@ func (br baseRenderer) makeHeader(v *toolCallCmp, tool string, width int, params
127 tool = t.S().Base.Foreground(t.Blue).Render(tool)
137 tool = t.S().Base.Foreground(t.Blue).Render(tool)
128 prefix := fmt.Sprintf("%s %s ", icon, tool)
138 prefix := fmt.Sprintf("%s %s ", icon, tool)
129− return prefix + renderParamList(width-lipgloss.Width(prefix), params...)
139+ return prefix + renderParamList(false, width-lipgloss.Width(prefix), params...)
132// renderError provides consistent error rendering
142// renderError provides consistent error rendering
@@ -477,25 +487,45 @@ type agentRenderer struct {
477 baseRenderer
487 baseRenderer
490+func RoundedEnumerator(children tree.Children, index int) string {
491+ if children.Length()-1 == index {
480// Render displays agent task parameters and result content
497// Render displays agent task parameters and result content
481func (tr agentRenderer) Render(v *toolCallCmp) string {
498func (tr agentRenderer) Render(v *toolCallCmp) string {
499+ t := styles.CurrentTheme()
482 var params agent.AgentParams
500 var params agent.AgentParams
483 if err := tr.unmarshalParams(v.call.Input, ¶ms); err != nil {
501 if err := tr.unmarshalParams(v.call.Input, ¶ms); err != nil {
484 return tr.renderError(v, "Invalid task parameters")
502 return tr.renderError(v, "Invalid task parameters")
486 prompt := params.Prompt
504 prompt := params.Prompt
487 prompt = strings.ReplaceAll(prompt, "\n", " ")
505 prompt = strings.ReplaceAll(prompt, "\n", " ")
488− args := newParamBuilder().addMain(prompt).build()
490− header := tr.makeHeader(v, "Task", v.textWidth(), args...)
507+ header := tr.makeHeader(v, "Agent", v.textWidth())
508+ taskTag := t.S().Base.Padding(0, 1).MarginLeft(1).Background(t.BlueLight).Foreground(t.White).Render("Task")
509+ remainingWidth := v.textWidth() - lipgloss.Width(header) - lipgloss.Width(taskTag) - 2 // -2 for padding
510+ prompt = t.S().Muted.Width(remainingWidth).Render(prompt)
511+ header = lipgloss.JoinVertical(
515+ lipgloss.JoinHorizontal(
491− t := tree.Root(header)
522+ childTools := tree.Root(header)
493 for _, call := range v.nestedToolCalls {
524 for _, call := range v.nestedToolCalls {
494− t.Child(call.View())
525+ childTools.Child(call.View())
497 parts := []string{
527 parts := []string{
498− t.Enumerator(tree.RoundedEnumerator).String(),
528+ childTools.Enumerator(RoundedEnumerator).String(),
500 if v.result.ToolCallID == "" {
530 if v.result.ToolCallID == "" {
501 v.spinning = true
531 v.spinning = true
@@ -518,7 +548,7 @@ func (tr agentRenderer) Render(v *toolCallCmp) string {
520// renderParamList renders params, params[0] (params[1]=params[2] ....)
550// renderParamList renders params, params[0] (params[1]=params[2] ....)
521−func renderParamList(paramsWidth int, params ...string) string {
551+func renderParamList(nested bool, paramsWidth int, params ...string) string {
522 t := styles.CurrentTheme()
552 t := styles.CurrentTheme()
523 if len(params) == 0 {
553 if len(params) == 0 {
524 return ""
554 return ""
@@ -529,6 +559,9 @@ func renderParamList(paramsWidth int, params ...string) string {
531 if len(params) == 1 {
561 if len(params) == 1 {
563+ return t.S().Muted.Render(mainParam)
532 return t.S().Subtle.Render(mainParam)
565 return t.S().Subtle.Render(mainParam)
534 otherParams := params[1:]
567 otherParams := params[1:]
@@ -550,6 +583,9 @@ func renderParamList(paramsWidth int, params ...string) string {
550 partsRendered := strings.Join(parts, ", ")
583 partsRendered := strings.Join(parts, ", ")
551 remainingWidth := paramsWidth - lipgloss.Width(partsRendered) - 3 // count for " ()"
584 remainingWidth := paramsWidth - lipgloss.Width(partsRendered) - 3 // count for " ()"
552 if remainingWidth < 30 {
585 if remainingWidth < 30 {
587+ return t.S().Muted.Render(mainParam)
553 // No space for the params, just show the main
589 // No space for the params, just show the main
554 return t.S().Subtle.Render(mainParam)
590 return t.S().Subtle.Render(mainParam)
@@ -558,6 +594,9 @@ func renderParamList(paramsWidth int, params ...string) string {
558 mainParam = fmt.Sprintf("%s (%s)", mainParam, strings.Join(parts, ", "))
594 mainParam = fmt.Sprintf("%s (%s)", mainParam, strings.Join(parts, ", "))
598+ return t.S().Muted.Render(ansi.Truncate(mainParam, paramsWidth, "..."))
561 return t.S().Subtle.Render(ansi.Truncate(mainParam, paramsWidth, "..."))
600 return t.S().Subtle.Render(ansi.Truncate(mainParam, paramsWidth, "..."))
@@ -635,7 +674,7 @@ func renderCodeContent(v *toolCallCmp, path, content string, offset int) string
635 if len(strings.Split(content, "\n")) > responseContextHeight {
674 if len(strings.Split(content, "\n")) > responseContextHeight {
636 lines = append(lines, t.S().Muted.
675 lines = append(lines, t.S().Muted.
637 Background(t.BgBase).
676 Background(t.BgBase).
638− Render(fmt.Sprintf(" ... (%d lines)", len(strings.Split(content, "\n"))-responseContextHeight)))
677+ Render(fmt.Sprintf(" …(%d lines)", len(strings.Split(content, "\n"))-responseContextHeight)))
641 maxLineNumber := len(lines) + offset
680 maxLineNumber := len(lines) + offset
@@ -647,13 +686,12 @@ func renderCodeContent(v *toolCallCmp, path, content string, offset int) string
647 PaddingRight(1).
686 PaddingRight(1).
648 PaddingLeft(1).
687 PaddingLeft(1).
649 Render(pad(i+1+offset, padding))
688 Render(pad(i+1+offset, padding))
650− w := v.textWidth() - 2 - lipgloss.Width(num) // -2 for left padding
689+ w := v.textWidth() - 10 - lipgloss.Width(num) // -4 for left padding
651 lines[i] = lipgloss.JoinHorizontal(lipgloss.Left,
690 lines[i] = lipgloss.JoinHorizontal(lipgloss.Left,
653 t.S().Base.
692 t.S().Base.
654 PaddingLeft(1).
693 PaddingLeft(1).
656− Render(v.fit(ln, w)))
694+ Render(v.fit(ln, w-1)))
658 return lipgloss.JoinVertical(lipgloss.Left, lines...)
696 return lipgloss.JoinVertical(lipgloss.Left, lines...)
@@ -662,7 +700,7 @@ func (v *toolCallCmp) renderToolError() string {
662 t := styles.CurrentTheme()
700 t := styles.CurrentTheme()
663 err := strings.ReplaceAll(v.result.Content, "\n", " ")
701 err := strings.ReplaceAll(v.result.Content, "\n", " ")
664 err = fmt.Sprintf("Error: %s", err)
702 err = fmt.Sprintf("Error: %s", err)
665− return t.S().Base.Foreground(t.Error).Render(v.fit(err, v.textWidth()))
703+ return t.S().Base.Foreground(t.Error).Render(v.fit(err, v.textWidth()-2))
668func truncateHeight(s string, h int) string {
706func truncateHeight(s string, h int) string {
@@ -676,7 +714,7 @@ func truncateHeight(s string, h int) string {
676func prettifyToolName(name string) string {
714func prettifyToolName(name string) string {
677 switch name {
715 switch name {
678 case agent.AgentToolName:
716 case agent.AgentToolName:
679− return "Task"
717+ return "Agent"
680 case tools.BashToolName:
718 case tools.BashToolName:
681 return "Bash"
719 return "Bash"
682 case tools.EditToolName:
720 case tools.EditToolName: