empathy-framework 4.6.2__py3-none-any.whl → 4.6.3__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.
- {empathy_framework-4.6.2.dist-info → empathy_framework-4.6.3.dist-info}/METADATA +1 -1
- {empathy_framework-4.6.2.dist-info → empathy_framework-4.6.3.dist-info}/RECORD +53 -20
- {empathy_framework-4.6.2.dist-info → empathy_framework-4.6.3.dist-info}/WHEEL +1 -1
- empathy_os/__init__.py +1 -1
- empathy_os/cli.py +361 -32
- empathy_os/config/xml_config.py +8 -3
- empathy_os/core.py +37 -4
- empathy_os/leverage_points.py +2 -1
- empathy_os/memory/short_term.py +45 -1
- empathy_os/meta_workflows/agent_creator 2.py +254 -0
- empathy_os/meta_workflows/builtin_templates 2.py +567 -0
- empathy_os/meta_workflows/cli_meta_workflows 2.py +1551 -0
- empathy_os/meta_workflows/form_engine 2.py +304 -0
- empathy_os/meta_workflows/intent_detector 2.py +298 -0
- empathy_os/meta_workflows/pattern_learner 2.py +754 -0
- empathy_os/meta_workflows/session_context 2.py +398 -0
- empathy_os/meta_workflows/template_registry 2.py +229 -0
- empathy_os/meta_workflows/workflow 2.py +980 -0
- empathy_os/models/token_estimator.py +16 -9
- empathy_os/models/validation.py +7 -1
- empathy_os/orchestration/pattern_learner 2.py +699 -0
- empathy_os/orchestration/real_tools 2.py +938 -0
- empathy_os/orchestration/real_tools.py +4 -2
- empathy_os/socratic/__init__ 2.py +273 -0
- empathy_os/socratic/ab_testing 2.py +969 -0
- empathy_os/socratic/blueprint 2.py +532 -0
- empathy_os/socratic/cli 2.py +689 -0
- empathy_os/socratic/collaboration 2.py +1112 -0
- empathy_os/socratic/domain_templates 2.py +916 -0
- empathy_os/socratic/embeddings 2.py +734 -0
- empathy_os/socratic/engine 2.py +729 -0
- empathy_os/socratic/explainer 2.py +663 -0
- empathy_os/socratic/feedback 2.py +767 -0
- empathy_os/socratic/forms 2.py +624 -0
- empathy_os/socratic/generator 2.py +716 -0
- empathy_os/socratic/llm_analyzer 2.py +635 -0
- empathy_os/socratic/mcp_server 2.py +751 -0
- empathy_os/socratic/session 2.py +306 -0
- empathy_os/socratic/storage 2.py +635 -0
- empathy_os/socratic/storage.py +2 -1
- empathy_os/socratic/success 2.py +719 -0
- empathy_os/socratic/visual_editor 2.py +812 -0
- empathy_os/socratic/web_ui 2.py +925 -0
- empathy_os/tier_recommender.py +5 -2
- empathy_os/workflow_commands.py +11 -6
- empathy_os/workflows/base.py +1 -1
- empathy_os/workflows/batch_processing 2.py +310 -0
- empathy_os/workflows/release_prep_crew 2.py +968 -0
- empathy_os/workflows/test_coverage_boost_crew 2.py +848 -0
- empathy_os/workflows/test_maintenance.py +3 -2
- {empathy_framework-4.6.2.dist-info → empathy_framework-4.6.3.dist-info}/entry_points.txt +0 -0
- {empathy_framework-4.6.2.dist-info → empathy_framework-4.6.3.dist-info}/licenses/LICENSE +0 -0
- {empathy_framework-4.6.2.dist-info → empathy_framework-4.6.3.dist-info}/top_level.txt +0 -0
empathy_os/memory/short_term.py
CHANGED
|
@@ -215,7 +215,13 @@ class RedisMetrics:
|
|
|
215
215
|
return (self.operations_success / self.operations_total) * 100
|
|
216
216
|
|
|
217
217
|
def to_dict(self) -> dict:
|
|
218
|
-
"""Convert to dictionary for reporting.
|
|
218
|
+
"""Convert metrics to dictionary for reporting and serialization.
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
Dictionary with keys: operations_total, operations_success,
|
|
222
|
+
operations_failed, retries_total, latency_avg_ms, latency_max_ms,
|
|
223
|
+
success_rate, by_operation, security.
|
|
224
|
+
"""
|
|
219
225
|
return {
|
|
220
226
|
"operations_total": self.operations_total,
|
|
221
227
|
"operations_success": self.operations_success,
|
|
@@ -334,6 +340,12 @@ class StagedPattern:
|
|
|
334
340
|
raise TypeError(f"interests must be list, got {type(self.interests).__name__}")
|
|
335
341
|
|
|
336
342
|
def to_dict(self) -> dict:
|
|
343
|
+
"""Convert staged pattern to dictionary for serialization.
|
|
344
|
+
|
|
345
|
+
Returns:
|
|
346
|
+
Dictionary with keys: pattern_id, agent_id, pattern_type, name,
|
|
347
|
+
description, code, context, confidence, staged_at, interests.
|
|
348
|
+
"""
|
|
337
349
|
return {
|
|
338
350
|
"pattern_id": self.pattern_id,
|
|
339
351
|
"agent_id": self.agent_id,
|
|
@@ -349,6 +361,19 @@ class StagedPattern:
|
|
|
349
361
|
|
|
350
362
|
@classmethod
|
|
351
363
|
def from_dict(cls, data: dict) -> "StagedPattern":
|
|
364
|
+
"""Reconstruct StagedPattern from dictionary.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
data: Dictionary with required keys: pattern_id, agent_id,
|
|
368
|
+
pattern_type, name, description, staged_at.
|
|
369
|
+
|
|
370
|
+
Returns:
|
|
371
|
+
Reconstructed StagedPattern instance.
|
|
372
|
+
|
|
373
|
+
Raises:
|
|
374
|
+
KeyError: If required keys are missing.
|
|
375
|
+
ValueError: If data format is invalid.
|
|
376
|
+
"""
|
|
352
377
|
return cls(
|
|
353
378
|
pattern_id=data["pattern_id"],
|
|
354
379
|
agent_id=data["agent_id"],
|
|
@@ -382,6 +407,12 @@ class ConflictContext:
|
|
|
382
407
|
resolution: str | None = None
|
|
383
408
|
|
|
384
409
|
def to_dict(self) -> dict:
|
|
410
|
+
"""Convert conflict context to dictionary for serialization.
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
Dictionary with keys: conflict_id, positions, interests,
|
|
414
|
+
batna, created_at, resolved, resolution.
|
|
415
|
+
"""
|
|
385
416
|
return {
|
|
386
417
|
"conflict_id": self.conflict_id,
|
|
387
418
|
"positions": self.positions,
|
|
@@ -394,6 +425,19 @@ class ConflictContext:
|
|
|
394
425
|
|
|
395
426
|
@classmethod
|
|
396
427
|
def from_dict(cls, data: dict) -> "ConflictContext":
|
|
428
|
+
"""Reconstruct ConflictContext from dictionary.
|
|
429
|
+
|
|
430
|
+
Args:
|
|
431
|
+
data: Dictionary with required keys: conflict_id, positions,
|
|
432
|
+
interests, created_at.
|
|
433
|
+
|
|
434
|
+
Returns:
|
|
435
|
+
Reconstructed ConflictContext instance.
|
|
436
|
+
|
|
437
|
+
Raises:
|
|
438
|
+
KeyError: If required keys are missing.
|
|
439
|
+
ValueError: If data format is invalid.
|
|
440
|
+
"""
|
|
397
441
|
return cls(
|
|
398
442
|
conflict_id=data["conflict_id"],
|
|
399
443
|
positions=data["positions"],
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"""Dynamic agent creator from templates and form responses.
|
|
2
|
+
|
|
3
|
+
Generates agent specifications based on template rules and user's
|
|
4
|
+
form responses. Core of the meta-workflow system's agent composition.
|
|
5
|
+
|
|
6
|
+
Created: 2026-01-17
|
|
7
|
+
Purpose: Dynamic agent team generation
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from empathy_os.meta_workflows.models import (
|
|
14
|
+
AgentCompositionRule,
|
|
15
|
+
AgentSpec,
|
|
16
|
+
FormResponse,
|
|
17
|
+
MetaWorkflowTemplate,
|
|
18
|
+
TierStrategy,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DynamicAgentCreator:
|
|
25
|
+
"""Creates agent teams dynamically from templates and form responses.
|
|
26
|
+
|
|
27
|
+
Takes a meta-workflow template and user's form responses, then generates
|
|
28
|
+
a list of agent specifications based on the template's composition rules.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self):
|
|
32
|
+
"""Initialize the dynamic agent creator."""
|
|
33
|
+
self.creation_stats: dict[str, int] = {
|
|
34
|
+
"total_rules_evaluated": 0,
|
|
35
|
+
"agents_created": 0,
|
|
36
|
+
"rules_skipped": 0,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
def create_agents(
|
|
40
|
+
self, template: MetaWorkflowTemplate, form_response: FormResponse
|
|
41
|
+
) -> list[AgentSpec]:
|
|
42
|
+
"""Create agents from template rules and form responses.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
template: Meta-workflow template with composition rules
|
|
46
|
+
form_response: User's responses to form questions
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
List of AgentSpec instances to execute
|
|
50
|
+
|
|
51
|
+
Raises:
|
|
52
|
+
ValueError: If template or form_response is invalid
|
|
53
|
+
"""
|
|
54
|
+
if not template.agent_composition_rules:
|
|
55
|
+
logger.warning(f"Template {template.template_id} has no composition rules")
|
|
56
|
+
return []
|
|
57
|
+
|
|
58
|
+
agents = []
|
|
59
|
+
self.creation_stats["total_rules_evaluated"] = len(
|
|
60
|
+
template.agent_composition_rules
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
logger.info(
|
|
64
|
+
f"Evaluating {len(template.agent_composition_rules)} composition rules"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
for rule in template.agent_composition_rules:
|
|
68
|
+
# Check if agent should be created based on form responses
|
|
69
|
+
if rule.should_create(form_response):
|
|
70
|
+
agent = self._create_agent_from_rule(rule, form_response)
|
|
71
|
+
agents.append(agent)
|
|
72
|
+
self.creation_stats["agents_created"] += 1
|
|
73
|
+
|
|
74
|
+
logger.debug(
|
|
75
|
+
f"Created agent: {agent.role} "
|
|
76
|
+
f"(tier: {agent.tier_strategy.value}, id: {agent.agent_id})"
|
|
77
|
+
)
|
|
78
|
+
else:
|
|
79
|
+
self.creation_stats["rules_skipped"] += 1
|
|
80
|
+
logger.debug(
|
|
81
|
+
f"Skipped agent {rule.role} - conditions not met"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
logger.info(
|
|
85
|
+
f"Created {len(agents)} agents from {len(template.agent_composition_rules)} rules"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return agents
|
|
89
|
+
|
|
90
|
+
def _create_agent_from_rule(
|
|
91
|
+
self, rule: AgentCompositionRule, form_response: FormResponse
|
|
92
|
+
) -> AgentSpec:
|
|
93
|
+
"""Create an AgentSpec from a composition rule and form responses.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
rule: Agent composition rule
|
|
97
|
+
form_response: User's form responses
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
AgentSpec instance configured for execution
|
|
101
|
+
"""
|
|
102
|
+
# Map config from form responses
|
|
103
|
+
config = rule.create_agent_config(form_response)
|
|
104
|
+
|
|
105
|
+
# Create agent spec
|
|
106
|
+
agent = AgentSpec(
|
|
107
|
+
role=rule.role,
|
|
108
|
+
base_template=rule.base_template,
|
|
109
|
+
tier_strategy=rule.tier_strategy,
|
|
110
|
+
tools=rule.tools.copy(), # Copy to avoid mutation
|
|
111
|
+
config=config,
|
|
112
|
+
success_criteria=rule.success_criteria.copy(), # Copy to avoid mutation
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
return agent
|
|
116
|
+
|
|
117
|
+
def get_creation_stats(self) -> dict[str, int]:
|
|
118
|
+
"""Get statistics about agent creation.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Dictionary with creation statistics
|
|
122
|
+
"""
|
|
123
|
+
return self.creation_stats.copy()
|
|
124
|
+
|
|
125
|
+
def reset_stats(self) -> None:
|
|
126
|
+
"""Reset creation statistics."""
|
|
127
|
+
self.creation_stats = {
|
|
128
|
+
"total_rules_evaluated": 0,
|
|
129
|
+
"agents_created": 0,
|
|
130
|
+
"rules_skipped": 0,
|
|
131
|
+
}
|
|
132
|
+
logger.debug("Agent creation stats reset")
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# =============================================================================
|
|
136
|
+
# Helper functions for agent composition
|
|
137
|
+
# =============================================================================
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def group_agents_by_tier_strategy(
|
|
141
|
+
agents: list[AgentSpec],
|
|
142
|
+
) -> dict[TierStrategy, list[AgentSpec]]:
|
|
143
|
+
"""Group agents by their tier strategy.
|
|
144
|
+
|
|
145
|
+
Useful for execution planning (e.g., run all cheap_only agents first).
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
agents: List of agent specs
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Dictionary mapping TierStrategy → list of agents
|
|
152
|
+
|
|
153
|
+
Example:
|
|
154
|
+
>>> agents = [
|
|
155
|
+
... AgentSpec(role="test", base_template="generic", tier_strategy=TierStrategy.CHEAP_ONLY),
|
|
156
|
+
... AgentSpec(role="review", base_template="generic", tier_strategy=TierStrategy.PROGRESSIVE),
|
|
157
|
+
... ]
|
|
158
|
+
>>> grouped = group_agents_by_tier_strategy(agents)
|
|
159
|
+
>>> len(grouped[TierStrategy.CHEAP_ONLY])
|
|
160
|
+
1
|
|
161
|
+
"""
|
|
162
|
+
grouped: dict[TierStrategy, list[AgentSpec]] = {}
|
|
163
|
+
|
|
164
|
+
for agent in agents:
|
|
165
|
+
if agent.tier_strategy not in grouped:
|
|
166
|
+
grouped[agent.tier_strategy] = []
|
|
167
|
+
grouped[agent.tier_strategy].append(agent)
|
|
168
|
+
|
|
169
|
+
return grouped
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def estimate_agent_costs(
|
|
173
|
+
agents: list[AgentSpec], cost_per_tier: dict[str, float] | None = None
|
|
174
|
+
) -> dict[str, Any]:
|
|
175
|
+
"""Estimate total cost for executing agents.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
agents: List of agent specs
|
|
179
|
+
cost_per_tier: Optional cost mapping (tier → estimated cost)
|
|
180
|
+
Defaults to reasonable estimates
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Dictionary with cost estimates
|
|
184
|
+
|
|
185
|
+
Example:
|
|
186
|
+
>>> agents = [AgentSpec(role="test", base_template="generic", tier_strategy=TierStrategy.CHEAP_ONLY)]
|
|
187
|
+
>>> estimate_agent_costs(agents)
|
|
188
|
+
{'total_estimated_cost': 0.05, 'by_tier': {'cheap_only': 0.05}, 'agent_count': 1}
|
|
189
|
+
"""
|
|
190
|
+
if cost_per_tier is None:
|
|
191
|
+
# Default cost estimates per tier strategy
|
|
192
|
+
cost_per_tier = {
|
|
193
|
+
"cheap_only": 0.05,
|
|
194
|
+
"progressive": 0.15, # Average, might escalate
|
|
195
|
+
"capable_first": 0.25, # Starts higher
|
|
196
|
+
"premium_only": 0.40,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
total_cost = 0.0
|
|
200
|
+
cost_by_tier: dict[str, float] = {}
|
|
201
|
+
|
|
202
|
+
for agent in agents:
|
|
203
|
+
tier_key = agent.tier_strategy.value
|
|
204
|
+
agent_cost = cost_per_tier.get(tier_key, 0.10) # Default fallback
|
|
205
|
+
|
|
206
|
+
total_cost += agent_cost
|
|
207
|
+
|
|
208
|
+
if tier_key not in cost_by_tier:
|
|
209
|
+
cost_by_tier[tier_key] = 0.0
|
|
210
|
+
cost_by_tier[tier_key] += agent_cost
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
"total_estimated_cost": round(total_cost, 2),
|
|
214
|
+
"by_tier": {k: round(v, 2) for k, v in cost_by_tier.items()},
|
|
215
|
+
"agent_count": len(agents),
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def validate_agent_dependencies(agents: list[AgentSpec]) -> list[str]:
|
|
220
|
+
"""Validate that agent dependencies are satisfied.
|
|
221
|
+
|
|
222
|
+
Checks for common dependency issues (e.g., publisher needs package_builder).
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
agents: List of agent specs
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
List of validation warnings (empty if all OK)
|
|
229
|
+
|
|
230
|
+
Example:
|
|
231
|
+
>>> agents = [AgentSpec(role="publisher", base_template="generic", tier_strategy=TierStrategy.CHEAP_ONLY)]
|
|
232
|
+
>>> warnings = validate_agent_dependencies(agents)
|
|
233
|
+
>>> len(warnings) > 0 # Should warn about missing package_builder
|
|
234
|
+
True
|
|
235
|
+
"""
|
|
236
|
+
warnings = []
|
|
237
|
+
agent_roles = {agent.role for agent in agents}
|
|
238
|
+
|
|
239
|
+
# Common dependencies
|
|
240
|
+
dependencies = {
|
|
241
|
+
"publisher": ["package_builder"],
|
|
242
|
+
"changelog_updater": ["version_manager"],
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
for agent in agents:
|
|
246
|
+
if agent.role in dependencies:
|
|
247
|
+
for required_role in dependencies[agent.role]:
|
|
248
|
+
if required_role not in agent_roles:
|
|
249
|
+
warnings.append(
|
|
250
|
+
f"Agent '{agent.role}' typically requires '{required_role}' "
|
|
251
|
+
f"but it's not in the agent list"
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
return warnings
|