isa-model 0.4.0__py3-none-any.whl → 0.4.3__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 (199) hide show
  1. isa_model/client.py +466 -43
  2. isa_model/core/cache/redis_cache.py +12 -3
  3. isa_model/core/config/config_manager.py +230 -3
  4. isa_model/core/config.py +90 -0
  5. isa_model/core/database/direct_db_client.py +114 -0
  6. isa_model/core/database/migration_manager.py +563 -0
  7. isa_model/core/database/migrations.py +21 -1
  8. isa_model/core/database/supabase_client.py +154 -19
  9. isa_model/core/dependencies.py +316 -0
  10. isa_model/core/discovery/__init__.py +19 -0
  11. isa_model/core/discovery/consul_discovery.py +190 -0
  12. isa_model/core/logging/__init__.py +54 -0
  13. isa_model/core/logging/influx_logger.py +523 -0
  14. isa_model/core/logging/loki_logger.py +160 -0
  15. isa_model/core/models/__init__.py +27 -18
  16. isa_model/core/models/config_models.py +625 -0
  17. isa_model/core/models/deployment_billing_tracker.py +430 -0
  18. isa_model/core/models/model_manager.py +40 -17
  19. isa_model/core/models/model_metadata.py +690 -0
  20. isa_model/core/models/model_repo.py +174 -18
  21. isa_model/core/models/system_models.py +857 -0
  22. isa_model/core/repositories/__init__.py +9 -0
  23. isa_model/core/repositories/config_repository.py +912 -0
  24. isa_model/core/services/intelligent_model_selector.py +399 -21
  25. isa_model/core/storage/hf_storage.py +1 -1
  26. isa_model/core/types.py +1 -0
  27. isa_model/deployment/__init__.py +5 -48
  28. isa_model/deployment/core/__init__.py +2 -31
  29. isa_model/deployment/core/deployment_manager.py +1278 -370
  30. isa_model/deployment/local/__init__.py +31 -0
  31. isa_model/deployment/local/config.py +248 -0
  32. isa_model/deployment/local/gpu_gateway.py +607 -0
  33. isa_model/deployment/local/health_checker.py +428 -0
  34. isa_model/deployment/local/provider.py +586 -0
  35. isa_model/deployment/local/tensorrt_service.py +621 -0
  36. isa_model/deployment/local/transformers_service.py +644 -0
  37. isa_model/deployment/local/vllm_service.py +527 -0
  38. isa_model/deployment/modal/__init__.py +8 -0
  39. isa_model/deployment/modal/config.py +136 -0
  40. isa_model/deployment/{services/auto_hf_modal_deployer.py → modal/deployer.py} +1 -1
  41. isa_model/deployment/modal/services/__init__.py +3 -0
  42. isa_model/deployment/modal/services/audio/__init__.py +1 -0
  43. isa_model/deployment/modal/services/embedding/__init__.py +1 -0
  44. isa_model/deployment/modal/services/llm/__init__.py +1 -0
  45. isa_model/deployment/modal/services/llm/isa_llm_service.py +424 -0
  46. isa_model/deployment/modal/services/video/__init__.py +1 -0
  47. isa_model/deployment/modal/services/vision/__init__.py +1 -0
  48. isa_model/deployment/models/org-org-acme-corp-tenant-a-service-llm-20250825-225822/tenant-a-service_modal_service.py +48 -0
  49. isa_model/deployment/models/org-test-org-123-prefix-test-service-llm-20250825-225822/prefix-test-service_modal_service.py +48 -0
  50. isa_model/deployment/models/test-llm-service-llm-20250825-204442/test-llm-service_modal_service.py +48 -0
  51. isa_model/deployment/models/test-monitoring-gpt2-llm-20250825-212906/test-monitoring-gpt2_modal_service.py +48 -0
  52. isa_model/deployment/models/test-monitoring-gpt2-llm-20250825-213009/test-monitoring-gpt2_modal_service.py +48 -0
  53. isa_model/deployment/storage/__init__.py +5 -0
  54. isa_model/deployment/storage/deployment_repository.py +824 -0
  55. isa_model/deployment/triton/__init__.py +10 -0
  56. isa_model/deployment/triton/config.py +196 -0
  57. isa_model/deployment/triton/configs/__init__.py +1 -0
  58. isa_model/deployment/triton/provider.py +512 -0
  59. isa_model/deployment/triton/scripts/__init__.py +1 -0
  60. isa_model/deployment/triton/templates/__init__.py +1 -0
  61. isa_model/inference/__init__.py +47 -1
  62. isa_model/inference/ai_factory.py +137 -10
  63. isa_model/inference/legacy_services/__init__.py +21 -0
  64. isa_model/inference/legacy_services/model_evaluation.py +637 -0
  65. isa_model/inference/legacy_services/model_service.py +573 -0
  66. isa_model/inference/legacy_services/model_serving.py +717 -0
  67. isa_model/inference/legacy_services/model_training.py +561 -0
  68. isa_model/inference/models/__init__.py +21 -0
  69. isa_model/inference/models/inference_config.py +551 -0
  70. isa_model/inference/models/inference_record.py +675 -0
  71. isa_model/inference/models/performance_models.py +714 -0
  72. isa_model/inference/repositories/__init__.py +9 -0
  73. isa_model/inference/repositories/inference_repository.py +828 -0
  74. isa_model/inference/services/audio/base_stt_service.py +184 -11
  75. isa_model/inference/services/audio/openai_stt_service.py +22 -6
  76. isa_model/inference/services/custom_model_manager.py +277 -0
  77. isa_model/inference/services/embedding/ollama_embed_service.py +15 -3
  78. isa_model/inference/services/embedding/resilient_embed_service.py +285 -0
  79. isa_model/inference/services/llm/__init__.py +10 -2
  80. isa_model/inference/services/llm/base_llm_service.py +335 -24
  81. isa_model/inference/services/llm/cerebras_llm_service.py +628 -0
  82. isa_model/inference/services/llm/helpers/llm_adapter.py +9 -4
  83. isa_model/inference/services/llm/helpers/llm_prompts.py +342 -0
  84. isa_model/inference/services/llm/helpers/llm_utils.py +321 -23
  85. isa_model/inference/services/llm/huggingface_llm_service.py +581 -0
  86. isa_model/inference/services/llm/local_llm_service.py +747 -0
  87. isa_model/inference/services/llm/ollama_llm_service.py +9 -2
  88. isa_model/inference/services/llm/openai_llm_service.py +33 -16
  89. isa_model/inference/services/llm/yyds_llm_service.py +8 -2
  90. isa_model/inference/services/vision/__init__.py +22 -1
  91. isa_model/inference/services/vision/blip_vision_service.py +359 -0
  92. isa_model/inference/services/vision/helpers/image_utils.py +8 -5
  93. isa_model/inference/services/vision/isa_vision_service.py +65 -4
  94. isa_model/inference/services/vision/openai_vision_service.py +19 -10
  95. isa_model/inference/services/vision/vgg16_vision_service.py +257 -0
  96. isa_model/serving/api/cache_manager.py +245 -0
  97. isa_model/serving/api/dependencies/__init__.py +1 -0
  98. isa_model/serving/api/dependencies/auth.py +194 -0
  99. isa_model/serving/api/dependencies/database.py +139 -0
  100. isa_model/serving/api/error_handlers.py +284 -0
  101. isa_model/serving/api/fastapi_server.py +172 -22
  102. isa_model/serving/api/middleware/auth.py +8 -2
  103. isa_model/serving/api/middleware/security.py +23 -33
  104. isa_model/serving/api/middleware/tenant_context.py +414 -0
  105. isa_model/serving/api/routes/analytics.py +4 -1
  106. isa_model/serving/api/routes/config.py +645 -0
  107. isa_model/serving/api/routes/deployment_billing.py +315 -0
  108. isa_model/serving/api/routes/deployments.py +138 -2
  109. isa_model/serving/api/routes/gpu_gateway.py +440 -0
  110. isa_model/serving/api/routes/health.py +32 -12
  111. isa_model/serving/api/routes/inference_monitoring.py +486 -0
  112. isa_model/serving/api/routes/local_deployments.py +448 -0
  113. isa_model/serving/api/routes/tenants.py +575 -0
  114. isa_model/serving/api/routes/unified.py +680 -18
  115. isa_model/serving/api/routes/webhooks.py +479 -0
  116. isa_model/serving/api/startup.py +68 -54
  117. isa_model/utils/gpu_utils.py +311 -0
  118. {isa_model-0.4.0.dist-info → isa_model-0.4.3.dist-info}/METADATA +66 -24
  119. isa_model-0.4.3.dist-info/RECORD +193 -0
  120. isa_model/core/storage/minio_storage.py +0 -0
  121. isa_model/deployment/cloud/__init__.py +0 -9
  122. isa_model/deployment/cloud/modal/__init__.py +0 -10
  123. isa_model/deployment/core/deployment_config.py +0 -356
  124. isa_model/deployment/core/isa_deployment_service.py +0 -401
  125. isa_model/deployment/gpu_int8_ds8/app/server.py +0 -66
  126. isa_model/deployment/gpu_int8_ds8/scripts/test_client.py +0 -43
  127. isa_model/deployment/gpu_int8_ds8/scripts/test_client_os.py +0 -35
  128. isa_model/deployment/runtime/deployed_service.py +0 -338
  129. isa_model/deployment/services/__init__.py +0 -9
  130. isa_model/deployment/services/auto_deploy_vision_service.py +0 -538
  131. isa_model/deployment/services/model_service.py +0 -332
  132. isa_model/deployment/services/service_monitor.py +0 -356
  133. isa_model/deployment/services/service_registry.py +0 -527
  134. isa_model/eval/__init__.py +0 -92
  135. isa_model/eval/benchmarks/__init__.py +0 -27
  136. isa_model/eval/benchmarks/multimodal_datasets.py +0 -460
  137. isa_model/eval/benchmarks.py +0 -701
  138. isa_model/eval/config/__init__.py +0 -10
  139. isa_model/eval/config/evaluation_config.py +0 -108
  140. isa_model/eval/evaluators/__init__.py +0 -24
  141. isa_model/eval/evaluators/audio_evaluator.py +0 -727
  142. isa_model/eval/evaluators/base_evaluator.py +0 -503
  143. isa_model/eval/evaluators/embedding_evaluator.py +0 -742
  144. isa_model/eval/evaluators/llm_evaluator.py +0 -472
  145. isa_model/eval/evaluators/vision_evaluator.py +0 -564
  146. isa_model/eval/example_evaluation.py +0 -395
  147. isa_model/eval/factory.py +0 -798
  148. isa_model/eval/infrastructure/__init__.py +0 -24
  149. isa_model/eval/infrastructure/experiment_tracker.py +0 -466
  150. isa_model/eval/isa_benchmarks.py +0 -700
  151. isa_model/eval/isa_integration.py +0 -582
  152. isa_model/eval/metrics.py +0 -951
  153. isa_model/eval/tests/unit/test_basic.py +0 -396
  154. isa_model/serving/api/routes/evaluations.py +0 -579
  155. isa_model/training/__init__.py +0 -168
  156. isa_model/training/annotation/annotation_schema.py +0 -47
  157. isa_model/training/annotation/processors/annotation_processor.py +0 -126
  158. isa_model/training/annotation/storage/dataset_manager.py +0 -131
  159. isa_model/training/annotation/storage/dataset_schema.py +0 -44
  160. isa_model/training/annotation/tests/test_annotation_flow.py +0 -109
  161. isa_model/training/annotation/tests/test_minio copy.py +0 -113
  162. isa_model/training/annotation/tests/test_minio_upload.py +0 -43
  163. isa_model/training/annotation/views/annotation_controller.py +0 -158
  164. isa_model/training/cloud/__init__.py +0 -22
  165. isa_model/training/cloud/job_orchestrator.py +0 -402
  166. isa_model/training/cloud/runpod_trainer.py +0 -454
  167. isa_model/training/cloud/storage_manager.py +0 -482
  168. isa_model/training/core/__init__.py +0 -26
  169. isa_model/training/core/config.py +0 -181
  170. isa_model/training/core/dataset.py +0 -222
  171. isa_model/training/core/trainer.py +0 -720
  172. isa_model/training/core/utils.py +0 -213
  173. isa_model/training/examples/intelligent_training_example.py +0 -281
  174. isa_model/training/factory.py +0 -424
  175. isa_model/training/intelligent/__init__.py +0 -25
  176. isa_model/training/intelligent/decision_engine.py +0 -643
  177. isa_model/training/intelligent/intelligent_factory.py +0 -888
  178. isa_model/training/intelligent/knowledge_base.py +0 -751
  179. isa_model/training/intelligent/resource_optimizer.py +0 -839
  180. isa_model/training/intelligent/task_classifier.py +0 -576
  181. isa_model/training/storage/__init__.py +0 -24
  182. isa_model/training/storage/core_integration.py +0 -439
  183. isa_model/training/storage/training_repository.py +0 -552
  184. isa_model/training/storage/training_storage.py +0 -628
  185. isa_model-0.4.0.dist-info/RECORD +0 -182
  186. /isa_model/deployment/{cloud/modal → modal/services/audio}/isa_audio_chatTTS_service.py +0 -0
  187. /isa_model/deployment/{cloud/modal → modal/services/audio}/isa_audio_fish_service.py +0 -0
  188. /isa_model/deployment/{cloud/modal → modal/services/audio}/isa_audio_openvoice_service.py +0 -0
  189. /isa_model/deployment/{cloud/modal → modal/services/audio}/isa_audio_service_v2.py +0 -0
  190. /isa_model/deployment/{cloud/modal → modal/services/embedding}/isa_embed_rerank_service.py +0 -0
  191. /isa_model/deployment/{cloud/modal → modal/services/video}/isa_video_hunyuan_service.py +0 -0
  192. /isa_model/deployment/{cloud/modal → modal/services/vision}/isa_vision_ocr_service.py +0 -0
  193. /isa_model/deployment/{cloud/modal → modal/services/vision}/isa_vision_qwen25_service.py +0 -0
  194. /isa_model/deployment/{cloud/modal → modal/services/vision}/isa_vision_table_service.py +0 -0
  195. /isa_model/deployment/{cloud/modal → modal/services/vision}/isa_vision_ui_service.py +0 -0
  196. /isa_model/deployment/{cloud/modal → modal/services/vision}/isa_vision_ui_service_optimized.py +0 -0
  197. /isa_model/deployment/{services → modal/services/vision}/simple_auto_deploy_vision_service.py +0 -0
  198. {isa_model-0.4.0.dist-info → isa_model-0.4.3.dist-info}/WHEEL +0 -0
  199. {isa_model-0.4.0.dist-info → isa_model-0.4.3.dist-info}/top_level.txt +0 -0
@@ -1,37 +1,46 @@
1
1
  """
2
- Core Models Module
2
+ Core Models
3
3
 
4
- Provides model management, registry, and lifecycle components for the ISA Model SDK.
5
-
6
- This module includes:
7
- - ModelRegistry: Central model registry and metadata management
8
- - ModelManager: High-level model lifecycle management
9
- - ModelVersionManager: Version control and lineage tracking
10
- - ModelBillingTracker: Cost tracking and billing
11
- - ModelStatisticsTracker: Usage statistics and analytics
4
+ Data models for core operations following the ISA Model architecture pattern.
12
5
  """
13
6
 
7
+ # Configuration models
8
+ from .config_models import ConfigRecord, ProviderConfig, EnvironmentConfig, ConfigAuditLog
9
+
10
+ # Model metadata models
11
+ from .model_metadata import ModelMetadata, ModelVersion, ModelBilling
12
+
13
+ # System monitoring models
14
+ from .system_models import SystemHealth, ResourceUsage, ServiceStatus
15
+
16
+ # Legacy model management (existing)
14
17
  from .model_repo import ModelRegistry, ModelType, ModelCapability
15
18
  from .model_manager import ModelManager
16
- from .model_version_manager import ModelVersionManager, ModelVersion, VersionType
19
+ from .model_version_manager import ModelVersionManager, ModelVersion as LegacyModelVersion, VersionType
17
20
  from .model_billing_tracker import ModelBillingTracker
18
21
  from .model_statistics_tracker import ModelStatisticsTracker
19
22
 
20
23
  __all__ = [
21
- # Core registry and types
24
+ # New standardized models
25
+ "ConfigRecord",
26
+ "ProviderConfig",
27
+ "EnvironmentConfig",
28
+ "ConfigAuditLog",
29
+ "ModelMetadata",
30
+ "ModelVersion",
31
+ "ModelBilling",
32
+ "SystemHealth",
33
+ "ResourceUsage",
34
+ "ServiceStatus",
35
+
36
+ # Legacy model management (existing)
22
37
  'ModelRegistry',
23
38
  'ModelType',
24
39
  'ModelCapability',
25
-
26
- # Model management
27
40
  'ModelManager',
28
-
29
- # Version management
30
41
  'ModelVersionManager',
31
- 'ModelVersion',
42
+ 'LegacyModelVersion',
32
43
  'VersionType',
33
-
34
- # Tracking and analytics
35
44
  'ModelBillingTracker',
36
45
  'ModelStatisticsTracker'
37
46
  ]
@@ -0,0 +1,625 @@
1
+ """
2
+ Configuration Models
3
+
4
+ Core data models for configuration management, extracted from repository layer
5
+ to follow the standard ISA Model architecture pattern.
6
+ """
7
+
8
+ import logging
9
+ from datetime import datetime, timezone
10
+ from typing import Dict, List, Optional, Any, Union
11
+ from dataclasses import dataclass, field
12
+ from enum import Enum
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ class ConfigType(str, Enum):
17
+ """Configuration type enumeration"""
18
+ PROVIDER = "provider"
19
+ ENVIRONMENT = "environment"
20
+ SYSTEM = "system"
21
+ USER = "user"
22
+ API_KEY = "api_key"
23
+ FEATURE_FLAG = "feature_flag"
24
+ DEPLOYMENT = "deployment"
25
+ SECURITY = "security"
26
+
27
+ class ConfigStatus(str, Enum):
28
+ """Configuration status enumeration"""
29
+ ACTIVE = "active"
30
+ INACTIVE = "inactive"
31
+ DEPRECATED = "deprecated"
32
+ PENDING = "pending"
33
+ ARCHIVED = "archived"
34
+
35
+ class SecurityLevel(str, Enum):
36
+ """Security level enumeration"""
37
+ PUBLIC = "public"
38
+ INTERNAL = "internal"
39
+ CONFIDENTIAL = "confidential"
40
+ SECRET = "secret"
41
+ TOP_SECRET = "top_secret"
42
+
43
+ @dataclass
44
+ class ConfigRecord:
45
+ """
46
+ Core configuration record model
47
+
48
+ Represents a single configuration entry with metadata, versioning,
49
+ and audit information for comprehensive configuration management.
50
+ """
51
+ config_id: str
52
+ config_type: str
53
+ config_key: str
54
+ config_value: Any
55
+ environment: str = "production"
56
+ is_active: bool = True
57
+ is_encrypted: bool = False
58
+ security_level: str = SecurityLevel.INTERNAL
59
+ version: int = 1
60
+ previous_version_id: Optional[str] = None
61
+ created_at: datetime = None
62
+ updated_at: datetime = None
63
+ effective_from: Optional[datetime] = None
64
+ expires_at: Optional[datetime] = None
65
+ created_by: Optional[str] = None
66
+ updated_by: Optional[str] = None
67
+ description: Optional[str] = None
68
+ tags: Optional[Dict[str, str]] = None
69
+ metadata: Optional[Dict[str, Any]] = None
70
+ validation_rules: Optional[Dict[str, Any]] = None
71
+ change_reason: Optional[str] = None
72
+
73
+ def __post_init__(self):
74
+ if self.created_at is None:
75
+ self.created_at = datetime.now(timezone.utc)
76
+ if self.updated_at is None:
77
+ self.updated_at = self.created_at
78
+ if self.effective_from is None:
79
+ self.effective_from = self.created_at
80
+ if self.tags is None:
81
+ self.tags = {}
82
+ if self.metadata is None:
83
+ self.metadata = {}
84
+ if self.validation_rules is None:
85
+ self.validation_rules = {}
86
+
87
+ @property
88
+ def is_effective(self) -> bool:
89
+ """Check if configuration is currently effective"""
90
+ now = datetime.now(timezone.utc)
91
+
92
+ if not self.is_active:
93
+ return False
94
+
95
+ if self.effective_from and now < self.effective_from:
96
+ return False
97
+
98
+ if self.expires_at and now > self.expires_at:
99
+ return False
100
+
101
+ return True
102
+
103
+ @property
104
+ def is_expired(self) -> bool:
105
+ """Check if configuration has expired"""
106
+ if not self.expires_at:
107
+ return False
108
+ return datetime.now(timezone.utc) > self.expires_at
109
+
110
+ @property
111
+ def is_sensitive(self) -> bool:
112
+ """Check if configuration contains sensitive data"""
113
+ return (self.is_encrypted or
114
+ self.security_level in [SecurityLevel.CONFIDENTIAL, SecurityLevel.SECRET, SecurityLevel.TOP_SECRET] or
115
+ any(keyword in self.config_key.lower() for keyword in ['password', 'key', 'secret', 'token']))
116
+
117
+ @property
118
+ def age_days(self) -> int:
119
+ """Get configuration age in days"""
120
+ return (datetime.now(timezone.utc) - self.created_at).days
121
+
122
+ def update_value(self, new_value: Any, updated_by: Optional[str] = None,
123
+ change_reason: Optional[str] = None, increment_version: bool = True):
124
+ """Update configuration value with versioning"""
125
+ if increment_version:
126
+ self.previous_version_id = f"{self.config_id}_v{self.version}"
127
+ self.version += 1
128
+
129
+ self.config_value = new_value
130
+ self.updated_at = datetime.now(timezone.utc)
131
+
132
+ if updated_by:
133
+ self.updated_by = updated_by
134
+ if change_reason:
135
+ self.change_reason = change_reason
136
+
137
+ def add_tag(self, key: str, value: str):
138
+ """Add or update a configuration tag"""
139
+ self.tags[key] = value
140
+ self.updated_at = datetime.now(timezone.utc)
141
+
142
+ def validate(self) -> List[str]:
143
+ """Validate configuration according to rules"""
144
+ issues = []
145
+
146
+ if not self.config_key:
147
+ issues.append("Configuration key is required")
148
+
149
+ if self.config_value is None:
150
+ issues.append("Configuration value cannot be None")
151
+
152
+ if self.version < 1:
153
+ issues.append("Version must be positive")
154
+
155
+ # Apply validation rules
156
+ for rule_name, rule_config in self.validation_rules.items():
157
+ rule_type = rule_config.get("type")
158
+
159
+ if rule_type == "required" and not self.config_value:
160
+ issues.append(f"Value is required by rule '{rule_name}'")
161
+
162
+ elif rule_type == "type_check":
163
+ expected_type = rule_config.get("expected_type")
164
+ if expected_type and not isinstance(self.config_value, eval(expected_type)):
165
+ issues.append(f"Value type mismatch for rule '{rule_name}': expected {expected_type}")
166
+
167
+ elif rule_type == "range" and isinstance(self.config_value, (int, float)):
168
+ min_val = rule_config.get("min")
169
+ max_val = rule_config.get("max")
170
+ if min_val is not None and self.config_value < min_val:
171
+ issues.append(f"Value below minimum for rule '{rule_name}': {min_val}")
172
+ if max_val is not None and self.config_value > max_val:
173
+ issues.append(f"Value above maximum for rule '{rule_name}': {max_val}")
174
+
175
+ elif rule_type == "enum" and isinstance(self.config_value, str):
176
+ allowed_values = rule_config.get("allowed_values", [])
177
+ if allowed_values and self.config_value not in allowed_values:
178
+ issues.append(f"Value not in allowed list for rule '{rule_name}': {allowed_values}")
179
+
180
+ return issues
181
+
182
+ def get_masked_value(self) -> Any:
183
+ """Get masked version of sensitive configuration values"""
184
+ if not self.is_sensitive:
185
+ return self.config_value
186
+
187
+ if isinstance(self.config_value, str):
188
+ if len(self.config_value) > 8:
189
+ return self.config_value[:4] + "***" + self.config_value[-4:]
190
+ else:
191
+ return "***"
192
+ elif isinstance(self.config_value, dict):
193
+ masked = {}
194
+ for key, value in self.config_value.items():
195
+ if any(keyword in key.lower() for keyword in ['password', 'key', 'secret', 'token']):
196
+ masked[key] = "***"
197
+ else:
198
+ masked[key] = value
199
+ return masked
200
+ else:
201
+ return "***"
202
+
203
+ @dataclass
204
+ class ProviderConfig:
205
+ """
206
+ Provider configuration model
207
+
208
+ Contains provider-specific settings, credentials, and operational parameters
209
+ for external service integrations.
210
+ """
211
+ provider_name: str
212
+ config_data: Dict[str, Any]
213
+ is_active: bool = True
214
+ environment: str = "production"
215
+ priority: int = 5 # 1-10 scale
216
+ health_check_enabled: bool = True
217
+ health_check_interval_seconds: int = 300
218
+ last_health_check: Optional[datetime] = None
219
+ health_status: str = "unknown" # healthy, unhealthy, unknown, maintenance
220
+ rate_limit_config: Optional[Dict[str, Any]] = None
221
+ retry_config: Optional[Dict[str, Any]] = None
222
+ timeout_config: Optional[Dict[str, Any]] = None
223
+ cost_tracking_enabled: bool = True
224
+ usage_limits: Optional[Dict[str, Any]] = None
225
+ created_at: datetime = None
226
+ updated_at: datetime = None
227
+ created_by: Optional[str] = None
228
+ updated_by: Optional[str] = None
229
+
230
+ def __post_init__(self):
231
+ if self.created_at is None:
232
+ self.created_at = datetime.now(timezone.utc)
233
+ if self.updated_at is None:
234
+ self.updated_at = self.created_at
235
+ if self.rate_limit_config is None:
236
+ self.rate_limit_config = {}
237
+ if self.retry_config is None:
238
+ self.retry_config = {"max_retries": 3, "backoff_factor": 2}
239
+ if self.timeout_config is None:
240
+ self.timeout_config = {"default_timeout": 300}
241
+ if self.usage_limits is None:
242
+ self.usage_limits = {}
243
+
244
+ @property
245
+ def is_healthy(self) -> bool:
246
+ """Check if provider is currently healthy"""
247
+ return self.health_status == "healthy" and self.is_active
248
+
249
+ @property
250
+ def time_since_last_check(self) -> Optional[int]:
251
+ """Get seconds since last health check"""
252
+ if self.last_health_check:
253
+ return int((datetime.now(timezone.utc) - self.last_health_check).total_seconds())
254
+ return None
255
+
256
+ @property
257
+ def needs_health_check(self) -> bool:
258
+ """Check if health check is due"""
259
+ if not self.health_check_enabled:
260
+ return False
261
+
262
+ if not self.last_health_check:
263
+ return True
264
+
265
+ time_since = self.time_since_last_check
266
+ return time_since is None or time_since >= self.health_check_interval_seconds
267
+
268
+ def get_config_value(self, key: str, default: Any = None) -> Any:
269
+ """Get configuration value with default fallback"""
270
+ return self.config_data.get(key, default)
271
+
272
+ def update_config_value(self, key: str, value: Any, updated_by: Optional[str] = None):
273
+ """Update specific configuration value"""
274
+ self.config_data[key] = value
275
+ self.updated_at = datetime.now(timezone.utc)
276
+ if updated_by:
277
+ self.updated_by = updated_by
278
+
279
+ def update_health_status(self, status: str, check_time: Optional[datetime] = None):
280
+ """Update health status with timestamp"""
281
+ self.health_status = status
282
+ self.last_health_check = check_time or datetime.now(timezone.utc)
283
+ self.updated_at = self.last_health_check
284
+
285
+ def validate_config(self) -> List[str]:
286
+ """Validate provider configuration"""
287
+ issues = []
288
+
289
+ if not self.provider_name:
290
+ issues.append("Provider name is required")
291
+
292
+ if not self.config_data:
293
+ issues.append("Configuration data is required")
294
+
295
+ # Provider-specific validation
296
+ if self.provider_name.lower() == "openai":
297
+ if "api_key" not in self.config_data:
298
+ issues.append("OpenAI API key is required")
299
+ if "base_url" not in self.config_data:
300
+ self.config_data["base_url"] = "https://api.openai.com/v1"
301
+
302
+ elif self.provider_name.lower() == "anthropic":
303
+ if "api_key" not in self.config_data:
304
+ issues.append("Anthropic API key is required")
305
+ if "base_url" not in self.config_data:
306
+ self.config_data["base_url"] = "https://api.anthropic.com"
307
+
308
+ elif self.provider_name.lower() == "replicate":
309
+ if "api_token" not in self.config_data:
310
+ issues.append("Replicate API token is required")
311
+
312
+ # Validate numeric configurations
313
+ if self.priority < 1 or self.priority > 10:
314
+ issues.append("Priority must be between 1 and 10")
315
+
316
+ if self.health_check_interval_seconds < 60:
317
+ issues.append("Health check interval must be at least 60 seconds")
318
+
319
+ return issues
320
+
321
+ def get_masked_config(self) -> Dict[str, Any]:
322
+ """Get configuration with sensitive values masked"""
323
+ masked_config = {}
324
+ sensitive_keys = ['api_key', 'api_token', 'secret', 'password', 'private_key']
325
+
326
+ for key, value in self.config_data.items():
327
+ if any(sensitive_key in key.lower() for sensitive_key in sensitive_keys):
328
+ if isinstance(value, str) and len(value) > 8:
329
+ masked_config[key] = value[:4] + "***" + value[-4:]
330
+ else:
331
+ masked_config[key] = "***"
332
+ else:
333
+ masked_config[key] = value
334
+
335
+ return masked_config
336
+
337
+ @dataclass
338
+ class EnvironmentConfig:
339
+ """
340
+ Environment configuration model
341
+
342
+ Manages environment-specific settings and configurations for different
343
+ deployment environments (development, staging, production, etc.).
344
+ """
345
+ environment: str
346
+ config_data: Dict[str, Any]
347
+ is_active: bool = True
348
+ is_default: bool = False
349
+ deployment_settings: Optional[Dict[str, Any]] = None
350
+ resource_limits: Optional[Dict[str, Any]] = None
351
+ feature_flags: Optional[Dict[str, bool]] = None
352
+ monitoring_config: Optional[Dict[str, Any]] = None
353
+ security_settings: Optional[Dict[str, Any]] = None
354
+ created_at: datetime = None
355
+ updated_at: datetime = None
356
+ created_by: Optional[str] = None
357
+ updated_by: Optional[str] = None
358
+
359
+ def __post_init__(self):
360
+ if self.created_at is None:
361
+ self.created_at = datetime.now(timezone.utc)
362
+ if self.updated_at is None:
363
+ self.updated_at = self.created_at
364
+ if self.deployment_settings is None:
365
+ self.deployment_settings = {}
366
+ if self.resource_limits is None:
367
+ self.resource_limits = {}
368
+ if self.feature_flags is None:
369
+ self.feature_flags = {}
370
+ if self.monitoring_config is None:
371
+ self.monitoring_config = {}
372
+ if self.security_settings is None:
373
+ self.security_settings = {}
374
+
375
+ @property
376
+ def environment_type(self) -> str:
377
+ """Classify environment type"""
378
+ env_lower = self.environment.lower()
379
+
380
+ if any(keyword in env_lower for keyword in ['prod', 'production']):
381
+ return "production"
382
+ elif any(keyword in env_lower for keyword in ['stag', 'staging']):
383
+ return "staging"
384
+ elif any(keyword in env_lower for keyword in ['dev', 'development']):
385
+ return "development"
386
+ elif any(keyword in env_lower for keyword in ['test', 'testing']):
387
+ return "testing"
388
+ else:
389
+ return "custom"
390
+
391
+ @property
392
+ def is_production(self) -> bool:
393
+ """Check if this is a production environment"""
394
+ return self.environment_type == "production"
395
+
396
+ @property
397
+ def security_level(self) -> str:
398
+ """Get security level based on environment type"""
399
+ if self.is_production:
400
+ return "high"
401
+ elif self.environment_type == "staging":
402
+ return "medium"
403
+ else:
404
+ return "low"
405
+
406
+ def get_feature_flag(self, flag_name: str, default: bool = False) -> bool:
407
+ """Get feature flag value"""
408
+ return self.feature_flags.get(flag_name, default)
409
+
410
+ def set_feature_flag(self, flag_name: str, enabled: bool, updated_by: Optional[str] = None):
411
+ """Set feature flag value"""
412
+ self.feature_flags[flag_name] = enabled
413
+ self.updated_at = datetime.now(timezone.utc)
414
+ if updated_by:
415
+ self.updated_by = updated_by
416
+
417
+ def get_resource_limit(self, resource_type: str, default: Any = None) -> Any:
418
+ """Get resource limit value"""
419
+ return self.resource_limits.get(resource_type, default)
420
+
421
+ def set_resource_limit(self, resource_type: str, limit: Any, updated_by: Optional[str] = None):
422
+ """Set resource limit"""
423
+ self.resource_limits[resource_type] = limit
424
+ self.updated_at = datetime.now(timezone.utc)
425
+ if updated_by:
426
+ self.updated_by = updated_by
427
+
428
+ def validate_environment(self) -> List[str]:
429
+ """Validate environment configuration"""
430
+ issues = []
431
+
432
+ if not self.environment:
433
+ issues.append("Environment name is required")
434
+
435
+ # Environment name validation
436
+ if self.environment not in ["development", "staging", "production", "testing"]:
437
+ if not self.environment.replace("_", "").replace("-", "").isalnum():
438
+ issues.append("Environment name should contain only alphanumeric characters, hyphens, and underscores")
439
+
440
+ # Production environment specific validations
441
+ if self.is_production:
442
+ required_security_settings = ["authentication_required", "encryption_enabled", "audit_logging"]
443
+ for setting in required_security_settings:
444
+ if setting not in self.security_settings:
445
+ issues.append(f"Production environment missing required security setting: {setting}")
446
+
447
+ return issues
448
+
449
+ @dataclass
450
+ class ConfigAuditLog:
451
+ """
452
+ Configuration audit log model
453
+
454
+ Tracks all configuration changes for compliance, debugging,
455
+ and security auditing purposes.
456
+ """
457
+ audit_id: str
458
+ config_id: str
459
+ config_key: str
460
+ action: str # create, update, delete, read, activate, deactivate
461
+ old_value: Optional[Any] = None
462
+ new_value: Optional[Any] = None
463
+ user_id: Optional[str] = None
464
+ session_id: Optional[str] = None
465
+ timestamp: datetime = None
466
+ ip_address: Optional[str] = None
467
+ user_agent: Optional[str] = None
468
+ change_reason: Optional[str] = None
469
+ approval_status: Optional[str] = None # pending, approved, rejected
470
+ approved_by: Optional[str] = None
471
+ approval_timestamp: Optional[datetime] = None
472
+ risk_level: str = "low" # low, medium, high, critical
473
+ compliance_flags: Optional[List[str]] = None
474
+ metadata: Optional[Dict[str, Any]] = None
475
+
476
+ def __post_init__(self):
477
+ if self.timestamp is None:
478
+ self.timestamp = datetime.now(timezone.utc)
479
+ if self.compliance_flags is None:
480
+ self.compliance_flags = []
481
+ if self.metadata is None:
482
+ self.metadata = {}
483
+
484
+ @property
485
+ def is_sensitive_change(self) -> bool:
486
+ """Check if this represents a sensitive configuration change"""
487
+ sensitive_keys = ['api_key', 'password', 'secret', 'token', 'private_key']
488
+ sensitive_actions = ['create', 'update', 'delete']
489
+
490
+ return (self.action in sensitive_actions and
491
+ any(keyword in self.config_key.lower() for keyword in sensitive_keys))
492
+
493
+ @property
494
+ def requires_approval(self) -> bool:
495
+ """Check if change requires approval"""
496
+ return (self.risk_level in ["high", "critical"] or
497
+ self.is_sensitive_change or
498
+ self.action == "delete")
499
+
500
+ @property
501
+ def is_approved(self) -> bool:
502
+ """Check if change is approved"""
503
+ return self.approval_status == "approved"
504
+
505
+ @property
506
+ def change_summary(self) -> str:
507
+ """Generate human-readable change summary"""
508
+ action_descriptions = {
509
+ "create": "created",
510
+ "update": "updated",
511
+ "delete": "deleted",
512
+ "read": "accessed",
513
+ "activate": "activated",
514
+ "deactivate": "deactivated"
515
+ }
516
+
517
+ action_desc = action_descriptions.get(self.action, self.action)
518
+ return f"Configuration '{self.config_key}' was {action_desc}"
519
+
520
+ def add_compliance_flag(self, flag: str):
521
+ """Add compliance flag"""
522
+ if flag not in self.compliance_flags:
523
+ self.compliance_flags.append(flag)
524
+
525
+ def approve_change(self, approved_by: str, approval_reason: Optional[str] = None):
526
+ """Approve the configuration change"""
527
+ self.approval_status = "approved"
528
+ self.approved_by = approved_by
529
+ self.approval_timestamp = datetime.now(timezone.utc)
530
+
531
+ if approval_reason:
532
+ self.metadata["approval_reason"] = approval_reason
533
+
534
+ def reject_change(self, rejected_by: str, rejection_reason: Optional[str] = None):
535
+ """Reject the configuration change"""
536
+ self.approval_status = "rejected"
537
+ self.approved_by = rejected_by
538
+ self.approval_timestamp = datetime.now(timezone.utc)
539
+
540
+ if rejection_reason:
541
+ self.metadata["rejection_reason"] = rejection_reason
542
+
543
+ # Utility functions for working with configuration models
544
+
545
+ def create_config_record(
546
+ config_key: str,
547
+ config_value: Any,
548
+ config_type: str = ConfigType.SYSTEM,
549
+ environment: str = "production",
550
+ created_by: Optional[str] = None,
551
+ description: Optional[str] = None
552
+ ) -> ConfigRecord:
553
+ """Factory function to create a new configuration record"""
554
+ import uuid
555
+
556
+ config_id = f"config_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4().hex[:8]}"
557
+
558
+ return ConfigRecord(
559
+ config_id=config_id,
560
+ config_type=config_type,
561
+ config_key=config_key,
562
+ config_value=config_value,
563
+ environment=environment,
564
+ created_by=created_by,
565
+ description=description
566
+ )
567
+
568
+ def create_provider_config(
569
+ provider_name: str,
570
+ config_data: Dict[str, Any],
571
+ environment: str = "production",
572
+ created_by: Optional[str] = None
573
+ ) -> ProviderConfig:
574
+ """Factory function to create a new provider configuration"""
575
+ return ProviderConfig(
576
+ provider_name=provider_name,
577
+ config_data=config_data,
578
+ environment=environment,
579
+ created_by=created_by
580
+ )
581
+
582
+ def create_environment_config(
583
+ environment: str,
584
+ config_data: Dict[str, Any],
585
+ created_by: Optional[str] = None
586
+ ) -> EnvironmentConfig:
587
+ """Factory function to create a new environment configuration"""
588
+ return EnvironmentConfig(
589
+ environment=environment,
590
+ config_data=config_data,
591
+ created_by=created_by
592
+ )
593
+
594
+ def create_audit_log(
595
+ config_id: str,
596
+ config_key: str,
597
+ action: str,
598
+ user_id: Optional[str] = None,
599
+ old_value: Optional[Any] = None,
600
+ new_value: Optional[Any] = None,
601
+ change_reason: Optional[str] = None
602
+ ) -> ConfigAuditLog:
603
+ """Factory function to create a new audit log entry"""
604
+ import uuid
605
+
606
+ audit_id = f"audit_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4().hex[:8]}"
607
+
608
+ # Determine risk level based on action and values
609
+ risk_level = "low"
610
+ if action in ["delete", "deactivate"]:
611
+ risk_level = "high"
612
+ elif action == "update" and old_value != new_value:
613
+ risk_level = "medium"
614
+
615
+ return ConfigAuditLog(
616
+ audit_id=audit_id,
617
+ config_id=config_id,
618
+ config_key=config_key,
619
+ action=action,
620
+ old_value=old_value,
621
+ new_value=new_value,
622
+ user_id=user_id,
623
+ change_reason=change_reason,
624
+ risk_level=risk_level
625
+ )