Add skill enable controls and data factory SQL skill

This commit is contained in:
武阳
2026-05-08 14:56:32 +08:00
parent 046b0eeab0
commit bd2f260b9f
16 changed files with 1167 additions and 25 deletions
+20 -5
View File
@@ -99,7 +99,7 @@ def build_system_prompt_parts(
get_doing_tasks_section(),
get_actions_section(),
get_using_your_tools_section(enabled_tool_names),
get_skill_guidance_section(prompt_context, enabled_tool_names),
get_skill_guidance_section(prompt_context, runtime_config, enabled_tool_names),
get_agent_guidance_section(enabled_tool_names, available_agents),
get_plugin_guidance_section(prompt_context),
get_mcp_guidance_section(prompt_context),
@@ -240,17 +240,32 @@ def get_using_your_tools_section(enabled_tool_names: set[str]) -> str:
def get_skill_guidance_section(
prompt_context: PromptContext,
runtime_config: AgentRuntimeConfig,
enabled_tool_names: set[str],
) -> str:
if 'Skill' not in enabled_tool_names:
return ''
skill_listing = format_skills_for_system_prompt(cwd=prompt_context.cwd)
skill_listing = format_skills_for_system_prompt(
cwd=prompt_context.cwd,
enabled_skill_names=runtime_config.enabled_skill_names,
)
enabled_skill_names = (
{
name.strip().lower()
for name in runtime_config.enabled_skill_names
if name.strip()
}
if runtime_config.enabled_skill_names is not None
else None
)
items = [
'当用户请求符合某个 skill 的适用范围时,优先调用 Skill 工具进入该 skill,不要先用 Agent 子任务或通用搜索绕路。',
'数据生成、标签边界、产品定义、示例 query 到数据集这类任务,优先使用 product-data skill。',
'线上 badcase 挖掘、router session 检索、候选转样本这类任务,优先使用 online-mining skill。',
'调用 skill 后遵守 skill 内部的人类 review 门禁和允许工具列表。',
]
if enabled_skill_names is None or 'product-data' in enabled_skill_names:
items.append('数据生成、标签边界、产品定义、示例 query 到数据集这类任务,优先使用 product-data skill。')
if enabled_skill_names is None or 'online-mining' in enabled_skill_names:
items.append('线上 badcase 挖掘、router session 检索、候选转样本这类任务,优先使用 online-mining skill。')
items.append('调用 skill 后遵守 skill 内部的人类 review 门禁和允许工具列表。')
return '\n'.join(['# Skills', *prepend_bullets(items), '', skill_listing])
+1
View File
@@ -171,6 +171,7 @@ class AgentRuntimeConfig:
session_directory: Path = field(default_factory=lambda: (Path('.port_sessions') / 'agent').resolve())
scratchpad_root: Path = field(default_factory=lambda: (Path('.port_sessions') / 'scratchpad').resolve())
python_env_dir: Path | None = None
enabled_skill_names: tuple[str, ...] | None = None
@dataclass(frozen=True)
+13
View File
@@ -20,6 +20,11 @@ if TYPE_CHECKING:
from .agent_runtime import LocalCodingAgent
ALWAYS_ENABLED_HIDDEN_SKILL_NAMES = frozenset(
{'update-config', 'verify', 'simplify', 'debug'}
)
@dataclass(frozen=True)
class BundledSkill:
"""A bundled skill definition."""
@@ -265,6 +270,7 @@ def find_bundled_skill(name: str, cwd: Path | str | None = None) -> BundledSkill
def format_skills_for_system_prompt(
max_chars: int = 8000,
cwd: Path | str | None = None,
enabled_skill_names: tuple[str, ...] | set[str] | None = None,
) -> str:
"""Format bundled skills for inclusion in system-reminder messages.
@@ -272,10 +278,17 @@ def format_skills_for_system_prompt(
"""
lines = ['Available skills (invoke via Skill tool):']
char_count = len(lines[0])
enabled_names = (
{name.strip().lower() for name in enabled_skill_names if name.strip()}
if enabled_skill_names is not None
else None
)
for skill in get_bundled_skills(cwd):
if not skill.user_invocable:
continue
if enabled_names is not None and skill.name.lower() not in enabled_names:
continue
entry = f'- {skill.name}: {skill.description}'
if skill.when_to_use:
entry += f' When to use: {skill.when_to_use}'
+16
View File
@@ -192,6 +192,11 @@ def serialize_runtime_config(runtime_config: AgentRuntimeConfig) -> JSONDict:
if runtime_config.python_env_dir is not None
else None
),
'enabled_skill_names': (
list(runtime_config.enabled_skill_names)
if runtime_config.enabled_skill_names is not None
else None
),
}
@@ -203,6 +208,16 @@ def deserialize_runtime_config(payload: JSONDict) -> AgentRuntimeConfig:
if not isinstance(budget_payload, dict):
budget_payload = {}
output_schema_payload = payload.get('output_schema')
enabled_skill_names_payload = payload.get('enabled_skill_names')
enabled_skill_names = (
tuple(
str(name)
for name in enabled_skill_names_payload
if str(name).strip()
)
if isinstance(enabled_skill_names_payload, list)
else None
)
return AgentRuntimeConfig(
cwd=Path(str(payload['cwd'])).resolve(),
max_turns=int(payload.get('max_turns', DEFAULT_MAX_TURNS)),
@@ -241,6 +256,7 @@ def deserialize_runtime_config(payload: JSONDict) -> AgentRuntimeConfig:
if payload.get('python_env_dir') is not None
else None
),
enabled_skill_names=enabled_skill_names,
)