mirror of
https://github.com/usestrix/strix.git
synced 2026-08-17 01:29:42 +02:00
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:
@@ -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),
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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 = [
|
||||
|
||||
Reference in New Issue
Block a user