Python: [BREAKING] Refactor FileSkillsSource for depth-based discovery and predicate filters#6488
Conversation
…y and predicate filters Refactors FileSkillsSource to make script and resource discovery more flexible. ## Changes - **Drops** resource_directories / script_directories options (preconfigured directory whitelists). - **Adds** search_depth option (>= 1, default 2): controls how deep the recursive scan goes within each skill directory. - **Adds** script_filter / resource_filter predicate options that receive a FileSkillFilterContext (skill_name + relative_file_path), allowing whitelist/blacklist filtering by file path. - **Adds** FileSkillFilterContext class exported from agent_framework. ## Notes - The Skills API is marked @experimental -- the option removals are intentional breaking changes within the experimental surface. - Security checks (path containment, symlink detection) are preserved and continue to use the skill root directory as the trusted boundary. - Ports the same refactoring from .NET PR microsoft#6109 while following Python conventions (instance methods, Callable type hints, __slots__). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Python Test Coverage Report •
Python Unit Test Overview
|
|||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Pull request overview
Refactors Python file-based skill discovery to match the newer .NET behavior by replacing fixed subdirectory whitelists with depth-based recursive scanning and optional predicate filters, while keeping existing containment/symlink safety checks.
Changes:
- Replace
resource_directories/script_directorieswithsearch_depth(default2) for recursive discovery within each skill directory. - Add
script_filter/resource_filterpredicates using the new exportedFileSkillFilterContextto allow per-file inclusion/exclusion decisions. - Rewrite/extend unit tests to validate depth behavior, filtering, and existing safety guarantees (path traversal + symlink skipping).
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| python/packages/core/tests/core/test_skills.py | Updates tests to validate depth-based discovery and filter predicate behavior. |
| python/packages/core/agent_framework/_tools.py | Minor refactor in approval-request state handling (no functional change intended). |
| python/packages/core/agent_framework/_skills.py | Implements search_depth + predicate filters for FileSkillsSource, adds FileSkillFilterContext, updates SkillsProvider.from_paths() surface. |
| python/packages/core/agent_framework/init.py | Exports FileSkillFilterContext from the public package surface. |
There was a problem hiding this comment.
Automated Code Review
Reviewers: 5 | Confidence: 89%
✓ Correctness
The refactoring from directory-whitelist to depth-based scanning with filter predicates is well-implemented and correct. The depth logic correctly maps search_depth=1 to root-only, search_depth=2 to root+one-level, etc. Security checks (path containment, symlink detection) are preserved at all recursion levels. Filter predicates are applied after security checks, and the FileSkillFilterContext validation is sound. The from_paths factory method correctly forwards new parameters. No correctness bugs found.
✓ Security Reliability
The refactoring correctly preserves all security invariants (path containment, symlink detection at both directory and file levels). The depth-based recursion applies directory-level security checks before descending and file-level checks before including any resource. One minor reliability concern: unhandled exceptions from user-provided filter predicates would crash the entire skill discovery process rather than gracefully skipping the affected file.
✓ Test Coverage
Test coverage for the refactored FileSkillsSource is generally strong. Depth-based discovery is well-tested for resources at both unit and integration levels. Filter predicates are tested for both resources and scripts. However, there's an asymmetry:
resource_filterhas a dedicated context-verification test (test_resource_filter_receives_correct_context) confirming thatskill_nameandrelative_file_pathare passed correctly, butscript_filterlacks an equivalent test. Similarly,from_pathshas a passthrough test forresource_filterandsearch_depthbut not forscript_filter. These are low-severity gaps since the code paths are structurally identical.
✓ Failure Modes
The refactoring from directory-whitelists to depth-based recursive scanning is well-implemented from a failure-mode perspective. Error handling for OS-level failures (iterdir OSError), security checks (symlinks, path traversal), and input validation (search_depth >= 1) are all preserved or improved. User-provided filter predicates follow standard Python fail-fast callback semantics. No silent failures, lost errors, or partial-write scenarios were identified.
✗ Design Approach
The refactor mostly hangs together, but the new recursive file discovery no longer preserves skill boundaries when one skill directory contains another nested skill directory. Because nested
SKILL.mdfolders are still discovered as separate skills elsewhere, the current approach can silently attach a child skill’s resources/scripts to its parent as well, which is a design regression worth fixing before merge.
Flagged Issues
- Nested skill directories are treated as separate skills by
_discover_skill_directories(lines 3161-3195), but the new recursive resource/script scanners descend into every subdirectory (lines 2796-2807 and 2945-2956) without checking for a nestedSKILL.md. Withparent/SKILL.mdandparent/child/SKILL.md, the child's files will be surfaced under both skills. The scaners should stop recursing into subdirectories that contain their ownSKILL.md.
Automated review by giles17's agents
|
Flagged issue Nested skill directories are treated as separate skills by Source: automated DevFlow PR review |
…rectories - Add clarifying comments distinguishing MAX_SEARCH_DEPTH (SKILL.md discovery) from DEFAULT_SEARCH_DEPTH (per-skill resource/script scanning). - Stop recursing into subdirectories that contain their own SKILL.md, preventing child skill files from being attached to the parent skill. - Add test verifying nested skill boundary is respected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Motivation and Context
Ports the refactoring from .NET PR #6109 to the Python side. The old directory-whitelist approach (
resource_directories/script_directories) was rigid — users had to know exact subdirectory names upfront. The new depth-based scanning with optional filter predicates is strictly more flexible and aligns both language implementations.Description
Refactors
FileSkillsSourceto replace preconfigured directory whitelists with depth-controlled recursive scanning and user-supplied filter predicates.Removed:
resource_directories/script_directoriesconstructor optionsAdded:
search_depthoption (>= 1, default2): controls how deep the recursive scan goes within each skill directory. Depth 1 = root only; depth 2 = root + one level of subdirectories.script_filter/resource_filterpredicate options that receive aFileSkillFilterContext(skill_name+relative_file_path), allowing whitelist/blacklist filtering by file path.FileSkillFilterContextclass exported fromagent_framework.Preserved:
resource_extensions/script_extensions).Updated:
SkillsProvider.from_paths()accepts the new parameters.@staticmethodto instance methods.Contribution Checklist