diff --git a/api/core/workflow/entities/node_entities.py b/api/core/workflow/entities/node_entities.py index cbadd15d38..72d881d3d5 100644 --- a/api/core/workflow/entities/node_entities.py +++ b/api/core/workflow/entities/node_entities.py @@ -66,6 +66,7 @@ class NodeRunMetadataKey(Enum): TOTAL_TOKENS = 'total_tokens' TOTAL_PRICE = 'total_price' CURRENCY = 'currency' + TOOL_INFO = 'tool_info' class NodeRunResult(BaseModel): diff --git a/api/core/workflow/nodes/tool/tool_node.py b/api/core/workflow/nodes/tool/tool_node.py index 63be230d6c..bbad1f1c36 100644 --- a/api/core/workflow/nodes/tool/tool_node.py +++ b/api/core/workflow/nodes/tool/tool_node.py @@ -8,7 +8,7 @@ from core.tools.tool_engine import ToolEngine from core.tools.tool_manager import ToolManager from core.tools.utils.message_transformer import ToolFileMessageTransformer from core.workflow.entities.base_node_data_entities import BaseNodeData -from core.workflow.entities.node_entities import NodeRunResult, NodeType +from core.workflow.entities.node_entities import NodeRunMetadataKey, NodeRunResult, NodeType from core.workflow.entities.variable_pool import VariablePool from core.workflow.nodes.base_node import BaseNode from core.workflow.nodes.tool.entities import ToolNodeData @@ -30,6 +30,12 @@ class ToolNode(BaseNode): node_data = cast(ToolNodeData, self.node_data) + # fetch tool icon + tool_info = { + 'provider_type': node_data.provider_type, + 'provider_id': node_data.provider_id + } + # get parameters parameters = self._generate_parameters(variable_pool, node_data) # get tool runtime @@ -39,6 +45,9 @@ class ToolNode(BaseNode): return NodeRunResult( status=WorkflowNodeExecutionStatus.FAILED, inputs=parameters, + metadata={ + NodeRunMetadataKey.TOOL_INFO: tool_info + }, error=f'Failed to get tool runtime: {str(e)}' ) @@ -54,6 +63,9 @@ class ToolNode(BaseNode): return NodeRunResult( status=WorkflowNodeExecutionStatus.FAILED, inputs=parameters, + metadata={ + NodeRunMetadataKey.TOOL_INFO: tool_info + }, error=f'Failed to invoke tool: {str(e)}', ) @@ -66,6 +78,9 @@ class ToolNode(BaseNode): 'text': plain_text, 'files': files }, + metadata={ + NodeRunMetadataKey.TOOL_INFO: tool_info + }, inputs=parameters ) diff --git a/api/fields/workflow_run_fields.py b/api/fields/workflow_run_fields.py index 902d0948c1..3e798473cd 100644 --- a/api/fields/workflow_run_fields.py +++ b/api/fields/workflow_run_fields.py @@ -89,6 +89,7 @@ workflow_run_node_execution_fields = { "error": fields.String, "elapsed_time": fields.Float, "execution_metadata": fields.Raw(attribute='execution_metadata_dict'), + "extras": fields.Raw, "created_at": TimestampField, "created_by_role": fields.String, "created_by_account": fields.Nested(simple_account_fields, attribute='created_by_account', allow_null=True), diff --git a/api/models/workflow.py b/api/models/workflow.py index cdeefd9e39..6408552d23 100644 --- a/api/models/workflow.py +++ b/api/models/workflow.py @@ -4,6 +4,7 @@ from typing import Optional, Union from sqlalchemy.dialects.postgresql import UUID +from core.tools.tool_manager import ToolManager from extensions.ext_database import db from models.account import Account @@ -451,6 +452,21 @@ class WorkflowNodeExecution(db.Model): def execution_metadata_dict(self): return json.loads(self.execution_metadata) if self.execution_metadata else None + @property + def extras(self): + extras = {} + if self.execution_metadata_dict: + from core.workflow.entities.node_entities import NodeType + if self.node_type == NodeType.TOOL.value and 'tool_info' in self.execution_metadata_dict: + tool_info = self.execution_metadata_dict['tool_info'] + extras['icon'] = ToolManager.get_tool_icon( + tenant_id=self.tenant_id, + provider_type=tool_info['provider_type'], + provider_id=tool_info['provider_id'] + ) + + return extras + class WorkflowAppLogCreatedFrom(Enum): """