From 91e0d8ecf0f88ea3aa43ca8f92f85485eda16889 Mon Sep 17 00:00:00 2001 From: Guido Trevisan Date: Tue, 20 May 2025 14:01:52 -0500 Subject: [PATCH 1/2] added support for openrouter --- workflows/.env.example | 5 ++-- workflows/cli.py | 33 ++++++++++++++++++------ workflows/workflow_use/llm/openrouter.py | 21 +++++++++++++++ 3 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 workflows/workflow_use/llm/openrouter.py diff --git a/workflows/.env.example b/workflows/.env.example index 3d6a3f43..b93375a3 100644 --- a/workflows/.env.example +++ b/workflows/.env.example @@ -1,2 +1,3 @@ -# We support all langchain models, openai only for demo purposes -OPENAI_API_KEY= \ No newline at end of file +# We support all openrouter models and langchain openai for demo purposes +OPENAI_API_KEY= +OPENROUTER_API_KEY= \ No newline at end of file diff --git a/workflows/cli.py b/workflows/cli.py index b2cc4734..ad354d64 100644 --- a/workflows/cli.py +++ b/workflows/cli.py @@ -1,5 +1,6 @@ import asyncio import json +import os import tempfile # For temporary file handling from pathlib import Path @@ -11,6 +12,7 @@ from workflow_use.builder.service import BuilderService from workflow_use.controller.service import WorkflowController +from workflow_use.llm.openrouter import ChatOpenRouter from workflow_use.recorder.service import RecordingService # Added import from workflow_use.workflow.service import Workflow @@ -27,14 +29,29 @@ # Default LLM instance to None llm_instance = None try: - llm_instance = ChatOpenAI(model='gpt-4o') -except Exception as e: - typer.secho(f'Error initializing LLM: {e}. Would you like to set your OPENAI_API_KEY?', fg=typer.colors.RED) - set_openai_api_key = input('Set OPENAI_API_KEY? (y/n): ') - if set_openai_api_key.lower() == 'y': - os.environ['OPENAI_API_KEY'] = input('Enter your OPENAI_API_KEY: ') + if os.getenv('OPENROUTER_API_KEY'): + llm_instance = ChatOpenRouter(model='openai/gpt-4o') + + elif os.getenv('OPENAI_API_KEY'): llm_instance = ChatOpenAI(model='gpt-4o') + else: + typer.secho( + 'No LLM API key found. Set OPENROUTER_API_KEY or OPENAI_API_KEY.', + fg=typer.colors.RED, + ) + +except Exception as e: + typer.secho(f'Error initialising LLM: {e}', fg=typer.colors.RED) + llm_instance = None + +if llm_instance is None: + typer.secho( + 'No valid LLM configured. Set OPENROUTER_API_KEY or OPENAI_API_KEY.', + fg=typer.colors.RED, + ) + raise typer.Exit(code=1) + builder_service = BuilderService(llm=llm_instance) if llm_instance else None # recorder_service = RecorderService() # Placeholder recording_service = ( @@ -119,9 +136,9 @@ def _build_and_save_workflow_from_recording( typer.style('Enter a name for the generated workflow file', bold=True) + ' (e.g., my_search.workflow.json):', default=default_workflow_filename, ) - # Ensure the file name ends with .json + # Ensure the file name ends with .json if not workflow_output_name.endswith('.json'): - workflow_output_name = f"{workflow_output_name}.json" + workflow_output_name = f'{workflow_output_name}.json' final_workflow_path = output_dir / workflow_output_name try: diff --git a/workflows/workflow_use/llm/openrouter.py b/workflows/workflow_use/llm/openrouter.py new file mode 100644 index 00000000..bc767bea --- /dev/null +++ b/workflows/workflow_use/llm/openrouter.py @@ -0,0 +1,21 @@ +import os + +from langchain_openai import ChatOpenAI +from pydantic import SecretStr + + +class ChatOpenRouter(ChatOpenAI): + def __init__( + self, + model: str, + openai_api_key: str | None = None, + openai_api_base: str = 'https://openrouter.ai/api/v1', + **kwargs, + ): + key = openai_api_key or os.getenv('OPENROUTER_API_KEY') + super().__init__( + openai_api_base=openai_api_base, + openai_api_key=SecretStr(key) if key else None, + model_name=model, + **kwargs, + ) From e63ca5fff2ca9f37fb2458802db319167219f644 Mon Sep 17 00:00:00 2001 From: Guido Trevisan Date: Tue, 20 May 2025 19:47:53 -0500 Subject: [PATCH 2/2] added comments / removed redundancy --- workflows/cli.py | 31 +++++++++--------------- workflows/workflow_use/llm/openrouter.py | 4 +-- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/workflows/cli.py b/workflows/cli.py index ad354d64..10516a25 100644 --- a/workflows/cli.py +++ b/workflows/cli.py @@ -28,29 +28,22 @@ # Default LLM instance to None llm_instance = None -try: - if os.getenv('OPENROUTER_API_KEY'): - llm_instance = ChatOpenRouter(model='openai/gpt-4o') - - elif os.getenv('OPENAI_API_KEY'): - llm_instance = ChatOpenAI(model='gpt-4o') - - else: - typer.secho( - 'No LLM API key found. Set OPENROUTER_API_KEY or OPENAI_API_KEY.', - fg=typer.colors.RED, - ) +try: + if os.getenv("OPENROUTER_API_KEY"): + llm_instance = ChatOpenRouter(model="openai/gpt-4o") + elif os.getenv("OPENAI_API_KEY"): + llm_instance = ChatOpenAI(model="gpt-4o") except Exception as e: - typer.secho(f'Error initialising LLM: {e}', fg=typer.colors.RED) - llm_instance = None + typer.secho(f"Error initialising LLM: {e}", fg=typer.colors.RED) + raise typer.Exit(code=1) if llm_instance is None: - typer.secho( - 'No valid LLM configured. Set OPENROUTER_API_KEY or OPENAI_API_KEY.', - fg=typer.colors.RED, - ) - raise typer.Exit(code=1) + typer.secho( + "No LLM API key found. Set OPENROUTER_API_KEY or OPENAI_API_KEY.", + fg=typer.colors.RED, + ) + raise typer.Exit(code=1) builder_service = BuilderService(llm=llm_instance) if llm_instance else None # recorder_service = RecorderService() # Placeholder diff --git a/workflows/workflow_use/llm/openrouter.py b/workflows/workflow_use/llm/openrouter.py index bc767bea..37506ecf 100644 --- a/workflows/workflow_use/llm/openrouter.py +++ b/workflows/workflow_use/llm/openrouter.py @@ -3,7 +3,7 @@ from langchain_openai import ChatOpenAI from pydantic import SecretStr - +# Adds support for LLM integration via OpenRouter class ChatOpenRouter(ChatOpenAI): def __init__( self, @@ -12,7 +12,7 @@ def __init__( openai_api_base: str = 'https://openrouter.ai/api/v1', **kwargs, ): - key = openai_api_key or os.getenv('OPENROUTER_API_KEY') + key = openai_api_key super().__init__( openai_api_base=openai_api_base, openai_api_key=SecretStr(key) if key else None,