fix(tui): show the actual subscription provider in the Go TUI

The Go TUI rewrite hardcoded "ChatGPT subscription" in the stats view and its
snapshot only carried a boolean, so a Grok run was labeled ChatGPT — the same
bug previously fixed on the Python side. Carry the provider label through the
snapshot protocol and render it, falling back to a generic "Subscription".

utils._subscription_label becomes public subscription_label since the TUI
backend now needs it too.
This commit is contained in:
yoni
2026-08-13 03:26:22 +00:00
parent cd3250576c
commit d4573a3197
8 changed files with 52 additions and 9 deletions
+5 -1
View File
@@ -24,7 +24,7 @@ from strix.interface.tui.backend.projection import (
sanitize_terminal_text,
terminal_projection,
)
from strix.interface.utils import is_subscription_run
from strix.interface.utils import is_subscription_run, subscription_label
if TYPE_CHECKING:
@@ -162,8 +162,11 @@ class TuiController:
if self.report_state is not None:
usage = dict(self.report_state.get_total_llm_usage())
subscription = False
subscription_name = ""
with contextlib.suppress(Exception):
subscription = is_subscription_run(self.report_state)
if subscription:
subscription_name = subscription_label(self.report_state)
model_warning = ""
if model and not is_recommended_or_frontier_model(model):
model_warning = (
@@ -200,6 +203,7 @@ class TuiController:
],
"usage": terminal_projection(usage, max_string=256, max_items=20),
"subscription": subscription,
"subscription_label": terminal_projection(subscription_name, max_string=64),
"viewer_status": self.viewer_status,
"viewer_url": terminal_projection(self.viewer_url, max_string=1024),
"error": terminal_projection(self.error, max_string=2 * 1024),
@@ -175,6 +175,7 @@ def bounded_state_projection(state: dict[str, Any]) -> dict[str, Any]:
"messages": [],
"usage": {},
"subscription": state["subscription"],
"subscription_label": state["subscription_label"],
"viewer_status": state["viewer_status"],
"viewer_url": None,
"error": terminal_projection(state["error"], max_string=256),
+13 -2
View File
@@ -1067,11 +1067,12 @@ func TestBudgetPauseShowsOneWarningToastUntilResumed(t *testing.T) {
func TestStatsViewShowsSubscription(t *testing.T) {
model := New(nil)
model.snapshot.Model = "gpt-5"
model.snapshot.Model = "grok/grok-4"
model.snapshot.Subscription = true
model.snapshot.SubscriptionLabel = "Grok subscription"
model.snapshot.Usage = map[string]any{"total_tokens": float64(1200), "cost": 3.5}
stats := ansi.Strip(model.statsView())
if !strings.Contains(stats, "ChatGPT subscription") {
if !strings.Contains(stats, "Grok subscription") {
t.Fatalf("stats missing subscription line: %q", stats)
}
if strings.Contains(stats, "$") {
@@ -1079,6 +1080,16 @@ func TestStatsViewShowsSubscription(t *testing.T) {
}
}
func TestStatsViewSubscriptionFallsBackWithoutLabel(t *testing.T) {
model := New(nil)
model.snapshot.Model = "gpt-5"
model.snapshot.Subscription = true
stats := ansi.Strip(model.statsView())
if !strings.Contains(stats, "Subscription") {
t.Fatalf("stats missing generic subscription line: %q", stats)
}
}
func TestVulnerabilityMarkdownReport(t *testing.T) {
report := vulnerabilityMarkdownReport(map[string]any{
"title": "SQLi in login",
+5 -1
View File
@@ -596,7 +596,11 @@ func (m Model) statsView() string {
if b.Len() > 0 {
b.WriteString("\n")
}
b.WriteString(lipgloss.NewStyle().Foreground(green).Render("ChatGPT subscription"))
label := m.snapshot.SubscriptionLabel
if label == "" {
label = "Subscription"
}
b.WriteString(lipgloss.NewStyle().Foreground(green).Render(label))
}
total := numberValue(m.snapshot.Usage["total_tokens"])
if total > 0 {
@@ -68,6 +68,7 @@ type Snapshot struct {
Vulnerabilities []map[string]any `json:"-"`
Usage map[string]any `json:"usage"`
Subscription bool `json:"subscription"`
SubscriptionLabel string `json:"subscription_label"`
ViewerStatus string `json:"viewer_status"`
ViewerURL *string `json:"viewer_url"`
Error *string `json:"error"`
+3 -3
View File
@@ -267,7 +267,7 @@ def is_subscription_run(report_state: Any) -> bool:
return subscription.auth_mode(load_settings().llm.model) == "subscription"
def _subscription_label(report_state: Any) -> str:
def subscription_label(report_state: Any) -> str:
"""Human label for the active model subscription (e.g. "Grok subscription").
Prefers the persisted run record so a resumed run keeps its original provider
@@ -386,7 +386,7 @@ def build_live_stats_text(report_state: Any) -> Text:
stats_text.append(str(model), style="white")
if is_subscription_run(report_state):
stats_text.append(" · ", style="dim white")
stats_text.append(_subscription_label(report_state), style="#22c55e")
stats_text.append(subscription_label(report_state), style="#22c55e")
stats_text.append("\n")
vuln_count = len(report_state.vulnerability_reports)
@@ -432,7 +432,7 @@ def build_tui_stats_text(report_state: Any) -> Text:
subscription = is_subscription_run(report_state)
if subscription:
stats_text.append("\n")
stats_text.append(_subscription_label(report_state), style="#22c55e")
stats_text.append(subscription_label(report_state), style="#22c55e")
usage = _llm_usage(report_state)
if usage and _int_stat(usage, "total_tokens") > 0:
+2 -2
View File
@@ -66,12 +66,12 @@ def test_subscription_label_prefers_persisted_provider(monkeypatch) -> None: #
resumed = mock.MagicMock(
run_record={"auth_mode": "subscription", "subscription_provider": "Grok"}
)
assert utils._subscription_label(resumed) == "Grok subscription"
assert utils.subscription_label(resumed) == "Grok subscription"
# With no persisted provider, it derives the label from settings (not a
# hardcoded default).
fresh = mock.MagicMock(run_record={})
assert utils._subscription_label(fresh) == "ChatGPT subscription"
assert utils.subscription_label(fresh) == "ChatGPT subscription"
def test_persisted_run_record_carries_provider(tmp_path, monkeypatch) -> None: # type: ignore[no-untyped-def]
+22
View File
@@ -110,6 +110,28 @@ def test_state_populates_model_warning_for_non_frontier_model() -> None:
assert "not a recommended frontier model" in warning
def test_snapshot_carries_the_subscription_provider_label() -> None:
os.environ["STRIX_LLM"] = "grok/grok-4"
loader._cached = None
snapshot = TuiController(args()).snapshot()
# The TUI renders this label, so it must name the actual provider rather
# than assuming ChatGPT.
assert snapshot["subscription"] is True
assert snapshot["subscription_label"] == "Grok subscription"
def test_snapshot_has_no_subscription_label_for_api_key_runs() -> None:
os.environ["STRIX_LLM"] = "openai/gpt-5.4"
loader._cached = None
snapshot = TuiController(args()).snapshot()
assert snapshot["subscription"] is False
assert snapshot["subscription_label"] == ""
def test_setup_restores_prepared_cli_targets() -> None:
setup_args = args()
setup_args.targets_info = [