Skip to content

Commit ac53426

Browse files
authored
Merge pull request #46 from browser-use/feature/output-variables
Type safe outputs from a workflow
2 parents bdcf42a + 88bc8c8 commit ac53426

File tree

18 files changed

+1163
-1062
lines changed

18 files changed

+1163
-1062
lines changed

workflows/backend/service.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,14 +180,14 @@ async def run_workflow_in_background(
180180
'extracted_content': s.extracted_content,
181181
'status': 'completed',
182182
}
183-
for i, s in enumerate(result)
183+
for i, s in enumerate(result.step_results)
184184
]
185185
for step in formatted_result:
186186
await self._write_log(log_file, f'[{ts}] Completed step {step["step_id"]}: {step["extracted_content"]}\n')
187187

188188
self.active_tasks[task_id].status = 'completed'
189189
self.active_tasks[task_id].result = formatted_result
190-
await self._write_log(log_file, f'[{ts}] Workflow completed successfully with {len(result)} steps\n')
190+
await self._write_log(log_file, f'[{ts}] Workflow completed successfully with {len(result.step_results)} steps\n')
191191

192192
except asyncio.CancelledError:
193193
await self._write_log(log_file, f'[{time.strftime("%Y-%m-%d %H:%M:%S")}] Workflow force‑cancelled\n')

workflows/cli.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@
3232
llm_instance = None
3333
try:
3434
llm_instance = ChatOpenAI(model='gpt-4o')
35+
page_extraction_llm = ChatOpenAI(model='gpt-4o-mini')
3536
except Exception as e:
3637
typer.secho(f'Error initializing LLM: {e}. Would you like to set your OPENAI_API_KEY?', fg=typer.colors.RED)
3738
set_openai_api_key = input('Set OPENAI_API_KEY? (y/n): ')
3839
if set_openai_api_key.lower() == 'y':
3940
os.environ['OPENAI_API_KEY'] = input('Enter your OPENAI_API_KEY: ')
4041
llm_instance = ChatOpenAI(model='gpt-4o')
42+
page_extraction_llm = ChatOpenAI(model='gpt-4o-mini')
4143

4244
builder_service = BuilderService(llm=llm_instance) if llm_instance else None
4345
# recorder_service = RecorderService() # Placeholder
@@ -151,7 +153,6 @@ def create_workflow():
151153
"""
152154
if not recording_service:
153155
# Adjusted RecordingService initialization check assuming it doesn't need LLM
154-
# If it does, this check should be more robust (e.g. based on llm_instance)
155156
typer.secho(
156157
'RecordingService not available. Cannot create workflow.',
157158
fg=typer.colors.RED,
@@ -279,7 +280,7 @@ def run_as_tool_command(
279280

280281
try:
281282
# Pass llm_instance to ensure the workflow can use it if needed for as_tool() or run_with_prompt()
282-
workflow_obj = Workflow.load_from_file(str(workflow_path), llm=llm_instance)
283+
workflow_obj = Workflow.load_from_file(str(workflow_path), llm=llm_instance, page_extraction_llm=page_extraction_llm)
283284
except Exception as e:
284285
typer.secho(f'Error loading workflow: {e}', fg=typer.colors.RED)
285286
raise typer.Exit(code=1)
@@ -328,7 +329,11 @@ def run_workflow_command(
328329
browser_instance = Browser() # Add any necessary config if required
329330
controller_instance = WorkflowController() # Add any necessary config if required
330331
workflow_obj = Workflow.load_from_file(
331-
str(workflow_path), llm=llm_instance, browser=browser_instance, controller=controller_instance
332+
str(workflow_path),
333+
llm=llm_instance,
334+
browser=browser_instance,
335+
controller=controller_instance,
336+
page_extraction_llm=page_extraction_llm,
332337
)
333338
except Exception as e:
334339
typer.secho(f'Error loading workflow: {e}', fg=typer.colors.RED)
@@ -389,7 +394,7 @@ def run_workflow_command(
389394
typer.secho('\nWorkflow execution completed!', fg=typer.colors.GREEN, bold=True)
390395
typer.echo(typer.style('Result:', bold=True))
391396
# Output the number of steps executed, similar to previous behavior
392-
typer.echo(f'{typer.style(str(len(result)), bold=True)} steps executed.')
397+
typer.echo(f'{typer.style(str(len(result.step_results)), bold=True)} steps executed.')
393398
# For more detailed results, one might want to iterate through the 'result' list
394399
# and print each item, or serialize the whole list to JSON.
395400
# For now, sticking to the step count as per original output.
@@ -415,7 +420,9 @@ def mcp_server_command(
415420
typer.echo() # Add space
416421

417422
llm_instance = ChatOpenAI(model='gpt-4o')
418-
mcp = get_mcp_server(llm_instance, workflow_dir='./tmp')
423+
page_extraction_llm = ChatOpenAI(model='gpt-4o-mini')
424+
425+
mcp = get_mcp_server(llm_instance, page_extraction_llm=page_extraction_llm, workflow_dir='./tmp')
419426

420427
mcp.run(
421428
transport='sse',

workflows/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ quote-style = "single"
4545
indent-style = "tab"
4646
docstring-code-format = true
4747

48+
[tool.pyright]
49+
typeCheckingMode = "basic"
50+
4851
[build-system]
4952
requires = ["hatchling"]
5053
build-backend = "hatchling.build"

workflows/workflow_use/builder/prompts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
- Evaluating content to match user input (e.g., finding a specific item based on its name or attributes).
3535
- Break complex tasks into multiple specific agentic steps rather than one broad task.
3636
- **Use the user’s goal (if provided) or inferred intent from the recording** to identify where agentic steps are needed for dynamic content, even if the recording uses deterministic steps.
37+
- **extract_page_content** - Use this type when you want to extract data from the page. If the task is simply extracting data from the page, use this instead of agentic steps (never create agentic step for simple data extraction).
3738
- **Deterministic events** → keep the original recorder event structure. The
3839
value of `"type"` MUST match **exactly** one of the available action
3940
names listed below; all additional keys are interpreted as parameters for

0 commit comments

Comments
 (0)