Skip to content

Conversation

@tkattkat
Copy link
Collaborator

@tkattkat tkattkat commented Dec 3, 2025

Agent Abort Signal and Message Continuation

Why

Enable users to cancel long-running agent tasks and continue conversations across multiple execute() calls. Also ensures graceful shutdown when stagehand.close() is called by automatically aborting any running agent tasks.

What Changed

New Features (behind experimental: true)

Abort Signal Support

  • Pass signal to agent.execute() to cancel execution mid-run
  • Works with AbortController and AbortSignal.timeout()
  • Throws AgentAbortError when aborted

Message Continuation

  • execute() now returns messages in the result
  • Pass previous messages to continue a conversation across calls

New Utilities

File Purpose
combineAbortSignals.ts Merges multiple signals (uses native AbortSignal.any() on Node 20+, fallback for older)
errorHandling.ts Consolidates abort detection logic—needed because close() may cause indirect errors (e.g., null context) that should still be treated as abort
validateExperimentalFeatures.ts Single place for all experimental/CUA feature validation

CUA Limitations

Abort signal and message continuation are not supported with CUA mode (throws StagehandInvalidArgumentError). This matches existing streaming limitation.

Tests Added

  • agent-abort-signal.spec.ts (7 tests)
  • agent-message-continuation.spec.ts (4 tests)
  • agent-experimental-validation.spec.ts (17 tests)

Summary by cubic

Adds agent abort support and conversation continuation. You can cancel long runs, auto-abort on close, and carry messages across execute() calls. Feature is gated behind experimental: true and has clear CUA limitations.

  • New Features

    • Abort signal for execute() and stream() with AbortController and AbortSignal.timeout; throws AgentAbortError; stagehand.close() auto-aborts via an internal controller combined with any user signal.
    • Message continuation: execute() returns messages and accepts previous messages on the next call; tool calls and results are included.
  • Refactors

    • Centralized experimental/CUA validation via validateExperimentalFeatures: CUA disallows streaming, abort signal, and message continuation; experimental required for integrations, tools, streaming, callbacks, signal, and messages.
    • Public API updates: re-export ModelMessage; Agent types include messages and signal; AgentAbortError exported for consistent abort typing.

Written for commit 9d2a4a6. Summary will update automatically on new commits.

@changeset-bot
Copy link

changeset-bot bot commented Dec 3, 2025

🦋 Changeset detected

Latest commit: 9d2a4a6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@browserbasehq/stagehand Patch
@browserbasehq/stagehand-evals Patch

Not sure what this means? Click here to learn what changesets are.

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

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 3, 2025

Greptile Overview

Greptile Summary

This PR introduces two major experimental features for Stagehand's agent system: abort signal support and message continuation. The abort signal functionality allows users to cancel long-running agent tasks using standard AbortController/AbortSignal APIs and automatically aborts all running agent tasks when stagehand.close() is called. The message continuation feature enables maintaining conversation context across multiple agent.execute() calls by returning messages in results and accepting previous messages as input.

Both features are gated behind the experimental: true flag and are not supported in CUA (Computer Use Agent) mode. The implementation adds an internal AbortController to each V3 instance that gets combined with user-provided signals, introduces a new AgentAbortError class for structured error handling, and consolidates experimental feature validation into centralized utilities. The changes maintain full backward compatibility while extending the agent API surface with these advanced capabilities.

Important Files Changed

Filename Score Overview
packages/core/lib/v3/v3.ts 4/5 Adds internal abort controller, signal combination logic, and experimental validation integration
packages/core/lib/v3/handlers/v3AgentHandler.ts 4/5 Implements abort signal handling and message continuation in agent execution pipeline
packages/core/lib/v3/types/public/agent.ts 4/5 Extends agent types with signal and messages properties for new experimental features
packages/core/lib/v3/agent/utils/combineAbortSignals.ts 5/5 New utility for merging multiple abort signals with Node 20+ optimization and fallback
packages/core/lib/v3/agent/utils/validateExperimentalFeatures.ts 5/5 Centralizes all experimental and CUA feature validation logic
packages/core/lib/v3/agent/utils/errorHandling.ts 4/5 New error handling utilities for abort signal extraction and error classification
packages/core/lib/v3/types/public/sdkErrors.ts 5/5 Adds AgentAbortError class with abort detection utility methods
packages/core/tests/public-api/public-error-types.test.ts 5/5 Adds AgentAbortError to public error types test coverage
packages/core/tests/public-api/public-types.test.ts 5/5 Updates type manifest with new ModelMessage export and agent option fields
packages/core/lib/v3/tests/agent-abort-signal.spec.ts 4/5 Comprehensive test coverage for abort signal functionality across different scenarios
packages/core/lib/v3/tests/agent-message-continuation.spec.ts 5/5 Tests message continuation feature with tool calls and streaming support
packages/core/lib/v3/tests/agent-experimental-validation.spec.ts 5/5 Validates experimental feature gating and CUA mode restrictions
packages/core/lib/v3/tests/agent-streaming.spec.ts 5/5 Minor fix to match updated error message casing in validation

Confidence score: 4/5

  • This PR introduces significant new functionality but is well-designed with proper experimental gating and comprehensive test coverage
  • Score reflects the complexity of agent lifecycle management and potential edge cases in abort signal handling, though the implementation appears robust
  • Pay close attention to packages/core/lib/v3/v3.ts and packages/core/lib/v3/handlers/v3AgentHandler.ts for the core abort and messaging logic

Sequence Diagram

sequenceDiagram
    participant User
    participant V3
    participant AgentHandler
    participant AbortController
    participant LLMClient
    participant CombineSignals as combineAbortSignals
    participant Validation as validateExperimentalFeatures

    User->>V3: "agent(config)"
    V3->>Validation: "validateExperimentalFeatures(config)"
    Validation-->>V3: "validation passed"
    V3-->>User: "agent instance"

    User->>V3: "agent.execute({ instruction, signal, messages })"
    V3->>Validation: "validateExperimentalFeatures(executeOptions)"
    Validation-->>V3: "validation passed"
    
    V3->>CombineSignals: "combineAbortSignals(instanceSignal, userSignal)"
    CombineSignals-->>V3: "combinedSignal"
    
    V3->>AgentHandler: "execute(options with combinedSignal)"
    AgentHandler->>AgentHandler: "extractAbortSignal(options)"
    AgentHandler->>AgentHandler: "prepareAgent(options)"
    AgentHandler->>LLMClient: "generateText({ signal: combinedSignal })"
    
    alt Execution completes normally
        LLMClient-->>AgentHandler: "result with messages"
        AgentHandler->>AgentHandler: "consolidateMetricsAndResult(messages)"
        AgentHandler-->>V3: "AgentResult with messages"
        V3-->>User: "AgentResult with messages"
    else User aborts signal
        User->>AbortController: "abort()"
        AbortController->>LLMClient: "signal aborted"
        LLMClient-->>AgentHandler: "error"
        AgentHandler->>AgentHandler: "getAbortErrorReason(error, signal)"
        AgentHandler->>AgentHandler: "throw AgentAbortError"
        AgentHandler-->>V3: "AgentAbortError"
        V3-->>User: "AgentAbortError"
    else Stagehand closes
        V3->>AbortController: "_agentAbortController.abort('closing')"
        AbortController->>LLMClient: "signal aborted"
        LLMClient-->>AgentHandler: "error"
        AgentHandler->>AgentHandler: "getAbortErrorReason(error, signal)"
        AgentHandler->>AgentHandler: "throw AgentAbortError"
        AgentHandler-->>V3: "AgentAbortError"
        V3-->>User: "AgentAbortError"
    end

    User->>V3: "agent.execute({ instruction, messages: previousMessages })"
    Note over User,V3: Message continuation - using messages from previous result
    V3->>AgentHandler: "execute(options with previous messages)"
    AgentHandler->>AgentHandler: "combine input messages with new instruction"
    AgentHandler->>LLMClient: "generateText({ messages: combinedMessages })"
    LLMClient-->>AgentHandler: "result with full conversation"
    AgentHandler-->>V3: "AgentResult with full conversation history"
    V3-->>User: "AgentResult with updated messages"
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.

13 files reviewed, 4 comments

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 14 files

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.

2 issues found across 5 files (changes from recent commits).

Prompt for AI agents (all 2 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/core/lib/v3/handlers/v3AgentHandler.ts">

<violation number="1">
P2: The `stream()` method no longer catches errors from `prepareAgent()`. If an abort signal causes `prepareAgent()` to throw (e.g., null context from `stagehand.close()`), the error won&#39;t be converted to `AgentAbortError`. The `execute()` method handles this by wrapping everything in try-catch with abort detection.</violation>

<violation number="2" location="packages/core/lib/v3/handlers/v3AgentHandler.ts:335">
P2: The `onError` handler in `stream()` only checks `AgentAbortError.isAbortError(event.error)` but doesn&#39;t check `options.signal?.aborted` like the `execute()` method does. This inconsistency means abort-related errors that don&#39;t match the `isAbortError` pattern (e.g., null context errors from `stagehand.close()`) won&#39;t be properly converted to `AgentAbortError` in streaming mode.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

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.

4 issues found across 32 files (changes from recent commits).

Prompt for AI agents (all 4 issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name=".changeset/orange-garlics-brake.md">

<violation number="1">
P1: Changeset description doesn&#39;t match PR content. The PR adds abort signal support and message continuation for agents, but the changeset says &quot;add support for page.addInitScript()&quot; which is unrelated. This will result in an incorrect changelog entry.</violation>
</file>

<file name=".changeset/wide-doors-allow.md">

<violation number="1">
P2: Changeset message doesn&#39;t match the PR changes. The message says &quot;Add support for 4.5 opus in cua agent&quot; but this PR adds abort signal support and message continuation features. This will result in an incorrect changelog entry.</violation>
</file>

<file name=".changeset/tasty-teams-call.md">

<violation number="1">
P2: Changeset description doesn&#39;t match the PR content. The PR implements abort signals, message continuation, and auto-abort on close, but the changeset describes &#39;make act, extract, and observe respect user defined timeout param&#39;. This will generate incorrect changelog entries. Consider updating the description to reflect the actual changes, e.g.:

`feat: add agent abort signal support and message continuation`</violation>
</file>

<file name=".changeset/fruity-clowns-pick.md">

<violation number="1">
P1: Changeset description doesn&#39;t match the PR content. The PR adds abort signal support and message continuation features, but the changeset says &#39;fix: don&#39;t attach to targets twice&#39;. This will result in an incorrect changelog entry. Consider updating to something like:

feat: add agent abort signal support and message continuation

</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

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.

2 participants