Skip to content
Open
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
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ python cli.py generate-workflow "Your task" \
--extraction-model "gpt-4.1-mini" \
--workflow-model "gpt-4o"

# Route generation through OrcaRouter's gateway (adaptive routing, failover,
# observability) using an OpenAI-compatible endpoint
python cli.py generate-workflow "Your task" \
--llm-provider orcarouter \
--agent-model "orcarouter/auto" \
--extraction-model "orcarouter/auto"

# Use Browser-Use Cloud browser
python cli.py generate-workflow "Your task" --use-cloud

Expand Down
5 changes: 4 additions & 1 deletion workflows/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# We support all langchain models, openai only for demo purposes
OPENAI_API_KEY=
GROQ_API_KEY=
GROQ_API_KEY=
# Optional: use OrcaRouter as the LLM provider for workflow generation
# (set --llm-provider orcarouter on `generate-workflow`)
ORCAROUTER_API_KEY=
28 changes: 25 additions & 3 deletions workflows/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import pandas as pd
import typer
from browser_use import Browser
from browser_use.llm import ChatBrowserUse
from browser_use.llm import ChatBrowserUse, ChatOpenAI
from browser_use.llm.base import BaseChatModel

from workflow_use.builder.service import BuilderService
Expand Down Expand Up @@ -2300,6 +2300,23 @@ def generate_csv_template_command(
# ==================== GENERATION MODE COMMANDS ====================


def _build_generation_llm(model: str, llm_provider: str) -> BaseChatModel:
"""Build the LLM used for workflow generation for a given provider.

``orcarouter`` points an OpenAI-compatible client at OrcaRouter's gateway so
its adaptive routing / failover stack is used directly. Any other value keeps
the existing browser-use cloud behavior (the ``bu-latest`` alias is resolved
by the gateway to the current premium model).
"""
if llm_provider == 'orcarouter':
return ChatOpenAI(
model=model,
base_url='https://api.orcarouter.ai/v1',
api_key=os.getenv('ORCAROUTER_API_KEY'),

@cubic-dev-ai cubic-dev-ai Bot Aug 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When ORCAROUTER_API_KEY is unset, os.getenv returns None, which ChatOpenAI drops from its client params and AsyncOpenAI then fills by falling back to OPENAI_API_KEY. The result is your OpenAI key being sent to OrcaRouter's endpoint, or a confusing client error if no key is set. Validate the key is non-empty before building the orcarouter LLM.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At workflows/cli.py, line 2315:

<comment>When `ORCAROUTER_API_KEY` is unset, `os.getenv` returns None, which ChatOpenAI drops from its client params and AsyncOpenAI then fills by falling back to `OPENAI_API_KEY`. The result is your OpenAI key being sent to OrcaRouter's endpoint, or a confusing client error if no key is set. Validate the key is non-empty before building the orcarouter LLM.</comment>

<file context>
@@ -2300,6 +2300,23 @@ def generate_csv_template_command(
+		return ChatOpenAI(
+			model=model,
+			base_url='https://api.orcarouter.ai/v1',
+			api_key=os.getenv('ORCAROUTER_API_KEY'),
+		)
+	return ChatBrowserUse(model='bu-latest')
</file context>
Fix with cubic

)
return ChatBrowserUse(model='bu-latest')

@cubic-dev-ai cubic-dev-ai Bot Aug 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When the default browser-use provider is selected, --agent-model and --extraction-model are ignored because this branch always creates bu-latest. Pass model to ChatBrowserUse so the documented custom-model options work for the default provider.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At workflows/cli.py, line 2317:

<comment>When the default `browser-use` provider is selected, `--agent-model` and `--extraction-model` are ignored because this branch always creates `bu-latest`. Pass `model` to `ChatBrowserUse` so the documented custom-model options work for the default provider.</comment>

<file context>
@@ -2300,6 +2300,23 @@ def generate_csv_template_command(
+			base_url='https://api.orcarouter.ai/v1',
+			api_key=os.getenv('ORCAROUTER_API_KEY'),
+		)
+	return ChatBrowserUse(model='bu-latest')
+
+
</file context>
Suggested change
return ChatBrowserUse(model='bu-latest')
return ChatBrowserUse(model=model)
Fix with cubic

Comment on lines +2311 to +2317

@cubic-dev-ai cubic-dev-ai Bot Aug 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: When --llm-provider contains a typo or unsupported value, this fallback silently uses Browser-Use instead of rejecting the provider. Validate browser-use explicitly and raise a CLI parameter error for every other value.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At workflows/cli.py, line 2311:

<comment>When `--llm-provider` contains a typo or unsupported value, this fallback silently uses Browser-Use instead of rejecting the provider. Validate `browser-use` explicitly and raise a CLI parameter error for every other value.</comment>

<file context>
@@ -2300,6 +2300,23 @@ def generate_csv_template_command(
+	the existing browser-use cloud behavior (the ``bu-latest`` alias is resolved
+	by the gateway to the current premium model).
+	"""
+	if llm_provider == 'orcarouter':
+		return ChatOpenAI(
+			model=model,
</file context>
Suggested change
if llm_provider == 'orcarouter':
return ChatOpenAI(
model=model,
base_url='https://api.orcarouter.ai/v1',
api_key=os.getenv('ORCAROUTER_API_KEY'),
)
return ChatBrowserUse(model='bu-latest')
if llm_provider == 'orcarouter':
return ChatOpenAI(
model=model,
base_url='https://api.orcarouter.ai/v1',
api_key=os.getenv('ORCAROUTER_API_KEY'),
)
elif llm_provider == 'browser-use':
return ChatBrowserUse(model='bu-latest')
raise typer.BadParameter(f'Unsupported LLM provider: {llm_provider}')
Fix with cubic



@app.command(name='generate-workflow')
def generate_workflow_from_task(
task: str = typer.Argument(..., help='The task to automate (e.g., "Fill out the contact form")'),
Expand All @@ -2309,6 +2326,10 @@ def generate_workflow_from_task(
save_to_storage: bool = typer.Option(True, help='Save workflow to storage database'),
output_file: Path | None = typer.Option(None, help='Optional: Save to specific file path'),
use_cloud: bool = typer.Option(False, help='Use Browser-Use Cloud browser'),
llm_provider: str = typer.Option(
'browser-use',
help='LLM provider for workflow generation: "browser-use" (default) or "orcarouter"',
),
):
"""
🤖 GENERATION MODE: Generate a semantic workflow from a task description.
Expand All @@ -2331,10 +2352,11 @@ def generate_workflow_from_task(
typer.echo()

# Initialize LLMs
agent_llm = ChatBrowserUse(model='bu-latest')
extraction_llm = ChatBrowserUse(model='bu-latest')
agent_llm = _build_generation_llm(agent_model, llm_provider)
extraction_llm = _build_generation_llm(extraction_model, llm_provider)

typer.echo('Starting browser automation to complete the task...')
typer.echo(f' LLM Provider: {llm_provider}')
typer.echo(f' Agent Model: {agent_model}')
typer.echo(f' Extraction Model: {extraction_model}')
typer.echo(f' Workflow Model: {workflow_model}')
Expand Down