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 2 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
25 changes: 18 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 @@ -119,17 +129,18 @@ 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
│ ├── 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
│ └── 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
80 changes: 80 additions & 0 deletions examples/integrations/temporal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Temporal + Stagehand Integration

A simplified example showing how Temporal handles browser automation failures with automatic retries.

## What it does

- Uses Stagehand to perform Google searches in a real browser
- Temporal automatically retries when browser sessions fail
- No artificial failure simulation - relies on real network/browser issues
- Clean, simple code focused on the retry pattern

## 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

1. **Activities** (`research-activities.ts`):
- `searchWeb`: Opens browser, searches Google, extracts results
- `formatResults`: Formats results as readable text
- Natural failures from network issues, timeouts, or page changes

2. **Workflow** (`workflows.ts`):
- `searchWithRetry`: Orchestrates the search with retry logic
- Configured for up to 10 retries with exponential backoff
- 2-minute timeout per attempt

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

## Retry Behavior

Temporal automatically retries on failures like:
- Network timeouts
- Browser session crashes
- Page load failures
- Element not found errors

The retry policy uses:
- Initial interval: 2 seconds
- Maximum interval: 20 seconds
- Backoff coefficient: 1.8x
- Maximum attempts: 10

## Benefits

- **Simplicity**: Clean code without complex error handling
- **Reliability**: Temporal ensures tasks complete or fail definitively
- **Visibility**: Monitor progress in Temporal Web UI at http://localhost:8233
- **Real-world**: Tests actual browser issues, not simulated failures
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