feat: show sender name and timestamp

This commit is contained in:
adamdottv
2025-05-05 11:02:02 -05:00
parent 167eb9ddfa
commit 874715838a
2 changed files with 67 additions and 20 deletions

View File

@@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"log/slog" "log/slog"
"os" "os"
"os/user"
"path/filepath" "path/filepath"
"strings" "strings"
@@ -712,6 +713,24 @@ func WorkingDirectory() string {
return cfg.WorkingDir return cfg.WorkingDir
} }
// GetHostname returns the system hostname or "User" if it can't be determined
func GetHostname() (string, error) {
hostname, err := os.Hostname()
if err != nil {
return "User", err
}
return hostname, nil
}
// GetUsername returns the current user's username
func GetUsername() (string, error) {
currentUser, err := user.Current()
if err != nil {
return "User", err
}
return currentUser.Username, nil
}
func UpdateAgentModel(agentName AgentName, modelID models.ModelID) error { func UpdateAgentModel(agentName AgentName, modelID models.ModelID) error {
if cfg == nil { if cfg == nil {
panic("config not loaded") panic("config not loaded")

View File

@@ -82,7 +82,8 @@ func renderMessage(msg string, isUser bool, isFocused bool, width int, info ...s
func renderUserMessage(msg message.Message, isFocused bool, width int, position int) uiMessage { func renderUserMessage(msg message.Message, isFocused bool, width int, position int) uiMessage {
var styledAttachments []string var styledAttachments []string
t := theme.CurrentTheme() t := theme.CurrentTheme()
attachmentStyles := styles.BaseStyle(). baseStyle := styles.BaseStyle()
attachmentStyles := baseStyle.
MarginLeft(1). MarginLeft(1).
Background(t.TextMuted()). Background(t.TextMuted()).
Foreground(t.Text()) Foreground(t.Text())
@@ -96,12 +97,23 @@ func renderUserMessage(msg message.Message, isFocused bool, width int, position
} }
styledAttachments = append(styledAttachments, attachmentStyles.Render(filename)) styledAttachments = append(styledAttachments, attachmentStyles.Render(filename))
} }
// Add timestamp info
info := []string{}
timestamp := time.Unix(msg.CreatedAt, 0).Format("15:04:05")
username, _ := config.GetUsername()
info = append(info, baseStyle.
Width(width-1).
Foreground(t.TextMuted()).
Render(fmt.Sprintf(" %s (%s)", username, timestamp)),
)
content := "" content := ""
if len(styledAttachments) > 0 { if len(styledAttachments) > 0 {
attachmentContent := styles.BaseStyle().Width(width).Render(lipgloss.JoinHorizontal(lipgloss.Left, styledAttachments...)) attachmentContent := baseStyle.Width(width).Render(lipgloss.JoinHorizontal(lipgloss.Left, styledAttachments...))
content = renderMessage(msg.Content().String(), true, isFocused, width, attachmentContent) content = renderMessage(msg.Content().String(), true, isFocused, width, append(info, attachmentContent)...)
} else { } else {
content = renderMessage(msg.Content().String(), true, isFocused, width) content = renderMessage(msg.Content().String(), true, isFocused, width, info...)
} }
userMsg := uiMessage{ userMsg := uiMessage{
ID: msg.ID, ID: msg.ID,
@@ -134,36 +146,43 @@ func renderAssistantMessage(
t := theme.CurrentTheme() t := theme.CurrentTheme()
baseStyle := styles.BaseStyle() baseStyle := styles.BaseStyle()
// Add finish info if available // Always add timestamp info
timestamp := time.Unix(msg.CreatedAt, 0).Format("15:04:05")
modelName := "Assistant"
if msg.Model != "" {
modelName = models.SupportedModels[msg.Model].Name
}
info = append(info, baseStyle.
Width(width-1).
Foreground(t.TextMuted()).
Render(fmt.Sprintf(" %s (%s)", modelName, timestamp)),
)
if finished { if finished {
// Add finish info if available
switch finishData.Reason { switch finishData.Reason {
case message.FinishReasonEndTurn:
took := formatTimestampDiff(msg.CreatedAt, finishData.Time)
info = append(info, baseStyle.
Width(width-1).
Foreground(t.TextMuted()).
Render(fmt.Sprintf(" %s (%s)", models.SupportedModels[msg.Model].Name, took)),
)
case message.FinishReasonCanceled: case message.FinishReasonCanceled:
info = append(info, baseStyle. info = append(info, baseStyle.
Width(width-1). Width(width-1).
Foreground(t.TextMuted()). Foreground(t.Warning()).
Render(fmt.Sprintf(" %s (%s)", models.SupportedModels[msg.Model].Name, "canceled")), Render("(canceled)"),
) )
case message.FinishReasonError: case message.FinishReasonError:
info = append(info, baseStyle. info = append(info, baseStyle.
Width(width-1). Width(width-1).
Foreground(t.TextMuted()). Foreground(t.Error()).
Render(fmt.Sprintf(" %s (%s)", models.SupportedModels[msg.Model].Name, "error")), Render("(error)"),
) )
case message.FinishReasonPermissionDenied: case message.FinishReasonPermissionDenied:
info = append(info, baseStyle. info = append(info, baseStyle.
Width(width-1). Width(width-1).
Foreground(t.TextMuted()). Foreground(t.Info()).
Render(fmt.Sprintf(" %s (%s)", models.SupportedModels[msg.Model].Name, "permission denied")), Render("(permission denied)"),
) )
} }
} }
if content != "" || (finished && finishData.Reason == message.FinishReasonEndTurn) { if content != "" || (finished && finishData.Reason == message.FinishReasonEndTurn) {
if content == "" { if content == "" {
content = "*Finished without output*" content = "*Finished without output*"
@@ -180,8 +199,17 @@ func renderAssistantMessage(
position += messages[0].height position += messages[0].height
position++ // for the space position++ // for the space
} else if thinking && thinkingContent != "" { } else if thinking && thinkingContent != "" {
// Render the thinking content // Render the thinking content with timestamp
content = renderMessage(thinkingContent, false, msg.ID == focusedUIMessageId, width) content = renderMessage(thinkingContent, false, msg.ID == focusedUIMessageId, width, info...)
messages = append(messages, uiMessage{
ID: msg.ID,
messageType: assistantMessageType,
position: position,
height: lipgloss.Height(content),
content: content,
})
position += lipgloss.Height(content)
position++ // for the space
} }
for i, toolCall := range msg.ToolCalls() { for i, toolCall := range msg.ToolCalls() {