Skip to content

Wire Stagehand lifecycle to browser context - #2583

Open
miguelg719 wants to merge 1 commit into
miguelgonzalez/stg-2763-change-stagehandcontext-to-browsercontextfrom
miguelgonzalez/stg-2763-wire-browsercontext
Open

Wire Stagehand lifecycle to browser context#2583
miguelg719 wants to merge 1 commit into
miguelgonzalez/stg-2763-change-stagehandcontext-to-browsercontextfrom
miguelgonzalez/stg-2763-wire-browsercontext

Conversation

@miguelg719

@miguelg719 miguelg719 commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

why

The browser-owned context must track Stagehand initialization and teardown without changing browser resource ownership.

what changed

Attaches context after successful Stagehand creation, routes default-page lookup through the browser, and detaches context on close across all SDKs.

No changeset: this targets the unreleased v4 API.

test plan

  • TypeScript Stagehand lifecycle tests
  • Python Stagehand lifecycle tests
  • Go SDK tests

Summary by cubic

Wired the Stagehand lifecycle to the Browser so a shared browser.context attaches on init and detaches on close. This fulfills STG-2763 by making browser.context the single access path across SDKs.

  • Refactors

    • Attach browser.context on successful init and detach on close across sdk-ts, sdk-python, and sdk-go.
    • Default page lookup now goes through browser.context.activePage().
    • Close sends stagehand.close only when initialized and never closes the Browser or transport.
  • Migration

    • Use browser.context instead of stagehand.context (STG-2763).
    • Before attach, browser.context throws “Browser context is unavailable … Attach the browser with await Stagehand.create({ browser }).”; after Stagehand.create, access it via stagehand.browser.context.

Written for commit 115d906. Summary will update on new commits.

Review in cubic

@changeset-bot

changeset-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 115d906

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

@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.

cubic analysis

1 issue found across 6 files

Confidence score: 4/5

  • In packages/sdk-ts/src/stagehand.ts, keeping stagehand.context publicly accessible preserves two API paths (stagehand.context and browser.context), which can stall the intended convergence and lead to inconsistent usage across consumers; remove the getter or convert it to an explicit deprecation/error path so integrations are forced onto browser.context.
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-ts/src/stagehand.ts">

<violation number="1" location="packages/sdk-ts/src/stagehand.ts:89">
P2: According to linked Linear issue STG-2763, this keeps `stagehand.context` publicly available, so both access patterns remain instead of converging on `browser.context`. Consider removing this getter (or making it an explicit deprecated error path) so the API surface has a single context entry point.</violation>
</file>

Linked issue analysis

Linked issue: STG-2763: Change stagehand.context to browser.context

Status Acceptance criteria Notes
Attach the BrowserContext to the Browser after successful Stagehand.create/init (so stagehand.context proxies to browser.context). Each SDK now attaches the context to the browser handle on create instead of storing a separate stagehand context.
Default-page lookup routes through browser.context.activePage() rather than a Stagehand-local context. Calls that previously used stagehand.context.activePage() were changed to use browser.context.activePage() in all SDKs.
Context is detached on Stagehand.close and Stagehand.close does not close the Browser or transport. Close now detaches the browser context and relies on initialized flag; tests assert browser remains open and transport not closed.
stagehand.context now proxies to browser.context and error messages when unavailable are updated accordingly. Context getters now return the browser handle's context; tests were updated to expect the new 'Browser context is unavailable...' message.
Stagehand initialization/close logic uses an initialized flag (not a separate context field) to determine RPC close behavior. Conditions checking for closing RPC now consult the initialized flag; separate context fields were removed in favor of browser-attached context.
Architecture diagram
sequenceDiagram
    participant Client as SDK Client (TS/Python/Go)
    participant SH as Stagehand Instance
    participant BH as BrowserHandle (StagehandBrowser)
    participant BC as BrowserContext
    participant RPC as RPC Client
    participant Remote as Stagehand Worker

    Note over Client,Remote: Stagehand Lifecycle — Context Ownership Change

    Client->>SH: Stagehand.create({browser, apiKey})
    SH->>BH: claim()
    SH->>RPC: connect CDP
    SH->>RPC: stagehand.init
    RPC->>Remote: init request
    Remote-->>RPC: init result
    RPC-->>SH: init success

    Note over SH,BC: NEW: context attachment
    SH->>BC: new BrowserContext(rpcClient)
    SH->>BH: attachStagehandBrowserContext(browser, context)
    BH->>BH: store context reference
    SH->>SH: isInitialized = true

    Note over Client,Remote: Standard Operations — Default Page via Browser Context

    Client->>SH: act() / observe() / extract()
    SH->>SH: parse options, extract page parameter
    alt page parameter provided
        SH->>SH: use provided page
    else no page parameter
        SH->>BH: browser.context.activePage()
        BH->>BC: activePage()
        BC->>RPC: get active page
        RPC-->>BC: page info
        BC-->>BH: active page
        BH-->>SH: target page
    end
    SH->>RPC: stagehand.act/observe/extract(pageId, ...)
    RPC-->>SH: result
    SH-->>Client: return result

    Note over Client,Remote: Close Lifecycle — Context Detachment

    Client->>SH: close()
    SH->>SH: check isInitialized flag
    alt isInitialized == true
        SH->>RPC: stagehand.close
        RPC->>Remote: close request
        Remote-->>RPC: close result
        RPC-->>SH: success
    else isInitialized == false (already closed)
        SH->>SH: skip close
    end
    SH->>SH: removeNotificationListener()
    SH->>RPC: close(closeTransport: false)
    SH->>SH: rpcClient = undefined
    SH->>BH: detachStagehandBrowserContext(browser)
    BH->>BH: clear context reference
    SH->>SH: isInitialized = false

    Note over Client,BH: Error Path — Context Unavailable

    Client->>SH: context (property getter)
    SH->>BH: browser.context
    alt context attached
        BH-->>SH: return BrowserContext
    else context not attached
        BH-->>SH: throw "Browser context is unavailable"
    end
Loading

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

Re-trigger cubic

Comment thread packages/sdk-ts/src/stagehand.ts
Comment thread packages/sdk-python/src/stagehand/stagehand.py
Comment thread packages/sdk-go/stagehand.go
@miguelg719
miguelg719 force-pushed the miguelgonzalez/stg-2763-wire-browsercontext branch from a00cef9 to ea4c302 Compare August 4, 2026 19:27
@miguelg719
miguelg719 force-pushed the miguelgonzalez/stg-2763-wire-browsercontext branch from ea4c302 to 202c7d4 Compare August 4, 2026 20:23
@miguelg719
miguelg719 force-pushed the miguelgonzalez/stg-2763-wire-browsercontext branch from 202c7d4 to 115d906 Compare August 4, 2026 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant