diff --git a/configs/skills/direct_agent.yaml b/configs/skills/direct_agent.yaml index c5ad434..ca5de64 100644 --- a/configs/skills/direct_agent.yaml +++ b/configs/skills/direct_agent.yaml @@ -8,7 +8,7 @@ max_steps: 1 max_concurrency: 5 intent: - keywords: ["翻译", "摘要", "格式化", "translate", "summarize", "什么是"] + keywords: ["翻译", "摘要", "格式化", "translate", "summarize", "你好", "什么是"] description: "简单生成任务,无需工具调用,单次LLM生成即可" examples: - "翻译这段话" diff --git a/src/agentkit/chat/skill_routing.py b/src/agentkit/chat/skill_routing.py index 055bf78..e4df932 100644 --- a/src/agentkit/chat/skill_routing.py +++ b/src/agentkit/chat/skill_routing.py @@ -133,16 +133,55 @@ async def resolve_skill_routing( skill_name = routing_result.matched_skill try: matched_skill = skill_registry.get(skill_name) - result.skill_name = skill_name - result.skill_config = matched_skill.config - result.skill_tools = matched_skill.tools or [] - result.matched = True - result.match_method = routing_result.method - result.match_confidence = routing_result.confidence - logger.info( - f"Session {session_id}: routed to skill '{skill_name}' " - f"via {routing_result.method} (confidence={routing_result.confidence})" - ) + skill_config = matched_skill.config + + # Check if matched skill can handle tool-calling tasks. + # Direct-mode agents with no tools cannot execute tasks + # that require tool use (shell, search, etc.). + # If the task content suggests tool needs, fall through + # to default agent which has full tool access. + execution_mode = getattr(skill_config, "execution_mode", "react") + skill_tools = matched_skill.tools or [] + if execution_mode == "direct" and not skill_tools: + # Direct agent matched but has no tools — check if + # the task might need tools. If so, skip this match + # and let it fall through to default agent. + tool_hints = [ + "执行", "运行", "命令", "终端", "shell", "bash", + "搜索", "查找", "联网", "搜索", "search", + "安装", "部署", "启动", "停止", "重启", + "文件", "目录", "创建", "删除", "修改", + "run", "execute", "install", "deploy", + "start", "stop", "restart", "file", + ] + content_lower = clean_content.lower() + needs_tools = any(h in content_lower for h in tool_hints) + if needs_tools: + logger.info( + f"Session {session_id}: skill '{skill_name}' is direct-mode " + f"but task may need tools, falling through to default agent" + ) + # Don't set result.matched, let it fall through + else: + result.skill_name = skill_name + result.skill_config = skill_config + result.skill_tools = skill_tools + result.matched = True + result.match_method = routing_result.method + result.match_confidence = routing_result.confidence + else: + result.skill_name = skill_name + result.skill_config = skill_config + result.skill_tools = skill_tools + result.matched = True + result.match_method = routing_result.method + result.match_confidence = routing_result.confidence + + if result.matched: + logger.info( + f"Session {session_id}: routed to skill '{skill_name}' " + f"via {routing_result.method} (confidence={routing_result.confidence})" + ) except Exception as e: logger.warning(f"Session {session_id}: skill '{skill_name}' found by router but not in registry: {e}") except Exception as e: