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
@@ -11,6 +11,7 @@ import logging
11
11
  from typing import Dict, List, Optional, Any
12
12
  from enum import Enum
13
13
  from datetime import datetime
14
+ from dataclasses import dataclass
14
15
 
15
16
  try:
16
17
  from ..database.supabase_client import get_supabase_client, get_supabase_table
@@ -22,6 +23,46 @@ from ..config import ConfigManager
22
23
 
23
24
  logger = logging.getLogger(__name__)
24
25
 
26
+ def _parse_metadata(metadata: Any) -> Dict[str, Any]:
27
+ """
28
+ Parse metadata field that might be a dict, JSON string, or None.
29
+
30
+ Args:
31
+ metadata: The metadata value from database (dict, str, or None)
32
+
33
+ Returns:
34
+ Dict with metadata, or empty dict if None
35
+ """
36
+ if not metadata:
37
+ return {}
38
+
39
+ # If already a dict (from JSONB column), return as-is
40
+ if isinstance(metadata, dict):
41
+ return metadata
42
+
43
+ # If string, parse as JSON
44
+ if isinstance(metadata, str):
45
+ try:
46
+ return json.loads(metadata)
47
+ except json.JSONDecodeError:
48
+ logger.warning(f"Failed to parse metadata as JSON: {metadata[:100]}")
49
+ return {}
50
+
51
+ # Unknown type
52
+ logger.warning(f"Unexpected metadata type: {type(metadata)}")
53
+ return {}
54
+
55
+ @dataclass
56
+ class RegisteredModel:
57
+ """Simple model representation for registration results"""
58
+ model_id: str
59
+ model_type: str
60
+ provider: str
61
+ capabilities: List[str]
62
+ metadata: Dict[str, Any]
63
+ created_at: str
64
+ updated_at: str
65
+
25
66
  class ModelCapability(str, Enum):
26
67
  """Model capabilities"""
27
68
  TEXT_GENERATION = "text_generation"
@@ -88,7 +129,7 @@ class ModelRegistry:
88
129
  model_type: ModelType,
89
130
  capabilities: List[ModelCapability],
90
131
  metadata: Dict[str, Any],
91
- provider: Optional[str] = None) -> bool:
132
+ provider: Optional[str] = None) -> Optional[RegisteredModel]:
92
133
  """Register a model with its capabilities and metadata"""
93
134
  try:
94
135
  current_time = datetime.now().isoformat()
@@ -113,7 +154,7 @@ class ModelRegistry:
113
154
 
114
155
  if not result.data:
115
156
  logger.error(f"Failed to insert model {model_id}")
116
- return False
157
+ return None
117
158
 
118
159
  # Delete existing capabilities
119
160
  self._table('model_capabilities').delete().eq('model_id', model_id).execute()
@@ -133,14 +174,24 @@ class ModelRegistry:
133
174
 
134
175
  if not cap_result.data:
135
176
  logger.error(f"Failed to insert capabilities for {model_id}")
136
- return False
177
+ return None
137
178
 
138
179
  logger.info(f"Successfully registered model {model_id} with {len(capabilities)} capabilities")
139
- return True
180
+
181
+ # Return the registered model object
182
+ return RegisteredModel(
183
+ model_id=model_id,
184
+ model_type=model_type.value,
185
+ provider=provider_value,
186
+ capabilities=[cap.value for cap in capabilities],
187
+ metadata=metadata,
188
+ created_at=current_time,
189
+ updated_at=current_time
190
+ )
140
191
 
141
192
  except Exception as e:
142
193
  logger.error(f"Failed to register model {model_id}: {e}")
143
- return False
194
+ return None
144
195
 
145
196
  def unregister_model(self, model_id: str) -> bool:
146
197
  """Unregister a model"""
@@ -203,13 +254,13 @@ class ModelRegistry:
203
254
  result[model_id] = {
204
255
  "type": model["model_type"],
205
256
  "capabilities": capabilities,
206
- "metadata": json.loads(model["metadata"]) if model["metadata"] else {},
257
+ "metadata": _parse_metadata(model["metadata"]),
207
258
  "created_at": model["created_at"],
208
259
  "updated_at": model["updated_at"]
209
260
  }
210
-
261
+
211
262
  return result
212
-
263
+
213
264
  except Exception as e:
214
265
  logger.error(f"Failed to get models by type {model_type}: {e}")
215
266
  return {}
@@ -238,13 +289,13 @@ class ModelRegistry:
238
289
  result[model_id] = {
239
290
  "type": model["model_type"],
240
291
  "capabilities": capabilities,
241
- "metadata": json.loads(model["metadata"]) if model["metadata"] else {},
292
+ "metadata": _parse_metadata(model["metadata"]),
242
293
  "created_at": model["created_at"],
243
294
  "updated_at": model["updated_at"]
244
295
  }
245
-
296
+
246
297
  return result
247
-
298
+
248
299
  except Exception as e:
249
300
  logger.error(f"Failed to get models by capability {capability}: {e}")
250
301
  return {}
@@ -276,13 +327,13 @@ class ModelRegistry:
276
327
  result[model_id] = {
277
328
  "type": model["model_type"],
278
329
  "capabilities": capabilities,
279
- "metadata": json.loads(model["metadata"]) if model["metadata"] else {},
330
+ "metadata": _parse_metadata(model["metadata"]),
280
331
  "created_at": model["created_at"],
281
332
  "updated_at": model["updated_at"]
282
333
  }
283
-
334
+
284
335
  return result
285
-
336
+
286
337
  except Exception as e:
287
338
  logger.error(f"Failed to list models: {e}")
288
339
  return {}
@@ -337,13 +388,118 @@ class ModelRegistry:
337
388
  result[model_id] = {
338
389
  "type": model["model_type"],
339
390
  "capabilities": capabilities,
340
- "metadata": json.loads(model["metadata"]) if model["metadata"] else {},
391
+ "metadata": _parse_metadata(model["metadata"]),
341
392
  "created_at": model["created_at"],
342
393
  "updated_at": model["updated_at"]
343
394
  }
344
-
395
+
345
396
  return result
346
-
397
+
347
398
  except Exception as e:
348
399
  logger.error(f"Failed to search models with query '{query}': {e}")
349
- return {}
400
+ return {}
401
+
402
+
403
+ class ModelRepo:
404
+ """Compatibility wrapper for unified API"""
405
+
406
+ def __init__(self):
407
+ self.registry = ModelRegistry()
408
+
409
+ def get_model_by_id(self, model_id: str):
410
+ """Get model by ID - returns a simple object with basic properties"""
411
+ info = self.registry.get_model_info(model_id)
412
+ if not info:
413
+ return None
414
+
415
+ # Return a simple object that has the expected properties
416
+ class ModelObject:
417
+ def __init__(self, data):
418
+ self.model_id = data["model_id"]
419
+ self.model_type = data["type"]
420
+ self.provider = data["metadata"].get("provider", "unknown")
421
+ self.metadata = data["metadata"]
422
+ self.capabilities = data["capabilities"]
423
+ self.created_at = datetime.fromisoformat(data["created_at"]) if data["created_at"] else None
424
+ self.updated_at = datetime.fromisoformat(data["updated_at"]) if data["updated_at"] else None
425
+
426
+ return ModelObject(info)
427
+
428
+ def update_model_metadata(self, model_id: str, metadata_updates: Dict[str, Any], updated_by: str = None):
429
+ """Update model metadata - simplified implementation"""
430
+ # Get existing model
431
+ info = self.registry.get_model_info(model_id)
432
+ if not info:
433
+ return False
434
+
435
+ # Merge metadata
436
+ new_metadata = info["metadata"].copy()
437
+ new_metadata.update(metadata_updates)
438
+
439
+ # Update via re-registration (simplified)
440
+ capabilities = [ModelCapability(cap) for cap in info["capabilities"] if cap in [c.value for c in ModelCapability]]
441
+ model_type = ModelType(info["type"])
442
+
443
+ return self.registry.register_model(
444
+ model_id=model_id,
445
+ model_type=model_type,
446
+ capabilities=capabilities,
447
+ metadata=new_metadata,
448
+ provider=info["metadata"].get("provider")
449
+ )
450
+
451
+ def search_models(self, query: str, model_type: str = None, provider: str = None, capabilities: List[str] = None, limit: int = 50):
452
+ """Search models with filters"""
453
+ results = self.registry.search_models(query)
454
+
455
+ # Apply filters
456
+ if model_type:
457
+ results = {k: v for k, v in results.items() if v["type"] == model_type}
458
+
459
+ if provider:
460
+ results = {k: v for k, v in results.items() if v["metadata"].get("provider") == provider}
461
+
462
+ if capabilities:
463
+ results = {k: v for k, v in results.items() if any(cap in v["capabilities"] for cap in capabilities)}
464
+
465
+ # Convert to expected format
466
+ final_results = []
467
+ for model_id, data in list(results.items())[:limit]:
468
+ class ModelObject:
469
+ def __init__(self, model_id, data):
470
+ self.model_id = model_id
471
+ self.model_type = data["type"]
472
+ self.provider = data["metadata"].get("provider", "unknown")
473
+ self.capabilities = data["capabilities"]
474
+ self.metadata = data["metadata"]
475
+ self.updated_at = datetime.fromisoformat(data["updated_at"]) if data["updated_at"] else None
476
+
477
+ final_results.append(ModelObject(model_id, data))
478
+
479
+ return final_results
480
+
481
+ def get_providers_summary(self):
482
+ """Get summary of available providers"""
483
+ models = self.registry.list_models()
484
+ providers = {}
485
+
486
+ for model_id, data in models.items():
487
+ provider = data["metadata"].get("provider", "unknown")
488
+ if provider not in providers:
489
+ providers[provider] = {
490
+ "provider": provider,
491
+ "model_count": 0,
492
+ "model_types": set(),
493
+ "capabilities": set()
494
+ }
495
+
496
+ providers[provider]["model_count"] += 1
497
+ providers[provider]["model_types"].add(data["type"])
498
+ providers[provider]["capabilities"].update(data["capabilities"])
499
+
500
+ # Convert sets to lists for JSON serialization
501
+ for provider_data in providers.values():
502
+ provider_data["model_types"] = list(provider_data["model_types"])
503
+ provider_data["capabilities"] = list(provider_data["capabilities"])
504
+
505
+ return list(providers.values())