|
5 | 5 | import asyncio |
6 | 6 | import logging |
7 | 7 | import os |
8 | | -import re |
9 | 8 | import sys |
10 | 9 | import time |
11 | 10 | from concurrent.futures import ThreadPoolExecutor |
@@ -263,13 +262,6 @@ def _promote(frag: MemoryFragment) -> None: |
263 | 262 | return _promote |
264 | 263 |
|
265 | 264 |
|
266 | | -def sanitize_skill_name(title: str) -> str: |
267 | | - """Convert a skill title to a registry-safe name.""" |
268 | | - name = re.sub(r"[^\w\s-]", "", title.lower()) |
269 | | - name = re.sub(r"[\s]+", "-", name.strip()) |
270 | | - return name or "unnamed-skill" |
271 | | - |
272 | | - |
273 | 265 | def _make_stored_skill_fn(stored: "StoredSkill", llm: Any): |
274 | 266 | """Create an LLM-backed execution function from a StoredSkill.""" |
275 | 267 | steps_text = "\n".join(f" {i+1}. {step}" for i, step in enumerate(stored.steps)) |
@@ -310,14 +302,17 @@ def _register_stored_skill_fallbacks( |
310 | 302 | llm: Any, |
311 | 303 | ) -> int: |
312 | 304 | """Register StoredSkills that lack a parameterized or doc counterpart.""" |
| 305 | + from leapflow.learning.document import title_to_kebab |
313 | 306 | from leapflow.skills.registry import Skill, SkillMetadata |
314 | 307 |
|
315 | 308 | registered_names = set(registry.names()) if hasattr(registry, 'names') else {s.name for s in registry.list_all()} |
316 | 309 | stored = skill_lib.load_all_active() |
317 | 310 | count = 0 |
318 | 311 |
|
319 | 312 | for s in stored: |
320 | | - name = sanitize_skill_name(s.title) |
| 313 | + # Same naming function as the SKILL.md write paths, otherwise the |
| 314 | + # dedup below misses doc-backed skills and registers a duplicate. |
| 315 | + name = title_to_kebab(s.title) |
321 | 316 | if name in registered_names: |
322 | 317 | continue |
323 | 318 | if not s.trigger_phrases: |
@@ -1512,6 +1507,12 @@ async def _summarize_via_llm(prompt: str) -> str: |
1512 | 1507 | logger.debug("Shell approval gate: action orchestrator mode") |
1513 | 1508 | except Exception: |
1514 | 1509 | logger.debug("Shell approval gate setup skipped", exc_info=True) |
| 1510 | + try: |
| 1511 | + from leapflow.tools.registry_bootstrap import set_desktop_gate |
| 1512 | + set_desktop_gate(self._approval_orchestrator) |
| 1513 | + logger.debug("Desktop approval gate: action orchestrator mode") |
| 1514 | + except Exception: |
| 1515 | + logger.debug("Desktop approval gate setup skipped", exc_info=True) |
1515 | 1516 |
|
1516 | 1517 | self._critical_tool_bridge = tool_bridge |
1517 | 1518 |
|
|
0 commit comments