empathy-framework 4.6.6__py3-none-any.whl → 4.7.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.
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/METADATA +7 -6
- empathy_framework-4.7.0.dist-info/RECORD +354 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/top_level.txt +0 -2
- empathy_healthcare_plugin/monitors/monitoring/__init__.py +9 -9
- empathy_llm_toolkit/agent_factory/__init__.py +6 -6
- empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +7 -10
- empathy_llm_toolkit/agents_md/__init__.py +22 -0
- empathy_llm_toolkit/agents_md/loader.py +218 -0
- empathy_llm_toolkit/agents_md/parser.py +271 -0
- empathy_llm_toolkit/agents_md/registry.py +307 -0
- empathy_llm_toolkit/commands/__init__.py +51 -0
- empathy_llm_toolkit/commands/context.py +375 -0
- empathy_llm_toolkit/commands/loader.py +301 -0
- empathy_llm_toolkit/commands/models.py +231 -0
- empathy_llm_toolkit/commands/parser.py +371 -0
- empathy_llm_toolkit/commands/registry.py +429 -0
- empathy_llm_toolkit/config/__init__.py +8 -8
- empathy_llm_toolkit/config/unified.py +3 -7
- empathy_llm_toolkit/context/__init__.py +22 -0
- empathy_llm_toolkit/context/compaction.py +455 -0
- empathy_llm_toolkit/context/manager.py +434 -0
- empathy_llm_toolkit/hooks/__init__.py +24 -0
- empathy_llm_toolkit/hooks/config.py +306 -0
- empathy_llm_toolkit/hooks/executor.py +289 -0
- empathy_llm_toolkit/hooks/registry.py +302 -0
- empathy_llm_toolkit/hooks/scripts/__init__.py +39 -0
- empathy_llm_toolkit/hooks/scripts/evaluate_session.py +201 -0
- empathy_llm_toolkit/hooks/scripts/first_time_init.py +285 -0
- empathy_llm_toolkit/hooks/scripts/pre_compact.py +207 -0
- empathy_llm_toolkit/hooks/scripts/session_end.py +183 -0
- empathy_llm_toolkit/hooks/scripts/session_start.py +163 -0
- empathy_llm_toolkit/hooks/scripts/suggest_compact.py +225 -0
- empathy_llm_toolkit/learning/__init__.py +30 -0
- empathy_llm_toolkit/learning/evaluator.py +438 -0
- empathy_llm_toolkit/learning/extractor.py +514 -0
- empathy_llm_toolkit/learning/storage.py +560 -0
- empathy_llm_toolkit/providers.py +4 -11
- empathy_llm_toolkit/security/__init__.py +17 -17
- empathy_llm_toolkit/utils/tokens.py +2 -5
- empathy_os/__init__.py +202 -70
- empathy_os/cache_monitor.py +5 -3
- empathy_os/cli/__init__.py +11 -55
- empathy_os/cli/__main__.py +29 -15
- empathy_os/cli/commands/inspection.py +21 -12
- empathy_os/cli/commands/memory.py +4 -12
- empathy_os/cli/commands/profiling.py +198 -0
- empathy_os/cli/commands/utilities.py +27 -7
- empathy_os/cli.py +28 -57
- empathy_os/cli_unified.py +525 -1164
- empathy_os/cost_tracker.py +9 -3
- empathy_os/dashboard/server.py +200 -2
- empathy_os/hot_reload/__init__.py +7 -7
- empathy_os/hot_reload/config.py +6 -7
- empathy_os/hot_reload/integration.py +35 -35
- empathy_os/hot_reload/reloader.py +57 -57
- empathy_os/hot_reload/watcher.py +28 -28
- empathy_os/hot_reload/websocket.py +2 -2
- empathy_os/memory/__init__.py +11 -4
- empathy_os/memory/claude_memory.py +1 -1
- empathy_os/memory/cross_session.py +8 -12
- empathy_os/memory/edges.py +6 -6
- empathy_os/memory/file_session.py +770 -0
- empathy_os/memory/graph.py +30 -30
- empathy_os/memory/nodes.py +6 -6
- empathy_os/memory/short_term.py +15 -9
- empathy_os/memory/unified.py +606 -140
- empathy_os/meta_workflows/agent_creator.py +3 -9
- empathy_os/meta_workflows/cli_meta_workflows.py +113 -53
- empathy_os/meta_workflows/form_engine.py +6 -18
- empathy_os/meta_workflows/intent_detector.py +64 -24
- empathy_os/meta_workflows/models.py +3 -1
- empathy_os/meta_workflows/pattern_learner.py +13 -31
- empathy_os/meta_workflows/plan_generator.py +55 -47
- empathy_os/meta_workflows/session_context.py +2 -3
- empathy_os/meta_workflows/workflow.py +20 -51
- empathy_os/models/cli.py +2 -2
- empathy_os/models/tasks.py +1 -2
- empathy_os/models/telemetry.py +4 -1
- empathy_os/models/token_estimator.py +3 -1
- empathy_os/monitoring/alerts.py +938 -9
- empathy_os/monitoring/alerts_cli.py +346 -183
- empathy_os/orchestration/execution_strategies.py +12 -29
- empathy_os/orchestration/pattern_learner.py +20 -26
- empathy_os/orchestration/real_tools.py +6 -15
- empathy_os/platform_utils.py +2 -1
- empathy_os/plugins/__init__.py +2 -2
- empathy_os/plugins/base.py +64 -64
- empathy_os/plugins/registry.py +32 -32
- empathy_os/project_index/index.py +49 -15
- empathy_os/project_index/models.py +1 -2
- empathy_os/project_index/reports.py +1 -1
- empathy_os/project_index/scanner.py +1 -0
- empathy_os/redis_memory.py +10 -7
- empathy_os/resilience/__init__.py +1 -1
- empathy_os/resilience/health.py +10 -10
- empathy_os/routing/__init__.py +7 -7
- empathy_os/routing/chain_executor.py +37 -37
- empathy_os/routing/classifier.py +36 -36
- empathy_os/routing/smart_router.py +40 -40
- empathy_os/routing/{wizard_registry.py → workflow_registry.py} +47 -47
- empathy_os/scaffolding/__init__.py +8 -8
- empathy_os/scaffolding/__main__.py +1 -1
- empathy_os/scaffolding/cli.py +28 -28
- empathy_os/socratic/__init__.py +3 -19
- empathy_os/socratic/ab_testing.py +25 -36
- empathy_os/socratic/blueprint.py +38 -38
- empathy_os/socratic/cli.py +34 -20
- empathy_os/socratic/collaboration.py +30 -28
- empathy_os/socratic/domain_templates.py +9 -1
- empathy_os/socratic/embeddings.py +17 -13
- empathy_os/socratic/engine.py +135 -70
- empathy_os/socratic/explainer.py +70 -60
- empathy_os/socratic/feedback.py +24 -19
- empathy_os/socratic/forms.py +15 -10
- empathy_os/socratic/generator.py +51 -35
- empathy_os/socratic/llm_analyzer.py +25 -23
- empathy_os/socratic/mcp_server.py +99 -159
- empathy_os/socratic/session.py +19 -13
- empathy_os/socratic/storage.py +98 -67
- empathy_os/socratic/success.py +38 -27
- empathy_os/socratic/visual_editor.py +51 -39
- empathy_os/socratic/web_ui.py +99 -66
- empathy_os/telemetry/cli.py +3 -1
- empathy_os/telemetry/usage_tracker.py +1 -3
- empathy_os/test_generator/__init__.py +3 -3
- empathy_os/test_generator/cli.py +28 -28
- empathy_os/test_generator/generator.py +64 -66
- empathy_os/test_generator/risk_analyzer.py +11 -11
- empathy_os/vscode_bridge.py +173 -0
- empathy_os/workflows/__init__.py +212 -120
- empathy_os/workflows/batch_processing.py +8 -24
- empathy_os/workflows/bug_predict.py +1 -1
- empathy_os/workflows/code_review.py +20 -5
- empathy_os/workflows/code_review_pipeline.py +13 -8
- empathy_os/workflows/keyboard_shortcuts/workflow.py +6 -2
- empathy_os/workflows/manage_documentation.py +1 -0
- empathy_os/workflows/orchestrated_health_check.py +6 -11
- empathy_os/workflows/orchestrated_release_prep.py +3 -3
- empathy_os/workflows/pr_review.py +18 -10
- empathy_os/workflows/progressive/__init__.py +2 -12
- empathy_os/workflows/progressive/cli.py +14 -37
- empathy_os/workflows/progressive/core.py +12 -12
- empathy_os/workflows/progressive/orchestrator.py +166 -144
- empathy_os/workflows/progressive/reports.py +22 -31
- empathy_os/workflows/progressive/telemetry.py +8 -14
- empathy_os/workflows/progressive/test_gen.py +29 -48
- empathy_os/workflows/progressive/workflow.py +31 -70
- empathy_os/workflows/release_prep.py +21 -6
- empathy_os/workflows/release_prep_crew.py +1 -0
- empathy_os/workflows/secure_release.py +13 -6
- empathy_os/workflows/security_audit.py +8 -3
- empathy_os/workflows/test_coverage_boost_crew.py +3 -2
- empathy_os/workflows/test_maintenance_crew.py +1 -0
- empathy_os/workflows/test_runner.py +16 -12
- empathy_software_plugin/SOFTWARE_PLUGIN_README.md +25 -703
- empathy_software_plugin/cli.py +0 -122
- coach_wizards/__init__.py +0 -45
- coach_wizards/accessibility_wizard.py +0 -91
- coach_wizards/api_wizard.py +0 -91
- coach_wizards/base_wizard.py +0 -209
- coach_wizards/cicd_wizard.py +0 -91
- coach_wizards/code_reviewer_README.md +0 -60
- coach_wizards/code_reviewer_wizard.py +0 -180
- coach_wizards/compliance_wizard.py +0 -91
- coach_wizards/database_wizard.py +0 -91
- coach_wizards/debugging_wizard.py +0 -91
- coach_wizards/documentation_wizard.py +0 -91
- coach_wizards/generate_wizards.py +0 -347
- coach_wizards/localization_wizard.py +0 -173
- coach_wizards/migration_wizard.py +0 -91
- coach_wizards/monitoring_wizard.py +0 -91
- coach_wizards/observability_wizard.py +0 -91
- coach_wizards/performance_wizard.py +0 -91
- coach_wizards/prompt_engineering_wizard.py +0 -661
- coach_wizards/refactoring_wizard.py +0 -91
- coach_wizards/scaling_wizard.py +0 -90
- coach_wizards/security_wizard.py +0 -92
- coach_wizards/testing_wizard.py +0 -91
- empathy_framework-4.6.6.dist-info/RECORD +0 -410
- empathy_llm_toolkit/wizards/__init__.py +0 -43
- empathy_llm_toolkit/wizards/base_wizard.py +0 -364
- empathy_llm_toolkit/wizards/customer_support_wizard.py +0 -190
- empathy_llm_toolkit/wizards/healthcare_wizard.py +0 -378
- empathy_llm_toolkit/wizards/patient_assessment_README.md +0 -64
- empathy_llm_toolkit/wizards/patient_assessment_wizard.py +0 -193
- empathy_llm_toolkit/wizards/technology_wizard.py +0 -209
- empathy_os/wizard_factory_cli.py +0 -170
- empathy_software_plugin/wizards/__init__.py +0 -42
- empathy_software_plugin/wizards/advanced_debugging_wizard.py +0 -395
- empathy_software_plugin/wizards/agent_orchestration_wizard.py +0 -511
- empathy_software_plugin/wizards/ai_collaboration_wizard.py +0 -503
- empathy_software_plugin/wizards/ai_context_wizard.py +0 -441
- empathy_software_plugin/wizards/ai_documentation_wizard.py +0 -503
- empathy_software_plugin/wizards/base_wizard.py +0 -288
- empathy_software_plugin/wizards/book_chapter_wizard.py +0 -519
- empathy_software_plugin/wizards/code_review_wizard.py +0 -604
- empathy_software_plugin/wizards/debugging/__init__.py +0 -50
- empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +0 -414
- empathy_software_plugin/wizards/debugging/config_loaders.py +0 -446
- empathy_software_plugin/wizards/debugging/fix_applier.py +0 -469
- empathy_software_plugin/wizards/debugging/language_patterns.py +0 -385
- empathy_software_plugin/wizards/debugging/linter_parsers.py +0 -470
- empathy_software_plugin/wizards/debugging/verification.py +0 -369
- empathy_software_plugin/wizards/enhanced_testing_wizard.py +0 -537
- empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +0 -816
- empathy_software_plugin/wizards/multi_model_wizard.py +0 -501
- empathy_software_plugin/wizards/pattern_extraction_wizard.py +0 -422
- empathy_software_plugin/wizards/pattern_retriever_wizard.py +0 -400
- empathy_software_plugin/wizards/performance/__init__.py +0 -9
- empathy_software_plugin/wizards/performance/bottleneck_detector.py +0 -221
- empathy_software_plugin/wizards/performance/profiler_parsers.py +0 -278
- empathy_software_plugin/wizards/performance/trajectory_analyzer.py +0 -429
- empathy_software_plugin/wizards/performance_profiling_wizard.py +0 -305
- empathy_software_plugin/wizards/prompt_engineering_wizard.py +0 -425
- empathy_software_plugin/wizards/rag_pattern_wizard.py +0 -461
- empathy_software_plugin/wizards/security/__init__.py +0 -32
- empathy_software_plugin/wizards/security/exploit_analyzer.py +0 -290
- empathy_software_plugin/wizards/security/owasp_patterns.py +0 -241
- empathy_software_plugin/wizards/security/vulnerability_scanner.py +0 -604
- empathy_software_plugin/wizards/security_analysis_wizard.py +0 -322
- empathy_software_plugin/wizards/security_learning_wizard.py +0 -740
- empathy_software_plugin/wizards/tech_debt_wizard.py +0 -726
- empathy_software_plugin/wizards/testing/__init__.py +0 -27
- empathy_software_plugin/wizards/testing/coverage_analyzer.py +0 -459
- empathy_software_plugin/wizards/testing/quality_analyzer.py +0 -525
- empathy_software_plugin/wizards/testing/test_suggester.py +0 -533
- empathy_software_plugin/wizards/testing_wizard.py +0 -274
- wizards/__init__.py +0 -82
- wizards/admission_assessment_wizard.py +0 -644
- wizards/care_plan.py +0 -321
- wizards/clinical_assessment.py +0 -769
- wizards/discharge_planning.py +0 -77
- wizards/discharge_summary_wizard.py +0 -468
- wizards/dosage_calculation.py +0 -497
- wizards/incident_report_wizard.py +0 -454
- wizards/medication_reconciliation.py +0 -85
- wizards/nursing_assessment.py +0 -171
- wizards/patient_education.py +0 -654
- wizards/quality_improvement.py +0 -705
- wizards/sbar_report.py +0 -324
- wizards/sbar_wizard.py +0 -608
- wizards/shift_handoff_wizard.py +0 -535
- wizards/soap_note_wizard.py +0 -679
- wizards/treatment_plan.py +0 -15
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/WHEEL +0 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/entry_points.txt +0 -0
- {empathy_framework-4.6.6.dist-info → empathy_framework-4.7.0.dist-info}/licenses/LICENSE +0 -0
empathy_os/socratic/storage.py
CHANGED
|
@@ -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
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
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
|
-
""",
|
|
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
|
-
""",
|
|
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
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
-
""",
|
|
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
|
-
""",
|
|
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
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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
|
-
""",
|
|
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
|
-
""",
|
|
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
|
-
""",
|
|
595
|
+
""",
|
|
596
|
+
(f"%{query}%", f"%{query}%", limit),
|
|
597
|
+
).fetchall()
|
|
567
598
|
|
|
568
599
|
return [dict(row) for row in rows]
|
|
569
600
|
|
empathy_os/socratic/success.py
CHANGED
|
@@ -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 =
|
|
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
|
|
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(
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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(
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
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 =
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
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 =
|
|
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(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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(
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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(
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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"
|
|
324
|
-
|
|
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(
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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[
|
|
640
|
-
const initialEdges = {json.dumps(react_schema[
|
|
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
|