From cc4c6fe346bf859818554bec4e76a7246f358149 Mon Sep 17 00:00:00 2001 From: chiguyong Date: Thu, 11 Jun 2026 15:26:19 +0800 Subject: [PATCH] fix: direct-mode agent falls through to default when task needs tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When IntentRouter matches a direct-mode agent (no tools), but the task content suggests tool needs (shell, search, file ops, etc.), the routing now falls through to the default agent which has full tool access. This fixes the issue where "帮我执行个命令" would be routed to direct_agent and fail because direct mode doesn't support tool calling. Also restored "你好" in direct_agent keywords since it's correctly handled now — greetings don't need tools, direct mode is fine. --- configs/skills/direct_agent.yaml | 2 +- src/agentkit/chat/skill_routing.py | 59 +++++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 11 deletions(-) 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: