|
7 | 7 | from pathlib import Path
|
8 | 8 |
|
9 | 9 | import typer
|
10 |
| -from browser_use.browser.browser import Browser |
| 10 | +from browser_use import Browser |
11 | 11 |
|
12 | 12 | # Assuming OPENAI_API_KEY is set in the environment
|
13 | 13 | from langchain_openai import ChatOpenAI
|
| 14 | +from patchright.async_api import async_playwright as patchright_async_playwright |
14 | 15 |
|
15 | 16 | from workflow_use.builder.service import BuilderService
|
16 | 17 | from workflow_use.controller.service import WorkflowController
|
@@ -318,90 +319,96 @@ def run_workflow_command(
|
318 | 319 | """
|
319 | 320 | Loads and executes a workflow, prompting the user for required inputs.
|
320 | 321 | """
|
321 |
| - typer.echo( |
322 |
| - typer.style(f'Loading workflow from: {typer.style(str(workflow_path.resolve()), fg=typer.colors.MAGENTA)}', bold=True) |
323 |
| - ) |
324 |
| - typer.echo() # Add space |
325 | 322 |
|
326 |
| - try: |
327 |
| - # Instantiate Browser and WorkflowController for the Workflow instance |
328 |
| - # Pass llm_instance for potential agent fallbacks or agentic steps |
329 |
| - browser_instance = Browser() # Add any necessary config if required |
330 |
| - controller_instance = WorkflowController() # Add any necessary config if required |
331 |
| - workflow_obj = Workflow.load_from_file( |
332 |
| - str(workflow_path), |
333 |
| - llm=llm_instance, |
334 |
| - browser=browser_instance, |
335 |
| - controller=controller_instance, |
336 |
| - page_extraction_llm=page_extraction_llm, |
| 323 | + async def _run_workflow(): |
| 324 | + typer.echo( |
| 325 | + typer.style(f'Loading workflow from: {typer.style(str(workflow_path.resolve()), fg=typer.colors.MAGENTA)}', bold=True) |
337 | 326 | )
|
338 |
| - except Exception as e: |
339 |
| - typer.secho(f'Error loading workflow: {e}', fg=typer.colors.RED) |
340 |
| - raise typer.Exit(code=1) |
341 |
| - |
342 |
| - typer.secho('Workflow loaded successfully.', fg=typer.colors.GREEN, bold=True) |
343 |
| - |
344 |
| - inputs = {} |
345 |
| - input_definitions = workflow_obj.inputs_def # Access inputs_def from the Workflow instance |
346 |
| - |
347 |
| - if input_definitions: # Check if the list is not empty |
348 |
| - typer.echo() # Add space |
349 |
| - typer.echo(typer.style('Provide values for the following workflow inputs:', bold=True)) |
350 | 327 | typer.echo() # Add space
|
351 | 328 |
|
352 |
| - for input_def in input_definitions: |
353 |
| - var_name_styled = typer.style(input_def.name, fg=typer.colors.CYAN, bold=True) |
354 |
| - prompt_question = typer.style(f'Enter value for {var_name_styled}', bold=True) |
355 |
| - |
356 |
| - var_type = input_def.type.lower() # type is a direct attribute |
357 |
| - is_required = input_def.required |
358 |
| - |
359 |
| - type_info_str = f'type: {var_type}' |
360 |
| - if is_required: |
361 |
| - status_str = typer.style('required', fg=typer.colors.RED) |
362 |
| - else: |
363 |
| - status_str = typer.style('optional', fg=typer.colors.YELLOW) |
364 |
| - |
365 |
| - full_prompt_text = f'{prompt_question} ({status_str}, {type_info_str})' |
366 |
| - |
367 |
| - input_val = None |
368 |
| - if var_type == 'bool': |
369 |
| - input_val = typer.confirm(full_prompt_text) |
370 |
| - elif var_type == 'number': |
371 |
| - input_val = typer.prompt(full_prompt_text, type=float) |
372 |
| - elif var_type == 'string': # Default to string for other unknown types as well |
373 |
| - input_val = typer.prompt(full_prompt_text, type=str) |
374 |
| - else: # Should ideally not happen if schema is validated, but good to have a fallback |
375 |
| - typer.secho( |
376 |
| - f"Warning: Unknown type '{var_type}' for variable '{input_def.name}'. Treating as string.", |
377 |
| - fg=typer.colors.YELLOW, |
378 |
| - ) |
379 |
| - input_val = typer.prompt(full_prompt_text, type=str) |
380 |
| - |
381 |
| - inputs[input_def.name] = input_val |
382 |
| - typer.echo() # Add space after each prompt |
383 |
| - else: |
384 |
| - typer.echo('No input schema found in the workflow, or no properties defined. Proceeding without inputs.') |
| 329 | + try: |
| 330 | + # Instantiate Browser and WorkflowController for the Workflow instance |
| 331 | + # Pass llm_instance for potential agent fallbacks or agentic steps |
| 332 | + playwright = await patchright_async_playwright().start() |
| 333 | + |
| 334 | + browser = Browser(playwright=playwright) |
| 335 | + controller_instance = WorkflowController() # Add any necessary config if required |
| 336 | + workflow_obj = Workflow.load_from_file( |
| 337 | + str(workflow_path), |
| 338 | + browser=browser, |
| 339 | + llm=llm_instance, |
| 340 | + controller=controller_instance, |
| 341 | + page_extraction_llm=page_extraction_llm, |
| 342 | + ) |
| 343 | + except Exception as e: |
| 344 | + typer.secho(f'Error loading workflow: {e}', fg=typer.colors.RED) |
| 345 | + raise typer.Exit(code=1) |
385 | 346 |
|
386 |
| - typer.echo() # Add space |
387 |
| - typer.echo(typer.style('Running workflow...', bold=True)) |
| 347 | + typer.secho('Workflow loaded successfully.', fg=typer.colors.GREEN, bold=True) |
| 348 | + |
| 349 | + inputs = {} |
| 350 | + input_definitions = workflow_obj.inputs_def # Access inputs_def from the Workflow instance |
| 351 | + |
| 352 | + if input_definitions: # Check if the list is not empty |
| 353 | + typer.echo() # Add space |
| 354 | + typer.echo(typer.style('Provide values for the following workflow inputs:', bold=True)) |
| 355 | + typer.echo() # Add space |
| 356 | + |
| 357 | + for input_def in input_definitions: |
| 358 | + var_name_styled = typer.style(input_def.name, fg=typer.colors.CYAN, bold=True) |
| 359 | + prompt_question = typer.style(f'Enter value for {var_name_styled}', bold=True) |
| 360 | + |
| 361 | + var_type = input_def.type.lower() # type is a direct attribute |
| 362 | + is_required = input_def.required |
| 363 | + |
| 364 | + type_info_str = f'type: {var_type}' |
| 365 | + if is_required: |
| 366 | + status_str = typer.style('required', fg=typer.colors.RED) |
| 367 | + else: |
| 368 | + status_str = typer.style('optional', fg=typer.colors.YELLOW) |
| 369 | + |
| 370 | + full_prompt_text = f'{prompt_question} ({status_str}, {type_info_str})' |
| 371 | + |
| 372 | + input_val = None |
| 373 | + if var_type == 'bool': |
| 374 | + input_val = typer.confirm(full_prompt_text) |
| 375 | + elif var_type == 'number': |
| 376 | + input_val = typer.prompt(full_prompt_text, type=float) |
| 377 | + elif var_type == 'string': # Default to string for other unknown types as well |
| 378 | + input_val = typer.prompt(full_prompt_text, type=str) |
| 379 | + else: # Should ideally not happen if schema is validated, but good to have a fallback |
| 380 | + typer.secho( |
| 381 | + f"Warning: Unknown type '{var_type}' for variable '{input_def.name}'. Treating as string.", |
| 382 | + fg=typer.colors.YELLOW, |
| 383 | + ) |
| 384 | + input_val = typer.prompt(full_prompt_text, type=str) |
| 385 | + |
| 386 | + inputs[input_def.name] = input_val |
| 387 | + typer.echo() # Add space after each prompt |
| 388 | + else: |
| 389 | + typer.echo('No input schema found in the workflow, or no properties defined. Proceeding without inputs.') |
388 | 390 |
|
389 |
| - try: |
390 |
| - # Call run on the Workflow instance |
391 |
| - # close_browser_at_end=True is the default for Workflow.run, but explicit for clarity |
392 |
| - result = asyncio.run(workflow_obj.run(inputs=inputs, close_browser_at_end=True)) |
| 391 | + typer.echo() # Add space |
| 392 | + typer.echo(typer.style('Running workflow...', bold=True)) |
393 | 393 |
|
394 |
| - typer.secho('\nWorkflow execution completed!', fg=typer.colors.GREEN, bold=True) |
395 |
| - typer.echo(typer.style('Result:', bold=True)) |
396 |
| - # Output the number of steps executed, similar to previous behavior |
397 |
| - typer.echo(f'{typer.style(str(len(result.step_results)), bold=True)} steps executed.') |
398 |
| - # For more detailed results, one might want to iterate through the 'result' list |
399 |
| - # and print each item, or serialize the whole list to JSON. |
400 |
| - # For now, sticking to the step count as per original output. |
| 394 | + try: |
| 395 | + # Call run on the Workflow instance |
| 396 | + # close_browser_at_end=True is the default for Workflow.run, but explicit for clarity |
| 397 | + result = await workflow_obj.run(inputs=inputs, close_browser_at_end=True) |
| 398 | + |
| 399 | + typer.secho('\nWorkflow execution completed!', fg=typer.colors.GREEN, bold=True) |
| 400 | + typer.echo(typer.style('Result:', bold=True)) |
| 401 | + # Output the number of steps executed, similar to previous behavior |
| 402 | + typer.echo(f'{typer.style(str(len(result.step_results)), bold=True)} steps executed.') |
| 403 | + # For more detailed results, one might want to iterate through the 'result' list |
| 404 | + # and print each item, or serialize the whole list to JSON. |
| 405 | + # For now, sticking to the step count as per original output. |
| 406 | + |
| 407 | + except Exception as e: |
| 408 | + typer.secho(f'Error running workflow: {e}', fg=typer.colors.RED) |
| 409 | + raise typer.Exit(code=1) |
401 | 410 |
|
402 |
| - except Exception as e: |
403 |
| - typer.secho(f'Error running workflow: {e}', fg=typer.colors.RED) |
404 |
| - raise typer.Exit(code=1) |
| 411 | + return asyncio.run(_run_workflow()) |
405 | 412 |
|
406 | 413 |
|
407 | 414 | @app.command(name='mcp-server', help='Starts the MCP server which expose all the created workflows as tools.')
|
|
0 commit comments