20321f21ee
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / security (push) Waiting to run
CI / quality (push) Waiting to run
CI / unit_tests (push) Waiting to run
CI / integration_tests (push) Waiting to run
CI / coverage (push) Blocked by required conditions
CI / build (push) Waiting to run
CI / docker (push) Blocked by required conditions
85 lines
3.0 KiB
Markdown
85 lines
3.0 KiB
Markdown
# Skill Resolution
|
|
|
|
The `SkillResolver` flattens a skill's tool set by recursively resolving
|
|
includes, collecting tool references, inline tools, and external sources
|
|
into a deterministic ordered list.
|
|
|
|
## Resolution Algorithm
|
|
|
|
1. **Cycle detection** -- Before descending into includes, check if the
|
|
current skill has already been visited in this resolution path. If so,
|
|
raise a `ValueError` with the full cycle path trace.
|
|
|
|
2. **Depth-first include resolution** -- Process each `SkillInclude` by
|
|
recursively resolving the included skill first. This ensures that
|
|
tools from deeper includes appear earlier in the final order.
|
|
|
|
3. **Tool ref collection** -- Add tool_refs from the current skill. If a
|
|
tool name already exists (from an include), it is replaced (last-wins
|
|
semantics for overrides).
|
|
|
|
4. **Inline tool collection** -- Anonymous tools are keyed as
|
|
`{skill_name}/_anon_{index}` and added in definition order.
|
|
|
|
5. **MCP source collection** -- For MCP servers with explicit tool lists,
|
|
each tool is added as `mcp:{server}/{tool_name}`.
|
|
|
|
6. **Agent skill collection** -- Each agent skill path is added as
|
|
`agent_skill:{path}`.
|
|
|
|
## De-duplication
|
|
|
|
When the same tool name appears multiple times (e.g., from overlapping
|
|
includes), the **last occurrence wins**. The tool's position in the
|
|
ordered list is preserved from its first appearance, but the entry
|
|
metadata is updated.
|
|
|
|
## Override Application
|
|
|
|
Overrides defined in the skill's `overrides` dict are applied to matching
|
|
tool refs during resolution. The overrides dict is keyed by tool name and
|
|
contains arbitrary metadata that is attached to the `ResolvedToolEntry`.
|
|
|
|
## Cycle Detection
|
|
|
|
The resolver tracks the current resolution path (stack of skill names).
|
|
If a skill is encountered that is already on the path, a `ValueError` is
|
|
raised with a human-readable path trace:
|
|
|
|
```
|
|
Cycle detected in skill includes: local/a -> local/b -> local/a
|
|
```
|
|
|
|
## CapabilitySummary
|
|
|
|
After resolution, `SkillResolver.compute_capability_summary()` aggregates
|
|
capability metadata from inline tools to produce a `SkillCapabilitySummary`:
|
|
|
|
- Counts read-only, write, and checkpointable tools
|
|
- Detects side effects across all inline tools
|
|
- Counts MCP and agent skill sources
|
|
|
|
## API
|
|
|
|
```python
|
|
resolver = SkillResolver()
|
|
|
|
# Resolve tools
|
|
entries = resolver.resolve_tools(skill, skill_lookup_dict)
|
|
|
|
# Compute summary
|
|
summary = resolver.compute_capability_summary(skill, entries)
|
|
```
|
|
|
|
## ResolvedToolEntry
|
|
|
|
Each entry in the resolved list contains:
|
|
|
|
| Field | Type | Description |
|
|
|----------------|--------------------------|--------------------------------------|
|
|
| `name` | `str` | Tool name or generated key |
|
|
| `source_skill` | `str` | Skill that contributed this tool |
|
|
| `is_inline` | `bool` | Whether this is an inline tool |
|
|
| `inline_tool` | `SkillInlineTool \| None`| Inline definition (if applicable) |
|
|
| `overrides` | `dict[str, Any]` | Applied overrides |
|