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
@@ -179,13 +179,15 @@ class JSONFileStorage(StorageBackend):
179
179
  if state and data.get("state") != state.value:
180
180
  continue
181
181
 
182
- sessions.append({
183
- "session_id": data.get("session_id"),
184
- "state": data.get("state"),
185
- "goal": data.get("goal", "")[:100],
186
- "created_at": data.get("created_at"),
187
- "updated_at": data.get("updated_at"),
188
- })
182
+ sessions.append(
183
+ {
184
+ "session_id": data.get("session_id"),
185
+ "state": data.get("state"),
186
+ "goal": data.get("goal", "")[:100],
187
+ "created_at": data.get("created_at"),
188
+ "updated_at": data.get("updated_at"),
189
+ }
190
+ )
189
191
  except (json.JSONDecodeError, KeyError):
190
192
  continue
191
193
 
@@ -245,13 +247,15 @@ class JSONFileStorage(StorageBackend):
245
247
  if domain and data.get("domain") != domain:
246
248
  continue
247
249
 
248
- blueprints.append({
249
- "id": data.get("id"),
250
- "name": data.get("name"),
251
- "domain": data.get("domain"),
252
- "agents_count": len(data.get("agents", [])),
253
- "generated_at": data.get("generated_at"),
254
- })
250
+ blueprints.append(
251
+ {
252
+ "id": data.get("id"),
253
+ "name": data.get("name"),
254
+ "domain": data.get("domain"),
255
+ "agents_count": len(data.get("agents", [])),
256
+ "generated_at": data.get("generated_at"),
257
+ }
258
+ )
255
259
  except (json.JSONDecodeError, KeyError):
256
260
  continue
257
261
 
@@ -329,7 +333,8 @@ class SQLiteStorage(StorageBackend):
329
333
  def _init_database(self) -> None:
330
334
  """Initialize database schema."""
331
335
  with self._get_connection() as conn:
332
- conn.executescript("""
336
+ conn.executescript(
337
+ """
333
338
  CREATE TABLE IF NOT EXISTS sessions (
334
339
  session_id TEXT PRIMARY KEY,
335
340
  state TEXT NOT NULL,
@@ -370,7 +375,8 @@ class SQLiteStorage(StorageBackend):
370
375
  );
371
376
 
372
377
  CREATE INDEX IF NOT EXISTS idx_evaluations_blueprint ON evaluations(blueprint_id);
373
- """)
378
+ """
379
+ )
374
380
 
375
381
  def save_session(self, session: SocraticSession) -> None:
376
382
  """Save session to database."""
@@ -379,27 +385,29 @@ class SQLiteStorage(StorageBackend):
379
385
  confidence = session.goal_analysis.confidence if session.goal_analysis else None
380
386
 
381
387
  with self._get_connection() as conn:
382
- conn.execute("""
388
+ conn.execute(
389
+ """
383
390
  INSERT OR REPLACE INTO sessions
384
391
  (session_id, state, goal, domain, confidence, created_at, updated_at, data)
385
392
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
386
- """, (
387
- session.session_id,
388
- session.state.value,
389
- session.goal,
390
- domain,
391
- confidence,
392
- session.created_at.isoformat(),
393
- session.updated_at.isoformat(),
394
- json.dumps(data, default=str),
395
- ))
393
+ """,
394
+ (
395
+ session.session_id,
396
+ session.state.value,
397
+ session.goal,
398
+ domain,
399
+ confidence,
400
+ session.created_at.isoformat(),
401
+ session.updated_at.isoformat(),
402
+ json.dumps(data, default=str),
403
+ ),
404
+ )
396
405
 
397
406
  def load_session(self, session_id: str) -> SocraticSession | None:
398
407
  """Load session from database."""
399
408
  with self._get_connection() as conn:
400
409
  row = conn.execute(
401
- "SELECT data FROM sessions WHERE session_id = ?",
402
- (session_id,)
410
+ "SELECT data FROM sessions WHERE session_id = ?", (session_id,)
403
411
  ).fetchone()
404
412
 
405
413
  if row:
@@ -415,30 +423,33 @@ class SQLiteStorage(StorageBackend):
415
423
  """List sessions from database."""
416
424
  with self._get_connection() as conn:
417
425
  if state:
418
- rows = conn.execute("""
426
+ rows = conn.execute(
427
+ """
419
428
  SELECT session_id, state, goal, domain, confidence, created_at, updated_at
420
429
  FROM sessions
421
430
  WHERE state = ?
422
431
  ORDER BY updated_at DESC
423
432
  LIMIT ?
424
- """, (state.value, limit)).fetchall()
433
+ """,
434
+ (state.value, limit),
435
+ ).fetchall()
425
436
  else:
426
- rows = conn.execute("""
437
+ rows = conn.execute(
438
+ """
427
439
  SELECT session_id, state, goal, domain, confidence, created_at, updated_at
428
440
  FROM sessions
429
441
  ORDER BY updated_at DESC
430
442
  LIMIT ?
431
- """, (limit,)).fetchall()
443
+ """,
444
+ (limit,),
445
+ ).fetchall()
432
446
 
433
447
  return [dict(row) for row in rows]
434
448
 
435
449
  def delete_session(self, session_id: str) -> bool:
436
450
  """Delete session from database."""
437
451
  with self._get_connection() as conn:
438
- cursor = conn.execute(
439
- "DELETE FROM sessions WHERE session_id = ?",
440
- (session_id,)
441
- )
452
+ cursor = conn.execute("DELETE FROM sessions WHERE session_id = ?", (session_id,))
442
453
  return cursor.rowcount > 0
443
454
 
444
455
  def save_blueprint(self, blueprint: WorkflowBlueprint) -> None:
@@ -446,26 +457,28 @@ class SQLiteStorage(StorageBackend):
446
457
  data = blueprint.to_dict()
447
458
 
448
459
  with self._get_connection() as conn:
449
- conn.execute("""
460
+ conn.execute(
461
+ """
450
462
  INSERT OR REPLACE INTO blueprints
451
463
  (blueprint_id, name, domain, agents_count, generated_at, source_session_id, data)
452
464
  VALUES (?, ?, ?, ?, ?, ?, ?)
453
- """, (
454
- blueprint.id,
455
- blueprint.name,
456
- blueprint.domain,
457
- len(blueprint.agents),
458
- blueprint.generated_at,
459
- blueprint.source_session_id,
460
- json.dumps(data, default=str),
461
- ))
465
+ """,
466
+ (
467
+ blueprint.id,
468
+ blueprint.name,
469
+ blueprint.domain,
470
+ len(blueprint.agents),
471
+ blueprint.generated_at,
472
+ blueprint.source_session_id,
473
+ json.dumps(data, default=str),
474
+ ),
475
+ )
462
476
 
463
477
  def load_blueprint(self, blueprint_id: str) -> WorkflowBlueprint | None:
464
478
  """Load blueprint from database."""
465
479
  with self._get_connection() as conn:
466
480
  row = conn.execute(
467
- "SELECT data FROM blueprints WHERE blueprint_id = ?",
468
- (blueprint_id,)
481
+ "SELECT data FROM blueprints WHERE blueprint_id = ?", (blueprint_id,)
469
482
  ).fetchone()
470
483
 
471
484
  if row:
@@ -481,20 +494,26 @@ class SQLiteStorage(StorageBackend):
481
494
  """List blueprints from database."""
482
495
  with self._get_connection() as conn:
483
496
  if domain:
484
- rows = conn.execute("""
497
+ rows = conn.execute(
498
+ """
485
499
  SELECT blueprint_id as id, name, domain, agents_count, generated_at
486
500
  FROM blueprints
487
501
  WHERE domain = ?
488
502
  ORDER BY generated_at DESC
489
503
  LIMIT ?
490
- """, (domain, limit)).fetchall()
504
+ """,
505
+ (domain, limit),
506
+ ).fetchall()
491
507
  else:
492
- rows = conn.execute("""
508
+ rows = conn.execute(
509
+ """
493
510
  SELECT blueprint_id as id, name, domain, agents_count, generated_at
494
511
  FROM blueprints
495
512
  ORDER BY generated_at DESC
496
513
  LIMIT ?
497
- """, (limit,)).fetchall()
514
+ """,
515
+ (limit,),
516
+ ).fetchall()
498
517
 
499
518
  return [dict(row) for row in rows]
500
519
 
@@ -507,17 +526,20 @@ class SQLiteStorage(StorageBackend):
507
526
  data = evaluation.to_dict()
508
527
 
509
528
  with self._get_connection() as conn:
510
- conn.execute("""
529
+ conn.execute(
530
+ """
511
531
  INSERT INTO evaluations
512
532
  (blueprint_id, overall_success, overall_score, evaluated_at, data)
513
533
  VALUES (?, ?, ?, ?, ?)
514
- """, (
515
- blueprint_id,
516
- 1 if evaluation.overall_success else 0,
517
- evaluation.overall_score,
518
- evaluation.evaluated_at,
519
- json.dumps(data, default=str),
520
- ))
534
+ """,
535
+ (
536
+ blueprint_id,
537
+ 1 if evaluation.overall_success else 0,
538
+ evaluation.overall_score,
539
+ evaluation.evaluated_at,
540
+ json.dumps(data, default=str),
541
+ ),
542
+ )
521
543
 
522
544
  def get_evaluations(
523
545
  self,
@@ -526,25 +548,31 @@ class SQLiteStorage(StorageBackend):
526
548
  ) -> list[dict[str, Any]]:
527
549
  """Get evaluations from database."""
528
550
  with self._get_connection() as conn:
529
- rows = conn.execute("""
551
+ rows = conn.execute(
552
+ """
530
553
  SELECT data FROM evaluations
531
554
  WHERE blueprint_id = ?
532
555
  ORDER BY evaluated_at DESC
533
556
  LIMIT ?
534
- """, (blueprint_id, limit)).fetchall()
557
+ """,
558
+ (blueprint_id, limit),
559
+ ).fetchall()
535
560
 
536
561
  return [json.loads(row["data"]) for row in rows]
537
562
 
538
563
  def get_success_rate(self, blueprint_id: str) -> float:
539
564
  """Get overall success rate for a blueprint."""
540
565
  with self._get_connection() as conn:
541
- row = conn.execute("""
566
+ row = conn.execute(
567
+ """
542
568
  SELECT
543
569
  COUNT(*) as total,
544
570
  SUM(overall_success) as successes
545
571
  FROM evaluations
546
572
  WHERE blueprint_id = ?
547
- """, (blueprint_id,)).fetchone()
573
+ """,
574
+ (blueprint_id,),
575
+ ).fetchone()
548
576
 
549
577
  if row and row["total"] > 0:
550
578
  return row["successes"] / row["total"]
@@ -557,13 +585,16 @@ class SQLiteStorage(StorageBackend):
557
585
  ) -> list[dict[str, Any]]:
558
586
  """Search blueprints by name or domain."""
559
587
  with self._get_connection() as conn:
560
- rows = conn.execute("""
588
+ rows = conn.execute(
589
+ """
561
590
  SELECT blueprint_id as id, name, domain, agents_count, generated_at
562
591
  FROM blueprints
563
592
  WHERE name LIKE ? OR domain LIKE ?
564
593
  ORDER BY generated_at DESC
565
594
  LIMIT ?
566
- """, (f"%{query}%", f"%{query}%", limit)).fetchall()
595
+ """,
596
+ (f"%{query}%", f"%{query}%", limit),
597
+ ).fetchall()
567
598
 
568
599
  return [dict(row) for row in rows]
569
600
 
@@ -147,7 +147,9 @@ class SuccessMetric:
147
147
  if self.maximum_value is not None:
148
148
  met = value <= self.maximum_value
149
149
  # Score is inverse ratio (lower is better)
150
- score = max(1.0 - (value / self.maximum_value), 0.0) if self.maximum_value > 0 else 1.0
150
+ score = (
151
+ max(1.0 - (value / self.maximum_value), 0.0) if self.maximum_value > 0 else 1.0
152
+ )
151
153
  else:
152
154
  met = True
153
155
  score = 1.0
@@ -204,7 +206,11 @@ class SuccessMetric:
204
206
  parts.append(f"Measured: {value}")
205
207
 
206
208
  # Comparison to baseline
207
- if baseline is not None and isinstance(value, (int, float)) and isinstance(baseline, (int, float)):
209
+ if (
210
+ baseline is not None
211
+ and isinstance(value, (int, float))
212
+ and isinstance(baseline, (int, float))
213
+ ):
208
214
  diff = value - baseline
209
215
  pct_change = (diff / baseline * 100) if baseline != 0 else 0
210
216
  direction = "↑" if diff > 0 else "↓" if diff < 0 else "→"
@@ -336,14 +342,16 @@ class SuccessCriteria:
336
342
 
337
343
  if value is None:
338
344
  # Metric not found in output
339
- results.append(MetricResult(
340
- metric_id=metric.id,
341
- value=0,
342
- met_criteria=False,
343
- score=0.0,
344
- explanation=f"Metric '{metric.name}' not found in output",
345
- timestamp=timestamp,
346
- ))
345
+ results.append(
346
+ MetricResult(
347
+ metric_id=metric.id,
348
+ value=0,
349
+ met_criteria=False,
350
+ score=0.0,
351
+ explanation=f"Metric '{metric.name}' not found in output",
352
+ timestamp=timestamp,
353
+ )
354
+ )
347
355
  continue
348
356
 
349
357
  # Get baseline if available
@@ -352,15 +360,17 @@ class SuccessCriteria:
352
360
  # Evaluate
353
361
  met, score, explanation = metric.evaluate(value, baseline)
354
362
 
355
- results.append(MetricResult(
356
- metric_id=metric.id,
357
- value=value,
358
- met_criteria=met,
359
- score=score,
360
- explanation=explanation,
361
- baseline=baseline,
362
- timestamp=timestamp,
363
- ))
363
+ results.append(
364
+ MetricResult(
365
+ metric_id=metric.id,
366
+ value=value,
367
+ met_criteria=met,
368
+ score=score,
369
+ explanation=explanation,
370
+ baseline=baseline,
371
+ timestamp=timestamp,
372
+ )
373
+ )
364
374
 
365
375
  # Calculate overall success
366
376
  return self._calculate_overall_success(results)
@@ -419,8 +429,7 @@ class SuccessCriteria:
419
429
 
420
430
  # Check primary metrics
421
431
  primary_results = [
422
- r for r in results
423
- if any(m.id == r.metric_id and m.is_primary for m in self.metrics)
432
+ r for r in results if any(m.id == r.metric_id and m.is_primary for m in self.metrics)
424
433
  ]
425
434
  primary_passed = sum(1 for r in primary_results if r.met_criteria)
426
435
 
@@ -435,15 +444,17 @@ class SuccessCriteria:
435
444
  else:
436
445
  # Weighted average score
437
446
  total_weight = sum(
438
- m.weight for m in self.metrics
439
- if any(r.metric_id == m.id for r in results)
447
+ m.weight for m in self.metrics if any(r.metric_id == m.id for r in results)
440
448
  )
441
449
 
442
450
  if total_weight > 0:
443
- weighted_score = sum(
444
- r.score * next((m.weight for m in self.metrics if m.id == r.metric_id), 1.0)
445
- for r in results
446
- ) / total_weight
451
+ weighted_score = (
452
+ sum(
453
+ r.score * next((m.weight for m in self.metrics if m.id == r.metric_id), 1.0)
454
+ for r in results
455
+ )
456
+ / total_weight
457
+ )
447
458
  else:
448
459
  weighted_score = sum(r.score for r in results) / len(results)
449
460
 
@@ -63,7 +63,9 @@ class EditorNode:
63
63
 
64
64
  def to_dict(self) -> dict[str, Any]:
65
65
  # Handle both string and enum for node_type
66
- node_type_str = self.node_type.value if isinstance(self.node_type, NodeType) else self.node_type
66
+ node_type_str = (
67
+ self.node_type.value if isinstance(self.node_type, NodeType) else self.node_type
68
+ )
67
69
  # Handle both dict and Position for position
68
70
  pos_dict = self.position.to_dict() if isinstance(self.position, Position) else self.position
69
71
  return {
@@ -193,20 +195,24 @@ class WorkflowVisualizer:
193
195
 
194
196
  # Connect from start or dependencies
195
197
  if first_stage:
196
- edges.append(EditorEdge(
197
- edge_id=f"start->{stage.id}",
198
- source="start",
199
- target=stage.id,
200
- animated=True,
201
- ))
198
+ edges.append(
199
+ EditorEdge(
200
+ edge_id=f"start->{stage.id}",
201
+ source="start",
202
+ target=stage.id,
203
+ animated=True,
204
+ )
205
+ )
202
206
  first_stage = False
203
207
  else:
204
208
  for dep in stage.depends_on:
205
- edges.append(EditorEdge(
206
- edge_id=f"{dep}->{stage.id}",
207
- source=dep,
208
- target=stage.id,
209
- ))
209
+ edges.append(
210
+ EditorEdge(
211
+ edge_id=f"{dep}->{stage.id}",
212
+ source=dep,
213
+ target=stage.id,
214
+ )
215
+ )
210
216
 
211
217
  # Create agent nodes for this stage
212
218
  agent_x_start = 200
@@ -232,11 +238,13 @@ class WorkflowVisualizer:
232
238
  nodes.append(agent_node)
233
239
 
234
240
  # Connect stage to agent
235
- edges.append(EditorEdge(
236
- edge_id=f"{stage.id}->{agent_id}",
237
- source=stage.id,
238
- target=agent_id,
239
- ))
241
+ edges.append(
242
+ EditorEdge(
243
+ edge_id=f"{stage.id}->{agent_id}",
244
+ source=stage.id,
245
+ target=agent_id,
246
+ )
247
+ )
240
248
 
241
249
  y_offset += self.stage_spacing
242
250
 
@@ -253,12 +261,14 @@ class WorkflowVisualizer:
253
261
  # Connect last stage to end
254
262
  if blueprint.stages:
255
263
  last_stage = blueprint.stages[-1]
256
- edges.append(EditorEdge(
257
- edge_id=f"{last_stage.id}->end",
258
- source=last_stage.id,
259
- target="end",
260
- animated=True,
261
- ))
264
+ edges.append(
265
+ EditorEdge(
266
+ edge_id=f"{last_stage.id}->end",
267
+ source=last_stage.id,
268
+ target="end",
269
+ animated=True,
270
+ )
271
+ )
262
272
 
263
273
  return EditorState(workflow_id=blueprint.id, nodes=nodes, edges=edges)
264
274
 
@@ -273,6 +283,7 @@ class WorkflowVisualizer:
273
283
  if original_blueprint is None:
274
284
  # Create minimal blueprint for reconstruction
275
285
  from .blueprint import WorkflowBlueprint
286
+
276
287
  original_blueprint = WorkflowBlueprint(
277
288
  id=state.workflow_id,
278
289
  name="Reconstructed Workflow",
@@ -320,21 +331,21 @@ class WorkflowVisualizer:
320
331
  dependencies = [
321
332
  source
322
333
  for source in edges_by_target.get(stage_node.node_id, [])
323
- if source != "start" and any(
324
- s.node_id == source and s.node_type == NodeType.STAGE
325
- for s in stage_nodes
326
- )
334
+ if source != "start"
335
+ and any(s.node_id == source and s.node_type == NodeType.STAGE for s in stage_nodes)
327
336
  ]
328
337
 
329
- new_stages.append(StageSpec(
330
- id=stage_node.node_id,
331
- name=stage_node.label,
332
- description=stage_node.data.get("description", f"Stage: {stage_node.label}"),
333
- agent_ids=agent_ids,
334
- depends_on=dependencies,
335
- parallel=stage_node.data.get("parallel", False),
336
- timeout=stage_node.data.get("timeout"),
337
- ))
338
+ new_stages.append(
339
+ StageSpec(
340
+ id=stage_node.node_id,
341
+ name=stage_node.label,
342
+ description=stage_node.data.get("description", f"Stage: {stage_node.label}"),
343
+ agent_ids=agent_ids,
344
+ depends_on=dependencies,
345
+ parallel=stage_node.data.get("parallel", False),
346
+ timeout=stage_node.data.get("timeout"),
347
+ )
348
+ )
338
349
 
339
350
  # Update blueprint
340
351
  return WorkflowBlueprint(
@@ -414,7 +425,7 @@ class ASCIIVisualizer:
414
425
  if stage.agent_ids:
415
426
  agent_str = " → ".join(stage.agent_ids)
416
427
  if len(agent_str) > self.width - 10:
417
- agent_str = agent_str[:self.width - 13] + "..."
428
+ agent_str = agent_str[: self.width - 13] + "..."
418
429
  lines.append(self._center(f"({agent_str})"))
419
430
 
420
431
  # Connector
@@ -636,8 +647,8 @@ def generate_editor_html(
636
647
  const {{ useState, useCallback }} = React;
637
648
  const {{ ReactFlow, Background, Controls, MiniMap }} = window.ReactFlow;
638
649
 
639
- const initialNodes = {json.dumps(react_schema['nodes'], indent=2)};
640
- const initialEdges = {json.dumps(react_schema['edges'], indent=2)};
650
+ const initialNodes = {json.dumps(react_schema["nodes"], indent=2)};
651
+ const initialEdges = {json.dumps(react_schema["edges"], indent=2)};
641
652
 
642
653
  function WorkflowEditor() {{
643
654
  const [nodes, setNodes] = useState(initialNodes);
@@ -826,6 +837,7 @@ class VisualWorkflowEditor:
826
837
  # Check for cycles (simple detection)
827
838
  # Note: A more robust implementation would use DFS
828
839
  visited: set[str] = set()
840
+
829
841
  def check_cycle(node_id: str, path: set[str]) -> bool:
830
842
  if node_id in path:
831
843
  return True