Skip to content

[feat]: expose timeout param in ts & protocol - #3033

Open
seanmcguire12 wants to merge 3 commits into
share-progress-in-locator-inputs-and-highlightsfrom
expose-timeout-param-schemas-ts
Open

seanmcguire12 wants to merge 3 commits into
share-progress-in-locator-inputs-and-highlightsfrom
expose-timeout-param-schemas-ts

Conversation

@seanmcguire12

@seanmcguire12 seanmcguire12 commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

why

this PR adds the timeout param to the protocol, & exposes it publicly in ts. the default timeout is 20 seconds

what changed

  • added optional timeout settings to all 17 terminal locator methods, including reads. typescript callers can use click({ timeout: 5000 }), fill("hello", { timeout: 5000 }), or count({ timeout: 0 }).
  • started one deadline before frame resolution & passed it through the whole call. frame readiness, element lookup, typing delays, highlight duration, & extension-side upload preparation all share that budget.
  • aligned typescript response waits with the execution timeout plus delivery grace. zero disables that response deadline too. long timeouts avoid the JS timer limit, & timeout errors retain their name & message.
  • made the compatibility facade pass its remaining budget to native locator calls, including zero, instead of dropping timeout options

test plan

  • locator-timeouts.test.ts checks every registered locator method accepts zero & positive timeouts, rejects invalid values, preserves omission, & keeps existing options working. timeout settings stay separate from locator identity.
  • runtime-locator-timeouts.test.ts uses controlled time to verify every entry point starts its deadline before resolution, applies the default or override, rejects stalled work, & leaves zero unlimited.
  • wrapper, rpc, & package tests cover option forwarding, the public options type, response deadlines & delivery grace, long timers, & timeout error details. facade tests check remaining-budget forwarding for ordinary & frame locators.
  • iframeLocatorReadiness.test.ts runs against real chrome with same-process frames & frames in a separate process. it verifies nested frame readiness & typing share one budget, explicit timeouts can exceed the old readiness cap, zero waits successfully, & loading a frame after expiry does not cause a late click.
  • locatorActions.test.ts exercises highlight & upload cleanup through the runtime: stalled cleanup preserves an earlier action error & does not delay timeout rejection.

Summary by cubic

Adds a timeout option to all 17 terminal locator methods in the protocol and TypeScript SDK. The default is 20 seconds, and { timeout: 0 } disables the deadline.

What changed

  • One deadline starts before frame resolution and covers frame readiness, element lookup, typing delays, highlight duration, and upload preparation.
  • TS response deadlines match the execution timeout plus a delivery grace, with 0 disabling them.
  • The Playwright compatibility facade forwards its remaining budget to native locator calls, including zero.
  • Timeout errors retain the TimeoutError name and message, and long timeouts work around the JS timer limit.

Written for commit bf86ce1. Summary will update on new commits.

Review in cubic

@changeset-bot

changeset-bot Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: bf86ce1

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@seanmcguire12
seanmcguire12 added this pull request to stack #3025 September 24, 2026 18:22

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 24 files

Confidence score: 3/5

  • In packages/sdk-python/src/stagehand/_generated/models.py, LocatorFillParams references LocatorOptions before it is defined, which can leave locator.fill() validation incomplete; define LocatorOptions earlier or rebuild the model afterward.
  • In packages/sdk-python/src/stagehand/_generated/models.py, strict-float timeout fields reject ordinary integer values such as 0 and 5000, making the timeout option unusable with common Python inputs; accept strict integers alongside strict floats.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/sdk-python/src/stagehand/_generated/models.py">

<violation number="1" location="packages/sdk-python/src/stagehand/_generated/models.py:1064">
P2: These `StrictFloat` timeout fields reject integer millisecond values such as `0` and `5000`, making the new timeout option unusable with normal Python inputs. Accept strict integers alongside strict floats while retaining the nonnegative constraint.</violation>

<violation number="2" location="packages/sdk-python/src/stagehand/_generated/models.py:1111">
P1: `LocatorFillParams` now references `LocatorOptions` before its definition, leaving this Pydantic model incomplete for `locator.fill()` validation. Define `LocatorOptions` earlier or rebuild `LocatorFillParams` after all generated classes are defined.</violation>
</file>
Architecture diagram
sequenceDiagram
    participant TS as TypeScript SDK (Locator)
    participant RPC as RPCClient
    participant EXT as Extension Runtime
    participant ACT as Locator Actions
    participant FAC as Playwright Compat Facade

    Note over TS,FAC: Locator timeout propagation across all 17 methods

    TS->>RPC: send(locator.click, {pageId, selector, options:{timeout}})
    Note over RPC: NEW: rpcResponseTimeoutMs = timeout + grace (default 20s + 10s)
    Note over RPC: timeout=0 -> no response deadline

    RPC->>EXT: JSON-RPC request with LocatorParams

    EXT->>EXT: runLocator() starts Progress deadline
    Note over EXT: timeout=0 -> Infinity budget
    EXT->>ACT: locator.click(options, progress)
    ACT->>ACT: frame readiness + element lookup
    ACT->>ACT: typing delays / highlight duration

    alt Timeout expires
        ACT-->>EXT: TimeoutError
        EXT-->>RPC: error with name="TimeoutError"
        RPC-->>TS: reject TimeoutError (name preserved)
    else Operation succeeds
        ACT-->>EXT: result
        EXT-->>RPC: success response
        RPC-->>TS: resolve result
    end

    Note over FAC,RPC: Compatibility facade forwards remaining budget

    FAC->>FAC: withTaggedTarget computes deadline
    FAC->>FAC: locatorTimeoutOptions(deadline) = remaining ms
    FAC->>RPC: locator.click({timeout: remaining})
    Note over FAC: Remaining budget includes frame resolution time
Loading

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

page_id: StrictStr
selector: Annotated[StrictStr, Field(min_length=1)]
nth: Annotated[Optional[StrictInt], Field(ge=0, le=9007199254740991)] = None
options: Optional[LocatorOptions] = None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: LocatorFillParams now references LocatorOptions before its definition, leaving this Pydantic model incomplete for locator.fill() validation. Define LocatorOptions earlier or rebuild LocatorFillParams after all generated classes are defined.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/sdk-python/src/stagehand/_generated/models.py, line 1111:

<comment>`LocatorFillParams` now references `LocatorOptions` before its definition, leaving this Pydantic model incomplete for `locator.fill()` validation. Define `LocatorOptions` earlier or rebuild `LocatorFillParams` after all generated classes are defined.</comment>

<file context>
@@ -1106,6 +1108,7 @@ class LocatorFillParams(WireModel):
     page_id: StrictStr
     selector: Annotated[StrictStr, Field(min_length=1)]
     nth: Annotated[Optional[StrictInt], Field(ge=0, le=9007199254740991)] = None
+    options: Optional[LocatorOptions] = None
     value: StrictStr
 
</file context>

extra="forbid",
validate_by_name=True,
)
timeout: Annotated[Optional[StrictFloat], Field(ge=0.0)] = None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: These StrictFloat timeout fields reject integer millisecond values such as 0 and 5000, making the new timeout option unusable with normal Python inputs. Accept strict integers alongside strict floats while retaining the nonnegative constraint.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/sdk-python/src/stagehand/_generated/models.py, line 1064:

<comment>These `StrictFloat` timeout fields reject integer millisecond values such as `0` and `5000`, making the new timeout option unusable with normal Python inputs. Accept strict integers alongside strict floats while retaining the nonnegative constraint.</comment>

<file context>
@@ -1061,6 +1061,8 @@ class LocatorClickOptions(WireModel):
         extra="forbid",
         validate_by_name=True,
     )
+    timeout: Annotated[Optional[StrictFloat], Field(ge=0.0)] = None
+    """Milliseconds for the whole locator call. Zero disables the timeout."""
     button: Optional[MouseButton] = None
</file context>

@seanmcguire12
seanmcguire12 force-pushed the expose-timeout-param-schemas-ts branch from d88f114 to bf86ce1 Compare September 25, 2026 22:10

This branch has not been deployed

No deployments
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