183 lines
5.5 KiB
Markdown
183 lines
5.5 KiB
Markdown
# Skill Protocol Reference
|
|
|
|
The **Skill Protocol** defines the type contracts used for skill discovery,
|
|
composition, execution, and error reporting within CleverAgents v3.
|
|
|
|
All protocol types are frozen Pydantic `BaseModel` instances, ensuring
|
|
immutability after construction.
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
| Type | Purpose |
|
|
|------|---------|
|
|
| `SkillErrorType` | `StrEnum` of all skill error categories |
|
|
| `SkillError` | Structured error payload |
|
|
| `SkillMetadata` | Lightweight discovery descriptor |
|
|
| `SkillDefinition` | Full skill + resolved tools + metadata |
|
|
| `SkillResult` | Outcome of a skill-tool invocation |
|
|
|
|
---
|
|
|
|
## SkillErrorType
|
|
|
|
A `StrEnum` with the following members:
|
|
|
|
| Value | Description |
|
|
|-------|-------------|
|
|
| `skill_not_found` | The requested skill does not exist |
|
|
| `resolution_failure` | Skill resolution failed (missing include, etc.) |
|
|
| `cycle_detected` | Circular dependency in skill includes |
|
|
| `tool_activation_failure` | Tool could not be activated |
|
|
| `tool_execution_failure` | Tool execution failed at runtime |
|
|
| `validation_error` | Input/output schema validation failed |
|
|
| `permission_denied` | Operation not permitted |
|
|
|
|
---
|
|
|
|
## SkillError
|
|
|
|
Structured error payload for skill operations.
|
|
|
|
### Fields
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `error_type` | `SkillErrorType` | Yes | Error category |
|
|
| `message` | `str` | Yes | Human-readable description |
|
|
| `details` | `dict[str, Any]` | No | Diagnostic context |
|
|
| `skill_name` | `str` | Yes | Originating skill |
|
|
| `tool_name` | `str \| None` | No | Originating tool |
|
|
|
|
---
|
|
|
|
## SkillMetadata
|
|
|
|
Lightweight metadata for skill discovery and catalogue listings.
|
|
|
|
### Fields
|
|
|
|
| Field | Type | Default | Description |
|
|
|-------|------|---------|-------------|
|
|
| `name` | `str` | — | Namespaced skill name |
|
|
| `description` | `str` | — | Skill description |
|
|
| `version` | `str` | `"0.0.0"` | Semantic version |
|
|
| `tool_count` | `int` | `0` | Number of resolved tools |
|
|
| `capability_summary` | `SkillCapabilitySummary` | empty | Aggregated capabilities |
|
|
| `source_types` | `list[str]` | `[]` | Distinct source type labels |
|
|
| `writes` | `bool` | `False` | Any tool can write |
|
|
| `read_only` | `bool` | `True` | Entire skill is read-only |
|
|
|
|
### Factory: `from_skill()`
|
|
|
|
```python
|
|
meta = SkillMetadata.from_skill(skill, resolved=resolved_entries, version="1.0.0")
|
|
```
|
|
|
|
Derives `writes` and `read_only` from the `SkillCapabilitySummary`:
|
|
|
|
- `writes = True` when `write_tools > 0` or `has_side_effects` is true
|
|
- `read_only = True` when `write_tools == 0` and no side effects
|
|
|
|
### Writes / Read-Only Gating
|
|
|
|
The `writes` and `read_only` flags are propagated to the ToolRuntime
|
|
gating layer. A skill marked `read_only=True` will never be allowed
|
|
to trigger a write-capable tool at runtime.
|
|
|
|
---
|
|
|
|
## SkillDefinition
|
|
|
|
Full skill definition combining the domain `Skill` model, resolved tools,
|
|
and pre-computed metadata.
|
|
|
|
### Fields
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `skill` | `Skill` | Yes | Domain-level Skill model |
|
|
| `resolved_tools` | `list[ResolvedToolEntry]` | No | Flattened tool set |
|
|
| `metadata` | `SkillMetadata` | Yes | Pre-computed metadata |
|
|
| `input_schema` | `dict \| None` | No | JSON Schema for inputs |
|
|
| `output_schema` | `dict \| None` | No | JSON Schema for outputs |
|
|
|
|
### JSON Schema Validation
|
|
|
|
When `input_schema` or `output_schema` is provided, it **must** include a
|
|
`"type"` key to be considered a valid JSON Schema object. The validator
|
|
rejects schemas missing this key at construction time.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"query": {"type": "string"}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Writes Consistency
|
|
|
|
The model validator checks that if `metadata.read_only` is `True`, none
|
|
of the resolved inline tools declare `writes=True`. A mismatch raises
|
|
a `ValidationError`.
|
|
|
|
---
|
|
|
|
## SkillResult
|
|
|
|
Outcome of a single skill-tool invocation.
|
|
|
|
### Fields
|
|
|
|
| Field | Type | Default | Description |
|
|
|-------|------|---------|-------------|
|
|
| `skill_name` | `str` | — | Invoked skill |
|
|
| `tool_name` | `str` | — | Invoked tool |
|
|
| `success` | `bool` | — | Whether invocation succeeded |
|
|
| `output_data` | `Any` | `None` | Tool output |
|
|
| `error` | `SkillError \| None` | `None` | Error on failure |
|
|
| `duration_ms` | `float` | `0.0` | Execution time in ms |
|
|
| `resource_changes` | `list[dict]` | `[]` | Resource change descriptors |
|
|
|
|
---
|
|
|
|
## Error Mapping
|
|
|
|
The `map_tool_error()` helper normalises arbitrary exceptions into
|
|
`SkillError` payloads:
|
|
|
|
```python
|
|
from cleveragents.skills.protocol import map_tool_error
|
|
|
|
try:
|
|
run_tool(...)
|
|
except Exception as exc:
|
|
error = map_tool_error(exc, skill_name="local/my-skill", tool_name="local/my-tool")
|
|
```
|
|
|
|
### Mapping Rules
|
|
|
|
| Exception Type | Message Contains | Mapped To |
|
|
|----------------|------------------|-----------|
|
|
| `ValueError` | `"cycle"` | `CYCLE_DETECTED` |
|
|
| `ValueError` | `"not found"` | `SKILL_NOT_FOUND` |
|
|
| `ValueError` | (other) | `RESOLUTION_FAILURE` |
|
|
| `PermissionError` | — | `PERMISSION_DENIED` |
|
|
| `ValidationError` | — | `VALIDATION_ERROR` |
|
|
| Any | `"activation"` | `TOOL_ACTIVATION_FAILURE` |
|
|
| Any | (other) | `TOOL_EXECUTION_FAILURE` |
|
|
|
|
---
|
|
|
|
## JSON Schema Rules Summary
|
|
|
|
1. **Input/output schemas** on `SkillDefinition` must include `"type"`.
|
|
2. **Writes/read_only metadata** on `SkillMetadata` must be consistent
|
|
with the resolved tool capabilities.
|
|
3. **Error payloads** always include `skill_name`; `tool_name` is
|
|
optional but recommended.
|
|
4. All protocol types are **frozen** (immutable after construction).
|