Skip to content

fix(doubao): adapt to 2026-07 DOM refactor - #2133

Closed
RusianHu wants to merge 3 commits into
jackwener:mainfrom
RusianHu:fix/doubao-2026-07-dom-refactor
Closed

fix(doubao): adapt to 2026-07 DOM refactor#2133
RusianHu wants to merge 3 commits into
jackwener:mainfrom
RusianHu:fix/doubao-2026-07-dom-refactor

Conversation

@RusianHu

Copy link
Copy Markdown

Problem

The doubao adapter is broken against Doubao's 2026-07 web refactor: ask, read, detail, and history all fail. The refactor removed data-testid attributes and renamed several CSS classes, so the adapter's selectors no longer match.

Symptoms on opencli v1.8.6:

  • doubao askCould not find Doubao input element (composer selector stale)
  • doubao readNo visible Doubao messages were found (message-list selector stale)
  • doubao historyNo conversation history found (sidebar selector stale)
  • doubao detailNo messages found. Verify the conversation ID. (detail script stale)

Root cause

  1. Composer: input is now a Semi Design <textarea class="semi-input-textarea"> with placeholder 发消息或按住空格说话...; data-testid="chat_input_input" was removed.
  2. Message list: container class is now list_items (previously matched via [class*="message-list-"] etc.).
  3. Sidebar: data-testid="flow_chat_sidebar" / chat_list_thread_item removed; sidebar now uses left-side-/w-sidebar-width classes, thread items are a[href*="/chat/"].
  4. Visibility check: the browser bridge operates on a 0x0/background tab where getBoundingClientRect().width === 0 for every element, so isVisible's width > 0 && height > 0 rejected everything — including the composer and message items that are nonetheless present and usable/readable.

Changes (clis/doubao/utils.js)

  • Composer selectors: prepend textarea.semi-input-textarea and textarea[placeholder*="发消息"].
  • isVisible (composer + getTurnsScript): relax width > 0. In a 0x0/background tab elements have zero width but are still present and readable; require height > 0 (composer) or drop the size check (message turns). display:none / visibility:hidden / hidden are still filtered.
  • getTurnsScript: add [class*="list_items"] to message-list selectors so messages are read via structured turns (clean) instead of falling back to the noisy transcript.
  • getTranscriptLinesScript: scope to the main chat area (sidebar's sibling) and strip header (title + disclaimer), input area (buttons), and follow-up suggestion chips, so the transcript fallback stays clean.
  • getConversationListScript (history): sidebar via [class*="left-side-"], [class*="w-sidebar-width"], thread items via a[href*="/chat/"].
  • getConversationDetail (detail): reuse getDoubaoVisibleTurns; the old data-testid-based detail script is fully stale.
  • prepareDoubaoComposerScript: include viewport/url/textarea details in the failure reason to aid future debugging.

Verification

End-to-end on opencli v1.8.6 against current doubao web (2026-07):

Command Result
doubao status ✅ Connected
doubao history ✅ lists 20 conversations
doubao detail <id> ✅ clean User/Assistant turns, no sidebar/follow-up noise
doubao read ✅ reads current conversation
doubao new ✅ creates new conversation
doubao ask "1加1等于几?请只回答数字" ✅ returns clean 2, no noise
  • Existing doubao unit tests: 32/32 pass (npx vitest run clis/doubao/)
  • npx tsc --noEmit: pass

Notes

  • The 0x0-viewport visibility issue is worth highlighting: it affects any adapter whose bridge tab is backgrounded/minimized. The relaxation here is scoped to doubao's composer + turns isVisible, so it should not affect other adapters.
  • Selector changes are additive (nothing removed) to preserve the 2026-05 fallback paths and existing unit-test fixtures.

@jackwener

Copy link
Copy Markdown
Owner

Reviewed for the low-risk PR sweep. I am not treating this as rejected, but I would defer it from this merge batch.

This is adapter-local and the selector direction may be right, but the claimed breakage/fix depends on current logged-in Doubao UI evidence. The branch currently has no reported GitHub checks and does not add regression fixtures for the new semi-input-textarea / list_items / sidebar selectors. It also changes detail behavior by replacing the old detail script with getDoubaoVisibleTurns() and returning meeting: null, which is probably acceptable for chat turns but needs explicit validation because this adapter also has meeting-summary/transcript helpers nearby.

Recommended disposition: keep open/defer until someone can attach current live trace evidence or DOM fixtures and add focused tests for the new selectors/history/detail behavior. I would not merge it solely from the PR description.

RusianHu and others added 2 commits September 1, 2026 00:12
Doubao's 2026-07 web refactor removed data-testid attributes and changed
several CSS class names, breaking the doubao adapter (ask/read/detail/
history all failed). Update selectors and relax the visibility check so
the adapter works against the current DOM.

- Composer: prepend `textarea.semi-input-textarea` and
  `textarea[placeholder*="发消息"]` (Semi Design textarea; data-testid removed)
- isVisible (composer + getTurnsScript): relax width>0. The browser bridge
  runs on a 0x0/background tab where elements have zero width but are still
  present and usable; require height>0 (composer) or drop the size check
  (message turns)
- getTurnsScript: add `[class*="list_items"]` to message-list selectors so
  messages are read via structured turns instead of the noisy transcript
- getTranscriptLinesScript: scope to the main chat area (sidebar's sibling)
  and strip header/input-area/follow-up chips so the transcript fallback
  stays clean
- getConversationListScript (history): sidebar via left-side-/w-sidebar-width,
  thread items via `a[href*="/chat/"]`
- getConversationDetail (detail): reuse getDoubaoVisibleTurns; the old
  data-testid-based detail script is fully stale
- prepareDoubaoComposerScript: include viewport/url/textarea details in the
  failure reason to aid future debugging

Verified end-to-end on opencli v1.8.6 against current doubao web:
status, history, detail, read, new, ask all pass; ask returns a clean
response with no sidebar/follow-up noise. Existing doubao unit tests
(32) and tsc --noEmit pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Add 'div.tiptap.ProseMirror' composer selector: the /chat/ new-thread
  page now renders a tiptap ProseMirror editor instead of the Semi
  textarea (verified live 2026-08-31, fixture included).
- sendDoubaoMessage: when no clickable send button is found, dispatch a
  synthetic KeyboardEvent('Enter') on the composer before falling back
  to native keys. The new composer's send control is a
  div.send-btn-wrapper with no button/[role=button] semantics, and CDP
  key events do not reach the tiptap keymap; the synthetic dispatch is
  verified to submit on the live site.
- getConversationDetail: prefer the legacy detail script (keeps meeting
  info wherever it still works) and only fall back to
  getDoubaoVisibleTurns when it returns no messages.
- Tests: JSDOM coverage for the ProseMirror submit path, the submit
  strategy order, and the detail fallback; live-captured composer
  fixture.
@RusianHu
RusianHu force-pushed the fix/doubao-2026-07-dom-refactor branch from ae1d4f3 to ad94659 Compare August 31, 2026 16:18
…ms, sidebar)

Export getConversationListScript and DOUBAO_COMPOSER_SELECTORS via
__test__ and add focused tests: composer selector coverage (Semi
textarea + ProseMirror), the 2026-07 list_items turns container, and
sidebar resolution via left-side-/w-sidebar-width classes with
a[href*="/chat/"] (including the legacy testid-only sidebar returning
empty).
@RusianHu

Copy link
Copy Markdown
Author

Updated the branch with 2026-08 live evidence and the review asks:

1. Current logged-in doubao.com evidence (2026-08-31, all verified live)

  • The composer has drifted again since this PR was opened: the /chat/ new-thread page now renders a tiptap ProseMirror editor (div.tiptap.ProseMirror, contenteditable, no textarea, no #flow-end-msg-send). The send control is div.send-btn-wrapper — a plain div with no button/[role=button] semantics — so the button-scoring path cannot find it, and CDP-level keys (nativeKeyPress/pressKey) do not reach the tiptap keymap.
  • Verified submission path on the live site: dispatching a synthetic KeyboardEvent('Enter') (key/code/keyCode/which) on the editor submits reliably. This commit wires that in as the fallback between button-click and native keys (submittedBy: 'synthetic-enter').
  • Live-captured composer DOM committed as a fixture: clis/doubao/__fixtures__/composer-2026-08-prosemirror.html (input-bar subtree only, no personal data).
  • Functional runs on the current DOM: validate doubao PASS (12 commands), doubao sendSubmittedBy: button + read-back verified, doubao ask ×3, doubao history/detail/read/status all verified.

2. Regression tests added (vitest + JSDOM, 38/38 green)

  • Composer selector coverage: textarea.semi-input-textarea (2026-07) + div.tiptap.ProseMirror (2026-08).
  • Submit strategy: synthetic-Enter path (synthetic-enter, native keys untouched) + updated native-Enter fallback ordering.
  • JSDOM run of syntheticEnterSubmitScript against the live-captured fixture, plus no-composer negative case.
  • Turns extraction keeps the 2026-07 list_items container.
  • Sidebar: conversation list resolves via left-side-/w-sidebar-width + a[href*="/chat/"] and returns empty for the legacy testid-only sidebar.

3. detail behavior change made legacy-first
getConversationDetail now prefers the legacy detail script (preserving meeting info wherever it still works) and only falls back to getDoubaoVisibleTurns when it returns no messages. Both paths are covered by tests, including the meeting: null fallback case.

Note: I also verified the 2026-08 ProseMirror + synthetic-Enter behavior end-to-end outside the adapter (image-edit/generation flows driven through the browser bridge today), so the mechanism is not speculative.

@RusianHu

RusianHu commented Sep 1, 2026

Copy link
Copy Markdown
Author

Closing this as superseded — @jackwener's defer call aged well. Live re-verification on 2026-09-01 (logged-in doubao.com) disproved this branch's core mechanism:

What changed since the 2026-08-31 update

  • The send control is button#flow-end-msg-send again (a real button, visible and enabled with text in the composer). The 2026-08 div.send-btn-wrapper state this branch adapted to is gone.
  • A synthetic KeyboardEvent('Enter') on the tiptap composer no longer submits — verified live: the composer keeps its text while the URL still flips to /chat/local_<id> and the user bubble renders optimistically, so the server never sees the message. That is the exact mechanism this PR introduced as the submit path (syntheticEnterSubmitScript), so the branch would now silently no-op sends.
  • Upstream main has meanwhile evolved past the 2026-07 DOM state this PR started from (it already carries the #flow-end-msg-send direct-click path), so the selector half of the diff is also stale.

What survived, and where it went

Two of the findings from re-testing this area were real and are now folded into #2447 instead of kept here:

  • A swallowed submit is invisible to URL/bubble checks — the composer clearing is the only reliable post-submit signal, and the submit should escalate across click flavors (JS click → native Enter → trusted CDP click).
  • Collapsed bridge viewports (0x0, window hidden) defeat coordinate clicks — surfaced via Page.bringToFront before clicking; same failure class as fix(chatgpt): adapt to 2026-08 chatgpt.com UI and zero-size bridge viewports #2436 (chatgpt).

Thanks for the review push on evidence-first fixtures — the fixtures/tests added here died with the mechanism they pinned, which is itself a data point on how fast this site churns. The live-verified versions of both ideas are in #2447 with 2026-09-01 evidence.

@RusianHu RusianHu closed this Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants