Skip to content

Commit f4acd88

Browse files
authored
[Integration]: Temporal x Stagehand (#11)
* first version of temporal integration * rm url * make acitons idempotent + more atomic * cleanup * add readme stuff + individual activity retries + fully stateless activities
1 parent c7be441 commit f4acd88

16 files changed

+10205
-7
lines changed

README.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ Powerful web automation combining Browserbase's Stagehand with Mastra's AI agent
6161
#### [**Browser-Use Integration**](./examples/integrations/browser-use/README.md)
6262
Streamlined browser automation for AI applications with a focus on simplicity and reliability.
6363

64+
#### [**Temporal Integration**](./examples/integrations/temporal/README.md)
65+
**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.
66+
67+
**Key Features:**
68+
- Automatic retry logic with exponential backoff
69+
- Durable execution that survives crashes and restarts
70+
- Visual workflow monitoring and debugging
71+
- Clean separation of business logic from retry concerns
72+
- Production-ready error handling and recovery
73+
6474
#### [**Portia AI Integration**](./examples/integrations/portia/README.md)
6575
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.
6676

@@ -135,18 +145,20 @@ integrations/
135145
| |
136146
│ └── community/ # WIP
137147
│ └── integrations/
148+
│ ├── agentkit/ # AgentKit implementations
149+
│ ├── agno/ # AI-powered web scraping agents
150+
│ ├── braintrust/ # Evaluation and testing tools
151+
│ ├── browser-use/ # Simplified browser automation
138152
│ ├── crewai/ # CrewAI framework integration
139-
│ ├── vercel/ # Vercel AI SDK integration
140-
│ ├── trigger/ # Trigger.dev background jobs & automation
141153
│ ├── stripe/ # Stripe Issuing + automation
142154
│ ├── langchain/ # LangChain framework integration
143155
│ ├── mastra/ # Mastra AI agent integration
144-
│ ├── browser-use/ # Simplified browser automation
145-
│ ├── braintrust/ # Evaluation and testing tools
146-
│ ├── portia/ # Portia AI multi-agent framework
147-
│ ├── agno/ # AI-powered web scraping agents
148156
│ ├── mongodb/ # MongoDB data extraction & storage
149-
│ └── agentkit/ # AgentKit implementations
157+
│ ├── portia/ # Portia AI multi-agent framework
158+
│ ├── stripe/ # Stripe Issuing + automation
159+
│ ├── temporal/ # Temporal workflow orchestration
160+
│ ├── trigger/ # Trigger.dev background jobs & automation
161+
│ └── vercel/ # Vercel AI SDK integration
150162
└── README.md # This file
151163
```
152164

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Temporal Server Configuration
2+
TEMPORAL_ADDRESS=localhost:7233
3+
TEMPORAL_NAMESPACE=default
4+
5+
# Stagehand Configuration
6+
# Get these from https://www.browserbase.com/
7+
BROWSERBASE_API_KEY=your_browserbase_api_key_here
8+
BROWSERBASE_PROJECT_ID=your_browserbase_project_id_here
9+
10+
# LLM Configuration (choose one)
11+
# OpenAI (recommended)
12+
OPENAI_API_KEY=your_openai_api_key_here
13+
14+
# OR Anthropic
15+
ANTHROPIC_API_KEY=your_anthropic_api_key_here
16+
17+
# Research Output Directory
18+
RESEARCH_OUTPUT_DIR=./research_outputs
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
lib
3+
.eslintrc.js
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
const { builtinModules } = require('module');
2+
3+
const ALLOWED_NODE_BUILTINS = new Set(['assert']);
4+
5+
module.exports = {
6+
root: true,
7+
parser: '@typescript-eslint/parser',
8+
parserOptions: {
9+
project: './tsconfig.json',
10+
tsconfigRootDir: __dirname,
11+
},
12+
plugins: ['@typescript-eslint', 'deprecation'],
13+
extends: [
14+
'eslint:recommended',
15+
'plugin:@typescript-eslint/eslint-recommended',
16+
'plugin:@typescript-eslint/recommended',
17+
'prettier',
18+
],
19+
rules: {
20+
// recommended for safety
21+
'@typescript-eslint/no-floating-promises': 'error', // forgetting to await Activities and Workflow APIs is bad
22+
'deprecation/deprecation': 'warn',
23+
24+
// code style preference
25+
'object-shorthand': ['error', 'always'],
26+
27+
// relaxed rules, for convenience
28+
'@typescript-eslint/no-unused-vars': [
29+
'warn',
30+
{
31+
argsIgnorePattern: '^_',
32+
varsIgnorePattern: '^_',
33+
},
34+
],
35+
'@typescript-eslint/no-explicit-any': 'off',
36+
},
37+
overrides: [
38+
{
39+
files: ['src/workflows.ts', 'src/workflows-*.ts', 'src/workflows/*.ts'],
40+
rules: {
41+
'no-restricted-imports': [
42+
'error',
43+
...builtinModules
44+
.filter((m) => !ALLOWED_NODE_BUILTINS.has(m))
45+
.flatMap((m) => [m, `node:${m}`]),
46+
],
47+
},
48+
},
49+
],
50+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
lib
2+
node_modules
3+
coverage
4+
5+
.env
6+
7+
tmp
8+
9+
/research_outputs
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
18
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
singleQuote: true
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Temporal + Stagehand Integration
2+
3+
A best practices example showing how Temporal handles browser automation failures with automatic retries using atomic, idempotent activities.
4+
5+
## What it does
6+
7+
- Uses Stagehand to perform Google searches in a real browser
8+
- Each individual task is encapsulated within a Temporal Activity following best practices for atomicity and idempotency
9+
- If any individual task fails, Temporal will automatically retry it, resulting in reliable browser automation
10+
- Clean, maintainable code following Temporal patterns
11+
12+
## Temporal Best Practices Demonstrated
13+
14+
### Atomic Activities
15+
Each Temporal activity performs a single, well-defined task:
16+
1. **initializeBrowser** - Creates and initializes browser session
17+
2. **navigateToSearchPage** - Navigates to Google
18+
3. **executeSearch** - Types query and submits search
19+
4. **extractSearchResults** - Extracts and validates results
20+
5. **cleanupBrowser** - Closes browser session
21+
6. **formatResults** - Formats results for display
22+
23+
### Why Atomic Activities?
24+
- **Efficient retries**: If extraction fails after search succeeds, only extraction is retried
25+
- **Better performance**: No need to repeat successful steps
26+
- **Clearer debugging**: Each activity's purpose is obvious
27+
- **Flexible retry policies**: Different activities can have different retry strategies
28+
29+
### Idempotent Design
30+
- Browser sessions are reused if already initialized
31+
- Cleanup handles already-closed sessions gracefully
32+
- Navigation always results in the same state
33+
- Formatting produces consistent output
34+
35+
## Setup
36+
37+
1. Install dependencies:
38+
```bash
39+
npm install
40+
```
41+
42+
2. Set up environment variables in `.env`:
43+
```
44+
BROWSERBASE_API_KEY=your_api_key
45+
BROWSERBASE_PROJECT_ID=your_project_id
46+
ANTHROPIC_API_KEY=your_anthropic_key # or OPENAI_API_KEY
47+
```
48+
49+
3. Start Temporal (if not already running):
50+
```bash
51+
temporal server start-dev
52+
```
53+
54+
## Running the Example
55+
56+
1. Start the worker in one terminal:
57+
```bash
58+
npm run worker
59+
```
60+
61+
2. Run a search in another terminal:
62+
```bash
63+
npm run demo # Default search
64+
npm run demo "your search term" # Custom search
65+
```
66+
67+
## How it Works
68+
69+
### Activities (`research-activities.ts`)
70+
Each activity is designed to be:
71+
- **Atomic**: Does one thing only
72+
- **Idempotent**: Can be safely retried
73+
- **Focused**: Clear single responsibility
74+
75+
### Workflow (`workflows.ts`)
76+
- Orchestrates the atomic activities in sequence
77+
- Uses tailored retry policies for each activity type
78+
- Handles cleanup in a finally block
79+
- Provides clear progress logging
80+
81+
### Worker (`research-worker.ts`)
82+
- Processes workflow tasks
83+
- Limits to 2 concurrent browser sessions
84+
- Simple configuration focused on essentials
85+
86+
## Retry Behavior
87+
88+
Each activity has a custom retry policy based on its characteristics:
89+
90+
- **Initialize Browser**: 5 attempts, 2-10 second intervals
91+
- **Navigate**: 8 attempts, 1-5 second intervals (fast retries)
92+
- **Execute Search**: 10 attempts, 2-15 second intervals
93+
- **Extract Results**: 10 attempts, 3-20 second intervals (most likely to fail)
94+
- **Cleanup**: 3 attempts, 1-3 second intervals
95+
- **Format**: 2 attempts, minimal retry (deterministic)
96+
97+
## Benefits
98+
99+
- **Simplicity**: Clean code without complex error handling
100+
- **Efficiency**: Only failed steps are retried
101+
- **Reliability**: Temporal ensures tasks complete or fail definitively
102+
- **Visibility**: Monitor progress in Temporal Web UI at http://localhost:8233
103+
- **Maintainability**: Each activity can be tested and updated independently
104+
- **Flexibility**: Easy to add new steps or modify retry behavior
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */
2+
module.exports = {
3+
preset: 'ts-jest',
4+
testEnvironment: 'node',
5+
modulePathIgnorePatterns: ['lib'],
6+
clearMocks: true,
7+
};

0 commit comments

Comments
 (0)