From dc765e6491c1e341fb931cceb5fe9319bb1b0050 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 22 Feb 2025 16:36:25 +0000 Subject: [PATCH] fix: Add Mistral provider configuration and tests (#2200) - Add Mistral provider to constants.py with API key config - Add Mistral models to available models list - Fix env file creation to only write when API keys are provided - Add tests for Mistral provider setup with and without API key Fixes #2200 Co-Authored-By: Joe Moura --- src/crewai/cli/constants.py | 13 +++++++ src/crewai/cli/create_crew.py | 7 +++- tests/cli/cli_test.py | 64 +++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/crewai/cli/constants.py b/src/crewai/cli/constants.py index 13279f8d3..2608aefc6 100644 --- a/src/crewai/cli/constants.py +++ b/src/crewai/cli/constants.py @@ -5,6 +5,12 @@ ENV_VARS = { "key_name": "OPENAI_API_KEY", } ], + "mistral": [ + { + "prompt": "Enter your MISTRAL API key (press Enter to skip)", + "key_name": "MISTRAL_API_KEY", + } + ], "anthropic": [ { "prompt": "Enter your ANTHROPIC API key (press Enter to skip)", @@ -98,10 +104,17 @@ PROVIDERS = [ "bedrock", "azure", "cerebras", + "mistral", ] MODELS = { "openai": ["gpt-4", "gpt-4o", "gpt-4o-mini", "o1-mini", "o1-preview"], + "mistral": [ + "mistral-tiny", + "mistral-small", + "mistral-medium", + "mistral-large", + ], "anthropic": [ "claude-3-5-sonnet-20240620", "claude-3-sonnet-20240229", diff --git a/src/crewai/cli/create_crew.py b/src/crewai/cli/create_crew.py index c658b0de1..3a83d1fe3 100644 --- a/src/crewai/cli/create_crew.py +++ b/src/crewai/cli/create_crew.py @@ -162,7 +162,12 @@ def create_crew(name, provider=None, skip_provider=False, parent_folder=None): if api_key_value.strip(): env_vars[key_name] = api_key_value - if env_vars: + # Only write env file if we have API keys + has_api_keys = any( + key in env_vars and env_vars[key].strip() + for key in ["MISTRAL_API_KEY", "OPENAI_API_KEY", "ANTHROPIC_API_KEY"] + ) + if has_api_keys: write_env_file(folder_path, env_vars) click.secho("API keys and model saved to .env file", fg="green") else: diff --git a/tests/cli/cli_test.py b/tests/cli/cli_test.py index 15ed81637..4106a61b1 100644 --- a/tests/cli/cli_test.py +++ b/tests/cli/cli_test.py @@ -20,6 +20,7 @@ from crewai.cli.cli import ( ) +from crewai.cli.cli import create @pytest.fixture def runner(): return CliRunner() @@ -309,6 +310,69 @@ def test_flow_add_crew(mock_path_exists, mock_create_embedded_crew, runner): assert isinstance(call_kwargs["parent_folder"], Path) +@mock.patch("crewai.cli.create_crew.write_env_file") +@mock.patch("crewai.cli.create_crew.load_env_vars") +@mock.patch("crewai.cli.create_crew.get_provider_data") +@mock.patch("crewai.cli.create_crew.select_model") +@mock.patch("crewai.cli.create_crew.select_provider") +@mock.patch("crewai.cli.create_crew.click.confirm") +@mock.patch("crewai.cli.create_crew.click.prompt") +def test_create_crew_with_mistral_provider( + mock_prompt, mock_confirm, mock_select_provider, mock_select_model, + mock_get_provider_data, mock_load_env_vars, mock_write_env_file, runner +): + # Mock folder override confirmation + mock_confirm.return_value = True + # Mock provider data + mock_get_provider_data.return_value = {"mistral": ["mistral-tiny"]} + # Mock empty env vars + mock_load_env_vars.return_value = {} + # Mock provider and model selection + mock_select_provider.return_value = "mistral" + mock_select_model.return_value = "mistral-tiny" + # Mock API key input + mock_prompt.return_value = "mistral_api_key_123" + + # Run the command + result = runner.invoke(create, ["crew", "test_crew"]) + + assert result.exit_code == 0 + assert "API keys and model saved to .env file" in result.output + assert "Selected model: mistral-tiny" in result.output + +@mock.patch("crewai.cli.create_crew.write_env_file") +@mock.patch("crewai.cli.create_crew.load_env_vars") +@mock.patch("crewai.cli.create_crew.get_provider_data") +@mock.patch("crewai.cli.create_crew.select_model") +@mock.patch("crewai.cli.create_crew.select_provider") +@mock.patch("crewai.cli.create_crew.click.confirm") +@mock.patch("crewai.cli.create_crew.click.prompt") +def test_create_crew_with_mistral_provider_no_key( + mock_prompt, mock_confirm, mock_select_provider, mock_select_model, + mock_get_provider_data, mock_load_env_vars, mock_write_env_file, runner +): + # Mock folder override confirmation + mock_confirm.return_value = True + # Mock provider data + mock_get_provider_data.return_value = {"mistral": ["mistral-tiny"]} + # Mock empty env vars + mock_load_env_vars.return_value = {} + # Mock provider and model selection + mock_select_provider.return_value = "mistral" + mock_select_model.return_value = "mistral-tiny" + # Mock empty API key input for all prompts + mock_prompt.side_effect = [""] * 10 # Enough empty responses for all prompts + + # Run the command + result = runner.invoke(create, ["crew", "test_crew"]) + + assert result.exit_code == 0 + assert "No API keys provided. Skipping .env file creation." in result.output + # Verify env file was not written since no API keys were provided + mock_write_env_file.assert_not_called() + # Verify model was still selected + assert "Selected model: mistral-tiny" in result.output + def test_add_crew_to_flow_not_in_root(runner): # Simulate not being in the root of a flow project with mock.patch("pathlib.Path.exists", autospec=True) as mock_exists: