Refactor skills tool integration and enhance system prompt
- Removed the skills_categories tool from the skills toolset, streamlining the skills functionality to focus on skills_list and skill_view. - Updated the system prompt to dynamically build a compact skills index, allowing the model to quickly reference available skills without additional tool calls. - Cleaned up related code and documentation to reflect the removal of skills_categories, ensuring clarity and consistency across the codebase.
This commit is contained in:
parent
669545f551
commit
153cd5bb44
4 changed files with 94 additions and 55 deletions
|
|
@ -41,7 +41,7 @@ from tools.terminal_hecate import terminal_hecate_tool, check_hecate_requirement
|
||||||
from tools.vision_tools import vision_analyze_tool, check_vision_requirements
|
from tools.vision_tools import vision_analyze_tool, check_vision_requirements
|
||||||
from tools.mixture_of_agents_tool import mixture_of_agents_tool, check_moa_requirements
|
from tools.mixture_of_agents_tool import mixture_of_agents_tool, check_moa_requirements
|
||||||
from tools.image_generation_tool import image_generate_tool, check_image_generation_requirements
|
from tools.image_generation_tool import image_generate_tool, check_image_generation_requirements
|
||||||
from tools.skills_tool import skills_categories, skills_list, skill_view, check_skills_requirements, SKILLS_TOOL_DESCRIPTION
|
from tools.skills_tool import skills_list, skill_view, check_skills_requirements, SKILLS_TOOL_DESCRIPTION
|
||||||
# RL Training tools (Tinker-Atropos)
|
# RL Training tools (Tinker-Atropos)
|
||||||
from tools.rl_training_tool import (
|
from tools.rl_training_tool import (
|
||||||
rl_list_environments,
|
rl_list_environments,
|
||||||
|
|
@ -143,7 +143,7 @@ TOOLSET_REQUIREMENTS = {
|
||||||
"env_vars": [], # Just needs skills directory
|
"env_vars": [], # Just needs skills directory
|
||||||
"check_fn": check_skills_requirements,
|
"check_fn": check_skills_requirements,
|
||||||
"setup_url": None,
|
"setup_url": None,
|
||||||
"tools": ["skills_categories", "skills_list", "skill_view"],
|
"tools": ["skills_list", "skill_view"],
|
||||||
},
|
},
|
||||||
"rl": {
|
"rl": {
|
||||||
"name": "RL Training (Tinker-Atropos)",
|
"name": "RL Training (Tinker-Atropos)",
|
||||||
|
|
@ -432,24 +432,7 @@ def get_skills_tool_definitions() -> List[Dict[str, Any]]:
|
||||||
"properties": {
|
"properties": {
|
||||||
"category": {
|
"category": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Optional category filter (from skills_categories)"
|
"description": "Optional category filter to narrow results"
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "skills_categories",
|
|
||||||
"description": "List available skill categories. Call this first to discover what skill categories exist, then use skills_list(category) to see skills in a category.",
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"verbose": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "If true, include skill counts per category. Default: false."
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|
@ -910,7 +893,7 @@ def get_all_tool_names() -> List[str]:
|
||||||
|
|
||||||
# Skills tools
|
# Skills tools
|
||||||
if check_skills_requirements():
|
if check_skills_requirements():
|
||||||
tool_names.extend(["skills_categories", "skills_list", "skill_view"])
|
tool_names.extend(["skills_list", "skill_view"])
|
||||||
|
|
||||||
# Browser automation tools
|
# Browser automation tools
|
||||||
if check_browser_requirements():
|
if check_browser_requirements():
|
||||||
|
|
@ -957,7 +940,6 @@ TOOL_TO_TOOLSET_MAP = {
|
||||||
"mixture_of_agents": "moa_tools",
|
"mixture_of_agents": "moa_tools",
|
||||||
"image_generate": "image_tools",
|
"image_generate": "image_tools",
|
||||||
# Skills tools
|
# Skills tools
|
||||||
"skills_categories": "skills_tools",
|
|
||||||
"skills_list": "skills_tools",
|
"skills_list": "skills_tools",
|
||||||
"skill_view": "skills_tools",
|
"skill_view": "skills_tools",
|
||||||
# Browser automation tools
|
# Browser automation tools
|
||||||
|
|
@ -1109,7 +1091,7 @@ def get_tool_definitions(
|
||||||
"vision_tools": ["vision_analyze"],
|
"vision_tools": ["vision_analyze"],
|
||||||
"moa_tools": ["mixture_of_agents"],
|
"moa_tools": ["mixture_of_agents"],
|
||||||
"image_tools": ["image_generate"],
|
"image_tools": ["image_generate"],
|
||||||
"skills_tools": ["skills_categories", "skills_list", "skill_view"],
|
"skills_tools": ["skills_list", "skill_view"],
|
||||||
"browser_tools": [
|
"browser_tools": [
|
||||||
"browser_navigate", "browser_snapshot", "browser_click",
|
"browser_navigate", "browser_snapshot", "browser_click",
|
||||||
"browser_type", "browser_scroll", "browser_back",
|
"browser_type", "browser_scroll", "browser_back",
|
||||||
|
|
@ -1162,7 +1144,7 @@ def get_tool_definitions(
|
||||||
"vision_tools": ["vision_analyze"],
|
"vision_tools": ["vision_analyze"],
|
||||||
"moa_tools": ["mixture_of_agents"],
|
"moa_tools": ["mixture_of_agents"],
|
||||||
"image_tools": ["image_generate"],
|
"image_tools": ["image_generate"],
|
||||||
"skills_tools": ["skills_categories", "skills_list", "skill_view"],
|
"skills_tools": ["skills_list", "skill_view"],
|
||||||
"browser_tools": [
|
"browser_tools": [
|
||||||
"browser_navigate", "browser_snapshot", "browser_click",
|
"browser_navigate", "browser_snapshot", "browser_click",
|
||||||
"browser_type", "browser_scroll", "browser_back",
|
"browser_type", "browser_scroll", "browser_back",
|
||||||
|
|
@ -1391,11 +1373,7 @@ def handle_skills_function_call(function_name: str, function_args: Dict[str, Any
|
||||||
Returns:
|
Returns:
|
||||||
str: Function result as JSON string
|
str: Function result as JSON string
|
||||||
"""
|
"""
|
||||||
if function_name == "skills_categories":
|
if function_name == "skills_list":
|
||||||
verbose = function_args.get("verbose", False)
|
|
||||||
return skills_categories(verbose=verbose)
|
|
||||||
|
|
||||||
elif function_name == "skills_list":
|
|
||||||
category = function_args.get("category")
|
category = function_args.get("category")
|
||||||
return skills_list(category=category)
|
return skills_list(category=category)
|
||||||
|
|
||||||
|
|
@ -1686,7 +1664,7 @@ def handle_function_call(
|
||||||
return handle_image_function_call(function_name, function_args)
|
return handle_image_function_call(function_name, function_args)
|
||||||
|
|
||||||
# Route skills tools
|
# Route skills tools
|
||||||
elif function_name in ["skills_categories", "skills_list", "skill_view"]:
|
elif function_name in ["skills_list", "skill_view"]:
|
||||||
return handle_skills_function_call(function_name, function_args)
|
return handle_skills_function_call(function_name, function_args)
|
||||||
|
|
||||||
# Route browser automation tools
|
# Route browser automation tools
|
||||||
|
|
@ -1767,7 +1745,7 @@ def get_available_toolsets() -> Dict[str, Dict[str, Any]]:
|
||||||
},
|
},
|
||||||
"skills_tools": {
|
"skills_tools": {
|
||||||
"available": check_skills_requirements(),
|
"available": check_skills_requirements(),
|
||||||
"tools": ["skills_categories", "skills_list", "skill_view"],
|
"tools": ["skills_list", "skill_view"],
|
||||||
"description": "Access skill documents that provide specialized instructions, guidelines, or knowledge the agent can load on demand",
|
"description": "Access skill documents that provide specialized instructions, guidelines, or knowledge the agent can load on demand",
|
||||||
"requirements": ["skills/ directory in repo root"]
|
"requirements": ["skills/ directory in repo root"]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
95
run_agent.py
95
run_agent.py
|
|
@ -550,14 +550,79 @@ def apply_anthropic_cache_control(
|
||||||
# Default System Prompt Components
|
# Default System Prompt Components
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
# Skills guidance - instructs the model to check skills before technical tasks
|
# Skills guidance - embeds a compact skill index in the system prompt so
|
||||||
SKILLS_SYSTEM_PROMPT = """## Skills
|
# the model can match skills at a glance without extra tool calls.
|
||||||
Before answering technical questions about tools, frameworks, or workflows:
|
def build_skills_system_prompt() -> str:
|
||||||
1. Check skills_categories to see if a relevant category exists
|
"""
|
||||||
2. If a category matches your task, use skills_list with that category
|
Build a dynamic skills system prompt by scanning the skills/ directory.
|
||||||
3. If a skill matches, load it with skill_view and follow its instructions
|
|
||||||
|
|
||||||
Skills contain vetted, up-to-date instructions for specific tools and workflows."""
|
Returns a prompt section that lists all skill categories (with descriptions
|
||||||
|
from DESCRIPTION.md) and their skill names inline, so the model can
|
||||||
|
immediately see if a relevant skill exists and load it with a single
|
||||||
|
skill_view(name) call -- no discovery tool calls needed.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The skills system prompt section, or empty string if no skills found.
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
skills_dir = Path(__file__).parent / "skills"
|
||||||
|
if not skills_dir.exists():
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# Scan for SKILL.md files grouped by category
|
||||||
|
skills_by_category = {}
|
||||||
|
for skill_file in skills_dir.rglob("SKILL.md"):
|
||||||
|
rel_path = skill_file.relative_to(skills_dir)
|
||||||
|
parts = rel_path.parts
|
||||||
|
if len(parts) >= 2:
|
||||||
|
category = parts[0]
|
||||||
|
skill_name = parts[-2] # Folder containing SKILL.md
|
||||||
|
else:
|
||||||
|
category = "general"
|
||||||
|
skill_name = skill_file.parent.name
|
||||||
|
skills_by_category.setdefault(category, []).append(skill_name)
|
||||||
|
|
||||||
|
if not skills_by_category:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
# Load category descriptions from DESCRIPTION.md files (YAML frontmatter)
|
||||||
|
category_descriptions = {}
|
||||||
|
for category in skills_by_category:
|
||||||
|
desc_file = skills_dir / category / "DESCRIPTION.md"
|
||||||
|
if desc_file.exists():
|
||||||
|
try:
|
||||||
|
content = desc_file.read_text(encoding="utf-8")
|
||||||
|
# Parse description from YAML frontmatter: ---\ndescription: ...\n---
|
||||||
|
match = re.search(r"^---\s*\n.*?description:\s*(.+?)\s*\n.*?^---", content, re.MULTILINE | re.DOTALL)
|
||||||
|
if match:
|
||||||
|
category_descriptions[category] = match.group(1).strip()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Build compact index: category with description + skill names
|
||||||
|
index_lines = []
|
||||||
|
for category in sorted(skills_by_category.keys()):
|
||||||
|
desc = category_descriptions.get(category, "")
|
||||||
|
names = ", ".join(sorted(skills_by_category[category]))
|
||||||
|
if desc:
|
||||||
|
index_lines.append(f" {category}: {desc}")
|
||||||
|
else:
|
||||||
|
index_lines.append(f" {category}:")
|
||||||
|
index_lines.append(f" skills: {names}")
|
||||||
|
|
||||||
|
return (
|
||||||
|
"## Skills (mandatory)\n"
|
||||||
|
"Before replying, scan the skills below. If one clearly matches your task, "
|
||||||
|
"load it with skill_view(name) and follow its instructions.\n"
|
||||||
|
"\n"
|
||||||
|
"<available_skills>\n"
|
||||||
|
+ "\n".join(index_lines) + "\n"
|
||||||
|
"</available_skills>\n"
|
||||||
|
"\n"
|
||||||
|
"If none match, proceed normally without loading a skill."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class KawaiiSpinner:
|
class KawaiiSpinner:
|
||||||
|
|
@ -1054,10 +1119,6 @@ class AIAgent:
|
||||||
return f"{face} 🎨 creating '{prompt}'... {time_str}"
|
return f"{face} 🎨 creating '{prompt}'... {time_str}"
|
||||||
|
|
||||||
# Skills - use large pool for variety
|
# Skills - use large pool for variety
|
||||||
elif tool_name == "skills_categories":
|
|
||||||
face = random.choice(self.KAWAII_SKILL)
|
|
||||||
return f"{face} 📚 listing categories... {time_str}"
|
|
||||||
|
|
||||||
elif tool_name == "skills_list":
|
elif tool_name == "skills_list":
|
||||||
category = args.get("category", "skills")
|
category = args.get("category", "skills")
|
||||||
face = random.choice(self.KAWAII_SKILL)
|
face = random.choice(self.KAWAII_SKILL)
|
||||||
|
|
@ -1635,12 +1696,15 @@ class AIAgent:
|
||||||
base_system_prompt = system_message if system_message is not None else self.ephemeral_system_prompt
|
base_system_prompt = system_message if system_message is not None else self.ephemeral_system_prompt
|
||||||
|
|
||||||
# Auto-include skills guidance if skills tools are available
|
# Auto-include skills guidance if skills tools are available
|
||||||
has_skills_tools = any(name in self.valid_tool_names for name in ['skills_list', 'skills_categories', 'skill_view'])
|
# Embeds a compact category:names index so the model can match skills
|
||||||
if has_skills_tools:
|
# at a glance and load with a single skill_view(name) call.
|
||||||
|
has_skills_tools = any(name in self.valid_tool_names for name in ['skills_list', 'skill_view'])
|
||||||
|
skills_prompt = build_skills_system_prompt() if has_skills_tools else ""
|
||||||
|
if skills_prompt:
|
||||||
if base_system_prompt:
|
if base_system_prompt:
|
||||||
active_system_prompt = f"{base_system_prompt}\n\n{SKILLS_SYSTEM_PROMPT}"
|
active_system_prompt = f"{base_system_prompt}\n\n{skills_prompt}"
|
||||||
else:
|
else:
|
||||||
active_system_prompt = SKILLS_SYSTEM_PROMPT
|
active_system_prompt = skills_prompt
|
||||||
else:
|
else:
|
||||||
active_system_prompt = base_system_prompt
|
active_system_prompt = base_system_prompt
|
||||||
|
|
||||||
|
|
@ -2277,7 +2341,6 @@ class AIAgent:
|
||||||
'image_generate': ('sparkle', ['🎨', '✨', '🖼️', '🌟']),
|
'image_generate': ('sparkle', ['🎨', '✨', '🖼️', '🌟']),
|
||||||
'skill_view': ('star', ['📚', '📖', '🎓', '✨']),
|
'skill_view': ('star', ['📚', '📖', '🎓', '✨']),
|
||||||
'skills_list': ('pulse', ['📋', '📝', '📑', '📜']),
|
'skills_list': ('pulse', ['📋', '📝', '📑', '📜']),
|
||||||
'skills_categories': ('pulse', ['📂', '🗂️', '📁', '🏷️']),
|
|
||||||
'moa_query': ('brain', ['🧠', '💭', '🤔', '💡']),
|
'moa_query': ('brain', ['🧠', '💭', '🤔', '💡']),
|
||||||
'analyze_image': ('sparkle', ['👁️', '🔍', '📷', '✨']),
|
'analyze_image': ('sparkle', ['👁️', '🔍', '📷', '✨']),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,6 @@ from .image_generation_tool import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from .skills_tool import (
|
from .skills_tool import (
|
||||||
skills_categories,
|
|
||||||
skills_list,
|
skills_list,
|
||||||
skill_view,
|
skill_view,
|
||||||
check_skills_requirements,
|
check_skills_requirements,
|
||||||
|
|
@ -158,7 +157,6 @@ __all__ = [
|
||||||
'image_generate_tool',
|
'image_generate_tool',
|
||||||
'check_image_generation_requirements',
|
'check_image_generation_requirements',
|
||||||
# Skills tools
|
# Skills tools
|
||||||
'skills_categories',
|
|
||||||
'skills_list',
|
'skills_list',
|
||||||
'skill_view',
|
'skill_view',
|
||||||
'check_skills_requirements',
|
'check_skills_requirements',
|
||||||
|
|
|
||||||
10
toolsets.py
10
toolsets.py
|
|
@ -69,7 +69,7 @@ TOOLSETS = {
|
||||||
|
|
||||||
"skills": {
|
"skills": {
|
||||||
"description": "Access skill documents with specialized instructions and knowledge",
|
"description": "Access skill documents with specialized instructions and knowledge",
|
||||||
"tools": ["skills_categories", "skills_list", "skill_view"],
|
"tools": ["skills_list", "skill_view"],
|
||||||
"includes": []
|
"includes": []
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -142,7 +142,7 @@ TOOLSETS = {
|
||||||
# MoA
|
# MoA
|
||||||
"mixture_of_agents",
|
"mixture_of_agents",
|
||||||
# Skills
|
# Skills
|
||||||
"skills_categories", "skills_list", "skill_view",
|
"skills_list", "skill_view",
|
||||||
# Browser
|
# Browser
|
||||||
"browser_navigate", "browser_snapshot", "browser_click",
|
"browser_navigate", "browser_snapshot", "browser_click",
|
||||||
"browser_type", "browser_scroll", "browser_back",
|
"browser_type", "browser_scroll", "browser_back",
|
||||||
|
|
@ -170,7 +170,7 @@ TOOLSETS = {
|
||||||
# Vision - analyze images sent by users
|
# Vision - analyze images sent by users
|
||||||
"vision_analyze",
|
"vision_analyze",
|
||||||
# Skills - access knowledge base
|
# Skills - access knowledge base
|
||||||
"skills_categories", "skills_list", "skill_view",
|
"skills_list", "skill_view",
|
||||||
# Cronjob management - let users schedule tasks
|
# Cronjob management - let users schedule tasks
|
||||||
"schedule_cronjob", "list_cronjobs", "remove_cronjob"
|
"schedule_cronjob", "list_cronjobs", "remove_cronjob"
|
||||||
],
|
],
|
||||||
|
|
@ -185,7 +185,7 @@ TOOLSETS = {
|
||||||
# Vision - analyze images
|
# Vision - analyze images
|
||||||
"vision_analyze",
|
"vision_analyze",
|
||||||
# Skills - access knowledge base
|
# Skills - access knowledge base
|
||||||
"skills_categories", "skills_list", "skill_view",
|
"skills_list", "skill_view",
|
||||||
# Cronjob - let users schedule reminders
|
# Cronjob - let users schedule reminders
|
||||||
"schedule_cronjob", "list_cronjobs", "remove_cronjob"
|
"schedule_cronjob", "list_cronjobs", "remove_cronjob"
|
||||||
],
|
],
|
||||||
|
|
@ -204,7 +204,7 @@ TOOLSETS = {
|
||||||
# Vision
|
# Vision
|
||||||
"vision_analyze",
|
"vision_analyze",
|
||||||
# Skills
|
# Skills
|
||||||
"skills_categories", "skills_list", "skill_view",
|
"skills_list", "skill_view",
|
||||||
# Cronjob management
|
# Cronjob management
|
||||||
"schedule_cronjob", "list_cronjobs", "remove_cronjob"
|
"schedule_cronjob", "list_cronjobs", "remove_cronjob"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue