mirror of
https://github.com/sst/opencode.git
synced 2025-08-30 01:44:11 +00:00
Feat: Add Agent Name in the LLM Response Footer (and re-order it) (#1770)
This commit is contained in:
parent
696ab1a752
commit
bd4319f2bc
4 changed files with 81 additions and 31 deletions
|
@ -324,9 +324,37 @@ func renderText(
|
||||||
if time.Now().Format("02 Jan 2006") == timestamp[:11] {
|
if time.Now().Format("02 Jan 2006") == timestamp[:11] {
|
||||||
timestamp = timestamp[12:]
|
timestamp = timestamp[12:]
|
||||||
}
|
}
|
||||||
info := fmt.Sprintf("%s (%s)", author, timestamp)
|
|
||||||
info = styles.NewStyle().Foreground(t.TextMuted()).Render(info)
|
|
||||||
|
|
||||||
|
// Check if this is an assistant message with mode (agent) information
|
||||||
|
var modelAndAgentSuffix string
|
||||||
|
if assistantMsg, ok := message.(opencode.AssistantMessage); ok && assistantMsg.Mode != "" {
|
||||||
|
// Find the agent index by name to get the correct color
|
||||||
|
var agentIndex int
|
||||||
|
for i, agent := range app.Agents {
|
||||||
|
if agent.Name == assistantMsg.Mode {
|
||||||
|
agentIndex = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get agent color based on the original agent index (same as status bar)
|
||||||
|
agentColor := util.GetAgentColor(agentIndex)
|
||||||
|
|
||||||
|
// Style the agent name with the same color as status bar
|
||||||
|
agentName := strings.Title(assistantMsg.Mode)
|
||||||
|
styledAgentName := styles.NewStyle().Foreground(agentColor).Bold(true).Render(agentName)
|
||||||
|
modelAndAgentSuffix = fmt.Sprintf(" | %s | %s", assistantMsg.ModelID, styledAgentName)
|
||||||
|
}
|
||||||
|
|
||||||
|
var info string
|
||||||
|
if modelAndAgentSuffix != "" {
|
||||||
|
// For assistant messages: "timestamp | modelID | agentName"
|
||||||
|
info = fmt.Sprintf("%s%s", timestamp, modelAndAgentSuffix)
|
||||||
|
} else {
|
||||||
|
// For user messages: "author (timestamp)"
|
||||||
|
info = fmt.Sprintf("%s (%s)", author, timestamp)
|
||||||
|
}
|
||||||
|
info = styles.NewStyle().Foreground(t.TextMuted()).Render(info)
|
||||||
if !showToolDetails && toolCalls != nil && len(toolCalls) > 0 {
|
if !showToolDetails && toolCalls != nil && len(toolCalls) > 0 {
|
||||||
content = content + "\n\n"
|
content = content + "\n\n"
|
||||||
for _, toolCall := range toolCalls {
|
for _, toolCall := range toolCalls {
|
||||||
|
|
|
@ -121,30 +121,14 @@ func (m *statusComponent) View() string {
|
||||||
|
|
||||||
var modeBackground compat.AdaptiveColor
|
var modeBackground compat.AdaptiveColor
|
||||||
var modeForeground compat.AdaptiveColor
|
var modeForeground compat.AdaptiveColor
|
||||||
switch m.app.AgentIndex {
|
|
||||||
case 0:
|
agentColor := util.GetAgentColor(m.app.AgentIndex)
|
||||||
|
|
||||||
|
if m.app.AgentIndex == 0 {
|
||||||
modeBackground = t.BackgroundElement()
|
modeBackground = t.BackgroundElement()
|
||||||
modeForeground = t.TextMuted()
|
modeForeground = agentColor
|
||||||
case 1:
|
} else {
|
||||||
modeBackground = t.Secondary()
|
modeBackground = agentColor
|
||||||
modeForeground = t.BackgroundPanel()
|
|
||||||
case 2:
|
|
||||||
modeBackground = t.Accent()
|
|
||||||
modeForeground = t.BackgroundPanel()
|
|
||||||
case 3:
|
|
||||||
modeBackground = t.Success()
|
|
||||||
modeForeground = t.BackgroundPanel()
|
|
||||||
case 4:
|
|
||||||
modeBackground = t.Warning()
|
|
||||||
modeForeground = t.BackgroundPanel()
|
|
||||||
case 5:
|
|
||||||
modeBackground = t.Primary()
|
|
||||||
modeForeground = t.BackgroundPanel()
|
|
||||||
case 6:
|
|
||||||
modeBackground = t.Error()
|
|
||||||
modeForeground = t.BackgroundPanel()
|
|
||||||
default:
|
|
||||||
modeBackground = t.Secondary()
|
|
||||||
modeForeground = t.BackgroundPanel()
|
modeForeground = t.BackgroundPanel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,9 @@ package util
|
||||||
import (
|
import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/lipgloss/v2/compat"
|
||||||
|
"github.com/sst/opencode/internal/theme"
|
||||||
)
|
)
|
||||||
|
|
||||||
var csiRE *regexp.Regexp
|
var csiRE *regexp.Regexp
|
||||||
|
@ -89,5 +92,24 @@ func ConvertRGBToAnsi16Colors(s string) string {
|
||||||
|
|
||||||
// func looksLikeByte(tok string) bool {
|
// func looksLikeByte(tok string) bool {
|
||||||
// v, err := strconv.Atoi(tok)
|
// v, err := strconv.Atoi(tok)
|
||||||
// return err == nil && v >= 0 && v <= 255
|
// return err == nil && v >= 0 && v <= 255
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// GetAgentColor returns the color for a given agent index, matching the status bar colors
|
||||||
|
func GetAgentColor(agentIndex int) compat.AdaptiveColor {
|
||||||
|
t := theme.CurrentTheme()
|
||||||
|
agentColors := []compat.AdaptiveColor{
|
||||||
|
t.TextMuted(),
|
||||||
|
t.Secondary(),
|
||||||
|
t.Accent(),
|
||||||
|
t.Success(),
|
||||||
|
t.Warning(),
|
||||||
|
t.Primary(),
|
||||||
|
t.Error(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if agentIndex >= 0 && agentIndex < len(agentColors) {
|
||||||
|
return agentColors[agentIndex]
|
||||||
|
}
|
||||||
|
return t.Secondary() // default fallback
|
||||||
|
}
|
||||||
|
|
|
@ -144,7 +144,15 @@ export function Part(props: PartProps) {
|
||||||
DateTime.DATETIME_FULL_WITH_SECONDS,
|
DateTime.DATETIME_FULL_WITH_SECONDS,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{DateTime.fromMillis(props.message.time.completed).toLocaleString(DateTime.DATETIME_MED)}
|
{DateTime.fromMillis(props.message.time.completed || props.message.time.created).toLocaleString(
|
||||||
|
DateTime.DATETIME_MED,
|
||||||
|
)}
|
||||||
|
{` | ${props.message.modelID}`}
|
||||||
|
{props.message.mode && (
|
||||||
|
<span style={{ "font-weight": "bold", color: "var(--sl-color-accent)" }}>
|
||||||
|
{` | ${props.message.mode}`}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</Footer>
|
</Footer>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -158,7 +166,17 @@ export function Part(props: PartProps) {
|
||||||
{props.part.type === "step-start" && props.message.role === "assistant" && (
|
{props.part.type === "step-start" && props.message.role === "assistant" && (
|
||||||
<div data-component="step-start">
|
<div data-component="step-start">
|
||||||
<div data-slot="provider">{props.message.providerID}</div>
|
<div data-slot="provider">{props.message.providerID}</div>
|
||||||
<div data-slot="model">{props.message.modelID}</div>
|
<div data-slot="model">
|
||||||
|
{DateTime.fromMillis(props.message.time.completed || props.message.time.created).toLocaleString(
|
||||||
|
DateTime.DATETIME_MED,
|
||||||
|
)}
|
||||||
|
{` | ${props.message.modelID}`}
|
||||||
|
{props.message.mode && (
|
||||||
|
<span style={{ "font-weight": "bold", color: "var(--sl-color-accent)" }}>
|
||||||
|
{` | ${props.message.mode}`}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{props.part.type === "tool" && props.part.state.status === "error" && (
|
{props.part.type === "tool" && props.part.state.status === "error" && (
|
||||||
|
@ -653,9 +671,7 @@ function TaskTool(props: ToolProps) {
|
||||||
<span data-slot="name">Task</span>
|
<span data-slot="name">Task</span>
|
||||||
<span data-slot="target">{props.state.input.description}</span>
|
<span data-slot="target">{props.state.input.description}</span>
|
||||||
</div>
|
</div>
|
||||||
<div data-component="tool-input">
|
<div data-component="tool-input">“{props.state.input.prompt}”</div>
|
||||||
“{props.state.input.prompt}”
|
|
||||||
</div>
|
|
||||||
<ResultsButton showCopy="Show output" hideCopy="Hide output">
|
<ResultsButton showCopy="Show output" hideCopy="Hide output">
|
||||||
<div data-component="tool-output">
|
<div data-component="tool-output">
|
||||||
<ContentMarkdown expand text={props.state.output} />
|
<ContentMarkdown expand text={props.state.output} />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue