fix(chatgpt): adapt to 2026-08 chatgpt.com UI and zero-size bridge viewports - #2436
Open
RusianHu wants to merge 3 commits into
Open
fix(chatgpt): adapt to 2026-08 chatgpt.com UI and zero-size bridge viewports#2436RusianHu wants to merge 3 commits into
RusianHu wants to merge 3 commits into
Conversation
RusianHu
force-pushed
the
fix/chatgpt-2026-08-viewport-and-model
branch
2 times, most recently
from
August 29, 2026 17:19
f52041b to
d4f6ec0
Compare
…ewports - Conversation discovery: sidebar entries are now attribute-less buttons (no /c/ anchors); getConversationList prefers the page-context backend-api route and keeps anchor extraction as a fallback - Message/image extraction: when the bridge window viewport is 0x0 (visibilityState still 'visible'), fluid-width node rects collapse to 0 and every rect-based visibility check fails; add clientWidth<=0 early exits to the isVisible implementations while keeping CSS display/visibility checks - Model switching: the new UI's model submenu is immune to synthetic events; the selector path stays as a fallback. Effort tiers now go through the page-context settings API (preserving the current model family); triggers gain a no-aria-label short-text button fallback with a full pointer-event sequence click - Upload preview: filename also matches aria-label (jackwener#2302); media nodes fall back to naturalWidth/videoWidth/background-image when the viewport is collapsed - Robustness: getCookies races a timeout; reload defers via setTimeout to avoid a synchronous-navigation hang inside evaluate; session fetch catches network interruptions Verified live against a logged-in zh-CN account: ask/history/detail/ read/image/image --image/model round-trips; chatgpt unit tests 180/180. Fixes jackwener#2435
RusianHu
force-pushed
the
fix/chatgpt-2026-08-viewport-and-model
branch
from
September 1, 2026 05:05
d4f6ec0 to
1144da8
Compare
This was referenced Sep 1, 2026
…26-09 frontend - parseChatGPTConversationId: the id character class now includes ':'; brand-new conversations route to /c/WEB:<uuid> where <uuid> is a client-side temporary id that never appears in the backend API - ask: when the parsed id is a WEB: temporary id, wait for the response first, then re-read the URL - the frontend swaps it for the real /c/<server-id> once generation finishes; fall back to the newest backend-api conversation listing (new resolveWebConversationId) when it still carries the WEB: prefix - ask: skip the leave-conversation URL guard on that path because the WEB: -> server-id swap is a legitimate navigation
…ecovery When ask times out (or otherwise fails mid-wait) after the message was sent, the conversation already exists on the server, but the thrown TimeoutError carried no conversation context - callers could not tell re-sending from waiting, and had to dig through chatgpt history to find the id. - attachConversationContext(): append [conversationId=... conversationUrl=...] to the error message and a ready-to-run 'opencli chatgpt detail <id>' recovery hint, mutating the caught error in place so code/exitCode (TIMEOUT/75) stay intact for script callers - readConversationContext(): re-read the current URL on failure, preferring the real server id if the frontend has already swapped out WEB:<uuid> - covered: both waitForChatGPTResponse branches (WEB: and regular) and the waitForConversationUrl 30s timeout (URL appended for diagnostics) Verified: ask --timeout 8 on a long-form prompt now reports the conversation id on TIMEOUT; 'detail <id>' then reads the session directly (no history detour). Success path regression-checked.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a cluster of
chatgptadapter failures against the 2026-08 chatgpt.com web UI (root cause report: #2435). All findings were reproduced against a real logged-in account (zh-CN UI) and verified end-to-end after the fix; the adapter's unit tests pass 180/180.Root causes found (verified live, see #2435 for details)
window.innerWidth/innerHeight === 0whiledocument.visibilityState === 'visible'(reproduced with--window foregroundtoo). The new chatgpt.com UI sizes message/image containers from the viewport, so fluid-width nodes reportrect.width === 0while their text renders fine. EveryisVisiblethat gates onrect.width > Nthen filters out exactly the nodes we need →askTIMEOUT,read/detailEMPTY,imagefinds no generated images.ul > li > buttonwith no attributes and no<a href="/c/...">anywhere in the document →historyEMPTY_RESULT.extended → 高,min → 中, zh-CN), and the thinking-effort options live in a 选择模型 submenu that ignores synthetic pointer/keyboard events entirely (full pointerdown/mousedown/pointerup/mouseup/click sequence, trusted-key attempts — all no-ops), so the picker path cannot reach intelligence options.body.innerTextmisses them.Changes (all in
clis/chatgpt/utils.js)isVisiblesites): whendocument.documentElement.clientWidth <= 0, skip the rect gate; CSSdisplay/visibilitychecks remain, so genuinely hidden aria-shadow copies are still excluded. On any normal viewport behavior is unchanged.getConversationListnow prefers the backend API (/api/auth/sessiontoken →/backend-api/conversations) executed in the page context; the anchor extraction is kept as fallback./backend-api/settings/user_last_used_model_config) run in the page context (the CLI host may not be able to reach chatgpt.com directly; the browser session always can). It keeps the account's current model family from theoai-last-model-configcookie and patches only the effort (fast→min,balanced→standard,advanced→extended,very-high→xhigh— vocabulary confirmed by the API's own enum validation). The visible picker stays the primary path; the API fallback only fires when the picker cannot reach the option or the postcondition fails. Server-side eligibility rejects invalid combos with the config untouched..click()does not open the menu) with coordinates returned as before so native clicks still work on real viewports.aria-labels as well as visible text; media nodes in zero-size viewports are accepted vianaturalWidth/videoWidth/background-image presence.waitForChatGPTImagesnow fails fast with the refusal text in the error instead of burning the full--timeouton a state that will never produce images. Conservative gating: requires two consecutive quiet polls with substantive (≥16 char) assistant text; if message extraction is unavailable it falls back to the existing deadline behavior. Covered by two new unit tests (182/182pass).getCookies()calls race an 8s timeout (the full-jar call was observed to hang the daemon bridge); the post-PATCH reload is scheduled viasetTimeout(reloading synchronously insideevaluatedestroys the execution context and leaves the promise pending forever); the session fetch inbuildChatGPTBackendHeaderscatches network aborts instead of surfacingAbortError.Verification
ask(new + continuation),history,detail,read,whoami,status,new,image(text-to-image),image --image(edit),model(fast → advanced round trip, confirmed server-side via the config cookie).npx vitest run clis/chatgpt→ 180/180 pass.opencli validate chatgpt→ PASS (14 commands).Notes for reviewers: the zero-size viewport is a property of our bridge environment (Windows, extension-connected daemon); the
clientWidth <= 0guards are no-ops on normal viewports. The history API path is strictly more robust than DOM anchors but the anchor fallback is retained in case the UI regresses or another locale renders anchors.Update 2026-09-03:
/c/WEB:<uuid>temporary route ids (new commit)Re-testing
askagainst the live site on 2026-09-03 surfaced a further frontend change that also breaks upstreammain, so it belongs in this PR:Symptom.
asksends the message and the model replies (server-side conversation is created), but the CLI fails withChatGPT did not create a conversation URL after sending the message.Root cause (verified live). Brand-new conversations now route to
/c/WEB:<uuid>:<uuid>is a client-side temporary id — it never appears inbackend-api, and it is not the real conversation id. Navigating directly to/c/WEB:<uuid>bounces back to the home page.:, which the oldparseChatGPTConversationIdcharacter class ([A-Za-z0-9_-]) rejects, sowaitForConversationUrltimes out after 30 s./c/<server-id>.Fix (second commit,
clis/chatgpt/utils.js+clis/chatgpt/ask.js):parseChatGPTConversationId: the id character class now includes:soWEB:ids parse.ask: when the parsed id is aWEB:temporary id, wait for the response first, then re-read the URL — if the frontend has already swapped in the real id, use it; otherwise fall back to the newest entry of the backend-api conversation listing (newresolveWebConversationIdhelper, reuses the existing page-context fetch fromgetConversationList).WEB:→ server-id swap is a legitimate navigation, and the old guard false-fires on it.Verification (same battery as above, re-run after this commit):
ask(new conversation) → returns the real server-side id and correct response;ask --conversation <real-id>continuation works.npx vitest run --project adapter clis/chatgpt/→ 164/164 pass.npx tsc --noEmit→ clean.npx tsx src/main.ts validate chatgpt→ PASS (14 commands).Fixes #2435