@@ -110,6 +110,8 @@ type UI struct {
110 session *session.Session
110 session *session.Session
111 sessionFiles []SessionFile
111 sessionFiles []SessionFile
113+ lastUserMessageTime int64
113 // The width and height of the terminal in cells.
115 // The width and height of the terminal in cells.
114 width int
116 width int
115 height int
117 height int
@@ -596,11 +598,26 @@ func (m *UI) setSessionMessages(msgs []message.Message) tea.Cmd {
596 msgPtrs[i] = &msgs[i]
598 msgPtrs[i] = &msgs[i]
598 toolResultMap := chat.BuildToolResultMap(msgPtrs)
600 toolResultMap := chat.BuildToolResultMap(msgPtrs)
601+ if len(msgPtrs) > 0 {
602+ m.lastUserMessageTime = msgPtrs[0].CreatedAt
600 // Add messages to chat with linked tool results
605 // Add messages to chat with linked tool results
601 items := make([]chat.MessageItem, 0, len(msgs)*2)
606 items := make([]chat.MessageItem, 0, len(msgs)*2)
602 for _, msg := range msgPtrs {
607 for _, msg := range msgPtrs {
610+ m.lastUserMessageTime = msg.CreatedAt
611+ items = append(items, chat.ExtractMessageItems(m.com.Styles, msg, toolResultMap)...)
612+ case message.Assistant:
613+ items = append(items, chat.ExtractMessageItems(m.com.Styles, msg, toolResultMap)...)
614+ if msg.FinishPart() != nil && msg.FinishPart().Reason == message.FinishReasonEndTurn {
615+ infoItem := chat.NewAssistantInfoItem(m.com.Styles, msg, time.Unix(m.lastUserMessageTime, 0))
616+ items = append(items, infoItem)
603− items = append(items, chat.ExtractMessageItems(m.com.Styles, msg, toolResultMap)...)
619+ items = append(items, chat.ExtractMessageItems(m.com.Styles, msg, toolResultMap)...)
606 // Load nested tool calls for agent/agentic_fetch tools.
623 // Load nested tool calls for agent/agentic_fetch tools.
@@ -692,7 +709,21 @@ func (m *UI) appendSessionMessage(msg message.Message) tea.Cmd {
692 return nil
709 return nil
694 switch msg.Role {
711 switch msg.Role {
695− case message.User, message.Assistant:
712+ case message.User:
713+ m.lastUserMessageTime = msg.CreatedAt
714+ items := chat.ExtractMessageItems(m.com.Styles, &msg, nil)
715+ for _, item := range items {
716+ if animatable, ok := item.(chat.Animatable); ok {
717+ if cmd := animatable.StartAnimation(); cmd != nil {
718+ cmds = append(cmds, cmd)
722+ m.chat.AppendMessages(items...)
723+ if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
724+ cmds = append(cmds, cmd)
726+ case message.Assistant:
696 items := chat.ExtractMessageItems(m.com.Styles, &msg, nil)
727 items := chat.ExtractMessageItems(m.com.Styles, &msg, nil)
697 for _, item := range items {
728 for _, item := range items {
698 if animatable, ok := item.(chat.Animatable); ok {
729 if animatable, ok := item.(chat.Animatable); ok {
@@ -705,6 +736,13 @@ func (m *UI) appendSessionMessage(msg message.Message) tea.Cmd {
705 if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
736 if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
706 cmds = append(cmds, cmd)
737 cmds = append(cmds, cmd)
739+ if msg.FinishPart() != nil && msg.FinishPart().Reason == message.FinishReasonEndTurn {
740+ infoItem := chat.NewAssistantInfoItem(m.com.Styles, &msg, time.Unix(m.lastUserMessageTime, 0))
741+ m.chat.AppendMessages(infoItem)
742+ if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
743+ cmds = append(cmds, cmd)
708 case message.Tool:
746 case message.Tool:
709 for _, tr := range msg.ToolResults() {
747 for _, tr := range msg.ToolResults() {
710 toolItem := m.chat.MessageItem(tr.ToolCallID)
748 toolItem := m.chat.MessageItem(tr.ToolCallID)
@@ -733,9 +771,23 @@ func (m *UI) updateSessionMessage(msg message.Message) tea.Cmd {
774+ shouldRenderAssistant := chat.ShouldRenderAssistantMessage(&msg)
736 // if the message of the assistant does not have any response just tool calls we need to remove it
775 // if the message of the assistant does not have any response just tool calls we need to remove it
737− if !chat.ShouldRenderAssistantMessage(&msg) && len(msg.ToolCalls()) > 0 && existingItem != nil {
776+ if !shouldRenderAssistant && len(msg.ToolCalls()) > 0 && existingItem != nil {
738 m.chat.RemoveMessage(msg.ID)
777 m.chat.RemoveMessage(msg.ID)
778+ if infoItem := m.chat.MessageItem(chat.AssistantInfoID(msg.ID)); infoItem != nil {
779+ m.chat.RemoveMessage(chat.AssistantInfoID(msg.ID))
783+ if shouldRenderAssistant && msg.FinishPart() != nil && msg.FinishPart().Reason == message.FinishReasonEndTurn {
784+ if infoItem := m.chat.MessageItem(chat.AssistantInfoID(msg.ID)); infoItem == nil {
785+ newInfoItem := chat.NewAssistantInfoItem(m.com.Styles, &msg, time.Unix(m.lastUserMessageTime, 0))
786+ m.chat.AppendMessages(newInfoItem)
787+ if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
788+ cmds = append(cmds, cmd)
741 var items []chat.MessageItem
793 var items []chat.MessageItem