empathy-framework 4.6.6__py3-none-any.whl → 4.7.1__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 (273) hide show
  1. empathy_framework-4.7.1.dist-info/METADATA +690 -0
  2. empathy_framework-4.7.1.dist-info/RECORD +379 -0
  3. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/top_level.txt +1 -2
  4. empathy_healthcare_plugin/monitors/monitoring/__init__.py +9 -9
  5. empathy_llm_toolkit/agent_factory/__init__.py +6 -6
  6. empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +7 -10
  7. empathy_llm_toolkit/agents_md/__init__.py +22 -0
  8. empathy_llm_toolkit/agents_md/loader.py +218 -0
  9. empathy_llm_toolkit/agents_md/parser.py +271 -0
  10. empathy_llm_toolkit/agents_md/registry.py +307 -0
  11. empathy_llm_toolkit/commands/__init__.py +51 -0
  12. empathy_llm_toolkit/commands/context.py +375 -0
  13. empathy_llm_toolkit/commands/loader.py +301 -0
  14. empathy_llm_toolkit/commands/models.py +231 -0
  15. empathy_llm_toolkit/commands/parser.py +371 -0
  16. empathy_llm_toolkit/commands/registry.py +429 -0
  17. empathy_llm_toolkit/config/__init__.py +8 -8
  18. empathy_llm_toolkit/config/unified.py +3 -7
  19. empathy_llm_toolkit/context/__init__.py +22 -0
  20. empathy_llm_toolkit/context/compaction.py +455 -0
  21. empathy_llm_toolkit/context/manager.py +434 -0
  22. empathy_llm_toolkit/hooks/__init__.py +24 -0
  23. empathy_llm_toolkit/hooks/config.py +306 -0
  24. empathy_llm_toolkit/hooks/executor.py +289 -0
  25. empathy_llm_toolkit/hooks/registry.py +302 -0
  26. empathy_llm_toolkit/hooks/scripts/__init__.py +39 -0
  27. empathy_llm_toolkit/hooks/scripts/evaluate_session.py +201 -0
  28. empathy_llm_toolkit/hooks/scripts/first_time_init.py +285 -0
  29. empathy_llm_toolkit/hooks/scripts/pre_compact.py +207 -0
  30. empathy_llm_toolkit/hooks/scripts/session_end.py +183 -0
  31. empathy_llm_toolkit/hooks/scripts/session_start.py +163 -0
  32. empathy_llm_toolkit/hooks/scripts/suggest_compact.py +225 -0
  33. empathy_llm_toolkit/learning/__init__.py +30 -0
  34. empathy_llm_toolkit/learning/evaluator.py +438 -0
  35. empathy_llm_toolkit/learning/extractor.py +514 -0
  36. empathy_llm_toolkit/learning/storage.py +560 -0
  37. empathy_llm_toolkit/providers.py +4 -11
  38. empathy_llm_toolkit/security/__init__.py +17 -17
  39. empathy_llm_toolkit/utils/tokens.py +2 -5
  40. empathy_os/__init__.py +202 -70
  41. empathy_os/cache_monitor.py +5 -3
  42. empathy_os/cli/__init__.py +11 -55
  43. empathy_os/cli/__main__.py +29 -15
  44. empathy_os/cli/commands/inspection.py +21 -12
  45. empathy_os/cli/commands/memory.py +4 -12
  46. empathy_os/cli/commands/profiling.py +198 -0
  47. empathy_os/cli/commands/utilities.py +27 -7
  48. empathy_os/cli.py +28 -57
  49. empathy_os/cli_unified.py +525 -1164
  50. empathy_os/cost_tracker.py +9 -3
  51. empathy_os/dashboard/server.py +200 -2
  52. empathy_os/hot_reload/__init__.py +7 -7
  53. empathy_os/hot_reload/config.py +6 -7
  54. empathy_os/hot_reload/integration.py +35 -35
  55. empathy_os/hot_reload/reloader.py +57 -57
  56. empathy_os/hot_reload/watcher.py +28 -28
  57. empathy_os/hot_reload/websocket.py +2 -2
  58. empathy_os/memory/__init__.py +11 -4
  59. empathy_os/memory/claude_memory.py +1 -1
  60. empathy_os/memory/cross_session.py +8 -12
  61. empathy_os/memory/edges.py +6 -6
  62. empathy_os/memory/file_session.py +770 -0
  63. empathy_os/memory/graph.py +30 -30
  64. empathy_os/memory/nodes.py +6 -6
  65. empathy_os/memory/short_term.py +15 -9
  66. empathy_os/memory/unified.py +606 -140
  67. empathy_os/meta_workflows/agent_creator.py +3 -9
  68. empathy_os/meta_workflows/cli_meta_workflows.py +113 -53
  69. empathy_os/meta_workflows/form_engine.py +6 -18
  70. empathy_os/meta_workflows/intent_detector.py +64 -24
  71. empathy_os/meta_workflows/models.py +3 -1
  72. empathy_os/meta_workflows/pattern_learner.py +13 -31
  73. empathy_os/meta_workflows/plan_generator.py +55 -47
  74. empathy_os/meta_workflows/session_context.py +2 -3
  75. empathy_os/meta_workflows/workflow.py +20 -51
  76. empathy_os/models/cli.py +2 -2
  77. empathy_os/models/tasks.py +1 -2
  78. empathy_os/models/telemetry.py +4 -1
  79. empathy_os/models/token_estimator.py +3 -1
  80. empathy_os/monitoring/alerts.py +938 -9
  81. empathy_os/monitoring/alerts_cli.py +346 -183
  82. empathy_os/orchestration/execution_strategies.py +12 -29
  83. empathy_os/orchestration/pattern_learner.py +20 -26
  84. empathy_os/orchestration/real_tools.py +6 -15
  85. empathy_os/platform_utils.py +2 -1
  86. empathy_os/plugins/__init__.py +2 -2
  87. empathy_os/plugins/base.py +64 -64
  88. empathy_os/plugins/registry.py +32 -32
  89. empathy_os/project_index/index.py +49 -15
  90. empathy_os/project_index/models.py +1 -2
  91. empathy_os/project_index/reports.py +1 -1
  92. empathy_os/project_index/scanner.py +1 -0
  93. empathy_os/redis_memory.py +10 -7
  94. empathy_os/resilience/__init__.py +1 -1
  95. empathy_os/resilience/health.py +10 -10
  96. empathy_os/routing/__init__.py +7 -7
  97. empathy_os/routing/chain_executor.py +37 -37
  98. empathy_os/routing/classifier.py +36 -36
  99. empathy_os/routing/smart_router.py +40 -40
  100. empathy_os/routing/{wizard_registry.py → workflow_registry.py} +47 -47
  101. empathy_os/scaffolding/__init__.py +8 -8
  102. empathy_os/scaffolding/__main__.py +1 -1
  103. empathy_os/scaffolding/cli.py +28 -28
  104. empathy_os/socratic/__init__.py +3 -19
  105. empathy_os/socratic/ab_testing.py +25 -36
  106. empathy_os/socratic/blueprint.py +38 -38
  107. empathy_os/socratic/cli.py +34 -20
  108. empathy_os/socratic/collaboration.py +30 -28
  109. empathy_os/socratic/domain_templates.py +9 -1
  110. empathy_os/socratic/embeddings.py +17 -13
  111. empathy_os/socratic/engine.py +135 -70
  112. empathy_os/socratic/explainer.py +70 -60
  113. empathy_os/socratic/feedback.py +24 -19
  114. empathy_os/socratic/forms.py +15 -10
  115. empathy_os/socratic/generator.py +51 -35
  116. empathy_os/socratic/llm_analyzer.py +25 -23
  117. empathy_os/socratic/mcp_server.py +99 -159
  118. empathy_os/socratic/session.py +19 -13
  119. empathy_os/socratic/storage.py +98 -67
  120. empathy_os/socratic/success.py +38 -27
  121. empathy_os/socratic/visual_editor.py +51 -39
  122. empathy_os/socratic/web_ui.py +99 -66
  123. empathy_os/telemetry/cli.py +3 -1
  124. empathy_os/telemetry/usage_tracker.py +1 -3
  125. empathy_os/test_generator/__init__.py +3 -3
  126. empathy_os/test_generator/cli.py +28 -28
  127. empathy_os/test_generator/generator.py +64 -66
  128. empathy_os/test_generator/risk_analyzer.py +11 -11
  129. empathy_os/vscode_bridge 2.py +173 -0
  130. empathy_os/vscode_bridge.py +173 -0
  131. empathy_os/workflows/__init__.py +212 -120
  132. empathy_os/workflows/batch_processing.py +8 -24
  133. empathy_os/workflows/bug_predict.py +1 -1
  134. empathy_os/workflows/code_review.py +20 -5
  135. empathy_os/workflows/code_review_pipeline.py +13 -8
  136. empathy_os/workflows/keyboard_shortcuts/workflow.py +6 -2
  137. empathy_os/workflows/manage_documentation.py +1 -0
  138. empathy_os/workflows/orchestrated_health_check.py +6 -11
  139. empathy_os/workflows/orchestrated_release_prep.py +3 -3
  140. empathy_os/workflows/pr_review.py +18 -10
  141. empathy_os/workflows/progressive/README 2.md +454 -0
  142. empathy_os/workflows/progressive/__init__ 2.py +92 -0
  143. empathy_os/workflows/progressive/__init__.py +2 -12
  144. empathy_os/workflows/progressive/cli 2.py +242 -0
  145. empathy_os/workflows/progressive/cli.py +14 -37
  146. empathy_os/workflows/progressive/core 2.py +488 -0
  147. empathy_os/workflows/progressive/core.py +12 -12
  148. empathy_os/workflows/progressive/orchestrator 2.py +701 -0
  149. empathy_os/workflows/progressive/orchestrator.py +166 -144
  150. empathy_os/workflows/progressive/reports 2.py +528 -0
  151. empathy_os/workflows/progressive/reports.py +22 -31
  152. empathy_os/workflows/progressive/telemetry 2.py +280 -0
  153. empathy_os/workflows/progressive/telemetry.py +8 -14
  154. empathy_os/workflows/progressive/test_gen 2.py +514 -0
  155. empathy_os/workflows/progressive/test_gen.py +29 -48
  156. empathy_os/workflows/progressive/workflow 2.py +628 -0
  157. empathy_os/workflows/progressive/workflow.py +31 -70
  158. empathy_os/workflows/release_prep.py +21 -6
  159. empathy_os/workflows/release_prep_crew.py +1 -0
  160. empathy_os/workflows/secure_release.py +13 -6
  161. empathy_os/workflows/security_audit.py +8 -3
  162. empathy_os/workflows/test_coverage_boost_crew.py +3 -2
  163. empathy_os/workflows/test_maintenance_crew.py +1 -0
  164. empathy_os/workflows/test_runner.py +16 -12
  165. empathy_software_plugin/SOFTWARE_PLUGIN_README.md +25 -703
  166. empathy_software_plugin/cli.py +0 -122
  167. patterns/README.md +119 -0
  168. patterns/__init__.py +95 -0
  169. patterns/behavior.py +298 -0
  170. patterns/code_review_memory.json +441 -0
  171. patterns/core.py +97 -0
  172. patterns/debugging.json +3763 -0
  173. patterns/empathy.py +268 -0
  174. patterns/health_check_memory.json +505 -0
  175. patterns/input.py +161 -0
  176. patterns/memory_graph.json +8 -0
  177. patterns/refactoring_memory.json +1113 -0
  178. patterns/registry.py +663 -0
  179. patterns/security_memory.json +8 -0
  180. patterns/structural.py +415 -0
  181. patterns/validation.py +194 -0
  182. coach_wizards/__init__.py +0 -45
  183. coach_wizards/accessibility_wizard.py +0 -91
  184. coach_wizards/api_wizard.py +0 -91
  185. coach_wizards/base_wizard.py +0 -209
  186. coach_wizards/cicd_wizard.py +0 -91
  187. coach_wizards/code_reviewer_README.md +0 -60
  188. coach_wizards/code_reviewer_wizard.py +0 -180
  189. coach_wizards/compliance_wizard.py +0 -91
  190. coach_wizards/database_wizard.py +0 -91
  191. coach_wizards/debugging_wizard.py +0 -91
  192. coach_wizards/documentation_wizard.py +0 -91
  193. coach_wizards/generate_wizards.py +0 -347
  194. coach_wizards/localization_wizard.py +0 -173
  195. coach_wizards/migration_wizard.py +0 -91
  196. coach_wizards/monitoring_wizard.py +0 -91
  197. coach_wizards/observability_wizard.py +0 -91
  198. coach_wizards/performance_wizard.py +0 -91
  199. coach_wizards/prompt_engineering_wizard.py +0 -661
  200. coach_wizards/refactoring_wizard.py +0 -91
  201. coach_wizards/scaling_wizard.py +0 -90
  202. coach_wizards/security_wizard.py +0 -92
  203. coach_wizards/testing_wizard.py +0 -91
  204. empathy_framework-4.6.6.dist-info/METADATA +0 -1597
  205. empathy_framework-4.6.6.dist-info/RECORD +0 -410
  206. empathy_llm_toolkit/wizards/__init__.py +0 -43
  207. empathy_llm_toolkit/wizards/base_wizard.py +0 -364
  208. empathy_llm_toolkit/wizards/customer_support_wizard.py +0 -190
  209. empathy_llm_toolkit/wizards/healthcare_wizard.py +0 -378
  210. empathy_llm_toolkit/wizards/patient_assessment_README.md +0 -64
  211. empathy_llm_toolkit/wizards/patient_assessment_wizard.py +0 -193
  212. empathy_llm_toolkit/wizards/technology_wizard.py +0 -209
  213. empathy_os/wizard_factory_cli.py +0 -170
  214. empathy_software_plugin/wizards/__init__.py +0 -42
  215. empathy_software_plugin/wizards/advanced_debugging_wizard.py +0 -395
  216. empathy_software_plugin/wizards/agent_orchestration_wizard.py +0 -511
  217. empathy_software_plugin/wizards/ai_collaboration_wizard.py +0 -503
  218. empathy_software_plugin/wizards/ai_context_wizard.py +0 -441
  219. empathy_software_plugin/wizards/ai_documentation_wizard.py +0 -503
  220. empathy_software_plugin/wizards/base_wizard.py +0 -288
  221. empathy_software_plugin/wizards/book_chapter_wizard.py +0 -519
  222. empathy_software_plugin/wizards/code_review_wizard.py +0 -604
  223. empathy_software_plugin/wizards/debugging/__init__.py +0 -50
  224. empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +0 -414
  225. empathy_software_plugin/wizards/debugging/config_loaders.py +0 -446
  226. empathy_software_plugin/wizards/debugging/fix_applier.py +0 -469
  227. empathy_software_plugin/wizards/debugging/language_patterns.py +0 -385
  228. empathy_software_plugin/wizards/debugging/linter_parsers.py +0 -470
  229. empathy_software_plugin/wizards/debugging/verification.py +0 -369
  230. empathy_software_plugin/wizards/enhanced_testing_wizard.py +0 -537
  231. empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +0 -816
  232. empathy_software_plugin/wizards/multi_model_wizard.py +0 -501
  233. empathy_software_plugin/wizards/pattern_extraction_wizard.py +0 -422
  234. empathy_software_plugin/wizards/pattern_retriever_wizard.py +0 -400
  235. empathy_software_plugin/wizards/performance/__init__.py +0 -9
  236. empathy_software_plugin/wizards/performance/bottleneck_detector.py +0 -221
  237. empathy_software_plugin/wizards/performance/profiler_parsers.py +0 -278
  238. empathy_software_plugin/wizards/performance/trajectory_analyzer.py +0 -429
  239. empathy_software_plugin/wizards/performance_profiling_wizard.py +0 -305
  240. empathy_software_plugin/wizards/prompt_engineering_wizard.py +0 -425
  241. empathy_software_plugin/wizards/rag_pattern_wizard.py +0 -461
  242. empathy_software_plugin/wizards/security/__init__.py +0 -32
  243. empathy_software_plugin/wizards/security/exploit_analyzer.py +0 -290
  244. empathy_software_plugin/wizards/security/owasp_patterns.py +0 -241
  245. empathy_software_plugin/wizards/security/vulnerability_scanner.py +0 -604
  246. empathy_software_plugin/wizards/security_analysis_wizard.py +0 -322
  247. empathy_software_plugin/wizards/security_learning_wizard.py +0 -740
  248. empathy_software_plugin/wizards/tech_debt_wizard.py +0 -726
  249. empathy_software_plugin/wizards/testing/__init__.py +0 -27
  250. empathy_software_plugin/wizards/testing/coverage_analyzer.py +0 -459
  251. empathy_software_plugin/wizards/testing/quality_analyzer.py +0 -525
  252. empathy_software_plugin/wizards/testing/test_suggester.py +0 -533
  253. empathy_software_plugin/wizards/testing_wizard.py +0 -274
  254. wizards/__init__.py +0 -82
  255. wizards/admission_assessment_wizard.py +0 -644
  256. wizards/care_plan.py +0 -321
  257. wizards/clinical_assessment.py +0 -769
  258. wizards/discharge_planning.py +0 -77
  259. wizards/discharge_summary_wizard.py +0 -468
  260. wizards/dosage_calculation.py +0 -497
  261. wizards/incident_report_wizard.py +0 -454
  262. wizards/medication_reconciliation.py +0 -85
  263. wizards/nursing_assessment.py +0 -171
  264. wizards/patient_education.py +0 -654
  265. wizards/quality_improvement.py +0 -705
  266. wizards/sbar_report.py +0 -324
  267. wizards/sbar_wizard.py +0 -608
  268. wizards/shift_handoff_wizard.py +0 -535
  269. wizards/soap_note_wizard.py +0 -679
  270. wizards/treatment_plan.py +0 -15
  271. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/WHEEL +0 -0
  272. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/entry_points.txt +0 -0
  273. {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,218 @@
1
+ """Agent Loader
2
+
3
+ Loads agents from directory structures.
4
+
5
+ Copyright 2025 Smart-AI-Memory
6
+ Licensed under Fair Source License 0.9
7
+ """
8
+
9
+ import logging
10
+ from collections.abc import Iterator
11
+ from pathlib import Path
12
+
13
+ from empathy_llm_toolkit.agents_md.parser import MarkdownAgentParser
14
+ from empathy_llm_toolkit.config.unified import UnifiedAgentConfig
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class AgentLoader:
20
+ """Loader for discovering and loading markdown agent files.
21
+
22
+ Scans directories for .md files with agent definitions and loads them
23
+ into UnifiedAgentConfig instances.
24
+
25
+ Example:
26
+ loader = AgentLoader()
27
+
28
+ # Load a single agent
29
+ config = loader.load("agents/architect.md")
30
+
31
+ # Load all agents from a directory
32
+ agents = loader.load_directory("agents/")
33
+
34
+ # Discover and iterate agents lazily
35
+ for config in loader.discover("agents/"):
36
+ print(config.name)
37
+ """
38
+
39
+ def __init__(self, parser: MarkdownAgentParser | None = None):
40
+ """Initialize the loader.
41
+
42
+ Args:
43
+ parser: Optional custom parser instance
44
+
45
+ """
46
+ self.parser = parser or MarkdownAgentParser()
47
+
48
+ def load(self, file_path: str | Path) -> UnifiedAgentConfig:
49
+ """Load a single agent file.
50
+
51
+ Args:
52
+ file_path: Path to the agent markdown file
53
+
54
+ Returns:
55
+ UnifiedAgentConfig instance
56
+
57
+ """
58
+ return self.parser.parse_file(file_path)
59
+
60
+ def load_directory(
61
+ self,
62
+ directory: str | Path,
63
+ recursive: bool = False,
64
+ ) -> dict[str, UnifiedAgentConfig]:
65
+ """Load all agents from a directory.
66
+
67
+ Args:
68
+ directory: Directory to scan for .md files
69
+ recursive: If True, scan subdirectories
70
+
71
+ Returns:
72
+ Dictionary mapping agent names to configs
73
+
74
+ """
75
+ agents = {}
76
+
77
+ for config in self.discover(directory, recursive=recursive):
78
+ if config.name in agents:
79
+ logger.warning(
80
+ "Duplicate agent name '%s' - keeping first occurrence",
81
+ config.name,
82
+ )
83
+ continue
84
+ agents[config.name] = config
85
+
86
+ logger.info("Loaded %d agent(s) from %s", len(agents), directory)
87
+ return agents
88
+
89
+ def discover(
90
+ self,
91
+ directory: str | Path,
92
+ recursive: bool = False,
93
+ ) -> Iterator[UnifiedAgentConfig]:
94
+ """Discover and yield agents from a directory.
95
+
96
+ Args:
97
+ directory: Directory to scan
98
+ recursive: If True, scan subdirectories
99
+
100
+ Yields:
101
+ UnifiedAgentConfig instances
102
+
103
+ """
104
+ directory = Path(directory)
105
+
106
+ if not directory.exists():
107
+ logger.warning("Agent directory not found: %s", directory)
108
+ return
109
+
110
+ if not directory.is_dir():
111
+ raise ValueError(f"Not a directory: {directory}")
112
+
113
+ # Get pattern for globbing
114
+ pattern = "**/*.md" if recursive else "*.md"
115
+
116
+ for file_path in sorted(directory.glob(pattern)):
117
+ if not file_path.is_file():
118
+ continue
119
+
120
+ # Skip files that don't look like agent definitions
121
+ if file_path.name.startswith("_"):
122
+ continue
123
+ if file_path.name.upper() in ("README.MD", "CHANGELOG.MD"):
124
+ continue
125
+
126
+ try:
127
+ config = self.parser.parse_file(file_path)
128
+ yield config
129
+ except ValueError as e:
130
+ logger.warning("Skipping invalid agent file %s: %s", file_path, e)
131
+ except Exception as e:
132
+ logger.error("Error loading agent file %s: %s", file_path, e)
133
+
134
+ def validate_directory(
135
+ self,
136
+ directory: str | Path,
137
+ recursive: bool = False,
138
+ ) -> dict[str, list[str]]:
139
+ """Validate all agent files in a directory.
140
+
141
+ Args:
142
+ directory: Directory to validate
143
+ recursive: If True, scan subdirectories
144
+
145
+ Returns:
146
+ Dictionary mapping file paths to lists of errors
147
+
148
+ """
149
+ directory = Path(directory)
150
+ results = {}
151
+
152
+ pattern = "**/*.md" if recursive else "*.md"
153
+
154
+ for file_path in sorted(directory.glob(pattern)):
155
+ if not file_path.is_file():
156
+ continue
157
+ if file_path.name.startswith("_"):
158
+ continue
159
+ if file_path.name.upper() in ("README.MD", "CHANGELOG.MD"):
160
+ continue
161
+
162
+ errors = self.parser.validate_file(file_path)
163
+ if errors:
164
+ results[str(file_path)] = errors
165
+
166
+ return results
167
+
168
+ def get_agent_names(
169
+ self,
170
+ directory: str | Path,
171
+ recursive: bool = False,
172
+ ) -> list[str]:
173
+ """Get list of agent names in a directory without fully loading.
174
+
175
+ Args:
176
+ directory: Directory to scan
177
+ recursive: If True, scan subdirectories
178
+
179
+ Returns:
180
+ List of agent names
181
+
182
+ """
183
+ names = []
184
+ for config in self.discover(directory, recursive=recursive):
185
+ names.append(config.name)
186
+ return names
187
+
188
+
189
+ def load_agents_from_paths(
190
+ paths: list[str | Path],
191
+ parser: MarkdownAgentParser | None = None,
192
+ ) -> dict[str, UnifiedAgentConfig]:
193
+ """Load agents from multiple paths (files or directories).
194
+
195
+ Args:
196
+ paths: List of file or directory paths
197
+ parser: Optional custom parser
198
+
199
+ Returns:
200
+ Dictionary mapping agent names to configs
201
+
202
+ """
203
+ loader = AgentLoader(parser=parser)
204
+ agents = {}
205
+
206
+ for path in paths:
207
+ path = Path(path)
208
+
209
+ if path.is_file():
210
+ config = loader.load(path)
211
+ agents[config.name] = config
212
+ elif path.is_dir():
213
+ dir_agents = loader.load_directory(path)
214
+ agents.update(dir_agents)
215
+ else:
216
+ logger.warning("Path not found: %s", path)
217
+
218
+ return agents
@@ -0,0 +1,271 @@
1
+ """Markdown Agent Parser
2
+
3
+ Parses Markdown files with YAML frontmatter into UnifiedAgentConfig.
4
+
5
+ Copyright 2025 Smart-AI-Memory
6
+ Licensed under Fair Source License 0.9
7
+ """
8
+
9
+ import logging
10
+ import re
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ from empathy_llm_toolkit.config.unified import ModelTier, Provider, UnifiedAgentConfig
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+ # YAML frontmatter regex pattern
19
+ FRONTMATTER_PATTERN = re.compile(
20
+ r"^---\s*\n(.*?)\n---\s*\n",
21
+ re.DOTALL,
22
+ )
23
+
24
+
25
+ class MarkdownAgentParser:
26
+ """Parser for Markdown agent definition files.
27
+
28
+ Parses files with YAML frontmatter containing agent configuration,
29
+ followed by Markdown content that becomes the system prompt.
30
+
31
+ Example file format:
32
+ ---
33
+ name: architect
34
+ description: Software architecture specialist
35
+ model: capable
36
+ tools: Read, Grep, Glob
37
+ empathy_level: 4
38
+ ---
39
+
40
+ You are an expert software architect...
41
+
42
+ Example usage:
43
+ parser = MarkdownAgentParser()
44
+ config = parser.parse_file("agents/architect.md")
45
+ """
46
+
47
+ # Mapping from string model names to ModelTier
48
+ MODEL_TIER_MAP = {
49
+ "cheap": ModelTier.CHEAP,
50
+ "haiku": ModelTier.CHEAP,
51
+ "capable": ModelTier.CAPABLE,
52
+ "sonnet": ModelTier.CAPABLE,
53
+ "premium": ModelTier.PREMIUM,
54
+ "opus": ModelTier.PREMIUM,
55
+ }
56
+
57
+ # Mapping from string provider names to Provider
58
+ PROVIDER_MAP = {
59
+ "anthropic": Provider.ANTHROPIC,
60
+ "openai": Provider.OPENAI,
61
+ "local": Provider.LOCAL,
62
+ }
63
+
64
+ def __init__(self):
65
+ """Initialize the parser."""
66
+ pass
67
+
68
+ def parse_file(self, file_path: str | Path) -> UnifiedAgentConfig:
69
+ """Parse a Markdown agent file into UnifiedAgentConfig.
70
+
71
+ Args:
72
+ file_path: Path to the Markdown agent file
73
+
74
+ Returns:
75
+ UnifiedAgentConfig instance
76
+
77
+ Raises:
78
+ FileNotFoundError: If file doesn't exist
79
+ ValueError: If file format is invalid
80
+
81
+ """
82
+ file_path = Path(file_path)
83
+
84
+ if not file_path.exists():
85
+ raise FileNotFoundError(f"Agent file not found: {file_path}")
86
+
87
+ with open(file_path, encoding="utf-8") as f:
88
+ content = f.read()
89
+
90
+ return self.parse_content(content, source=str(file_path))
91
+
92
+ def parse_content(
93
+ self,
94
+ content: str,
95
+ source: str = "unknown",
96
+ ) -> UnifiedAgentConfig:
97
+ """Parse Markdown content into UnifiedAgentConfig.
98
+
99
+ Args:
100
+ content: Markdown content with YAML frontmatter
101
+ source: Source identifier for error messages
102
+
103
+ Returns:
104
+ UnifiedAgentConfig instance
105
+
106
+ Raises:
107
+ ValueError: If content format is invalid
108
+
109
+ """
110
+ # Extract frontmatter
111
+ match = FRONTMATTER_PATTERN.match(content)
112
+
113
+ if not match:
114
+ raise ValueError(f"Invalid agent file format - missing YAML frontmatter: {source}")
115
+
116
+ frontmatter_yaml = match.group(1)
117
+ body = content[match.end() :].strip()
118
+
119
+ # Parse YAML
120
+ try:
121
+ import yaml
122
+
123
+ frontmatter = yaml.safe_load(frontmatter_yaml) or {}
124
+ except yaml.YAMLError as e:
125
+ raise ValueError(f"Invalid YAML frontmatter in {source}: {e}")
126
+
127
+ return self._create_config(frontmatter, body, source)
128
+
129
+ def _create_config(
130
+ self,
131
+ frontmatter: dict[str, Any],
132
+ body: str,
133
+ source: str,
134
+ ) -> UnifiedAgentConfig:
135
+ """Create UnifiedAgentConfig from parsed data.
136
+
137
+ Args:
138
+ frontmatter: Parsed YAML frontmatter
139
+ body: Markdown body content
140
+ source: Source identifier
141
+
142
+ Returns:
143
+ UnifiedAgentConfig instance
144
+
145
+ """
146
+ # Required field
147
+ name = frontmatter.get("name")
148
+ if not name:
149
+ raise ValueError(f"Agent file missing required 'name' field: {source}")
150
+
151
+ # Parse model tier
152
+ model_str = frontmatter.get("model", "capable").lower()
153
+ model_tier = self.MODEL_TIER_MAP.get(model_str, ModelTier.CAPABLE)
154
+
155
+ # Parse provider
156
+ provider_str = frontmatter.get("provider", "anthropic").lower()
157
+ provider = self.PROVIDER_MAP.get(provider_str, Provider.ANTHROPIC)
158
+
159
+ # Parse tools list
160
+ tools_raw = frontmatter.get("tools", [])
161
+ if isinstance(tools_raw, str):
162
+ # Handle comma-separated string
163
+ tools = [t.strip() for t in tools_raw.split(",")]
164
+ else:
165
+ tools = list(tools_raw)
166
+
167
+ # Parse capabilities
168
+ capabilities = frontmatter.get("capabilities", [])
169
+ if isinstance(capabilities, str):
170
+ capabilities = [c.strip() for c in capabilities.split(",")]
171
+
172
+ # Build config
173
+ config = UnifiedAgentConfig(
174
+ name=name,
175
+ role=frontmatter.get("role", name),
176
+ description=frontmatter.get("description", ""),
177
+ model_tier=model_tier,
178
+ model_override=frontmatter.get("model_override"),
179
+ provider=provider,
180
+ empathy_level=int(frontmatter.get("empathy_level", 4)),
181
+ memory_enabled=frontmatter.get("memory_enabled", True),
182
+ pattern_learning=frontmatter.get("pattern_learning", True),
183
+ cost_tracking=frontmatter.get("cost_tracking", True),
184
+ use_patterns=frontmatter.get("use_patterns", True),
185
+ temperature=float(frontmatter.get("temperature", 0.7)),
186
+ max_tokens=int(frontmatter.get("max_tokens", 4096)),
187
+ timeout=int(frontmatter.get("timeout", 120)),
188
+ retry_attempts=int(frontmatter.get("retry_attempts", 3)),
189
+ retry_delay=float(frontmatter.get("retry_delay", 1.0)),
190
+ system_prompt=body if body else None,
191
+ tools=tools,
192
+ capabilities=capabilities,
193
+ framework_options=frontmatter.get("framework_options", {}),
194
+ extra={
195
+ "source_file": source,
196
+ "raw_frontmatter": frontmatter,
197
+ "interaction_mode": frontmatter.get("interaction_mode", "standard"),
198
+ "socratic_config": frontmatter.get("socratic_config", {}),
199
+ },
200
+ )
201
+
202
+ logger.debug("Parsed agent config: %s from %s", name, source)
203
+ return config
204
+
205
+ def validate_file(self, file_path: str | Path) -> list[str]:
206
+ """Validate a Markdown agent file without fully parsing.
207
+
208
+ Args:
209
+ file_path: Path to validate
210
+
211
+ Returns:
212
+ List of validation error messages (empty if valid)
213
+
214
+ """
215
+ errors = []
216
+ file_path = Path(file_path)
217
+
218
+ if not file_path.exists():
219
+ return [f"File not found: {file_path}"]
220
+
221
+ try:
222
+ with open(file_path, encoding="utf-8") as f:
223
+ content = f.read()
224
+ except OSError as e:
225
+ return [f"Cannot read file: {e}"]
226
+
227
+ # Check frontmatter
228
+ match = FRONTMATTER_PATTERN.match(content)
229
+ if not match:
230
+ errors.append("Missing YAML frontmatter (must start with ---)")
231
+ return errors
232
+
233
+ # Parse YAML
234
+ try:
235
+ import yaml
236
+
237
+ frontmatter = yaml.safe_load(match.group(1)) or {}
238
+ except yaml.YAMLError as e:
239
+ errors.append(f"Invalid YAML: {e}")
240
+ return errors
241
+
242
+ # Check required fields
243
+ if not frontmatter.get("name"):
244
+ errors.append("Missing required field: name")
245
+
246
+ # Validate model tier
247
+ model = frontmatter.get("model", "").lower()
248
+ if model and model not in self.MODEL_TIER_MAP:
249
+ errors.append(
250
+ f"Invalid model '{model}'. Valid options: {', '.join(self.MODEL_TIER_MAP.keys())}"
251
+ )
252
+
253
+ # Validate provider
254
+ provider = frontmatter.get("provider", "").lower()
255
+ if provider and provider not in self.PROVIDER_MAP:
256
+ errors.append(
257
+ f"Invalid provider '{provider}'. "
258
+ f"Valid options: {', '.join(self.PROVIDER_MAP.keys())}"
259
+ )
260
+
261
+ # Validate empathy level
262
+ empathy_level = frontmatter.get("empathy_level")
263
+ if empathy_level is not None:
264
+ try:
265
+ level = int(empathy_level)
266
+ if not 1 <= level <= 5:
267
+ errors.append(f"empathy_level must be 1-5, got {level}")
268
+ except (TypeError, ValueError):
269
+ errors.append(f"empathy_level must be an integer, got {empathy_level}")
270
+
271
+ return errors