Wire Stagehand lifecycle to browser context - #2583
Open
miguelg719 wants to merge 1 commit into
Open
Conversation
|
Contributor
There was a problem hiding this comment.
cubic analysis
1 issue found across 6 files
Confidence score: 4/5
- In
packages/sdk-ts/src/stagehand.ts, keepingstagehand.contextpublicly accessible preserves two API paths (stagehand.contextandbrowser.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 ontobrowser.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
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
miguelg719
force-pushed
the
miguelgonzalez/stg-2763-wire-browsercontext
branch
from
August 4, 2026 19:27
a00cef9 to
ea4c302
Compare
miguelg719
force-pushed
the
miguelgonzalez/stg-2763-wire-browsercontext
branch
from
August 4, 2026 20:23
ea4c302 to
202c7d4
Compare
miguelg719
force-pushed
the
miguelgonzalez/stg-2763-wire-browsercontext
branch
from
August 4, 2026 20:25
202c7d4 to
115d906
Compare
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.
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
Summary by cubic
Wired the Stagehand lifecycle to the Browser so a shared
browser.contextattaches on init and detaches on close. This fulfills STG-2763 by makingbrowser.contextthe single access path across SDKs.Refactors
browser.contexton successful init and detach on close acrosssdk-ts,sdk-python, andsdk-go.browser.context.activePage().stagehand.closeonly when initialized and never closes the Browser or transport.Migration
browser.contextinstead ofstagehand.context(STG-2763).browser.contextthrows “Browser context is unavailable … Attach the browser with await Stagehand.create({ browser }).”; afterStagehand.create, access it viastagehand.browser.context.Written for commit 115d906. Summary will update on new commits.