jackwener / jackwener/OpenCLI

[Bug]: chatgpt model cannot switch tiers — the picker is now a Radix popover that ignores synthetic events

Open
#2,462 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
29.5k
Forks
2.9k
Avg merge
15h 36m
Merged PRs (30d)
70

Description

### Description

`opencli chatgpt model ` can no longer switch tiers on the current chatgpt.com frontend (observed 2026-09-05, opencli 1.8.7, extension v1.0.24, zh-TW Pro account).

This is a root-cause report, not a fix. I could not repair it at the adapter layer; the evidence points at the page abstraction.

The error message changes with how far the adapter gets, so there are three stacked breakages:

| State | Error |
|---|---|
| Stock 1.8.7 | `Could not find the ChatGPT model selector in the composer.` |
| After teaching it the new button selector | `ChatGPT model did not switch to .` |
| After also fixing tier readback | `Could not click the ChatGPT model option.` |

### Steps to Reproduce

1. `opencli chatgpt model pro --window background --trace retain-on-failure`

```
ok: false
error:
code: COMMAND_EXEC
message: Could not find the ChatGPT model selector in the composer.
```

2. Rule out auth: `opencli chatgpt status` reports `Connected`, `Login: 'Yes'`, and `opencli chatgpt whoami` resolves the account.

3. Inspect the picker button on the live bound tab:

```
opencli browser eval "(() => { const p = document.querySelector('button[class*=\"__composer-pill\"]'); return JSON.stringify({ testid: p.getAttribute('data-testid'), aria: p.getAttribute('aria-label'), haspopup: p.getAttribute('aria-haspopup') }); })()"
→ {"testid":null,"aria":null,"haspopup":"menu"}
```

4. Open it with a real CDP click, then read the menu:

```
opencli browser click "button[class*=__composer-pill]"
opencli browser eval "JSON.stringify(Array.from(document.querySelectorAll('[role=\"menuitemradio\"]')).map(r => r.textContent.trim()))"
→ ["最新的","GPT-5.6 Sol","GPT-5.5"]
```

### Expected Behavior

`opencli chatgpt model pro` selects the Pro tier and reports `Success` or `Already selected`.

### Root cause

**1. The picker button lost every selector the adapter looks for.**

`menuButtonSelectors` looks for `button[data-testid="model-switcher-dropdown-button"]` and `button[aria-label*=...]`. The current button has neither — no `data-testid`, `aria-label` is `null`. It is identifiable only by class and popup attributes:

```
class="__composer-pill __composer-pill--neutral ..."
aria-haspopup="menu" aria-expanded="false" data-state="closed"
id="radix-_r_4e_" interestfor="_r_4g_"
style="anchor-name: --anchor-_r_4g_;"
```

The `radix-*` id, `interestfor`, and `anchor-name` indicate Radix UI on top of the HTML Popover API, Interest Invokers, and CSS Anchor Positioning. (Those generated ids differ per render — they are shown as evidence of the stack, not as stable selectors.)

**2. The tier list is no longer a set of menu items — it is a slider.**

With the popover open, `[role="menuitemradio"]` yields three entries, and they are *model families*, not tiers: `["最新的", "GPT-5.6 Sol", "GPT-5.5"]`.

The tier itself is a slider. The menu's accessible text reads (zh-TW): 「第 5 項,共 5 項。使用向左鍵與向右鍵調整效能。」 — item 5 of 5, adjust with left/right arrow keys.

This breaks the `intelligenceOptions.length === 5` branch in `selectChatGPTModel`, which assumes five clickable tier options.

**3. Tier readback parses the button text, which no longer word-breaks.**

`getCurrentChatGPTModel` falls back to matching the composer button's `textContent` against known labels using:

```js
new RegExp('(^|\\b)' + label + '(\\b|$)', 'i')
```

The button's `textContent` is now `"6Pro"` with no separator. `6` and `P` are both word characters, so there is no `\b` between them and `\bPro\b` cannot match; the current tier reads as `null`. Locally, `(?

Contributor guide

Open the contributing guide

Research direction

Start with selectChatGPTModel, getCurrentChatGPTModel, setChatGPTModelConfig, and the page.nativeClick path, then reproduce with `opencli chatgpt model pro --window background --trace retain-on-failure`. Done means the live ChatGPT picker reliably selects the requested tier and reports Success or Already selected; the issue notes that keyboard navigation or a single-context locate-and-click flow still needs verification.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
cli, devtools
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.