Coverage for src / lexigram / contracts / ai / skills.py: 0%

62 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-15 18:57 +0800

1"""Composable skills/tools system contracts.""" 

2 

3from __future__ import annotations 

4 

5from dataclasses import dataclass, field 

6from typing import TYPE_CHECKING, Any 

7 

8from typing_extensions import Protocol, runtime_checkable 

9 

10from lexigram.contracts.ai.exceptions import SkillError 

11 

12if TYPE_CHECKING: 

13 from lexigram.contracts.core.result import Result 

14 

15 

16@dataclass(frozen=True) 

17class SkillParameter: 

18 """Parameter definition for a skill. 

19 

20 Attributes: 

21 name: Parameter name 

22 type: Parameter type (e.g., "string", "integer", "boolean") 

23 description: Human-readable description 

24 required: Whether this parameter is required 

25 default: Default value if not provided 

26 enum: List of allowed values (if restricted) 

27 min_value: Numeric minimum (if applicable) 

28 max_value: Numeric maximum (if applicable) 

29 max_length: String max length (if applicable) 

30 """ 

31 

32 name: str 

33 type: str 

34 description: str 

35 required: bool = True 

36 default: Any = None 

37 enum: list[Any] | None = None 

38 min_value: float | None = None 

39 max_value: float | None = None 

40 max_length: int | None = None 

41 

42 

43@dataclass(frozen=True) 

44class SkillDefinition: 

45 """Definition of a skill's interface and behavior. 

46 

47 Attributes: 

48 name: Unique skill name 

49 description: What the skill does 

50 parameters_schema: JSON Schema for parameters 

51 returns_schema: JSON Schema for return value 

52 category: Skill category for organization 

53 requires_confirmation: If True, requires user approval before execution 

54 cacheable: Whether results can be cached 

55 max_retries: Maximum retry attempts on failure 

56 timeout_seconds: Execution timeout in seconds 

57 permissions: Required permissions to execute 

58 """ 

59 

60 name: str 

61 description: str 

62 parameters_schema: dict[str, Any] = field(default_factory=dict) 

63 returns_schema: dict[str, Any] = field(default_factory=dict) 

64 category: str = "general" 

65 requires_confirmation: bool = False 

66 cacheable: bool = False 

67 max_retries: int = 0 

68 timeout_seconds: float = 30.0 

69 permissions: list[str] = field(default_factory=list) 

70 metadata: dict[str, Any] = field(default_factory=dict) 

71 

72 

73@dataclass(frozen=True) 

74class SkillResult: 

75 """Result of a skill execution. 

76 

77 Attributes: 

78 skill_name: Name of the executed skill 

79 success: Whether execution succeeded 

80 output: The output value (if successful) 

81 error: Error message (if failed) 

82 duration_ms: Time taken to execute 

83 cached: Whether result came from cache 

84 metadata: Additional execution metadata 

85 """ 

86 

87 skill_name: str 

88 success: bool 

89 output: Any = None 

90 error: str | None = None 

91 duration_ms: float = 0.0 

92 cached: bool = False 

93 metadata: dict[str, Any] = field(default_factory=dict) 

94 

95 

96@runtime_checkable 

97class SkillProtocol(Protocol): 

98 """Protocol for a composable skill. 

99 

100 A skill is an async-callable capability that can be registered, 

101 discovered, and executed with validation and error handling. 

102 """ 

103 

104 @property 

105 def definition(self) -> SkillDefinition: 

106 """Get the skill definition. 

107 

108 Returns: 

109 The skill's definition including parameters and metadata 

110 """ 

111 ... 

112 

113 async def execute(self, **kwargs: Any) -> Result[SkillResult, SkillError]: 

114 """Execute the skill. 

115 

116 Args: 

117 **kwargs: Skill-specific parameters 

118 

119 Returns: 

120 Result with SkillResult on success or SkillError on failure 

121 """ 

122 ... 

123 

124 def validate(self, params: dict[str, Any]) -> list[str]: 

125 """Validate parameters against the definition. 

126 

127 Args: 

128 params: Parameters to validate 

129 

130 Returns: 

131 List of validation errors (empty if valid) 

132 """ 

133 ... 

134 

135 

136@runtime_checkable 

137class SkillRegistryProtocol(Protocol): 

138 """Protocol for registering and discovering skills. 

139 

140 Maintains a registry of available skills with support for 

141 filtering by category and permissions. 

142 """ 

143 

144 def register(self, skill: SkillProtocol) -> None: 

145 """Register a skill in the registry. 

146 

147 Args: 

148 skill: The skill to register 

149 """ 

150 ... 

151 

152 def get(self, name: str) -> SkillProtocol | None: 

153 """Get a skill by name. 

154 

155 Args: 

156 name: The skill name 

157 

158 Returns: 

159 The skill, or None if not found 

160 """ 

161 ... 

162 

163 def list_skills( 

164 self, 

165 category: str | None = None, 

166 permissions: list[str] | None = None, 

167 ) -> list[SkillDefinition]: 

168 """List available skills with optional filtering. 

169 

170 Args: 

171 category: Filter by skill category 

172 permissions: Filter to skills that match any of these permissions 

173 

174 Returns: 

175 List of skill definitions matching the criteria 

176 """ 

177 ... 

178 

179 def get_schemas(self) -> list[dict[str, Any]]: 

180 """Get OpenAI function-calling compatible schemas. 

181 

182 Returns: 

183 List of skill schemas in OpenAI function calling format 

184 """ 

185 ... 

186 

187 

188@runtime_checkable 

189class SkillExecutorProtocol(Protocol): 

190 """Protocol for executing skills with lifecycle management. 

191 

192 Handles skill selection, validation, execution, retry, caching, 

193 permission checking, and observability. 

194 """ 

195 

196 async def execute( 

197 self, 

198 skill_name: str, 

199 params: dict[str, Any], 

200 user_id: str | None = None, 

201 session_id: str | None = None, 

202 ) -> Result[SkillResult, SkillError]: 

203 """Execute a skill with full lifecycle management. 

204 

205 Args: 

206 skill_name: Name of the skill to execute 

207 params: Parameters for the skill 

208 user_id: Optional user ID for permission checks 

209 session_id: Optional session ID for context 

210 

211 Returns: 

212 Result with SkillResult on success or SkillError on failure 

213 """ 

214 ... 

215 

216 

217@runtime_checkable 

218class ToolkitProtocol(Protocol): 

219 """Protocol for a collection of related skills. 

220 

221 A toolkit groups semantically related skills together, such as 

222 database operations, web browsing, or file operations. 

223 """ 

224 

225 @property 

226 def tools(self) -> tuple[SkillProtocol, ...]: 

227 """Get the collection of skills in this toolkit. 

228 

229 Returns: 

230 Tuple of SkillProtocol instances provided by this toolkit. 

231 """ 

232 ... 

233 

234 @property 

235 def name(self) -> str: 

236 """Get the toolkit name. 

237 

238 Returns: 

239 Unique identifier for this toolkit. 

240 """ 

241 ... 

242 

243 @property 

244 def description(self) -> str: 

245 """Get the toolkit description. 

246 

247 Returns: 

248 Human-readable description of what this toolkit provides. 

249 """ 

250 ... 

251 

252 

253__all__ = [ 

254 "SkillDefinition", 

255 "SkillError", 

256 "SkillExecutorProtocol", 

257 "SkillParameter", 

258 "SkillProtocol", 

259 "SkillRegistryProtocol", 

260 "SkillResult", 

261 "ToolkitProtocol", 

262]