diff --git a/agent/skills/loader.py b/agent/skills/loader.py index a39dba28..3784b015 100644 --- a/agent/skills/loader.py +++ b/agent/skills/loader.py @@ -53,6 +53,12 @@ class SkillLoader: """ Recursively load skills from a directory. + If a subdirectory contains its own SKILL.md, it is treated as a + self-contained skill (or skill-collection) and its children are + NOT scanned further. This prevents sub-skills inside a collection + (e.g. style-collection/style-anjing) from being listed as + independent top-level skills. + :param dir_path: Directory to scan :param source: Source identifier :param include_root_files: Whether to include root-level .md files @@ -66,38 +72,41 @@ class SkillLoader: except Exception as e: diagnostics.append(f"Failed to list directory {dir_path}: {e}") return LoadSkillsResult(skills=skills, diagnostics=diagnostics) + + # If this directory has its own SKILL.md, load it and stop recursing. + # The sub-directories are internal resources of this skill. + if not include_root_files and 'SKILL.md' in entries: + skill_md_path = os.path.join(dir_path, 'SKILL.md') + if os.path.isfile(skill_md_path): + skill_result = self._load_skill_from_file(skill_md_path, source) + if skill_result.skills: + skills.extend(skill_result.skills) + diagnostics.extend(skill_result.diagnostics) + return LoadSkillsResult(skills=skills, diagnostics=diagnostics) for entry in entries: - # Skip hidden files and directories if entry.startswith('.'): continue - # Skip common non-skill directories if entry in ('node_modules', '__pycache__', 'venv', '.git'): continue full_path = os.path.join(dir_path, entry) - # Handle directories if os.path.isdir(full_path): - # Recursively scan subdirectories sub_result = self._load_skills_recursive(full_path, source, include_root_files=False) skills.extend(sub_result.skills) diagnostics.extend(sub_result.diagnostics) continue - # Handle files if not os.path.isfile(full_path): continue - # Check if this is a skill file is_root_md = include_root_files and entry.endswith('.md') and entry.upper() != 'README.MD' - is_skill_md = not include_root_files and entry == 'SKILL.md' - if not (is_root_md or is_skill_md): + if not is_root_md: continue - # Load the skill skill_result = self._load_skill_from_file(full_path, source) if skill_result.skills: skills.extend(skill_result.skills) diff --git a/channel/web/web_channel.py b/channel/web/web_channel.py index e23c5e32..a7ea74ed 100644 --- a/channel/web/web_channel.py +++ b/channel/web/web_channel.py @@ -563,7 +563,7 @@ class ConfigHandler: _RECOMMENDED_MODELS = [ const.MINIMAX_M2_7, const.MINIMAX_M2_5, const.MINIMAX_M2_1, const.MINIMAX_M2_1_LIGHTNING, const.GLM_5_TURBO, const.GLM_5, const.GLM_4_7, - const.QWEN3_MAX, const.QWEN35_PLUS, + const.QWEN35_PLUS, const.QWEN3_MAX, const.KIMI_K2_5, const.KIMI_K2, const.DOUBAO_SEED_2_PRO, const.DOUBAO_SEED_2_CODE, const.CLAUDE_4_6_SONNET, const.CLAUDE_4_6_OPUS, const.CLAUDE_4_5_SONNET, @@ -592,7 +592,7 @@ class ConfigHandler: "api_key_field": "dashscope_api_key", "api_base_key": None, "api_base_default": None, - "models": [const.QWEN3_MAX, const.QWEN35_PLUS], + "models": [const.QWEN35_PLUS, const.QWEN3_MAX], }), ("moonshot", { "label": "Kimi", diff --git a/common/const.py b/common/const.py index 6c422b8e..654ee5da 100644 --- a/common/const.py +++ b/common/const.py @@ -172,7 +172,7 @@ MODEL_LIST = [ DEEPSEEK_CHAT, DEEPSEEK_REASONER, # Qwen - QWEN, QWEN_TURBO, QWEN_PLUS, QWEN_MAX, QWEN_LONG, QWEN3_MAX, QWEN35_PLUS, + QWEN35_PLUS, QWEN3_MAX, QWEN_MAX, QWEN_PLUS, QWEN_TURBO, QWEN_LONG, QWEN, # MiniMax MiniMax, MINIMAX_M2_7, MINIMAX_M2_5, MINIMAX_M2_1, MINIMAX_M2_1_LIGHTNING, MINIMAX_M2, MINIMAX_ABAB6_5,