Skip to content

Commit ab3ed55

Browse files
authored
fixed workflow storage issue (#120)
* fixed workflow storage issue * fixed lint issues
1 parent 4fbfc6b commit ab3ed55

File tree

11 files changed

+672
-85
lines changed

11 files changed

+672
-85
lines changed
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Workflow Generation Scripts
2+
3+
This directory contains scripts for creating and managing workflows.
4+
5+
## Quick Start: Generate a Workflow
6+
7+
Use `generate_workflow.py` to create a workflow from any task description and automatically store it.
8+
9+
### How to Use
10+
11+
1. **Edit the task configuration** in `generate_workflow.py`:
12+
13+
```python
14+
# At the top of generate_workflow.py
15+
TASK_NAME = "Your Task Name"
16+
TASK_DESCRIPTION = """
17+
Your task description here.
18+
For example: Go to GitHub, search for a repository, and extract the star count.
19+
"""
20+
```
21+
22+
2. **Run the script**:
23+
24+
```bash
25+
cd workflows
26+
uv run python examples/scripts/generate_workflow.py
27+
```
28+
29+
Or with a custom API key:
30+
31+
```bash
32+
cd workflows
33+
BROWSER_USE_API_KEY=your_key uv run python examples/scripts/generate_workflow.py
34+
```
35+
36+
3. **The script will**:
37+
- Open a browser and execute your task
38+
- Record all browser interactions
39+
- Generate a semantic workflow with steps
40+
- Automatically extract variables (optional)
41+
- Store the workflow in `workflows/storage/`
42+
- Provide you with the workflow ID and usage instructions
43+
44+
### Configuration Options
45+
46+
In `generate_workflow.py`, you can configure:
47+
48+
```python
49+
# Enable variable extraction (uses LLM to identify reusable variables)
50+
ENABLE_VARIABLE_EXTRACTION = True
51+
52+
# Use deterministic conversion (no LLM for step creation - faster, cheaper)
53+
USE_DETERMINISTIC_CONVERSION = True
54+
55+
# Storage directory for workflows
56+
STORAGE_DIR = Path(__file__).parent.parent.parent / 'storage'
57+
```
58+
59+
### What You Get
60+
61+
After running the script, you'll get:
62+
63+
- **Workflow ID**: Unique identifier for your workflow
64+
- **Workflow File**: Stored as `{workflow_id}.workflow.yaml` in the storage directory
65+
- **Metadata**: Tracked in `storage/metadata.json`
66+
- **Usage Instructions**: How to run the workflow with or without variables
67+
68+
### Example Output
69+
70+
```
71+
================================================================================
72+
WORKFLOW SUMMARY
73+
================================================================================
74+
75+
Workflow ID: 8077c0ec-f61b-4b48-b0df-65aac77372ae
76+
Name: Get GitHub Repository Stars
77+
Description: Search for a GitHub repository and extract its star count
78+
Version: 1.0
79+
File Path: workflows/storage/workflows/8077c0ec-f61b-4b48-b0df-65aac77372ae.workflow.yaml
80+
81+
Input Variables (1):
82+
- repo_name: string (required) - format: owner/repo-name
83+
84+
Workflow Steps (5):
85+
Step 1: navigation
86+
URL: https://github.com
87+
88+
Step 2: input
89+
Target: Search or jump to
90+
Value: {repo_name}
91+
92+
Step 3: key_press
93+
Key: Enter
94+
95+
Step 4: click
96+
Target: {repo_name}
97+
98+
Step 5: extract
99+
Goal: Extract the number of stars
100+
Output Variable: star_count
101+
102+
✅ Pure semantic workflow (no agent steps)
103+
This workflow will execute fast and cost $0 per run!
104+
```
105+
106+
### Running Your Generated Workflow
107+
108+
After generation, you can run your workflow:
109+
110+
```bash
111+
cd workflows
112+
113+
# List all workflows
114+
BROWSER_USE_API_KEY=your_key uv run python cli.py list-workflows
115+
116+
# Run by ID
117+
BROWSER_USE_API_KEY=your_key uv run python cli.py run-workflow {workflow_id}
118+
119+
# Run with variables
120+
BROWSER_USE_API_KEY=your_key uv run python cli.py run-workflow {workflow_id} --repo_name browser-use/browser-use
121+
```
122+
123+
**Important**: Always run from the `workflows` directory!
124+
125+
## Other Scripts
126+
127+
### Deterministic Workflows
128+
129+
See `deterministic/` directory for more examples:
130+
131+
- `create_deterministic_workflow.py` - Create pure semantic workflows
132+
- `auto_generate_workflow.py` - Auto-generate with variable detection
133+
- `test_deterministic_workflow.py` - Test deterministic conversion
134+
- `test_custom_task.py` - Test with custom tasks
135+
136+
### Variables
137+
138+
See `variables/` directory for examples of creating workflows with parameterized inputs.
139+
140+
## Tips
141+
142+
1. **Keep tasks simple**: The more specific your task description, the better the workflow
143+
2. **Use deterministic mode**: Set `USE_DETERMINISTIC_CONVERSION = True` for faster, cheaper workflows
144+
3. **Test your workflows**: Always test generated workflows to ensure they work as expected
145+
4. **Variable extraction**: Enable `ENABLE_VARIABLE_EXTRACTION` to make workflows reusable with different inputs
146+
147+
## Troubleshooting
148+
149+
**Module not found errors**: Make sure you're running from the `workflows` directory with `uv run`
150+
151+
**API key errors**: Set your API key:
152+
```bash
153+
export BROWSER_USE_API_KEY=your_key
154+
```
155+
156+
**Browser issues**: Ensure you have Chrome/Chromium installed and playwright dependencies set up
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
"""
2+
Generic Workflow Generator
3+
4+
This script creates a workflow from a task description and stores it in the workflow storage.
5+
Simply modify the TASK_NAME and TASK_DESCRIPTION at the top of this file and run it.
6+
7+
Usage:
8+
cd workflows
9+
uv run python examples/scripts/generate_workflow.py
10+
11+
Or with custom API key:
12+
BROWSER_USE_API_KEY=your_key uv run python examples/scripts/generate_workflow.py
13+
"""
14+
15+
import asyncio
16+
from pathlib import Path
17+
18+
from browser_use.llm import ChatBrowserUse
19+
20+
from workflow_use.healing.service import HealingService
21+
from workflow_use.storage.service import WorkflowStorageService
22+
23+
# ============================================================================
24+
# CONFIGURE YOUR TASK HERE
25+
# ============================================================================
26+
27+
TASK_NAME = 'Get GitHub Repository Stars'
28+
TASK_DESCRIPTION = """
29+
Go to GitHub, search for the browser-use repository, click on it,
30+
and extract the star count.
31+
"""
32+
33+
# ============================================================================
34+
# CONFIGURATION OPTIONS
35+
# ============================================================================
36+
37+
# Enable variable extraction (uses LLM to identify reusable variables)
38+
ENABLE_VARIABLE_EXTRACTION = True
39+
40+
# Use deterministic conversion (no LLM for step creation - faster, cheaper)
41+
USE_DETERMINISTIC_CONVERSION = True
42+
43+
# Storage directory for workflows
44+
STORAGE_DIR = Path(__file__).parent.parent.parent / 'storage'
45+
46+
47+
# ============================================================================
48+
# MAIN SCRIPT - DO NOT MODIFY BELOW UNLESS YOU KNOW WHAT YOU'RE DOING
49+
# ============================================================================
50+
51+
52+
async def generate_and_store_workflow():
53+
"""Generate a workflow from the task description and store it."""
54+
55+
print('=' * 80)
56+
print('WORKFLOW GENERATOR')
57+
print('=' * 80)
58+
print(f'\nTask Name: {TASK_NAME}')
59+
print(f'Task Description: {TASK_DESCRIPTION.strip()}\n')
60+
61+
# Initialize LLM
62+
print('Step 1: Initializing LLM...')
63+
llm = ChatBrowserUse(model='bu-latest')
64+
65+
# Create HealingService for workflow generation
66+
print('Step 2: Setting up workflow generation service...')
67+
healing_service = HealingService(
68+
llm=llm, enable_variable_extraction=ENABLE_VARIABLE_EXTRACTION, use_deterministic_conversion=USE_DETERMINISTIC_CONVERSION
69+
)
70+
71+
# Generate workflow
72+
print('\nStep 3: Recording browser interactions and generating workflow...')
73+
print('(This will open a browser and execute the task)\n')
74+
75+
workflow = await healing_service.generate_workflow_from_prompt(
76+
prompt=TASK_DESCRIPTION, agent_llm=llm, extraction_llm=llm, use_cloud=True
77+
)
78+
79+
print('✅ Workflow generated successfully!\n')
80+
81+
# Initialize storage service
82+
print('Step 4: Storing workflow...')
83+
storage = WorkflowStorageService(storage_dir=STORAGE_DIR)
84+
85+
# Save to storage
86+
metadata = storage.save_workflow(
87+
workflow=workflow,
88+
generation_mode='browser_use',
89+
original_task=TASK_DESCRIPTION.strip(),
90+
)
91+
92+
print(f'✅ Workflow saved to storage!\n')
93+
94+
# Display summary
95+
print('=' * 80)
96+
print('WORKFLOW SUMMARY')
97+
print('=' * 80)
98+
99+
print(f'\nWorkflow ID: {metadata.id}')
100+
print(f'Name: {metadata.name}')
101+
print(f'Description: {metadata.description}')
102+
print(f'Version: {metadata.version}')
103+
print(f'File Path: {metadata.file_path}')
104+
print(f'Generation Mode: {metadata.generation_mode}')
105+
print(f'Created At: {metadata.created_at}')
106+
107+
# Show input schema
108+
if workflow.input_schema:
109+
print(f'\nInput Variables ({len(workflow.input_schema)}):')
110+
for var in workflow.input_schema:
111+
required = '(required)' if var.required else '(optional)'
112+
format_info = f' - format: {var.format}' if var.format else ''
113+
print(f' - {var.name}: {var.type} {required}{format_info}')
114+
else:
115+
print('\nNo input variables')
116+
117+
# Show steps
118+
if workflow.steps:
119+
print(f'\nWorkflow Steps ({len(workflow.steps)}):')
120+
121+
step_types = {}
122+
for i, step in enumerate(workflow.steps, 1):
123+
step_type = step.type
124+
step_types[step_type] = step_types.get(step_type, 0) + 1
125+
126+
print(f'\n Step {i}: {step_type}')
127+
if hasattr(step, 'description') and step.description:
128+
print(f' Description: {step.description}')
129+
130+
# Show key fields based on step type
131+
if step_type == 'navigation' and hasattr(step, 'url'):
132+
print(f' URL: {step.url}')
133+
elif step_type == 'input' and hasattr(step, 'target_text'):
134+
print(f' Target: {step.target_text}')
135+
if hasattr(step, 'value'):
136+
print(f' Value: {step.value}')
137+
elif step_type == 'click' and hasattr(step, 'target_text'):
138+
print(f' Target: {step.target_text}')
139+
elif step_type == 'key_press' and hasattr(step, 'key'):
140+
print(f' Key: {step.key}')
141+
elif step_type == 'extract' and hasattr(step, 'extractionGoal'):
142+
print(f' Goal: {step.extractionGoal}')
143+
if hasattr(step, 'output'):
144+
print(f' Output Variable: {step.output}')
145+
146+
# Show step type summary
147+
print('\n' + '-' * 80)
148+
print('Step Type Summary:')
149+
for step_type, count in sorted(step_types.items()):
150+
print(f' {step_type}: {count}')
151+
152+
# Check for agent steps
153+
agent_steps = step_types.get('agent', 0)
154+
if agent_steps == 0:
155+
print('\n✅ Pure semantic workflow (no agent steps)')
156+
print(' This workflow will execute fast and cost $0 per run!')
157+
else:
158+
print(f'\n⚠️ Contains {agent_steps} agent step(s)')
159+
print(' Agent steps may be slower and cost money per execution')
160+
161+
# Usage instructions
162+
print('\n' + '=' * 80)
163+
print('HOW TO USE THIS WORKFLOW')
164+
print('=' * 80)
165+
166+
print(f'\nWorkflow ID: {metadata.id}')
167+
print('\n1. List all workflows:')
168+
print(' cd workflows')
169+
print(' BROWSER_USE_API_KEY=your_key uv run python cli.py list-workflows')
170+
171+
print('\n2. Run by ID:')
172+
print(' cd workflows')
173+
print(f' BROWSER_USE_API_KEY=your_key uv run python cli.py run-workflow {metadata.id}')
174+
175+
if workflow.input_schema:
176+
print('\n3. Run with input variables:')
177+
print(' cd workflows')
178+
var_args = ' '.join([f'--{v.name} <value>' for v in workflow.input_schema])
179+
print(f' BROWSER_USE_API_KEY=your_key uv run python cli.py run-workflow {metadata.id} {var_args}')
180+
181+
print('\n' + '=' * 80)
182+
print('DONE!')
183+
print('=' * 80 + '\n')
184+
185+
186+
if __name__ == '__main__':
187+
asyncio.run(generate_and_store_workflow())

workflows/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "workflow-use"
3-
version = "0.2.1"
3+
version = "0.2.2"
44
authors = [{ name = "Gregor Zunic" }]
55
description = "Create, edit, run deterministic workflows"
66
readme = "README.md"

workflows/storage/metadata.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"bfaf87d9-f5d9-4245-b210-5bfdf302a9b2": {
3+
"id": "bfaf87d9-f5d9-4245-b210-5bfdf302a9b2",
4+
"name": "\nGo to GitHub, search for the browser-use repository, click on it,\nand extract the star count.\n",
5+
"description": "Workflow for: \nGo to GitHub, search for the browser-use repository, click on it,\nand extract the star count.\n",
6+
"version": "1.0.0",
7+
"created_at": "2025-10-29T19:10:18.180929",
8+
"updated_at": "2025-10-29T19:10:18.180939",
9+
"file_path": "/Users/sauravpanda/Github/LLMs/Browser-Use/workflow-use/workflows/storage/workflows/bfaf87d9-f5d9-4245-b210-5bfdf302a9b2.workflow.yaml",
10+
"generation_mode": "browser_use",
11+
"original_task": "Go to GitHub, search for the browser-use repository, click on it,\nand extract the star count."
12+
},
13+
"01093ced-5dfc-4590-8806-2eae6840bc8f": {
14+
"id": "01093ced-5dfc-4590-8806-2eae6840bc8f",
15+
"name": "\nGo to GitHub, search for the browser-use repository, click on it,\nand extract the star count.\n",
16+
"description": "Workflow for: \nGo to GitHub, search for the browser-use repository, click on it,\nand extract the star count.\n",
17+
"version": "1.0.0",
18+
"created_at": "2025-10-29T19:16:50.042455",
19+
"updated_at": "2025-10-29T19:16:50.042464",
20+
"file_path": "/Users/sauravpanda/Github/LLMs/Browser-Use/workflow-use/workflows/storage/workflows/01093ced-5dfc-4590-8806-2eae6840bc8f.workflow.yaml",
21+
"generation_mode": "browser_use",
22+
"original_task": "Go to GitHub, search for the browser-use repository, click on it,\nand extract the star count."
23+
}
24+
}

0 commit comments

Comments
 (0)