mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-09 08:08:32 +00:00
Merge branch 'main' into devin/1754007084-fix-agentops-example-links
This commit is contained in:
@@ -88,7 +88,7 @@ crewai replay [OPTIONS]
|
|||||||
- `-t, --task_id TEXT`: Replay the crew from this task ID, including all subsequent tasks
|
- `-t, --task_id TEXT`: Replay the crew from this task ID, including all subsequent tasks
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```shell Terminal
|
```shell Terminal
|
||||||
crewai replay -t task_123456
|
crewai replay -t task_123456
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ crewai test [OPTIONS]
|
|||||||
- `-m, --model TEXT`: LLM Model to run the tests on the Crew (default: "gpt-4o-mini")
|
- `-m, --model TEXT`: LLM Model to run the tests on the Crew (default: "gpt-4o-mini")
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
```shell Terminal
|
```shell Terminal
|
||||||
crewai test -n 5 -m gpt-3.5-turbo
|
crewai test -n 5 -m gpt-3.5-turbo
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@ Starting from version 0.103.0, the `crewai run` command can be used to run both
|
|||||||
</Note>
|
</Note>
|
||||||
|
|
||||||
<Note>
|
<Note>
|
||||||
Make sure to run these commands from the directory where your CrewAI project is set up.
|
Make sure to run these commands from the directory where your CrewAI project is set up.
|
||||||
Some commands may require additional configuration or setup within your project structure.
|
Some commands may require additional configuration or setup within your project structure.
|
||||||
</Note>
|
</Note>
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ You must be authenticated to CrewAI Enterprise to use these organization managem
|
|||||||
- **Deploy the Crew**: Once you are authenticated, you can deploy your crew or flow to CrewAI Enterprise.
|
- **Deploy the Crew**: Once you are authenticated, you can deploy your crew or flow to CrewAI Enterprise.
|
||||||
```shell Terminal
|
```shell Terminal
|
||||||
crewai deploy push
|
crewai deploy push
|
||||||
```
|
```
|
||||||
- Initiates the deployment process on the CrewAI Enterprise platform.
|
- Initiates the deployment process on the CrewAI Enterprise platform.
|
||||||
- Upon successful initiation, it will output the Deployment created successfully! message along with the Deployment Name and a unique Deployment ID (UUID).
|
- Upon successful initiation, it will output the Deployment created successfully! message along with the Deployment Name and a unique Deployment ID (UUID).
|
||||||
|
|
||||||
@@ -309,3 +309,82 @@ When you select a provider, the CLI will prompt you to enter the Key name and th
|
|||||||
See the following link for each provider's key name:
|
See the following link for each provider's key name:
|
||||||
|
|
||||||
* [LiteLLM Providers](https://docs.litellm.ai/docs/providers)
|
* [LiteLLM Providers](https://docs.litellm.ai/docs/providers)
|
||||||
|
|
||||||
|
### 12. Configuration Management
|
||||||
|
|
||||||
|
Manage CLI configuration settings for CrewAI.
|
||||||
|
|
||||||
|
```shell Terminal
|
||||||
|
crewai config [COMMAND] [OPTIONS]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Commands:
|
||||||
|
|
||||||
|
- `list`: Display all CLI configuration parameters
|
||||||
|
```shell Terminal
|
||||||
|
crewai config list
|
||||||
|
```
|
||||||
|
|
||||||
|
- `set`: Set a CLI configuration parameter
|
||||||
|
```shell Terminal
|
||||||
|
crewai config set <key> <value>
|
||||||
|
```
|
||||||
|
|
||||||
|
- `reset`: Reset all CLI configuration parameters to default values
|
||||||
|
```shell Terminal
|
||||||
|
crewai config reset
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Available Configuration Parameters
|
||||||
|
|
||||||
|
- `enterprise_base_url`: Base URL of the CrewAI Enterprise instance
|
||||||
|
- `oauth2_provider`: OAuth2 provider used for authentication (e.g., workos, okta, auth0)
|
||||||
|
- `oauth2_audience`: OAuth2 audience value, typically used to identify the target API or resource
|
||||||
|
- `oauth2_client_id`: OAuth2 client ID issued by the provider, used during authentication requests
|
||||||
|
- `oauth2_domain`: OAuth2 provider's domain (e.g., your-org.auth0.com) used for issuing tokens
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
|
||||||
|
Display current configuration:
|
||||||
|
```shell Terminal
|
||||||
|
crewai config list
|
||||||
|
```
|
||||||
|
|
||||||
|
Example output:
|
||||||
|
```
|
||||||
|
CrewAI CLI Configuration
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ Setting ┃ Value ┃ Description ┃
|
||||||
|
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||||
|
│ enterprise_base_url│ https://app.crewai.com │ Base URL of the CrewAI Enterprise instance │
|
||||||
|
│ org_name │ Not set │ Name of the currently active organization │
|
||||||
|
│ org_uuid │ Not set │ UUID of the currently active organization │
|
||||||
|
│ oauth2_provider │ workos │ OAuth2 provider used for authentication (e.g., workos, okta, auth0). │
|
||||||
|
│ oauth2_audience │ client_01YYY │ OAuth2 audience value, typically used to identify the target API or resource. │
|
||||||
|
│ oauth2_client_id │ client_01XXX │ OAuth2 client ID issued by the provider, used during authentication requests. │
|
||||||
|
│ oauth2_domain │ login.crewai.com │ OAuth2 provider's domain (e.g., your-org.auth0.com) used for issuing tokens. │
|
||||||
|
```
|
||||||
|
|
||||||
|
Set the enterprise base URL:
|
||||||
|
```shell Terminal
|
||||||
|
crewai config set enterprise_base_url https://my-enterprise.crewai.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Set OAuth2 provider:
|
||||||
|
```shell Terminal
|
||||||
|
crewai config set oauth2_provider auth0
|
||||||
|
```
|
||||||
|
|
||||||
|
Set OAuth2 domain:
|
||||||
|
```shell Terminal
|
||||||
|
crewai config set oauth2_domain my-company.auth0.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Reset all configuration to defaults:
|
||||||
|
```shell Terminal
|
||||||
|
crewai config reset
|
||||||
|
```
|
||||||
|
|
||||||
|
<Note>
|
||||||
|
Configuration settings are stored in `~/.config/crewai/settings.json`. Some settings like organization name and UUID are read-only and managed through authentication and organization commands. Tool repository related settings are hidden and cannot be set directly by users.
|
||||||
|
</Note>
|
||||||
|
|||||||
@@ -44,6 +44,19 @@ The `MCPServerAdapter` class from `crewai-tools` is the primary way to connect t
|
|||||||
|
|
||||||
Using a Python context manager (`with` statement) is the **recommended approach** for `MCPServerAdapter`. It automatically handles starting and stopping the connection to the MCP server.
|
Using a Python context manager (`with` statement) is the **recommended approach** for `MCPServerAdapter`. It automatically handles starting and stopping the connection to the MCP server.
|
||||||
|
|
||||||
|
## Connection Configuration
|
||||||
|
|
||||||
|
The `MCPServerAdapter` supports several configuration options to customize the connection behavior:
|
||||||
|
|
||||||
|
- **`connect_timeout`** (optional): Maximum time in seconds to wait for establishing a connection to the MCP server. Defaults to 30 seconds if not specified. This is particularly useful for remote servers that may have variable response times.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Example with custom connection timeout
|
||||||
|
with MCPServerAdapter(server_params, connect_timeout=60) as tools:
|
||||||
|
# Connection will timeout after 60 seconds if not established
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from crewai import Agent
|
from crewai import Agent
|
||||||
from crewai_tools import MCPServerAdapter
|
from crewai_tools import MCPServerAdapter
|
||||||
@@ -70,7 +83,7 @@ server_params = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Example usage (uncomment and adapt once server_params is set):
|
# Example usage (uncomment and adapt once server_params is set):
|
||||||
with MCPServerAdapter(server_params) as mcp_tools:
|
with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
|
||||||
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
|
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
|
||||||
|
|
||||||
my_agent = Agent(
|
my_agent = Agent(
|
||||||
@@ -95,7 +108,7 @@ There are two ways to filter tools:
|
|||||||
### Accessing a specific tool using dictionary-style indexing.
|
### Accessing a specific tool using dictionary-style indexing.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
with MCPServerAdapter(server_params) as mcp_tools:
|
with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
|
||||||
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
|
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
|
||||||
|
|
||||||
my_agent = Agent(
|
my_agent = Agent(
|
||||||
@@ -112,7 +125,7 @@ with MCPServerAdapter(server_params) as mcp_tools:
|
|||||||
### Pass a list of tool names to the `MCPServerAdapter` constructor.
|
### Pass a list of tool names to the `MCPServerAdapter` constructor.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
with MCPServerAdapter(server_params, "tool_name") as mcp_tools:
|
with MCPServerAdapter(server_params, "tool_name", connect_timeout=60) as mcp_tools:
|
||||||
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
|
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
|
||||||
|
|
||||||
my_agent = Agent(
|
my_agent = Agent(
|
||||||
|
|||||||
@@ -324,3 +324,82 @@ Ao escolher um provedor, o CLI solicitará que você informe o nome da chave e a
|
|||||||
Veja o seguinte link para o nome de chave de cada provedor:
|
Veja o seguinte link para o nome de chave de cada provedor:
|
||||||
|
|
||||||
* [LiteLLM Providers](https://docs.litellm.ai/docs/providers)
|
* [LiteLLM Providers](https://docs.litellm.ai/docs/providers)
|
||||||
|
|
||||||
|
### 12. Gerenciamento de Configuração
|
||||||
|
|
||||||
|
Gerencie as configurações do CLI para CrewAI.
|
||||||
|
|
||||||
|
```shell Terminal
|
||||||
|
crewai config [COMANDO] [OPÇÕES]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Comandos:
|
||||||
|
|
||||||
|
- `list`: Exibir todos os parâmetros de configuração do CLI
|
||||||
|
```shell Terminal
|
||||||
|
crewai config list
|
||||||
|
```
|
||||||
|
|
||||||
|
- `set`: Definir um parâmetro de configuração do CLI
|
||||||
|
```shell Terminal
|
||||||
|
crewai config set <chave> <valor>
|
||||||
|
```
|
||||||
|
|
||||||
|
- `reset`: Redefinir todos os parâmetros de configuração do CLI para valores padrão
|
||||||
|
```shell Terminal
|
||||||
|
crewai config reset
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Parâmetros de Configuração Disponíveis
|
||||||
|
|
||||||
|
- `enterprise_base_url`: URL base da instância CrewAI Enterprise
|
||||||
|
- `oauth2_provider`: Provedor OAuth2 usado para autenticação (ex: workos, okta, auth0)
|
||||||
|
- `oauth2_audience`: Valor de audiência OAuth2, tipicamente usado para identificar a API ou recurso de destino
|
||||||
|
- `oauth2_client_id`: ID do cliente OAuth2 emitido pelo provedor, usado durante solicitações de autenticação
|
||||||
|
- `oauth2_domain`: Domínio do provedor OAuth2 (ex: sua-org.auth0.com) usado para emissão de tokens
|
||||||
|
|
||||||
|
#### Exemplos
|
||||||
|
|
||||||
|
Exibir configuração atual:
|
||||||
|
```shell Terminal
|
||||||
|
crewai config list
|
||||||
|
```
|
||||||
|
|
||||||
|
Exemplo de saída:
|
||||||
|
```
|
||||||
|
CrewAI CLI Configuration
|
||||||
|
┏━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||||
|
┃ Setting ┃ Value ┃ Description ┃
|
||||||
|
┡━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||||
|
│ enterprise_base_url│ https://app.crewai.com │ Base URL of the CrewAI Enterprise instance │
|
||||||
|
│ org_name │ Not set │ Name of the currently active organization │
|
||||||
|
│ org_uuid │ Not set │ UUID of the currently active organization │
|
||||||
|
│ oauth2_provider │ workos │ OAuth2 provider used for authentication (e.g., workos, okta, auth0). │
|
||||||
|
│ oauth2_audience │ client_01YYY │ OAuth2 audience value, typically used to identify the target API or resource. │
|
||||||
|
│ oauth2_client_id │ client_01XXX │ OAuth2 client ID issued by the provider, used during authentication requests. │
|
||||||
|
│ oauth2_domain │ login.crewai.com │ OAuth2 provider's domain (e.g., your-org.auth0.com) used for issuing tokens. │
|
||||||
|
```
|
||||||
|
|
||||||
|
Definir a URL base do enterprise:
|
||||||
|
```shell Terminal
|
||||||
|
crewai config set enterprise_base_url https://minha-empresa.crewai.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Definir provedor OAuth2:
|
||||||
|
```shell Terminal
|
||||||
|
crewai config set oauth2_provider auth0
|
||||||
|
```
|
||||||
|
|
||||||
|
Definir domínio OAuth2:
|
||||||
|
```shell Terminal
|
||||||
|
crewai config set oauth2_domain minha-empresa.auth0.com
|
||||||
|
```
|
||||||
|
|
||||||
|
Redefinir todas as configurações para padrões:
|
||||||
|
```shell Terminal
|
||||||
|
crewai config reset
|
||||||
|
```
|
||||||
|
|
||||||
|
<Note>
|
||||||
|
As configurações são armazenadas em `~/.config/crewai/settings.json`. Algumas configurações como nome da organização e UUID são somente leitura e gerenciadas através de comandos de autenticação e organização. Configurações relacionadas ao repositório de ferramentas são ocultas e não podem ser definidas diretamente pelo usuário.
|
||||||
|
</Note>
|
||||||
|
|||||||
@@ -44,6 +44,19 @@ A classe `MCPServerAdapter` da `crewai-tools` é a principal forma de conectar-s
|
|||||||
|
|
||||||
O uso de um gerenciador de contexto Python (`with`) é a **abordagem recomendada** para o `MCPServerAdapter`. Ele lida automaticamente com a abertura e o fechamento da conexão com o servidor MCP.
|
O uso de um gerenciador de contexto Python (`with`) é a **abordagem recomendada** para o `MCPServerAdapter`. Ele lida automaticamente com a abertura e o fechamento da conexão com o servidor MCP.
|
||||||
|
|
||||||
|
## Configuração de Conexão
|
||||||
|
|
||||||
|
O `MCPServerAdapter` suporta várias opções de configuração para personalizar o comportamento da conexão:
|
||||||
|
|
||||||
|
- **`connect_timeout`** (opcional): Tempo máximo em segundos para aguardar o estabelecimento de uma conexão com o servidor MCP. O padrão é 30 segundos se não especificado. Isso é particularmente útil para servidores remotos que podem ter tempos de resposta variáveis.
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Exemplo com timeout personalizado para conexão
|
||||||
|
with MCPServerAdapter(server_params, connect_timeout=60) as tools:
|
||||||
|
# A conexão terá timeout após 60 segundos se não estabelecida
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from crewai import Agent
|
from crewai import Agent
|
||||||
from crewai_tools import MCPServerAdapter
|
from crewai_tools import MCPServerAdapter
|
||||||
@@ -70,7 +83,7 @@ server_params = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Exemplo de uso (descomente e adapte após definir server_params):
|
# Exemplo de uso (descomente e adapte após definir server_params):
|
||||||
with MCPServerAdapter(server_params) as mcp_tools:
|
with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
|
||||||
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
|
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
|
||||||
|
|
||||||
meu_agente = Agent(
|
meu_agente = Agent(
|
||||||
@@ -88,7 +101,7 @@ Este padrão geral mostra como integrar ferramentas. Para exemplos específicos
|
|||||||
## Filtrando Ferramentas
|
## Filtrando Ferramentas
|
||||||
|
|
||||||
```python
|
```python
|
||||||
with MCPServerAdapter(server_params) as mcp_tools:
|
with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
|
||||||
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
|
print(f"Available tools: {[tool.name for tool in mcp_tools]}")
|
||||||
|
|
||||||
meu_agente = Agent(
|
meu_agente = Agent(
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
ALGORITHMS = ["RS256"]
|
ALGORITHMS = ["RS256"]
|
||||||
|
|
||||||
|
#TODO: The AUTH0 constants should be removed after WorkOS migration is completed
|
||||||
AUTH0_DOMAIN = "crewai.us.auth0.com"
|
AUTH0_DOMAIN = "crewai.us.auth0.com"
|
||||||
AUTH0_CLIENT_ID = "DEVC5Fw6NlRoSzmDCcOhVq85EfLBjKa8"
|
AUTH0_CLIENT_ID = "DEVC5Fw6NlRoSzmDCcOhVq85EfLBjKa8"
|
||||||
AUTH0_AUDIENCE = "https://crewai.us.auth0.com/api/v2/"
|
AUTH0_AUDIENCE = "https://crewai.us.auth0.com/api/v2/"
|
||||||
|
|
||||||
WORKOS_DOMAIN = "login.crewai.com"
|
|
||||||
WORKOS_CLI_CONNECT_APP_ID = "client_01JYT06R59SP0NXYGD994NFXXX"
|
|
||||||
WORKOS_ENVIRONMENT_ID = "client_01JNJQWBJ4SPFN3SWJM5T7BDG8"
|
|
||||||
|
|||||||
@@ -1,76 +1,92 @@
|
|||||||
import time
|
import time
|
||||||
import webbrowser
|
import webbrowser
|
||||||
from typing import Any, Dict
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from .constants import (
|
|
||||||
AUTH0_AUDIENCE,
|
|
||||||
AUTH0_CLIENT_ID,
|
|
||||||
AUTH0_DOMAIN,
|
|
||||||
WORKOS_DOMAIN,
|
|
||||||
WORKOS_CLI_CONNECT_APP_ID,
|
|
||||||
WORKOS_ENVIRONMENT_ID,
|
|
||||||
)
|
|
||||||
|
|
||||||
from .utils import TokenManager, validate_jwt_token
|
from .utils import TokenManager, validate_jwt_token
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
from crewai.cli.plus_api import PlusAPI
|
from crewai.cli.plus_api import PlusAPI
|
||||||
from crewai.cli.config import Settings
|
from crewai.cli.config import Settings
|
||||||
|
from crewai.cli.authentication.constants import (
|
||||||
|
AUTH0_AUDIENCE,
|
||||||
|
AUTH0_CLIENT_ID,
|
||||||
|
AUTH0_DOMAIN,
|
||||||
|
)
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
|
|
||||||
|
class Oauth2Settings(BaseModel):
|
||||||
|
provider: str = Field(description="OAuth2 provider used for authentication (e.g., workos, okta, auth0).")
|
||||||
|
client_id: str = Field(description="OAuth2 client ID issued by the provider, used during authentication requests.")
|
||||||
|
domain: str = Field(description="OAuth2 provider's domain (e.g., your-org.auth0.com) used for issuing tokens.")
|
||||||
|
audience: Optional[str] = Field(description="OAuth2 audience value, typically used to identify the target API or resource.", default=None)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_settings(cls):
|
||||||
|
settings = Settings()
|
||||||
|
|
||||||
|
return cls(
|
||||||
|
provider=settings.oauth2_provider,
|
||||||
|
domain=settings.oauth2_domain,
|
||||||
|
client_id=settings.oauth2_client_id,
|
||||||
|
audience=settings.oauth2_audience,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ProviderFactory:
|
||||||
|
@classmethod
|
||||||
|
def from_settings(cls, settings: Optional[Oauth2Settings] = None):
|
||||||
|
settings = settings or Oauth2Settings.from_settings()
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
module = importlib.import_module(f"crewai.cli.authentication.providers.{settings.provider.lower()}")
|
||||||
|
provider = getattr(module, f"{settings.provider.capitalize()}Provider")
|
||||||
|
|
||||||
|
return provider(settings)
|
||||||
|
|
||||||
class AuthenticationCommand:
|
class AuthenticationCommand:
|
||||||
AUTH0_DEVICE_CODE_URL = f"https://{AUTH0_DOMAIN}/oauth/device/code"
|
|
||||||
AUTH0_TOKEN_URL = f"https://{AUTH0_DOMAIN}/oauth/token"
|
|
||||||
|
|
||||||
WORKOS_DEVICE_CODE_URL = f"https://{WORKOS_DOMAIN}/oauth2/device_authorization"
|
|
||||||
WORKOS_TOKEN_URL = f"https://{WORKOS_DOMAIN}/oauth2/token"
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.token_manager = TokenManager()
|
self.token_manager = TokenManager()
|
||||||
# TODO: WORKOS - This variable is temporary until migration to WorkOS is complete.
|
self.oauth2_provider = ProviderFactory.from_settings()
|
||||||
self.user_provider = "workos"
|
|
||||||
|
|
||||||
def login(self) -> None:
|
def login(self) -> None:
|
||||||
"""Sign up to CrewAI+"""
|
"""Sign up to CrewAI+"""
|
||||||
|
|
||||||
device_code_url = self.WORKOS_DEVICE_CODE_URL
|
|
||||||
token_url = self.WORKOS_TOKEN_URL
|
|
||||||
client_id = WORKOS_CLI_CONNECT_APP_ID
|
|
||||||
audience = None
|
|
||||||
|
|
||||||
console.print("Signing in to CrewAI Enterprise...\n", style="bold blue")
|
console.print("Signing in to CrewAI Enterprise...\n", style="bold blue")
|
||||||
|
|
||||||
# TODO: WORKOS - Next line and conditional are temporary until migration to WorkOS is complete.
|
# TODO: WORKOS - Next line and conditional are temporary until migration to WorkOS is complete.
|
||||||
user_provider = self._determine_user_provider()
|
user_provider = self._determine_user_provider()
|
||||||
if user_provider == "auth0":
|
if user_provider == "auth0":
|
||||||
device_code_url = self.AUTH0_DEVICE_CODE_URL
|
settings = Oauth2Settings(
|
||||||
token_url = self.AUTH0_TOKEN_URL
|
provider="auth0",
|
||||||
client_id = AUTH0_CLIENT_ID
|
client_id=AUTH0_CLIENT_ID,
|
||||||
audience = AUTH0_AUDIENCE
|
domain=AUTH0_DOMAIN,
|
||||||
self.user_provider = "auth0"
|
audience=AUTH0_AUDIENCE
|
||||||
|
)
|
||||||
|
self.oauth2_provider = ProviderFactory.from_settings(settings)
|
||||||
# End of temporary code.
|
# End of temporary code.
|
||||||
|
|
||||||
device_code_data = self._get_device_code(client_id, device_code_url, audience)
|
device_code_data = self._get_device_code()
|
||||||
self._display_auth_instructions(device_code_data)
|
self._display_auth_instructions(device_code_data)
|
||||||
|
|
||||||
return self._poll_for_token(device_code_data, client_id, token_url)
|
return self._poll_for_token(device_code_data)
|
||||||
|
|
||||||
def _get_device_code(
|
def _get_device_code(
|
||||||
self, client_id: str, device_code_url: str, audience: str | None = None
|
self
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""Get the device code to authenticate the user."""
|
"""Get the device code to authenticate the user."""
|
||||||
|
|
||||||
device_code_payload = {
|
device_code_payload = {
|
||||||
"client_id": client_id,
|
"client_id": self.oauth2_provider.get_client_id(),
|
||||||
"scope": "openid",
|
"scope": "openid",
|
||||||
"audience": audience,
|
"audience": self.oauth2_provider.get_audience(),
|
||||||
}
|
}
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
url=device_code_url, data=device_code_payload, timeout=20
|
url=self.oauth2_provider.get_authorize_url(), data=device_code_payload, timeout=20
|
||||||
)
|
)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json()
|
return response.json()
|
||||||
@@ -82,21 +98,21 @@ class AuthenticationCommand:
|
|||||||
webbrowser.open(device_code_data["verification_uri_complete"])
|
webbrowser.open(device_code_data["verification_uri_complete"])
|
||||||
|
|
||||||
def _poll_for_token(
|
def _poll_for_token(
|
||||||
self, device_code_data: Dict[str, Any], client_id: str, token_poll_url: str
|
self, device_code_data: Dict[str, Any]
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Polls the server for the token until it is received, or max attempts are reached."""
|
"""Polls the server for the token until it is received, or max attempts are reached."""
|
||||||
|
|
||||||
token_payload = {
|
token_payload = {
|
||||||
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
|
"grant_type": "urn:ietf:params:oauth:grant-type:device_code",
|
||||||
"device_code": device_code_data["device_code"],
|
"device_code": device_code_data["device_code"],
|
||||||
"client_id": client_id,
|
"client_id": self.oauth2_provider.get_client_id(),
|
||||||
}
|
}
|
||||||
|
|
||||||
console.print("\nWaiting for authentication... ", style="bold blue", end="")
|
console.print("\nWaiting for authentication... ", style="bold blue", end="")
|
||||||
|
|
||||||
attempts = 0
|
attempts = 0
|
||||||
while True and attempts < 10:
|
while True and attempts < 10:
|
||||||
response = requests.post(token_poll_url, data=token_payload, timeout=30)
|
response = requests.post(self.oauth2_provider.get_token_url(), data=token_payload, timeout=30)
|
||||||
token_data = response.json()
|
token_data = response.json()
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
@@ -128,19 +144,14 @@ class AuthenticationCommand:
|
|||||||
"""Validates the JWT token and saves the token to the token manager."""
|
"""Validates the JWT token and saves the token to the token manager."""
|
||||||
|
|
||||||
jwt_token = token_data["access_token"]
|
jwt_token = token_data["access_token"]
|
||||||
|
issuer = self.oauth2_provider.get_issuer()
|
||||||
jwt_token_data = {
|
jwt_token_data = {
|
||||||
"jwt_token": jwt_token,
|
"jwt_token": jwt_token,
|
||||||
"jwks_url": f"https://{WORKOS_DOMAIN}/oauth2/jwks",
|
"jwks_url": self.oauth2_provider.get_jwks_url(),
|
||||||
"issuer": f"https://{WORKOS_DOMAIN}",
|
"issuer": issuer,
|
||||||
"audience": WORKOS_ENVIRONMENT_ID,
|
"audience": self.oauth2_provider.get_audience(),
|
||||||
}
|
}
|
||||||
|
|
||||||
# TODO: WORKOS - The following conditional is temporary until migration to WorkOS is complete.
|
|
||||||
if self.user_provider == "auth0":
|
|
||||||
jwt_token_data["jwks_url"] = f"https://{AUTH0_DOMAIN}/.well-known/jwks.json"
|
|
||||||
jwt_token_data["issuer"] = f"https://{AUTH0_DOMAIN}/"
|
|
||||||
jwt_token_data["audience"] = AUTH0_AUDIENCE
|
|
||||||
|
|
||||||
decoded_token = validate_jwt_token(**jwt_token_data)
|
decoded_token = validate_jwt_token(**jwt_token_data)
|
||||||
|
|
||||||
expires_at = decoded_token.get("exp", 0)
|
expires_at = decoded_token.get("exp", 0)
|
||||||
|
|||||||
26
src/crewai/cli/authentication/providers/auth0.py
Normal file
26
src/crewai/cli/authentication/providers/auth0.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
from crewai.cli.authentication.providers.base_provider import BaseProvider
|
||||||
|
|
||||||
|
class Auth0Provider(BaseProvider):
|
||||||
|
def get_authorize_url(self) -> str:
|
||||||
|
return f"https://{self._get_domain()}/oauth/device/code"
|
||||||
|
|
||||||
|
def get_token_url(self) -> str:
|
||||||
|
return f"https://{self._get_domain()}/oauth/token"
|
||||||
|
|
||||||
|
def get_jwks_url(self) -> str:
|
||||||
|
return f"https://{self._get_domain()}/.well-known/jwks.json"
|
||||||
|
|
||||||
|
def get_issuer(self) -> str:
|
||||||
|
return f"https://{self._get_domain()}/"
|
||||||
|
|
||||||
|
def get_audience(self) -> str:
|
||||||
|
assert self.settings.audience is not None, "Audience is required"
|
||||||
|
return self.settings.audience
|
||||||
|
|
||||||
|
def get_client_id(self) -> str:
|
||||||
|
assert self.settings.client_id is not None, "Client ID is required"
|
||||||
|
return self.settings.client_id
|
||||||
|
|
||||||
|
def _get_domain(self) -> str:
|
||||||
|
assert self.settings.domain is not None, "Domain is required"
|
||||||
|
return self.settings.domain
|
||||||
30
src/crewai/cli/authentication/providers/base_provider.py
Normal file
30
src/crewai/cli/authentication/providers/base_provider.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from crewai.cli.authentication.main import Oauth2Settings
|
||||||
|
|
||||||
|
class BaseProvider(ABC):
|
||||||
|
def __init__(self, settings: Oauth2Settings):
|
||||||
|
self.settings = settings
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_authorize_url(self) -> str:
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_token_url(self) -> str:
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_jwks_url(self) -> str:
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_issuer(self) -> str:
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_audience(self) -> str:
|
||||||
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_client_id(self) -> str:
|
||||||
|
...
|
||||||
22
src/crewai/cli/authentication/providers/okta.py
Normal file
22
src/crewai/cli/authentication/providers/okta.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from crewai.cli.authentication.providers.base_provider import BaseProvider
|
||||||
|
|
||||||
|
class OktaProvider(BaseProvider):
|
||||||
|
def get_authorize_url(self) -> str:
|
||||||
|
return f"https://{self.settings.domain}/oauth2/default/v1/device/authorize"
|
||||||
|
|
||||||
|
def get_token_url(self) -> str:
|
||||||
|
return f"https://{self.settings.domain}/oauth2/default/v1/token"
|
||||||
|
|
||||||
|
def get_jwks_url(self) -> str:
|
||||||
|
return f"https://{self.settings.domain}/oauth2/default/v1/keys"
|
||||||
|
|
||||||
|
def get_issuer(self) -> str:
|
||||||
|
return f"https://{self.settings.domain}/oauth2/default"
|
||||||
|
|
||||||
|
def get_audience(self) -> str:
|
||||||
|
assert self.settings.audience is not None
|
||||||
|
return self.settings.audience
|
||||||
|
|
||||||
|
def get_client_id(self) -> str:
|
||||||
|
assert self.settings.client_id is not None
|
||||||
|
return self.settings.client_id
|
||||||
25
src/crewai/cli/authentication/providers/workos.py
Normal file
25
src/crewai/cli/authentication/providers/workos.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
from crewai.cli.authentication.providers.base_provider import BaseProvider
|
||||||
|
|
||||||
|
class WorkosProvider(BaseProvider):
|
||||||
|
def get_authorize_url(self) -> str:
|
||||||
|
return f"https://{self._get_domain()}/oauth2/device_authorization"
|
||||||
|
|
||||||
|
def get_token_url(self) -> str:
|
||||||
|
return f"https://{self._get_domain()}/oauth2/token"
|
||||||
|
|
||||||
|
def get_jwks_url(self) -> str:
|
||||||
|
return f"https://{self._get_domain()}/oauth2/jwks"
|
||||||
|
|
||||||
|
def get_issuer(self) -> str:
|
||||||
|
return f"https://{self._get_domain()}"
|
||||||
|
|
||||||
|
def get_audience(self) -> str:
|
||||||
|
return self.settings.audience or ""
|
||||||
|
|
||||||
|
def get_client_id(self) -> str:
|
||||||
|
assert self.settings.client_id is not None, "Client ID is required"
|
||||||
|
return self.settings.client_id
|
||||||
|
|
||||||
|
def _get_domain(self) -> str:
|
||||||
|
assert self.settings.domain is not None, "Domain is required"
|
||||||
|
return self.settings.domain
|
||||||
@@ -4,7 +4,13 @@ from typing import Optional
|
|||||||
|
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from crewai.cli.constants import DEFAULT_CREWAI_ENTERPRISE_URL
|
from crewai.cli.constants import (
|
||||||
|
DEFAULT_CREWAI_ENTERPRISE_URL,
|
||||||
|
CREWAI_ENTERPRISE_DEFAULT_OAUTH2_PROVIDER,
|
||||||
|
CREWAI_ENTERPRISE_DEFAULT_OAUTH2_AUDIENCE,
|
||||||
|
CREWAI_ENTERPRISE_DEFAULT_OAUTH2_CLIENT_ID,
|
||||||
|
CREWAI_ENTERPRISE_DEFAULT_OAUTH2_DOMAIN,
|
||||||
|
)
|
||||||
|
|
||||||
DEFAULT_CONFIG_PATH = Path.home() / ".config" / "crewai" / "settings.json"
|
DEFAULT_CONFIG_PATH = Path.home() / ".config" / "crewai" / "settings.json"
|
||||||
|
|
||||||
@@ -19,11 +25,19 @@ USER_SETTINGS_KEYS = [
|
|||||||
# Settings that are related to the CLI
|
# Settings that are related to the CLI
|
||||||
CLI_SETTINGS_KEYS = [
|
CLI_SETTINGS_KEYS = [
|
||||||
"enterprise_base_url",
|
"enterprise_base_url",
|
||||||
|
"oauth2_provider",
|
||||||
|
"oauth2_audience",
|
||||||
|
"oauth2_client_id",
|
||||||
|
"oauth2_domain",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Default values for CLI settings
|
# Default values for CLI settings
|
||||||
DEFAULT_CLI_SETTINGS = {
|
DEFAULT_CLI_SETTINGS = {
|
||||||
"enterprise_base_url": DEFAULT_CREWAI_ENTERPRISE_URL,
|
"enterprise_base_url": DEFAULT_CREWAI_ENTERPRISE_URL,
|
||||||
|
"oauth2_provider": CREWAI_ENTERPRISE_DEFAULT_OAUTH2_PROVIDER,
|
||||||
|
"oauth2_audience": CREWAI_ENTERPRISE_DEFAULT_OAUTH2_AUDIENCE,
|
||||||
|
"oauth2_client_id": CREWAI_ENTERPRISE_DEFAULT_OAUTH2_CLIENT_ID,
|
||||||
|
"oauth2_domain": CREWAI_ENTERPRISE_DEFAULT_OAUTH2_DOMAIN,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Readonly settings - cannot be set by the user
|
# Readonly settings - cannot be set by the user
|
||||||
@@ -39,10 +53,9 @@ HIDDEN_SETTINGS_KEYS = [
|
|||||||
"tool_repository_password",
|
"tool_repository_password",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseModel):
|
class Settings(BaseModel):
|
||||||
enterprise_base_url: Optional[str] = Field(
|
enterprise_base_url: Optional[str] = Field(
|
||||||
default=DEFAULT_CREWAI_ENTERPRISE_URL,
|
default=DEFAULT_CLI_SETTINGS["enterprise_base_url"],
|
||||||
description="Base URL of the CrewAI Enterprise instance",
|
description="Base URL of the CrewAI Enterprise instance",
|
||||||
)
|
)
|
||||||
tool_repository_username: Optional[str] = Field(
|
tool_repository_username: Optional[str] = Field(
|
||||||
@@ -59,6 +72,26 @@ class Settings(BaseModel):
|
|||||||
)
|
)
|
||||||
config_path: Path = Field(default=DEFAULT_CONFIG_PATH, frozen=True, exclude=True)
|
config_path: Path = Field(default=DEFAULT_CONFIG_PATH, frozen=True, exclude=True)
|
||||||
|
|
||||||
|
oauth2_provider: str = Field(
|
||||||
|
description="OAuth2 provider used for authentication (e.g., workos, okta, auth0).",
|
||||||
|
default=DEFAULT_CLI_SETTINGS["oauth2_provider"]
|
||||||
|
)
|
||||||
|
|
||||||
|
oauth2_audience: Optional[str] = Field(
|
||||||
|
description="OAuth2 audience value, typically used to identify the target API or resource.",
|
||||||
|
default=DEFAULT_CLI_SETTINGS["oauth2_audience"]
|
||||||
|
)
|
||||||
|
|
||||||
|
oauth2_client_id: str = Field(
|
||||||
|
default=DEFAULT_CLI_SETTINGS["oauth2_client_id"],
|
||||||
|
description="OAuth2 client ID issued by the provider, used during authentication requests.",
|
||||||
|
)
|
||||||
|
|
||||||
|
oauth2_domain: str = Field(
|
||||||
|
description="OAuth2 provider's domain (e.g., your-org.auth0.com) used for issuing tokens.",
|
||||||
|
default=DEFAULT_CLI_SETTINGS["oauth2_domain"]
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, config_path: Path = DEFAULT_CONFIG_PATH, **data):
|
def __init__(self, config_path: Path = DEFAULT_CONFIG_PATH, **data):
|
||||||
"""Load Settings from config path"""
|
"""Load Settings from config path"""
|
||||||
config_path.parent.mkdir(parents=True, exist_ok=True)
|
config_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
@@ -105,4 +138,4 @@ class Settings(BaseModel):
|
|||||||
def _reset_cli_settings(self) -> None:
|
def _reset_cli_settings(self) -> None:
|
||||||
"""Reset all CLI settings to default values"""
|
"""Reset all CLI settings to default values"""
|
||||||
for key in CLI_SETTINGS_KEYS:
|
for key in CLI_SETTINGS_KEYS:
|
||||||
setattr(self, key, DEFAULT_CLI_SETTINGS[key])
|
setattr(self, key, DEFAULT_CLI_SETTINGS.get(key))
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
DEFAULT_CREWAI_ENTERPRISE_URL = "https://app.crewai.com"
|
DEFAULT_CREWAI_ENTERPRISE_URL = "https://app.crewai.com"
|
||||||
|
CREWAI_ENTERPRISE_DEFAULT_OAUTH2_PROVIDER = "workos"
|
||||||
|
CREWAI_ENTERPRISE_DEFAULT_OAUTH2_AUDIENCE = "client_01JNJQWBJ4SPFN3SWJM5T7BDG8"
|
||||||
|
CREWAI_ENTERPRISE_DEFAULT_OAUTH2_CLIENT_ID = "client_01JYT06R59SP0NXYGD994NFXXX"
|
||||||
|
CREWAI_ENTERPRISE_DEFAULT_OAUTH2_DOMAIN = "login.crewai.com"
|
||||||
|
|
||||||
ENV_VARS = {
|
ENV_VARS = {
|
||||||
"openai": [
|
"openai": [
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
default_factory=TaskOutputStorageHandler
|
default_factory=TaskOutputStorageHandler
|
||||||
)
|
)
|
||||||
|
|
||||||
name: Optional[str] = Field(default=None)
|
name: Optional[str] = Field(default="crew")
|
||||||
cache: bool = Field(default=True)
|
cache: bool = Field(default=True)
|
||||||
tasks: List[Task] = Field(default_factory=list)
|
tasks: List[Task] = Field(default_factory=list)
|
||||||
agents: List[BaseAgent] = Field(default_factory=list)
|
agents: List[BaseAgent] = Field(default_factory=list)
|
||||||
@@ -575,7 +575,7 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
self,
|
self,
|
||||||
CrewTrainStartedEvent(
|
CrewTrainStartedEvent(
|
||||||
crew_name=self.name or "crew",
|
crew_name=self.name,
|
||||||
n_iterations=n_iterations,
|
n_iterations=n_iterations,
|
||||||
filename=filename,
|
filename=filename,
|
||||||
inputs=inputs,
|
inputs=inputs,
|
||||||
@@ -602,7 +602,7 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
self,
|
self,
|
||||||
CrewTrainCompletedEvent(
|
CrewTrainCompletedEvent(
|
||||||
crew_name=self.name or "crew",
|
crew_name=self.name,
|
||||||
n_iterations=n_iterations,
|
n_iterations=n_iterations,
|
||||||
filename=filename,
|
filename=filename,
|
||||||
),
|
),
|
||||||
@@ -610,7 +610,7 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
self,
|
self,
|
||||||
CrewTrainFailedEvent(error=str(e), crew_name=self.name or "crew"),
|
CrewTrainFailedEvent(error=str(e), crew_name=self.name),
|
||||||
)
|
)
|
||||||
self._logger.log("error", f"Training failed: {e}", color="red")
|
self._logger.log("error", f"Training failed: {e}", color="red")
|
||||||
CrewTrainingHandler(TRAINING_DATA_FILE).clear()
|
CrewTrainingHandler(TRAINING_DATA_FILE).clear()
|
||||||
@@ -634,7 +634,7 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
|
|
||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
self,
|
self,
|
||||||
CrewKickoffStartedEvent(crew_name=self.name or "crew", inputs=inputs),
|
CrewKickoffStartedEvent(crew_name=self.name, inputs=inputs),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Starts the crew to work on its assigned tasks.
|
# Starts the crew to work on its assigned tasks.
|
||||||
@@ -683,7 +683,7 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
self,
|
self,
|
||||||
CrewKickoffFailedEvent(error=str(e), crew_name=self.name or "crew"),
|
CrewKickoffFailedEvent(error=str(e), crew_name=self.name),
|
||||||
)
|
)
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
@@ -1077,7 +1077,7 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
self,
|
self,
|
||||||
CrewKickoffCompletedEvent(
|
CrewKickoffCompletedEvent(
|
||||||
crew_name=self.name or "crew", output=final_task_output
|
crew_name=self.name, output=final_task_output
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
return CrewOutput(
|
return CrewOutput(
|
||||||
@@ -1325,7 +1325,7 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
self,
|
self,
|
||||||
CrewTestStartedEvent(
|
CrewTestStartedEvent(
|
||||||
crew_name=self.name or "crew",
|
crew_name=self.name,
|
||||||
n_iterations=n_iterations,
|
n_iterations=n_iterations,
|
||||||
eval_llm=llm_instance,
|
eval_llm=llm_instance,
|
||||||
inputs=inputs,
|
inputs=inputs,
|
||||||
@@ -1344,13 +1344,13 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
self,
|
self,
|
||||||
CrewTestCompletedEvent(
|
CrewTestCompletedEvent(
|
||||||
crew_name=self.name or "crew",
|
crew_name=self.name,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
crewai_event_bus.emit(
|
crewai_event_bus.emit(
|
||||||
self,
|
self,
|
||||||
CrewTestFailedEvent(error=str(e), crew_name=self.name or "crew"),
|
CrewTestFailedEvent(error=str(e), crew_name=self.name),
|
||||||
)
|
)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ class LiteAgent(FlowTrackable, BaseModel):
|
|||||||
default=15, description="Maximum number of iterations for tool usage"
|
default=15, description="Maximum number of iterations for tool usage"
|
||||||
)
|
)
|
||||||
max_execution_time: Optional[int] = Field(
|
max_execution_time: Optional[int] = Field(
|
||||||
default=None, description="Maximum execution time in seconds"
|
default=None, description=". Maximum execution time in seconds"
|
||||||
)
|
)
|
||||||
respect_context_window: bool = Field(
|
respect_context_window: bool = Field(
|
||||||
default=True,
|
default=True,
|
||||||
@@ -622,4 +622,4 @@ class LiteAgent(FlowTrackable, BaseModel):
|
|||||||
|
|
||||||
def _append_message(self, text: str, role: str = "assistant") -> None:
|
def _append_message(self, text: str, role: str = "assistant") -> None:
|
||||||
"""Append a message to the message list with the given role."""
|
"""Append a message to the message list with the given role."""
|
||||||
self._messages.append(format_message_for_llm(text, role=role))
|
self._messages.append(format_message_for_llm(text, role=role))
|
||||||
|
|||||||
@@ -1387,6 +1387,7 @@ class ConsoleFormatter:
|
|||||||
theme="monokai",
|
theme="monokai",
|
||||||
line_numbers=False,
|
line_numbers=False,
|
||||||
background_color="default",
|
background_color="default",
|
||||||
|
word_wrap=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
content.append("\n")
|
content.append("\n")
|
||||||
|
|||||||
0
tests/cli/authentication/providers/__init__.py
Normal file
0
tests/cli/authentication/providers/__init__.py
Normal file
91
tests/cli/authentication/providers/test_auth0.py
Normal file
91
tests/cli/authentication/providers/test_auth0.py
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import pytest
|
||||||
|
from crewai.cli.authentication.main import Oauth2Settings
|
||||||
|
from crewai.cli.authentication.providers.auth0 import Auth0Provider
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TestAuth0Provider:
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def setup_method(self):
|
||||||
|
self.valid_settings = Oauth2Settings(
|
||||||
|
provider="auth0",
|
||||||
|
domain="test-domain.auth0.com",
|
||||||
|
client_id="test-client-id",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
self.provider = Auth0Provider(self.valid_settings)
|
||||||
|
|
||||||
|
def test_initialization_with_valid_settings(self):
|
||||||
|
provider = Auth0Provider(self.valid_settings)
|
||||||
|
assert provider.settings == self.valid_settings
|
||||||
|
assert provider.settings.provider == "auth0"
|
||||||
|
assert provider.settings.domain == "test-domain.auth0.com"
|
||||||
|
assert provider.settings.client_id == "test-client-id"
|
||||||
|
assert provider.settings.audience == "test-audience"
|
||||||
|
|
||||||
|
def test_get_authorize_url(self):
|
||||||
|
expected_url = "https://test-domain.auth0.com/oauth/device/code"
|
||||||
|
assert self.provider.get_authorize_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_authorize_url_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="auth0",
|
||||||
|
domain="my-company.auth0.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = Auth0Provider(settings)
|
||||||
|
expected_url = "https://my-company.auth0.com/oauth/device/code"
|
||||||
|
assert provider.get_authorize_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_token_url(self):
|
||||||
|
expected_url = "https://test-domain.auth0.com/oauth/token"
|
||||||
|
assert self.provider.get_token_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_token_url_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="auth0",
|
||||||
|
domain="another-domain.auth0.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = Auth0Provider(settings)
|
||||||
|
expected_url = "https://another-domain.auth0.com/oauth/token"
|
||||||
|
assert provider.get_token_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_jwks_url(self):
|
||||||
|
expected_url = "https://test-domain.auth0.com/.well-known/jwks.json"
|
||||||
|
assert self.provider.get_jwks_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_jwks_url_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="auth0",
|
||||||
|
domain="dev.auth0.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = Auth0Provider(settings)
|
||||||
|
expected_url = "https://dev.auth0.com/.well-known/jwks.json"
|
||||||
|
assert provider.get_jwks_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_issuer(self):
|
||||||
|
expected_issuer = "https://test-domain.auth0.com/"
|
||||||
|
assert self.provider.get_issuer() == expected_issuer
|
||||||
|
|
||||||
|
def test_get_issuer_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="auth0",
|
||||||
|
domain="prod.auth0.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = Auth0Provider(settings)
|
||||||
|
expected_issuer = "https://prod.auth0.com/"
|
||||||
|
assert provider.get_issuer() == expected_issuer
|
||||||
|
|
||||||
|
def test_get_audience(self):
|
||||||
|
assert self.provider.get_audience() == "test-audience"
|
||||||
|
|
||||||
|
def test_get_client_id(self):
|
||||||
|
assert self.provider.get_client_id() == "test-client-id"
|
||||||
102
tests/cli/authentication/providers/test_okta.py
Normal file
102
tests/cli/authentication/providers/test_okta.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import pytest
|
||||||
|
from crewai.cli.authentication.main import Oauth2Settings
|
||||||
|
from crewai.cli.authentication.providers.okta import OktaProvider
|
||||||
|
|
||||||
|
|
||||||
|
class TestOktaProvider:
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def setup_method(self):
|
||||||
|
self.valid_settings = Oauth2Settings(
|
||||||
|
provider="okta",
|
||||||
|
domain="test-domain.okta.com",
|
||||||
|
client_id="test-client-id",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
self.provider = OktaProvider(self.valid_settings)
|
||||||
|
|
||||||
|
def test_initialization_with_valid_settings(self):
|
||||||
|
provider = OktaProvider(self.valid_settings)
|
||||||
|
assert provider.settings == self.valid_settings
|
||||||
|
assert provider.settings.provider == "okta"
|
||||||
|
assert provider.settings.domain == "test-domain.okta.com"
|
||||||
|
assert provider.settings.client_id == "test-client-id"
|
||||||
|
assert provider.settings.audience == "test-audience"
|
||||||
|
|
||||||
|
def test_get_authorize_url(self):
|
||||||
|
expected_url = "https://test-domain.okta.com/oauth2/default/v1/device/authorize"
|
||||||
|
assert self.provider.get_authorize_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_authorize_url_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="okta",
|
||||||
|
domain="my-company.okta.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = OktaProvider(settings)
|
||||||
|
expected_url = "https://my-company.okta.com/oauth2/default/v1/device/authorize"
|
||||||
|
assert provider.get_authorize_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_token_url(self):
|
||||||
|
expected_url = "https://test-domain.okta.com/oauth2/default/v1/token"
|
||||||
|
assert self.provider.get_token_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_token_url_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="okta",
|
||||||
|
domain="another-domain.okta.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = OktaProvider(settings)
|
||||||
|
expected_url = "https://another-domain.okta.com/oauth2/default/v1/token"
|
||||||
|
assert provider.get_token_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_jwks_url(self):
|
||||||
|
expected_url = "https://test-domain.okta.com/oauth2/default/v1/keys"
|
||||||
|
assert self.provider.get_jwks_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_jwks_url_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="okta",
|
||||||
|
domain="dev.okta.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = OktaProvider(settings)
|
||||||
|
expected_url = "https://dev.okta.com/oauth2/default/v1/keys"
|
||||||
|
assert provider.get_jwks_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_issuer(self):
|
||||||
|
expected_issuer = "https://test-domain.okta.com/oauth2/default"
|
||||||
|
assert self.provider.get_issuer() == expected_issuer
|
||||||
|
|
||||||
|
def test_get_issuer_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="okta",
|
||||||
|
domain="prod.okta.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = OktaProvider(settings)
|
||||||
|
expected_issuer = "https://prod.okta.com/oauth2/default"
|
||||||
|
assert provider.get_issuer() == expected_issuer
|
||||||
|
|
||||||
|
def test_get_audience(self):
|
||||||
|
assert self.provider.get_audience() == "test-audience"
|
||||||
|
|
||||||
|
def test_get_audience_assertion_error_when_none(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="okta",
|
||||||
|
domain="test-domain.okta.com",
|
||||||
|
client_id="test-client-id",
|
||||||
|
audience=None
|
||||||
|
)
|
||||||
|
provider = OktaProvider(settings)
|
||||||
|
|
||||||
|
with pytest.raises(AssertionError):
|
||||||
|
provider.get_audience()
|
||||||
|
|
||||||
|
def test_get_client_id(self):
|
||||||
|
assert self.provider.get_client_id() == "test-client-id"
|
||||||
100
tests/cli/authentication/providers/test_workos.py
Normal file
100
tests/cli/authentication/providers/test_workos.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import pytest
|
||||||
|
from crewai.cli.authentication.main import Oauth2Settings
|
||||||
|
from crewai.cli.authentication.providers.workos import WorkosProvider
|
||||||
|
|
||||||
|
|
||||||
|
class TestWorkosProvider:
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def setup_method(self):
|
||||||
|
self.valid_settings = Oauth2Settings(
|
||||||
|
provider="workos",
|
||||||
|
domain="login.company.com",
|
||||||
|
client_id="test-client-id",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
self.provider = WorkosProvider(self.valid_settings)
|
||||||
|
|
||||||
|
def test_initialization_with_valid_settings(self):
|
||||||
|
provider = WorkosProvider(self.valid_settings)
|
||||||
|
assert provider.settings == self.valid_settings
|
||||||
|
assert provider.settings.provider == "workos"
|
||||||
|
assert provider.settings.domain == "login.company.com"
|
||||||
|
assert provider.settings.client_id == "test-client-id"
|
||||||
|
assert provider.settings.audience == "test-audience"
|
||||||
|
|
||||||
|
def test_get_authorize_url(self):
|
||||||
|
expected_url = "https://login.company.com/oauth2/device_authorization"
|
||||||
|
assert self.provider.get_authorize_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_authorize_url_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="workos",
|
||||||
|
domain="login.example.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = WorkosProvider(settings)
|
||||||
|
expected_url = "https://login.example.com/oauth2/device_authorization"
|
||||||
|
assert provider.get_authorize_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_token_url(self):
|
||||||
|
expected_url = "https://login.company.com/oauth2/token"
|
||||||
|
assert self.provider.get_token_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_token_url_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="workos",
|
||||||
|
domain="api.workos.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = WorkosProvider(settings)
|
||||||
|
expected_url = "https://api.workos.com/oauth2/token"
|
||||||
|
assert provider.get_token_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_jwks_url(self):
|
||||||
|
expected_url = "https://login.company.com/oauth2/jwks"
|
||||||
|
assert self.provider.get_jwks_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_jwks_url_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="workos",
|
||||||
|
domain="auth.enterprise.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = WorkosProvider(settings)
|
||||||
|
expected_url = "https://auth.enterprise.com/oauth2/jwks"
|
||||||
|
assert provider.get_jwks_url() == expected_url
|
||||||
|
|
||||||
|
def test_get_issuer(self):
|
||||||
|
expected_issuer = "https://login.company.com"
|
||||||
|
assert self.provider.get_issuer() == expected_issuer
|
||||||
|
|
||||||
|
def test_get_issuer_with_different_domain(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="workos",
|
||||||
|
domain="sso.company.com",
|
||||||
|
client_id="test-client",
|
||||||
|
audience="test-audience"
|
||||||
|
)
|
||||||
|
provider = WorkosProvider(settings)
|
||||||
|
expected_issuer = "https://sso.company.com"
|
||||||
|
assert provider.get_issuer() == expected_issuer
|
||||||
|
|
||||||
|
def test_get_audience(self):
|
||||||
|
assert self.provider.get_audience() == "test-audience"
|
||||||
|
|
||||||
|
def test_get_audience_fallback_to_default(self):
|
||||||
|
settings = Oauth2Settings(
|
||||||
|
provider="workos",
|
||||||
|
domain="login.company.com",
|
||||||
|
client_id="test-client-id",
|
||||||
|
audience=None
|
||||||
|
)
|
||||||
|
provider = WorkosProvider(settings)
|
||||||
|
assert provider.get_audience() == ""
|
||||||
|
|
||||||
|
def test_get_client_id(self):
|
||||||
|
assert self.provider.get_client_id() == "test-client-id"
|
||||||
@@ -6,10 +6,12 @@ from crewai.cli.authentication.main import AuthenticationCommand
|
|||||||
from crewai.cli.authentication.constants import (
|
from crewai.cli.authentication.constants import (
|
||||||
AUTH0_AUDIENCE,
|
AUTH0_AUDIENCE,
|
||||||
AUTH0_CLIENT_ID,
|
AUTH0_CLIENT_ID,
|
||||||
AUTH0_DOMAIN,
|
AUTH0_DOMAIN
|
||||||
WORKOS_DOMAIN,
|
)
|
||||||
WORKOS_CLI_CONNECT_APP_ID,
|
from crewai.cli.constants import (
|
||||||
WORKOS_ENVIRONMENT_ID,
|
CREWAI_ENTERPRISE_DEFAULT_OAUTH2_DOMAIN,
|
||||||
|
CREWAI_ENTERPRISE_DEFAULT_OAUTH2_CLIENT_ID,
|
||||||
|
CREWAI_ENTERPRISE_DEFAULT_OAUTH2_AUDIENCE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -27,14 +29,17 @@ class TestAuthenticationCommand:
|
|||||||
"token_url": f"https://{AUTH0_DOMAIN}/oauth/token",
|
"token_url": f"https://{AUTH0_DOMAIN}/oauth/token",
|
||||||
"client_id": AUTH0_CLIENT_ID,
|
"client_id": AUTH0_CLIENT_ID,
|
||||||
"audience": AUTH0_AUDIENCE,
|
"audience": AUTH0_AUDIENCE,
|
||||||
|
"domain": AUTH0_DOMAIN,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"workos",
|
"workos",
|
||||||
{
|
{
|
||||||
"device_code_url": f"https://{WORKOS_DOMAIN}/oauth2/device_authorization",
|
"device_code_url": f"https://{CREWAI_ENTERPRISE_DEFAULT_OAUTH2_DOMAIN}/oauth2/device_authorization",
|
||||||
"token_url": f"https://{WORKOS_DOMAIN}/oauth2/token",
|
"token_url": f"https://{CREWAI_ENTERPRISE_DEFAULT_OAUTH2_DOMAIN}/oauth2/token",
|
||||||
"client_id": WORKOS_CLI_CONNECT_APP_ID,
|
"client_id": CREWAI_ENTERPRISE_DEFAULT_OAUTH2_CLIENT_ID,
|
||||||
|
"audience": CREWAI_ENTERPRISE_DEFAULT_OAUTH2_AUDIENCE,
|
||||||
|
"domain": CREWAI_ENTERPRISE_DEFAULT_OAUTH2_DOMAIN,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -70,19 +75,16 @@ class TestAuthenticationCommand:
|
|||||||
"Signing in to CrewAI Enterprise...\n", style="bold blue"
|
"Signing in to CrewAI Enterprise...\n", style="bold blue"
|
||||||
)
|
)
|
||||||
mock_determine_provider.assert_called_once()
|
mock_determine_provider.assert_called_once()
|
||||||
mock_get_device.assert_called_once_with(
|
mock_get_device.assert_called_once()
|
||||||
expected_urls["client_id"],
|
|
||||||
expected_urls["device_code_url"],
|
|
||||||
expected_urls.get("audience", None),
|
|
||||||
)
|
|
||||||
mock_display.assert_called_once_with(
|
mock_display.assert_called_once_with(
|
||||||
{"device_code": "test_code", "user_code": "123456"}
|
{"device_code": "test_code", "user_code": "123456"}
|
||||||
)
|
)
|
||||||
mock_poll.assert_called_once_with(
|
mock_poll.assert_called_once_with(
|
||||||
{"device_code": "test_code", "user_code": "123456"},
|
{"device_code": "test_code", "user_code": "123456"},
|
||||||
expected_urls["client_id"],
|
|
||||||
expected_urls["token_url"],
|
|
||||||
)
|
)
|
||||||
|
assert self.auth_command.oauth2_provider.get_client_id() == expected_urls["client_id"]
|
||||||
|
assert self.auth_command.oauth2_provider.get_audience() == expected_urls["audience"]
|
||||||
|
assert self.auth_command.oauth2_provider._get_domain() == expected_urls["domain"]
|
||||||
|
|
||||||
@patch("crewai.cli.authentication.main.webbrowser")
|
@patch("crewai.cli.authentication.main.webbrowser")
|
||||||
@patch("crewai.cli.authentication.main.console.print")
|
@patch("crewai.cli.authentication.main.console.print")
|
||||||
@@ -115,9 +117,9 @@ class TestAuthenticationCommand:
|
|||||||
(
|
(
|
||||||
"workos",
|
"workos",
|
||||||
{
|
{
|
||||||
"jwks_url": f"https://{WORKOS_DOMAIN}/oauth2/jwks",
|
"jwks_url": f"https://{CREWAI_ENTERPRISE_DEFAULT_OAUTH2_DOMAIN}/oauth2/jwks",
|
||||||
"issuer": f"https://{WORKOS_DOMAIN}",
|
"issuer": f"https://{CREWAI_ENTERPRISE_DEFAULT_OAUTH2_DOMAIN}",
|
||||||
"audience": WORKOS_ENVIRONMENT_ID,
|
"audience": CREWAI_ENTERPRISE_DEFAULT_OAUTH2_AUDIENCE,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -133,7 +135,15 @@ class TestAuthenticationCommand:
|
|||||||
jwt_config,
|
jwt_config,
|
||||||
has_expiration,
|
has_expiration,
|
||||||
):
|
):
|
||||||
self.auth_command.user_provider = user_provider
|
from crewai.cli.authentication.providers.auth0 import Auth0Provider
|
||||||
|
from crewai.cli.authentication.providers.workos import WorkosProvider
|
||||||
|
from crewai.cli.authentication.main import Oauth2Settings
|
||||||
|
|
||||||
|
if user_provider == "auth0":
|
||||||
|
self.auth_command.oauth2_provider = Auth0Provider(settings=Oauth2Settings(provider=user_provider, client_id="test-client-id", domain=AUTH0_DOMAIN, audience=jwt_config["audience"]))
|
||||||
|
elif user_provider == "workos":
|
||||||
|
self.auth_command.oauth2_provider = WorkosProvider(settings=Oauth2Settings(provider=user_provider, client_id="test-client-id", domain=CREWAI_ENTERPRISE_DEFAULT_OAUTH2_DOMAIN, audience=jwt_config["audience"]))
|
||||||
|
|
||||||
token_data = {"access_token": "test_access_token", "id_token": "test_id_token"}
|
token_data = {"access_token": "test_access_token", "id_token": "test_id_token"}
|
||||||
|
|
||||||
if has_expiration:
|
if has_expiration:
|
||||||
@@ -311,11 +321,12 @@ class TestAuthenticationCommand:
|
|||||||
}
|
}
|
||||||
mock_post.return_value = mock_response
|
mock_post.return_value = mock_response
|
||||||
|
|
||||||
result = self.auth_command._get_device_code(
|
self.auth_command.oauth2_provider = MagicMock()
|
||||||
client_id="test_client",
|
self.auth_command.oauth2_provider.get_client_id.return_value = "test_client"
|
||||||
device_code_url="https://example.com/device",
|
self.auth_command.oauth2_provider.get_authorize_url.return_value = "https://example.com/device"
|
||||||
audience="test_audience",
|
self.auth_command.oauth2_provider.get_audience.return_value = "test_audience"
|
||||||
)
|
|
||||||
|
result = self.auth_command._get_device_code()
|
||||||
|
|
||||||
mock_post.assert_called_once_with(
|
mock_post.assert_called_once_with(
|
||||||
url="https://example.com/device",
|
url="https://example.com/device",
|
||||||
@@ -354,8 +365,12 @@ class TestAuthenticationCommand:
|
|||||||
self.auth_command, "_login_to_tool_repository"
|
self.auth_command, "_login_to_tool_repository"
|
||||||
) as mock_tool_login,
|
) as mock_tool_login,
|
||||||
):
|
):
|
||||||
|
self.auth_command.oauth2_provider = MagicMock()
|
||||||
|
self.auth_command.oauth2_provider.get_token_url.return_value = "https://example.com/token"
|
||||||
|
self.auth_command.oauth2_provider.get_client_id.return_value = "test_client"
|
||||||
|
|
||||||
self.auth_command._poll_for_token(
|
self.auth_command._poll_for_token(
|
||||||
device_code_data, "test_client", "https://example.com/token"
|
device_code_data
|
||||||
)
|
)
|
||||||
|
|
||||||
mock_post.assert_called_once_with(
|
mock_post.assert_called_once_with(
|
||||||
@@ -392,7 +407,7 @@ class TestAuthenticationCommand:
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.auth_command._poll_for_token(
|
self.auth_command._poll_for_token(
|
||||||
device_code_data, "test_client", "https://example.com/token"
|
device_code_data
|
||||||
)
|
)
|
||||||
|
|
||||||
mock_console_print.assert_any_call(
|
mock_console_print.assert_any_call(
|
||||||
@@ -415,5 +430,14 @@ class TestAuthenticationCommand:
|
|||||||
|
|
||||||
with pytest.raises(requests.HTTPError):
|
with pytest.raises(requests.HTTPError):
|
||||||
self.auth_command._poll_for_token(
|
self.auth_command._poll_for_token(
|
||||||
device_code_data, "test_client", "https://example.com/token"
|
device_code_data
|
||||||
)
|
)
|
||||||
|
# @patch(
|
||||||
|
# "crewai.cli.authentication.main.AuthenticationCommand._determine_user_provider"
|
||||||
|
# )
|
||||||
|
# def test_login_with_auth0(self, mock_determine_provider):
|
||||||
|
# from crewai.cli.authentication.providers.auth0 import Auth0Provider
|
||||||
|
# from crewai.cli.authentication.main import Oauth2Settings
|
||||||
|
|
||||||
|
# self.auth_command.oauth2_provider = Auth0Provider(settings=Oauth2Settings(provider="auth0", client_id=AUTH0_CLIENT_ID, domain=AUTH0_DOMAIN, audience=AUTH0_AUDIENCE))
|
||||||
|
# self.auth_command.login()
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class TestSettings(unittest.TestCase):
|
|||||||
for key in user_settings.keys():
|
for key in user_settings.keys():
|
||||||
self.assertEqual(getattr(settings, key), None)
|
self.assertEqual(getattr(settings, key), None)
|
||||||
for key in cli_settings.keys():
|
for key in cli_settings.keys():
|
||||||
self.assertEqual(getattr(settings, key), DEFAULT_CLI_SETTINGS[key])
|
self.assertEqual(getattr(settings, key), DEFAULT_CLI_SETTINGS.get(key))
|
||||||
|
|
||||||
def test_dump_new_settings(self):
|
def test_dump_new_settings(self):
|
||||||
settings = Settings(
|
settings = Settings(
|
||||||
|
|||||||
@@ -81,11 +81,10 @@ class TestSettingsCommand(unittest.TestCase):
|
|||||||
|
|
||||||
self.settings_command.reset_all_settings()
|
self.settings_command.reset_all_settings()
|
||||||
|
|
||||||
print(USER_SETTINGS_KEYS)
|
|
||||||
for key in USER_SETTINGS_KEYS:
|
for key in USER_SETTINGS_KEYS:
|
||||||
self.assertEqual(getattr(self.settings_command.settings, key), None)
|
self.assertEqual(getattr(self.settings_command.settings, key), None)
|
||||||
|
|
||||||
for key in CLI_SETTINGS_KEYS:
|
for key in CLI_SETTINGS_KEYS:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
getattr(self.settings_command.settings, key), DEFAULT_CLI_SETTINGS[key]
|
getattr(self.settings_command.settings, key), DEFAULT_CLI_SETTINGS.get(key)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4756,3 +4756,13 @@ def test_reset_agent_knowledge_with_only_agent_knowledge(researcher, writer):
|
|||||||
mock_reset_agent_knowledge.assert_called_once_with(
|
mock_reset_agent_knowledge.assert_called_once_with(
|
||||||
[mock_ks_research, mock_ks_writer]
|
[mock_ks_research, mock_ks_writer]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_default_crew_name(researcher, writer):
|
||||||
|
crew = Crew(
|
||||||
|
agents=[researcher, writer],
|
||||||
|
tasks=[
|
||||||
|
Task(description="Task 1", expected_output="output", agent=researcher),
|
||||||
|
Task(description="Task 2", expected_output="output", agent=writer),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert crew.name == "crew"
|
||||||
|
|||||||
Reference in New Issue
Block a user