cmd/tui/chat: show availability badge beside model name instead of plan in meta

This commit is contained in:
ParthSareen 2026-06-24 15:34:04 -07:00
parent 1e004ef209
commit eacaa79706
3 changed files with 64 additions and 8 deletions

View file

@ -577,9 +577,56 @@ func agentModelOptions(ctx context.Context, client *api.Client) ([]agentchat.Mod
add(name, agentLocalModelDescription(model), false, "", false)
}
// Compute availability badges for cloud models based on account state.
badges := cloudAvailabilityBadges(ctx, client, options)
for i := range options {
options[i].AvailabilityBadge = badges[options[i].Name]
}
return options, nil
}
// cloudAvailabilityBadges returns a map of model name → availability badge
// for cloud models that require sign-in or a plan upgrade.
func cloudAvailabilityBadges(ctx context.Context, client *api.Client, options []agentchat.ModelOption) map[string]string {
badges := make(map[string]string)
hasCloud := false
for _, opt := range options {
if opt.Cloud {
hasCloud = true
break
}
}
if !hasCloud {
return badges
}
if disabled, known := agentCloudStatusDisabled(ctx, client); known && disabled {
return badges
}
whoamiCtx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
user, err := client.Whoami(whoamiCtx)
if err != nil {
// Can't determine auth state — don't show badges.
return badges
}
signedIn := user != nil && user.Name != ""
for _, opt := range options {
if !opt.Cloud {
continue
}
if !signedIn {
badges[opt.Name] = "Sign in required"
} else if opt.RequiredPlan != "" && !launch.PlanSatisfies(user.Plan, opt.RequiredPlan) {
badges[opt.Name] = "Upgrade required"
}
}
return badges
}
func agentRecommendationDescription(rec api.ModelRecommendation) string {
var parts []string
if description := strings.TrimSpace(rec.Description); description != "" {

View file

@ -36,11 +36,12 @@ var chatEmptyPrompts = []string{
}
type ModelOption struct {
Name string
Description string
Recommended bool
RequiredPlan string
Cloud bool
Name string
Description string
Recommended bool
RequiredPlan string
Cloud bool
AvailabilityBadge string
}
type Options struct {

View file

@ -46,6 +46,7 @@ type chatPicker[T any] struct {
fullFooter string
itemTitle func(T) string
itemMeta func(T) string
itemBadge func(T) string
}
type chatHistoryPopup struct {
@ -318,6 +319,7 @@ func newChatModelPicker(models []ModelOption, current, filter string) *chatModel
picker.fullFooter = "↑/↓ move • enter switch • type search • esc cancel"
picker.itemTitle = func(model ModelOption) string { return model.Name }
picker.itemMeta = func(model ModelOption) string { return modelOptionMeta(model, current) }
picker.itemBadge = func(model ModelOption) string { return model.AvailabilityBadge }
return picker
}
@ -542,6 +544,7 @@ func newChatResumePicker(chats []appstore.ChatSummary, currentChatID string) *ch
picker.fullFooter = "↑/↓ move • enter resume • type search • esc cancel"
picker.itemTitle = resumeChatTitle
picker.itemMeta = resumeChatMeta
picker.itemBadge = func(appstore.ChatSummary) string { return "" }
return picker
}
@ -915,11 +918,15 @@ func (p *chatPicker[T]) render(width int) string {
for i := start; i < end; i++ {
item := filtered[i]
selected := i == p.cursor
badge := p.itemBadge(item)
for j, line := range wrapChatText(p.itemTitle(item), max(10, width-2)) {
marker := " "
if selected && j == 0 {
marker = " "
}
if j == 0 && badge != "" {
line += " " + chatResumeMetaStyle.Render("("+badge+")")
}
if selected {
b.WriteString(chatResumeSelectedStyle.Render(marker + line))
} else {
@ -974,11 +981,15 @@ func (p *chatPicker[T]) renderInline(width int) []string {
for i := start; i < end; i++ {
item := filtered[i]
selected := i == p.cursor
badge := p.itemBadge(item)
for j, line := range wrapChatText(p.itemTitle(item), max(10, width-2)) {
marker := " "
if selected && j == 0 {
marker = " "
}
if j == 0 && badge != "" {
line += " " + chatResumeMetaStyle.Render("("+badge+")")
}
if selected {
lines = append(lines, truncateRenderedLine(chatResumeSelectedStyle.Render(marker+line), width))
} else {
@ -1006,9 +1017,6 @@ func modelOptionMeta(model ModelOption, current string) string {
if model.Description != "" {
parts = append(parts, model.Description)
}
if model.RequiredPlan != "" {
parts = append(parts, model.RequiredPlan+" plan")
}
return strings.Join(parts, " · ")
}