mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-18 00:10:59 +00:00
fix(skill): remove auto activation setting
This commit is contained in:
@@ -21,7 +21,6 @@ _FRONTMATTER_FIELDS = (
|
|||||||
'name',
|
'name',
|
||||||
'display_name',
|
'display_name',
|
||||||
'description',
|
'description',
|
||||||
'auto_activate',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
_PUBLIC_SKILL_FIELDS = (
|
_PUBLIC_SKILL_FIELDS = (
|
||||||
@@ -30,7 +29,6 @@ _PUBLIC_SKILL_FIELDS = (
|
|||||||
'description',
|
'description',
|
||||||
'instructions',
|
'instructions',
|
||||||
'package_root',
|
'package_root',
|
||||||
'auto_activate',
|
|
||||||
'created_at',
|
'created_at',
|
||||||
'updated_at',
|
'updated_at',
|
||||||
)
|
)
|
||||||
@@ -51,8 +49,6 @@ def _build_skill_md(metadata: dict, instructions: str) -> str:
|
|||||||
value = metadata.get(key)
|
value = metadata.get(key)
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
if key == 'auto_activate' and value is True:
|
|
||||||
continue
|
|
||||||
if isinstance(value, str) and not value.strip():
|
if isinstance(value, str) and not value.strip():
|
||||||
continue
|
continue
|
||||||
frontmatter[key] = value
|
frontmatter[key] = value
|
||||||
@@ -118,7 +114,6 @@ class SkillService:
|
|||||||
'name': name,
|
'name': name,
|
||||||
'display_name': self._resolve_create_field(data, 'display_name', imported_skill_data, default=''),
|
'display_name': self._resolve_create_field(data, 'display_name', imported_skill_data, default=''),
|
||||||
'description': self._resolve_create_field(data, 'description', imported_skill_data, default=''),
|
'description': self._resolve_create_field(data, 'description', imported_skill_data, default=''),
|
||||||
'auto_activate': self._resolve_create_bool(data, 'auto_activate', imported_skill_data, default=True),
|
|
||||||
}
|
}
|
||||||
instructions = self._resolve_create_field(data, 'instructions', imported_skill_data, default='')
|
instructions = self._resolve_create_field(data, 'instructions', imported_skill_data, default='')
|
||||||
self._write_skill_md(target_root, metadata, instructions)
|
self._write_skill_md(target_root, metadata, instructions)
|
||||||
@@ -147,7 +142,6 @@ class SkillService:
|
|||||||
'name': skill['name'],
|
'name': skill['name'],
|
||||||
'display_name': data.get('display_name', skill.get('display_name', '')),
|
'display_name': data.get('display_name', skill.get('display_name', '')),
|
||||||
'description': data.get('description', skill.get('description', '')),
|
'description': data.get('description', skill.get('description', '')),
|
||||||
'auto_activate': data.get('auto_activate', skill.get('auto_activate', True)),
|
|
||||||
}
|
}
|
||||||
instructions = str(data.get('instructions', skill.get('instructions', '')) or '')
|
instructions = str(data.get('instructions', skill.get('instructions', '')) or '')
|
||||||
self._write_skill_md(skill['package_root'], metadata, instructions)
|
self._write_skill_md(skill['package_root'], metadata, instructions)
|
||||||
@@ -372,7 +366,6 @@ class SkillService:
|
|||||||
'display_name': str(metadata.get('display_name') or '').strip(),
|
'display_name': str(metadata.get('display_name') or '').strip(),
|
||||||
'description': str(metadata.get('description') or '').strip(),
|
'description': str(metadata.get('description') or '').strip(),
|
||||||
'instructions': instructions,
|
'instructions': instructions,
|
||||||
'auto_activate': bool(metadata.get('auto_activate', True)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async def _reload_skills(self) -> None:
|
async def _reload_skills(self) -> None:
|
||||||
@@ -400,7 +393,6 @@ class SkillService:
|
|||||||
'display_name': str(metadata.get('display_name') or '').strip(),
|
'display_name': str(metadata.get('display_name') or '').strip(),
|
||||||
'description': str(metadata.get('description') or '').strip(),
|
'description': str(metadata.get('description') or '').strip(),
|
||||||
'instructions': instructions,
|
'instructions': instructions,
|
||||||
'auto_activate': bool(metadata.get('auto_activate', True)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async def _download_github_skill_to_temp(self, asset_url: str, tmp_dir: str) -> str:
|
async def _download_github_skill_to_temp(self, asset_url: str, tmp_dir: str) -> str:
|
||||||
@@ -488,7 +480,6 @@ class SkillService:
|
|||||||
'display_name': str(metadata.get('display_name') or '').strip(),
|
'display_name': str(metadata.get('display_name') or '').strip(),
|
||||||
'description': str(metadata.get('description') or '').strip(),
|
'description': str(metadata.get('description') or '').strip(),
|
||||||
'instructions': instructions,
|
'instructions': instructions,
|
||||||
'auto_activate': bool(metadata.get('auto_activate', True)),
|
|
||||||
'package_root': self._build_preview_target_dir(base_target_name, relative_path, suffix),
|
'package_root': self._build_preview_target_dir(base_target_name, relative_path, suffix),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -626,14 +617,6 @@ class SkillService:
|
|||||||
return str(imported_skill_data.get(field, default) or default)
|
return str(imported_skill_data.get(field, default) or default)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _resolve_create_bool(data: dict, field: str, imported_skill_data: dict | None, *, default: bool) -> bool:
|
|
||||||
if field in data and data[field] is not None:
|
|
||||||
return bool(data[field])
|
|
||||||
if imported_skill_data is not None:
|
|
||||||
return bool(imported_skill_data.get(field, default))
|
|
||||||
return default
|
|
||||||
|
|
||||||
def _write_skill_md(self, package_root: str, metadata: dict, instructions: str) -> None:
|
def _write_skill_md(self, package_root: str, metadata: dict, instructions: str) -> None:
|
||||||
package_root = self._normalize_package_root(package_root)
|
package_root = self._normalize_package_root(package_root)
|
||||||
os.makedirs(package_root, exist_ok=True)
|
os.makedirs(package_root, exist_ok=True)
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ class PreProcessor(stage.PipelineStage):
|
|||||||
f'Skill index injected into system prompt: '
|
f'Skill index injected into system prompt: '
|
||||||
f'pipeline={query.pipeline_uuid} '
|
f'pipeline={query.pipeline_uuid} '
|
||||||
f'bound_skills={bound_skills or "all"} '
|
f'bound_skills={bound_skills or "all"} '
|
||||||
f'available_skills=[{", ".join(s["name"] for s in self.ap.skill_mgr.skills.values() if s.get("auto_activate", True))}]'
|
f'available_skills=[{", ".join(s["name"] for s in self.ap.skill_mgr.skills.values() if bound_skills is None or s["name"] in bound_skills)}]'
|
||||||
)
|
)
|
||||||
# Append skill instruction to the first system message
|
# Append skill instruction to the first system message
|
||||||
if query.prompt.messages and query.prompt.messages[0].role == 'system':
|
if query.prompt.messages and query.prompt.messages[0].role == 'system':
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ class SkillAuthoringToolLoader(loader.ToolLoader):
|
|||||||
'display_name': str(parameters.get('display_name', '') or '').strip(),
|
'display_name': str(parameters.get('display_name', '') or '').strip(),
|
||||||
'description': str(parameters.get('description', '') or '').strip(),
|
'description': str(parameters.get('description', '') or '').strip(),
|
||||||
'instructions': instructions,
|
'instructions': instructions,
|
||||||
'auto_activate': parameters.get('auto_activate', True),
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
@@ -137,7 +136,7 @@ class SkillAuthoringToolLoader(loader.ToolLoader):
|
|||||||
raise ValueError('name is required')
|
raise ValueError('name is required')
|
||||||
|
|
||||||
data = {'name': name}
|
data = {'name': name}
|
||||||
for field in ('display_name', 'description', 'instructions', 'auto_activate'):
|
for field in ('display_name', 'description', 'instructions'):
|
||||||
if field in parameters:
|
if field in parameters:
|
||||||
data[field] = parameters[field]
|
data[field] = parameters[field]
|
||||||
|
|
||||||
@@ -172,7 +171,6 @@ class SkillAuthoringToolLoader(loader.ToolLoader):
|
|||||||
'description': str(parameters.get('description') or scanned.get('description', '')).strip(),
|
'description': str(parameters.get('description') or scanned.get('description', '')).strip(),
|
||||||
'instructions': str(parameters.get('instructions') or scanned.get('instructions', '')),
|
'instructions': str(parameters.get('instructions') or scanned.get('instructions', '')),
|
||||||
'package_root': host_path,
|
'package_root': host_path,
|
||||||
'auto_activate': parameters.get('auto_activate', scanned.get('auto_activate', True)),
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
@@ -228,10 +226,6 @@ class SkillAuthoringToolLoader(loader.ToolLoader):
|
|||||||
'type': 'string',
|
'type': 'string',
|
||||||
'description': 'The SKILL.md body instructions for the new skill.',
|
'description': 'The SKILL.md body instructions for the new skill.',
|
||||||
},
|
},
|
||||||
'auto_activate': {
|
|
||||||
'type': 'boolean',
|
|
||||||
'description': 'Whether the skill should be considered for automatic activation. Defaults to true.',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
'required': ['name', 'instructions'],
|
'required': ['name', 'instructions'],
|
||||||
'additionalProperties': False,
|
'additionalProperties': False,
|
||||||
@@ -299,10 +293,6 @@ class SkillAuthoringToolLoader(loader.ToolLoader):
|
|||||||
'type': 'string',
|
'type': 'string',
|
||||||
'description': 'Optional replacement SKILL.md body instructions.',
|
'description': 'Optional replacement SKILL.md body instructions.',
|
||||||
},
|
},
|
||||||
'auto_activate': {
|
|
||||||
'type': 'boolean',
|
|
||||||
'description': 'Optional new auto_activate value.',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
'required': ['name'],
|
'required': ['name'],
|
||||||
'additionalProperties': False,
|
'additionalProperties': False,
|
||||||
@@ -363,10 +353,6 @@ class SkillAuthoringToolLoader(loader.ToolLoader):
|
|||||||
'type': 'string',
|
'type': 'string',
|
||||||
'description': 'Optional instructions override.',
|
'description': 'Optional instructions override.',
|
||||||
},
|
},
|
||||||
'auto_activate': {
|
|
||||||
'type': 'boolean',
|
|
||||||
'description': 'Optional auto_activate override.',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
'required': ['path'],
|
'required': ['path'],
|
||||||
'additionalProperties': False,
|
'additionalProperties': False,
|
||||||
|
|||||||
@@ -119,7 +119,12 @@ def prepare_skill_activation(
|
|||||||
if not response_content or not getattr(ap, 'skill_mgr', None):
|
if not response_content or not getattr(ap, 'skill_mgr', None):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
activated_skill_names = ap.skill_mgr.detect_skill_activations(response_content)
|
visible_skills = skill_loader.get_visible_skills(ap, query)
|
||||||
|
activated_skill_names = [
|
||||||
|
skill_name
|
||||||
|
for skill_name in ap.skill_mgr.detect_skill_activations(response_content)
|
||||||
|
if skill_name in visible_skills
|
||||||
|
]
|
||||||
if not activated_skill_names:
|
if not activated_skill_names:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -135,7 +135,6 @@ class SkillManager:
|
|||||||
'raw_content': content,
|
'raw_content': content,
|
||||||
'package_root': package_root,
|
'package_root': package_root,
|
||||||
'entry_file': entry_file,
|
'entry_file': entry_file,
|
||||||
'auto_activate': bool(metadata.get('auto_activate', True)),
|
|
||||||
'created_at': dt.datetime.fromtimestamp(stat.st_ctime, tz=dt.timezone.utc).isoformat(),
|
'created_at': dt.datetime.fromtimestamp(stat.st_ctime, tz=dt.timezone.utc).isoformat(),
|
||||||
'updated_at': dt.datetime.fromtimestamp(stat.st_mtime, tz=dt.timezone.utc).isoformat(),
|
'updated_at': dt.datetime.fromtimestamp(stat.st_mtime, tz=dt.timezone.utc).isoformat(),
|
||||||
}
|
}
|
||||||
@@ -154,8 +153,6 @@ class SkillManager:
|
|||||||
def get_skill_index(self, pipeline_uuid: str | None = None, bound_skills: list[str] | None = None) -> str:
|
def get_skill_index(self, pipeline_uuid: str | None = None, bound_skills: list[str] | None = None) -> str:
|
||||||
skills_to_index = []
|
skills_to_index = []
|
||||||
for skill in self.skills.values():
|
for skill in self.skills.values():
|
||||||
if not skill.get('auto_activate', True):
|
|
||||||
continue
|
|
||||||
if bound_skills is not None and skill['name'] not in bound_skills:
|
if bound_skills is not None and skill['name'] not in bound_skills:
|
||||||
continue
|
continue
|
||||||
skills_to_index.append(skill)
|
skills_to_index.append(skill)
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ def _make_skill_data(
|
|||||||
instructions='Do something',
|
instructions='Do something',
|
||||||
package_root='',
|
package_root='',
|
||||||
entry_file='SKILL.md',
|
entry_file='SKILL.md',
|
||||||
auto_activate=True,
|
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
return {
|
return {
|
||||||
@@ -32,7 +31,6 @@ def _make_skill_data(
|
|||||||
'instructions': instructions,
|
'instructions': instructions,
|
||||||
'package_root': package_root,
|
'package_root': package_root,
|
||||||
'entry_file': entry_file,
|
'entry_file': entry_file,
|
||||||
'auto_activate': auto_activate,
|
|
||||||
**kwargs,
|
**kwargs,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +148,30 @@ class TestSkillActivationHelper:
|
|||||||
assert activation.cleaned_content == 'Working on it.'
|
assert activation.cleaned_content == 'Working on it.'
|
||||||
assert set(query.variables[ACTIVATED_SKILLS_KEY].keys()) == {'primary', 'aux'}
|
assert set(query.variables[ACTIVATED_SKILLS_KEY].keys()) == {'primary', 'aux'}
|
||||||
|
|
||||||
|
def test_prepare_skill_activation_ignores_skills_not_bound_to_pipeline(self):
|
||||||
|
from langbot.pkg.skill.activation import prepare_skill_activation
|
||||||
|
from langbot.pkg.provider.tools.loaders.skill import ACTIVATED_SKILLS_KEY, PIPELINE_BOUND_SKILLS_KEY
|
||||||
|
from langbot.pkg.skill.manager import SkillManager
|
||||||
|
|
||||||
|
ap = _make_ap()
|
||||||
|
mgr = SkillManager(ap)
|
||||||
|
mgr.skills = {
|
||||||
|
'primary': _make_skill_data(name='primary', instructions='Primary instructions'),
|
||||||
|
'hidden': _make_skill_data(name='hidden', instructions='Hidden instructions'),
|
||||||
|
}
|
||||||
|
ap.skill_mgr = mgr
|
||||||
|
|
||||||
|
query = SimpleNamespace(variables={PIPELINE_BOUND_SKILLS_KEY: ['primary']}, use_funcs=[])
|
||||||
|
activation = prepare_skill_activation(
|
||||||
|
ap,
|
||||||
|
query,
|
||||||
|
'[ACTIVATE_SKILL: hidden]\n[ACTIVATE_SKILL: primary]\nWorking on it.',
|
||||||
|
)
|
||||||
|
|
||||||
|
assert activation is not None
|
||||||
|
assert activation.activated_skill_names == ['primary']
|
||||||
|
assert set(query.variables[ACTIVATED_SKILLS_KEY].keys()) == {'primary'}
|
||||||
|
|
||||||
|
|
||||||
class TestSkillPathHelpers:
|
class TestSkillPathHelpers:
|
||||||
def test_get_visible_skills_filters_by_bound_names(self):
|
def test_get_visible_skills_filters_by_bound_names(self):
|
||||||
@@ -252,7 +274,6 @@ class TestSkillAuthoringToolLoader:
|
|||||||
'display_name': 'Prompt Skill',
|
'display_name': 'Prompt Skill',
|
||||||
'description': 'Prompt only skill',
|
'description': 'Prompt only skill',
|
||||||
'instructions': 'Follow these steps carefully.',
|
'instructions': 'Follow these steps carefully.',
|
||||||
'auto_activate': False,
|
|
||||||
},
|
},
|
||||||
SimpleNamespace(),
|
SimpleNamespace(),
|
||||||
)
|
)
|
||||||
@@ -263,7 +284,6 @@ class TestSkillAuthoringToolLoader:
|
|||||||
'display_name': 'Prompt Skill',
|
'display_name': 'Prompt Skill',
|
||||||
'description': 'Prompt only skill',
|
'description': 'Prompt only skill',
|
||||||
'instructions': 'Follow these steps carefully.',
|
'instructions': 'Follow these steps carefully.',
|
||||||
'auto_activate': False,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
assert result == {
|
assert result == {
|
||||||
@@ -342,7 +362,6 @@ class TestSkillAuthoringToolLoader:
|
|||||||
'name': 'time-now',
|
'name': 'time-now',
|
||||||
'description': 'Fixed to Beijing time',
|
'description': 'Fixed to Beijing time',
|
||||||
'instructions': 'Always use Asia/Shanghai and never offer other timezones.',
|
'instructions': 'Always use Asia/Shanghai and never offer other timezones.',
|
||||||
'auto_activate': True,
|
|
||||||
},
|
},
|
||||||
SimpleNamespace(),
|
SimpleNamespace(),
|
||||||
)
|
)
|
||||||
@@ -353,7 +372,6 @@ class TestSkillAuthoringToolLoader:
|
|||||||
'name': 'time-now',
|
'name': 'time-now',
|
||||||
'description': 'Fixed to Beijing time',
|
'description': 'Fixed to Beijing time',
|
||||||
'instructions': 'Always use Asia/Shanghai and never offer other timezones.',
|
'instructions': 'Always use Asia/Shanghai and never offer other timezones.',
|
||||||
'auto_activate': True,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
assert result == {
|
assert result == {
|
||||||
@@ -400,7 +418,6 @@ class TestSkillAuthoringToolLoader:
|
|||||||
'display_name': 'Cloned Skill',
|
'display_name': 'Cloned Skill',
|
||||||
'description': 'Imported from clone',
|
'description': 'Imported from clone',
|
||||||
'instructions': 'Do work',
|
'instructions': 'Do work',
|
||||||
'auto_activate': True,
|
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
create_skill=AsyncMock(return_value=_make_skill_data(name='cloned-skill', package_root='/repo/root')),
|
create_skill=AsyncMock(return_value=_make_skill_data(name='cloned-skill', package_root='/repo/root')),
|
||||||
@@ -430,7 +447,6 @@ class TestSkillAuthoringToolLoader:
|
|||||||
'description': 'Imported from clone',
|
'description': 'Imported from clone',
|
||||||
'instructions': 'Do work',
|
'instructions': 'Do work',
|
||||||
'package_root': os.path.realpath(repo_dir),
|
'package_root': os.path.realpath(repo_dir),
|
||||||
'auto_activate': True,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
assert result['imported'] is True
|
assert result['imported'] is True
|
||||||
|
|||||||
@@ -15,14 +15,11 @@ def _create_skill_file(
|
|||||||
name: str = 'imported-skill',
|
name: str = 'imported-skill',
|
||||||
display_name: str = '',
|
display_name: str = '',
|
||||||
description: str = 'Imported from local directory',
|
description: str = 'Imported from local directory',
|
||||||
auto_activate: bool = True,
|
|
||||||
body: str = 'Skill instructions',
|
body: str = 'Skill instructions',
|
||||||
) -> None:
|
) -> None:
|
||||||
frontmatter = ['name: ' + name, 'description: ' + description]
|
frontmatter = ['name: ' + name, 'description: ' + description]
|
||||||
if display_name:
|
if display_name:
|
||||||
frontmatter.insert(1, 'display_name: ' + display_name)
|
frontmatter.insert(1, 'display_name: ' + display_name)
|
||||||
if not auto_activate:
|
|
||||||
frontmatter.append('auto_activate: false')
|
|
||||||
|
|
||||||
path.write_text(
|
path.write_text(
|
||||||
'---\n' + '\n'.join(frontmatter) + f'\n---\n\n{body}\n',
|
'---\n' + '\n'.join(frontmatter) + f'\n---\n\n{body}\n',
|
||||||
@@ -83,7 +80,6 @@ async def test_create_skill_import_preserves_existing_skill_content_when_form_fi
|
|||||||
source_dir / 'SKILL.md',
|
source_dir / 'SKILL.md',
|
||||||
display_name='Imported Skill',
|
display_name='Imported Skill',
|
||||||
description='Imported description',
|
description='Imported description',
|
||||||
auto_activate=False,
|
|
||||||
body='Original instructions',
|
body='Original instructions',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -96,7 +92,6 @@ async def test_create_skill_import_preserves_existing_skill_content_when_form_fi
|
|||||||
'package_root': str(managed_root.resolve()),
|
'package_root': str(managed_root.resolve()),
|
||||||
'description': 'Imported description',
|
'description': 'Imported description',
|
||||||
'instructions': 'Original instructions',
|
'instructions': 'Original instructions',
|
||||||
'auto_activate': False,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -115,7 +110,6 @@ async def test_create_skill_import_preserves_existing_skill_content_when_form_fi
|
|||||||
content = (managed_root / 'SKILL.md').read_text(encoding='utf-8')
|
content = (managed_root / 'SKILL.md').read_text(encoding='utf-8')
|
||||||
assert 'display_name: Imported Skill' in content
|
assert 'display_name: Imported Skill' in content
|
||||||
assert 'description: Imported description' in content
|
assert 'description: Imported description' in content
|
||||||
assert 'auto_activate: false' in content
|
|
||||||
assert content.endswith('Original instructions')
|
assert content.endswith('Original instructions')
|
||||||
|
|
||||||
|
|
||||||
@@ -139,7 +133,6 @@ async def test_create_skill_reuses_existing_managed_directory_without_copying(tm
|
|||||||
'package_root': str(managed_root.resolve()),
|
'package_root': str(managed_root.resolve()),
|
||||||
'description': 'Already managed',
|
'description': 'Already managed',
|
||||||
'instructions': 'Managed instructions',
|
'instructions': 'Managed instructions',
|
||||||
'auto_activate': True,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -167,11 +160,7 @@ def _build_skill_archive() -> bytes:
|
|||||||
with zipfile.ZipFile(stream, 'w') as archive:
|
with zipfile.ZipFile(stream, 'w') as archive:
|
||||||
archive.writestr(
|
archive.writestr(
|
||||||
'demo-repo-main/skills/nested-skill/SKILL.md',
|
'demo-repo-main/skills/nested-skill/SKILL.md',
|
||||||
'---\n'
|
'---\nname: imported-skill\ndescription: Imported from GitHub archive\n---\n\nSkill instructions\n',
|
||||||
'name: imported-skill\n'
|
|
||||||
'description: Imported from GitHub archive\n'
|
|
||||||
'---\n\n'
|
|
||||||
'Skill instructions\n',
|
|
||||||
)
|
)
|
||||||
return stream.getvalue()
|
return stream.getvalue()
|
||||||
|
|
||||||
@@ -336,7 +325,6 @@ async def test_update_skill_rejects_package_root_change(tmp_path):
|
|||||||
'display_name': 'Writer',
|
'display_name': 'Writer',
|
||||||
'description': 'Writes things',
|
'description': 'Writes things',
|
||||||
'instructions': 'Do work',
|
'instructions': 'Do work',
|
||||||
'auto_activate': True,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { Label } from '@/components/ui/label';
|
import { Label } from '@/components/ui/label';
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
import { Switch } from '@/components/ui/switch';
|
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { FolderSearch, ChevronDown, ChevronRight } from 'lucide-react';
|
import { FolderSearch, ChevronDown, ChevronRight } from 'lucide-react';
|
||||||
import { httpClient } from '@/app/infra/http/HttpClient';
|
import { httpClient } from '@/app/infra/http/HttpClient';
|
||||||
@@ -30,7 +29,6 @@ const emptySkillDraft: SkillFormDraft = {
|
|||||||
description: '',
|
description: '',
|
||||||
instructions: '',
|
instructions: '',
|
||||||
package_root: '',
|
package_root: '',
|
||||||
auto_activate: true,
|
|
||||||
},
|
},
|
||||||
showAdvanced: false,
|
showAdvanced: false,
|
||||||
};
|
};
|
||||||
@@ -95,7 +93,6 @@ export default function SkillForm({
|
|||||||
description: prev.description || result.description,
|
description: prev.description || result.description,
|
||||||
package_root: result.package_root,
|
package_root: result.package_root,
|
||||||
instructions: result.instructions,
|
instructions: result.instructions,
|
||||||
auto_activate: result.auto_activate ?? true,
|
|
||||||
}));
|
}));
|
||||||
toast.success(t('skills.scanSuccess'));
|
toast.success(t('skills.scanSuccess'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -123,7 +120,6 @@ export default function SkillForm({
|
|||||||
display_name: skill.display_name || '',
|
display_name: skill.display_name || '',
|
||||||
description: skill.description || '',
|
description: skill.description || '',
|
||||||
instructions: skill.instructions || '',
|
instructions: skill.instructions || '',
|
||||||
auto_activate: skill.auto_activate ?? true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -203,23 +199,6 @@ export default function SkillForm({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-start justify-between gap-4">
|
|
||||||
<div className="space-y-1">
|
|
||||||
<Label htmlFor="auto_activate">{t('skills.autoActivate')}</Label>
|
|
||||||
<p className="text-xs leading-relaxed text-muted-foreground">
|
|
||||||
{t('skills.autoActivateDescription')}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<Switch
|
|
||||||
id="auto_activate"
|
|
||||||
className="mt-0.5"
|
|
||||||
checked={skill.auto_activate ?? true}
|
|
||||||
onCheckedChange={(checked) =>
|
|
||||||
setSkill({ ...skill, auto_activate: checked })
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -590,7 +590,6 @@ export interface Skill {
|
|||||||
description: string;
|
description: string;
|
||||||
instructions?: string;
|
instructions?: string;
|
||||||
package_root?: string;
|
package_root?: string;
|
||||||
auto_activate?: boolean;
|
|
||||||
is_builtin?: boolean;
|
is_builtin?: boolean;
|
||||||
created_at?: string;
|
created_at?: string;
|
||||||
updated_at?: string;
|
updated_at?: string;
|
||||||
|
|||||||
@@ -1269,7 +1269,6 @@ export class BackendClient extends BaseHttpClient {
|
|||||||
display_name?: string;
|
display_name?: string;
|
||||||
description: string;
|
description: string;
|
||||||
instructions: string;
|
instructions: string;
|
||||||
auto_activate?: boolean;
|
|
||||||
}> {
|
}> {
|
||||||
return this.get('/api/v1/skills/scan', { path });
|
return this.get('/api/v1/skills/scan', { path });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1346,9 +1346,6 @@ const enUS = {
|
|||||||
'Used as the skill directory name. Only letters, numbers, hyphens and underscores.',
|
'Used as the skill directory name. Only letters, numbers, hyphens and underscores.',
|
||||||
skillDescription: 'Skill Description',
|
skillDescription: 'Skill Description',
|
||||||
skillInstructions: 'Instructions',
|
skillInstructions: 'Instructions',
|
||||||
autoActivate: 'Auto Activate',
|
|
||||||
autoActivateDescription:
|
|
||||||
'When enabled, the Agent may match and activate this skill based on its description during conversations.',
|
|
||||||
saveSuccess: 'Saved successfully',
|
saveSuccess: 'Saved successfully',
|
||||||
saveError: 'Save failed: ',
|
saveError: 'Save failed: ',
|
||||||
createSuccess: 'Created successfully',
|
createSuccess: 'Created successfully',
|
||||||
|
|||||||
@@ -1290,9 +1290,6 @@ const zhHans = {
|
|||||||
skillSlugHelp: '用作技能目录名,仅支持英文字母、数字、连字符和下划线。',
|
skillSlugHelp: '用作技能目录名,仅支持英文字母、数字、连字符和下划线。',
|
||||||
skillDescription: '技能描述',
|
skillDescription: '技能描述',
|
||||||
skillInstructions: '指令内容',
|
skillInstructions: '指令内容',
|
||||||
autoActivate: '自动激活',
|
|
||||||
autoActivateDescription:
|
|
||||||
'开启后,Agent 会在对话中根据技能描述自动匹配并激活此技能。',
|
|
||||||
saveSuccess: '保存成功',
|
saveSuccess: '保存成功',
|
||||||
saveError: '保存失败:',
|
saveError: '保存失败:',
|
||||||
createSuccess: '创建成功',
|
createSuccess: '创建成功',
|
||||||
|
|||||||
@@ -1360,9 +1360,6 @@ const zhHant = {
|
|||||||
skillSlugHelp: '用作技能目錄名,僅支援英文字母、數字、連字符和底線。',
|
skillSlugHelp: '用作技能目錄名,僅支援英文字母、數字、連字符和底線。',
|
||||||
skillDescription: '技能描述',
|
skillDescription: '技能描述',
|
||||||
skillInstructions: '指令內容',
|
skillInstructions: '指令內容',
|
||||||
autoActivate: '自動啟用',
|
|
||||||
autoActivateDescription:
|
|
||||||
'開啟後,Agent 會在對話中根據技能描述自動匹配並啟用此技能。',
|
|
||||||
saveSuccess: '儲存成功',
|
saveSuccess: '儲存成功',
|
||||||
saveError: '儲存失敗:',
|
saveError: '儲存失敗:',
|
||||||
createSuccess: '創建成功',
|
createSuccess: '創建成功',
|
||||||
|
|||||||
Reference in New Issue
Block a user