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,430 @@
1
+ """
2
+ Agent execution management for Django App Agent Module.
3
+
4
+ This module provides execution management and orchestration for AI agents,
5
+ including result handling, error management, and performance tracking.
6
+ """
7
+
8
+ from typing import TypeVar, Generic, Optional, Dict, Any, List, Union, Callable, Awaitable
9
+ from dataclasses import dataclass, field
10
+ from datetime import datetime, timezone
11
+ from enum import Enum
12
+ import asyncio
13
+
14
+ from pydantic import BaseModel, Field, ConfigDict
15
+
16
+ from ...core.config import AgentConfig
17
+ from ...core.exceptions import AgentExecutionError, ValidationError
18
+ from ...models.base import TimestampedModel
19
+ from ...utils.logging import StructuredLogger, get_logger
20
+ from .context import AgentDependencies, AgentContext
21
+ from .agent import DjangoAgent
22
+
23
+ # Type variables
24
+ OutputT = TypeVar('OutputT')
25
+ DepsT = TypeVar('DepsT', bound=AgentDependencies)
26
+
27
+
28
+ class ExecutionStatus(str, Enum):
29
+ """Status of agent execution."""
30
+ PENDING = "pending"
31
+ RUNNING = "running"
32
+ COMPLETED = "completed"
33
+ FAILED = "failed"
34
+ CANCELLED = "cancelled"
35
+
36
+
37
+ class ExecutionResult(BaseModel, Generic[OutputT]):
38
+ """Result of agent execution."""
39
+
40
+ model_config = ConfigDict(
41
+ extra='forbid',
42
+ validate_assignment=True,
43
+ arbitrary_types_allowed=True
44
+ )
45
+
46
+ # Execution metadata
47
+ execution_id: str = Field(description="Unique execution identifier")
48
+ agent_name: str = Field(description="Name of the agent that was executed")
49
+ status: ExecutionStatus = Field(description="Execution status")
50
+
51
+ # Timing information
52
+ start_time: datetime = Field(description="Execution start time")
53
+ end_time: Optional[datetime] = Field(default=None, description="Execution end time")
54
+
55
+ # Results
56
+ output: Optional[OutputT] = Field(default=None, description="Agent output")
57
+ error: Optional[str] = Field(default=None, description="Error message if failed")
58
+
59
+ # Performance metrics
60
+ execution_time_seconds: float = Field(default=0.0, description="Total execution time")
61
+ token_usage: Dict[str, int] = Field(default_factory=dict, description="Token usage by provider")
62
+ api_calls_count: int = Field(default=0, description="Number of API calls made")
63
+
64
+ # Context information
65
+ correlation_id: str = Field(description="Correlation ID for tracing")
66
+ operation_name: str = Field(description="Name of the operation")
67
+
68
+ @property
69
+ def is_successful(self) -> bool:
70
+ """Check if execution was successful."""
71
+ return self.status == ExecutionStatus.COMPLETED and self.output is not None
72
+
73
+ @property
74
+ def is_failed(self) -> bool:
75
+ """Check if execution failed."""
76
+ return self.status == ExecutionStatus.FAILED
77
+
78
+ def get_summary(self) -> Dict[str, Any]:
79
+ """Get execution summary."""
80
+ return {
81
+ "execution_id": self.execution_id,
82
+ "agent_name": self.agent_name,
83
+ "status": self.status.value,
84
+ "is_successful": self.is_successful,
85
+ "execution_time_seconds": self.execution_time_seconds,
86
+ "total_tokens": sum(self.token_usage.values()),
87
+ "api_calls": self.api_calls_count,
88
+ "has_output": self.output is not None,
89
+ "has_error": self.error is not None,
90
+ }
91
+
92
+
93
+ @dataclass
94
+ class ExecutionPlan:
95
+ """Plan for executing multiple agents in sequence or parallel."""
96
+
97
+ name: str
98
+ agents: List[DjangoAgent] = field(default_factory=list)
99
+ dependencies: Dict[str, List[str]] = field(default_factory=dict)
100
+ parallel_groups: List[List[str]] = field(default_factory=list)
101
+ timeout_seconds: float = 300.0
102
+
103
+ def add_agent(self, agent: DjangoAgent, depends_on: Optional[List[str]] = None) -> None:
104
+ """Add agent to execution plan."""
105
+ self.agents.append(agent)
106
+ if depends_on:
107
+ self.dependencies[agent.agent_name] = depends_on
108
+
109
+ def add_parallel_group(self, agent_names: List[str]) -> None:
110
+ """Add group of agents that can run in parallel."""
111
+ self.parallel_groups.append(agent_names)
112
+
113
+ def validate(self) -> List[str]:
114
+ """Validate execution plan."""
115
+ errors = []
116
+ agent_names = {agent.agent_name for agent in self.agents}
117
+
118
+ # Check dependencies reference existing agents
119
+ for agent_name, deps in self.dependencies.items():
120
+ if agent_name not in agent_names:
121
+ errors.append(f"Agent '{agent_name}' in dependencies not found in plan")
122
+
123
+ for dep in deps:
124
+ if dep not in agent_names:
125
+ errors.append(f"Dependency '{dep}' for '{agent_name}' not found in plan")
126
+
127
+ # Check parallel groups reference existing agents
128
+ for group in self.parallel_groups:
129
+ for agent_name in group:
130
+ if agent_name not in agent_names:
131
+ errors.append(f"Agent '{agent_name}' in parallel group not found in plan")
132
+
133
+ return errors
134
+
135
+
136
+ class AgentExecutor:
137
+ """Executor for managing and running Django App Agent AI agents."""
138
+
139
+ def __init__(self, config: AgentConfig):
140
+ """Initialize agent executor.
141
+
142
+ Args:
143
+ config: Agent configuration
144
+ """
145
+ self.config = config
146
+ self.logger = get_logger("agent_executor")
147
+ self._active_executions: Dict[str, ExecutionResult] = {}
148
+
149
+ async def execute_single(
150
+ self,
151
+ agent: DjangoAgent[DepsT, OutputT],
152
+ prompt: str,
153
+ deps: DepsT,
154
+ execution_id: Optional[str] = None,
155
+ timeout_seconds: Optional[float] = None
156
+ ) -> ExecutionResult[OutputT]:
157
+ """Execute a single agent.
158
+
159
+ Args:
160
+ agent: Agent to execute
161
+ prompt: Input prompt
162
+ deps: Agent dependencies
163
+ execution_id: Optional execution ID
164
+ timeout_seconds: Optional timeout override
165
+
166
+ Returns:
167
+ Execution result
168
+ """
169
+ import uuid
170
+
171
+ if execution_id is None:
172
+ execution_id = str(uuid.uuid4())
173
+
174
+ start_time = datetime.now(timezone.utc)
175
+
176
+ # Create execution result
177
+ result = ExecutionResult[OutputT](
178
+ execution_id=execution_id,
179
+ agent_name=agent.agent_name,
180
+ status=ExecutionStatus.PENDING,
181
+ start_time=start_time,
182
+ correlation_id=deps.correlation_id,
183
+ operation_name=deps.operation_name
184
+ )
185
+
186
+ # Track active execution
187
+ self._active_executions[execution_id] = result
188
+
189
+ try:
190
+ # Update status to running
191
+ result.status = ExecutionStatus.RUNNING
192
+
193
+ # Create execution context
194
+ context = AgentContext()
195
+
196
+ # Determine timeout
197
+ timeout = timeout_seconds or 300.0
198
+
199
+ self.logger.info(
200
+ f"Starting execution of agent {agent.agent_name}",
201
+ execution_id=execution_id,
202
+ agent_name=agent.agent_name,
203
+ timeout_seconds=timeout
204
+ )
205
+
206
+ # Execute agent with timeout
207
+ output = await asyncio.wait_for(
208
+ agent.run(prompt, deps, context),
209
+ timeout=timeout
210
+ )
211
+
212
+ # Update result with success
213
+ end_time = datetime.now(timezone.utc)
214
+ result.status = ExecutionStatus.COMPLETED
215
+ result.output = output
216
+ result.end_time = end_time
217
+ result.execution_time_seconds = (end_time - start_time).total_seconds()
218
+ result.token_usage = context.token_usage.copy()
219
+ result.api_calls_count = context.api_calls_count
220
+
221
+ self.logger.info(
222
+ f"Completed execution of agent {agent.agent_name}",
223
+ execution_id=execution_id,
224
+ execution_time_seconds=result.execution_time_seconds,
225
+ success=True
226
+ )
227
+
228
+ return result
229
+
230
+ except asyncio.TimeoutError:
231
+ error_msg = f"Agent {agent.agent_name} execution timed out after {timeout} seconds"
232
+ result.status = ExecutionStatus.FAILED
233
+ result.error = error_msg
234
+ result.end_time = datetime.now(timezone.utc)
235
+ result.execution_time_seconds = (result.end_time - start_time).total_seconds()
236
+
237
+ self.logger.error(
238
+ error_msg,
239
+ execution_id=execution_id,
240
+ agent_name=agent.agent_name,
241
+ timeout_seconds=timeout
242
+ )
243
+
244
+ return result
245
+
246
+ except Exception as e:
247
+ error_msg = f"Agent {agent.agent_name} execution failed: {e}"
248
+ result.status = ExecutionStatus.FAILED
249
+ result.error = error_msg
250
+ result.end_time = datetime.now(timezone.utc)
251
+ result.execution_time_seconds = (result.end_time - start_time).total_seconds()
252
+
253
+ self.logger.error(
254
+ error_msg,
255
+ execution_id=execution_id,
256
+ agent_name=agent.agent_name,
257
+ error=str(e),
258
+ error_type=type(e).__name__
259
+ )
260
+
261
+ return result
262
+
263
+ finally:
264
+ # Remove from active executions
265
+ self._active_executions.pop(execution_id, None)
266
+
267
+ async def execute_plan(
268
+ self,
269
+ plan: ExecutionPlan,
270
+ prompt: str,
271
+ deps: AgentDependencies,
272
+ execution_id: Optional[str] = None
273
+ ) -> Dict[str, ExecutionResult]:
274
+ """Execute multiple agents according to a plan.
275
+
276
+ Args:
277
+ plan: Execution plan
278
+ prompt: Input prompt for all agents
279
+ deps: Base dependencies (will be copied for each agent)
280
+ execution_id: Optional execution ID
281
+
282
+ Returns:
283
+ Dictionary mapping agent names to execution results
284
+ """
285
+ import uuid
286
+
287
+ if execution_id is None:
288
+ execution_id = str(uuid.uuid4())
289
+
290
+ # Validate plan
291
+ validation_errors = plan.validate()
292
+ if validation_errors:
293
+ raise ValidationError(
294
+ f"Invalid execution plan: {'; '.join(validation_errors)}",
295
+ validation_type="execution_plan"
296
+ )
297
+
298
+ self.logger.info(
299
+ f"Starting execution plan '{plan.name}'",
300
+ execution_id=execution_id,
301
+ agents_count=len(plan.agents),
302
+ parallel_groups=len(plan.parallel_groups)
303
+ )
304
+
305
+ results: Dict[str, ExecutionResult] = {}
306
+ agent_map = {agent.agent_name: agent for agent in plan.agents}
307
+
308
+ try:
309
+ # Execute agents in dependency order
310
+ executed = set()
311
+
312
+ while len(executed) < len(plan.agents):
313
+ # Find agents ready to execute (dependencies satisfied)
314
+ ready_agents = []
315
+
316
+ for agent in plan.agents:
317
+ if agent.agent_name in executed:
318
+ continue
319
+
320
+ # Check if dependencies are satisfied
321
+ agent_deps = plan.dependencies.get(agent.agent_name, [])
322
+ if all(dep in executed for dep in agent_deps):
323
+ ready_agents.append(agent)
324
+
325
+ if not ready_agents:
326
+ # Check for circular dependencies
327
+ remaining = [a.agent_name for a in plan.agents if a.agent_name not in executed]
328
+ raise AgentExecutionError(
329
+ f"Circular dependency detected or no agents ready to execute. Remaining: {remaining}",
330
+ agent_name="executor",
331
+ agent_operation="execute_plan"
332
+ )
333
+
334
+ # Execute ready agents (potentially in parallel)
335
+ tasks = []
336
+ for agent in ready_agents:
337
+ # Create agent-specific dependencies
338
+ agent_deps = AgentDependencies(
339
+ config=deps.config,
340
+ logger=deps.logger,
341
+ project_context=deps.project_context,
342
+ infrastructure_context=deps.infrastructure_context,
343
+ correlation_id=f"{execution_id}_{agent.agent_name}",
344
+ operation_name=f"{deps.operation_name}_{agent.agent_name}",
345
+ project_root=deps.project_root,
346
+ output_directory=deps.output_directory,
347
+ execution_metadata=deps.execution_metadata.copy()
348
+ )
349
+
350
+ task = self.execute_single(
351
+ agent,
352
+ prompt,
353
+ agent_deps,
354
+ f"{execution_id}_{agent.agent_name}",
355
+ plan.timeout_seconds
356
+ )
357
+ tasks.append((agent.agent_name, task))
358
+
359
+ # Wait for all ready agents to complete
360
+ for agent_name, task in tasks:
361
+ result = await task
362
+ results[agent_name] = result
363
+ executed.add(agent_name)
364
+
365
+ if not result.is_successful:
366
+ self.logger.warning(
367
+ f"Agent {agent_name} failed in execution plan",
368
+ execution_id=execution_id,
369
+ error=result.error
370
+ )
371
+
372
+ self.logger.info(
373
+ f"Completed execution plan '{plan.name}'",
374
+ execution_id=execution_id,
375
+ successful_agents=sum(1 for r in results.values() if r.is_successful),
376
+ failed_agents=sum(1 for r in results.values() if r.is_failed)
377
+ )
378
+
379
+ return results
380
+
381
+ except Exception as e:
382
+ self.logger.error(
383
+ f"Execution plan '{plan.name}' failed",
384
+ execution_id=execution_id,
385
+ error=str(e),
386
+ error_type=type(e).__name__
387
+ )
388
+ raise
389
+
390
+ def get_active_executions(self) -> Dict[str, ExecutionResult]:
391
+ """Get currently active executions."""
392
+ return self._active_executions.copy()
393
+
394
+ def cancel_execution(self, execution_id: str) -> bool:
395
+ """Cancel an active execution.
396
+
397
+ Args:
398
+ execution_id: ID of execution to cancel
399
+
400
+ Returns:
401
+ True if execution was cancelled, False if not found
402
+ """
403
+ if execution_id in self._active_executions:
404
+ result = self._active_executions[execution_id]
405
+ result.status = ExecutionStatus.CANCELLED
406
+ result.end_time = datetime.now(timezone.utc)
407
+ result.execution_time_seconds = (result.end_time - result.start_time).total_seconds()
408
+
409
+ self.logger.info(
410
+ f"Cancelled execution {execution_id}",
411
+ execution_id=execution_id,
412
+ agent_name=result.agent_name
413
+ )
414
+
415
+ return True
416
+
417
+ return False
418
+
419
+ def get_execution_summary(self) -> Dict[str, Any]:
420
+ """Get summary of executor state."""
421
+ active = self.get_active_executions()
422
+
423
+ return {
424
+ "active_executions_count": len(active),
425
+ "active_agents": [r.agent_name for r in active.values()],
426
+ "executor_config": {
427
+ "debug_mode": self.config.debug_mode,
428
+ "log_level": self.config.log_level.value,
429
+ }
430
+ }
@@ -0,0 +1,12 @@
1
+ """
2
+ Code Generation Agents for Django App Agent Module.
3
+
4
+ This module contains AI agents responsible for generating Django application code
5
+ using Pydantic AI framework.
6
+ """
7
+
8
+ from .app_generator import AppGeneratorAgent
9
+
10
+ __all__ = [
11
+ "AppGeneratorAgent",
12
+ ]
@@ -0,0 +1,15 @@
1
+ """
2
+ Django Application Generator Agent Package.
3
+
4
+ This package contains the decomposed components of the AI agent
5
+ responsible for generating Django applications with intelligent code generation.
6
+ """
7
+
8
+ from .main import AppGeneratorAgent
9
+ from .models import FileGenerationRequest, GeneratedFileResponse
10
+
11
+ __all__ = [
12
+ 'AppGeneratorAgent',
13
+ 'FileGenerationRequest',
14
+ 'GeneratedFileResponse'
15
+ ]
@@ -0,0 +1,147 @@
1
+ """
2
+ Configuration validation for the App Generator Agent.
3
+
4
+ This module handles API key validation and model configuration
5
+ using django-cfg integration.
6
+ """
7
+
8
+ import os
9
+ from typing import Optional
10
+
11
+ from pydantic_ai.models.openai import OpenAIModel
12
+
13
+ from ....core.config import AgentConfig, AIProvider
14
+ from ....core.exceptions import ConfigurationError
15
+
16
+
17
+ class ConfigValidator:
18
+ """Validates and configures API keys and AI models."""
19
+
20
+ def __init__(self):
21
+ """Initialize the config validator."""
22
+ self.model: Optional[OpenAIModel] = None
23
+
24
+ def validate_and_configure(self, config) -> OpenAIModel:
25
+ """
26
+ Validate API keys and configure AI model.
27
+
28
+ Args:
29
+ config: Configuration object (AgentConfig or other)
30
+
31
+ Returns:
32
+ Configured OpenAI model
33
+
34
+ Raises:
35
+ ConfigurationError: If no valid API keys found
36
+ """
37
+ try:
38
+ # Get configuration from django-cfg
39
+ print(f"πŸ” Debug config type: {type(config)}")
40
+ print(f"πŸ” Debug config: {config}")
41
+
42
+ if isinstance(config, AgentConfig):
43
+ # Use provided AgentConfig
44
+ agent_config = config
45
+ print("βœ… Using provided AgentConfig")
46
+ else:
47
+ # Load from django-cfg
48
+ print("πŸ”„ Loading from django-cfg...")
49
+ agent_config = AgentConfig.from_django_cfg()
50
+ print(f"βœ… Loaded AgentConfig: {type(agent_config)}")
51
+
52
+ print(f"πŸ” AgentConfig attributes: {dir(agent_config)}")
53
+
54
+ # Get API keys from configuration
55
+ openai_key = self._get_api_key(agent_config, AIProvider.OPENAI)
56
+ openrouter_key = self._get_api_key(agent_config, AIProvider.OPENROUTER)
57
+
58
+ print(f"πŸ” API keys via get_api_key: OpenAI={bool(openai_key)}, OpenRouter={bool(openrouter_key)}")
59
+
60
+ # Fallback to direct access
61
+ if not openai_key and not openrouter_key:
62
+ openai_key, openrouter_key = self._get_keys_direct_access(agent_config)
63
+
64
+ # Debug: Print what we found
65
+ print(f"πŸ” Final API Keys from django-cfg:")
66
+ print(f" OpenAI: {'βœ… Found' if openai_key else '❌ Missing'}")
67
+ print(f" OpenRouter: {'βœ… Found' if openrouter_key else '❌ Missing'}")
68
+
69
+ if not openai_key and not openrouter_key:
70
+ raise ConfigurationError(
71
+ "❌ AI Agent Configuration Error: No API keys found in django-cfg!\n\n"
72
+ "πŸ”‘ Required: Either OpenAI or OpenRouter API key must be configured.\n\n"
73
+ "πŸ“ How to fix in django-cfg config:\n"
74
+ " api_keys:\n"
75
+ " openai: 'your-openai-key'\n"
76
+ " openrouter: 'your-openrouter-key'\n\n"
77
+ "πŸš€ Without API keys, AI agents cannot generate intelligent code!\n"
78
+ " You'll only get basic template-based generation.",
79
+ config_key="api_keys"
80
+ )
81
+
82
+ # Configure and return the model
83
+ return self._configure_model(openai_key, openrouter_key)
84
+
85
+ except Exception as e:
86
+ print(f"❌ Error loading API keys from django-cfg: {e}")
87
+ raise ConfigurationError(
88
+ f"Failed to load API keys from django-cfg configuration: {e}\n\n"
89
+ "πŸ”§ Make sure django-cfg is properly configured with API keys.",
90
+ config_key="api_keys",
91
+ cause=e
92
+ )
93
+
94
+ def _get_api_key(self, agent_config: AgentConfig, provider: AIProvider) -> Optional[str]:
95
+ """Get API key for specific provider."""
96
+ if hasattr(agent_config, 'get_api_key'):
97
+ return agent_config.get_api_key(provider)
98
+ return None
99
+
100
+ def _get_keys_direct_access(self, agent_config: AgentConfig) -> tuple[Optional[str], Optional[str]]:
101
+ """Get API keys via direct access as fallback."""
102
+ openai_key = None
103
+ openrouter_key = None
104
+
105
+ print("πŸ”„ Trying direct access to api_keys...")
106
+ if hasattr(agent_config, 'api_keys') and agent_config.api_keys:
107
+ print(f"πŸ” api_keys type: {type(agent_config.api_keys)}")
108
+ print(f"πŸ” api_keys content: {agent_config.api_keys}")
109
+
110
+ if hasattr(agent_config.api_keys, 'get'):
111
+ openai_key = agent_config.api_keys.get('openai', '')
112
+ openrouter_key = agent_config.api_keys.get('openrouter', '')
113
+ else:
114
+ openai_key = getattr(agent_config.api_keys, 'openai', '')
115
+ openrouter_key = getattr(agent_config.api_keys, 'openrouter', '')
116
+
117
+ print(f"πŸ” Direct access results: OpenAI={bool(openai_key)}, OpenRouter={bool(openrouter_key)}")
118
+
119
+ return openai_key, openrouter_key
120
+
121
+ def _configure_model(self, openai_key: Optional[str], openrouter_key: Optional[str]) -> OpenAIModel:
122
+ """Configure AI model with available API key."""
123
+ if openrouter_key:
124
+ print("πŸš€ Using OpenRouter API via django-cfg")
125
+ print(f"πŸ” OpenRouter key length: {len(openrouter_key)}")
126
+ print(f"πŸ” OpenRouter key prefix: {openrouter_key[:20]}...")
127
+
128
+ # Set environment variables for OpenRouter
129
+ os.environ['OPENAI_API_KEY'] = openrouter_key
130
+ os.environ['OPENAI_BASE_URL'] = 'https://openrouter.ai/api/v1'
131
+ # OpenRouter Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½Ρ‹Π΅ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ
132
+ os.environ['OPENAI_DEFAULT_HEADERS'] = '{"HTTP-Referer": "https://djangocfg.com", "X-Title": "Django CFG App Agent"}'
133
+
134
+ self.model = OpenAIModel('gpt-4o-mini')
135
+
136
+ elif openai_key:
137
+ print("πŸš€ Using OpenAI API via django-cfg")
138
+
139
+ # Set environment variable for OpenAI
140
+ os.environ['OPENAI_API_KEY'] = openai_key
141
+ # Remove base URL for standard OpenAI
142
+ if 'OPENAI_BASE_URL' in os.environ:
143
+ del os.environ['OPENAI_BASE_URL']
144
+
145
+ self.model = OpenAIModel('gpt-4o-mini')
146
+
147
+ return self.model