fischer-agentkit/src/agentkit/cli/skill.py

172 lines
5.3 KiB
Python

"""Skill management CLI commands"""
import os
from typing import Optional
import typer
from rich import print as rprint
from rich.table import Table
skill_app = typer.Typer(name="skill", help="Skill management commands", no_args_is_help=True)
@skill_app.command("list")
def list_skills(
server_url: Optional[str] = typer.Option(None, "--server-url", help="AgentKit server URL"),
):
"""List registered skills"""
if server_url:
# Remote mode: call API
import httpx
try:
with httpx.Client(timeout=10.0) as client:
response = client.get(f"{server_url}/api/v1/skills")
response.raise_for_status()
skills = response.json()
except Exception as e:
rprint(f"[red]Error connecting to server: {e}[/red]")
raise typer.Exit(code=1)
else:
# Local mode: use SkillRegistry directly, loading from default configs/skills/
from agentkit.skills.loader import SkillLoader
from agentkit.skills.registry import SkillRegistry
from agentkit.tools.registry import ToolRegistry
registry = SkillRegistry()
# Load skills from the default configs/skills/ directory if it exists
default_skills_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "configs", "skills")
if os.path.isdir(default_skills_dir):
loader = SkillLoader(registry, ToolRegistry())
loader.load_from_directory(default_skills_dir)
skills = [
{
"name": s.name,
"agent_type": s.config.agent_type,
"version": s.config.version,
"description": s.config.description,
}
for s in registry.list_skills()
]
if not skills:
rprint("[dim]No skills registered[/dim]")
return
table = Table(title="Skills")
table.add_column("Name", style="cyan")
table.add_column("Type")
table.add_column("Description")
for s in skills:
table.add_row(
s.get("name", ""),
s.get("agent_type", ""),
s.get("description", ""),
)
rprint(table)
@skill_app.command("load")
def load_skill(
path: str = typer.Argument(help="Path to skill YAML file"),
):
"""Load a skill from YAML file"""
if not os.path.exists(path):
rprint(f"[red]Error: File not found: {path}[/red]")
raise typer.Exit(code=1)
try:
from agentkit.skills.loader import SkillLoader
from agentkit.skills.registry import SkillRegistry
from agentkit.tools.registry import ToolRegistry
registry = SkillRegistry()
loader = SkillLoader(registry, ToolRegistry())
skill = loader.load_from_file(path)
rprint(f"[green]Skill loaded:[/green] {skill.name}")
rprint(f" Description: {skill.config.description}")
rprint(f" Mode: {skill.config.task_mode}")
except Exception as e:
rprint(f"[red]Error loading skill: {e}[/red]")
raise typer.Exit(code=1)
@skill_app.command("create")
def skill_create(
name: str = typer.Argument(..., help="Skill name"),
output_dir: Optional[str] = typer.Option(".", "--output-dir", "-o", help="Output directory"),
):
"""Create a new SKILL.md template"""
template = f'''---
name: {name}
description: "Description of {name}"
agent_type: {name}
execution_mode: react
intent:
keywords: ["{name}"]
description: "Tasks related to {name}"
quality_gate:
required_fields: []
min_word_count: 0
---
# Trigger
- When to use this skill
# Steps
1. Step one
2. Step two
3. Step three
# Pitfalls
- Common mistakes to avoid
# Verification
- How to verify the output
'''
output_path = os.path.join(output_dir, f"{name}.md")
os.makedirs(output_dir, exist_ok=True)
with open(output_path, "w", encoding="utf-8") as f:
f.write(template)
rprint(f"[green]Created SKILL.md template:[/green] {output_path}")
@skill_app.command("info")
def skill_info(
name: str = typer.Argument(help="Skill name"),
server_url: Optional[str] = typer.Option(None, "--server-url", help="AgentKit server URL"),
):
"""Show skill details"""
if server_url:
import httpx
try:
with httpx.Client(timeout=10.0) as client:
response = client.get(f"{server_url}/api/v1/skills/{name}")
response.raise_for_status()
info = response.json()
except Exception as e:
rprint(f"[red]Error: {e}[/red]")
raise typer.Exit(code=1)
else:
from agentkit.skills.registry import SkillRegistry
registry = SkillRegistry()
try:
skill = registry.get(name)
info = {
"name": skill.name,
"agent_type": skill.config.agent_type,
"version": skill.config.version,
"description": skill.config.description,
"task_mode": skill.config.task_mode,
"execution_mode": skill.config.execution_mode,
}
except Exception as e:
rprint(f"[red]Skill '{name}' not found: {e}[/red]")
raise typer.Exit(code=1)
table = Table(title=f"Skill: {name}")
table.add_column("Field", style="cyan")
table.add_column("Value")
for key, value in info.items():
table.add_row(key, str(value))
rprint(table)