Feat: Skills for Livekit Agents#5167
Feat: Skills for Livekit Agents#5167Nisarg38 wants to merge 14 commits intolivekit:longc/improve-toolsetsfrom
Conversation
…ption Introduces `beta/skills/` module with a `Skill` class that bundles instructions with function tools. Supports explicit tools via constructor and auto-discovery of @function_tool methods on subclasses. Includes 9 tests covering creation, repr, subclassing, and read-only properties. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Implement registry.py with register/unregister/get/from_directory and loader.py that parses skill.md frontmatter with optional tools.py import. Tests cover all registry operations and loader edge cases. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… activation SkillSelector provides search-driven skill discovery with instruction hot-swapping. Supports replacement mode (default) and accumulate mode with configurable max_active_skills and eviction. Includes on_change callback and inline instruction delivery in search results. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Widen Skill.tools param to list[Tool | Toolset] to match Toolset base class. Fix list invariance in loader.py. Move imports to top of test file. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Demonstrates search-driven skill discovery with weather and calendar skills loaded from skill.md + tools.py directories. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| if inspect.isawaitable(results): | ||
| results = await results | ||
|
|
||
| return list({result.source for result in results}) |
There was a problem hiding this comment.
🟡 Set-based deduplication in _search_tools loses relevance ordering of search results
In _search_tools, the deduplication list({result.source for result in results}) uses a set comprehension, which does not preserve insertion order in Python. The search strategy returns results ordered by relevance score (highest first), but converting to a set and back to a list produces a nondeterministic order.
This directly affects SkillSelector._handle_search (livekit-agents/livekit/agents/beta/skills/skill_selector.py:86-93) where max_active_skills is set: the order of matched_skills determines which skills are appended to _active_skills and consequently which skills are evicted. With nondeterministic ordering from the set, eviction behavior becomes unpredictable.
Fix: use dict.fromkeys to preserve order
Replace list({result.source for result in results}) with order-preserving deduplication:
return list(dict.fromkeys(result.source for result in results))| return list({result.source for result in results}) | |
| return list(dict.fromkeys(result.source for result in results)) |
Was this helpful? React with 👍 or 👎 to provide feedback.
| self._tools: Sequence[Tool | Toolset] = tools or [] | ||
| self._tools.extend(find_function_tools(self)) |
There was a problem hiding this comment.
🟡 Toolset.__init__ mutates the caller's tools list via extend()
When tools is a non-empty list, tools or [] returns the same list reference (not a copy). The subsequent self._tools.extend(find_function_tools(self)) mutates the caller's original list. This is inconsistent with the pattern used in Agent.__init__ (livekit-agents/livekit/agents/voice/agent.py:62) which creates a new list: self._tools = [*tools, *find_function_tools(self)].
This is hazardous for SkillSelector.__init__ (livekit-agents/livekit/agents/beta/skills/skill_selector.py:50-60) which stores the same skill_list reference as both self._skill_list and passes it to super().__init__(tools=skill_list). If a user subclasses SkillSelector and adds @function_tool methods, find_function_tools(self) would append to _skill_list unexpectedly, corrupting the skill list used for source resolution.
| self._tools: Sequence[Tool | Toolset] = tools or [] | |
| self._tools.extend(find_function_tools(self)) | |
| self._tools: Sequence[Tool | Toolset] = [*(tools or []), *find_function_tools(self)] |
Was this helpful? React with 👍 or 👎 to provide feedback.
No description provided.