isa-model 0.3.91__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 (228) hide show
  1. isa_model/client.py +1166 -584
  2. isa_model/core/cache/redis_cache.py +410 -0
  3. isa_model/core/config/config_manager.py +282 -12
  4. isa_model/core/config.py +91 -1
  5. isa_model/core/database/__init__.py +1 -0
  6. isa_model/core/database/direct_db_client.py +114 -0
  7. isa_model/core/database/migration_manager.py +563 -0
  8. isa_model/core/database/migrations.py +297 -0
  9. isa_model/core/database/supabase_client.py +258 -0
  10. isa_model/core/dependencies.py +316 -0
  11. isa_model/core/discovery/__init__.py +19 -0
  12. isa_model/core/discovery/consul_discovery.py +190 -0
  13. isa_model/core/logging/__init__.py +54 -0
  14. isa_model/core/logging/influx_logger.py +523 -0
  15. isa_model/core/logging/loki_logger.py +160 -0
  16. isa_model/core/models/__init__.py +46 -0
  17. isa_model/core/models/config_models.py +625 -0
  18. isa_model/core/models/deployment_billing_tracker.py +430 -0
  19. isa_model/core/models/model_billing_tracker.py +60 -88
  20. isa_model/core/models/model_manager.py +66 -25
  21. isa_model/core/models/model_metadata.py +690 -0
  22. isa_model/core/models/model_repo.py +217 -55
  23. isa_model/core/models/model_statistics_tracker.py +234 -0
  24. isa_model/core/models/model_storage.py +0 -1
  25. isa_model/core/models/model_version_manager.py +959 -0
  26. isa_model/core/models/system_models.py +857 -0
  27. isa_model/core/pricing_manager.py +2 -249
  28. isa_model/core/repositories/__init__.py +9 -0
  29. isa_model/core/repositories/config_repository.py +912 -0
  30. isa_model/core/resilience/circuit_breaker.py +366 -0
  31. isa_model/core/security/secrets.py +358 -0
  32. isa_model/core/services/__init__.py +2 -4
  33. isa_model/core/services/intelligent_model_selector.py +479 -370
  34. isa_model/core/storage/hf_storage.py +2 -2
  35. isa_model/core/types.py +8 -0
  36. isa_model/deployment/__init__.py +5 -48
  37. isa_model/deployment/core/__init__.py +2 -31
  38. isa_model/deployment/core/deployment_manager.py +1278 -368
  39. isa_model/deployment/local/__init__.py +31 -0
  40. isa_model/deployment/local/config.py +248 -0
  41. isa_model/deployment/local/gpu_gateway.py +607 -0
  42. isa_model/deployment/local/health_checker.py +428 -0
  43. isa_model/deployment/local/provider.py +586 -0
  44. isa_model/deployment/local/tensorrt_service.py +621 -0
  45. isa_model/deployment/local/transformers_service.py +644 -0
  46. isa_model/deployment/local/vllm_service.py +527 -0
  47. isa_model/deployment/modal/__init__.py +8 -0
  48. isa_model/deployment/modal/config.py +136 -0
  49. isa_model/deployment/modal/deployer.py +894 -0
  50. isa_model/deployment/modal/services/__init__.py +3 -0
  51. isa_model/deployment/modal/services/audio/__init__.py +1 -0
  52. isa_model/deployment/modal/services/audio/isa_audio_chatTTS_service.py +520 -0
  53. isa_model/deployment/modal/services/audio/isa_audio_openvoice_service.py +758 -0
  54. isa_model/deployment/modal/services/audio/isa_audio_service_v2.py +1044 -0
  55. isa_model/deployment/modal/services/embedding/__init__.py +1 -0
  56. isa_model/deployment/modal/services/embedding/isa_embed_rerank_service.py +296 -0
  57. isa_model/deployment/modal/services/llm/__init__.py +1 -0
  58. isa_model/deployment/modal/services/llm/isa_llm_service.py +424 -0
  59. isa_model/deployment/modal/services/video/__init__.py +1 -0
  60. isa_model/deployment/modal/services/video/isa_video_hunyuan_service.py +423 -0
  61. isa_model/deployment/modal/services/vision/__init__.py +1 -0
  62. isa_model/deployment/modal/services/vision/isa_vision_ocr_service.py +519 -0
  63. isa_model/deployment/modal/services/vision/isa_vision_qwen25_service.py +709 -0
  64. isa_model/deployment/modal/services/vision/isa_vision_table_service.py +676 -0
  65. isa_model/deployment/modal/services/vision/isa_vision_ui_service.py +833 -0
  66. isa_model/deployment/modal/services/vision/isa_vision_ui_service_optimized.py +660 -0
  67. isa_model/deployment/models/org-org-acme-corp-tenant-a-service-llm-20250825-225822/tenant-a-service_modal_service.py +48 -0
  68. isa_model/deployment/models/org-test-org-123-prefix-test-service-llm-20250825-225822/prefix-test-service_modal_service.py +48 -0
  69. isa_model/deployment/models/test-llm-service-llm-20250825-204442/test-llm-service_modal_service.py +48 -0
  70. isa_model/deployment/models/test-monitoring-gpt2-llm-20250825-212906/test-monitoring-gpt2_modal_service.py +48 -0
  71. isa_model/deployment/models/test-monitoring-gpt2-llm-20250825-213009/test-monitoring-gpt2_modal_service.py +48 -0
  72. isa_model/deployment/storage/__init__.py +5 -0
  73. isa_model/deployment/storage/deployment_repository.py +824 -0
  74. isa_model/deployment/triton/__init__.py +10 -0
  75. isa_model/deployment/triton/config.py +196 -0
  76. isa_model/deployment/triton/configs/__init__.py +1 -0
  77. isa_model/deployment/triton/provider.py +512 -0
  78. isa_model/deployment/triton/scripts/__init__.py +1 -0
  79. isa_model/deployment/triton/templates/__init__.py +1 -0
  80. isa_model/inference/__init__.py +47 -1
  81. isa_model/inference/ai_factory.py +179 -16
  82. isa_model/inference/legacy_services/__init__.py +21 -0
  83. isa_model/inference/legacy_services/model_evaluation.py +637 -0
  84. isa_model/inference/legacy_services/model_service.py +573 -0
  85. isa_model/inference/legacy_services/model_serving.py +717 -0
  86. isa_model/inference/legacy_services/model_training.py +561 -0
  87. isa_model/inference/models/__init__.py +21 -0
  88. isa_model/inference/models/inference_config.py +551 -0
  89. isa_model/inference/models/inference_record.py +675 -0
  90. isa_model/inference/models/performance_models.py +714 -0
  91. isa_model/inference/repositories/__init__.py +9 -0
  92. isa_model/inference/repositories/inference_repository.py +828 -0
  93. isa_model/inference/services/audio/__init__.py +21 -0
  94. isa_model/inference/services/audio/base_realtime_service.py +225 -0
  95. isa_model/inference/services/audio/base_stt_service.py +184 -11
  96. isa_model/inference/services/audio/isa_tts_service.py +0 -0
  97. isa_model/inference/services/audio/openai_realtime_service.py +320 -124
  98. isa_model/inference/services/audio/openai_stt_service.py +53 -11
  99. isa_model/inference/services/base_service.py +17 -1
  100. isa_model/inference/services/custom_model_manager.py +277 -0
  101. isa_model/inference/services/embedding/__init__.py +13 -0
  102. isa_model/inference/services/embedding/base_embed_service.py +111 -8
  103. isa_model/inference/services/embedding/isa_embed_service.py +305 -0
  104. isa_model/inference/services/embedding/ollama_embed_service.py +15 -3
  105. isa_model/inference/services/embedding/openai_embed_service.py +2 -4
  106. isa_model/inference/services/embedding/resilient_embed_service.py +285 -0
  107. isa_model/inference/services/embedding/tests/test_embedding.py +222 -0
  108. isa_model/inference/services/img/__init__.py +2 -2
  109. isa_model/inference/services/img/base_image_gen_service.py +24 -7
  110. isa_model/inference/services/img/replicate_image_gen_service.py +84 -422
  111. isa_model/inference/services/img/services/replicate_face_swap.py +193 -0
  112. isa_model/inference/services/img/services/replicate_flux.py +226 -0
  113. isa_model/inference/services/img/services/replicate_flux_kontext.py +219 -0
  114. isa_model/inference/services/img/services/replicate_sticker_maker.py +249 -0
  115. isa_model/inference/services/img/tests/test_img_client.py +297 -0
  116. isa_model/inference/services/llm/__init__.py +10 -2
  117. isa_model/inference/services/llm/base_llm_service.py +361 -26
  118. isa_model/inference/services/llm/cerebras_llm_service.py +628 -0
  119. isa_model/inference/services/llm/helpers/llm_adapter.py +71 -12
  120. isa_model/inference/services/llm/helpers/llm_prompts.py +342 -0
  121. isa_model/inference/services/llm/helpers/llm_utils.py +321 -23
  122. isa_model/inference/services/llm/huggingface_llm_service.py +581 -0
  123. isa_model/inference/services/llm/local_llm_service.py +747 -0
  124. isa_model/inference/services/llm/ollama_llm_service.py +11 -3
  125. isa_model/inference/services/llm/openai_llm_service.py +670 -56
  126. isa_model/inference/services/llm/yyds_llm_service.py +10 -3
  127. isa_model/inference/services/vision/__init__.py +27 -6
  128. isa_model/inference/services/vision/base_vision_service.py +118 -185
  129. isa_model/inference/services/vision/blip_vision_service.py +359 -0
  130. isa_model/inference/services/vision/helpers/image_utils.py +19 -10
  131. isa_model/inference/services/vision/isa_vision_service.py +634 -0
  132. isa_model/inference/services/vision/openai_vision_service.py +19 -10
  133. isa_model/inference/services/vision/tests/test_ocr_client.py +284 -0
  134. isa_model/inference/services/vision/vgg16_vision_service.py +257 -0
  135. isa_model/serving/api/cache_manager.py +245 -0
  136. isa_model/serving/api/dependencies/__init__.py +1 -0
  137. isa_model/serving/api/dependencies/auth.py +194 -0
  138. isa_model/serving/api/dependencies/database.py +139 -0
  139. isa_model/serving/api/error_handlers.py +284 -0
  140. isa_model/serving/api/fastapi_server.py +240 -18
  141. isa_model/serving/api/middleware/auth.py +317 -0
  142. isa_model/serving/api/middleware/security.py +268 -0
  143. isa_model/serving/api/middleware/tenant_context.py +414 -0
  144. isa_model/serving/api/routes/analytics.py +489 -0
  145. isa_model/serving/api/routes/config.py +645 -0
  146. isa_model/serving/api/routes/deployment_billing.py +315 -0
  147. isa_model/serving/api/routes/deployments.py +475 -0
  148. isa_model/serving/api/routes/gpu_gateway.py +440 -0
  149. isa_model/serving/api/routes/health.py +32 -12
  150. isa_model/serving/api/routes/inference_monitoring.py +486 -0
  151. isa_model/serving/api/routes/local_deployments.py +448 -0
  152. isa_model/serving/api/routes/logs.py +430 -0
  153. isa_model/serving/api/routes/settings.py +582 -0
  154. isa_model/serving/api/routes/tenants.py +575 -0
  155. isa_model/serving/api/routes/unified.py +992 -171
  156. isa_model/serving/api/routes/webhooks.py +479 -0
  157. isa_model/serving/api/startup.py +318 -0
  158. isa_model/serving/modal_proxy_server.py +249 -0
  159. isa_model/utils/gpu_utils.py +311 -0
  160. {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/METADATA +76 -22
  161. isa_model-0.4.3.dist-info/RECORD +193 -0
  162. isa_model/deployment/cloud/__init__.py +0 -9
  163. isa_model/deployment/cloud/modal/__init__.py +0 -10
  164. isa_model/deployment/cloud/modal/isa_vision_doc_service.py +0 -766
  165. isa_model/deployment/cloud/modal/isa_vision_table_service.py +0 -532
  166. isa_model/deployment/cloud/modal/isa_vision_ui_service.py +0 -406
  167. isa_model/deployment/cloud/modal/register_models.py +0 -321
  168. isa_model/deployment/core/deployment_config.py +0 -356
  169. isa_model/deployment/core/isa_deployment_service.py +0 -401
  170. isa_model/deployment/gpu_int8_ds8/app/server.py +0 -66
  171. isa_model/deployment/gpu_int8_ds8/scripts/test_client.py +0 -43
  172. isa_model/deployment/gpu_int8_ds8/scripts/test_client_os.py +0 -35
  173. isa_model/deployment/runtime/deployed_service.py +0 -338
  174. isa_model/deployment/services/__init__.py +0 -9
  175. isa_model/deployment/services/auto_deploy_vision_service.py +0 -538
  176. isa_model/deployment/services/model_service.py +0 -332
  177. isa_model/deployment/services/service_monitor.py +0 -356
  178. isa_model/deployment/services/service_registry.py +0 -527
  179. isa_model/eval/__init__.py +0 -92
  180. isa_model/eval/benchmarks.py +0 -469
  181. isa_model/eval/config/__init__.py +0 -10
  182. isa_model/eval/config/evaluation_config.py +0 -108
  183. isa_model/eval/evaluators/__init__.py +0 -18
  184. isa_model/eval/evaluators/base_evaluator.py +0 -503
  185. isa_model/eval/evaluators/llm_evaluator.py +0 -472
  186. isa_model/eval/factory.py +0 -531
  187. isa_model/eval/infrastructure/__init__.py +0 -24
  188. isa_model/eval/infrastructure/experiment_tracker.py +0 -466
  189. isa_model/eval/metrics.py +0 -798
  190. isa_model/inference/adapter/unified_api.py +0 -248
  191. isa_model/inference/services/helpers/stacked_config.py +0 -148
  192. isa_model/inference/services/img/flux_professional_service.py +0 -603
  193. isa_model/inference/services/img/helpers/base_stacked_service.py +0 -274
  194. isa_model/inference/services/others/table_transformer_service.py +0 -61
  195. isa_model/inference/services/vision/doc_analysis_service.py +0 -640
  196. isa_model/inference/services/vision/helpers/base_stacked_service.py +0 -274
  197. isa_model/inference/services/vision/ui_analysis_service.py +0 -823
  198. isa_model/scripts/inference_tracker.py +0 -283
  199. isa_model/scripts/mlflow_manager.py +0 -379
  200. isa_model/scripts/model_registry.py +0 -465
  201. isa_model/scripts/register_models.py +0 -370
  202. isa_model/scripts/register_models_with_embeddings.py +0 -510
  203. isa_model/scripts/start_mlflow.py +0 -95
  204. isa_model/scripts/training_tracker.py +0 -257
  205. isa_model/training/__init__.py +0 -74
  206. isa_model/training/annotation/annotation_schema.py +0 -47
  207. isa_model/training/annotation/processors/annotation_processor.py +0 -126
  208. isa_model/training/annotation/storage/dataset_manager.py +0 -131
  209. isa_model/training/annotation/storage/dataset_schema.py +0 -44
  210. isa_model/training/annotation/tests/test_annotation_flow.py +0 -109
  211. isa_model/training/annotation/tests/test_minio copy.py +0 -113
  212. isa_model/training/annotation/tests/test_minio_upload.py +0 -43
  213. isa_model/training/annotation/views/annotation_controller.py +0 -158
  214. isa_model/training/cloud/__init__.py +0 -22
  215. isa_model/training/cloud/job_orchestrator.py +0 -402
  216. isa_model/training/cloud/runpod_trainer.py +0 -454
  217. isa_model/training/cloud/storage_manager.py +0 -482
  218. isa_model/training/core/__init__.py +0 -23
  219. isa_model/training/core/config.py +0 -181
  220. isa_model/training/core/dataset.py +0 -222
  221. isa_model/training/core/trainer.py +0 -720
  222. isa_model/training/core/utils.py +0 -213
  223. isa_model/training/factory.py +0 -424
  224. isa_model-0.3.91.dist-info/RECORD +0 -138
  225. /isa_model/{core/storage/minio_storage.py → deployment/modal/services/audio/isa_audio_fish_service.py} +0 -0
  226. /isa_model/deployment/{services → modal/services/vision}/simple_auto_deploy_vision_service.py +0 -0
  227. {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/WHEEL +0 -0
  228. {isa_model-0.3.91.dist-info → isa_model-0.4.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,912 @@
1
+ """
2
+ Configuration Repository - Data persistence layer for configuration management
3
+
4
+ Provides standardized data access for configuration data, provider settings, and environment configurations
5
+ following the ISA Model architecture pattern.
6
+ """
7
+
8
+ import logging
9
+ import json
10
+ import os
11
+ from datetime import datetime, timezone
12
+ from typing import Dict, List, Optional, Any, Union
13
+ from pathlib import Path
14
+ from dataclasses import dataclass, asdict
15
+ from enum import Enum
16
+
17
+ try:
18
+ # Try to import Supabase for centralized data storage
19
+ from ...core.database.supabase_client import get_supabase_client
20
+ SUPABASE_AVAILABLE = True
21
+ except ImportError:
22
+ SUPABASE_AVAILABLE = False
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+ class ConfigType(str, Enum):
27
+ """Configuration type enumeration"""
28
+ PROVIDER = "provider"
29
+ ENVIRONMENT = "environment"
30
+ SYSTEM = "system"
31
+ USER = "user"
32
+ API_KEY = "api_key"
33
+ FEATURE_FLAG = "feature_flag"
34
+
35
+ @dataclass
36
+ class ConfigRecord:
37
+ """Configuration record model"""
38
+ config_id: str
39
+ config_type: str
40
+ config_key: str
41
+ config_value: Any
42
+ environment: str = "production"
43
+ is_active: bool = True
44
+ is_encrypted: bool = False
45
+ created_at: datetime = None
46
+ updated_at: datetime = None
47
+ created_by: Optional[str] = None
48
+ updated_by: Optional[str] = None
49
+ description: Optional[str] = None
50
+ tags: Optional[Dict[str, str]] = None
51
+ metadata: Optional[Dict[str, Any]] = None
52
+
53
+ def __post_init__(self):
54
+ if self.created_at is None:
55
+ self.created_at = datetime.now(timezone.utc)
56
+ if self.updated_at is None:
57
+ self.updated_at = self.created_at
58
+
59
+ @dataclass
60
+ class ProviderConfig:
61
+ """Provider configuration model"""
62
+ provider_name: str
63
+ config_data: Dict[str, Any]
64
+ is_active: bool = True
65
+ environment: str = "production"
66
+ created_at: datetime = None
67
+ updated_at: datetime = None
68
+ created_by: Optional[str] = None
69
+ updated_by: Optional[str] = None
70
+
71
+ def __post_init__(self):
72
+ if self.created_at is None:
73
+ self.created_at = datetime.now(timezone.utc)
74
+ if self.updated_at is None:
75
+ self.updated_at = self.created_at
76
+
77
+ @dataclass
78
+ class EnvironmentConfig:
79
+ """Environment configuration model"""
80
+ environment: str
81
+ config_data: Dict[str, Any]
82
+ is_active: bool = True
83
+ created_at: datetime = None
84
+ updated_at: datetime = None
85
+ created_by: Optional[str] = None
86
+ updated_by: Optional[str] = None
87
+
88
+ def __post_init__(self):
89
+ if self.created_at is None:
90
+ self.created_at = datetime.now(timezone.utc)
91
+ if self.updated_at is None:
92
+ self.updated_at = self.created_at
93
+
94
+ @dataclass
95
+ class ConfigAuditLog:
96
+ """Configuration audit log model"""
97
+ audit_id: str
98
+ config_id: str
99
+ action: str # create, update, delete, read
100
+ old_value: Optional[Any] = None
101
+ new_value: Optional[Any] = None
102
+ user_id: Optional[str] = None
103
+ timestamp: datetime = None
104
+ ip_address: Optional[str] = None
105
+ user_agent: Optional[str] = None
106
+
107
+ def __post_init__(self):
108
+ if self.timestamp is None:
109
+ self.timestamp = datetime.now(timezone.utc)
110
+
111
+ class ConfigRepository:
112
+ """
113
+ Repository for configuration data persistence
114
+
115
+ Supports multiple backend storage options:
116
+ 1. Environment variables (for sensitive data)
117
+ 2. File system (for development and local configs)
118
+ 3. Supabase (for centralized storage)
119
+ 4. In-memory (for testing)
120
+ """
121
+
122
+ def __init__(self, storage_backend: str = "auto", **kwargs):
123
+ """
124
+ Initialize configuration repository
125
+
126
+ Args:
127
+ storage_backend: "env", "file", "supabase", "memory", or "auto"
128
+ **kwargs: Backend-specific configuration
129
+ """
130
+ self.storage_backend = self._determine_backend(storage_backend)
131
+ self.config = kwargs
132
+
133
+ # Initialize storage backend
134
+ if self.storage_backend == "supabase":
135
+ self._init_supabase()
136
+ elif self.storage_backend == "env":
137
+ self._init_env()
138
+ elif self.storage_backend == "memory":
139
+ self._init_memory()
140
+ else: # file system
141
+ self._init_file_system()
142
+
143
+ logger.info(f"Configuration repository initialized with {self.storage_backend} backend")
144
+
145
+ def _determine_backend(self, preference: str) -> str:
146
+ """Determine the best available storage backend"""
147
+ if preference == "supabase" and SUPABASE_AVAILABLE:
148
+ return "supabase"
149
+ elif preference in ["env", "file", "memory", "supabase"]:
150
+ return preference
151
+
152
+ # Auto-select best available backend
153
+ if SUPABASE_AVAILABLE:
154
+ return "supabase"
155
+ else:
156
+ return "file"
157
+
158
+ def _init_supabase(self):
159
+ """Initialize Supabase backend"""
160
+ try:
161
+ self.supabase_client = get_supabase_client()
162
+ self._ensure_supabase_tables()
163
+ logger.info("Supabase backend initialized for configurations")
164
+ except Exception as e:
165
+ logger.error(f"Failed to initialize Supabase backend: {e}")
166
+ self.storage_backend = "file"
167
+ self._init_file_system()
168
+
169
+ def _init_file_system(self):
170
+ """Initialize file system backend"""
171
+ self.config_dir = Path(self.config.get("config_dir", "./config_data"))
172
+ self.config_dir.mkdir(parents=True, exist_ok=True)
173
+
174
+ # Create subdirectories
175
+ (self.config_dir / "providers").mkdir(exist_ok=True)
176
+ (self.config_dir / "environments").mkdir(exist_ok=True)
177
+ (self.config_dir / "system").mkdir(exist_ok=True)
178
+ (self.config_dir / "audit").mkdir(exist_ok=True)
179
+
180
+ logger.info(f"File system backend initialized: {self.config_dir}")
181
+
182
+ def _init_env(self):
183
+ """Initialize environment variables backend"""
184
+ self.env_prefix = self.config.get("env_prefix", "ISA_")
185
+ logger.info(f"Environment variables backend initialized with prefix: {self.env_prefix}")
186
+
187
+ def _init_memory(self):
188
+ """Initialize in-memory backend for testing"""
189
+ self.configs = {}
190
+ self.providers = {}
191
+ self.environments = {}
192
+ self.audit_logs = []
193
+ logger.info("In-memory backend initialized for configurations")
194
+
195
+ def _ensure_supabase_tables(self):
196
+ """Ensure required Supabase tables exist"""
197
+ try:
198
+ self.supabase_client.table("config_records").select("config_id").limit(1).execute()
199
+ self.supabase_client.table("provider_configs").select("provider_name").limit(1).execute()
200
+ self.supabase_client.table("environment_configs").select("environment").limit(1).execute()
201
+ self.supabase_client.table("config_audit_logs").select("audit_id").limit(1).execute()
202
+ except Exception as e:
203
+ logger.warning(f"Some configuration tables may not exist in Supabase: {e}")
204
+
205
+ # Provider Configuration Methods
206
+
207
+ def get_provider_config(
208
+ self,
209
+ provider_name: str,
210
+ environment: str = "production",
211
+ mask_secrets: bool = True
212
+ ) -> Optional[Dict[str, Any]]:
213
+ """Get provider configuration"""
214
+ if self.storage_backend == "supabase":
215
+ return self._get_provider_config_supabase(provider_name, environment, mask_secrets)
216
+ elif self.storage_backend == "env":
217
+ return self._get_provider_config_env(provider_name, environment, mask_secrets)
218
+ elif self.storage_backend == "memory":
219
+ return self._get_provider_config_memory(provider_name, environment, mask_secrets)
220
+ else:
221
+ return self._get_provider_config_file(provider_name, environment, mask_secrets)
222
+
223
+ def update_provider_config(
224
+ self,
225
+ provider_name: str,
226
+ config_data: Dict[str, Any],
227
+ environment: str = "production",
228
+ is_active: bool = True,
229
+ updated_by: Optional[str] = None
230
+ ) -> bool:
231
+ """Update provider configuration"""
232
+ if self.storage_backend == "supabase":
233
+ return self._update_provider_config_supabase(provider_name, config_data, environment, is_active, updated_by)
234
+ elif self.storage_backend == "env":
235
+ return self._update_provider_config_env(provider_name, config_data, environment, is_active, updated_by)
236
+ elif self.storage_backend == "memory":
237
+ return self._update_provider_config_memory(provider_name, config_data, environment, is_active, updated_by)
238
+ else:
239
+ return self._update_provider_config_file(provider_name, config_data, environment, is_active, updated_by)
240
+
241
+ def list_provider_configs(
242
+ self,
243
+ environment: str = "production",
244
+ include_inactive: bool = False
245
+ ) -> List[ProviderConfig]:
246
+ """List all provider configurations"""
247
+ if self.storage_backend == "supabase":
248
+ return self._list_provider_configs_supabase(environment, include_inactive)
249
+ elif self.storage_backend == "env":
250
+ return self._list_provider_configs_env(environment, include_inactive)
251
+ elif self.storage_backend == "memory":
252
+ return self._list_provider_configs_memory(environment, include_inactive)
253
+ else:
254
+ return self._list_provider_configs_file(environment, include_inactive)
255
+
256
+ def delete_provider_config(
257
+ self,
258
+ provider_name: str,
259
+ environment: str = "production",
260
+ deleted_by: Optional[str] = None
261
+ ) -> bool:
262
+ """Delete provider configuration"""
263
+ if self.storage_backend == "supabase":
264
+ return self._delete_provider_config_supabase(provider_name, environment, deleted_by)
265
+ elif self.storage_backend == "env":
266
+ return self._delete_provider_config_env(provider_name, environment, deleted_by)
267
+ elif self.storage_backend == "memory":
268
+ return self._delete_provider_config_memory(provider_name, environment, deleted_by)
269
+ else:
270
+ return self._delete_provider_config_file(provider_name, environment, deleted_by)
271
+
272
+ # Environment Configuration Methods
273
+
274
+ def get_environment_config(
275
+ self,
276
+ environment: str,
277
+ mask_secrets: bool = True
278
+ ) -> Optional[Dict[str, Any]]:
279
+ """Get environment configuration"""
280
+ if self.storage_backend == "supabase":
281
+ return self._get_environment_config_supabase(environment, mask_secrets)
282
+ elif self.storage_backend == "env":
283
+ return self._get_environment_config_env(environment, mask_secrets)
284
+ elif self.storage_backend == "memory":
285
+ return self._get_environment_config_memory(environment, mask_secrets)
286
+ else:
287
+ return self._get_environment_config_file(environment, mask_secrets)
288
+
289
+ def update_environment_config(
290
+ self,
291
+ environment: str,
292
+ config_data: Dict[str, Any],
293
+ updated_by: Optional[str] = None
294
+ ) -> bool:
295
+ """Update environment configuration"""
296
+ if self.storage_backend == "supabase":
297
+ return self._update_environment_config_supabase(environment, config_data, updated_by)
298
+ elif self.storage_backend == "env":
299
+ return self._update_environment_config_env(environment, config_data, updated_by)
300
+ elif self.storage_backend == "memory":
301
+ return self._update_environment_config_memory(environment, config_data, updated_by)
302
+ else:
303
+ return self._update_environment_config_file(environment, config_data, updated_by)
304
+
305
+ def list_environment_configs(self) -> List[EnvironmentConfig]:
306
+ """List all environment configurations"""
307
+ if self.storage_backend == "supabase":
308
+ return self._list_environment_configs_supabase()
309
+ elif self.storage_backend == "env":
310
+ return self._list_environment_configs_env()
311
+ elif self.storage_backend == "memory":
312
+ return self._list_environment_configs_memory()
313
+ else:
314
+ return self._list_environment_configs_file()
315
+
316
+ # Generic Configuration Methods
317
+
318
+ def get_config(
319
+ self,
320
+ config_key: str,
321
+ config_type: str = "system",
322
+ environment: str = "production",
323
+ default_value: Any = None
324
+ ) -> Any:
325
+ """Get generic configuration value"""
326
+ if self.storage_backend == "env":
327
+ return self._get_config_env(config_key, config_type, environment, default_value)
328
+ elif self.storage_backend == "memory":
329
+ return self._get_config_memory(config_key, config_type, environment, default_value)
330
+ elif self.storage_backend == "supabase":
331
+ return self._get_config_supabase(config_key, config_type, environment, default_value)
332
+ else:
333
+ return self._get_config_file(config_key, config_type, environment, default_value)
334
+
335
+ def set_config(
336
+ self,
337
+ config_key: str,
338
+ config_value: Any,
339
+ config_type: str = "system",
340
+ environment: str = "production",
341
+ updated_by: Optional[str] = None,
342
+ description: Optional[str] = None
343
+ ) -> bool:
344
+ """Set generic configuration value"""
345
+ if self.storage_backend == "env":
346
+ return self._set_config_env(config_key, config_value, config_type, environment, updated_by, description)
347
+ elif self.storage_backend == "memory":
348
+ return self._set_config_memory(config_key, config_value, config_type, environment, updated_by, description)
349
+ elif self.storage_backend == "supabase":
350
+ return self._set_config_supabase(config_key, config_value, config_type, environment, updated_by, description)
351
+ else:
352
+ return self._set_config_file(config_key, config_value, config_type, environment, updated_by, description)
353
+
354
+ # Validation Methods
355
+
356
+ def validate_provider_config(
357
+ self,
358
+ provider_name: str,
359
+ config_data: Dict[str, Any]
360
+ ) -> Dict[str, Any]:
361
+ """Validate provider configuration"""
362
+ validation_result = {
363
+ "valid": True,
364
+ "errors": [],
365
+ "warnings": []
366
+ }
367
+
368
+ # Basic validation rules
369
+ if not provider_name:
370
+ validation_result["valid"] = False
371
+ validation_result["errors"].append("Provider name is required")
372
+
373
+ if not config_data:
374
+ validation_result["valid"] = False
375
+ validation_result["errors"].append("Configuration data is required")
376
+
377
+ # Provider-specific validation
378
+ if provider_name == "openai":
379
+ if "api_key" not in config_data:
380
+ validation_result["valid"] = False
381
+ validation_result["errors"].append("OpenAI API key is required")
382
+ elif provider_name == "anthropic":
383
+ if "api_key" not in config_data:
384
+ validation_result["valid"] = False
385
+ validation_result["errors"].append("Anthropic API key is required")
386
+ elif provider_name == "replicate":
387
+ if "api_token" not in config_data:
388
+ validation_result["valid"] = False
389
+ validation_result["errors"].append("Replicate API token is required")
390
+
391
+ return validation_result
392
+
393
+ def validate_environment_config(
394
+ self,
395
+ environment: str,
396
+ config_data: Dict[str, Any]
397
+ ) -> Dict[str, Any]:
398
+ """Validate environment configuration"""
399
+ validation_result = {
400
+ "valid": True,
401
+ "errors": [],
402
+ "warnings": []
403
+ }
404
+
405
+ if not environment:
406
+ validation_result["valid"] = False
407
+ validation_result["errors"].append("Environment name is required")
408
+
409
+ if environment not in ["development", "staging", "production"]:
410
+ validation_result["warnings"].append(f"Unusual environment name: {environment}")
411
+
412
+ return validation_result
413
+
414
+ # Audit and Logging Methods
415
+
416
+ def log_config_change(
417
+ self,
418
+ config_id: str,
419
+ action: str,
420
+ old_value: Optional[Any] = None,
421
+ new_value: Optional[Any] = None,
422
+ user_id: Optional[str] = None,
423
+ ip_address: Optional[str] = None
424
+ ) -> str:
425
+ """Log configuration change for audit purposes"""
426
+ audit_id = f"audit_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{hash(config_id) % 10000}"
427
+
428
+ audit_log = ConfigAuditLog(
429
+ audit_id=audit_id,
430
+ config_id=config_id,
431
+ action=action,
432
+ old_value=old_value,
433
+ new_value=new_value,
434
+ user_id=user_id,
435
+ ip_address=ip_address
436
+ )
437
+
438
+ if self.storage_backend == "memory":
439
+ self.audit_logs.append(audit_log)
440
+ elif self.storage_backend == "file":
441
+ self._save_audit_log_file(audit_log)
442
+ # Supabase implementation would go here
443
+
444
+ return audit_id
445
+
446
+ def get_audit_logs(
447
+ self,
448
+ config_id: Optional[str] = None,
449
+ action: Optional[str] = None,
450
+ user_id: Optional[str] = None,
451
+ limit: int = 100
452
+ ) -> List[ConfigAuditLog]:
453
+ """Get configuration audit logs"""
454
+ if self.storage_backend == "memory":
455
+ return self._get_audit_logs_memory(config_id, action, user_id, limit)
456
+ elif self.storage_backend == "file":
457
+ return self._get_audit_logs_file(config_id, action, user_id, limit)
458
+ else:
459
+ return [] # Supabase implementation needed
460
+
461
+ # Backend-specific implementations (File System)
462
+
463
+ def _get_provider_config_file(self, provider_name: str, environment: str, mask_secrets: bool) -> Optional[Dict[str, Any]]:
464
+ """Get provider config from file system"""
465
+ try:
466
+ config_file = self.config_dir / "providers" / f"{provider_name}_{environment}.json"
467
+ if not config_file.exists():
468
+ return None
469
+
470
+ with open(config_file, 'r') as f:
471
+ config_data = json.load(f)
472
+
473
+ if mask_secrets:
474
+ config_data = self._mask_sensitive_data(config_data)
475
+
476
+ return config_data.get("config_data")
477
+ except Exception as e:
478
+ logger.error(f"Failed to get provider config from file: {e}")
479
+ return None
480
+
481
+ def _update_provider_config_file(
482
+ self, provider_name: str, config_data: Dict[str, Any],
483
+ environment: str, is_active: bool, updated_by: Optional[str]
484
+ ) -> bool:
485
+ """Update provider config in file system"""
486
+ try:
487
+ config_file = self.config_dir / "providers" / f"{provider_name}_{environment}.json"
488
+
489
+ provider_config = ProviderConfig(
490
+ provider_name=provider_name,
491
+ config_data=config_data,
492
+ is_active=is_active,
493
+ environment=environment,
494
+ updated_by=updated_by,
495
+ updated_at=datetime.now(timezone.utc)
496
+ )
497
+
498
+ # Preserve created_at if file exists
499
+ if config_file.exists():
500
+ with open(config_file, 'r') as f:
501
+ existing_data = json.load(f)
502
+ if 'created_at' in existing_data:
503
+ provider_config.created_at = datetime.fromisoformat(existing_data['created_at'])
504
+
505
+ config_dict = asdict(provider_config)
506
+ # Convert datetime objects to ISO strings
507
+ for key in ['created_at', 'updated_at']:
508
+ if config_dict[key] and isinstance(config_dict[key], datetime):
509
+ config_dict[key] = config_dict[key].isoformat()
510
+
511
+ with open(config_file, 'w') as f:
512
+ json.dump(config_dict, f, indent=2, ensure_ascii=False)
513
+
514
+ # Log the change
515
+ self.log_config_change(
516
+ config_id=f"provider_{provider_name}_{environment}",
517
+ action="update",
518
+ new_value=config_data,
519
+ user_id=updated_by
520
+ )
521
+
522
+ return True
523
+ except Exception as e:
524
+ logger.error(f"Failed to update provider config in file: {e}")
525
+ return False
526
+
527
+ def _list_provider_configs_file(self, environment: str, include_inactive: bool) -> List[ProviderConfig]:
528
+ """List provider configs from file system"""
529
+ try:
530
+ configs = []
531
+ providers_dir = self.config_dir / "providers"
532
+
533
+ for config_file in providers_dir.glob(f"*_{environment}.json"):
534
+ with open(config_file, 'r') as f:
535
+ config_data = json.load(f)
536
+
537
+ if not include_inactive and not config_data.get('is_active', True):
538
+ continue
539
+
540
+ # Convert datetime fields
541
+ for key in ['created_at', 'updated_at']:
542
+ if config_data[key]:
543
+ config_data[key] = datetime.fromisoformat(config_data[key])
544
+
545
+ configs.append(ProviderConfig(**config_data))
546
+
547
+ return configs
548
+ except Exception as e:
549
+ logger.error(f"Failed to list provider configs from file: {e}")
550
+ return []
551
+
552
+ def _get_environment_config_file(self, environment: str, mask_secrets: bool) -> Optional[Dict[str, Any]]:
553
+ """Get environment config from file system"""
554
+ try:
555
+ config_file = self.config_dir / "environments" / f"{environment}.json"
556
+ if not config_file.exists():
557
+ return None
558
+
559
+ with open(config_file, 'r') as f:
560
+ config_data = json.load(f)
561
+
562
+ if mask_secrets:
563
+ config_data = self._mask_sensitive_data(config_data)
564
+
565
+ return config_data.get("config_data")
566
+ except Exception as e:
567
+ logger.error(f"Failed to get environment config from file: {e}")
568
+ return None
569
+
570
+ def _get_config_file(self, config_key: str, config_type: str, environment: str, default_value: Any) -> Any:
571
+ """Get generic config from file system"""
572
+ try:
573
+ config_file = self.config_dir / "system" / f"{config_type}_{environment}.json"
574
+ if not config_file.exists():
575
+ return default_value
576
+
577
+ with open(config_file, 'r') as f:
578
+ config_data = json.load(f)
579
+
580
+ return config_data.get(config_key, default_value)
581
+ except Exception as e:
582
+ logger.error(f"Failed to get config from file: {e}")
583
+ return default_value
584
+
585
+ def _set_config_file(
586
+ self, config_key: str, config_value: Any, config_type: str,
587
+ environment: str, updated_by: Optional[str], description: Optional[str]
588
+ ) -> bool:
589
+ """Set generic config in file system"""
590
+ try:
591
+ config_file = self.config_dir / "system" / f"{config_type}_{environment}.json"
592
+
593
+ # Load existing config or create new
594
+ if config_file.exists():
595
+ with open(config_file, 'r') as f:
596
+ config_data = json.load(f)
597
+ else:
598
+ config_data = {}
599
+
600
+ config_data[config_key] = config_value
601
+ config_data['_updated_at'] = datetime.now(timezone.utc).isoformat()
602
+ config_data['_updated_by'] = updated_by
603
+
604
+ with open(config_file, 'w') as f:
605
+ json.dump(config_data, f, indent=2, ensure_ascii=False)
606
+
607
+ return True
608
+ except Exception as e:
609
+ logger.error(f"Failed to set config in file: {e}")
610
+ return False
611
+
612
+ # Backend-specific implementations (Environment Variables)
613
+
614
+ def _get_provider_config_env(self, provider_name: str, environment: str, mask_secrets: bool) -> Optional[Dict[str, Any]]:
615
+ """Get provider config from environment variables"""
616
+ env_key = f"{self.env_prefix}{provider_name.upper()}_{environment.upper()}_CONFIG"
617
+ config_json = os.getenv(env_key)
618
+
619
+ if not config_json:
620
+ return None
621
+
622
+ try:
623
+ config_data = json.loads(config_json)
624
+ if mask_secrets:
625
+ config_data = self._mask_sensitive_data(config_data)
626
+ return config_data
627
+ except json.JSONDecodeError:
628
+ logger.error(f"Invalid JSON in environment variable: {env_key}")
629
+ return None
630
+
631
+ def _get_config_env(self, config_key: str, config_type: str, environment: str, default_value: Any) -> Any:
632
+ """Get config from environment variables"""
633
+ env_key = f"{self.env_prefix}{config_type.upper()}_{environment.upper()}_{config_key.upper()}"
634
+ return os.getenv(env_key, default_value)
635
+
636
+ # Backend-specific implementations (Memory)
637
+
638
+ def _get_provider_config_memory(self, provider_name: str, environment: str, mask_secrets: bool) -> Optional[Dict[str, Any]]:
639
+ """Get provider config from memory"""
640
+ key = f"{provider_name}_{environment}"
641
+ config = self.providers.get(key)
642
+ if not config:
643
+ return None
644
+
645
+ config_data = config.config_data.copy()
646
+ if mask_secrets:
647
+ config_data = self._mask_sensitive_data(config_data)
648
+ return config_data
649
+
650
+ def _update_provider_config_memory(
651
+ self, provider_name: str, config_data: Dict[str, Any],
652
+ environment: str, is_active: bool, updated_by: Optional[str]
653
+ ) -> bool:
654
+ """Update provider config in memory"""
655
+ key = f"{provider_name}_{environment}"
656
+
657
+ provider_config = ProviderConfig(
658
+ provider_name=provider_name,
659
+ config_data=config_data,
660
+ is_active=is_active,
661
+ environment=environment,
662
+ updated_by=updated_by,
663
+ updated_at=datetime.now(timezone.utc)
664
+ )
665
+
666
+ self.providers[key] = provider_config
667
+ return True
668
+
669
+ def _get_config_memory(self, config_key: str, config_type: str, environment: str, default_value: Any) -> Any:
670
+ """Get config from memory"""
671
+ key = f"{config_type}_{environment}_{config_key}"
672
+ return self.configs.get(key, default_value)
673
+
674
+ def _set_config_memory(
675
+ self, config_key: str, config_value: Any, config_type: str,
676
+ environment: str, updated_by: Optional[str], description: Optional[str]
677
+ ) -> bool:
678
+ """Set config in memory"""
679
+ key = f"{config_type}_{environment}_{config_key}"
680
+ self.configs[key] = config_value
681
+ return True
682
+
683
+ # Utility Methods
684
+
685
+ def _mask_sensitive_data(self, data: Dict[str, Any]) -> Dict[str, Any]:
686
+ """Mask sensitive configuration data"""
687
+ masked_data = data.copy()
688
+ sensitive_keys = ['api_key', 'api_token', 'secret', 'password', 'private_key']
689
+
690
+ for key, value in masked_data.items():
691
+ if any(sensitive_key in key.lower() for sensitive_key in sensitive_keys):
692
+ if isinstance(value, str) and len(value) > 8:
693
+ masked_data[key] = value[:4] + "***" + value[-4:]
694
+ else:
695
+ masked_data[key] = "***"
696
+
697
+ return masked_data
698
+
699
+ def _save_audit_log_file(self, audit_log: ConfigAuditLog):
700
+ """Save audit log to file system"""
701
+ try:
702
+ audit_file = self.config_dir / "audit" / f"{audit_log.audit_id}.json"
703
+ audit_data = asdict(audit_log)
704
+
705
+ if audit_data['timestamp'] and isinstance(audit_data['timestamp'], datetime):
706
+ audit_data['timestamp'] = audit_data['timestamp'].isoformat()
707
+
708
+ with open(audit_file, 'w') as f:
709
+ json.dump(audit_data, f, indent=2, ensure_ascii=False)
710
+ except Exception as e:
711
+ logger.error(f"Failed to save audit log to file: {e}")
712
+
713
+ def _get_audit_logs_file(self, config_id: Optional[str], action: Optional[str], user_id: Optional[str], limit: int) -> List[ConfigAuditLog]:
714
+ """Get audit logs from file system"""
715
+ try:
716
+ logs = []
717
+ audit_dir = self.config_dir / "audit"
718
+
719
+ for audit_file in audit_dir.glob("*.json"):
720
+ with open(audit_file, 'r') as f:
721
+ audit_data = json.load(f)
722
+
723
+ # Apply filters
724
+ if config_id and audit_data.get('config_id') != config_id:
725
+ continue
726
+ if action and audit_data.get('action') != action:
727
+ continue
728
+ if user_id and audit_data.get('user_id') != user_id:
729
+ continue
730
+
731
+ # Convert timestamp
732
+ if audit_data['timestamp']:
733
+ audit_data['timestamp'] = datetime.fromisoformat(audit_data['timestamp'])
734
+
735
+ logs.append(ConfigAuditLog(**audit_data))
736
+
737
+ if len(logs) >= limit:
738
+ break
739
+
740
+ return sorted(logs, key=lambda x: x.timestamp, reverse=True)
741
+ except Exception as e:
742
+ logger.error(f"Failed to get audit logs from file: {e}")
743
+ return []
744
+
745
+ def _get_audit_logs_memory(self, config_id: Optional[str], action: Optional[str], user_id: Optional[str], limit: int) -> List[ConfigAuditLog]:
746
+ """Get audit logs from memory"""
747
+ filtered_logs = []
748
+
749
+ for log in self.audit_logs:
750
+ # Apply filters
751
+ if config_id and log.config_id != config_id:
752
+ continue
753
+ if action and log.action != action:
754
+ continue
755
+ if user_id and log.user_id != user_id:
756
+ continue
757
+
758
+ filtered_logs.append(log)
759
+
760
+ if len(filtered_logs) >= limit:
761
+ break
762
+
763
+ return sorted(filtered_logs, key=lambda x: x.timestamp, reverse=True)
764
+
765
+ # Placeholder implementations for remaining methods
766
+ def _delete_provider_config_file(self, provider_name: str, environment: str, deleted_by: Optional[str]) -> bool:
767
+ try:
768
+ config_file = self.config_dir / "providers" / f"{provider_name}_{environment}.json"
769
+ if config_file.exists():
770
+ config_file.unlink()
771
+ self.log_config_change(
772
+ config_id=f"provider_{provider_name}_{environment}",
773
+ action="delete",
774
+ user_id=deleted_by
775
+ )
776
+ return True
777
+ except Exception as e:
778
+ logger.error(f"Failed to delete provider config from file: {e}")
779
+ return False
780
+
781
+ def _delete_provider_config_memory(self, provider_name: str, environment: str, deleted_by: Optional[str]) -> bool:
782
+ key = f"{provider_name}_{environment}"
783
+ return self.providers.pop(key, None) is not None
784
+
785
+ def _delete_provider_config_env(self, provider_name: str, environment: str, deleted_by: Optional[str]) -> bool:
786
+ # Cannot delete environment variables programmatically
787
+ return False
788
+
789
+ def _update_environment_config_file(self, environment: str, config_data: Dict[str, Any], updated_by: Optional[str]) -> bool:
790
+ try:
791
+ config_file = self.config_dir / "environments" / f"{environment}.json"
792
+
793
+ env_config = EnvironmentConfig(
794
+ environment=environment,
795
+ config_data=config_data,
796
+ updated_by=updated_by,
797
+ updated_at=datetime.now(timezone.utc)
798
+ )
799
+
800
+ config_dict = asdict(env_config)
801
+ # Convert datetime objects to ISO strings
802
+ for key in ['created_at', 'updated_at']:
803
+ if config_dict[key] and isinstance(config_dict[key], datetime):
804
+ config_dict[key] = config_dict[key].isoformat()
805
+
806
+ with open(config_file, 'w') as f:
807
+ json.dump(config_dict, f, indent=2, ensure_ascii=False)
808
+
809
+ return True
810
+ except Exception as e:
811
+ logger.error(f"Failed to update environment config in file: {e}")
812
+ return False
813
+
814
+ def _list_environment_configs_file(self) -> List[EnvironmentConfig]:
815
+ try:
816
+ configs = []
817
+ environments_dir = self.config_dir / "environments"
818
+
819
+ for config_file in environments_dir.glob("*.json"):
820
+ with open(config_file, 'r') as f:
821
+ config_data = json.load(f)
822
+
823
+ # Convert datetime fields
824
+ for key in ['created_at', 'updated_at']:
825
+ if config_data[key]:
826
+ config_data[key] = datetime.fromisoformat(config_data[key])
827
+
828
+ configs.append(EnvironmentConfig(**config_data))
829
+
830
+ return configs
831
+ except Exception as e:
832
+ logger.error(f"Failed to list environment configs from file: {e}")
833
+ return []
834
+
835
+ # Placeholder implementations for Supabase and other methods
836
+ def _get_provider_config_supabase(self, provider_name: str, environment: str, mask_secrets: bool) -> Optional[Dict[str, Any]]:
837
+ return None # Implementation needed
838
+
839
+ def _update_provider_config_supabase(self, provider_name: str, config_data: Dict[str, Any], environment: str, is_active: bool, updated_by: Optional[str]) -> bool:
840
+ return False # Implementation needed
841
+
842
+ def _list_provider_configs_supabase(self, environment: str, include_inactive: bool) -> List[ProviderConfig]:
843
+ return [] # Implementation needed
844
+
845
+ def _update_provider_config_env(self, provider_name: str, config_data: Dict[str, Any], environment: str, is_active: bool, updated_by: Optional[str]) -> bool:
846
+ return False # Environment variables are read-only
847
+
848
+ def _list_provider_configs_env(self, environment: str, include_inactive: bool) -> List[ProviderConfig]:
849
+ return [] # Implementation needed
850
+
851
+ def _list_provider_configs_memory(self, environment: str, include_inactive: bool) -> List[ProviderConfig]:
852
+ configs = []
853
+ for key, config in self.providers.items():
854
+ if environment not in key:
855
+ continue
856
+ if not include_inactive and not config.is_active:
857
+ continue
858
+ configs.append(config)
859
+ return configs
860
+
861
+ def _get_environment_config_supabase(self, environment: str, mask_secrets: bool) -> Optional[Dict[str, Any]]:
862
+ return None # Implementation needed
863
+
864
+ def _get_environment_config_env(self, environment: str, mask_secrets: bool) -> Optional[Dict[str, Any]]:
865
+ return None # Implementation needed
866
+
867
+ def _get_environment_config_memory(self, environment: str, mask_secrets: bool) -> Optional[Dict[str, Any]]:
868
+ env_config = self.environments.get(environment)
869
+ if not env_config:
870
+ return None
871
+
872
+ config_data = env_config.config_data.copy()
873
+ if mask_secrets:
874
+ config_data = self._mask_sensitive_data(config_data)
875
+ return config_data
876
+
877
+ def _update_environment_config_supabase(self, environment: str, config_data: Dict[str, Any], updated_by: Optional[str]) -> bool:
878
+ return False # Implementation needed
879
+
880
+ def _update_environment_config_env(self, environment: str, config_data: Dict[str, Any], updated_by: Optional[str]) -> bool:
881
+ return False # Environment variables are read-only
882
+
883
+ def _update_environment_config_memory(self, environment: str, config_data: Dict[str, Any], updated_by: Optional[str]) -> bool:
884
+ env_config = EnvironmentConfig(
885
+ environment=environment,
886
+ config_data=config_data,
887
+ updated_by=updated_by,
888
+ updated_at=datetime.now(timezone.utc)
889
+ )
890
+ self.environments[environment] = env_config
891
+ return True
892
+
893
+ def _list_environment_configs_supabase(self) -> List[EnvironmentConfig]:
894
+ return [] # Implementation needed
895
+
896
+ def _list_environment_configs_env(self) -> List[EnvironmentConfig]:
897
+ return [] # Implementation needed
898
+
899
+ def _list_environment_configs_memory(self) -> List[EnvironmentConfig]:
900
+ return list(self.environments.values())
901
+
902
+ def _get_config_supabase(self, config_key: str, config_type: str, environment: str, default_value: Any) -> Any:
903
+ return default_value # Implementation needed
904
+
905
+ def _set_config_supabase(self, config_key: str, config_value: Any, config_type: str, environment: str, updated_by: Optional[str], description: Optional[str]) -> bool:
906
+ return False # Implementation needed
907
+
908
+ def _set_config_env(self, config_key: str, config_value: Any, config_type: str, environment: str, updated_by: Optional[str], description: Optional[str]) -> bool:
909
+ return False # Environment variables are read-only
910
+
911
+ def _delete_provider_config_supabase(self, provider_name: str, environment: str, deleted_by: Optional[str]) -> bool:
912
+ return False # Implementation needed