diff --git a/lib/crewai/src/crewai/cli/tools/main.py b/lib/crewai/src/crewai/cli/tools/main.py index ad8690ea6..881fae92a 100644 --- a/lib/crewai/src/crewai/cli/tools/main.py +++ b/lib/crewai/src/crewai/cli/tools/main.py @@ -108,15 +108,12 @@ class ToolCommand(BaseCommand, PlusAPIMixin): tools_metadata = extract_tools_metadata() except Exception as e: console.print( - f"[bold red]Failed to extract tool metadata.[/bold red]\n" - f"Error: {e}\n\n" - f"Please ensure your tools:\n" - f"* Inherit from BaseTool\n" - f"* Are properly exported in __init__.py with __all__\n" - f"* Have valid Pydantic field definitions" + f"[yellow]Warning: Could not extract tool metadata: {e}[/yellow]\n" + f"Publishing will continue without detailed metadata." ) - raise SystemExit(1) + tools_metadata = [] + self._print_tools_preview(tools_metadata) self._print_current_organization() with tempfile.TemporaryDirectory() as temp_build_dir: @@ -263,6 +260,39 @@ class ToolCommand(BaseCommand, PlusAPIMixin): ) raise SystemExit + def _print_tools_preview(self, tools_metadata: list[dict[str, Any]]) -> None: + if not tools_metadata: + console.print("[yellow]No tool metadata extracted.[/yellow]") + return + + console.print(f"\n[bold]Tools to be published ({len(tools_metadata)}):[/bold]\n") + + for tool in tools_metadata: + console.print(f" [bold cyan]{tool.get('name', 'Unknown')}[/bold cyan]") + console.print(f" Name: {tool.get('humanized_name', 'N/A')}") + console.print(f" Description: {tool.get('description', 'N/A')[:80]}{'...' if len(tool.get('description', '')) > 80 else ''}") + + init_params = tool.get("init_params_schema", {}).get("properties", {}) + if init_params: + required = tool.get("init_params_schema", {}).get("required", []) + console.print(" Init parameters:") + for param_name, param_info in init_params.items(): + param_type = param_info.get("type", "any") + is_required = param_name in required + req_marker = "[red]*[/red]" if is_required else "" + default = f" = {param_info['default']}" if "default" in param_info else "" + console.print(f" - {param_name}: {param_type}{default} {req_marker}") + + env_vars = tool.get("env_vars", []) + if env_vars: + console.print(" Environment variables:") + for env_var in env_vars: + req_marker = "[red]*[/red]" if env_var.get("required") else "" + default = f" (default: {env_var['default']})" if env_var.get("default") else "" + console.print(f" - {env_var['name']}: {env_var.get('description', 'N/A')}{default} {req_marker}") + + console.print() + def _print_current_organization(self) -> None: settings = Settings() if settings.org_uuid: diff --git a/lib/crewai/tests/cli/tools/test_main.py b/lib/crewai/tests/cli/tools/test_main.py index 15ffeddbd..3ffab377a 100644 --- a/lib/crewai/tests/cli/tools/test_main.py +++ b/lib/crewai/tests/cli/tools/test_main.py @@ -396,7 +396,7 @@ def test_publish_api_error( "crewai.cli.tools.main.extract_tools_metadata", side_effect=Exception("Failed to extract metadata"), ) -def test_publish_metadata_extraction_failure( +def test_publish_metadata_extraction_failure_continues_with_warning( mock_tools_metadata, mock_available_exports, mock_is_synced, @@ -406,11 +406,15 @@ def test_publish_metadata_extraction_failure( capsys, tool_command, ): - with raises(SystemExit): + """Test that metadata extraction failure shows warning but continues publishing.""" + try: tool_command.publish(is_public=True) + except SystemExit: + pass # May fail later due to API mock, but should get past metadata extraction output = capsys.readouterr().out - assert "Failed to extract tool metadata" in output - assert "Inherit from BaseTool" in output + assert "Warning: Could not extract tool metadata" in output + assert "Publishing will continue without detailed metadata" in output + assert "No tool metadata extracted" in output @patch("crewai.cli.tools.main.Settings")