Skip to content

Feat: Skills for Livekit Agents#5167

Closed
Nisarg38 wants to merge 14 commits intolivekit:longc/improve-toolsetsfrom
Nisarg38:feat/skills-system
Closed

Feat: Skills for Livekit Agents#5167
Nisarg38 wants to merge 14 commits intolivekit:longc/improve-toolsetsfrom
Nisarg38:feat/skills-system

Conversation

@Nisarg38
Copy link
Contributor

No description provided.

longcw and others added 14 commits March 18, 2026 21:16
…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>
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

View 6 additional findings in Devin Review.

Open in Devin Review

if inspect.isawaitable(results):
results = await results

return list({result.source for result in results})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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))
Suggested change
return list({result.source for result in results})
return list(dict.fromkeys(result.source for result in results))
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines 64 to +65
self._tools: Sequence[Tool | Toolset] = tools or []
self._tools.extend(find_function_tools(self))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Suggested change
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)]
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@longcw longcw deleted the branch livekit:longc/improve-toolsets March 23, 2026 14:46
@longcw longcw closed this Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants