diff --git a/api/controllers/console/app/skills.py b/api/controllers/console/app/skills.py index 714edfa636..8364b1daf6 100644 --- a/api/controllers/console/app/skills.py +++ b/api/controllers/console/app/skills.py @@ -4,8 +4,10 @@ from controllers.console import console_ns from controllers.console.app.error import DraftWorkflowNotExist from controllers.console.app.wraps import get_app_model from controllers.console.wraps import account_initialization_required, current_account_with_tenant, setup_required +from core.skill.entities.api_entities import NodeSkillInfo from libs.login import login_required from models import App +from models._workflow_exc import NodeNotFoundError from models.model import AppMode from services.skill_service import SkillService from services.workflow_service import WorkflowService @@ -40,12 +42,15 @@ class NodeSkillsApi(Resource): if not workflow: raise DraftWorkflowNotExist() - skill_info = SkillService.get_node_skill_info( - app=app_model, - workflow=workflow, - node_id=node_id, - user_id=current_user.id, - ) + try: + skill_info = SkillService.get_node_skill_info( + app=app_model, + workflow=workflow, + node_id=node_id, + user_id=current_user.id, + ) + except NodeNotFoundError: + return NodeSkillInfo.empty(node_id=node_id).model_dump() return skill_info.model_dump() diff --git a/api/core/skill/entities/api_entities.py b/api/core/skill/entities/api_entities.py index 6c0e37011d..969aedaef9 100644 --- a/api/core/skill/entities/api_entities.py +++ b/api/core/skill/entities/api_entities.py @@ -10,3 +10,8 @@ class NodeSkillInfo(BaseModel): tool_dependencies: list[ToolDependency] = Field( default_factory=list, description="Tool dependencies extracted from skill prompts" ) + + @staticmethod + def empty(node_id: str = "") -> "NodeSkillInfo": + """Create an empty NodeSkillInfo with no tool dependencies.""" + return NodeSkillInfo(node_id=node_id, tool_dependencies=[]) diff --git a/api/services/skill_service.py b/api/services/skill_service.py index 591a853c26..a1d8f84187 100644 --- a/api/services/skill_service.py +++ b/api/services/skill_service.py @@ -7,7 +7,9 @@ from core.skill.entities.skill_document import SkillDocument from core.skill.entities.tool_dependencies import ToolDependencies, ToolDependency from core.skill.skill_compiler import SkillCompiler from core.skill.skill_manager import SkillManager +from core.workflow.entities.graph_config import NodeConfigData, NodeConfigDict from core.workflow.enums import NodeType +from models._workflow_exc import NodeNotFoundError from models.model import App from models.workflow import Workflow from services.app_asset_service import AppAssetService @@ -34,8 +36,10 @@ class SkillService: Returns: NodeSkillInfo containing tool dependencies for the node """ - node_config = workflow.get_node_config_by_id(node_id) - node_data = node_config.get("data", {}) + node_config: NodeConfigDict = workflow.get_node_config_by_id(node_id) + if not node_config: + raise NodeNotFoundError(f"Node with ID {node_id} not found in workflow {workflow.id}") + node_data: NodeConfigData = node_config["data"] node_type = node_data.get("type", "") # Only LLM nodes support skills currently @@ -84,7 +88,7 @@ class SkillService: return result @staticmethod - def _has_skill(node_data: dict[str, Any]) -> bool: + def _has_skill(node_data: NodeConfigData) -> bool: """Check if node has any skill prompts.""" prompt_template = node_data.get("prompt_template", []) if isinstance(prompt_template, list):