django-cfg 1.3.5__py3-none-any.whl → 1.3.9__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 (252) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/admin/__init__.py +24 -8
  3. django_cfg/apps/accounts/admin/activity_admin.py +146 -0
  4. django_cfg/apps/accounts/admin/filters.py +98 -22
  5. django_cfg/apps/accounts/admin/group_admin.py +86 -0
  6. django_cfg/apps/accounts/admin/inlines.py +42 -13
  7. django_cfg/apps/accounts/admin/otp_admin.py +115 -0
  8. django_cfg/apps/accounts/admin/registration_admin.py +173 -0
  9. django_cfg/apps/accounts/admin/resources.py +123 -19
  10. django_cfg/apps/accounts/admin/twilio_admin.py +327 -0
  11. django_cfg/apps/accounts/admin/user_admin.py +362 -0
  12. django_cfg/apps/agents/admin/__init__.py +17 -4
  13. django_cfg/apps/agents/admin/execution_admin.py +204 -183
  14. django_cfg/apps/agents/admin/registry_admin.py +230 -255
  15. django_cfg/apps/agents/admin/toolsets_admin.py +274 -321
  16. django_cfg/apps/agents/core/__init__.py +1 -1
  17. django_cfg/apps/agents/core/django_agent.py +221 -0
  18. django_cfg/apps/agents/core/exceptions.py +14 -0
  19. django_cfg/apps/agents/core/orchestrator.py +18 -3
  20. django_cfg/apps/knowbase/admin/__init__.py +1 -1
  21. django_cfg/apps/knowbase/admin/archive_admin.py +352 -640
  22. django_cfg/apps/knowbase/admin/chat_admin.py +258 -192
  23. django_cfg/apps/knowbase/admin/document_admin.py +269 -262
  24. django_cfg/apps/knowbase/admin/external_data_admin.py +271 -489
  25. django_cfg/apps/knowbase/config/settings.py +21 -4
  26. django_cfg/apps/knowbase/views/chat_views.py +3 -0
  27. django_cfg/apps/leads/admin/__init__.py +3 -1
  28. django_cfg/apps/leads/admin/leads_admin.py +235 -35
  29. django_cfg/apps/maintenance/admin/__init__.py +2 -2
  30. django_cfg/apps/maintenance/admin/api_key_admin.py +125 -63
  31. django_cfg/apps/maintenance/admin/log_admin.py +143 -61
  32. django_cfg/apps/maintenance/admin/scheduled_admin.py +212 -301
  33. django_cfg/apps/maintenance/admin/site_admin.py +213 -352
  34. django_cfg/apps/newsletter/admin/__init__.py +29 -2
  35. django_cfg/apps/newsletter/admin/newsletter_admin.py +531 -193
  36. django_cfg/apps/payments/admin/__init__.py +18 -27
  37. django_cfg/apps/payments/admin/api_keys_admin.py +179 -546
  38. django_cfg/apps/payments/admin/balance_admin.py +166 -632
  39. django_cfg/apps/payments/admin/currencies_admin.py +235 -607
  40. django_cfg/apps/payments/admin/endpoint_groups_admin.py +127 -0
  41. django_cfg/apps/payments/admin/filters.py +83 -3
  42. django_cfg/apps/payments/admin/networks_admin.py +258 -0
  43. django_cfg/apps/payments/admin/payments_admin.py +171 -461
  44. django_cfg/apps/payments/admin/subscriptions_admin.py +119 -636
  45. django_cfg/apps/payments/admin/tariffs_admin.py +248 -0
  46. django_cfg/apps/payments/admin_interface/serializers/payment_serializers.py +105 -34
  47. django_cfg/apps/payments/admin_interface/templates/payments/payment_form.html +12 -16
  48. django_cfg/apps/payments/admin_interface/views/__init__.py +2 -0
  49. django_cfg/apps/payments/admin_interface/views/api/webhook_admin.py +13 -18
  50. django_cfg/apps/payments/management/commands/manage_currencies.py +236 -274
  51. django_cfg/apps/payments/management/commands/manage_providers.py +4 -1
  52. django_cfg/apps/payments/middleware/api_access.py +32 -6
  53. django_cfg/apps/payments/migrations/0002_currency_usd_rate_currency_usd_rate_updated_at.py +26 -0
  54. django_cfg/apps/payments/migrations/0003_remove_provider_currency_fields.py +28 -0
  55. django_cfg/apps/payments/migrations/0004_add_reserved_usd_field.py +30 -0
  56. django_cfg/apps/payments/models/balance.py +12 -0
  57. django_cfg/apps/payments/models/currencies.py +106 -32
  58. django_cfg/apps/payments/models/managers/currency_managers.py +65 -0
  59. django_cfg/apps/payments/services/core/currency_service.py +35 -28
  60. django_cfg/apps/payments/services/core/payment_service.py +1 -1
  61. django_cfg/apps/payments/services/providers/__init__.py +3 -0
  62. django_cfg/apps/payments/services/providers/base.py +95 -39
  63. django_cfg/apps/payments/services/providers/models/__init__.py +40 -0
  64. django_cfg/apps/payments/services/providers/models/base.py +122 -0
  65. django_cfg/apps/payments/services/providers/models/providers.py +87 -0
  66. django_cfg/apps/payments/services/providers/models/universal.py +48 -0
  67. django_cfg/apps/payments/services/providers/nowpayments/__init__.py +31 -0
  68. django_cfg/apps/payments/services/providers/nowpayments/config.py +70 -0
  69. django_cfg/apps/payments/services/providers/nowpayments/models.py +150 -0
  70. django_cfg/apps/payments/services/providers/nowpayments/parsers.py +879 -0
  71. django_cfg/apps/payments/services/providers/{nowpayments.py → nowpayments/provider.py} +240 -209
  72. django_cfg/apps/payments/services/providers/nowpayments/sync.py +196 -0
  73. django_cfg/apps/payments/services/providers/registry.py +4 -32
  74. django_cfg/apps/payments/services/providers/sync_service.py +277 -0
  75. django_cfg/apps/payments/static/payments/js/api-client.js +23 -5
  76. django_cfg/apps/payments/static/payments/js/payment-form.js +65 -8
  77. django_cfg/apps/payments/tasks/__init__.py +39 -0
  78. django_cfg/apps/payments/tasks/types.py +73 -0
  79. django_cfg/apps/payments/tasks/usage_tracking.py +308 -0
  80. django_cfg/apps/payments/templates/admin/payments/_components/dashboard_header.html +23 -0
  81. django_cfg/apps/payments/templates/admin/payments/_components/stats_card.html +25 -0
  82. django_cfg/apps/payments/templates/admin/payments/_components/stats_grid.html +16 -0
  83. django_cfg/apps/payments/templates/admin/payments/apikey/change_list.html +39 -0
  84. django_cfg/apps/payments/templates/admin/payments/balance/change_list.html +50 -0
  85. django_cfg/apps/payments/templates/admin/payments/currency/change_list.html +40 -0
  86. django_cfg/apps/payments/templates/admin/payments/payment/change_list.html +48 -0
  87. django_cfg/apps/payments/templates/admin/payments/subscription/change_list.html +48 -0
  88. django_cfg/apps/payments/urls_admin.py +1 -1
  89. django_cfg/apps/payments/views/api/currencies.py +5 -5
  90. django_cfg/apps/payments/views/overview/services.py +2 -2
  91. django_cfg/apps/payments/views/serializers/currencies.py +4 -3
  92. django_cfg/apps/support/admin/__init__.py +10 -1
  93. django_cfg/apps/support/admin/support_admin.py +338 -141
  94. django_cfg/apps/tasks/admin/__init__.py +11 -0
  95. django_cfg/apps/tasks/admin/tasks_admin.py +430 -0
  96. django_cfg/apps/urls.py +1 -2
  97. django_cfg/config.py +1 -1
  98. django_cfg/core/config.py +10 -5
  99. django_cfg/core/generation.py +1 -1
  100. django_cfg/management/commands/__init__.py +13 -1
  101. django_cfg/management/commands/app_agent_diagnose.py +470 -0
  102. django_cfg/management/commands/app_agent_generate.py +342 -0
  103. django_cfg/management/commands/app_agent_info.py +308 -0
  104. django_cfg/management/commands/migrate_all.py +9 -3
  105. django_cfg/management/commands/migrator.py +11 -6
  106. django_cfg/management/commands/rundramatiq.py +3 -2
  107. django_cfg/middleware/__init__.py +0 -2
  108. django_cfg/models/api_keys.py +115 -0
  109. django_cfg/modules/django_admin/__init__.py +64 -0
  110. django_cfg/modules/django_admin/decorators/__init__.py +13 -0
  111. django_cfg/modules/django_admin/decorators/actions.py +106 -0
  112. django_cfg/modules/django_admin/decorators/display.py +106 -0
  113. django_cfg/modules/django_admin/mixins/__init__.py +14 -0
  114. django_cfg/modules/django_admin/mixins/display_mixin.py +81 -0
  115. django_cfg/modules/django_admin/mixins/optimization_mixin.py +41 -0
  116. django_cfg/modules/django_admin/mixins/standalone_actions_mixin.py +202 -0
  117. django_cfg/modules/django_admin/models/__init__.py +20 -0
  118. django_cfg/modules/django_admin/models/action_models.py +33 -0
  119. django_cfg/modules/django_admin/models/badge_models.py +20 -0
  120. django_cfg/modules/django_admin/models/base.py +26 -0
  121. django_cfg/modules/django_admin/models/display_models.py +31 -0
  122. django_cfg/modules/django_admin/utils/badges.py +159 -0
  123. django_cfg/modules/django_admin/utils/displays.py +247 -0
  124. django_cfg/modules/django_app_agent/__init__.py +87 -0
  125. django_cfg/modules/django_app_agent/agents/__init__.py +40 -0
  126. django_cfg/modules/django_app_agent/agents/base/__init__.py +24 -0
  127. django_cfg/modules/django_app_agent/agents/base/agent.py +354 -0
  128. django_cfg/modules/django_app_agent/agents/base/context.py +236 -0
  129. django_cfg/modules/django_app_agent/agents/base/executor.py +430 -0
  130. django_cfg/modules/django_app_agent/agents/generation/__init__.py +12 -0
  131. django_cfg/modules/django_app_agent/agents/generation/app_generator/__init__.py +15 -0
  132. django_cfg/modules/django_app_agent/agents/generation/app_generator/config_validator.py +147 -0
  133. django_cfg/modules/django_app_agent/agents/generation/app_generator/main.py +99 -0
  134. django_cfg/modules/django_app_agent/agents/generation/app_generator/models.py +32 -0
  135. django_cfg/modules/django_app_agent/agents/generation/app_generator/prompt_manager.py +290 -0
  136. django_cfg/modules/django_app_agent/agents/interfaces.py +376 -0
  137. django_cfg/modules/django_app_agent/core/__init__.py +33 -0
  138. django_cfg/modules/django_app_agent/core/config.py +300 -0
  139. django_cfg/modules/django_app_agent/core/exceptions.py +359 -0
  140. django_cfg/modules/django_app_agent/models/__init__.py +71 -0
  141. django_cfg/modules/django_app_agent/models/base.py +283 -0
  142. django_cfg/modules/django_app_agent/models/context.py +496 -0
  143. django_cfg/modules/django_app_agent/models/enums.py +481 -0
  144. django_cfg/modules/django_app_agent/models/requests.py +500 -0
  145. django_cfg/modules/django_app_agent/models/responses.py +585 -0
  146. django_cfg/modules/django_app_agent/pytest.ini +6 -0
  147. django_cfg/modules/django_app_agent/services/__init__.py +42 -0
  148. django_cfg/modules/django_app_agent/services/app_generator/__init__.py +30 -0
  149. django_cfg/modules/django_app_agent/services/app_generator/ai_integration.py +133 -0
  150. django_cfg/modules/django_app_agent/services/app_generator/context.py +40 -0
  151. django_cfg/modules/django_app_agent/services/app_generator/main.py +202 -0
  152. django_cfg/modules/django_app_agent/services/app_generator/structure.py +316 -0
  153. django_cfg/modules/django_app_agent/services/app_generator/validation.py +125 -0
  154. django_cfg/modules/django_app_agent/services/base.py +437 -0
  155. django_cfg/modules/django_app_agent/services/context_builder/__init__.py +34 -0
  156. django_cfg/modules/django_app_agent/services/context_builder/code_extractor.py +141 -0
  157. django_cfg/modules/django_app_agent/services/context_builder/context_generator.py +276 -0
  158. django_cfg/modules/django_app_agent/services/context_builder/main.py +272 -0
  159. django_cfg/modules/django_app_agent/services/context_builder/models.py +40 -0
  160. django_cfg/modules/django_app_agent/services/context_builder/pattern_analyzer.py +85 -0
  161. django_cfg/modules/django_app_agent/services/project_scanner/__init__.py +31 -0
  162. django_cfg/modules/django_app_agent/services/project_scanner/app_discovery.py +311 -0
  163. django_cfg/modules/django_app_agent/services/project_scanner/main.py +221 -0
  164. django_cfg/modules/django_app_agent/services/project_scanner/models.py +59 -0
  165. django_cfg/modules/django_app_agent/services/project_scanner/pattern_detection.py +94 -0
  166. django_cfg/modules/django_app_agent/services/questioning_service/__init__.py +28 -0
  167. django_cfg/modules/django_app_agent/services/questioning_service/main.py +273 -0
  168. django_cfg/modules/django_app_agent/services/questioning_service/models.py +111 -0
  169. django_cfg/modules/django_app_agent/services/questioning_service/question_generator.py +251 -0
  170. django_cfg/modules/django_app_agent/services/questioning_service/response_processor.py +347 -0
  171. django_cfg/modules/django_app_agent/services/questioning_service/session_manager.py +356 -0
  172. django_cfg/modules/django_app_agent/services/report_service.py +332 -0
  173. django_cfg/modules/django_app_agent/services/template_manager/__init__.py +18 -0
  174. django_cfg/modules/django_app_agent/services/template_manager/jinja_engine.py +236 -0
  175. django_cfg/modules/django_app_agent/services/template_manager/main.py +159 -0
  176. django_cfg/modules/django_app_agent/services/template_manager/models.py +36 -0
  177. django_cfg/modules/django_app_agent/services/template_manager/template_loader.py +100 -0
  178. django_cfg/modules/django_app_agent/services/template_manager/templates/admin.py.j2 +105 -0
  179. django_cfg/modules/django_app_agent/services/template_manager/templates/apps.py.j2 +31 -0
  180. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_config.py.j2 +44 -0
  181. django_cfg/modules/django_app_agent/services/template_manager/templates/cfg_module.py.j2 +81 -0
  182. django_cfg/modules/django_app_agent/services/template_manager/templates/forms.py.j2 +107 -0
  183. django_cfg/modules/django_app_agent/services/template_manager/templates/models.py.j2 +139 -0
  184. django_cfg/modules/django_app_agent/services/template_manager/templates/serializers.py.j2 +91 -0
  185. django_cfg/modules/django_app_agent/services/template_manager/templates/tests.py.j2 +195 -0
  186. django_cfg/modules/django_app_agent/services/template_manager/templates/urls.py.j2 +35 -0
  187. django_cfg/modules/django_app_agent/services/template_manager/templates/views.py.j2 +211 -0
  188. django_cfg/modules/django_app_agent/services/template_manager/variable_processor.py +200 -0
  189. django_cfg/modules/django_app_agent/services/validation_service/__init__.py +25 -0
  190. django_cfg/modules/django_app_agent/services/validation_service/django_validator.py +333 -0
  191. django_cfg/modules/django_app_agent/services/validation_service/main.py +242 -0
  192. django_cfg/modules/django_app_agent/services/validation_service/models.py +66 -0
  193. django_cfg/modules/django_app_agent/services/validation_service/quality_validator.py +352 -0
  194. django_cfg/modules/django_app_agent/services/validation_service/security_validator.py +272 -0
  195. django_cfg/modules/django_app_agent/services/validation_service/syntax_validator.py +203 -0
  196. django_cfg/modules/django_app_agent/ui/__init__.py +25 -0
  197. django_cfg/modules/django_app_agent/ui/cli.py +419 -0
  198. django_cfg/modules/django_app_agent/ui/rich_components.py +622 -0
  199. django_cfg/modules/django_app_agent/utils/__init__.py +38 -0
  200. django_cfg/modules/django_app_agent/utils/logging.py +360 -0
  201. django_cfg/modules/django_app_agent/utils/validation.py +417 -0
  202. django_cfg/modules/django_currency/__init__.py +2 -2
  203. django_cfg/modules/django_currency/clients/__init__.py +2 -2
  204. django_cfg/modules/django_currency/clients/hybrid_client.py +587 -0
  205. django_cfg/modules/django_currency/core/converter.py +12 -12
  206. django_cfg/modules/django_currency/database/__init__.py +2 -2
  207. django_cfg/modules/django_currency/database/database_loader.py +93 -42
  208. django_cfg/modules/django_llm/llm/client.py +10 -2
  209. django_cfg/modules/django_unfold/callbacks/actions.py +1 -1
  210. django_cfg/modules/django_unfold/callbacks/statistics.py +1 -1
  211. django_cfg/modules/django_unfold/dashboard.py +14 -13
  212. django_cfg/modules/django_unfold/models/config.py +1 -1
  213. django_cfg/registry/core.py +3 -0
  214. django_cfg/registry/third_party.py +2 -2
  215. django_cfg/template_archive/django_sample.zip +0 -0
  216. {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/METADATA +2 -1
  217. {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/RECORD +224 -118
  218. django_cfg/apps/accounts/admin/activity.py +0 -96
  219. django_cfg/apps/accounts/admin/group.py +0 -17
  220. django_cfg/apps/accounts/admin/otp.py +0 -59
  221. django_cfg/apps/accounts/admin/registration_source.py +0 -97
  222. django_cfg/apps/accounts/admin/twilio_response.py +0 -227
  223. django_cfg/apps/accounts/admin/user.py +0 -300
  224. django_cfg/apps/agents/core/agent.py +0 -281
  225. django_cfg/apps/payments/admin_interface/old/payments/base.html +0 -175
  226. django_cfg/apps/payments/admin_interface/old/payments/components/dev_tool_card.html +0 -125
  227. django_cfg/apps/payments/admin_interface/old/payments/components/loading_spinner.html +0 -16
  228. django_cfg/apps/payments/admin_interface/old/payments/components/ngrok_status_card.html +0 -113
  229. django_cfg/apps/payments/admin_interface/old/payments/components/notification.html +0 -27
  230. django_cfg/apps/payments/admin_interface/old/payments/components/provider_card.html +0 -86
  231. django_cfg/apps/payments/admin_interface/old/payments/components/status_card.html +0 -35
  232. django_cfg/apps/payments/admin_interface/old/payments/currency_converter.html +0 -382
  233. django_cfg/apps/payments/admin_interface/old/payments/payment_dashboard.html +0 -309
  234. django_cfg/apps/payments/admin_interface/old/payments/payment_form.html +0 -303
  235. django_cfg/apps/payments/admin_interface/old/payments/payment_list.html +0 -382
  236. django_cfg/apps/payments/admin_interface/old/payments/payment_status.html +0 -500
  237. django_cfg/apps/payments/admin_interface/old/payments/webhook_dashboard.html +0 -518
  238. django_cfg/apps/payments/admin_interface/old/static/payments/css/components.css +0 -619
  239. django_cfg/apps/payments/admin_interface/old/static/payments/css/dashboard.css +0 -188
  240. django_cfg/apps/payments/admin_interface/old/static/payments/js/components.js +0 -545
  241. django_cfg/apps/payments/admin_interface/old/static/payments/js/ngrok-status.js +0 -163
  242. django_cfg/apps/payments/admin_interface/old/static/payments/js/utils.js +0 -412
  243. django_cfg/apps/tasks/admin.py +0 -320
  244. django_cfg/middleware/static_nocache.py +0 -55
  245. django_cfg/modules/django_currency/clients/yahoo_client.py +0 -157
  246. /django_cfg/modules/{django_unfold → django_admin}/icons/README.md +0 -0
  247. /django_cfg/modules/{django_unfold → django_admin}/icons/__init__.py +0 -0
  248. /django_cfg/modules/{django_unfold → django_admin}/icons/constants.py +0 -0
  249. /django_cfg/modules/{django_unfold → django_admin}/icons/generate_icons.py +0 -0
  250. {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/WHEEL +0 -0
  251. {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/entry_points.txt +0 -0
  252. {django_cfg-1.3.5.dist-info → django_cfg-1.3.9.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,300 @@
1
+ """
2
+ Configuration management for Django App Agent Module.
3
+
4
+ This module provides type-safe configuration management with:
5
+ - Integration with django-cfg BaseCfgModule
6
+ - Pydantic 2 models for all configuration
7
+ - Environment variable support
8
+ - Validation and default values
9
+ - AI model configuration
10
+ """
11
+
12
+ from typing import Optional, Dict, Any, List, Literal
13
+ from pathlib import Path
14
+ from pydantic import BaseModel, Field, ConfigDict, field_validator
15
+ from enum import Enum
16
+
17
+ from django_cfg.modules.base import BaseCfgModule
18
+ from .exceptions import ConfigurationError
19
+
20
+
21
+ class LogLevel(str, Enum):
22
+ """Logging levels."""
23
+ DEBUG = "DEBUG"
24
+ INFO = "INFO"
25
+ WARNING = "WARNING"
26
+ ERROR = "ERROR"
27
+ CRITICAL = "CRITICAL"
28
+
29
+
30
+ class AIProvider(str, Enum):
31
+ """AI service providers."""
32
+ OPENAI = "openai"
33
+ ANTHROPIC = "anthropic"
34
+ OPENROUTER = "openrouter"
35
+
36
+
37
+ class ModelTier(str, Enum):
38
+ """AI model performance tiers."""
39
+ FAST = "fast" # Fast, cheaper models for simple tasks
40
+ BALANCED = "balanced" # Balanced performance and cost
41
+ PREMIUM = "premium" # Best quality, higher cost
42
+
43
+
44
+ class ModelConfig(BaseModel):
45
+ """Configuration for AI models."""
46
+
47
+ model_config = ConfigDict(
48
+ extra='forbid',
49
+ validate_assignment=True,
50
+ str_strip_whitespace=True
51
+ )
52
+
53
+ provider: AIProvider = Field(description="AI service provider")
54
+ model_id: str = Field(description="Model identifier")
55
+ tier: ModelTier = Field(description="Model performance tier")
56
+ max_tokens: int = Field(gt=0, le=200000, description="Maximum tokens per request")
57
+ temperature: float = Field(ge=0.0, le=2.0, default=0.1, description="Model temperature")
58
+ timeout_seconds: float = Field(gt=0, default=300.0, description="Request timeout")
59
+
60
+ @field_validator('model_id')
61
+ @classmethod
62
+ def validate_model_id(cls, v: str) -> str:
63
+ """Validate model ID format."""
64
+ if not v or len(v.strip()) == 0:
65
+ raise ValueError("Model ID cannot be empty")
66
+ return v.strip()
67
+
68
+
69
+ class APIKeyConfig(BaseModel):
70
+ """API key configuration."""
71
+
72
+ model_config = ConfigDict(
73
+ extra='forbid',
74
+ validate_assignment=True,
75
+ str_strip_whitespace=True
76
+ )
77
+
78
+ openai: Optional[str] = Field(default=None, description="OpenAI API key")
79
+ anthropic: Optional[str] = Field(default=None, description="Anthropic API key")
80
+ openrouter: Optional[str] = Field(default=None, description="OpenRouter API key")
81
+
82
+ def get_key(self, provider: AIProvider) -> Optional[str]:
83
+ """Get API key for provider."""
84
+ return getattr(self, provider.value, None)
85
+
86
+ def has_key(self, provider: AIProvider) -> bool:
87
+ """Check if API key exists for provider."""
88
+ key = self.get_key(provider)
89
+ return key is not None and len(key.strip()) > 0
90
+
91
+
92
+ class UIConfig(BaseModel):
93
+ """User interface configuration."""
94
+
95
+ model_config = ConfigDict(
96
+ extra='forbid',
97
+ validate_assignment=True
98
+ )
99
+
100
+ enable_rich_interface: bool = Field(default=True, description="Enable Rich CLI interface")
101
+ show_progress_bars: bool = Field(default=True, description="Show progress bars")
102
+ enable_colors: bool = Field(default=True, description="Enable colored output")
103
+ verbose_output: bool = Field(default=False, description="Enable verbose output")
104
+ max_console_width: int = Field(gt=40, le=200, default=120, description="Maximum console width")
105
+
106
+
107
+ class GenerationConfig(BaseModel):
108
+ """Code generation configuration."""
109
+
110
+ model_config = ConfigDict(
111
+ extra='forbid',
112
+ validate_assignment=True
113
+ )
114
+
115
+ max_questions: int = Field(gt=0, le=50, default=20, description="Maximum questions to ask")
116
+ questioning_timeout_minutes: int = Field(gt=0, le=60, default=15, description="Questioning timeout")
117
+ quality_threshold: float = Field(ge=0.0, le=10.0, default=8.0, description="Minimum quality score")
118
+ enable_caching: bool = Field(default=True, description="Enable response caching")
119
+ cache_ttl_seconds: int = Field(gt=0, default=3600, description="Cache TTL in seconds")
120
+ max_concurrent_generations: int = Field(gt=0, le=10, default=3, description="Max concurrent generations")
121
+
122
+ @field_validator('quality_threshold')
123
+ @classmethod
124
+ def validate_quality_threshold(cls, v: float) -> float:
125
+ """Validate quality threshold is reasonable."""
126
+ if v < 5.0:
127
+ raise ValueError("Quality threshold should be at least 5.0 for production use")
128
+ return v
129
+
130
+
131
+ class AgentConfig(BaseModel):
132
+ """Django App Agent Module configuration."""
133
+
134
+ model_config = ConfigDict(
135
+ extra='forbid',
136
+ validate_assignment=True,
137
+ str_strip_whitespace=True
138
+ )
139
+
140
+ # Core settings
141
+ module_name: str = Field(default="django_app_agent", description="Module name")
142
+ version: str = Field(default="0.1.0", description="Module version")
143
+ debug_mode: bool = Field(default=False, description="Enable debug mode")
144
+ log_level: LogLevel = Field(default=LogLevel.INFO, description="Logging level")
145
+
146
+ # API configuration
147
+ api_keys: APIKeyConfig = Field(default_factory=APIKeyConfig, description="API keys")
148
+ preferred_models: Dict[str, ModelConfig] = Field(
149
+ default_factory=dict,
150
+ description="Preferred models for different tasks"
151
+ )
152
+
153
+ # UI configuration
154
+ ui: UIConfig = Field(default_factory=UIConfig, description="UI settings")
155
+
156
+ # Generation configuration
157
+ generation: GenerationConfig = Field(default_factory=GenerationConfig, description="Generation settings")
158
+
159
+ # File paths
160
+ output_directory: Optional[Path] = Field(default=None, description="Default output directory")
161
+ template_directory: Optional[Path] = Field(default=None, description="Template directory")
162
+ cache_directory: Optional[Path] = Field(default=None, description="Cache directory")
163
+
164
+ @classmethod
165
+ def from_django_cfg(cls) -> "AgentConfig":
166
+ """Load configuration from django-cfg."""
167
+ try:
168
+ cfg_module = BaseCfgModule()
169
+ django_cfg_config = cfg_module.get_config()
170
+
171
+ # Extract relevant configuration
172
+ config_data: Dict[str, Any] = {}
173
+
174
+ # API keys - extract string values from SecretStr
175
+ if hasattr(django_cfg_config, 'api_keys'):
176
+ api_keys_data = {}
177
+ if hasattr(django_cfg_config.api_keys, 'openai') and django_cfg_config.api_keys.openai:
178
+ # Extract string value from SecretStr if needed
179
+ openai_key = django_cfg_config.api_keys.openai
180
+ api_keys_data['openai'] = str(openai_key) if hasattr(openai_key, 'get_secret_value') else openai_key
181
+ if hasattr(django_cfg_config.api_keys, 'anthropic') and django_cfg_config.api_keys.anthropic:
182
+ # Extract string value from SecretStr if needed
183
+ anthropic_key = django_cfg_config.api_keys.anthropic
184
+ api_keys_data['anthropic'] = str(anthropic_key) if hasattr(anthropic_key, 'get_secret_value') else anthropic_key
185
+ if hasattr(django_cfg_config.api_keys, 'openrouter') and django_cfg_config.api_keys.openrouter:
186
+ # Extract string value from SecretStr if needed
187
+ openrouter_key = django_cfg_config.api_keys.openrouter
188
+ api_keys_data['openrouter'] = str(openrouter_key) if hasattr(openrouter_key, 'get_secret_value') else openrouter_key
189
+
190
+ config_data['api_keys'] = api_keys_data
191
+
192
+ # Agent-specific settings
193
+ if hasattr(django_cfg_config, 'agents') and django_cfg_config.agents:
194
+ agent_config = django_cfg_config.agents
195
+
196
+ if hasattr(agent_config, 'debug_mode'):
197
+ config_data['debug_mode'] = agent_config.debug_mode
198
+
199
+ if hasattr(agent_config, 'max_questions'):
200
+ config_data['generation'] = config_data.get('generation', {})
201
+ config_data['generation']['max_questions'] = agent_config.max_questions
202
+
203
+ if hasattr(agent_config, 'quality_threshold'):
204
+ config_data['generation'] = config_data.get('generation', {})
205
+ config_data['generation']['quality_threshold'] = agent_config.quality_threshold
206
+
207
+ return cls(**config_data)
208
+
209
+ except Exception as e:
210
+ raise ConfigurationError(
211
+ f"Failed to load configuration from django-cfg: {e}",
212
+ cause=e
213
+ )
214
+
215
+ def get_api_key(self, provider: AIProvider) -> Optional[str]:
216
+ """Get API key for provider."""
217
+ return self.api_keys.get_key(provider)
218
+
219
+ def has_api_key(self, provider: AIProvider) -> bool:
220
+ """Check if API key exists for provider."""
221
+ return self.api_keys.has_key(provider)
222
+
223
+ def get_model_config(self, task_type: str) -> Optional[ModelConfig]:
224
+ """Get model configuration for task type."""
225
+ return self.preferred_models.get(task_type)
226
+
227
+ def validate_configuration(self) -> List[str]:
228
+ """Validate configuration and return list of issues."""
229
+ issues: List[str] = []
230
+
231
+ # Check API keys
232
+ if not any(self.api_keys.has_key(provider) for provider in AIProvider):
233
+ issues.append("No API keys configured for any AI provider")
234
+
235
+ # Check directories
236
+ if self.output_directory and not self.output_directory.exists():
237
+ issues.append(f"Output directory does not exist: {self.output_directory}")
238
+
239
+ if self.template_directory and not self.template_directory.exists():
240
+ issues.append(f"Template directory does not exist: {self.template_directory}")
241
+
242
+ # Check model configurations
243
+ for task_type, model_config in self.preferred_models.items():
244
+ if not self.has_api_key(model_config.provider):
245
+ issues.append(f"No API key for {model_config.provider} (required for {task_type})")
246
+
247
+ return issues
248
+
249
+
250
+ # Default model configurations
251
+ DEFAULT_MODELS: Dict[str, ModelConfig] = {
252
+ "generation": ModelConfig(
253
+ provider=AIProvider.OPENROUTER,
254
+ model_id="anthropic/claude-3-haiku",
255
+ tier=ModelTier.BALANCED,
256
+ max_tokens=100000,
257
+ temperature=0.1,
258
+ timeout_seconds=300.0
259
+ ),
260
+ "analysis": ModelConfig(
261
+ provider=AIProvider.OPENROUTER,
262
+ model_id="openai/gpt-4o-mini",
263
+ tier=ModelTier.FAST,
264
+ max_tokens=50000,
265
+ temperature=0.0,
266
+ timeout_seconds=180.0
267
+ ),
268
+ "validation": ModelConfig(
269
+ provider=AIProvider.OPENROUTER,
270
+ model_id="anthropic/claude-3-haiku",
271
+ tier=ModelTier.FAST,
272
+ max_tokens=30000,
273
+ temperature=0.0,
274
+ timeout_seconds=120.0
275
+ ),
276
+ "dialogue": ModelConfig(
277
+ provider=AIProvider.OPENROUTER,
278
+ model_id="openai/gpt-4o-mini",
279
+ tier=ModelTier.FAST,
280
+ max_tokens=20000,
281
+ temperature=0.2,
282
+ timeout_seconds=60.0
283
+ )
284
+ }
285
+
286
+
287
+ def get_default_config() -> AgentConfig:
288
+ """Get default configuration with sensible defaults."""
289
+ return AgentConfig(
290
+ preferred_models=DEFAULT_MODELS.copy()
291
+ )
292
+
293
+
294
+ def load_config() -> AgentConfig:
295
+ """Load configuration from django-cfg or use defaults."""
296
+ try:
297
+ return AgentConfig.from_django_cfg()
298
+ except ConfigurationError:
299
+ # Fall back to default configuration
300
+ return get_default_config()
@@ -0,0 +1,359 @@
1
+ """
2
+ Exception hierarchy for Django App Agent Module.
3
+
4
+ This module defines a comprehensive exception hierarchy following best practices:
5
+ - Clear inheritance structure
6
+ - Contextual error information
7
+ - Structured error data with Pydantic models
8
+ - Support for error recovery and retry logic
9
+ """
10
+
11
+ from typing import Optional, Dict, Any, List
12
+ from pathlib import Path
13
+ from pydantic import BaseModel, Field, ConfigDict
14
+
15
+
16
+ class ErrorContext(BaseModel):
17
+ """Context information for errors."""
18
+
19
+ model_config = ConfigDict(
20
+ extra='forbid',
21
+ validate_assignment=True,
22
+ str_strip_whitespace=True
23
+ )
24
+
25
+ operation: str = Field(description="Operation that caused the error")
26
+ component: str = Field(description="Component where error occurred")
27
+ timestamp: str = Field(description="Error timestamp")
28
+ correlation_id: Optional[str] = Field(default=None, description="Correlation ID for tracing")
29
+ additional_data: Dict[str, Any] = Field(default_factory=dict, description="Additional error context")
30
+
31
+
32
+ class DjangoAppAgentError(Exception):
33
+ """Base exception for all Django App Agent Module errors."""
34
+
35
+ def __init__(
36
+ self,
37
+ message: str,
38
+ *,
39
+ error_code: Optional[str] = None,
40
+ context: Optional[ErrorContext] = None,
41
+ cause: Optional[Exception] = None,
42
+ recoverable: bool = False
43
+ ) -> None:
44
+ """Initialize Django App Agent error.
45
+
46
+ Args:
47
+ message: Human-readable error message
48
+ error_code: Machine-readable error code
49
+ context: Error context information
50
+ cause: Original exception that caused this error
51
+ recoverable: Whether this error can be recovered from
52
+ """
53
+ super().__init__(message)
54
+ self.message = message
55
+ self.error_code = error_code or self.__class__.__name__
56
+ self.context = context
57
+ self.cause = cause
58
+ self.recoverable = recoverable
59
+
60
+ def __str__(self) -> str:
61
+ """String representation of the error."""
62
+ parts = [self.message]
63
+
64
+ if self.error_code:
65
+ parts.append(f"[{self.error_code}]")
66
+
67
+ if self.context:
68
+ parts.append(f"Operation: {self.context.operation}")
69
+ parts.append(f"Component: {self.context.component}")
70
+
71
+ return " | ".join(parts)
72
+
73
+ def to_dict(self) -> Dict[str, Any]:
74
+ """Convert error to dictionary representation."""
75
+ return {
76
+ "error_type": self.__class__.__name__,
77
+ "message": self.message,
78
+ "error_code": self.error_code,
79
+ "context": self.context.model_dump() if self.context else None,
80
+ "recoverable": self.recoverable,
81
+ "cause": str(self.cause) if self.cause else None,
82
+ }
83
+
84
+
85
+ class ConfigurationError(DjangoAppAgentError):
86
+ """Error in module configuration or setup."""
87
+
88
+ def __init__(
89
+ self,
90
+ message: str,
91
+ *,
92
+ config_key: Optional[str] = None,
93
+ config_file: Optional[Path] = None,
94
+ **kwargs
95
+ ) -> None:
96
+ """Initialize configuration error.
97
+
98
+ Args:
99
+ message: Error message
100
+ config_key: Configuration key that caused the error
101
+ config_file: Configuration file path
102
+ **kwargs: Additional arguments for base class
103
+ """
104
+ super().__init__(message, **kwargs)
105
+ self.config_key = config_key
106
+ self.config_file = config_file
107
+
108
+
109
+ class GenerationError(DjangoAppAgentError):
110
+ """Error during application generation process."""
111
+
112
+ def __init__(
113
+ self,
114
+ message: str,
115
+ *,
116
+ app_name: Optional[str] = None,
117
+ generation_stage: Optional[str] = None,
118
+ partial_results: Optional[List[str]] = None,
119
+ **kwargs
120
+ ) -> None:
121
+ """Initialize generation error.
122
+
123
+ Args:
124
+ message: Error message
125
+ app_name: Name of app being generated
126
+ generation_stage: Stage where error occurred
127
+ partial_results: Partial results before error
128
+ **kwargs: Additional arguments for base class
129
+ """
130
+ super().__init__(message, recoverable=True, **kwargs)
131
+ self.app_name = app_name
132
+ self.generation_stage = generation_stage
133
+ self.partial_results = partial_results or []
134
+
135
+
136
+ class ValidationError(DjangoAppAgentError):
137
+ """Error during validation of generated code or user input."""
138
+
139
+ def __init__(
140
+ self,
141
+ message: str,
142
+ *,
143
+ validation_type: Optional[str] = None,
144
+ field_name: Optional[str] = None,
145
+ field_value: Optional[Any] = None,
146
+ **kwargs
147
+ ) -> None:
148
+ """Initialize validation error.
149
+
150
+ Args:
151
+ message: Error message
152
+ validation_type: Type of validation that failed
153
+ field_name: Field that failed validation
154
+ field_value: Value that failed validation
155
+ **kwargs: Additional arguments for base class
156
+ """
157
+ super().__init__(message, **kwargs)
158
+ self.validation_type = validation_type
159
+ self.field_name = field_name
160
+ self.field_value = field_value
161
+
162
+
163
+ class QualityValidationError(ValidationError):
164
+ """Error when generated code doesn't meet quality standards."""
165
+
166
+ def __init__(
167
+ self,
168
+ message: str,
169
+ *,
170
+ quality_score: Optional[float] = None,
171
+ minimum_score: Optional[float] = None,
172
+ quality_issues: Optional[List[str]] = None,
173
+ **kwargs
174
+ ) -> None:
175
+ """Initialize quality validation error.
176
+
177
+ Args:
178
+ message: Error message
179
+ quality_score: Actual quality score achieved
180
+ minimum_score: Minimum required quality score
181
+ quality_issues: List of specific quality issues
182
+ **kwargs: Additional arguments for base class
183
+ """
184
+ super().__init__(message, validation_type="quality", **kwargs)
185
+ self.quality_score = quality_score
186
+ self.minimum_score = minimum_score
187
+ self.quality_issues = quality_issues or []
188
+
189
+
190
+ class AgentExecutionError(DjangoAppAgentError):
191
+ """Error during AI agent execution."""
192
+
193
+ def __init__(
194
+ self,
195
+ message: str,
196
+ *,
197
+ agent_name: Optional[str] = None,
198
+ agent_operation: Optional[str] = None,
199
+ retry_count: int = 0,
200
+ max_retries: int = 3,
201
+ **kwargs
202
+ ) -> None:
203
+ """Initialize agent execution error.
204
+
205
+ Args:
206
+ message: Error message
207
+ agent_name: Name of the agent that failed
208
+ agent_operation: Operation the agent was performing
209
+ retry_count: Number of retries attempted
210
+ max_retries: Maximum number of retries allowed
211
+ **kwargs: Additional arguments for base class
212
+ """
213
+ recoverable = retry_count < max_retries
214
+ super().__init__(message, recoverable=recoverable, **kwargs)
215
+ self.agent_name = agent_name
216
+ self.agent_operation = agent_operation
217
+ self.retry_count = retry_count
218
+ self.max_retries = max_retries
219
+
220
+
221
+ class AuthenticationError(DjangoAppAgentError):
222
+ """Error with AI service authentication."""
223
+
224
+ def __init__(
225
+ self,
226
+ message: str,
227
+ *,
228
+ provider: Optional[str] = None,
229
+ api_key_hint: Optional[str] = None,
230
+ **kwargs
231
+ ) -> None:
232
+ """Initialize authentication error.
233
+
234
+ Args:
235
+ message: Error message
236
+ provider: AI service provider (openai, anthropic, etc.)
237
+ api_key_hint: Hint about API key (first/last chars)
238
+ **kwargs: Additional arguments for base class
239
+ """
240
+ super().__init__(message, **kwargs)
241
+ self.provider = provider
242
+ self.api_key_hint = api_key_hint
243
+
244
+
245
+ class RateLimitError(DjangoAppAgentError):
246
+ """Error when AI service rate limits are exceeded."""
247
+
248
+ def __init__(
249
+ self,
250
+ message: str,
251
+ *,
252
+ provider: Optional[str] = None,
253
+ retry_after: Optional[int] = None,
254
+ requests_remaining: Optional[int] = None,
255
+ **kwargs
256
+ ) -> None:
257
+ """Initialize rate limit error.
258
+
259
+ Args:
260
+ message: Error message
261
+ provider: AI service provider
262
+ retry_after: Seconds to wait before retry
263
+ requests_remaining: Number of requests remaining
264
+ **kwargs: Additional arguments for base class
265
+ """
266
+ super().__init__(message, recoverable=True, **kwargs)
267
+ self.provider = provider
268
+ self.retry_after = retry_after
269
+ self.requests_remaining = requests_remaining
270
+
271
+
272
+ class TimeoutError(DjangoAppAgentError):
273
+ """Error when operations exceed time limits."""
274
+
275
+ def __init__(
276
+ self,
277
+ message: str,
278
+ *,
279
+ operation: Optional[str] = None,
280
+ timeout_seconds: Optional[float] = None,
281
+ elapsed_seconds: Optional[float] = None,
282
+ **kwargs
283
+ ) -> None:
284
+ """Initialize timeout error.
285
+
286
+ Args:
287
+ message: Error message
288
+ operation: Operation that timed out
289
+ timeout_seconds: Configured timeout
290
+ elapsed_seconds: Actual elapsed time
291
+ **kwargs: Additional arguments for base class
292
+ """
293
+ super().__init__(message, recoverable=True, **kwargs)
294
+ self.operation = operation
295
+ self.timeout_seconds = timeout_seconds
296
+ self.elapsed_seconds = elapsed_seconds
297
+
298
+
299
+ class FileSystemError(DjangoAppAgentError):
300
+ """Error when file system operations fail."""
301
+
302
+ def __init__(
303
+ self,
304
+ message: str,
305
+ *,
306
+ file_path: Optional[str] = None,
307
+ operation: Optional[str] = None,
308
+ **kwargs
309
+ ) -> None:
310
+ """Initialize file system error.
311
+
312
+ Args:
313
+ message: Error message
314
+ file_path: Path to the file that caused the error
315
+ operation: File system operation that failed
316
+ **kwargs: Additional arguments for base class
317
+ """
318
+ super().__init__(message, recoverable=True, **kwargs)
319
+ self.file_path = file_path
320
+ self.operation = operation
321
+
322
+
323
+ # Exception mapping for easy lookup
324
+ EXCEPTION_MAP: Dict[str, type[DjangoAppAgentError]] = {
325
+ "configuration": ConfigurationError,
326
+ "generation": GenerationError,
327
+ "validation": ValidationError,
328
+ "quality": QualityValidationError,
329
+ "agent": AgentExecutionError,
330
+ "auth": AuthenticationError,
331
+ "rate_limit": RateLimitError,
332
+ "timeout": TimeoutError,
333
+ "filesystem": FileSystemError,
334
+ }
335
+
336
+
337
+ def create_error(
338
+ error_type: str,
339
+ message: str,
340
+ **kwargs
341
+ ) -> DjangoAppAgentError:
342
+ """Create an error of the specified type.
343
+
344
+ Args:
345
+ error_type: Type of error to create
346
+ message: Error message
347
+ **kwargs: Additional arguments for the error
348
+
349
+ Returns:
350
+ Appropriate error instance
351
+
352
+ Raises:
353
+ ValueError: If error_type is not recognized
354
+ """
355
+ if error_type not in EXCEPTION_MAP:
356
+ raise ValueError(f"Unknown error type: {error_type}")
357
+
358
+ error_class = EXCEPTION_MAP[error_type]
359
+ return error_class(message, **kwargs)