diff --git a/autogpt_platform/backend/backend/blocks/smart_decision_maker.py b/autogpt_platform/backend/backend/blocks/smart_decision_maker.py index d96fa13efd..9b9856a0a6 100644 --- a/autogpt_platform/backend/backend/blocks/smart_decision_maker.py +++ b/autogpt_platform/backend/backend/blocks/smart_decision_maker.py @@ -391,8 +391,12 @@ class SmartDecisionMakerBlock(Block): """ block = sink_node.block + # Use custom name from node metadata if set, otherwise fall back to block.name + custom_name = sink_node.metadata.get("customized_name") + tool_name = custom_name if custom_name else block.name + tool_function: dict[str, Any] = { - "name": SmartDecisionMakerBlock.cleanup(block.name), + "name": SmartDecisionMakerBlock.cleanup(tool_name), "description": block.description, } sink_block_input_schema = block.input_schema @@ -489,8 +493,12 @@ class SmartDecisionMakerBlock(Block): f"Sink graph metadata not found: {graph_id} {graph_version}" ) + # Use custom name from node metadata if set, otherwise fall back to graph name + custom_name = sink_node.metadata.get("customized_name") + tool_name = custom_name if custom_name else sink_graph_meta.name + tool_function: dict[str, Any] = { - "name": SmartDecisionMakerBlock.cleanup(sink_graph_meta.name), + "name": SmartDecisionMakerBlock.cleanup(tool_name), "description": sink_graph_meta.description, } diff --git a/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker.py b/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker.py index c930fab37e..8266d433ad 100644 --- a/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker.py +++ b/autogpt_platform/backend/backend/blocks/test/test_smart_decision_maker.py @@ -1057,3 +1057,153 @@ async def test_smart_decision_maker_traditional_mode_default(): ) # Should yield individual tool parameters assert "tools_^_test-sink-node-id_~_max_keyword_difficulty" in outputs assert "conversations" in outputs + + +@pytest.mark.asyncio +async def test_smart_decision_maker_uses_customized_name_for_blocks(): + """Test that SmartDecisionMakerBlock uses customized_name from node metadata for tool names.""" + from unittest.mock import MagicMock + + from backend.blocks.basic import StoreValueBlock + from backend.blocks.smart_decision_maker import SmartDecisionMakerBlock + from backend.data.graph import Link, Node + + # Create a mock node with customized_name in metadata + mock_node = MagicMock(spec=Node) + mock_node.id = "test-node-id" + mock_node.block_id = StoreValueBlock().id + mock_node.metadata = {"customized_name": "My Custom Tool Name"} + mock_node.block = StoreValueBlock() + + # Create a mock link + mock_link = MagicMock(spec=Link) + mock_link.sink_name = "input" + + # Call the function directly + result = await SmartDecisionMakerBlock._create_block_function_signature( + mock_node, [mock_link] + ) + + # Verify the tool name uses the customized name (cleaned up) + assert result["type"] == "function" + assert result["function"]["name"] == "my_custom_tool_name" # Cleaned version + assert result["function"]["_sink_node_id"] == "test-node-id" + + +@pytest.mark.asyncio +async def test_smart_decision_maker_falls_back_to_block_name(): + """Test that SmartDecisionMakerBlock falls back to block.name when no customized_name.""" + from unittest.mock import MagicMock + + from backend.blocks.basic import StoreValueBlock + from backend.blocks.smart_decision_maker import SmartDecisionMakerBlock + from backend.data.graph import Link, Node + + # Create a mock node without customized_name + mock_node = MagicMock(spec=Node) + mock_node.id = "test-node-id" + mock_node.block_id = StoreValueBlock().id + mock_node.metadata = {} # No customized_name + mock_node.block = StoreValueBlock() + + # Create a mock link + mock_link = MagicMock(spec=Link) + mock_link.sink_name = "input" + + # Call the function directly + result = await SmartDecisionMakerBlock._create_block_function_signature( + mock_node, [mock_link] + ) + + # Verify the tool name uses the block's default name + assert result["type"] == "function" + assert result["function"]["name"] == "storevalueblock" # Default block name cleaned + assert result["function"]["_sink_node_id"] == "test-node-id" + + +@pytest.mark.asyncio +async def test_smart_decision_maker_uses_customized_name_for_agents(): + """Test that SmartDecisionMakerBlock uses customized_name from metadata for agent nodes.""" + from unittest.mock import AsyncMock, MagicMock, patch + + from backend.blocks.smart_decision_maker import SmartDecisionMakerBlock + from backend.data.graph import Link, Node + + # Create a mock node with customized_name in metadata + mock_node = MagicMock(spec=Node) + mock_node.id = "test-agent-node-id" + mock_node.metadata = {"customized_name": "My Custom Agent"} + mock_node.input_default = { + "graph_id": "test-graph-id", + "graph_version": 1, + "input_schema": {"properties": {"test_input": {"description": "Test input"}}}, + } + + # Create a mock link + mock_link = MagicMock(spec=Link) + mock_link.sink_name = "test_input" + + # Mock the database client + mock_graph_meta = MagicMock() + mock_graph_meta.name = "Original Agent Name" + mock_graph_meta.description = "Agent description" + + mock_db_client = AsyncMock() + mock_db_client.get_graph_metadata.return_value = mock_graph_meta + + with patch( + "backend.blocks.smart_decision_maker.get_database_manager_async_client", + return_value=mock_db_client, + ): + result = await SmartDecisionMakerBlock._create_agent_function_signature( + mock_node, [mock_link] + ) + + # Verify the tool name uses the customized name (cleaned up) + assert result["type"] == "function" + assert result["function"]["name"] == "my_custom_agent" # Cleaned version + assert result["function"]["_sink_node_id"] == "test-agent-node-id" + + +@pytest.mark.asyncio +async def test_smart_decision_maker_agent_falls_back_to_graph_name(): + """Test that agent node falls back to graph name when no customized_name.""" + from unittest.mock import AsyncMock, MagicMock, patch + + from backend.blocks.smart_decision_maker import SmartDecisionMakerBlock + from backend.data.graph import Link, Node + + # Create a mock node without customized_name + mock_node = MagicMock(spec=Node) + mock_node.id = "test-agent-node-id" + mock_node.metadata = {} # No customized_name + mock_node.input_default = { + "graph_id": "test-graph-id", + "graph_version": 1, + "input_schema": {"properties": {"test_input": {"description": "Test input"}}}, + } + + # Create a mock link + mock_link = MagicMock(spec=Link) + mock_link.sink_name = "test_input" + + # Mock the database client + mock_graph_meta = MagicMock() + mock_graph_meta.name = "Original Agent Name" + mock_graph_meta.description = "Agent description" + + mock_db_client = AsyncMock() + mock_db_client.get_graph_metadata.return_value = mock_graph_meta + + with patch( + "backend.blocks.smart_decision_maker.get_database_manager_async_client", + return_value=mock_db_client, + ): + result = await SmartDecisionMakerBlock._create_agent_function_signature( + mock_node, [mock_link] + ) + + # Verify the tool name uses the graph's default name + assert result["type"] == "function" + assert result["function"]["name"] == "original_agent_name" # Graph name cleaned + assert result["function"]["_sink_node_id"] == "test-agent-node-id"