Skip to content

feat: gate experimental pointer hover action - #658

Open
huyua9 wants to merge 11 commits into
alibaba:mainfrom
huyua9:feat/experimental-pointer-actions-huyua9
Open

feat: gate experimental pointer hover action#658
huyua9 wants to merge 11 commits into
alibaba:mainfrom
huyua9:feat/experimental-pointer-actions-huyua9

Conversation

@huyua9

@huyua9 huyua9 commented Aug 5, 2026

Copy link
Copy Markdown

Summary

  • add opt-in experimentalPointerActions configuration to the agent and page controller
  • expose hover_element_by_index only when the experimental flag is enabled
  • dispatch pointer/mouse hover events without clicking and add focused core/controller tests
  • preserve synthetic hover transitions into descendants with relatedTarget and without premature leave events
  • dispatch enter events along newly entered ancestor paths
  • preserve the full synthetic hover ancestry and clear it when leaving the subtree
  • clear stale synthetic hover state before non-hover pointer actions
  • route the experimental hover action and flag through the extension remote/background/content controllers
  • clarify that synthetic hover events do not activate CSS :hover

Related to #222.

Validation

  • npm test --workspace=@page-agent/page-controller (11 tests)
  • cd packages/core && npx vitest run --config vitest.config.js (22 tests)
  • git diff --check
  • npx tsc --noEmit -p packages/extension/tsconfig.json was attempted but is blocked by existing repository environment issues (.wxt/tsconfig.json, WXT globals, CSS module declarations, and simple-icons type resolution); no errors were reported in the changed extension controller files.

The change is intentionally opt-in and does not alter the default tool surface.

…mentalPointerActions

Implement the maintainer's preferred scope for alibaba#222: expose a single
experimental pointer-based action (hover) only when
experimentalPointerActions: true is set on both PageControllerConfig
and AgentConfig. Disabled by default so the tool surface stays minimal
until real usage shows the value.

Mirrors the existing experimentalScriptExecutionTool pattern:
- PageController.hoverElement(index) returns an explanatory failure
  when the flag is off, and dispatches pointerover/pointerenter +
  mouseover/mouseenter otherwise.
- PageAgentCore deletes hover_element_by_index from this.tools at
  construction unless experimentalPointerActions is true.

Extension bridge is intentionally untouched.

Tests cover tool gating in PageAgentCore and the hoverElement method
behavior in PageController.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ebc834a84f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/page-controller/src/actions.ts
@huyua9
huyua9 force-pushed the feat/experimental-pointer-actions-huyua9 branch from ebc834a to 599b494 Compare August 5, 2026 08:04

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 599b494a71

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/core/src/PageAgentCore.ts Outdated
Comment thread packages/page-controller/src/actions.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 52998961f5

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/page-controller/src/actions.ts Outdated
@huyua9

huyua9 commented Aug 5, 2026

Copy link
Copy Markdown
Author

Addressed the current review feedback in e7cb8ba37db15c72e239b2f674a457b49ef6375d:

  • Track the previous synthetic hover target and dispatch leave events when moving to a different subtree.
  • Preserve relatedTarget and suppress leave events for transitions into descendants, so menu-level handlers do not close prematurely.
  • Apply the built-in experimental gate before customTools, preserving caller-provided hover_element_by_index overrides.
  • Clarify the result and docs that synthetic events can invoke JavaScript hover handlers but cannot activate CSS :hover.

Validation: page-controller 8/8, core 22/22, and git diff --check pass. The PR body records the existing repository typecheck environment blocker.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e7cb8ba37d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/core/src/tools/index.ts
@huyua9

huyua9 commented Aug 5, 2026

Copy link
Copy Markdown
Author

Follow-up for the extension-path review feedback: dd3281ee7b5969cad71b5353c70575e14afc086d now adds RemotePageController.hoverElement, forwards experimentalPointerActions through the background bridge, and dispatches hover_element_by_index to the content-side PageController without rebuilding its indexed tree. The controller capability remains gated by the agent flag.

Page-controller 8/8 and core 22/22 pass; the extension typecheck remains blocked by the repository's existing WXT/CSS/simple-icons environment errors.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd3281ee7b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/page-controller/src/PageController.ts Outdated
Comment thread packages/extension/src/agent/RemotePageController.content.ts Outdated
@huyua9

huyua9 commented Aug 5, 2026

Copy link
Copy Markdown
Author

Addressed the two latest P2 findings in f634c55e6175cb61064ab863f3c449cadb3ce376:

  • Before click/input/select actions target another subtree, the controller now dispatches synthetic hover leave events with relatedTarget and clears the stored hover state.
  • The extension content-side controller now applies the current experimentalPointerActions flag on every PAGE_CONTROL message, so capability does not remain enabled after a flagged run ends.

Validation is now page-controller 9/9, core 22/22, and git diff --check.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f634c55e61

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/page-controller/src/PageController.ts Outdated
@huyua9

huyua9 commented Aug 5, 2026

Copy link
Copy Markdown
Author

Addressed the latest P2 in bb78116e723225d036beccd0443cea4cb7582649:

  • Synthetic hover now retains the full hovered ancestry when entering descendants.
  • Leaving the menu dispatches leave events for the deepest item and its ancestor wrapper, so native non-bubbling mouseleave/pointerleave handlers can clean up correctly.
  • Added a wrapper → descendant → outside regression test.

Validation is now page-controller 10/10, core 22/22, and git diff --check.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bb78116e72

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/page-controller/src/actions.ts
@huyua9

huyua9 commented Aug 5, 2026

Copy link
Copy Markdown
Author

Addressed the latest P2 in 602c4f34d6c2a3a5b2fd6ffe86553bf967aa404b:

  • When hovering a descendant directly, synthetic pointerenter and mouseenter are now dispatched to each newly entered ancestor as well as the target.
  • Added a regression test covering direct child hover and ancestor enter listeners.

Validation is now page-controller 11/11, core 22/22, and git diff --check.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 602c4f34d6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

const elemText = this.elementTextMap.get(index)
await hoverElement(element, this.syntheticHoverPath)
const retained = this.syntheticHoverPath.filter((hovered) => hovered.contains(element))
this.syntheticHoverPath = retained.includes(element) ? retained : [...retained, element]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Track ancestors that receive synthetic enter

With the new ancestor-enter dispatch, a direct hover on a child now fires mouseenter/pointerenter on wrappers, but this state update still records only the target when there was no previously retained ancestor. In that scenario, the next click or hover outside calls clearSyntheticHover with a path containing only the child, so native non-bubbling leave listeners on the wrapper never run and JS-opened menus/tooltips can remain stuck open; store the full entered ancestor path, not just the indexed element.

Useful? React with 👍 / 👎.

@huyua9

huyua9 commented Aug 5, 2026

Copy link
Copy Markdown
Author

Addressed the latest P2 in 739cf43b162e11a7c3b072518f51168e50a8ae64:

  • hoverElement now returns the complete ancestor path that received synthetic enter events.
  • PageController retains that full path, so direct child hover is fully cleared when a later action leaves the subtree.
  • Added a regression test covering direct child hover followed by a click outside, verifying the wrapper receives pointerleave and mouseleave.

Validation: page-controller 12/12, core 22/22, and git diff --check pass.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 739cf43b16

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

this.assertIndexed()
const element = getElementByIndex(this.selectorMap, index)
const elemText = this.elementTextMap.get(index)
this.syntheticHoverPath = await hoverElement(element, this.syntheticHoverPath)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear hover state when the run ends

When hover_element_by_index is the last action in a task, or the run is stopped before a later click/input/select, the synthetic hover path stored here is never transitioned out: the agent’s normal teardown only cleans highlights/mask, and dispose() now drops the path without dispatching leave events. For JS-controlled menus/tooltips that close in mouseleave/mouseout, this leaves the page in a hovered/open state for the user or the next task until some later pointer action happens; clear the synthetic hover with leave/out events during task/controller cleanup as well.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d3e015863c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/page-controller/src/actions.ts Outdated

if (!movingWithinPreviousElement) {
previousElement.dispatchEvent(
new PointerEvent('pointerleave', { bubbles: false, relatedTarget })

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve mouse pointerType when clearing hover

When a component opens/closes hover state in pointer handlers that filter for event.pointerType === 'mouse', the synthetic enter path supplies pointerType: 'mouse', but this leave path creates pointerleave without it. Browser mouse leave events carry the mouse pointer type; here the synthetic event defaults to an empty pointer type, so those close handlers can ignore the cleanup and leave JS-opened menus/tooltips stuck after the agent moves or clicks away. Include the same pointer metadata on the synthetic pointerout/pointerleave events.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4cf203d6ae

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

this.assertIndexed()
const element = getElementByIndex(this.selectorMap, index)
const elemText = this.elementTextMap.get(index)
this.syntheticHoverPath = await hoverElement(element, this.syntheticHoverPath)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clear prior click hover before synthetic hovers

When an agent clicks an element that opened hover-driven UI and then calls hover_element_by_index on a different, non-contained element before another click/input, the clicked element never receives the synthetic pointerleave/mouseleave that clickElement() defers via its module-level lastClickedElement. This path only transitions syntheticHoverPath, so a menu or tooltip opened by the click action's hover events can stay open and interfere with the subsequent hover/observation until a later click happens.

Useful? React with 👍 / 👎.

@huyua9

huyua9 commented Aug 7, 2026

Copy link
Copy Markdown
Author

Addressed the two latest Codex P2 findings in 8ad0772deaa8b2e2651ab16cb9ac1f7ebc83f395.

  • Synthetic hover now clears any prior click hover before dispatching the next hover transition.
  • The click cleanup path now emits pointerout/pointerleave with pointerType: "mouse".
  • Added a regression test covering click-then-hover cleanup and pointer metadata.

Validation:

  • npm test --workspace @page-agent/page-controller — 15 passed.
  • npx eslint packages/page-controller/src/actions.ts packages/page-controller/src/PageController.test.ts — passed.
  • git diff --check — passed.

The repository-wide typecheck remains blocked by the existing extension .wxt/CSS/simple-icons environment declarations; the page-controller test suite is green.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8ad0772dea

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


await movePointerToElement(element, x, y)

const pointerOpts = {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Set composed on synthetic hover events

When the indexed target is inside a web component shadow root (the DOM walker already descends into node.shadowRoot), these constructed pointer/mouse events default to composed: false, so the bubbling pointerover/mouseover events never cross to the host or document. Components that attach hover handlers on the host will not open/close even though hover_element_by_index reports success; include composed: true for the synthetic hover/leave events that should escape the shadow boundary.

Useful? React with 👍 / 👎.

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.

1 participant