empathy-framework 4.6.3__py3-none-any.whl → 4.6.5__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.
Files changed (65) hide show
  1. {empathy_framework-4.6.3.dist-info → empathy_framework-4.6.5.dist-info}/METADATA +53 -11
  2. {empathy_framework-4.6.3.dist-info → empathy_framework-4.6.5.dist-info}/RECORD +32 -57
  3. empathy_llm_toolkit/agent_factory/crews/health_check.py +7 -4
  4. empathy_llm_toolkit/agent_factory/decorators.py +3 -2
  5. empathy_llm_toolkit/agent_factory/memory_integration.py +6 -2
  6. empathy_llm_toolkit/contextual_patterns.py +5 -2
  7. empathy_llm_toolkit/git_pattern_extractor.py +8 -4
  8. empathy_llm_toolkit/providers.py +4 -3
  9. empathy_os/__init__.py +1 -1
  10. empathy_os/cli/__init__.py +306 -0
  11. empathy_os/cli/__main__.py +26 -0
  12. empathy_os/cli/commands/__init__.py +8 -0
  13. empathy_os/cli/commands/inspection.py +48 -0
  14. empathy_os/cli/commands/memory.py +56 -0
  15. empathy_os/cli/commands/provider.py +86 -0
  16. empathy_os/cli/commands/utilities.py +94 -0
  17. empathy_os/cli/core.py +32 -0
  18. empathy_os/cli.py +18 -6
  19. empathy_os/cli_unified.py +19 -3
  20. empathy_os/memory/short_term.py +12 -2
  21. empathy_os/project_index/scanner.py +151 -49
  22. empathy_os/socratic/visual_editor.py +9 -4
  23. empathy_os/workflows/bug_predict.py +70 -1
  24. empathy_os/workflows/pr_review.py +6 -0
  25. empathy_os/workflows/security_audit.py +13 -0
  26. empathy_os/workflows/tier_tracking.py +50 -2
  27. wizards/discharge_summary_wizard.py +4 -2
  28. wizards/incident_report_wizard.py +4 -2
  29. empathy_os/meta_workflows/agent_creator 2.py +0 -254
  30. empathy_os/meta_workflows/builtin_templates 2.py +0 -567
  31. empathy_os/meta_workflows/cli_meta_workflows 2.py +0 -1551
  32. empathy_os/meta_workflows/form_engine 2.py +0 -304
  33. empathy_os/meta_workflows/intent_detector 2.py +0 -298
  34. empathy_os/meta_workflows/pattern_learner 2.py +0 -754
  35. empathy_os/meta_workflows/session_context 2.py +0 -398
  36. empathy_os/meta_workflows/template_registry 2.py +0 -229
  37. empathy_os/meta_workflows/workflow 2.py +0 -980
  38. empathy_os/orchestration/pattern_learner 2.py +0 -699
  39. empathy_os/orchestration/real_tools 2.py +0 -938
  40. empathy_os/socratic/__init__ 2.py +0 -273
  41. empathy_os/socratic/ab_testing 2.py +0 -969
  42. empathy_os/socratic/blueprint 2.py +0 -532
  43. empathy_os/socratic/cli 2.py +0 -689
  44. empathy_os/socratic/collaboration 2.py +0 -1112
  45. empathy_os/socratic/domain_templates 2.py +0 -916
  46. empathy_os/socratic/embeddings 2.py +0 -734
  47. empathy_os/socratic/engine 2.py +0 -729
  48. empathy_os/socratic/explainer 2.py +0 -663
  49. empathy_os/socratic/feedback 2.py +0 -767
  50. empathy_os/socratic/forms 2.py +0 -624
  51. empathy_os/socratic/generator 2.py +0 -716
  52. empathy_os/socratic/llm_analyzer 2.py +0 -635
  53. empathy_os/socratic/mcp_server 2.py +0 -751
  54. empathy_os/socratic/session 2.py +0 -306
  55. empathy_os/socratic/storage 2.py +0 -635
  56. empathy_os/socratic/success 2.py +0 -719
  57. empathy_os/socratic/visual_editor 2.py +0 -812
  58. empathy_os/socratic/web_ui 2.py +0 -925
  59. empathy_os/workflows/batch_processing 2.py +0 -310
  60. empathy_os/workflows/release_prep_crew 2.py +0 -968
  61. empathy_os/workflows/test_coverage_boost_crew 2.py +0 -848
  62. {empathy_framework-4.6.3.dist-info → empathy_framework-4.6.5.dist-info}/WHEEL +0 -0
  63. {empathy_framework-4.6.3.dist-info → empathy_framework-4.6.5.dist-info}/entry_points.txt +0 -0
  64. {empathy_framework-4.6.3.dist-info → empathy_framework-4.6.5.dist-info}/licenses/LICENSE +0 -0
  65. {empathy_framework-4.6.3.dist-info → empathy_framework-4.6.5.dist-info}/top_level.txt +0 -0
@@ -1,398 +0,0 @@
1
- """Session Context for Meta-Workflows
2
-
3
- Tracks user choices and preferences across workflow executions using short-term memory.
4
- Enables intelligent defaults and personalized recommendations based on recent history.
5
-
6
- Features:
7
- - Record form choices per template
8
- - Suggest defaults based on recent choices
9
- - Session isolation per user
10
- - TTL-based expiration (1 hour default)
11
- - Graceful fallback when memory unavailable
12
-
13
- Usage:
14
- from empathy_os.meta_workflows.session_context import SessionContext
15
- from empathy_os.memory.unified import UnifiedMemory
16
-
17
- memory = UnifiedMemory(user_id="user@example.com")
18
- session = SessionContext(memory=memory)
19
-
20
- # Record choice
21
- session.record_choice("python_package_publish", "has_tests", "Yes")
22
-
23
- # Get suggested defaults
24
- defaults = session.suggest_defaults("python_package_publish")
25
-
26
- Copyright 2025 Smart AI Memory, LLC
27
- Licensed under Fair Source 0.9
28
- """
29
-
30
- import logging
31
- import uuid
32
- from datetime import datetime
33
- from typing import TYPE_CHECKING, Any
34
-
35
- if TYPE_CHECKING:
36
- from empathy_os.memory.unified import UnifiedMemory
37
- from empathy_os.meta_workflows.models import FormSchema
38
-
39
- logger = logging.getLogger(__name__)
40
-
41
-
42
- class SessionContext:
43
- """Track session-level patterns and user preferences.
44
-
45
- Uses short-term memory to record form choices and suggest intelligent
46
- defaults for subsequent workflow executions.
47
-
48
- Attributes:
49
- memory: UnifiedMemory instance for storage
50
- session_id: Unique session identifier
51
- user_id: User identifier (from memory)
52
- default_ttl: Time-to-live for session data (seconds)
53
- """
54
-
55
- def __init__(
56
- self,
57
- memory: "UnifiedMemory | None" = None,
58
- session_id: str | None = None,
59
- default_ttl: int = 3600,
60
- ):
61
- """Initialize session context.
62
-
63
- Args:
64
- memory: UnifiedMemory instance (optional, graceful fallback if None)
65
- session_id: Optional session ID (generates new if None)
66
- default_ttl: TTL for session data in seconds (default: 1 hour)
67
- """
68
- self.memory = memory
69
- self.session_id = session_id or str(uuid.uuid4())
70
- self.user_id = memory.user_id if memory else "anonymous"
71
- self.default_ttl = default_ttl
72
-
73
- logger.info(
74
- f"SessionContext initialized: session_id={self.session_id}, "
75
- f"user_id={self.user_id}, memory={'enabled' if memory else 'disabled'}"
76
- )
77
-
78
- def record_choice(
79
- self,
80
- template_id: str,
81
- question_id: str,
82
- choice: Any,
83
- ttl: int | None = None,
84
- ) -> bool:
85
- """Record a form choice in short-term memory.
86
-
87
- Args:
88
- template_id: Template identifier
89
- question_id: Question identifier
90
- choice: User's choice (any JSON-serializable type)
91
- ttl: Optional TTL override (uses default_ttl if None)
92
-
93
- Returns:
94
- True if recorded successfully, False otherwise
95
- """
96
- if not self.memory:
97
- logger.debug("Memory not available, cannot record choice")
98
- return False
99
-
100
- try:
101
- key = self._make_choice_key(template_id, question_id)
102
- value = {
103
- "choice": choice,
104
- "timestamp": datetime.utcnow().isoformat(),
105
- "template_id": template_id,
106
- "question_id": question_id,
107
- }
108
-
109
- self.memory.stash(key, value, ttl_seconds=ttl or self.default_ttl)
110
-
111
- logger.debug(
112
- f"Recorded choice: template={template_id}, "
113
- f"question={question_id}, choice={choice}"
114
- )
115
- return True
116
-
117
- except Exception as e:
118
- logger.error(f"Failed to record choice: {e}")
119
- return False
120
-
121
- def get_recent_choice(
122
- self,
123
- template_id: str,
124
- question_id: str,
125
- ) -> Any | None:
126
- """Get the most recent choice for a specific question.
127
-
128
- Args:
129
- template_id: Template identifier
130
- question_id: Question identifier
131
-
132
- Returns:
133
- Most recent choice, or None if not found
134
- """
135
- if not self.memory:
136
- return None
137
-
138
- try:
139
- key = self._make_choice_key(template_id, question_id)
140
- value = self.memory.retrieve(key)
141
-
142
- if value and isinstance(value, dict):
143
- return value.get("choice")
144
-
145
- return None
146
-
147
- except Exception as e:
148
- logger.debug(f"Failed to get recent choice: {e}")
149
- return None
150
-
151
- def get_recent_choices(
152
- self,
153
- template_id: str,
154
- ) -> dict[str, Any]:
155
- """Get all recent choices for a template.
156
-
157
- Args:
158
- template_id: Template identifier
159
-
160
- Returns:
161
- Dict mapping question_id -> choice
162
- """
163
- if not self.memory:
164
- return {}
165
-
166
- try:
167
- # Get all keys for this template and session
168
- pattern = f"session:{self.session_id}:form:{template_id}:*"
169
-
170
- # Note: This requires pattern matching support in short-term memory
171
- # For now, we return empty dict (could be enhanced later)
172
- logger.debug(f"Pattern matching not yet implemented: {pattern}")
173
- return {}
174
-
175
- except Exception as e:
176
- logger.error(f"Failed to get recent choices: {e}")
177
- return {}
178
-
179
- def suggest_defaults(
180
- self,
181
- template_id: str,
182
- form_schema: "FormSchema | None" = None,
183
- ) -> dict[str, Any]:
184
- """Suggest default values based on recent choices.
185
-
186
- Args:
187
- template_id: Template identifier
188
- form_schema: Optional form schema for validation
189
-
190
- Returns:
191
- Dict mapping question_id -> suggested_default
192
- """
193
- if not self.memory:
194
- return {}
195
-
196
- try:
197
- # Get recent choices for this template
198
- recent_choices = self.get_recent_choices(template_id)
199
-
200
- # If form_schema provided, validate suggestions
201
- if form_schema:
202
- validated_suggestions = {}
203
- for question in form_schema.questions:
204
- if question.id in recent_choices:
205
- # Validate that suggestion is valid for question type
206
- choice = recent_choices[question.id]
207
- if self._validate_choice(choice, question):
208
- validated_suggestions[question.id] = choice
209
-
210
- return validated_suggestions
211
-
212
- return recent_choices
213
-
214
- except Exception as e:
215
- logger.error(f"Failed to suggest defaults: {e}")
216
- return {}
217
-
218
- def record_execution(
219
- self,
220
- template_id: str,
221
- run_id: str,
222
- success: bool,
223
- cost: float,
224
- duration: float,
225
- ttl: int | None = None,
226
- ) -> bool:
227
- """Record workflow execution metadata.
228
-
229
- Args:
230
- template_id: Template identifier
231
- run_id: Execution run ID
232
- success: Whether execution succeeded
233
- cost: Total cost in USD
234
- duration: Duration in seconds
235
- ttl: Optional TTL override
236
-
237
- Returns:
238
- True if recorded successfully
239
- """
240
- if not self.memory:
241
- return False
242
-
243
- try:
244
- key = f"session:{self.session_id}:execution:{run_id}"
245
- value = {
246
- "template_id": template_id,
247
- "run_id": run_id,
248
- "success": success,
249
- "cost": cost,
250
- "duration": duration,
251
- "timestamp": datetime.utcnow().isoformat(),
252
- }
253
-
254
- self.memory.stash(key, value, ttl_seconds=ttl or self.default_ttl)
255
-
256
- logger.debug(f"Recorded execution: run_id={run_id}, success={success}")
257
- return True
258
-
259
- except Exception as e:
260
- logger.error(f"Failed to record execution: {e}")
261
- return False
262
-
263
- def get_session_stats(self) -> dict[str, Any]:
264
- """Get statistics for current session.
265
-
266
- Returns:
267
- Dict with session statistics (executions, success rate, etc.)
268
- """
269
- if not self.memory:
270
- return {"session_id": self.session_id, "memory_enabled": False}
271
-
272
- try:
273
- stats = {
274
- "session_id": self.session_id,
275
- "user_id": self.user_id,
276
- "memory_enabled": True,
277
- "executions": 0,
278
- "successful_executions": 0,
279
- "total_cost": 0.0,
280
- "total_duration": 0.0,
281
- }
282
-
283
- # Note: Would need to query all execution records
284
- # For now, return basic stats
285
- return stats
286
-
287
- except Exception as e:
288
- logger.error(f"Failed to get session stats: {e}")
289
- return {"session_id": self.session_id, "error": str(e)}
290
-
291
- def clear_session(self) -> bool:
292
- """Clear all session data from memory.
293
-
294
- Returns:
295
- True if cleared successfully
296
- """
297
- if not self.memory:
298
- return False
299
-
300
- try:
301
- # Note: Would need to delete all keys matching session pattern
302
- # For now, just log
303
- logger.info(f"Session clear requested: {self.session_id}")
304
- # Implementation would require pattern delete support
305
- return True
306
-
307
- except Exception as e:
308
- logger.error(f"Failed to clear session: {e}")
309
- return False
310
-
311
- # =========================================================================
312
- # HELPER METHODS
313
- # =========================================================================
314
-
315
- def _make_choice_key(self, template_id: str, question_id: str) -> str:
316
- """Create Redis key for a form choice.
317
-
318
- Args:
319
- template_id: Template identifier
320
- question_id: Question identifier
321
-
322
- Returns:
323
- Redis key string
324
- """
325
- return f"session:{self.session_id}:form:{template_id}:{question_id}"
326
-
327
- def _validate_choice(self, choice: Any, question: Any) -> bool:
328
- """Validate that a choice is valid for a question.
329
-
330
- Args:
331
- choice: User's choice
332
- question: FormQuestion object
333
-
334
- Returns:
335
- True if valid, False otherwise
336
- """
337
- try:
338
- # Basic validation - could be enhanced
339
- if hasattr(question, 'options') and question.options:
340
- # Check if choice is in options (only if options are defined)
341
- if isinstance(choice, list):
342
- # Multi-select - all choices must be in options
343
- return all(c in question.options for c in choice)
344
- else:
345
- # Single-select - choice must be in options
346
- return choice in question.options
347
-
348
- # No specific validation - assume valid
349
- return True
350
-
351
- except Exception:
352
- return False
353
-
354
-
355
- # =========================================================================
356
- # CONVENIENCE FUNCTIONS
357
- # =========================================================================
358
-
359
-
360
- def create_session_context(
361
- memory: "UnifiedMemory | None" = None,
362
- session_id: str | None = None,
363
- ) -> SessionContext:
364
- """Create a new session context.
365
-
366
- Convenience function for creating SessionContext instances.
367
-
368
- Args:
369
- memory: UnifiedMemory instance (optional)
370
- session_id: Optional session ID
371
-
372
- Returns:
373
- SessionContext instance
374
- """
375
- return SessionContext(memory=memory, session_id=session_id)
376
-
377
-
378
- def get_session_defaults(
379
- template_id: str,
380
- form_schema: "FormSchema | None" = None,
381
- memory: "UnifiedMemory | None" = None,
382
- session_id: str | None = None,
383
- ) -> dict[str, Any]:
384
- """Get suggested defaults for a template.
385
-
386
- Convenience function for getting defaults without creating SessionContext.
387
-
388
- Args:
389
- template_id: Template identifier
390
- form_schema: Optional form schema
391
- memory: Optional UnifiedMemory instance
392
- session_id: Optional session ID
393
-
394
- Returns:
395
- Dict of suggested defaults
396
- """
397
- session = SessionContext(memory=memory, session_id=session_id)
398
- return session.suggest_defaults(template_id, form_schema)
@@ -1,229 +0,0 @@
1
- """Template registry for meta-workflows.
2
-
3
- Handles loading, saving, and discovering meta-workflow templates.
4
-
5
- Created: 2026-01-17
6
- Updated: 2026-01-18 (v4.3.0 - Added built-in templates)
7
- Purpose: Manage reusable workflow templates
8
- """
9
-
10
- import importlib.util
11
- import logging
12
- from pathlib import Path
13
-
14
- from empathy_os.meta_workflows.builtin_templates import (
15
- BUILTIN_TEMPLATES,
16
- get_builtin_template,
17
- list_builtin_templates,
18
- )
19
- from empathy_os.meta_workflows.models import MetaWorkflowTemplate
20
-
21
- logger = logging.getLogger(__name__)
22
-
23
- # Import _validate_file_path from parent config.py (not config package)
24
- _config_py_path = Path(__file__).parent.parent / "config.py"
25
- _spec = importlib.util.spec_from_file_location("_config_module", _config_py_path)
26
- if _spec and _spec.loader:
27
- _config_module = importlib.util.module_from_spec(_spec)
28
- _spec.loader.exec_module(_config_module)
29
- _validate_file_path = _config_module._validate_file_path
30
- else:
31
- # Fallback: simple validation if import fails
32
- def _validate_file_path(path: str, allowed_dir: str | None = None) -> Path:
33
- if not path:
34
- raise ValueError("path must be non-empty")
35
- return Path(path).resolve()
36
-
37
-
38
- class TemplateRegistry:
39
- """Registry for meta-workflow templates.
40
-
41
- Manages template storage, loading, and discovery.
42
- Templates are stored as JSON files in a directory.
43
-
44
- Attributes:
45
- storage_dir: Directory where templates are stored
46
- """
47
-
48
- def __init__(self, storage_dir: str | None = None):
49
- """Initialize template registry.
50
-
51
- Args:
52
- storage_dir: Directory for template storage
53
- (default: .empathy/meta_workflows/templates/)
54
-
55
- Raises:
56
- ValueError: If storage_dir is invalid
57
- """
58
- if storage_dir is None:
59
- storage_dir = str(Path.home() / ".empathy" / "meta_workflows" / "templates")
60
-
61
- # Validate and create storage directory
62
- self.storage_dir = Path(_validate_file_path(storage_dir))
63
- self.storage_dir.mkdir(parents=True, exist_ok=True)
64
-
65
- logger.info(f"Template registry initialized at: {self.storage_dir}")
66
-
67
- def load_template(self, template_id: str) -> MetaWorkflowTemplate | None:
68
- """Load a template by ID.
69
-
70
- Checks built-in templates first, then user templates.
71
-
72
- Args:
73
- template_id: ID of template to load
74
-
75
- Returns:
76
- MetaWorkflowTemplate if found, None otherwise
77
-
78
- Raises:
79
- ValueError: If template file is invalid or corrupted
80
- """
81
- # Check built-in templates first
82
- builtin = get_builtin_template(template_id)
83
- if builtin is not None:
84
- logger.info(f"Loaded built-in template: {template_id}")
85
- return builtin
86
-
87
- # Fall back to user templates
88
- template_path = self.storage_dir / f"{template_id}.json"
89
-
90
- if not template_path.exists():
91
- logger.warning(f"Template not found: {template_id}")
92
- return None
93
-
94
- try:
95
- json_str = template_path.read_text(encoding="utf-8")
96
- template = MetaWorkflowTemplate.from_json(json_str)
97
- logger.info(f"Loaded template: {template_id}")
98
- return template
99
-
100
- except (ValueError, KeyError) as e:
101
- logger.error(f"Failed to load template {template_id}: {e}")
102
- raise ValueError(f"Invalid template file {template_id}: {e}") from e
103
-
104
- def save_template(self, template: MetaWorkflowTemplate) -> Path:
105
- """Save a template to disk.
106
-
107
- Args:
108
- template: Template to save
109
-
110
- Returns:
111
- Path where template was saved
112
-
113
- Raises:
114
- ValueError: If template is invalid or path is unsafe
115
- OSError: If write operation fails
116
- """
117
- template_path = self.storage_dir / f"{template.template_id}.json"
118
-
119
- # Validate path (prevent path traversal)
120
- validated_path = _validate_file_path(str(template_path))
121
-
122
- try:
123
- json_str = template.to_json()
124
- validated_path.write_text(json_str, encoding="utf-8")
125
- logger.info(f"Saved template: {template.template_id} → {validated_path}")
126
- return validated_path
127
-
128
- except OSError as e:
129
- logger.error(f"Failed to save template {template.template_id}: {e}")
130
- raise
131
-
132
- def list_templates(self, include_builtin: bool = True) -> list[str]:
133
- """List all available template IDs.
134
-
135
- Args:
136
- include_builtin: Whether to include built-in templates (default: True)
137
-
138
- Returns:
139
- List of template IDs (sorted, built-in templates marked with *)
140
- """
141
- # User templates
142
- template_files = self.storage_dir.glob("*.json")
143
- template_ids = set(f.stem for f in template_files)
144
-
145
- # Add built-in templates
146
- if include_builtin:
147
- template_ids.update(list_builtin_templates())
148
-
149
- result = sorted(template_ids)
150
- logger.debug(f"Found {len(result)} templates ({len(list_builtin_templates())} built-in)")
151
- return result
152
-
153
- def is_builtin(self, template_id: str) -> bool:
154
- """Check if a template is built-in.
155
-
156
- Args:
157
- template_id: ID of template to check
158
-
159
- Returns:
160
- True if template is built-in
161
- """
162
- return template_id in BUILTIN_TEMPLATES
163
-
164
- def get_template_info(self, template_id: str) -> dict | None:
165
- """Get basic info about a template without loading it fully.
166
-
167
- Args:
168
- template_id: ID of template
169
-
170
- Returns:
171
- Dictionary with basic template info, or None if not found
172
- """
173
- template = self.load_template(template_id)
174
- if template is None:
175
- return None
176
-
177
- return {
178
- "template_id": template.template_id,
179
- "name": template.name,
180
- "description": template.description,
181
- "version": template.version,
182
- "tags": template.tags,
183
- "author": template.author,
184
- "estimated_cost_range": template.estimated_cost_range,
185
- "estimated_duration_minutes": template.estimated_duration_minutes,
186
- "question_count": len(template.form_schema.questions),
187
- "agent_rule_count": len(template.agent_composition_rules),
188
- }
189
-
190
- def delete_template(self, template_id: str) -> bool:
191
- """Delete a template.
192
-
193
- Args:
194
- template_id: ID of template to delete
195
-
196
- Returns:
197
- True if deleted, False if not found
198
-
199
- Raises:
200
- OSError: If delete operation fails
201
- """
202
- template_path = self.storage_dir / f"{template_id}.json"
203
-
204
- if not template_path.exists():
205
- logger.warning(f"Template not found for deletion: {template_id}")
206
- return False
207
-
208
- try:
209
- template_path.unlink()
210
- logger.info(f"Deleted template: {template_id}")
211
- return True
212
-
213
- except OSError as e:
214
- logger.error(f"Failed to delete template {template_id}: {e}")
215
- raise
216
-
217
-
218
- # =============================================================================
219
- # Module-level helpers
220
- # =============================================================================
221
-
222
-
223
- def get_default_registry() -> TemplateRegistry:
224
- """Get default template registry instance.
225
-
226
- Returns:
227
- TemplateRegistry using default storage location
228
- """
229
- return TemplateRegistry()