feat(cli): prioritize platform integrations

This commit is contained in:
ViditOstwal
2026-09-18 12:13:03 +05:30
committed by GitHub
parent 6e1fa8cf2a
commit a1670b13b1
7 changed files with 74 additions and 44 deletions

View File

@@ -234,9 +234,9 @@ _FLAT_TOOLS: list[tuple[str, str]] = [
_COMMON_TOOL_ORDER = [
"SerperDevTool",
"ScrapeWebsiteTool",
"DirectoryReadTool",
"FileReadTool",
"FileWriterTool",
"platform:gmail",
"platform:whatsapp",
]
_ANSI_SEQUENCE_RE = re.compile(r"\x1b\[[0-?]*[ -/]*[@-~]")
@@ -898,19 +898,19 @@ def _platform_app_name(app: str) -> str:
def _prompt_platform_token() -> str:
"""Explain how to obtain and securely prompt for an AMP integration token."""
"""Explain how to securely prompt for an AMP Enterprise Action Auth Token."""
click.secho(
" To use CrewAI Platform tools, you need a CrewAI Platform Integration Token.",
" To use CrewAI Platform tools, you need a CrewAI Platform Enterprise Action Auth Token.",
fg="yellow",
)
click.secho(
" Get your token from CrewAI AMP: https://app.crewai.com "
"→ Settings → Integration Tokens.",
"→ Settings → Account → Enterprise Action Auth Token.",
fg="cyan",
)
return str(
click.prompt(
click.style(" CREWAI_PLATFORM_INTEGRATION_TOKEN", fg="cyan"),
click.style(" CREWAI_ENTERPRISE_ACTION_AUTH_TOKEN", fg="cyan"),
hide_input=True,
prompt_suffix=click.style(" > ", fg="bright_white"),
)
@@ -954,7 +954,7 @@ def _report_platform_app_validation(
status_code = getattr(getattr(error, "response", None), "status_code", None)
if status_code in {401, 403}:
click.secho(
" ✘ CrewAI Platform Integration Token is invalid or expired",
" ✘ CrewAI Platform Enterprise Action Auth Token is invalid or expired",
fg="red",
)
return True
@@ -1008,7 +1008,7 @@ def _validate_platform_apps(
app_name = _platform_app_name(app)
click.echo()
click.secho(
" Checking CrewAI Platform Integration Token and "
" Checking CrewAI Platform Enterprise Action Auth Token and "
f"{app_name} integration on AMP...",
fg="cyan",
)
@@ -1027,7 +1027,7 @@ def _show_platform_validation_guidance(
click.echo()
if token_invalid:
click.secho(
" Check your CrewAI Platform Integration Token in AMP.",
" Check your CrewAI Platform Enterprise Action Auth Token in AMP.",
fg="yellow",
)
return
@@ -1037,7 +1037,7 @@ def _show_platform_validation_guidance(
" Check the "
f"{', '.join(failed_app_names)} integration"
f"{'s' if len(failed_app_names) != 1 else ''} and your CrewAI "
"Platform Integration Token in AMP.",
"Platform Enterprise Action Auth Token in AMP.",
fg="yellow",
)
@@ -1082,19 +1082,21 @@ def _setup_platform_auth(agents: list[dict[str, Any]]) -> str | None:
"`pip install 'crewai[tools]'`."
) from error
token = os.environ.get("CREWAI_PLATFORM_INTEGRATION_TOKEN", "")
token = os.environ.get("CREWAI_ENTERPRISE_ACTION_AUTH_TOKEN") or os.environ.get(
"CREWAI_PLATFORM_INTEGRATION_TOKEN", ""
)
while True:
if not token:
token = _prompt_platform_token()
if not token:
click.secho(
" A CrewAI Platform Integration Token is required to validate "
" A CrewAI Platform Enterprise Action Auth Token is required to validate "
"the selected integrations.",
fg="yellow",
)
continue
os.environ["CREWAI_PLATFORM_INTEGRATION_TOKEN"] = token
os.environ["CREWAI_ENTERPRISE_ACTION_AUTH_TOKEN"] = token
failed_apps, token_invalid = _validate_platform_apps(
apps, ApplicationSelector, client_for_selector
)
@@ -1110,7 +1112,7 @@ def _setup_platform_auth(agents: list[dict[str, Any]]) -> str | None:
replacement_token = _prompt_platform_revalidation_token()
if replacement_token:
token = replacement_token
os.environ["CREWAI_PLATFORM_INTEGRATION_TOKEN"] = token
os.environ["CREWAI_ENTERPRISE_ACTION_AUTH_TOKEN"] = token
# ── Main ────────────────────────────────────────────────────────
@@ -1178,11 +1180,11 @@ def create_json_crew(
copy_assistant_instructions(folder_path)
if platform_token:
os.environ["CREWAI_PLATFORM_INTEGRATION_TOKEN"] = platform_token
os.environ["CREWAI_ENTERPRISE_ACTION_AUTH_TOKEN"] = platform_token
env_vars = load_env_vars(folder_path)
env_vars["CREWAI_PLATFORM_INTEGRATION_TOKEN"] = platform_token
env_vars["CREWAI_ENTERPRISE_ACTION_AUTH_TOKEN"] = platform_token
write_env_file(folder_path, env_vars)
_success("CrewAI Platform integration token saved to .env")
_success("CrewAI Platform Enterprise Action Auth Token saved to .env")
for agent in agents:
_write_jsonc(

View File

@@ -6,20 +6,27 @@ from crewai_core.platform_apps import PLATFORM_APPS
PLATFORM_TOOL_PREFIX = "platform:"
_APP_DESCRIPTIONS: dict[str, str] = {
"gmail": "Gmail Integration",
"github": "GitHub Integration",
"google_drive": "Google Drive Integration",
"google_sheets": "Google Sheets Integration",
"slack": "Slack Integration",
"google_calendar": "Google Calendar Integration",
"whatsapp": "WhatsApp Integration",
"youtube": "YouTube Integration",
"instagram": "Instagram Integration",
"outlook": "Outlook Integration",
"google_docs": "Google Docs Integration",
"linkedin": "LinkedIn Integration",
"asana": "Asana Integration",
"box": "Box Integration",
"clickup": "ClickUp Integration",
"github": "GitHub Integration",
"gmail": "Gmail Integration",
"google_calendar": "Google Calendar Integration",
"google_sheets": "Google Sheets Integration",
"hubspot": "HubSpot Integration",
"jira": "Jira Integration",
"linear": "Linear Integration",
"notion": "Notion Integration",
"salesforce": "Salesforce Integration",
"shopify": "Shopify Integration",
"slack": "Slack Integration",
"stripe": "Stripe Integration",
"zendesk": "Zendesk Integration",
}

View File

@@ -470,16 +470,18 @@ def test_json_wizard_tool_picker_prioritizes_common_tools(monkeypatch):
tools = json_crew._select_tools()
assert tools == ["SerperDevTool", "DirectoryReadTool"]
assert tools == ["SerperDevTool", "FileReadTool"]
assert len(picker_calls) == 1
labels = picker_calls[0][1]
assert 0 in picker_calls[0][2]["separator_indices"]
assert labels[0] == "── Common tools ──"
assert labels[1].strip().endswith("SerperDevTool")
assert labels[2].strip().endswith("ScrapeWebsiteTool")
assert labels[3].strip().endswith("DirectoryReadTool")
assert labels[4].strip().endswith("FileReadTool")
assert labels[5].strip().endswith("FileWriterTool")
assert labels[3].strip().endswith("FileReadTool")
assert labels[4].startswith("Gmail Integration")
assert labels[4].endswith("Platform: GmailIntegration")
assert labels[5].startswith("WhatsApp Integration")
assert labels[5].endswith("Platform: WhatsAppIntegration")
assert labels[1].index("Google search") < labels[1].index("SerperDevTool")
assert "More tools" not in labels
@@ -749,7 +751,7 @@ def test_platform_validation_announces_concurrent_apps_together(capsys):
output = capsys.readouterr().out
assert (failed_apps, token_invalid) == ([], False)
assert "Checking GitHub, Gmail, Google Calendar integrations together on AMP" in output
assert "Checking CrewAI Platform Integration Token and GitHub" not in output
assert "Checking CrewAI Platform Enterprise Action Auth Token and GitHub" not in output
def test_platform_validation_falls_back_to_sequential_checks(monkeypatch, capsys):
@@ -779,8 +781,8 @@ def test_platform_validation_falls_back_to_sequential_checks(monkeypatch, capsys
assert (failed_apps, token_invalid) == ([], False)
assert checked_apps == ["github", "gmail"]
output = capsys.readouterr().out
assert "Checking CrewAI Platform Integration Token and GitHub integration" in output
assert "Checking CrewAI Platform Integration Token and Gmail integration" in output
assert "Checking CrewAI Platform Enterprise Action Auth Token and GitHub integration" in output
assert "Checking CrewAI Platform Enterprise Action Auth Token and Gmail integration" in output
def test_multi_picker_skips_separator_on_initial_cursor(monkeypatch):
@@ -1040,7 +1042,7 @@ def test_json_create_saves_platform_token_to_env_file(tmp_path, monkeypatch):
json_crew.create_json_crew("Platform Crew", skip_provider=True)
env_file = tmp_path / "platform_crew" / ".env"
assert "CREWAI_PLATFORM_INTEGRATION_TOKEN=token" in env_file.read_text()
assert "CREWAI_ENTERPRISE_ACTION_AUTH_TOKEN=token" in env_file.read_text()
def test_json_crew_uses_template_files():

View File

@@ -4,20 +4,27 @@ from typing import Final, Literal, get_args
PlatformApp = Literal[
"gmail",
"github",
"google_drive",
"google_sheets",
"slack",
"google_calendar",
"whatsapp",
"youtube",
"instagram",
"outlook",
"google_docs",
"linkedin",
"asana",
"box",
"clickup",
"github",
"gmail",
"google_calendar",
"google_sheets",
"hubspot",
"jira",
"linear",
"notion",
"salesforce",
"shopify",
"slack",
"stripe",
"zendesk",
]

View File

@@ -2,10 +2,15 @@ import os
def get_platform_integration_token() -> str:
"""Get the platform integration token from the environment."""
token = os.getenv("CREWAI_PLATFORM_INTEGRATION_TOKEN") or ""
"""Get the Platform Enterprise Action Auth Token from the environment."""
token = (
os.getenv("CREWAI_ENTERPRISE_ACTION_AUTH_TOKEN")
or os.getenv("CREWAI_PLATFORM_INTEGRATION_TOKEN")
or ""
)
if not token:
raise ValueError(
"No platform integration token found, please set the CREWAI_PLATFORM_INTEGRATION_TOKEN environment variable"
"No Platform Enterprise Action Auth Token found, please set the "
"CREWAI_ENTERPRISE_ACTION_AUTH_TOKEN environment variable"
)
return token # TODO: Use context manager to get token

View File

@@ -3,20 +3,27 @@ from crewai_core.platform_apps import PLATFORM_APPS
def test_platform_apps_contains_supported_application_catalog() -> None:
assert PLATFORM_APPS == (
"gmail",
"github",
"google_drive",
"google_sheets",
"slack",
"google_calendar",
"whatsapp",
"youtube",
"instagram",
"outlook",
"google_docs",
"linkedin",
"asana",
"box",
"clickup",
"github",
"gmail",
"google_calendar",
"google_sheets",
"hubspot",
"jira",
"linear",
"notion",
"salesforce",
"shopify",
"slack",
"stripe",
"zendesk",
)

View File

@@ -367,7 +367,7 @@ def test_clipper_client_requires_platform_integration_token(
parameters={},
)
with pytest.raises(ValueError, match="CREWAI_PLATFORM_INTEGRATION_TOKEN"):
with pytest.raises(ValueError, match="CREWAI_ENTERPRISE_ACTION_AUTH_TOKEN"):
ClipperClient().execute_action(tool, {})
mock_post.assert_not_called()