empathy-framework 4.9.0__py3-none-any.whl → 5.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.
Files changed (47) hide show
  1. {empathy_framework-4.9.0.dist-info → empathy_framework-5.0.0.dist-info}/METADATA +64 -25
  2. {empathy_framework-4.9.0.dist-info → empathy_framework-5.0.0.dist-info}/RECORD +47 -26
  3. empathy_os/__init__.py +2 -2
  4. empathy_os/cache/hash_only.py +6 -3
  5. empathy_os/cache/hybrid.py +6 -3
  6. empathy_os/cli_legacy.py +27 -1
  7. empathy_os/cli_minimal.py +512 -15
  8. empathy_os/cli_router.py +145 -113
  9. empathy_os/cli_unified.py +25 -0
  10. empathy_os/dashboard/__init__.py +42 -0
  11. empathy_os/dashboard/app.py +512 -0
  12. empathy_os/dashboard/simple_server.py +403 -0
  13. empathy_os/dashboard/standalone_server.py +536 -0
  14. empathy_os/memory/__init__.py +19 -5
  15. empathy_os/memory/short_term.py +4 -70
  16. empathy_os/memory/types.py +2 -2
  17. empathy_os/models/__init__.py +3 -0
  18. empathy_os/models/adaptive_routing.py +437 -0
  19. empathy_os/models/registry.py +4 -4
  20. empathy_os/socratic/ab_testing.py +1 -1
  21. empathy_os/telemetry/__init__.py +29 -1
  22. empathy_os/telemetry/agent_coordination.py +478 -0
  23. empathy_os/telemetry/agent_tracking.py +350 -0
  24. empathy_os/telemetry/approval_gates.py +563 -0
  25. empathy_os/telemetry/event_streaming.py +405 -0
  26. empathy_os/telemetry/feedback_loop.py +557 -0
  27. empathy_os/vscode_bridge 2.py +173 -0
  28. empathy_os/workflows/__init__.py +4 -4
  29. empathy_os/workflows/base.py +495 -43
  30. empathy_os/workflows/history.py +3 -5
  31. empathy_os/workflows/output.py +410 -0
  32. empathy_os/workflows/progress.py +324 -22
  33. empathy_os/workflows/progressive/README 2.md +454 -0
  34. empathy_os/workflows/progressive/__init__ 2.py +92 -0
  35. empathy_os/workflows/progressive/cli 2.py +242 -0
  36. empathy_os/workflows/progressive/core 2.py +488 -0
  37. empathy_os/workflows/progressive/orchestrator 2.py +701 -0
  38. empathy_os/workflows/progressive/reports 2.py +528 -0
  39. empathy_os/workflows/progressive/telemetry 2.py +280 -0
  40. empathy_os/workflows/progressive/test_gen 2.py +514 -0
  41. empathy_os/workflows/progressive/workflow 2.py +628 -0
  42. empathy_os/workflows/routing.py +5 -0
  43. empathy_os/workflows/security_audit.py +189 -0
  44. {empathy_framework-4.9.0.dist-info → empathy_framework-5.0.0.dist-info}/WHEEL +0 -0
  45. {empathy_framework-4.9.0.dist-info → empathy_framework-5.0.0.dist-info}/entry_points.txt +0 -0
  46. {empathy_framework-4.9.0.dist-info → empathy_framework-5.0.0.dist-info}/licenses/LICENSE +0 -0
  47. {empathy_framework-4.9.0.dist-info → empathy_framework-5.0.0.dist-info}/top_level.txt +0 -0
empathy_os/cli_router.py CHANGED
@@ -1,16 +1,14 @@
1
- """Hybrid CLI Router - Slash Commands + Natural Language
1
+ """Hybrid CLI Router - Skills + Natural Language
2
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)
3
+ Routes keywords and natural language to Claude Code skill invocations:
4
+ - Skills: /dev, /testing, /workflows (Claude Code Skill tool)
5
+ - Keywords: commit, test, security (maps to skills)
6
+ - Natural language: "commit my changes" (SmartRouter classification)
7
7
 
8
8
  Copyright 2025 Smart-AI-Memory
9
9
  Licensed under Fair Source License 0.9
10
10
  """
11
11
 
12
- import os
13
- import re
14
12
  from dataclasses import dataclass
15
13
  from pathlib import Path
16
14
  from typing import Any
@@ -25,33 +23,34 @@ class RoutingPreference:
25
23
  """User's learned routing preferences."""
26
24
 
27
25
  keyword: str
28
- slash_command: str
26
+ skill: str
27
+ args: str = ""
29
28
  usage_count: int = 0
30
29
  confidence: float = 1.0
31
30
 
32
31
 
33
32
  class HybridRouter:
34
- """Routes user input to appropriate commands or workflows.
33
+ """Routes user input to Claude Code skill invocations.
35
34
 
36
35
  Supports three input modes:
37
- 1. Slash commands: /dev commit (direct, structured)
38
- 2. Single words: commit (infers /dev commit from context)
36
+ 1. Skills: /dev, /testing (returns skill invocation metadata)
37
+ 2. Keywords: commit, test (maps to skill invocations)
39
38
  3. Natural language: "I need to commit" (uses SmartRouter)
40
39
 
41
40
  Example:
42
41
  router = HybridRouter()
43
42
 
44
- # Direct slash command
45
- result = await router.route("/dev commit")
46
- # → {type: "slash", hub: "dev", command: "commit"}
43
+ # Skill invocation
44
+ result = await router.route("/dev")
45
+ # → {type: "skill", skill: "dev", args: "", instruction: "Use Skill tool..."}
47
46
 
48
- # Single word inference
47
+ # Keyword to skill
49
48
  result = await router.route("commit")
50
- # → {type: "inferred", hub: "dev", command: "commit", confidence: 0.9}
49
+ # → {type: "skill", skill: "dev", args: "commit", instruction: "Use Skill tool..."}
51
50
 
52
51
  # Natural language
53
52
  result = await router.route("I want to commit my changes")
54
- # → {type: "natural", workflow: "commit", slash_equivalent: "/dev commit"}
53
+ # → {type: "skill", skill: "dev", args: "commit", reasoning: "..."}
55
54
  """
56
55
 
57
56
  def __init__(self, preferences_path: str | None = None):
@@ -67,38 +66,47 @@ class HybridRouter:
67
66
  self.smart_router = SmartRouter()
68
67
  self.preferences: dict[str, RoutingPreference] = {}
69
68
 
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",
69
+ # Keyword to skill mapping: keyword → (skill_name, args)
70
+ self._keyword_to_skill = {
71
+ # Dev commands → /dev skill
72
+ "commit": ("dev", "commit"),
73
+ "review": ("dev", "review"),
74
+ "review-pr": ("dev", "review"),
75
+ "refactor": ("dev", "refactor"),
76
+ "perf": ("dev", "perf-audit"),
77
+ "perf-audit": ("dev", "perf-audit"),
78
+ "debug": ("dev", "debug"),
79
+ # Testing commands → /testing skill
80
+ "test": ("testing", "run"),
81
+ "tests": ("testing", "run"),
82
+ "coverage": ("testing", "coverage"),
83
+ "generate-tests": ("testing", "gen"),
84
+ "test-gen": ("testing", "gen"),
85
+ "benchmark": ("testing", "benchmark"),
86
+ # Learning commands → /learning skill
87
+ "evaluate": ("learning", "evaluate"),
88
+ "patterns": ("learning", "patterns"),
89
+ "improve": ("learning", "improve"),
90
+ # Workflow commands → /workflows skill
91
+ "security": ("workflows", "run security-audit"),
92
+ "security-audit": ("workflows", "run security-audit"),
93
+ "bug-predict": ("workflows", "run bug-predict"),
94
+ "bugs": ("workflows", "run bug-predict"),
95
+ "perf-workflow": ("workflows", "run perf-audit"),
96
+ # Context commands → /context skill
97
+ "status": ("context", "status"),
98
+ "memory": ("context", "memory"),
99
+ "state": ("context", "state"),
100
+ # Doc commands → /docs skill
101
+ "explain": ("docs", "explain"),
102
+ "document": ("docs", "generate"),
103
+ "overview": ("docs", "overview"),
104
+ # Plan commands → /plan skill
105
+ "plan": ("plan", ""),
106
+ "tdd": ("plan", "tdd"),
107
+ # Release commands → /release skill
108
+ "release": ("release", "prep"),
109
+ "ship": ("release", "prep"),
102
110
  }
103
111
 
104
112
  # Hub descriptions for disambiguation
@@ -126,9 +134,22 @@ class HybridRouter:
126
134
  data = yaml.safe_load(f) or {}
127
135
 
128
136
  for keyword, pref_data in data.get("preferences", {}).items():
137
+ # Handle backward compatibility: old format had "slash_command"
138
+ if "slash_command" in pref_data:
139
+ # Migrate old format: "/dev commit" → skill="dev", args="commit"
140
+ slash_cmd = pref_data["slash_command"].lstrip("/")
141
+ parts = slash_cmd.split(maxsplit=1)
142
+ skill = parts[0] if parts else "help"
143
+ args = parts[1] if len(parts) > 1 else ""
144
+ else:
145
+ # New format
146
+ skill = pref_data["skill"]
147
+ args = pref_data.get("args", "")
148
+
129
149
  self.preferences[keyword] = RoutingPreference(
130
150
  keyword=keyword,
131
- slash_command=pref_data["slash_command"],
151
+ skill=skill,
152
+ args=args,
132
153
  usage_count=pref_data.get("usage_count", 0),
133
154
  confidence=pref_data.get("confidence", 1.0),
134
155
  )
@@ -142,7 +163,8 @@ class HybridRouter:
142
163
  data = {
143
164
  "preferences": {
144
165
  pref.keyword: {
145
- "slash_command": pref.slash_command,
166
+ "skill": pref.skill,
167
+ "args": pref.args,
146
168
  "usage_count": pref.usage_count,
147
169
  "confidence": pref.confidence,
148
170
  }
@@ -182,82 +204,83 @@ class HybridRouter:
182
204
  return await self._route_natural_language(user_input, context)
183
205
 
184
206
  def _route_slash_command(self, command: str) -> dict[str, Any]:
185
- """Route slash command directly.
207
+ """Route slash command to skill invocation.
186
208
 
187
209
  Args:
188
- command: Slash command like "/dev commit"
210
+ command: Slash command like "/dev" or "/dev commit"
189
211
 
190
212
  Returns:
191
- Routing result
213
+ Skill invocation instructions
192
214
  """
193
215
  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
216
+ skill = parts[0] if parts else "help"
217
+ args = parts[1] if len(parts) > 1 else ""
196
218
 
197
219
  return {
198
- "type": "slash",
199
- "hub": hub,
200
- "command": subcommand,
220
+ "type": "skill",
221
+ "skill": skill,
222
+ "args": args,
201
223
  "original": command,
202
224
  "confidence": 1.0,
225
+ "instruction": f"Use Skill tool with skill='{skill}'" + (f", args='{args}'" if args else ""),
203
226
  }
204
227
 
205
228
  def _infer_command(self, keyword: str) -> dict[str, Any] | None:
206
- """Infer slash command from keyword or short phrase.
229
+ """Infer skill invocation from keyword or short phrase.
207
230
 
208
231
  Args:
209
232
  keyword: Single word or short phrase
210
233
 
211
234
  Returns:
212
- Routing result if inference successful, None otherwise
235
+ Skill invocation instructions if inference successful, None otherwise
213
236
  """
214
237
  keyword_lower = keyword.lower().strip()
215
238
 
216
239
  # Check learned preferences first
217
240
  if keyword_lower in self.preferences:
218
241
  pref = self.preferences[keyword_lower]
219
- slash_cmd = pref.slash_command
220
242
 
221
243
  # Update usage count
222
244
  pref.usage_count += 1
223
245
  self._save_preferences()
224
246
 
225
- return self._parse_inferred(slash_cmd, keyword, pref.confidence, "learned")
247
+ return {
248
+ "type": "skill",
249
+ "skill": pref.skill,
250
+ "args": pref.args,
251
+ "original": keyword,
252
+ "confidence": pref.confidence,
253
+ "source": "learned",
254
+ "instruction": f"Use Skill tool with skill='{pref.skill}'" + (f", args='{pref.args}'" if pref.args else ""),
255
+ }
226
256
 
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")
257
+ # Check built-in keyword map
258
+ if keyword_lower in self._keyword_to_skill:
259
+ skill, args = self._keyword_to_skill[keyword_lower]
260
+ return {
261
+ "type": "skill",
262
+ "skill": skill,
263
+ "args": args,
264
+ "original": keyword,
265
+ "confidence": 0.9,
266
+ "source": "builtin",
267
+ "instruction": f"Use Skill tool with skill='{skill}'" + (f", args='{args}'" if args else ""),
268
+ }
231
269
 
232
270
  # Check for hub names (show hub menu)
233
271
  if keyword_lower in self._hub_descriptions:
234
272
  return {
235
- "type": "hub_menu",
236
- "hub": keyword_lower,
273
+ "type": "skill",
274
+ "skill": keyword_lower,
275
+ "args": "",
237
276
  "original": keyword,
238
277
  "confidence": 1.0,
278
+ "source": "hub",
279
+ "instruction": f"Use Skill tool with skill='{keyword_lower}'",
239
280
  }
240
281
 
241
282
  return None
242
283
 
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
284
  async def _route_natural_language(
262
285
  self, text: str, context: dict[str, Any] | None = None
263
286
  ) -> dict[str, Any]:
@@ -268,52 +291,59 @@ class HybridRouter:
268
291
  context: Optional context
269
292
 
270
293
  Returns:
271
- Routing result with workflow and slash equivalent
294
+ Skill invocation instructions based on SmartRouter decision
272
295
  """
273
296
  # Use SmartRouter for classification
274
297
  decision = await self.smart_router.route(text, context)
275
298
 
276
- # Map workflow to slash command
277
- slash_equivalent = self._workflow_to_slash(decision.primary_workflow)
299
+ # Map workflow to skill invocation
300
+ skill, args = self._workflow_to_skill(decision.primary_workflow)
278
301
 
279
302
  return {
280
- "type": "natural",
303
+ "type": "skill",
304
+ "skill": skill,
305
+ "args": args,
281
306
  "workflow": decision.primary_workflow,
282
307
  "secondary_workflows": decision.secondary_workflows,
283
- "slash_equivalent": slash_equivalent,
284
308
  "confidence": decision.confidence,
285
309
  "reasoning": decision.reasoning,
286
310
  "original": text,
311
+ "source": "natural_language",
312
+ "instruction": f"Use Skill tool with skill='{skill}'" + (f", args='{args}'" if args else ""),
287
313
  }
288
314
 
289
- def _workflow_to_slash(self, workflow: str) -> str:
290
- """Map workflow name to slash command equivalent.
315
+ def _workflow_to_skill(self, workflow: str) -> tuple[str, str]:
316
+ """Map workflow name to skill invocation.
291
317
 
292
318
  Args:
293
319
  workflow: Workflow name (e.g., "security-audit")
294
320
 
295
321
  Returns:
296
- Slash command equivalent
322
+ Tuple of (skill_name, args)
297
323
  """
298
- # Workflow to slash command mapping
324
+ # Workflow to skill mapping
299
325
  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",
326
+ "security-audit": ("workflows", "run security-audit"),
327
+ "bug-predict": ("workflows", "run bug-predict"),
328
+ "code-review": ("dev", "review"),
329
+ "test-gen": ("testing", "gen"),
330
+ "perf-audit": ("workflows", "run perf-audit"),
331
+ "commit": ("dev", "commit"),
332
+ "refactor": ("dev", "refactor"),
333
+ "debug": ("dev", "debug"),
334
+ "explain": ("docs", "explain"),
335
+ "plan": ("plan", ""),
307
336
  }
308
337
 
309
- return workflow_map.get(workflow, f"/workflows {workflow}")
338
+ return workflow_map.get(workflow, ("workflows", f"run {workflow}"))
310
339
 
311
- def learn_preference(self, keyword: str, slash_command: str) -> None:
340
+ def learn_preference(self, keyword: str, skill: str, args: str = "") -> None:
312
341
  """Learn user's routing preference.
313
342
 
314
343
  Args:
315
344
  keyword: Keyword user typed
316
- slash_command: Command that was executed
345
+ skill: Skill name that was invoked
346
+ args: Arguments passed to skill
317
347
  """
318
348
  if keyword in self.preferences:
319
349
  pref = self.preferences[keyword]
@@ -323,7 +353,8 @@ class HybridRouter:
323
353
  else:
324
354
  self.preferences[keyword] = RoutingPreference(
325
355
  keyword=keyword,
326
- slash_command=slash_command,
356
+ skill=skill,
357
+ args=args,
327
358
  usage_count=1,
328
359
  confidence=0.8,
329
360
  )
@@ -337,20 +368,21 @@ class HybridRouter:
337
368
  partial: Partial command input
338
369
 
339
370
  Returns:
340
- List of suggested commands
371
+ List of suggested keywords and skills
341
372
  """
342
373
  suggestions = []
343
374
  partial_lower = partial.lower()
344
375
 
345
- # Suggest slash commands
346
- for cmd in self._command_map.values():
347
- if partial_lower in cmd.lower():
348
- suggestions.append(cmd)
376
+ # Suggest keywords
377
+ for keyword in self._keyword_to_skill.keys():
378
+ if partial_lower in keyword:
379
+ skill, args = self._keyword_to_skill[keyword]
380
+ suggestions.append(f"{keyword} → /{skill} {args}".strip())
349
381
 
350
382
  # Suggest learned preferences
351
383
  for pref in self.preferences.values():
352
384
  if partial_lower in pref.keyword.lower():
353
- suggestions.append(f"{pref.keyword} → {pref.slash_command}")
385
+ suggestions.append(f"{pref.keyword} → /{pref.skill} {pref.args}".strip())
354
386
 
355
387
  return suggestions[:5] # Top 5 suggestions
356
388
 
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
@@ -0,0 +1,42 @@
1
+ """Agent Coordination Dashboard.
2
+
3
+ Web-based monitoring dashboard for all 6 agent coordination patterns.
4
+
5
+ Usage (Standalone - Direct Redis Access):
6
+ >>> from empathy_os.dashboard import run_standalone_dashboard
7
+ >>> run_standalone_dashboard(host="0.0.0.0", port=8080)
8
+
9
+ Usage (Simple Server - Uses Telemetry API):
10
+ >>> from empathy_os.dashboard import run_simple_dashboard
11
+ >>> run_simple_dashboard(host="0.0.0.0", port=8080)
12
+
13
+ Usage (FastAPI - Requires fastapi and uvicorn):
14
+ >>> from empathy_os.dashboard import run_dashboard
15
+ >>> run_dashboard(host="0.0.0.0", port=8080)
16
+
17
+ Features:
18
+ - Real-time agent status monitoring (Pattern 1)
19
+ - Coordination signal viewer (Pattern 2)
20
+ - Event stream monitor (Pattern 4)
21
+ - Approval request manager (Pattern 5)
22
+ - Quality feedback analytics (Pattern 6)
23
+ - Auto-refresh every 5 seconds
24
+
25
+ Copyright 2025 Smart-AI-Memory
26
+ Licensed under Fair Source License 0.9
27
+ """
28
+
29
+ # Standalone server - reads directly from Redis
30
+ from .standalone_server import run_standalone_dashboard
31
+
32
+ # Simple server - uses telemetry API classes
33
+ from .simple_server import run_simple_dashboard
34
+
35
+ # Optional FastAPI version (requires dependencies)
36
+ try:
37
+ from .app import app, run_dashboard
38
+
39
+ __all__ = ["app", "run_dashboard", "run_simple_dashboard", "run_standalone_dashboard"]
40
+ except ImportError:
41
+ # FastAPI not installed
42
+ __all__ = ["run_simple_dashboard", "run_standalone_dashboard"]