empathy-framework 4.7.1__py3-none-any.whl → 4.8.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.
Files changed (90) hide show
  1. {empathy_framework-4.7.1.dist-info → empathy_framework-4.8.0.dist-info}/METADATA +65 -2
  2. {empathy_framework-4.7.1.dist-info → empathy_framework-4.8.0.dist-info}/RECORD +73 -52
  3. {empathy_framework-4.7.1.dist-info → empathy_framework-4.8.0.dist-info}/WHEEL +1 -1
  4. {empathy_framework-4.7.1.dist-info → empathy_framework-4.8.0.dist-info}/entry_points.txt +2 -1
  5. {empathy_framework-4.7.1.dist-info → empathy_framework-4.8.0.dist-info}/top_level.txt +0 -1
  6. empathy_os/__init__.py +2 -0
  7. empathy_os/cache/hash_only.py +6 -3
  8. empathy_os/cache/hybrid.py +6 -3
  9. empathy_os/cli/__init__.py +128 -238
  10. empathy_os/cli/__main__.py +5 -33
  11. empathy_os/cli/commands/__init__.py +1 -8
  12. empathy_os/cli/commands/help.py +331 -0
  13. empathy_os/cli/commands/info.py +140 -0
  14. empathy_os/cli/commands/inspect.py +437 -0
  15. empathy_os/cli/commands/metrics.py +92 -0
  16. empathy_os/cli/commands/orchestrate.py +184 -0
  17. empathy_os/cli/commands/patterns.py +207 -0
  18. empathy_os/cli/commands/provider.py +93 -81
  19. empathy_os/cli/commands/setup.py +96 -0
  20. empathy_os/cli/commands/status.py +235 -0
  21. empathy_os/cli/commands/sync.py +166 -0
  22. empathy_os/cli/commands/tier.py +121 -0
  23. empathy_os/cli/commands/workflow.py +574 -0
  24. empathy_os/cli/parsers/__init__.py +62 -0
  25. empathy_os/cli/parsers/help.py +41 -0
  26. empathy_os/cli/parsers/info.py +26 -0
  27. empathy_os/cli/parsers/inspect.py +66 -0
  28. empathy_os/cli/parsers/metrics.py +42 -0
  29. empathy_os/cli/parsers/orchestrate.py +61 -0
  30. empathy_os/cli/parsers/patterns.py +54 -0
  31. empathy_os/cli/parsers/provider.py +40 -0
  32. empathy_os/cli/parsers/setup.py +42 -0
  33. empathy_os/cli/parsers/status.py +47 -0
  34. empathy_os/cli/parsers/sync.py +31 -0
  35. empathy_os/cli/parsers/tier.py +33 -0
  36. empathy_os/cli/parsers/workflow.py +77 -0
  37. empathy_os/cli/utils/__init__.py +1 -0
  38. empathy_os/cli/utils/data.py +242 -0
  39. empathy_os/cli/utils/helpers.py +68 -0
  40. empathy_os/{cli.py → cli_legacy.py} +27 -27
  41. empathy_os/cli_minimal.py +662 -0
  42. empathy_os/cli_router.py +384 -0
  43. empathy_os/cli_unified.py +38 -2
  44. empathy_os/memory/__init__.py +19 -5
  45. empathy_os/memory/short_term.py +14 -404
  46. empathy_os/memory/types.py +437 -0
  47. empathy_os/memory/unified.py +61 -48
  48. empathy_os/models/fallback.py +1 -1
  49. empathy_os/models/provider_config.py +59 -344
  50. empathy_os/models/registry.py +31 -180
  51. empathy_os/monitoring/alerts.py +14 -20
  52. empathy_os/monitoring/alerts_cli.py +24 -7
  53. empathy_os/project_index/__init__.py +2 -0
  54. empathy_os/project_index/index.py +210 -5
  55. empathy_os/project_index/scanner.py +45 -14
  56. empathy_os/project_index/scanner_parallel.py +291 -0
  57. empathy_os/socratic/ab_testing.py +1 -1
  58. empathy_os/workflows/__init__.py +31 -2
  59. empathy_os/workflows/base.py +349 -325
  60. empathy_os/workflows/bug_predict.py +8 -0
  61. empathy_os/workflows/builder.py +273 -0
  62. empathy_os/workflows/caching.py +253 -0
  63. empathy_os/workflows/code_review_pipeline.py +1 -0
  64. empathy_os/workflows/history.py +510 -0
  65. empathy_os/workflows/output.py +410 -0
  66. empathy_os/workflows/perf_audit.py +125 -19
  67. empathy_os/workflows/progress.py +324 -22
  68. empathy_os/workflows/routing.py +168 -0
  69. empathy_os/workflows/secure_release.py +1 -0
  70. empathy_os/workflows/security_audit.py +190 -0
  71. empathy_os/workflows/security_audit_phase3.py +328 -0
  72. empathy_os/workflows/telemetry_mixin.py +269 -0
  73. empathy_os/dashboard/__init__.py +0 -15
  74. empathy_os/dashboard/server.py +0 -941
  75. patterns/README.md +0 -119
  76. patterns/__init__.py +0 -95
  77. patterns/behavior.py +0 -298
  78. patterns/code_review_memory.json +0 -441
  79. patterns/core.py +0 -97
  80. patterns/debugging.json +0 -3763
  81. patterns/empathy.py +0 -268
  82. patterns/health_check_memory.json +0 -505
  83. patterns/input.py +0 -161
  84. patterns/memory_graph.json +0 -8
  85. patterns/refactoring_memory.json +0 -1113
  86. patterns/registry.py +0 -663
  87. patterns/security_memory.json +0 -8
  88. patterns/structural.py +0 -415
  89. patterns/validation.py +0 -194
  90. {empathy_framework-4.7.1.dist-info → empathy_framework-4.8.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,384 @@
1
+ """Hybrid CLI Router - Slash Commands + Natural Language
2
+
3
+ Supports both structured slash commands and natural language routing:
4
+ - Slash commands: empathy /dev commit
5
+ - Natural language: empathy "commit my changes"
6
+ - Single word: empathy commit (infers /dev commit)
7
+
8
+ Copyright 2025 Smart-AI-Memory
9
+ Licensed under Fair Source License 0.9
10
+ """
11
+
12
+ import os
13
+ import re
14
+ from dataclasses import dataclass
15
+ from pathlib import Path
16
+ from typing import Any
17
+
18
+ import yaml
19
+
20
+ from empathy_os.routing import SmartRouter
21
+
22
+
23
+ @dataclass
24
+ class RoutingPreference:
25
+ """User's learned routing preferences."""
26
+
27
+ keyword: str
28
+ slash_command: str
29
+ usage_count: int = 0
30
+ confidence: float = 1.0
31
+
32
+
33
+ class HybridRouter:
34
+ """Routes user input to appropriate commands or workflows.
35
+
36
+ Supports three input modes:
37
+ 1. Slash commands: /dev commit (direct, structured)
38
+ 2. Single words: commit (infers /dev commit from context)
39
+ 3. Natural language: "I need to commit" (uses SmartRouter)
40
+
41
+ Example:
42
+ router = HybridRouter()
43
+
44
+ # Direct slash command
45
+ result = await router.route("/dev commit")
46
+ # → {type: "slash", hub: "dev", command: "commit"}
47
+
48
+ # Single word inference
49
+ result = await router.route("commit")
50
+ # → {type: "inferred", hub: "dev", command: "commit", confidence: 0.9}
51
+
52
+ # Natural language
53
+ result = await router.route("I want to commit my changes")
54
+ # → {type: "natural", workflow: "commit", slash_equivalent: "/dev commit"}
55
+ """
56
+
57
+ def __init__(self, preferences_path: str | None = None):
58
+ """Initialize hybrid router.
59
+
60
+ Args:
61
+ preferences_path: Path to user preferences YAML
62
+ Default: .empathy/routing_preferences.yaml
63
+ """
64
+ self.preferences_path = Path(
65
+ preferences_path or Path.home() / ".empathy" / "routing_preferences.yaml"
66
+ )
67
+ self.smart_router = SmartRouter()
68
+ self.preferences: dict[str, RoutingPreference] = {}
69
+
70
+ # Command to slash command mapping
71
+ self._command_map = {
72
+ # Dev commands
73
+ "commit": "/dev commit",
74
+ "review": "/dev review-pr",
75
+ "review-pr": "/dev review-pr",
76
+ "refactor": "/dev refactor",
77
+ "perf": "/dev perf-audit",
78
+ "perf-audit": "/dev perf-audit",
79
+ # Testing commands
80
+ "test": "/testing run",
81
+ "tests": "/testing run",
82
+ "coverage": "/testing coverage",
83
+ "generate-tests": "/testing gen",
84
+ "test-gen": "/testing gen",
85
+ # Learning commands
86
+ "evaluate": "/learning evaluate",
87
+ "patterns": "/learning patterns",
88
+ "improve": "/learning improve",
89
+ # Workflow commands
90
+ "security": "/workflows security-audit",
91
+ "security-audit": "/workflows security-audit",
92
+ "bug-predict": "/workflows bug-predict",
93
+ "bugs": "/workflows bug-predict",
94
+ # Context commands
95
+ "status": "/context status",
96
+ "memory": "/context memory",
97
+ "state": "/context state",
98
+ # Doc commands
99
+ "explain": "/docs explain",
100
+ "document": "/docs generate",
101
+ "overview": "/docs overview",
102
+ }
103
+
104
+ # Hub descriptions for disambiguation
105
+ self._hub_descriptions = {
106
+ "dev": "Development tools (commits, reviews, refactoring)",
107
+ "testing": "Test generation and coverage analysis",
108
+ "learning": "Session evaluation and pattern learning",
109
+ "workflows": "AI-powered workflows (security, bugs, performance)",
110
+ "context": "Memory and state management",
111
+ "docs": "Documentation generation",
112
+ "plan": "Development planning and architecture",
113
+ "release": "Release preparation and publishing",
114
+ "utilities": "Utility tools (profiling, dependencies)",
115
+ }
116
+
117
+ self._load_preferences()
118
+
119
+ def _load_preferences(self) -> None:
120
+ """Load user routing preferences from disk."""
121
+ if not self.preferences_path.exists():
122
+ return
123
+
124
+ try:
125
+ with open(self.preferences_path) as f:
126
+ data = yaml.safe_load(f) or {}
127
+
128
+ for keyword, pref_data in data.get("preferences", {}).items():
129
+ self.preferences[keyword] = RoutingPreference(
130
+ keyword=keyword,
131
+ slash_command=pref_data["slash_command"],
132
+ usage_count=pref_data.get("usage_count", 0),
133
+ confidence=pref_data.get("confidence", 1.0),
134
+ )
135
+ except Exception as e:
136
+ print(f"Warning: Could not load routing preferences: {e}")
137
+
138
+ def _save_preferences(self) -> None:
139
+ """Save user routing preferences to disk."""
140
+ self.preferences_path.parent.mkdir(parents=True, exist_ok=True)
141
+
142
+ data = {
143
+ "preferences": {
144
+ pref.keyword: {
145
+ "slash_command": pref.slash_command,
146
+ "usage_count": pref.usage_count,
147
+ "confidence": pref.confidence,
148
+ }
149
+ for pref in self.preferences.values()
150
+ }
151
+ }
152
+
153
+ with open(self.preferences_path, "w") as f:
154
+ yaml.dump(data, f, default_flow_style=False)
155
+
156
+ async def route(
157
+ self, user_input: str, context: dict[str, Any] | None = None
158
+ ) -> dict[str, Any]:
159
+ """Route user input to appropriate command or workflow.
160
+
161
+ Args:
162
+ user_input: User's input (slash command, keyword, or natural language)
163
+ context: Optional context (current file, project info, etc.)
164
+
165
+ Returns:
166
+ Routing result with type, command/workflow, and metadata
167
+ """
168
+ user_input = user_input.strip()
169
+
170
+ # Level 1: Slash command (direct execution)
171
+ if user_input.startswith("/"):
172
+ return self._route_slash_command(user_input)
173
+
174
+ # Level 2: Single word or known command (inference)
175
+ words = user_input.split()
176
+ if len(words) <= 2:
177
+ inferred = self._infer_command(user_input)
178
+ if inferred:
179
+ return inferred
180
+
181
+ # Level 3: Natural language (SmartRouter)
182
+ return await self._route_natural_language(user_input, context)
183
+
184
+ def _route_slash_command(self, command: str) -> dict[str, Any]:
185
+ """Route slash command directly.
186
+
187
+ Args:
188
+ command: Slash command like "/dev commit"
189
+
190
+ Returns:
191
+ Routing result
192
+ """
193
+ parts = command[1:].split(maxsplit=1) # Remove leading /
194
+ hub = parts[0] if parts else "help"
195
+ subcommand = parts[1] if len(parts) > 1 else None
196
+
197
+ return {
198
+ "type": "slash",
199
+ "hub": hub,
200
+ "command": subcommand,
201
+ "original": command,
202
+ "confidence": 1.0,
203
+ }
204
+
205
+ def _infer_command(self, keyword: str) -> dict[str, Any] | None:
206
+ """Infer slash command from keyword or short phrase.
207
+
208
+ Args:
209
+ keyword: Single word or short phrase
210
+
211
+ Returns:
212
+ Routing result if inference successful, None otherwise
213
+ """
214
+ keyword_lower = keyword.lower().strip()
215
+
216
+ # Check learned preferences first
217
+ if keyword_lower in self.preferences:
218
+ pref = self.preferences[keyword_lower]
219
+ slash_cmd = pref.slash_command
220
+
221
+ # Update usage count
222
+ pref.usage_count += 1
223
+ self._save_preferences()
224
+
225
+ return self._parse_inferred(slash_cmd, keyword, pref.confidence, "learned")
226
+
227
+ # Check built-in command map
228
+ if keyword_lower in self._command_map:
229
+ slash_cmd = self._command_map[keyword_lower]
230
+ return self._parse_inferred(slash_cmd, keyword, 0.9, "builtin")
231
+
232
+ # Check for hub names (show hub menu)
233
+ if keyword_lower in self._hub_descriptions:
234
+ return {
235
+ "type": "hub_menu",
236
+ "hub": keyword_lower,
237
+ "original": keyword,
238
+ "confidence": 1.0,
239
+ }
240
+
241
+ return None
242
+
243
+ def _parse_inferred(
244
+ self, slash_cmd: str, original: str, confidence: float, source: str
245
+ ) -> dict[str, Any]:
246
+ """Parse inferred slash command."""
247
+ parts = slash_cmd[1:].split(maxsplit=1) # Remove leading /
248
+ hub = parts[0] if parts else "help"
249
+ subcommand = parts[1] if len(parts) > 1 else None
250
+
251
+ return {
252
+ "type": "inferred",
253
+ "hub": hub,
254
+ "command": subcommand,
255
+ "original": original,
256
+ "slash_equivalent": slash_cmd,
257
+ "confidence": confidence,
258
+ "source": source, # learned, builtin
259
+ }
260
+
261
+ async def _route_natural_language(
262
+ self, text: str, context: dict[str, Any] | None = None
263
+ ) -> dict[str, Any]:
264
+ """Route natural language input using SmartRouter.
265
+
266
+ Args:
267
+ text: Natural language input
268
+ context: Optional context
269
+
270
+ Returns:
271
+ Routing result with workflow and slash equivalent
272
+ """
273
+ # Use SmartRouter for classification
274
+ decision = await self.smart_router.route(text, context)
275
+
276
+ # Map workflow to slash command
277
+ slash_equivalent = self._workflow_to_slash(decision.primary_workflow)
278
+
279
+ return {
280
+ "type": "natural",
281
+ "workflow": decision.primary_workflow,
282
+ "secondary_workflows": decision.secondary_workflows,
283
+ "slash_equivalent": slash_equivalent,
284
+ "confidence": decision.confidence,
285
+ "reasoning": decision.reasoning,
286
+ "original": text,
287
+ }
288
+
289
+ def _workflow_to_slash(self, workflow: str) -> str:
290
+ """Map workflow name to slash command equivalent.
291
+
292
+ Args:
293
+ workflow: Workflow name (e.g., "security-audit")
294
+
295
+ Returns:
296
+ Slash command equivalent
297
+ """
298
+ # Workflow to slash command mapping
299
+ workflow_map = {
300
+ "security-audit": "/workflows security-audit",
301
+ "bug-predict": "/workflows bug-predict",
302
+ "code-review": "/dev review",
303
+ "test-gen": "/testing gen",
304
+ "perf-audit": "/dev perf-audit",
305
+ "commit": "/dev commit",
306
+ "refactor": "/dev refactor",
307
+ }
308
+
309
+ return workflow_map.get(workflow, f"/workflows {workflow}")
310
+
311
+ def learn_preference(self, keyword: str, slash_command: str) -> None:
312
+ """Learn user's routing preference.
313
+
314
+ Args:
315
+ keyword: Keyword user typed
316
+ slash_command: Command that was executed
317
+ """
318
+ if keyword in self.preferences:
319
+ pref = self.preferences[keyword]
320
+ pref.usage_count += 1
321
+ # Increase confidence with repeated usage
322
+ pref.confidence = min(1.0, pref.confidence + 0.05)
323
+ else:
324
+ self.preferences[keyword] = RoutingPreference(
325
+ keyword=keyword,
326
+ slash_command=slash_command,
327
+ usage_count=1,
328
+ confidence=0.8,
329
+ )
330
+
331
+ self._save_preferences()
332
+
333
+ def get_suggestions(self, partial: str) -> list[str]:
334
+ """Get command suggestions based on partial input.
335
+
336
+ Args:
337
+ partial: Partial command input
338
+
339
+ Returns:
340
+ List of suggested commands
341
+ """
342
+ suggestions = []
343
+ partial_lower = partial.lower()
344
+
345
+ # Suggest slash commands
346
+ for cmd in self._command_map.values():
347
+ if partial_lower in cmd.lower():
348
+ suggestions.append(cmd)
349
+
350
+ # Suggest learned preferences
351
+ for pref in self.preferences.values():
352
+ if partial_lower in pref.keyword.lower():
353
+ suggestions.append(f"{pref.keyword} → {pref.slash_command}")
354
+
355
+ return suggestions[:5] # Top 5 suggestions
356
+
357
+
358
+ # Convenience functions
359
+ async def route_user_input(
360
+ user_input: str, context: dict[str, Any] | None = None
361
+ ) -> dict[str, Any]:
362
+ """Quick routing helper.
363
+
364
+ Args:
365
+ user_input: User's input
366
+ context: Optional context
367
+
368
+ Returns:
369
+ Routing result
370
+ """
371
+ router = HybridRouter()
372
+ return await router.route(user_input, context)
373
+
374
+
375
+ def is_slash_command(text: str) -> bool:
376
+ """Check if text is a slash command.
377
+
378
+ Args:
379
+ text: Input text
380
+
381
+ Returns:
382
+ True if slash command, False otherwise
383
+ """
384
+ return text.strip().startswith("/")
empathy_os/cli_unified.py CHANGED
@@ -1,5 +1,21 @@
1
1
  """Unified CLI for Empathy Framework
2
2
 
3
+ DEPRECATED: This module is deprecated as of v5.0.0.
4
+ Use the minimal CLI instead: `empathy` (empathy_os.cli_minimal)
5
+
6
+ The minimal CLI provides:
7
+ - `empathy workflow list|info|run` - Workflow management
8
+ - `empathy telemetry show|savings|export` - Usage tracking
9
+ - `empathy provider show|set` - Provider configuration
10
+ - `empathy validate` - Configuration validation
11
+
12
+ For interactive features, use Claude Code slash commands:
13
+ - /dev, /testing, /docs, /release, /help
14
+
15
+ Migration guide: https://smartaimemory.com/framework-docs/migration/cli/
16
+
17
+ ---
18
+
3
19
  A simplified, intelligent CLI using Socratic questioning.
4
20
 
5
21
  Usage:
@@ -14,6 +30,15 @@ Copyright 2025 Smart-AI-Memory
14
30
  Licensed under Fair Source License 0.9
15
31
  """
16
32
 
33
+ import warnings
34
+
35
+ warnings.warn(
36
+ "empathy-unified CLI is deprecated. Use 'empathy' (cli_minimal) instead. "
37
+ "See: https://smartaimemory.com/framework-docs/reference/cli-reference/",
38
+ DeprecationWarning,
39
+ stacklevel=2,
40
+ )
41
+
17
42
  import json
18
43
  import subprocess
19
44
  import sys
@@ -542,7 +567,9 @@ def utilities_status():
542
567
  @utilities_app.command("scan")
543
568
  def utilities_scan(
544
569
  path: Path = typer.Argument(Path("."), help="Path to scan"),
545
- scan_type: str = typer.Option("all", "--type", "-t", help="Scan type: security, performance, or all"),
570
+ scan_type: str = typer.Option(
571
+ "all", "--type", "-t", help="Scan type: security, performance, or all"
572
+ ),
546
573
  ):
547
574
  """Scan codebase for issues.
548
575
 
@@ -649,7 +676,16 @@ def telemetry_export(
649
676
  ):
650
677
  """Export telemetry data."""
651
678
  subprocess.run(
652
- [sys.executable, "-m", "empathy_os.cli", "telemetry", "export", str(output), "--format", format_type],
679
+ [
680
+ sys.executable,
681
+ "-m",
682
+ "empathy_os.cli",
683
+ "telemetry",
684
+ "export",
685
+ str(output),
686
+ "--format",
687
+ format_type,
688
+ ],
653
689
  check=False,
654
690
  )
655
691
 
@@ -123,17 +123,24 @@ from .security import ( # Audit Logging; PII Scrubbing; Secrets Detection
123
123
  Severity,
124
124
  detect_secrets,
125
125
  )
126
- from .short_term import (
126
+ from .short_term import RedisShortTermMemory
127
+
128
+ # Conversation Summary Index
129
+ from .summary_index import AgentContext, ConversationSummaryIndex
130
+
131
+ # Types (extracted to types.py for cleaner separation)
132
+ from .types import (
127
133
  AccessTier,
128
134
  AgentCredentials,
129
135
  ConflictContext,
130
- RedisShortTermMemory,
136
+ PaginatedResult,
137
+ RedisConfig,
138
+ RedisMetrics,
131
139
  StagedPattern,
140
+ TimeWindowQuery,
132
141
  TTLStrategy,
133
142
  )
134
-
135
- # Conversation Summary Index
136
- from .summary_index import AgentContext, ConversationSummaryIndex
143
+ from .types import SecurityError as ShortTermSecurityError
137
144
 
138
145
  # Unified memory interface
139
146
  from .unified import Environment, MemoryConfig, UnifiedMemory
@@ -180,6 +187,8 @@ __all__ = [
180
187
  "MemoryStats",
181
188
  "Node",
182
189
  "NodeType",
190
+ # Pagination and Query Types
191
+ "PaginatedResult",
183
192
  "PIIDetection",
184
193
  "PIIPattern",
185
194
  # Security - PII
@@ -187,6 +196,9 @@ __all__ = [
187
196
  "PatternMetadata",
188
197
  "PatternNode",
189
198
  "PerformanceNode",
199
+ # Redis Configuration and Metrics
200
+ "RedisConfig",
201
+ "RedisMetrics",
190
202
  # Short-term Memory
191
203
  "RedisShortTermMemory",
192
204
  "RedisStartMethod",
@@ -203,8 +215,10 @@ __all__ = [
203
215
  "SessionInfo",
204
216
  "SessionType",
205
217
  "Severity",
218
+ "ShortTermSecurityError",
206
219
  "StagedPattern",
207
220
  "TTLStrategy",
221
+ "TimeWindowQuery",
208
222
  # Unified Memory Interface (recommended)
209
223
  "UnifiedMemory",
210
224
  "VulnerabilityNode",