empathy-framework 3.7.0__py3-none-any.whl → 3.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- coach_wizards/code_reviewer_README.md +60 -0
- coach_wizards/code_reviewer_wizard.py +180 -0
- {empathy_framework-3.7.0.dist-info → empathy_framework-3.8.0.dist-info}/METADATA +148 -11
- empathy_framework-3.8.0.dist-info/RECORD +333 -0
- {empathy_framework-3.7.0.dist-info → empathy_framework-3.8.0.dist-info}/top_level.txt +5 -1
- empathy_healthcare_plugin/monitors/__init__.py +9 -0
- empathy_healthcare_plugin/monitors/clinical_protocol_monitor.py +315 -0
- empathy_healthcare_plugin/monitors/monitoring/__init__.py +44 -0
- empathy_healthcare_plugin/monitors/monitoring/protocol_checker.py +300 -0
- empathy_healthcare_plugin/monitors/monitoring/protocol_loader.py +214 -0
- empathy_healthcare_plugin/monitors/monitoring/sensor_parsers.py +306 -0
- empathy_healthcare_plugin/monitors/monitoring/trajectory_analyzer.py +389 -0
- empathy_llm_toolkit/agent_factory/__init__.py +53 -0
- empathy_llm_toolkit/agent_factory/adapters/__init__.py +85 -0
- empathy_llm_toolkit/agent_factory/adapters/autogen_adapter.py +312 -0
- empathy_llm_toolkit/agent_factory/adapters/crewai_adapter.py +454 -0
- empathy_llm_toolkit/agent_factory/adapters/haystack_adapter.py +298 -0
- empathy_llm_toolkit/agent_factory/adapters/langchain_adapter.py +362 -0
- empathy_llm_toolkit/agent_factory/adapters/langgraph_adapter.py +333 -0
- empathy_llm_toolkit/agent_factory/adapters/native.py +228 -0
- empathy_llm_toolkit/agent_factory/adapters/wizard_adapter.py +426 -0
- empathy_llm_toolkit/agent_factory/base.py +305 -0
- empathy_llm_toolkit/agent_factory/crews/__init__.py +67 -0
- empathy_llm_toolkit/agent_factory/crews/code_review.py +1113 -0
- empathy_llm_toolkit/agent_factory/crews/health_check.py +1246 -0
- empathy_llm_toolkit/agent_factory/crews/refactoring.py +1128 -0
- empathy_llm_toolkit/agent_factory/crews/security_audit.py +1018 -0
- empathy_llm_toolkit/agent_factory/decorators.py +286 -0
- empathy_llm_toolkit/agent_factory/factory.py +558 -0
- empathy_llm_toolkit/agent_factory/framework.py +192 -0
- empathy_llm_toolkit/agent_factory/memory_integration.py +324 -0
- empathy_llm_toolkit/agent_factory/resilient.py +320 -0
- empathy_llm_toolkit/cli/__init__.py +8 -0
- empathy_llm_toolkit/cli/sync_claude.py +487 -0
- empathy_llm_toolkit/code_health.py +150 -3
- empathy_llm_toolkit/config/__init__.py +29 -0
- empathy_llm_toolkit/config/unified.py +295 -0
- empathy_llm_toolkit/routing/__init__.py +32 -0
- empathy_llm_toolkit/routing/model_router.py +362 -0
- empathy_llm_toolkit/security/IMPLEMENTATION_SUMMARY.md +413 -0
- empathy_llm_toolkit/security/PHASE2_COMPLETE.md +384 -0
- empathy_llm_toolkit/security/PHASE2_SECRETS_DETECTOR_COMPLETE.md +271 -0
- empathy_llm_toolkit/security/QUICK_REFERENCE.md +316 -0
- empathy_llm_toolkit/security/README.md +262 -0
- empathy_llm_toolkit/security/__init__.py +62 -0
- empathy_llm_toolkit/security/audit_logger.py +929 -0
- empathy_llm_toolkit/security/audit_logger_example.py +152 -0
- empathy_llm_toolkit/security/pii_scrubber.py +640 -0
- empathy_llm_toolkit/security/secrets_detector.py +678 -0
- empathy_llm_toolkit/security/secrets_detector_example.py +304 -0
- empathy_llm_toolkit/security/secure_memdocs.py +1192 -0
- empathy_llm_toolkit/security/secure_memdocs_example.py +278 -0
- empathy_llm_toolkit/wizards/__init__.py +38 -0
- empathy_llm_toolkit/wizards/base_wizard.py +364 -0
- empathy_llm_toolkit/wizards/customer_support_wizard.py +190 -0
- empathy_llm_toolkit/wizards/healthcare_wizard.py +362 -0
- empathy_llm_toolkit/wizards/patient_assessment_README.md +64 -0
- empathy_llm_toolkit/wizards/patient_assessment_wizard.py +193 -0
- empathy_llm_toolkit/wizards/technology_wizard.py +194 -0
- empathy_os/__init__.py +52 -52
- empathy_os/adaptive/__init__.py +13 -0
- empathy_os/adaptive/task_complexity.py +127 -0
- empathy_os/cache/__init__.py +117 -0
- empathy_os/cache/base.py +166 -0
- empathy_os/cache/dependency_manager.py +253 -0
- empathy_os/cache/hash_only.py +248 -0
- empathy_os/cache/hybrid.py +390 -0
- empathy_os/cache/storage.py +282 -0
- empathy_os/cli.py +118 -8
- empathy_os/cli_unified.py +121 -1
- empathy_os/config/__init__.py +63 -0
- empathy_os/config/xml_config.py +239 -0
- empathy_os/config.py +2 -1
- empathy_os/dashboard/__init__.py +15 -0
- empathy_os/dashboard/server.py +743 -0
- empathy_os/memory/__init__.py +195 -0
- empathy_os/memory/claude_memory.py +466 -0
- empathy_os/memory/config.py +224 -0
- empathy_os/memory/control_panel.py +1298 -0
- empathy_os/memory/edges.py +179 -0
- empathy_os/memory/graph.py +567 -0
- empathy_os/memory/long_term.py +1194 -0
- empathy_os/memory/nodes.py +179 -0
- empathy_os/memory/redis_bootstrap.py +540 -0
- empathy_os/memory/security/__init__.py +31 -0
- empathy_os/memory/security/audit_logger.py +930 -0
- empathy_os/memory/security/pii_scrubber.py +640 -0
- empathy_os/memory/security/secrets_detector.py +678 -0
- empathy_os/memory/short_term.py +2119 -0
- empathy_os/memory/storage/__init__.py +15 -0
- empathy_os/memory/summary_index.py +583 -0
- empathy_os/memory/unified.py +619 -0
- empathy_os/metrics/__init__.py +12 -0
- empathy_os/metrics/prompt_metrics.py +190 -0
- empathy_os/models/__init__.py +136 -0
- empathy_os/models/__main__.py +13 -0
- empathy_os/models/cli.py +655 -0
- empathy_os/models/empathy_executor.py +354 -0
- empathy_os/models/executor.py +252 -0
- empathy_os/models/fallback.py +671 -0
- empathy_os/models/provider_config.py +563 -0
- empathy_os/models/registry.py +382 -0
- empathy_os/models/tasks.py +302 -0
- empathy_os/models/telemetry.py +548 -0
- empathy_os/models/token_estimator.py +378 -0
- empathy_os/models/validation.py +274 -0
- empathy_os/monitoring/__init__.py +52 -0
- empathy_os/monitoring/alerts.py +23 -0
- empathy_os/monitoring/alerts_cli.py +268 -0
- empathy_os/monitoring/multi_backend.py +271 -0
- empathy_os/monitoring/otel_backend.py +363 -0
- empathy_os/optimization/__init__.py +19 -0
- empathy_os/optimization/context_optimizer.py +272 -0
- empathy_os/plugins/__init__.py +28 -0
- empathy_os/plugins/base.py +361 -0
- empathy_os/plugins/registry.py +268 -0
- empathy_os/project_index/__init__.py +30 -0
- empathy_os/project_index/cli.py +335 -0
- empathy_os/project_index/crew_integration.py +430 -0
- empathy_os/project_index/index.py +425 -0
- empathy_os/project_index/models.py +501 -0
- empathy_os/project_index/reports.py +473 -0
- empathy_os/project_index/scanner.py +538 -0
- empathy_os/prompts/__init__.py +61 -0
- empathy_os/prompts/config.py +77 -0
- empathy_os/prompts/context.py +177 -0
- empathy_os/prompts/parser.py +285 -0
- empathy_os/prompts/registry.py +313 -0
- empathy_os/prompts/templates.py +208 -0
- empathy_os/resilience/__init__.py +56 -0
- empathy_os/resilience/circuit_breaker.py +256 -0
- empathy_os/resilience/fallback.py +179 -0
- empathy_os/resilience/health.py +300 -0
- empathy_os/resilience/retry.py +209 -0
- empathy_os/resilience/timeout.py +135 -0
- empathy_os/routing/__init__.py +43 -0
- empathy_os/routing/chain_executor.py +433 -0
- empathy_os/routing/classifier.py +217 -0
- empathy_os/routing/smart_router.py +234 -0
- empathy_os/routing/wizard_registry.py +307 -0
- empathy_os/trust/__init__.py +28 -0
- empathy_os/trust/circuit_breaker.py +579 -0
- empathy_os/validation/__init__.py +19 -0
- empathy_os/validation/xml_validator.py +281 -0
- empathy_os/wizard_factory_cli.py +170 -0
- empathy_os/workflows/__init__.py +360 -0
- empathy_os/workflows/base.py +1660 -0
- empathy_os/workflows/bug_predict.py +962 -0
- empathy_os/workflows/code_review.py +960 -0
- empathy_os/workflows/code_review_adapters.py +310 -0
- empathy_os/workflows/code_review_pipeline.py +720 -0
- empathy_os/workflows/config.py +600 -0
- empathy_os/workflows/dependency_check.py +648 -0
- empathy_os/workflows/document_gen.py +1069 -0
- empathy_os/workflows/documentation_orchestrator.py +1205 -0
- empathy_os/workflows/health_check.py +679 -0
- empathy_os/workflows/keyboard_shortcuts/__init__.py +39 -0
- empathy_os/workflows/keyboard_shortcuts/generators.py +386 -0
- empathy_os/workflows/keyboard_shortcuts/parsers.py +414 -0
- empathy_os/workflows/keyboard_shortcuts/prompts.py +295 -0
- empathy_os/workflows/keyboard_shortcuts/schema.py +193 -0
- empathy_os/workflows/keyboard_shortcuts/workflow.py +505 -0
- empathy_os/workflows/manage_documentation.py +804 -0
- empathy_os/workflows/new_sample_workflow1.py +146 -0
- empathy_os/workflows/new_sample_workflow1_README.md +150 -0
- empathy_os/workflows/perf_audit.py +687 -0
- empathy_os/workflows/pr_review.py +748 -0
- empathy_os/workflows/progress.py +445 -0
- empathy_os/workflows/progress_server.py +322 -0
- empathy_os/workflows/refactor_plan.py +693 -0
- empathy_os/workflows/release_prep.py +808 -0
- empathy_os/workflows/research_synthesis.py +404 -0
- empathy_os/workflows/secure_release.py +585 -0
- empathy_os/workflows/security_adapters.py +297 -0
- empathy_os/workflows/security_audit.py +1046 -0
- empathy_os/workflows/step_config.py +234 -0
- empathy_os/workflows/test5.py +125 -0
- empathy_os/workflows/test5_README.md +158 -0
- empathy_os/workflows/test_gen.py +1855 -0
- empathy_os/workflows/test_lifecycle.py +526 -0
- empathy_os/workflows/test_maintenance.py +626 -0
- empathy_os/workflows/test_maintenance_cli.py +590 -0
- empathy_os/workflows/test_maintenance_crew.py +821 -0
- empathy_os/workflows/xml_enhanced_crew.py +285 -0
- empathy_software_plugin/cli/__init__.py +120 -0
- empathy_software_plugin/cli/inspect.py +362 -0
- empathy_software_plugin/cli.py +3 -1
- empathy_software_plugin/wizards/__init__.py +42 -0
- empathy_software_plugin/wizards/advanced_debugging_wizard.py +392 -0
- empathy_software_plugin/wizards/agent_orchestration_wizard.py +511 -0
- empathy_software_plugin/wizards/ai_collaboration_wizard.py +503 -0
- empathy_software_plugin/wizards/ai_context_wizard.py +441 -0
- empathy_software_plugin/wizards/ai_documentation_wizard.py +503 -0
- empathy_software_plugin/wizards/base_wizard.py +288 -0
- empathy_software_plugin/wizards/book_chapter_wizard.py +519 -0
- empathy_software_plugin/wizards/code_review_wizard.py +606 -0
- empathy_software_plugin/wizards/debugging/__init__.py +50 -0
- empathy_software_plugin/wizards/debugging/bug_risk_analyzer.py +414 -0
- empathy_software_plugin/wizards/debugging/config_loaders.py +442 -0
- empathy_software_plugin/wizards/debugging/fix_applier.py +469 -0
- empathy_software_plugin/wizards/debugging/language_patterns.py +383 -0
- empathy_software_plugin/wizards/debugging/linter_parsers.py +470 -0
- empathy_software_plugin/wizards/debugging/verification.py +369 -0
- empathy_software_plugin/wizards/enhanced_testing_wizard.py +537 -0
- empathy_software_plugin/wizards/memory_enhanced_debugging_wizard.py +816 -0
- empathy_software_plugin/wizards/multi_model_wizard.py +501 -0
- empathy_software_plugin/wizards/pattern_extraction_wizard.py +422 -0
- empathy_software_plugin/wizards/pattern_retriever_wizard.py +400 -0
- empathy_software_plugin/wizards/performance/__init__.py +9 -0
- empathy_software_plugin/wizards/performance/bottleneck_detector.py +221 -0
- empathy_software_plugin/wizards/performance/profiler_parsers.py +278 -0
- empathy_software_plugin/wizards/performance/trajectory_analyzer.py +429 -0
- empathy_software_plugin/wizards/performance_profiling_wizard.py +305 -0
- empathy_software_plugin/wizards/prompt_engineering_wizard.py +425 -0
- empathy_software_plugin/wizards/rag_pattern_wizard.py +461 -0
- empathy_software_plugin/wizards/security/__init__.py +32 -0
- empathy_software_plugin/wizards/security/exploit_analyzer.py +290 -0
- empathy_software_plugin/wizards/security/owasp_patterns.py +241 -0
- empathy_software_plugin/wizards/security/vulnerability_scanner.py +604 -0
- empathy_software_plugin/wizards/security_analysis_wizard.py +322 -0
- empathy_software_plugin/wizards/security_learning_wizard.py +740 -0
- empathy_software_plugin/wizards/tech_debt_wizard.py +726 -0
- empathy_software_plugin/wizards/testing/__init__.py +27 -0
- empathy_software_plugin/wizards/testing/coverage_analyzer.py +459 -0
- empathy_software_plugin/wizards/testing/quality_analyzer.py +531 -0
- empathy_software_plugin/wizards/testing/test_suggester.py +533 -0
- empathy_software_plugin/wizards/testing_wizard.py +274 -0
- hot_reload/README.md +473 -0
- hot_reload/__init__.py +62 -0
- hot_reload/config.py +84 -0
- hot_reload/integration.py +228 -0
- hot_reload/reloader.py +298 -0
- hot_reload/watcher.py +179 -0
- hot_reload/websocket.py +176 -0
- scaffolding/README.md +589 -0
- scaffolding/__init__.py +35 -0
- scaffolding/__main__.py +14 -0
- scaffolding/cli.py +240 -0
- test_generator/__init__.py +38 -0
- test_generator/__main__.py +14 -0
- test_generator/cli.py +226 -0
- test_generator/generator.py +325 -0
- test_generator/risk_analyzer.py +216 -0
- workflow_patterns/__init__.py +33 -0
- workflow_patterns/behavior.py +249 -0
- workflow_patterns/core.py +76 -0
- workflow_patterns/output.py +99 -0
- workflow_patterns/registry.py +255 -0
- workflow_patterns/structural.py +288 -0
- workflow_scaffolding/__init__.py +11 -0
- workflow_scaffolding/__main__.py +12 -0
- workflow_scaffolding/cli.py +206 -0
- workflow_scaffolding/generator.py +265 -0
- agents/code_inspection/patterns/inspection/recurring_B112.json +0 -18
- agents/code_inspection/patterns/inspection/recurring_F541.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_FORMAT.json +0 -25
- agents/code_inspection/patterns/inspection/recurring_bug_20250822_def456.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20250915_abc123.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_3c5b9951.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_97c0f72f.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_a0871d53.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_20251212_a9b6ec41.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_bug_null_001.json +0 -16
- agents/code_inspection/patterns/inspection/recurring_builtin.json +0 -16
- agents/compliance_anticipation_agent.py +0 -1422
- agents/compliance_db.py +0 -339
- agents/epic_integration_wizard.py +0 -530
- agents/notifications.py +0 -291
- agents/trust_building_behaviors.py +0 -872
- empathy_framework-3.7.0.dist-info/RECORD +0 -105
- {empathy_framework-3.7.0.dist-info → empathy_framework-3.8.0.dist-info}/WHEEL +0 -0
- {empathy_framework-3.7.0.dist-info → empathy_framework-3.8.0.dist-info}/entry_points.txt +0 -0
- {empathy_framework-3.7.0.dist-info → empathy_framework-3.8.0.dist-info}/licenses/LICENSE +0 -0
- /empathy_os/{monitoring.py → agent_monitoring.py} +0 -0
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"""XML validation for response verification.
|
|
2
|
+
|
|
3
|
+
Validates XML-structured responses with graceful fallbacks.
|
|
4
|
+
|
|
5
|
+
Copyright 2026 Smart-AI-Memory
|
|
6
|
+
Licensed under Fair Source License 0.9
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import xml.etree.ElementTree as ET
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class ValidationResult:
|
|
17
|
+
"""Result of XML validation.
|
|
18
|
+
|
|
19
|
+
Attributes:
|
|
20
|
+
is_valid: Whether XML is valid
|
|
21
|
+
error_message: Error message if invalid
|
|
22
|
+
parsed_data: Parsed data if valid
|
|
23
|
+
fallback_used: Whether fallback parsing was used
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
is_valid: bool
|
|
27
|
+
error_message: str | None = None
|
|
28
|
+
parsed_data: dict[str, Any] | None = None
|
|
29
|
+
fallback_used: bool = False
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class XMLValidator:
|
|
33
|
+
"""Validates XML responses with graceful fallbacks.
|
|
34
|
+
|
|
35
|
+
Supports:
|
|
36
|
+
- Well-formedness validation
|
|
37
|
+
- XSD schema validation (optional)
|
|
38
|
+
- Graceful fallback on validation errors
|
|
39
|
+
- Schema caching for performance
|
|
40
|
+
|
|
41
|
+
Usage:
|
|
42
|
+
validator = XMLValidator()
|
|
43
|
+
result = validator.validate("<thinking>...</thinking>")
|
|
44
|
+
|
|
45
|
+
if result.is_valid:
|
|
46
|
+
data = result.parsed_data
|
|
47
|
+
else:
|
|
48
|
+
# Use fallback parsing
|
|
49
|
+
data = fallback_parse(response)
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
schema_dir: str = ".empathy/schemas",
|
|
55
|
+
strict: bool = False,
|
|
56
|
+
enable_xsd: bool = False,
|
|
57
|
+
):
|
|
58
|
+
"""Initialize validator.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
schema_dir: Directory containing XSD schemas
|
|
62
|
+
strict: If True, fail on validation errors. If False, use fallback.
|
|
63
|
+
enable_xsd: Enable XSD schema validation (requires lxml)
|
|
64
|
+
"""
|
|
65
|
+
self.schema_dir = Path(schema_dir)
|
|
66
|
+
self.strict = strict
|
|
67
|
+
self.enable_xsd = enable_xsd
|
|
68
|
+
self._schema_cache: dict[str, Any] = {}
|
|
69
|
+
|
|
70
|
+
# Try to import lxml for XSD validation
|
|
71
|
+
self._lxml_available = False
|
|
72
|
+
if enable_xsd:
|
|
73
|
+
try:
|
|
74
|
+
from lxml import etree as lxml_etree # noqa: F401
|
|
75
|
+
|
|
76
|
+
self._lxml_available = True
|
|
77
|
+
except ImportError:
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
def validate(self, xml_string: str, schema_name: str | None = None) -> ValidationResult:
|
|
81
|
+
"""Validate XML string.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
xml_string: XML content to validate
|
|
85
|
+
schema_name: Optional XSD schema name (e.g., "agent_response")
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
ValidationResult with validation status and parsed data
|
|
89
|
+
"""
|
|
90
|
+
# Step 1: Well-formedness validation
|
|
91
|
+
try:
|
|
92
|
+
root = ET.fromstring(xml_string) # nosec B314 - parsing trusted LLM responses
|
|
93
|
+
except ET.ParseError as e:
|
|
94
|
+
if self.strict:
|
|
95
|
+
return ValidationResult(
|
|
96
|
+
is_valid=False,
|
|
97
|
+
error_message=f"XML parsing failed: {e}",
|
|
98
|
+
fallback_used=False,
|
|
99
|
+
)
|
|
100
|
+
# Try fallback parsing
|
|
101
|
+
return self._fallback_parse(xml_string, str(e))
|
|
102
|
+
|
|
103
|
+
# Step 2: XSD schema validation (optional)
|
|
104
|
+
if schema_name and self.enable_xsd and self._lxml_available:
|
|
105
|
+
schema_result = self._validate_with_xsd(xml_string, schema_name)
|
|
106
|
+
if not schema_result.is_valid:
|
|
107
|
+
if self.strict:
|
|
108
|
+
return schema_result
|
|
109
|
+
# Continue with parsed data despite schema error
|
|
110
|
+
return ValidationResult(
|
|
111
|
+
is_valid=True,
|
|
112
|
+
parsed_data=self._extract_data(root),
|
|
113
|
+
fallback_used=True,
|
|
114
|
+
error_message=f"Schema validation failed: {schema_result.error_message}",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# Step 3: Extract structured data
|
|
118
|
+
parsed_data = self._extract_data(root)
|
|
119
|
+
|
|
120
|
+
return ValidationResult(
|
|
121
|
+
is_valid=True,
|
|
122
|
+
parsed_data=parsed_data,
|
|
123
|
+
fallback_used=False,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
def _validate_with_xsd(self, xml_string: str, schema_name: str) -> ValidationResult:
|
|
127
|
+
"""Validate XML against XSD schema.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
xml_string: XML content
|
|
131
|
+
schema_name: Schema file name (without .xsd extension)
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
ValidationResult
|
|
135
|
+
"""
|
|
136
|
+
if not self._lxml_available:
|
|
137
|
+
return ValidationResult(
|
|
138
|
+
is_valid=False,
|
|
139
|
+
error_message="lxml not available for XSD validation",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
from lxml import etree as lxml_etree
|
|
144
|
+
except ImportError:
|
|
145
|
+
return ValidationResult(
|
|
146
|
+
is_valid=False,
|
|
147
|
+
error_message="lxml import failed",
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# Load schema
|
|
151
|
+
schema_path = self.schema_dir / f"{schema_name}.xsd"
|
|
152
|
+
if not schema_path.exists():
|
|
153
|
+
return ValidationResult(
|
|
154
|
+
is_valid=False,
|
|
155
|
+
error_message=f"Schema not found: {schema_path}",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Check cache
|
|
159
|
+
if schema_name not in self._schema_cache:
|
|
160
|
+
try:
|
|
161
|
+
schema_doc = lxml_etree.parse(str(schema_path))
|
|
162
|
+
self._schema_cache[schema_name] = lxml_etree.XMLSchema(schema_doc)
|
|
163
|
+
except Exception as e:
|
|
164
|
+
return ValidationResult(
|
|
165
|
+
is_valid=False,
|
|
166
|
+
error_message=f"Schema loading failed: {e}",
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
schema = self._schema_cache[schema_name]
|
|
170
|
+
|
|
171
|
+
# Validate
|
|
172
|
+
try:
|
|
173
|
+
xml_doc = lxml_etree.fromstring(xml_string.encode("utf-8"))
|
|
174
|
+
is_valid = schema.validate(xml_doc)
|
|
175
|
+
|
|
176
|
+
if not is_valid:
|
|
177
|
+
error_log = schema.error_log
|
|
178
|
+
return ValidationResult(
|
|
179
|
+
is_valid=False,
|
|
180
|
+
error_message=f"Schema validation failed: {error_log}",
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
return ValidationResult(is_valid=True)
|
|
184
|
+
|
|
185
|
+
except Exception as e:
|
|
186
|
+
return ValidationResult(
|
|
187
|
+
is_valid=False,
|
|
188
|
+
error_message=f"Validation error: {e}",
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def _fallback_parse(self, xml_string: str, error: str) -> ValidationResult:
|
|
192
|
+
"""Attempt fallback parsing of malformed XML.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
xml_string: XML string that failed to parse
|
|
196
|
+
error: Parse error message
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
ValidationResult with fallback data
|
|
200
|
+
"""
|
|
201
|
+
# Try to extract data using regex patterns
|
|
202
|
+
import re
|
|
203
|
+
|
|
204
|
+
data: dict[str, Any] = {}
|
|
205
|
+
|
|
206
|
+
# Extract thinking content
|
|
207
|
+
thinking_match = re.search(r"<thinking[^>]*>(.*?)</thinking>", xml_string, re.DOTALL)
|
|
208
|
+
if thinking_match:
|
|
209
|
+
data["thinking"] = thinking_match.group(1).strip()
|
|
210
|
+
|
|
211
|
+
# Extract answer content
|
|
212
|
+
answer_match = re.search(r"<answer[^>]*>(.*?)</answer>", xml_string, re.DOTALL)
|
|
213
|
+
if answer_match:
|
|
214
|
+
data["answer"] = answer_match.group(1).strip()
|
|
215
|
+
|
|
216
|
+
# If we extracted something, consider it a partial success
|
|
217
|
+
if data:
|
|
218
|
+
return ValidationResult(
|
|
219
|
+
is_valid=True,
|
|
220
|
+
parsed_data=data,
|
|
221
|
+
fallback_used=True,
|
|
222
|
+
error_message=f"XML parsing failed, used fallback: {error}",
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
# Complete failure
|
|
226
|
+
return ValidationResult(
|
|
227
|
+
is_valid=False,
|
|
228
|
+
error_message=f"XML parsing and fallback failed: {error}",
|
|
229
|
+
fallback_used=True,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
def _extract_data(self, root: ET.Element) -> dict[str, Any]:
|
|
233
|
+
"""Extract structured data from parsed XML.
|
|
234
|
+
|
|
235
|
+
Args:
|
|
236
|
+
root: Parsed XML root element
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
Dictionary with extracted data
|
|
240
|
+
"""
|
|
241
|
+
data: dict[str, Any] = {}
|
|
242
|
+
|
|
243
|
+
# Extract all child elements
|
|
244
|
+
for child in root:
|
|
245
|
+
# Handle nested elements
|
|
246
|
+
if len(child):
|
|
247
|
+
data[child.tag] = self._extract_data(child)
|
|
248
|
+
else:
|
|
249
|
+
# Leaf node - get text content
|
|
250
|
+
data[child.tag] = child.text if child.text else ""
|
|
251
|
+
|
|
252
|
+
# Also store root attributes
|
|
253
|
+
if root.attrib:
|
|
254
|
+
data["_attributes"] = dict(root.attrib)
|
|
255
|
+
|
|
256
|
+
return data
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def validate_xml_response(
|
|
260
|
+
response: str,
|
|
261
|
+
schema_name: str | None = None,
|
|
262
|
+
strict: bool = False,
|
|
263
|
+
) -> ValidationResult:
|
|
264
|
+
"""Convenience function to validate XML response.
|
|
265
|
+
|
|
266
|
+
Args:
|
|
267
|
+
response: XML response string
|
|
268
|
+
schema_name: Optional XSD schema name
|
|
269
|
+
strict: If True, fail on validation errors
|
|
270
|
+
|
|
271
|
+
Returns:
|
|
272
|
+
ValidationResult
|
|
273
|
+
|
|
274
|
+
Example:
|
|
275
|
+
>>> response = "<thinking>Analysis</thinking><answer>Result</answer>"
|
|
276
|
+
>>> result = validate_xml_response(response)
|
|
277
|
+
>>> if result.is_valid:
|
|
278
|
+
... print(result.parsed_data)
|
|
279
|
+
"""
|
|
280
|
+
validator = XMLValidator(strict=strict)
|
|
281
|
+
return validator.validate(response, schema_name)
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"""Wizard Factory CLI integration for Empathy Framework.
|
|
2
|
+
|
|
3
|
+
Provides wizard-factory commands integrated into the main empathy CLI:
|
|
4
|
+
- empathy wizard-factory create
|
|
5
|
+
- empathy wizard-factory list-patterns
|
|
6
|
+
- empathy wizard-factory generate-tests
|
|
7
|
+
- empathy wizard-factory analyze
|
|
8
|
+
|
|
9
|
+
Copyright 2025 Smart AI Memory, LLC
|
|
10
|
+
Licensed under Fair Source 0.9
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import subprocess
|
|
14
|
+
import sys
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def cmd_wizard_factory_create(args):
|
|
18
|
+
"""Create a new wizard using scaffolding."""
|
|
19
|
+
# Build command
|
|
20
|
+
cmd = ["python", "-m", "scaffolding", "create", args.name]
|
|
21
|
+
|
|
22
|
+
if args.domain:
|
|
23
|
+
cmd.extend(["--domain", args.domain])
|
|
24
|
+
|
|
25
|
+
if args.type:
|
|
26
|
+
cmd.extend(["--type", args.type])
|
|
27
|
+
|
|
28
|
+
if args.methodology:
|
|
29
|
+
cmd.extend(["--methodology", args.methodology])
|
|
30
|
+
|
|
31
|
+
if args.patterns:
|
|
32
|
+
cmd.extend(["--patterns", args.patterns])
|
|
33
|
+
|
|
34
|
+
if args.interactive:
|
|
35
|
+
cmd.append("--interactive")
|
|
36
|
+
|
|
37
|
+
# Run scaffolding
|
|
38
|
+
result = subprocess.run(cmd)
|
|
39
|
+
sys.exit(result.returncode)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def cmd_wizard_factory_list_patterns(args):
|
|
43
|
+
"""List available patterns."""
|
|
44
|
+
result = subprocess.run(["python", "-m", "scaffolding", "list-patterns"])
|
|
45
|
+
sys.exit(result.returncode)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def cmd_wizard_factory_generate_tests(args):
|
|
49
|
+
"""Generate tests for a wizard."""
|
|
50
|
+
cmd = ["python", "-m", "test_generator", "generate", args.wizard_id]
|
|
51
|
+
|
|
52
|
+
if args.patterns:
|
|
53
|
+
cmd.extend(["--patterns", args.patterns])
|
|
54
|
+
|
|
55
|
+
if args.output:
|
|
56
|
+
cmd.extend(["--output", args.output])
|
|
57
|
+
|
|
58
|
+
result = subprocess.run(cmd)
|
|
59
|
+
sys.exit(result.returncode)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def cmd_wizard_factory_analyze(args):
|
|
63
|
+
"""Analyze wizard risk."""
|
|
64
|
+
cmd = ["python", "-m", "test_generator", "analyze", args.wizard_id]
|
|
65
|
+
|
|
66
|
+
if args.patterns:
|
|
67
|
+
cmd.extend(["--patterns", args.patterns])
|
|
68
|
+
|
|
69
|
+
if args.json:
|
|
70
|
+
cmd.append("--json")
|
|
71
|
+
|
|
72
|
+
result = subprocess.run(cmd)
|
|
73
|
+
sys.exit(result.returncode)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def add_wizard_factory_commands(subparsers):
|
|
77
|
+
"""Add wizard-factory commands to main CLI.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
subparsers: ArgumentParser subparsers object
|
|
81
|
+
"""
|
|
82
|
+
# Main wizard-factory command
|
|
83
|
+
parser_wf = subparsers.add_parser(
|
|
84
|
+
"wizard-factory",
|
|
85
|
+
help="Wizard Factory - create wizards 12x faster",
|
|
86
|
+
)
|
|
87
|
+
wf_subparsers = parser_wf.add_subparsers(dest="wizard_factory_command")
|
|
88
|
+
|
|
89
|
+
# wizard-factory create
|
|
90
|
+
parser_wf_create = wf_subparsers.add_parser(
|
|
91
|
+
"create",
|
|
92
|
+
help="Create a new wizard",
|
|
93
|
+
)
|
|
94
|
+
parser_wf_create.add_argument("name", help="Wizard name (snake_case)")
|
|
95
|
+
parser_wf_create.add_argument(
|
|
96
|
+
"--domain",
|
|
97
|
+
"-d",
|
|
98
|
+
help="Domain (healthcare, finance, software, legal, etc.)",
|
|
99
|
+
)
|
|
100
|
+
parser_wf_create.add_argument(
|
|
101
|
+
"--type",
|
|
102
|
+
"-t",
|
|
103
|
+
choices=["domain", "coach", "ai"],
|
|
104
|
+
default="domain",
|
|
105
|
+
help="Wizard type (default: domain)",
|
|
106
|
+
)
|
|
107
|
+
parser_wf_create.add_argument(
|
|
108
|
+
"--methodology",
|
|
109
|
+
"-m",
|
|
110
|
+
choices=["pattern", "tdd"],
|
|
111
|
+
default="pattern",
|
|
112
|
+
help="Methodology (pattern-compose or tdd-first, default: pattern)",
|
|
113
|
+
)
|
|
114
|
+
parser_wf_create.add_argument(
|
|
115
|
+
"--patterns",
|
|
116
|
+
"-p",
|
|
117
|
+
help="Comma-separated pattern IDs (e.g. linear_flow,approval)",
|
|
118
|
+
)
|
|
119
|
+
parser_wf_create.add_argument(
|
|
120
|
+
"--interactive",
|
|
121
|
+
"-i",
|
|
122
|
+
action="store_true",
|
|
123
|
+
help="Interactive pattern selection",
|
|
124
|
+
)
|
|
125
|
+
parser_wf_create.set_defaults(func=cmd_wizard_factory_create)
|
|
126
|
+
|
|
127
|
+
# wizard-factory list-patterns
|
|
128
|
+
parser_wf_list = wf_subparsers.add_parser(
|
|
129
|
+
"list-patterns",
|
|
130
|
+
help="List available patterns",
|
|
131
|
+
)
|
|
132
|
+
parser_wf_list.set_defaults(func=cmd_wizard_factory_list_patterns)
|
|
133
|
+
|
|
134
|
+
# wizard-factory generate-tests
|
|
135
|
+
parser_wf_gen = wf_subparsers.add_parser(
|
|
136
|
+
"generate-tests",
|
|
137
|
+
help="Generate tests for a wizard",
|
|
138
|
+
)
|
|
139
|
+
parser_wf_gen.add_argument("wizard_id", help="Wizard ID")
|
|
140
|
+
parser_wf_gen.add_argument(
|
|
141
|
+
"--patterns",
|
|
142
|
+
"-p",
|
|
143
|
+
required=True,
|
|
144
|
+
help="Comma-separated pattern IDs",
|
|
145
|
+
)
|
|
146
|
+
parser_wf_gen.add_argument(
|
|
147
|
+
"--output",
|
|
148
|
+
"-o",
|
|
149
|
+
help="Output directory for tests",
|
|
150
|
+
)
|
|
151
|
+
parser_wf_gen.set_defaults(func=cmd_wizard_factory_generate_tests)
|
|
152
|
+
|
|
153
|
+
# wizard-factory analyze
|
|
154
|
+
parser_wf_analyze = wf_subparsers.add_parser(
|
|
155
|
+
"analyze",
|
|
156
|
+
help="Analyze wizard risk and get coverage recommendations",
|
|
157
|
+
)
|
|
158
|
+
parser_wf_analyze.add_argument("wizard_id", help="Wizard ID")
|
|
159
|
+
parser_wf_analyze.add_argument(
|
|
160
|
+
"--patterns",
|
|
161
|
+
"-p",
|
|
162
|
+
required=True,
|
|
163
|
+
help="Comma-separated pattern IDs",
|
|
164
|
+
)
|
|
165
|
+
parser_wf_analyze.add_argument(
|
|
166
|
+
"--json",
|
|
167
|
+
action="store_true",
|
|
168
|
+
help="Output JSON format",
|
|
169
|
+
)
|
|
170
|
+
parser_wf_analyze.set_defaults(func=cmd_wizard_factory_analyze)
|