Skip to content

[Integration]: Temporal x Stagehand #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ Powerful web automation combining Browserbase's Stagehand with Mastra's AI agent
#### [**Browser-Use Integration**](./examples/integrations/browser-use/README.md)
Streamlined browser automation for AI applications with a focus on simplicity and reliability.

#### [**Temporal Integration**](./examples/integrations/temporal/README.md)
**Resilient Browser Automation with Workflow Orchestration** - Build fault-tolerant web automation that automatically recovers from failures using Temporal's durable execution engine. Perfect for mission-critical browser tasks that need guaranteed completion.

**Key Features:**
- Automatic retry logic with exponential backoff
- Durable execution that survives crashes and restarts
- Visual workflow monitoring and debugging
- Clean separation of business logic from retry concerns
- Production-ready error handling and recovery

#### [**Portia AI Integration**](./examples/integrations/portia/README.md)
Build intelligent web agents with **persistent authentication** using Portia AI's multi-agent framework. Portia enables both multi-agent task planning with human feedback and stateful multi-agent task execution with human control.

Expand Down Expand Up @@ -135,18 +145,20 @@ integrations/
| |
│ └── community/ # WIP
│ └── integrations/
│ ├── agentkit/ # AgentKit implementations
│ ├── agno/ # AI-powered web scraping agents
│ ├── braintrust/ # Evaluation and testing tools
│ ├── browser-use/ # Simplified browser automation
│ ├── crewai/ # CrewAI framework integration
│ ├── vercel/ # Vercel AI SDK integration
│ ├── trigger/ # Trigger.dev background jobs & automation
│ ├── stripe/ # Stripe Issuing + automation
│ ├── langchain/ # LangChain framework integration
│ ├── mastra/ # Mastra AI agent integration
│ ├── browser-use/ # Simplified browser automation
│ ├── braintrust/ # Evaluation and testing tools
│ ├── portia/ # Portia AI multi-agent framework
│ ├── agno/ # AI-powered web scraping agents
│ ├── mongodb/ # MongoDB data extraction & storage
│ └── agentkit/ # AgentKit implementations
│ ├── portia/ # Portia AI multi-agent framework
│ ├── stripe/ # Stripe Issuing + automation
│ ├── temporal/ # Temporal workflow orchestration
│ ├── trigger/ # Trigger.dev background jobs & automation
│ └── vercel/ # Vercel AI SDK integration
└── README.md # This file
```

Expand Down
18 changes: 18 additions & 0 deletions examples/integrations/temporal/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Temporal Server Configuration
TEMPORAL_ADDRESS=localhost:7233
TEMPORAL_NAMESPACE=default

# Stagehand Configuration
# Get these from https://www.browserbase.com/
BROWSERBASE_API_KEY=your_browserbase_api_key_here
BROWSERBASE_PROJECT_ID=your_browserbase_project_id_here

# LLM Configuration (choose one)
# OpenAI (recommended)
OPENAI_API_KEY=your_openai_api_key_here

# OR Anthropic
ANTHROPIC_API_KEY=your_anthropic_api_key_here

# Research Output Directory
RESEARCH_OUTPUT_DIR=./research_outputs
3 changes: 3 additions & 0 deletions examples/integrations/temporal/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
lib
.eslintrc.js
50 changes: 50 additions & 0 deletions examples/integrations/temporal/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const { builtinModules } = require('module');

const ALLOWED_NODE_BUILTINS = new Set(['assert']);

module.exports = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint', 'deprecation'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
],
rules: {
// recommended for safety
'@typescript-eslint/no-floating-promises': 'error', // forgetting to await Activities and Workflow APIs is bad
'deprecation/deprecation': 'warn',

// code style preference
'object-shorthand': ['error', 'always'],

// relaxed rules, for convenience
'@typescript-eslint/no-unused-vars': [
'warn',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
},
],
'@typescript-eslint/no-explicit-any': 'off',
},
overrides: [
{
files: ['src/workflows.ts', 'src/workflows-*.ts', 'src/workflows/*.ts'],
rules: {
'no-restricted-imports': [
'error',
...builtinModules
.filter((m) => !ALLOWED_NODE_BUILTINS.has(m))
.flatMap((m) => [m, `node:${m}`]),
],
},
},
],
};
9 changes: 9 additions & 0 deletions examples/integrations/temporal/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
lib
node_modules
coverage

.env

tmp

/research_outputs
1 change: 1 addition & 0 deletions examples/integrations/temporal/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
18
1 change: 1 addition & 0 deletions examples/integrations/temporal/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
singleQuote: true
104 changes: 104 additions & 0 deletions examples/integrations/temporal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Temporal + Stagehand Integration

A best practices example showing how Temporal handles browser automation failures with automatic retries using atomic, idempotent activities.

## What it does

- Uses Stagehand to perform Google searches in a real browser
- Each individual task is encapsulated within a Temporal Activity following best practices for atomicity and idempotency
- If any individual task fails, Temporal will automatically retry it, resulting in reliable browser automation
- Clean, maintainable code following Temporal patterns

## Temporal Best Practices Demonstrated

### Atomic Activities
Each Temporal activity performs a single, well-defined task:
1. **initializeBrowser** - Creates and initializes browser session
2. **navigateToSearchPage** - Navigates to Google
3. **executeSearch** - Types query and submits search
4. **extractSearchResults** - Extracts and validates results
5. **cleanupBrowser** - Closes browser session
6. **formatResults** - Formats results for display

### Why Atomic Activities?
- **Efficient retries**: If extraction fails after search succeeds, only extraction is retried
- **Better performance**: No need to repeat successful steps
- **Clearer debugging**: Each activity's purpose is obvious
- **Flexible retry policies**: Different activities can have different retry strategies

### Idempotent Design
- Browser sessions are reused if already initialized
- Cleanup handles already-closed sessions gracefully
- Navigation always results in the same state
- Formatting produces consistent output

## Setup

1. Install dependencies:
```bash
npm install
```

2. Set up environment variables in `.env`:
```
BROWSERBASE_API_KEY=your_api_key
BROWSERBASE_PROJECT_ID=your_project_id
ANTHROPIC_API_KEY=your_anthropic_key # or OPENAI_API_KEY
```

3. Start Temporal (if not already running):
```bash
temporal server start-dev
```

## Running the Example

1. Start the worker in one terminal:
```bash
npm run worker
```

2. Run a search in another terminal:
```bash
npm run demo # Default search
npm run demo "your search term" # Custom search
```

## How it Works

### Activities (`research-activities.ts`)
Each activity is designed to be:
- **Atomic**: Does one thing only
- **Idempotent**: Can be safely retried
- **Focused**: Clear single responsibility

### Workflow (`workflows.ts`)
- Orchestrates the atomic activities in sequence
- Uses tailored retry policies for each activity type
- Handles cleanup in a finally block
- Provides clear progress logging

### Worker (`research-worker.ts`)
- Processes workflow tasks
- Limits to 2 concurrent browser sessions
- Simple configuration focused on essentials

## Retry Behavior

Each activity has a custom retry policy based on its characteristics:

- **Initialize Browser**: 5 attempts, 2-10 second intervals
- **Navigate**: 8 attempts, 1-5 second intervals (fast retries)
- **Execute Search**: 10 attempts, 2-15 second intervals
- **Extract Results**: 10 attempts, 3-20 second intervals (most likely to fail)
- **Cleanup**: 3 attempts, 1-3 second intervals
- **Format**: 2 attempts, minimal retry (deterministic)

## Benefits

- **Simplicity**: Clean code without complex error handling
- **Efficiency**: Only failed steps are retried
- **Reliability**: Temporal ensures tasks complete or fail definitively
- **Visibility**: Monitor progress in Temporal Web UI at http://localhost:8233
- **Maintainability**: Each activity can be tested and updated independently
- **Flexibility**: Easy to add new steps or modify retry behavior
7 changes: 7 additions & 0 deletions examples/integrations/temporal/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
modulePathIgnorePatterns: ['lib'],
clearMocks: true,
};
Loading