Skip to content

Conversation

@kernel-systems-bot
Copy link

@kernel-systems-bot kernel-systems-bot commented Jan 14, 2026

Fix: Stream Continues After stagehand.close()

Summary

Adds ensureNotClosed() checks to V3AgentHandler to properly detect when stagehand.close() is called during agent execution. This mirrors the existing pattern from V3CuaAgentHandler and ensures the agent terminates gracefully with a clear error instead of continuing to execute with a null context.

Problem

In v3AgentHandler.ts, there are no checks to detect if the stagehand instance was closed during streaming. When stagehand.close() is called mid-execution:

// BEFORE (bug):
const streamResult = await agent.execute({ instruction: "long task", maxSteps: 10 });

let consumed = 0;
for await (const _ of streamResult.fullStream) {
  consumed++;
  if (consumed === 3) {
    await stagehand.close(); // Close while streaming
  }
}
// Stream continues running, attempts to access null context
// Throws: TypeError: Cannot read properties of null (reading 'awaitActivePage')

The CUA handler (v3CuaAgentHandler.ts) already has this pattern implemented correctly with ensureNotClosed() checks.

Solution

Added the ensureNotClosed() method and checks at key points in the agent lifecycle:

// AFTER (fix):
/**
 * Ensures the V3 context is still available (not closed).
 * Throws StagehandClosedError if stagehand.close() was called.
 */
private ensureNotClosed(): void {
  if (!this.v3.context) {
    throw new StagehandClosedError();
  }
}

Checks added in:

  1. prepareAgent() - Before accessing context for initial page URL
  2. createStepHandler() - At the start of each step callback
  3. captureAndEmitScreenshot() - Before accessing context for screenshots

Impact

Scenario Before Fix After Fix
Close during execute() TypeError: Cannot read properties of null Returns failure result with clear message
Close during stream() TypeError: Cannot read properties of null Throws StagehandClosedError
Step handler after close TypeError: Cannot read properties of null Throws StagehandClosedError

Error message improvement:

  • Before: "Cannot read properties of null (reading 'awaitActivePage')"
  • After: "Stagehand session was closed"

Test Plan

  • Added regression test stream-close-cleanup.test.ts (7 test cases)
  • Verified test FAILS on main (5/7 tests fail - wrong error type)
  • Verified test PASSES with fix (7/7 tests pass)
  • Pattern matches existing implementation in v3CuaAgentHandler.ts

Files Changed

  • packages/core/lib/v3/handlers/v3AgentHandler.ts - Added ensureNotClosed() method and checks
  • packages/core/tests/stream-close-cleanup.test.ts - New regression test (7 test cases)

Feedback? Email [email protected]


Summary by cubic

Fixes BUG-019 by stopping agent streams after stagehand.close(). Adds closed-context checks to V3AgentHandler so runs end cleanly with StagehandClosedError instead of a TypeError.

  • Bug Fixes
    • Add ensureNotClosed() and call it in prepareAgent, step handler, and screenshot capture.
    • Align behavior with V3CuaAgentHandler.
    • On close: execute() returns a failure result; stream() rejects with StagehandClosedError; message is "Stagehand session was closed".
    • Add regression test stream-close-cleanup.test.ts covering close before and during execution.

Written for commit 54bc3fc. Summary will update on new commits.

Adds ensureNotClosed() checks to V3AgentHandler to properly detect when
stagehand.close() is called during agent execution. This mirrors the
existing pattern from V3CuaAgentHandler.

Before: Accessing null context threw TypeError with confusing message
After: Throws StagehandClosedError with clear "Stagehand session was closed"

Checks added in:
- prepareAgent(): Before accessing context for initial page URL
- createStepHandler(): At the start of each step callback
- captureAndEmitScreenshot(): Before accessing context for screenshots
@changeset-bot
Copy link

changeset-bot bot commented Jan 14, 2026

⚠️ No Changeset found

Latest commit: 54bc3fc

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

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 14, 2026

Greptile Summary

This PR adds proper closed context detection to V3AgentHandler by implementing the ensureNotClosed() pattern already used in V3CuaAgentHandler. The fix prevents TypeError: Cannot read properties of null errors when stagehand.close() is called during agent execution, replacing them with clear StagehandClosedError exceptions.

Key Changes:

  • Added ensureNotClosed() method that checks if this.v3.context is null and throws StagehandClosedError
  • Added checks in three locations: prepareAgent() (line 95), createStepHandler() (line 168), and captureAndEmitScreenshot() (line 623)
  • Comprehensive test suite with 7 test cases covering all scenarios

Issues Found:

  • Potential race condition at line 214 where this.v3.context is accessed after tool execution, but the ensureNotClosed() check happens much earlier (line 168). If context is closed between these points, the null dereference error can still occur.

Confidence Score: 4/5

  • This PR is safe to merge with one identified race condition that should be addressed
  • The implementation correctly mirrors the v3CuaAgentHandler pattern and includes comprehensive tests. However, there's a race condition in createStepHandler() where context is accessed at line 214 without a check immediately before it, leaving a window where the context could be closed between the check at line 168 and the access at line 214.
  • Pay close attention to packages/core/lib/v3/handlers/v3AgentHandler.ts line 214 for the race condition issue

Important Files Changed

Filename Overview
packages/core/lib/v3/handlers/v3AgentHandler.ts Added ensureNotClosed() method and checks at three key points (prepareAgent, createStepHandler, captureAndEmitScreenshot) to detect closed context. Implementation mirrors v3CuaAgentHandler pattern. One potential race condition at line 214.
packages/core/tests/stream-close-cleanup.test.ts Comprehensive test coverage with 7 test cases covering all scenarios: closed context, active context, mid-execution closure, and pattern comparison. Tests verify both execute() and stream() behaviors.

Sequence Diagram

sequenceDiagram
    participant User
    participant Agent as V3AgentHandler
    participant Context as V3.context
    participant LLM as LLMClient

    User->>Agent: execute() or stream()
    Agent->>Agent: prepareAgent()
    Agent->>Agent: ensureNotClosed()
    alt context is null
        Agent-->>User: throw StagehandClosedError
    else context exists
        Agent->>Context: awaitActivePage()
        Context-->>Agent: page with URL
        Agent->>LLM: generateText/streamText()
        
        loop Each step
            LLM->>Agent: onStepFinish callback
            Agent->>Agent: createStepHandler()
            Agent->>Agent: ensureNotClosed()
            alt context closed during execution
                Agent-->>User: throw StagehandClosedError
            else context still exists
                Agent->>Context: awaitActivePage()
                Context-->>Agent: page URL
                
                opt EVALS mode
                    Agent->>Agent: captureAndEmitScreenshot()
                    Agent->>Agent: ensureNotClosed()
                    alt context closed
                        Agent-->>User: throw StagehandClosedError
                    else context exists
                        Agent->>Context: awaitActivePage()
                        Context-->>Agent: screenshot
                    end
                end
            end
        end
        
        Agent-->>User: return result
    end
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (1)

  1. packages/core/lib/v3/handlers/v3AgentHandler.ts, line 214 (link)

    logic: Potential race condition - this.v3.context could be set to null between the ensureNotClosed() check at line 168 and this access. Consider storing context in a local variable after the check or adding another ensureNotClosed() call before this line.

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Copy link
Contributor

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

Choose a reason for hiding this comment

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

No issues found across 2 files

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