empathy-framework 3.11.0__py3-none-any.whl → 4.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,516 @@
1
+ """Agent template system for meta-orchestration.
2
+
3
+ This module provides reusable agent archetypes that can be customized
4
+ for specific tasks. Templates define agent capabilities, tools, and
5
+ quality gates.
6
+
7
+ Security:
8
+ - All template fields validated on creation
9
+ - No eval() or exec() usage
10
+ - Input sanitization on template lookup
11
+
12
+ Example:
13
+ >>> template = get_template("test_coverage_analyzer")
14
+ >>> print(template.role)
15
+ Test Coverage Expert
16
+
17
+ >>> templates = get_templates_by_capability("analyze_gaps")
18
+ >>> print([t.id for t in templates])
19
+ ['test_coverage_analyzer']
20
+ """
21
+
22
+ import logging
23
+ from dataclasses import dataclass, field
24
+ from typing import Any
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ @dataclass(frozen=True)
30
+ class AgentCapability:
31
+ """Capability that an agent can perform.
32
+
33
+ Attributes:
34
+ name: Capability identifier (e.g., "analyze_gaps")
35
+ description: Human-readable description
36
+ required_tools: List of tools needed for this capability
37
+
38
+ Example:
39
+ >>> cap = AgentCapability(
40
+ ... name="analyze_gaps",
41
+ ... description="Identify test coverage gaps",
42
+ ... required_tools=["coverage_analyzer"]
43
+ ... )
44
+ """
45
+
46
+ name: str
47
+ description: str
48
+ required_tools: list[str] = field(default_factory=list)
49
+
50
+ def __post_init__(self):
51
+ """Validate capability fields."""
52
+ if not self.name or not isinstance(self.name, str):
53
+ raise ValueError("name must be a non-empty string")
54
+ if not self.description or not isinstance(self.description, str):
55
+ raise ValueError("description must be a non-empty string")
56
+ if not isinstance(self.required_tools, list):
57
+ raise ValueError("required_tools must be a list")
58
+
59
+
60
+ @dataclass(frozen=True)
61
+ class ResourceRequirements:
62
+ """Resource requirements for agent execution.
63
+
64
+ Attributes:
65
+ min_tokens: Minimum token budget required
66
+ max_tokens: Maximum token budget allowed
67
+ timeout_seconds: Maximum execution time in seconds
68
+ memory_mb: Maximum memory usage in megabytes
69
+
70
+ Example:
71
+ >>> req = ResourceRequirements(
72
+ ... min_tokens=1000,
73
+ ... max_tokens=10000,
74
+ ... timeout_seconds=300,
75
+ ... memory_mb=512
76
+ ... )
77
+ """
78
+
79
+ min_tokens: int = 1000
80
+ max_tokens: int = 10000
81
+ timeout_seconds: int = 300
82
+ memory_mb: int = 512
83
+
84
+ def __post_init__(self):
85
+ """Validate resource requirements."""
86
+ if self.min_tokens < 0:
87
+ raise ValueError("min_tokens must be non-negative")
88
+ if self.max_tokens < self.min_tokens:
89
+ raise ValueError("max_tokens must be >= min_tokens")
90
+ if self.timeout_seconds <= 0:
91
+ raise ValueError("timeout_seconds must be positive")
92
+ if self.memory_mb <= 0:
93
+ raise ValueError("memory_mb must be positive")
94
+
95
+
96
+ @dataclass(frozen=True)
97
+ class AgentTemplate:
98
+ """Reusable agent archetype.
99
+
100
+ Templates define agent capabilities, tools, and quality gates.
101
+ They can be customized for specific tasks during agent spawning.
102
+
103
+ Attributes:
104
+ id: Unique template identifier
105
+ role: Agent role description
106
+ capabilities: List of capability names
107
+ tier_preference: Preferred tier ("CHEAP", "CAPABLE", "PREMIUM")
108
+ tools: List of tool identifiers
109
+ default_instructions: Default instructions for the agent
110
+ quality_gates: Quality gate thresholds
111
+ resource_requirements: Resource limits and requirements
112
+
113
+ Example:
114
+ >>> template = AgentTemplate(
115
+ ... id="test_coverage_analyzer",
116
+ ... role="Test Coverage Expert",
117
+ ... capabilities=["analyze_gaps", "suggest_tests"],
118
+ ... tier_preference="CAPABLE",
119
+ ... tools=["coverage_analyzer"],
120
+ ... default_instructions="Analyze test coverage...",
121
+ ... quality_gates={"min_coverage": 80}
122
+ ... )
123
+
124
+ Security:
125
+ - All fields validated on creation
126
+ - tier_preference restricted to allowed values
127
+ - No user input used in eval/exec
128
+ """
129
+
130
+ id: str
131
+ role: str
132
+ capabilities: list[str]
133
+ tier_preference: str
134
+ tools: list[str]
135
+ default_instructions: str
136
+ quality_gates: dict[str, Any]
137
+ resource_requirements: ResourceRequirements = field(default_factory=ResourceRequirements)
138
+
139
+ ALLOWED_TIERS = {"CHEAP", "CAPABLE", "PREMIUM"}
140
+
141
+ def __post_init__(self):
142
+ """Validate template fields.
143
+
144
+ Raises:
145
+ ValueError: If any field is invalid
146
+ """
147
+ # Validate ID
148
+ if not self.id or not isinstance(self.id, str):
149
+ raise ValueError("id must be a non-empty string")
150
+
151
+ # Validate role
152
+ if not self.role or not isinstance(self.role, str):
153
+ raise ValueError("role must be a non-empty string")
154
+
155
+ # Validate capabilities
156
+ if not isinstance(self.capabilities, list):
157
+ raise ValueError("capabilities must be a list")
158
+ if not self.capabilities:
159
+ raise ValueError("capabilities must not be empty")
160
+ for cap in self.capabilities:
161
+ if not isinstance(cap, str) or not cap:
162
+ raise ValueError("all capabilities must be non-empty strings")
163
+
164
+ # Validate tier preference
165
+ if self.tier_preference not in self.ALLOWED_TIERS:
166
+ raise ValueError(f"tier_preference must be one of {self.ALLOWED_TIERS}")
167
+
168
+ # Validate tools
169
+ if not isinstance(self.tools, list):
170
+ raise ValueError("tools must be a list")
171
+ for tool in self.tools:
172
+ if not isinstance(tool, str) or not tool:
173
+ raise ValueError("all tools must be non-empty strings")
174
+
175
+ # Validate instructions
176
+ if not self.default_instructions or not isinstance(self.default_instructions, str):
177
+ raise ValueError("default_instructions must be a non-empty string")
178
+
179
+ # Validate quality gates
180
+ if not isinstance(self.quality_gates, dict):
181
+ raise ValueError("quality_gates must be a dict")
182
+
183
+ # Validate resource requirements
184
+ if not isinstance(self.resource_requirements, ResourceRequirements):
185
+ raise ValueError("resource_requirements must be a ResourceRequirements instance")
186
+
187
+
188
+ # Registry of pre-built agent templates
189
+ _TEMPLATE_REGISTRY: dict[str, AgentTemplate] = {}
190
+
191
+
192
+ def _register_template(template: AgentTemplate) -> None:
193
+ """Register a template in the global registry.
194
+
195
+ Args:
196
+ template: Template to register
197
+
198
+ Raises:
199
+ ValueError: If template with same ID already registered
200
+ """
201
+ if template.id in _TEMPLATE_REGISTRY:
202
+ raise ValueError(f"Template '{template.id}' already registered")
203
+ _TEMPLATE_REGISTRY[template.id] = template
204
+ logger.debug(f"Registered template: {template.id}")
205
+
206
+
207
+ def get_template(template_id: str) -> AgentTemplate | None:
208
+ """Retrieve template by ID.
209
+
210
+ Args:
211
+ template_id: Template identifier
212
+
213
+ Returns:
214
+ Template if found, None otherwise
215
+
216
+ Example:
217
+ >>> template = get_template("test_coverage_analyzer")
218
+ >>> print(template.role)
219
+ Test Coverage Expert
220
+ """
221
+ if not template_id or not isinstance(template_id, str):
222
+ logger.warning(f"Invalid template_id: {template_id}")
223
+ return None
224
+ return _TEMPLATE_REGISTRY.get(template_id)
225
+
226
+
227
+ def get_all_templates() -> list[AgentTemplate]:
228
+ """Retrieve all registered templates.
229
+
230
+ Returns:
231
+ List of all templates
232
+
233
+ Example:
234
+ >>> templates = get_all_templates()
235
+ >>> len(templates) >= 7
236
+ True
237
+ """
238
+ return list(_TEMPLATE_REGISTRY.values())
239
+
240
+
241
+ def get_templates_by_capability(capability: str) -> list[AgentTemplate]:
242
+ """Retrieve templates with a specific capability.
243
+
244
+ Args:
245
+ capability: Capability name to search for
246
+
247
+ Returns:
248
+ List of templates with that capability
249
+
250
+ Example:
251
+ >>> templates = get_templates_by_capability("analyze_gaps")
252
+ >>> any(t.id == "test_coverage_analyzer" for t in templates)
253
+ True
254
+ """
255
+ if not capability or not isinstance(capability, str):
256
+ logger.warning(f"Invalid capability: {capability}")
257
+ return []
258
+
259
+ return [
260
+ template for template in _TEMPLATE_REGISTRY.values() if capability in template.capabilities
261
+ ]
262
+
263
+
264
+ def get_templates_by_tier(tier: str) -> list[AgentTemplate]:
265
+ """Retrieve templates preferring a specific tier.
266
+
267
+ Args:
268
+ tier: Tier name ("CHEAP", "CAPABLE", "PREMIUM")
269
+
270
+ Returns:
271
+ List of templates preferring that tier
272
+
273
+ Example:
274
+ >>> templates = get_templates_by_tier("CAPABLE")
275
+ >>> len(templates) > 0
276
+ True
277
+ """
278
+ if tier not in AgentTemplate.ALLOWED_TIERS:
279
+ logger.warning(f"Invalid tier: {tier}")
280
+ return []
281
+
282
+ return [
283
+ template for template in _TEMPLATE_REGISTRY.values() if template.tier_preference == tier
284
+ ]
285
+
286
+
287
+ # Pre-built agent templates
288
+
289
+ # Template 1: Test Coverage Analyzer
290
+ _TEST_COVERAGE_ANALYZER = AgentTemplate(
291
+ id="test_coverage_analyzer",
292
+ role="Test Coverage Expert",
293
+ capabilities=["analyze_gaps", "suggest_tests", "validate_coverage"],
294
+ tier_preference="CAPABLE",
295
+ tools=["coverage_analyzer", "ast_parser"],
296
+ default_instructions=(
297
+ "You are a test coverage expert. Analyze the codebase to:\n"
298
+ "1. Identify test coverage gaps\n"
299
+ "2. Suggest specific tests to improve coverage\n"
300
+ "3. Validate that coverage meets quality gates\n"
301
+ "Focus on high-value test cases that improve code quality."
302
+ ),
303
+ quality_gates={"min_coverage": 80, "min_quality_score": 7},
304
+ resource_requirements=ResourceRequirements(
305
+ min_tokens=2000,
306
+ max_tokens=15000,
307
+ timeout_seconds=600,
308
+ memory_mb=1024,
309
+ ),
310
+ )
311
+
312
+ # Template 2: Security Auditor
313
+ _SECURITY_AUDITOR = AgentTemplate(
314
+ id="security_auditor",
315
+ role="Security Auditor",
316
+ capabilities=[
317
+ "vulnerability_scan",
318
+ "threat_modeling",
319
+ "compliance_check",
320
+ ],
321
+ tier_preference="PREMIUM",
322
+ tools=["security_scanner", "bandit", "dependency_checker"],
323
+ default_instructions=(
324
+ "You are a security auditor. Perform comprehensive security analysis:\n"
325
+ "1. Scan for common vulnerabilities (OWASP Top 10)\n"
326
+ "2. Perform threat modeling for critical components\n"
327
+ "3. Verify compliance with security standards\n"
328
+ "4. Generate remediation plan for findings\n"
329
+ "Prioritize critical and high-severity issues."
330
+ ),
331
+ quality_gates={
332
+ "max_critical_issues": 0,
333
+ "max_high_issues": 0,
334
+ "min_compliance_score": 90,
335
+ },
336
+ resource_requirements=ResourceRequirements(
337
+ min_tokens=5000,
338
+ max_tokens=30000,
339
+ timeout_seconds=900,
340
+ memory_mb=2048,
341
+ ),
342
+ )
343
+
344
+ # Template 3: Code Reviewer
345
+ _CODE_REVIEWER = AgentTemplate(
346
+ id="code_reviewer",
347
+ role="Code Quality Reviewer",
348
+ capabilities=[
349
+ "code_review",
350
+ "quality_assessment",
351
+ "best_practices_check",
352
+ ],
353
+ tier_preference="CAPABLE",
354
+ tools=["ast_parser", "complexity_analyzer", "style_checker"],
355
+ default_instructions=(
356
+ "You are a code quality reviewer. Review code for:\n"
357
+ "1. Code quality and maintainability\n"
358
+ "2. Adherence to best practices\n"
359
+ "3. Potential bugs and edge cases\n"
360
+ "4. Performance considerations\n"
361
+ "Provide actionable feedback with specific examples."
362
+ ),
363
+ quality_gates={
364
+ "min_quality_score": 7,
365
+ "max_complexity": 15,
366
+ "min_test_coverage": 80,
367
+ },
368
+ resource_requirements=ResourceRequirements(
369
+ min_tokens=3000,
370
+ max_tokens=20000,
371
+ timeout_seconds=600,
372
+ memory_mb=1024,
373
+ ),
374
+ )
375
+
376
+ # Template 4: Documentation Writer
377
+ _DOCUMENTATION_WRITER = AgentTemplate(
378
+ id="documentation_writer",
379
+ role="Documentation Writer",
380
+ capabilities=[
381
+ "generate_docs",
382
+ "check_completeness",
383
+ "update_examples",
384
+ ],
385
+ tier_preference="CHEAP",
386
+ tools=["ast_parser", "doc_generator"],
387
+ default_instructions=(
388
+ "You are a documentation writer. Create clear, comprehensive docs:\n"
389
+ "1. Generate API documentation from code\n"
390
+ "2. Write usage examples and tutorials\n"
391
+ "3. Update existing documentation for consistency\n"
392
+ "4. Verify all public APIs are documented\n"
393
+ "Focus on clarity and usefulness for developers."
394
+ ),
395
+ quality_gates={
396
+ "min_doc_coverage": 100,
397
+ "min_example_count": 3,
398
+ },
399
+ resource_requirements=ResourceRequirements(
400
+ min_tokens=1000,
401
+ max_tokens=10000,
402
+ timeout_seconds=300,
403
+ memory_mb=512,
404
+ ),
405
+ )
406
+
407
+ # Template 5: Performance Optimizer
408
+ _PERFORMANCE_OPTIMIZER = AgentTemplate(
409
+ id="performance_optimizer",
410
+ role="Performance Optimizer",
411
+ capabilities=[
412
+ "profile_code",
413
+ "identify_bottlenecks",
414
+ "suggest_optimizations",
415
+ ],
416
+ tier_preference="CAPABLE",
417
+ tools=["profiler", "complexity_analyzer", "benchmark_runner"],
418
+ default_instructions=(
419
+ "You are a performance optimizer. Analyze and improve performance:\n"
420
+ "1. Profile code to identify bottlenecks\n"
421
+ "2. Analyze time and space complexity\n"
422
+ "3. Suggest specific optimizations\n"
423
+ "4. Validate improvements with benchmarks\n"
424
+ "Focus on high-impact optimizations with measurable results."
425
+ ),
426
+ quality_gates={
427
+ "min_performance_improvement": 20,
428
+ "max_regression_percent": 5,
429
+ },
430
+ resource_requirements=ResourceRequirements(
431
+ min_tokens=2000,
432
+ max_tokens=15000,
433
+ timeout_seconds=900,
434
+ memory_mb=2048,
435
+ ),
436
+ )
437
+
438
+ # Template 6: Architecture Analyst
439
+ _ARCHITECTURE_ANALYST = AgentTemplate(
440
+ id="architecture_analyst",
441
+ role="Architecture Analyst",
442
+ capabilities=[
443
+ "analyze_architecture",
444
+ "identify_patterns",
445
+ "suggest_improvements",
446
+ ],
447
+ tier_preference="PREMIUM",
448
+ tools=["dependency_analyzer", "pattern_detector", "metrics_collector"],
449
+ default_instructions=(
450
+ "You are an architecture analyst. Analyze system architecture:\n"
451
+ "1. Map dependencies and component relationships\n"
452
+ "2. Identify architectural patterns and anti-patterns\n"
453
+ "3. Assess scalability and maintainability\n"
454
+ "4. Suggest architectural improvements\n"
455
+ "Focus on long-term maintainability and system evolution."
456
+ ),
457
+ quality_gates={
458
+ "max_circular_dependencies": 0,
459
+ "min_modularity_score": 7,
460
+ },
461
+ resource_requirements=ResourceRequirements(
462
+ min_tokens=5000,
463
+ max_tokens=30000,
464
+ timeout_seconds=900,
465
+ memory_mb=2048,
466
+ ),
467
+ )
468
+
469
+ # Template 7: Refactoring Specialist
470
+ _REFACTORING_SPECIALIST = AgentTemplate(
471
+ id="refactoring_specialist",
472
+ role="Refactoring Specialist",
473
+ capabilities=[
474
+ "identify_code_smells",
475
+ "suggest_refactorings",
476
+ "validate_changes",
477
+ ],
478
+ tier_preference="CAPABLE",
479
+ tools=[
480
+ "ast_parser",
481
+ "complexity_analyzer",
482
+ "duplication_detector",
483
+ ],
484
+ default_instructions=(
485
+ "You are a refactoring specialist. Improve code structure:\n"
486
+ "1. Identify code smells and technical debt\n"
487
+ "2. Suggest specific refactorings\n"
488
+ "3. Ensure behavior preservation\n"
489
+ "4. Validate improvements with tests\n"
490
+ "Focus on improving maintainability without changing behavior."
491
+ ),
492
+ quality_gates={
493
+ "max_duplication_percent": 5,
494
+ "max_complexity": 10,
495
+ "min_test_coverage": 90,
496
+ },
497
+ resource_requirements=ResourceRequirements(
498
+ min_tokens=2000,
499
+ max_tokens=15000,
500
+ timeout_seconds=600,
501
+ memory_mb=1024,
502
+ ),
503
+ )
504
+
505
+
506
+ # Register all pre-built templates
507
+ _register_template(_TEST_COVERAGE_ANALYZER)
508
+ _register_template(_SECURITY_AUDITOR)
509
+ _register_template(_CODE_REVIEWER)
510
+ _register_template(_DOCUMENTATION_WRITER)
511
+ _register_template(_PERFORMANCE_OPTIMIZER)
512
+ _register_template(_ARCHITECTURE_ANALYST)
513
+ _register_template(_REFACTORING_SPECIALIST)
514
+
515
+
516
+ logger.info(f"Registered {len(_TEMPLATE_REGISTRY)} agent templates")