django-cfg 1.1.81__py3-none-any.whl → 1.2.0__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 (246) hide show
  1. django_cfg/__init__.py +20 -448
  2. django_cfg/apps/accounts/README.md +3 -3
  3. django_cfg/apps/accounts/admin/__init__.py +0 -2
  4. django_cfg/apps/accounts/admin/activity.py +2 -9
  5. django_cfg/apps/accounts/admin/filters.py +0 -42
  6. django_cfg/apps/accounts/admin/inlines.py +8 -8
  7. django_cfg/apps/accounts/admin/otp.py +5 -5
  8. django_cfg/apps/accounts/admin/registration_source.py +1 -8
  9. django_cfg/apps/accounts/admin/user.py +12 -20
  10. django_cfg/apps/accounts/managers/user_manager.py +2 -129
  11. django_cfg/apps/accounts/migrations/0006_remove_twilioresponse_otp_secret_and_more.py +46 -0
  12. django_cfg/apps/accounts/models.py +3 -123
  13. django_cfg/apps/accounts/serializers/otp.py +40 -44
  14. django_cfg/apps/accounts/serializers/profile.py +0 -2
  15. django_cfg/apps/accounts/services/otp_service.py +98 -186
  16. django_cfg/apps/accounts/signals.py +25 -15
  17. django_cfg/apps/accounts/utils/auth_email_service.py +84 -0
  18. django_cfg/apps/accounts/views/otp.py +35 -36
  19. django_cfg/apps/agents/README.md +129 -0
  20. django_cfg/apps/agents/__init__.py +68 -0
  21. django_cfg/apps/agents/admin/__init__.py +17 -0
  22. django_cfg/apps/agents/admin/execution_admin.py +460 -0
  23. django_cfg/apps/agents/admin/registry_admin.py +360 -0
  24. django_cfg/apps/agents/admin/toolsets_admin.py +482 -0
  25. django_cfg/apps/agents/apps.py +29 -0
  26. django_cfg/apps/agents/core/__init__.py +20 -0
  27. django_cfg/apps/agents/core/agent.py +281 -0
  28. django_cfg/apps/agents/core/dependencies.py +154 -0
  29. django_cfg/apps/agents/core/exceptions.py +66 -0
  30. django_cfg/apps/agents/core/models.py +106 -0
  31. django_cfg/apps/agents/core/orchestrator.py +391 -0
  32. django_cfg/apps/agents/examples/__init__.py +3 -0
  33. django_cfg/apps/agents/examples/simple_example.py +161 -0
  34. django_cfg/apps/agents/integration/__init__.py +14 -0
  35. django_cfg/apps/agents/integration/middleware.py +80 -0
  36. django_cfg/apps/agents/integration/registry.py +345 -0
  37. django_cfg/apps/agents/integration/signals.py +50 -0
  38. django_cfg/apps/agents/management/__init__.py +3 -0
  39. django_cfg/apps/agents/management/commands/__init__.py +3 -0
  40. django_cfg/apps/agents/management/commands/create_agent.py +365 -0
  41. django_cfg/apps/agents/management/commands/orchestrator_status.py +191 -0
  42. django_cfg/apps/agents/managers/__init__.py +23 -0
  43. django_cfg/apps/agents/managers/execution.py +236 -0
  44. django_cfg/apps/agents/managers/registry.py +254 -0
  45. django_cfg/apps/agents/managers/toolsets.py +496 -0
  46. django_cfg/apps/agents/migrations/0001_initial.py +286 -0
  47. django_cfg/apps/agents/migrations/__init__.py +5 -0
  48. django_cfg/apps/agents/models/__init__.py +15 -0
  49. django_cfg/apps/agents/models/execution.py +215 -0
  50. django_cfg/apps/agents/models/registry.py +220 -0
  51. django_cfg/apps/agents/models/toolsets.py +305 -0
  52. django_cfg/apps/agents/patterns/__init__.py +24 -0
  53. django_cfg/apps/agents/patterns/content_agents.py +234 -0
  54. django_cfg/apps/agents/toolsets/__init__.py +15 -0
  55. django_cfg/apps/agents/toolsets/cache_toolset.py +285 -0
  56. django_cfg/apps/agents/toolsets/django_toolset.py +220 -0
  57. django_cfg/apps/agents/toolsets/file_toolset.py +324 -0
  58. django_cfg/apps/agents/toolsets/orm_toolset.py +319 -0
  59. django_cfg/apps/agents/urls.py +46 -0
  60. django_cfg/apps/knowbase/README.md +150 -0
  61. django_cfg/apps/knowbase/__init__.py +27 -0
  62. django_cfg/apps/knowbase/admin/__init__.py +23 -0
  63. django_cfg/apps/knowbase/admin/archive_admin.py +857 -0
  64. django_cfg/apps/knowbase/admin/chat_admin.py +386 -0
  65. django_cfg/apps/knowbase/admin/document_admin.py +650 -0
  66. django_cfg/apps/knowbase/admin/external_data_admin.py +685 -0
  67. django_cfg/apps/knowbase/apps.py +81 -0
  68. django_cfg/apps/knowbase/config/README.md +176 -0
  69. django_cfg/apps/knowbase/config/__init__.py +51 -0
  70. django_cfg/apps/knowbase/config/constance_fields.py +186 -0
  71. django_cfg/apps/knowbase/config/constance_settings.py +200 -0
  72. django_cfg/apps/knowbase/config/settings.py +444 -0
  73. django_cfg/apps/knowbase/examples/__init__.py +3 -0
  74. django_cfg/apps/knowbase/examples/external_data_usage.py +191 -0
  75. django_cfg/apps/knowbase/management/__init__.py +0 -0
  76. django_cfg/apps/knowbase/management/commands/__init__.py +0 -0
  77. django_cfg/apps/knowbase/management/commands/knowbase_stats.py +158 -0
  78. django_cfg/apps/knowbase/management/commands/setup_knowbase.py +59 -0
  79. django_cfg/apps/knowbase/managers/__init__.py +22 -0
  80. django_cfg/apps/knowbase/managers/archive.py +426 -0
  81. django_cfg/apps/knowbase/managers/base.py +32 -0
  82. django_cfg/apps/knowbase/managers/chat.py +141 -0
  83. django_cfg/apps/knowbase/managers/document.py +203 -0
  84. django_cfg/apps/knowbase/managers/external_data.py +471 -0
  85. django_cfg/apps/knowbase/migrations/0001_initial.py +427 -0
  86. django_cfg/apps/knowbase/migrations/0002_archiveitem_archiveitemchunk_documentarchive_and_more.py +434 -0
  87. django_cfg/apps/knowbase/migrations/__init__.py +5 -0
  88. django_cfg/apps/knowbase/mixins/__init__.py +15 -0
  89. django_cfg/apps/knowbase/mixins/config.py +108 -0
  90. django_cfg/apps/knowbase/mixins/creator.py +81 -0
  91. django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +199 -0
  92. django_cfg/apps/knowbase/mixins/external_data_mixin.py +813 -0
  93. django_cfg/apps/knowbase/mixins/service.py +362 -0
  94. django_cfg/apps/knowbase/models/__init__.py +41 -0
  95. django_cfg/apps/knowbase/models/archive.py +599 -0
  96. django_cfg/apps/knowbase/models/base.py +58 -0
  97. django_cfg/apps/knowbase/models/chat.py +157 -0
  98. django_cfg/apps/knowbase/models/document.py +267 -0
  99. django_cfg/apps/knowbase/models/external_data.py +376 -0
  100. django_cfg/apps/knowbase/serializers/__init__.py +68 -0
  101. django_cfg/apps/knowbase/serializers/archive_serializers.py +386 -0
  102. django_cfg/apps/knowbase/serializers/chat_serializers.py +137 -0
  103. django_cfg/apps/knowbase/serializers/document_serializers.py +94 -0
  104. django_cfg/apps/knowbase/serializers/external_data_serializers.py +256 -0
  105. django_cfg/apps/knowbase/serializers/public_serializers.py +74 -0
  106. django_cfg/apps/knowbase/services/__init__.py +40 -0
  107. django_cfg/apps/knowbase/services/archive/__init__.py +42 -0
  108. django_cfg/apps/knowbase/services/archive/archive_service.py +541 -0
  109. django_cfg/apps/knowbase/services/archive/chunking_service.py +791 -0
  110. django_cfg/apps/knowbase/services/archive/exceptions.py +52 -0
  111. django_cfg/apps/knowbase/services/archive/extraction_service.py +508 -0
  112. django_cfg/apps/knowbase/services/archive/vectorization_service.py +362 -0
  113. django_cfg/apps/knowbase/services/base.py +53 -0
  114. django_cfg/apps/knowbase/services/chat_service.py +239 -0
  115. django_cfg/apps/knowbase/services/document_service.py +144 -0
  116. django_cfg/apps/knowbase/services/embedding/__init__.py +43 -0
  117. django_cfg/apps/knowbase/services/embedding/async_processor.py +244 -0
  118. django_cfg/apps/knowbase/services/embedding/batch_processor.py +250 -0
  119. django_cfg/apps/knowbase/services/embedding/batch_result.py +61 -0
  120. django_cfg/apps/knowbase/services/embedding/models.py +229 -0
  121. django_cfg/apps/knowbase/services/embedding/processors.py +148 -0
  122. django_cfg/apps/knowbase/services/embedding/utils.py +176 -0
  123. django_cfg/apps/knowbase/services/prompt_builder.py +191 -0
  124. django_cfg/apps/knowbase/services/search_service.py +293 -0
  125. django_cfg/apps/knowbase/signals/__init__.py +21 -0
  126. django_cfg/apps/knowbase/signals/archive_signals.py +211 -0
  127. django_cfg/apps/knowbase/signals/chat_signals.py +37 -0
  128. django_cfg/apps/knowbase/signals/document_signals.py +143 -0
  129. django_cfg/apps/knowbase/signals/external_data_signals.py +157 -0
  130. django_cfg/apps/knowbase/tasks/__init__.py +39 -0
  131. django_cfg/apps/knowbase/tasks/archive_tasks.py +316 -0
  132. django_cfg/apps/knowbase/tasks/document_processing.py +341 -0
  133. django_cfg/apps/knowbase/tasks/external_data_tasks.py +341 -0
  134. django_cfg/apps/knowbase/tasks/maintenance.py +195 -0
  135. django_cfg/apps/knowbase/urls.py +43 -0
  136. django_cfg/apps/knowbase/utils/__init__.py +12 -0
  137. django_cfg/apps/knowbase/utils/chunk_settings.py +261 -0
  138. django_cfg/apps/knowbase/utils/text_processing.py +375 -0
  139. django_cfg/apps/knowbase/utils/validation.py +99 -0
  140. django_cfg/apps/knowbase/views/__init__.py +28 -0
  141. django_cfg/apps/knowbase/views/archive_views.py +469 -0
  142. django_cfg/apps/knowbase/views/base.py +49 -0
  143. django_cfg/apps/knowbase/views/chat_views.py +181 -0
  144. django_cfg/apps/knowbase/views/document_views.py +183 -0
  145. django_cfg/apps/knowbase/views/public_views.py +129 -0
  146. django_cfg/apps/leads/admin.py +70 -0
  147. django_cfg/apps/newsletter/admin.py +234 -0
  148. django_cfg/apps/newsletter/admin_filters.py +124 -0
  149. django_cfg/apps/support/admin.py +196 -0
  150. django_cfg/apps/support/admin_filters.py +71 -0
  151. django_cfg/apps/support/templates/support/chat/ticket_chat.html +1 -1
  152. django_cfg/apps/urls.py +5 -4
  153. django_cfg/cli/README.md +1 -1
  154. django_cfg/cli/commands/create_project.py +2 -2
  155. django_cfg/cli/commands/info.py +1 -1
  156. django_cfg/config.py +44 -0
  157. django_cfg/core/config.py +29 -82
  158. django_cfg/core/environment.py +1 -1
  159. django_cfg/core/generation.py +19 -107
  160. django_cfg/{integration.py → core/integration.py} +18 -16
  161. django_cfg/core/validation.py +1 -1
  162. django_cfg/management/__init__.py +1 -1
  163. django_cfg/management/commands/__init__.py +1 -1
  164. django_cfg/management/commands/auto_generate.py +482 -0
  165. django_cfg/management/commands/migrator.py +19 -101
  166. django_cfg/management/commands/test_email.py +1 -1
  167. django_cfg/middleware/README.md +0 -158
  168. django_cfg/middleware/__init__.py +0 -2
  169. django_cfg/middleware/user_activity.py +3 -3
  170. django_cfg/models/api.py +145 -0
  171. django_cfg/models/base.py +287 -0
  172. django_cfg/models/cache.py +4 -4
  173. django_cfg/models/constance.py +25 -88
  174. django_cfg/models/database.py +9 -9
  175. django_cfg/models/drf.py +3 -36
  176. django_cfg/models/email.py +163 -0
  177. django_cfg/models/environment.py +276 -0
  178. django_cfg/models/limits.py +1 -1
  179. django_cfg/models/logging.py +366 -0
  180. django_cfg/models/revolution.py +41 -2
  181. django_cfg/models/security.py +125 -0
  182. django_cfg/models/services.py +1 -1
  183. django_cfg/modules/__init__.py +2 -56
  184. django_cfg/modules/base.py +78 -52
  185. django_cfg/modules/django_currency/service.py +2 -2
  186. django_cfg/modules/django_email.py +2 -2
  187. django_cfg/modules/django_health.py +267 -0
  188. django_cfg/modules/django_llm/llm/client.py +79 -17
  189. django_cfg/modules/django_llm/translator/translator.py +2 -2
  190. django_cfg/modules/django_logger.py +2 -2
  191. django_cfg/modules/django_ngrok.py +2 -2
  192. django_cfg/modules/django_tasks.py +68 -3
  193. django_cfg/modules/django_telegram.py +3 -3
  194. django_cfg/modules/django_twilio/sendgrid_service.py +2 -2
  195. django_cfg/modules/django_twilio/service.py +2 -2
  196. django_cfg/modules/django_twilio/simple_service.py +2 -2
  197. django_cfg/modules/django_twilio/templates/guide.md +266 -0
  198. django_cfg/modules/django_twilio/twilio_service.py +2 -2
  199. django_cfg/modules/django_unfold/__init__.py +69 -0
  200. django_cfg/modules/{unfold → django_unfold}/callbacks.py +23 -22
  201. django_cfg/modules/django_unfold/dashboard.py +278 -0
  202. django_cfg/modules/django_unfold/icons/README.md +145 -0
  203. django_cfg/modules/django_unfold/icons/__init__.py +12 -0
  204. django_cfg/modules/django_unfold/icons/constants.py +2851 -0
  205. django_cfg/modules/django_unfold/icons/generate_icons.py +486 -0
  206. django_cfg/modules/django_unfold/models/__init__.py +42 -0
  207. django_cfg/modules/django_unfold/models/config.py +601 -0
  208. django_cfg/modules/django_unfold/models/dashboard.py +206 -0
  209. django_cfg/modules/django_unfold/models/dropdown.py +40 -0
  210. django_cfg/modules/django_unfold/models/navigation.py +73 -0
  211. django_cfg/modules/django_unfold/models/tabs.py +25 -0
  212. django_cfg/modules/{unfold → django_unfold}/system_monitor.py +2 -2
  213. django_cfg/modules/django_unfold/utils.py +140 -0
  214. django_cfg/registry/__init__.py +23 -0
  215. django_cfg/registry/core.py +61 -0
  216. django_cfg/registry/exceptions.py +11 -0
  217. django_cfg/registry/modules.py +12 -0
  218. django_cfg/registry/services.py +26 -0
  219. django_cfg/registry/third_party.py +52 -0
  220. django_cfg/routing/__init__.py +19 -0
  221. django_cfg/routing/callbacks.py +198 -0
  222. django_cfg/routing/routers.py +48 -0
  223. django_cfg/templates/admin/layouts/dashboard_with_tabs.html +8 -9
  224. django_cfg/templatetags/__init__.py +0 -0
  225. django_cfg/templatetags/django_cfg.py +33 -0
  226. django_cfg/urls.py +33 -0
  227. django_cfg/utils/path_resolution.py +1 -1
  228. django_cfg/utils/smart_defaults.py +7 -61
  229. django_cfg/utils/toolkit.py +663 -0
  230. {django_cfg-1.1.81.dist-info → django_cfg-1.2.0.dist-info}/METADATA +83 -86
  231. django_cfg-1.2.0.dist-info/RECORD +441 -0
  232. django_cfg/apps/tasks/@docs/README.md +0 -195
  233. django_cfg/archive/django_sample.zip +0 -0
  234. django_cfg/models/unfold.py +0 -271
  235. django_cfg/modules/unfold/__init__.py +0 -29
  236. django_cfg/modules/unfold/dashboard.py +0 -318
  237. django_cfg/pyproject.toml +0 -370
  238. django_cfg/routers.py +0 -83
  239. django_cfg-1.1.81.dist-info/RECORD +0 -278
  240. /django_cfg/{exceptions.py → core/exceptions.py} +0 -0
  241. /django_cfg/modules/{unfold → django_unfold}/models.py +0 -0
  242. /django_cfg/modules/{unfold → django_unfold}/tailwind.py +0 -0
  243. /django_cfg/{version_check.py → utils/version_check.py} +0 -0
  244. {django_cfg-1.1.81.dist-info → django_cfg-1.2.0.dist-info}/WHEEL +0 -0
  245. {django_cfg-1.1.81.dist-info → django_cfg-1.2.0.dist-info}/entry_points.txt +0 -0
  246. {django_cfg-1.1.81.dist-info → django_cfg-1.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,220 @@
1
+ """
2
+ Django models for agent registry and configuration.
3
+ """
4
+
5
+ from django.db import models
6
+ from django.conf import settings
7
+ from django.core.exceptions import ValidationError
8
+ import json
9
+
10
+
11
+ class AgentDefinition(models.Model):
12
+ """Registry of available agents with their configurations."""
13
+
14
+ name = models.CharField(max_length=100, unique=True, db_index=True)
15
+ display_name = models.CharField(max_length=200, blank=True)
16
+ description = models.TextField()
17
+ instructions = models.TextField(help_text="System prompt for the agent")
18
+
19
+ # Type information
20
+ deps_type = models.CharField(max_length=100, help_text="Python class name for dependencies")
21
+ output_type = models.CharField(max_length=100, help_text="Python class name for output")
22
+
23
+ # Model configuration
24
+ model = models.CharField(max_length=100, default='openai:gpt-4o-mini')
25
+ timeout = models.PositiveIntegerField(default=300, help_text="Timeout in seconds")
26
+ max_retries = models.PositiveIntegerField(default=3)
27
+ enable_caching = models.BooleanField(default=True)
28
+
29
+ # Tools configuration
30
+ tools_config = models.JSONField(
31
+ default=dict,
32
+ blank=True,
33
+ help_text="Configuration for agent tools"
34
+ )
35
+
36
+ # Permissions and access control
37
+ is_active = models.BooleanField(default=True, db_index=True)
38
+ is_public = models.BooleanField(default=False, help_text="Available to all users")
39
+ allowed_users = models.ManyToManyField(
40
+ settings.AUTH_USER_MODEL,
41
+ blank=True,
42
+ related_name='allowed_agents',
43
+ help_text="Users allowed to use this agent"
44
+ )
45
+ allowed_groups = models.ManyToManyField(
46
+ 'auth.Group',
47
+ blank=True,
48
+ related_name='allowed_agents',
49
+ help_text="Groups allowed to use this agent"
50
+ )
51
+
52
+ # Metadata
53
+ category = models.CharField(max_length=50, blank=True, db_index=True)
54
+ tags = models.JSONField(default=list, blank=True, help_text="List of tags")
55
+ version = models.CharField(max_length=20, default='1.0.0')
56
+
57
+ # Audit fields
58
+ created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='created_agents')
59
+ created_at = models.DateTimeField(auto_now_add=True)
60
+ updated_at = models.DateTimeField(auto_now=True)
61
+
62
+ # Usage statistics
63
+ usage_count = models.PositiveIntegerField(default=0)
64
+ last_used_at = models.DateTimeField(null=True, blank=True)
65
+
66
+ # Custom managers
67
+ from ..managers.registry import AgentDefinitionManager
68
+ objects = AgentDefinitionManager()
69
+
70
+ class Meta:
71
+ db_table = 'orchestrator_agent_definitions'
72
+ indexes = [
73
+ models.Index(fields=['is_active', 'category']),
74
+ models.Index(fields=['created_by', '-created_at']),
75
+ models.Index(fields=['-usage_count']),
76
+ ]
77
+ ordering = ['name']
78
+
79
+ def __str__(self):
80
+ return f"AgentDefinition({self.name})"
81
+
82
+ def clean(self):
83
+ """Validate agent definition."""
84
+ super().clean()
85
+
86
+ # Validate tools_config is valid JSON
87
+ if self.tools_config:
88
+ try:
89
+ if isinstance(self.tools_config, str):
90
+ json.loads(self.tools_config)
91
+ except json.JSONDecodeError:
92
+ raise ValidationError({'tools_config': 'Invalid JSON format'})
93
+
94
+ # Validate tags is a list
95
+ if self.tags and not isinstance(self.tags, list):
96
+ raise ValidationError({'tags': 'Tags must be a list'})
97
+
98
+ # Validate timeout range
99
+ if self.timeout < 1 or self.timeout > 3600:
100
+ raise ValidationError({'timeout': 'Timeout must be between 1 and 3600 seconds'})
101
+
102
+ # Validate max_retries range
103
+ if self.max_retries < 0 or self.max_retries > 10:
104
+ raise ValidationError({'max_retries': 'Max retries must be between 0 and 10'})
105
+
106
+ def save(self, *args, **kwargs):
107
+ # Set display_name if not provided
108
+ if not self.display_name:
109
+ self.display_name = self.name.replace('_', ' ').title()
110
+
111
+ # Clean and validate
112
+ self.full_clean()
113
+
114
+ super().save(*args, **kwargs)
115
+
116
+ def can_be_used_by(self, user) -> bool:
117
+ """Check if user can use this agent."""
118
+ if not self.is_active:
119
+ return False
120
+
121
+ if self.is_public:
122
+ return True
123
+
124
+ if user == self.created_by:
125
+ return True
126
+
127
+ if self.allowed_users.filter(id=user.id).exists():
128
+ return True
129
+
130
+ if self.allowed_groups.filter(user__id=user.id).exists():
131
+ return True
132
+
133
+ return False
134
+
135
+ def increment_usage(self):
136
+ """Increment usage count and update last used timestamp."""
137
+ from django.utils import timezone
138
+ self.usage_count += 1
139
+ self.last_used_at = timezone.now()
140
+ self.save(update_fields=['usage_count', 'last_used_at'])
141
+
142
+ def to_dict(self) -> dict:
143
+ """Convert to dictionary for serialization."""
144
+ return {
145
+ 'name': self.name,
146
+ 'display_name': self.display_name,
147
+ 'description': self.description,
148
+ 'instructions': self.instructions,
149
+ 'deps_type': self.deps_type,
150
+ 'output_type': self.output_type,
151
+ 'model': self.model,
152
+ 'timeout': self.timeout,
153
+ 'max_retries': self.max_retries,
154
+ 'enable_caching': self.enable_caching,
155
+ 'tools_config': self.tools_config,
156
+ 'is_active': self.is_active,
157
+ 'category': self.category,
158
+ 'tags': self.tags,
159
+ 'version': self.version,
160
+ 'usage_count': self.usage_count,
161
+ 'created_at': self.created_at.isoformat() if self.created_at else None,
162
+ 'updated_at': self.updated_at.isoformat() if self.updated_at else None,
163
+ }
164
+
165
+
166
+
167
+ class AgentTemplate(models.Model):
168
+ """Templates for creating new agents."""
169
+
170
+ name = models.CharField(max_length=100, unique=True)
171
+ description = models.TextField()
172
+
173
+ # Template configuration
174
+ template_config = models.JSONField(help_text="Template configuration")
175
+ default_instructions = models.TextField()
176
+ recommended_model = models.CharField(max_length=100, default='openai:gpt-4o-mini')
177
+
178
+ # Categorization
179
+ category = models.CharField(max_length=50, db_index=True)
180
+ use_cases = models.JSONField(default=list, help_text="List of use cases")
181
+
182
+ # Metadata
183
+ created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
184
+ created_at = models.DateTimeField(auto_now_add=True)
185
+ updated_at = models.DateTimeField(auto_now=True)
186
+ is_active = models.BooleanField(default=True)
187
+
188
+ # Custom managers
189
+ from ..managers.registry import AgentTemplateManager
190
+ objects = AgentTemplateManager()
191
+
192
+ class Meta:
193
+ db_table = 'orchestrator_agent_templates'
194
+ ordering = ['category', 'name']
195
+
196
+ def __str__(self):
197
+ return f"AgentTemplate({self.name})"
198
+
199
+ def create_agent_definition(
200
+ self,
201
+ name: str,
202
+ user,
203
+ custom_instructions: str = None
204
+ ) -> AgentDefinition:
205
+ """Create agent definition from template."""
206
+ config = self.template_config.copy()
207
+
208
+ return AgentDefinition.objects.create(
209
+ name=name,
210
+ description=self.description,
211
+ instructions=custom_instructions or self.default_instructions,
212
+ deps_type=config.get('deps_type', 'DjangoDeps'),
213
+ output_type=config.get('output_type', 'ProcessResult'),
214
+ model=config.get('model', self.recommended_model),
215
+ timeout=config.get('timeout', 300),
216
+ max_retries=config.get('max_retries', 3),
217
+ tools_config=config.get('tools_config', {}),
218
+ category=self.category,
219
+ created_by=user
220
+ )
@@ -0,0 +1,305 @@
1
+ """
2
+ Django models for toolset management and tool execution tracking.
3
+ """
4
+
5
+ import uuid
6
+ from django.db import models
7
+ from django.conf import settings
8
+ from django.utils import timezone
9
+
10
+
11
+ class ToolExecution(models.Model):
12
+ """Track tool executions within agent runs."""
13
+
14
+ class Status(models.TextChoices):
15
+ PENDING = 'pending', 'Pending'
16
+ RUNNING = 'running', 'Running'
17
+ COMPLETED = 'completed', 'Completed'
18
+ FAILED = 'failed', 'Failed'
19
+
20
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
21
+
22
+ # Context
23
+ user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
24
+ agent_execution = models.ForeignKey(
25
+ 'AgentExecution',
26
+ on_delete=models.CASCADE,
27
+ related_name='tool_executions'
28
+ )
29
+
30
+ # Tool information
31
+ tool_name = models.CharField(max_length=100, db_index=True)
32
+ toolset_name = models.CharField(max_length=100, blank=True)
33
+
34
+ # Execution data
35
+ status = models.CharField(
36
+ max_length=20,
37
+ choices=Status.choices,
38
+ default=Status.PENDING,
39
+ db_index=True
40
+ )
41
+ arguments = models.JSONField(help_text="Tool arguments")
42
+ result = models.JSONField(null=True, blank=True, help_text="Tool execution result")
43
+ error_message = models.TextField(blank=True)
44
+
45
+ # Metrics
46
+ execution_time = models.FloatField(null=True, blank=True)
47
+ retry_count = models.PositiveIntegerField(default=0)
48
+
49
+ # Timestamps
50
+ created_at = models.DateTimeField(auto_now_add=True)
51
+ started_at = models.DateTimeField(null=True, blank=True)
52
+ completed_at = models.DateTimeField(null=True, blank=True)
53
+
54
+ # Custom managers
55
+ from ..managers.toolsets import ToolExecutionManager
56
+ objects = ToolExecutionManager()
57
+
58
+ class Meta:
59
+ db_table = 'orchestrator_tool_executions'
60
+ indexes = [
61
+ models.Index(fields=['tool_name', 'status']),
62
+ models.Index(fields=['user', '-created_at']),
63
+ models.Index(fields=['agent_execution', 'created_at']),
64
+ ]
65
+ ordering = ['-created_at']
66
+
67
+ def __str__(self):
68
+ return f"ToolExecution({self.tool_name}, {self.status})"
69
+
70
+ def save(self, *args, **kwargs):
71
+ # Auto-set timestamps based on status
72
+ if self.status == self.Status.RUNNING and not self.started_at:
73
+ self.started_at = timezone.now()
74
+ elif self.status in [self.Status.COMPLETED, self.Status.FAILED] and not self.completed_at:
75
+ self.completed_at = timezone.now()
76
+
77
+ super().save(*args, **kwargs)
78
+
79
+ @property
80
+ def duration(self):
81
+ """Calculate execution duration."""
82
+ if self.started_at and self.completed_at:
83
+ return (self.completed_at - self.started_at).total_seconds()
84
+ return None
85
+
86
+ @property
87
+ def is_successful(self):
88
+ """Check if execution was successful."""
89
+ return self.status == self.Status.COMPLETED and not self.error_message
90
+
91
+
92
+ class ApprovalLog(models.Model):
93
+ """Log approval decisions for tool executions."""
94
+
95
+ class Status(models.TextChoices):
96
+ PENDING = 'pending', 'Pending'
97
+ APPROVED = 'approved', 'Approved'
98
+ REJECTED = 'rejected', 'Rejected'
99
+ EXPIRED = 'expired', 'Expired'
100
+
101
+ id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
102
+ approval_id = models.CharField(max_length=100, unique=True, db_index=True)
103
+
104
+ # Request context
105
+ user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='approval_requests')
106
+ tool_name = models.CharField(max_length=100)
107
+ tool_args = models.JSONField()
108
+ justification = models.TextField(blank=True)
109
+
110
+ # Approval decision
111
+ status = models.CharField(
112
+ max_length=20,
113
+ choices=Status.choices,
114
+ default=Status.PENDING,
115
+ db_index=True
116
+ )
117
+ approved_by = models.ForeignKey(
118
+ settings.AUTH_USER_MODEL,
119
+ on_delete=models.SET_NULL,
120
+ null=True,
121
+ blank=True,
122
+ related_name='approvals_given'
123
+ )
124
+ rejected_by = models.ForeignKey(
125
+ settings.AUTH_USER_MODEL,
126
+ on_delete=models.SET_NULL,
127
+ null=True,
128
+ blank=True,
129
+ related_name='rejections_given'
130
+ )
131
+ rejection_reason = models.TextField(blank=True)
132
+
133
+ # Timestamps
134
+ requested_at = models.DateTimeField(auto_now_add=True)
135
+ decided_at = models.DateTimeField(null=True, blank=True)
136
+ expires_at = models.DateTimeField(null=True, blank=True)
137
+
138
+ # Custom managers
139
+ from ..managers.toolsets import ApprovalLogManager
140
+ objects = ApprovalLogManager()
141
+
142
+ class Meta:
143
+ db_table = 'orchestrator_approval_logs'
144
+ indexes = [
145
+ models.Index(fields=['status', 'requested_at']),
146
+ models.Index(fields=['user', '-requested_at']),
147
+ models.Index(fields=['approved_by', '-decided_at']),
148
+ ]
149
+ ordering = ['-requested_at']
150
+
151
+ def __str__(self):
152
+ return f"ApprovalLog({self.approval_id}, {self.status})"
153
+
154
+ def save(self, *args, **kwargs):
155
+ # Auto-set decided_at timestamp
156
+ if self.status in [self.Status.APPROVED, self.Status.REJECTED] and not self.decided_at:
157
+ self.decided_at = timezone.now()
158
+
159
+ super().save(*args, **kwargs)
160
+
161
+ @property
162
+ def is_expired(self):
163
+ """Check if approval request has expired."""
164
+ if self.expires_at:
165
+ return timezone.now() > self.expires_at
166
+ return False
167
+
168
+ @property
169
+ def time_to_decision(self):
170
+ """Calculate time from request to decision."""
171
+ if self.decided_at:
172
+ return (self.decided_at - self.requested_at).total_seconds()
173
+ return None
174
+
175
+ def approve(self, approver):
176
+ """Approve the request."""
177
+ self.status = self.Status.APPROVED
178
+ self.approved_by = approver
179
+ self.decided_at = timezone.now()
180
+ self.save()
181
+
182
+ def reject(self, rejector, reason: str = ""):
183
+ """Reject the request."""
184
+ self.status = self.Status.REJECTED
185
+ self.rejected_by = rejector
186
+ self.rejection_reason = reason
187
+ self.decided_at = timezone.now()
188
+ self.save()
189
+
190
+
191
+ class ToolsetConfiguration(models.Model):
192
+ """Configuration for toolsets."""
193
+
194
+ name = models.CharField(max_length=100, unique=True)
195
+ description = models.TextField()
196
+
197
+ # Configuration
198
+ toolset_class = models.CharField(max_length=200, help_text="Python class path")
199
+ config = models.JSONField(default=dict, help_text="Toolset configuration")
200
+
201
+ # Access control
202
+ is_active = models.BooleanField(default=True)
203
+ allowed_users = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='allowed_toolsets')
204
+ allowed_groups = models.ManyToManyField('auth.Group', blank=True, related_name='allowed_toolsets')
205
+
206
+ # Metadata
207
+ created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
208
+ created_at = models.DateTimeField(auto_now_add=True)
209
+ updated_at = models.DateTimeField(auto_now=True)
210
+
211
+ # Custom managers
212
+ from ..managers.toolsets import ToolsetConfigurationManager
213
+ objects = ToolsetConfigurationManager()
214
+
215
+ class Meta:
216
+ db_table = 'orchestrator_toolset_configurations'
217
+ ordering = ['name']
218
+
219
+ def __str__(self):
220
+ return f"ToolsetConfiguration({self.name})"
221
+
222
+ def can_be_used_by(self, user) -> bool:
223
+ """Check if user can use this toolset."""
224
+ if not self.is_active:
225
+ return False
226
+
227
+ if user == self.created_by:
228
+ return True
229
+
230
+ if self.allowed_users.filter(id=user.id).exists():
231
+ return True
232
+
233
+ if self.allowed_groups.filter(user__id=user.id).exists():
234
+ return True
235
+
236
+ return False
237
+
238
+
239
+ class ToolPermission(models.Model):
240
+ """Permissions for specific tools."""
241
+
242
+ class Permission(models.TextChoices):
243
+ ALLOW = 'allow', 'Allow'
244
+ DENY = 'deny', 'Deny'
245
+ REQUIRE_APPROVAL = 'require_approval', 'Require Approval'
246
+
247
+ user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
248
+ tool_name = models.CharField(max_length=100, db_index=True)
249
+ permission = models.CharField(
250
+ max_length=20,
251
+ choices=Permission.choices,
252
+ default=Permission.ALLOW
253
+ )
254
+
255
+ # Optional conditions
256
+ conditions = models.JSONField(
257
+ default=dict,
258
+ blank=True,
259
+ help_text="Conditions for permission (e.g., argument limits)"
260
+ )
261
+
262
+ # Metadata
263
+ created_by = models.ForeignKey(
264
+ settings.AUTH_USER_MODEL,
265
+ on_delete=models.CASCADE,
266
+ related_name='tool_permissions_created'
267
+ )
268
+ created_at = models.DateTimeField(auto_now_add=True)
269
+
270
+ # Custom managers
271
+ from ..managers.toolsets import ToolPermissionManager
272
+ objects = ToolPermissionManager()
273
+
274
+ class Meta:
275
+ db_table = 'orchestrator_tool_permissions'
276
+ unique_together = ['user', 'tool_name']
277
+ indexes = [
278
+ models.Index(fields=['user', 'tool_name']),
279
+ models.Index(fields=['tool_name', 'permission']),
280
+ ]
281
+
282
+ def __str__(self):
283
+ return f"ToolPermission({self.user.username}, {self.tool_name}, {self.permission})"
284
+
285
+ def check_conditions(self, tool_args: dict) -> bool:
286
+ """Check if tool arguments meet permission conditions."""
287
+ if not self.conditions:
288
+ return True
289
+
290
+ # Implement condition checking logic
291
+ # This is a simple example - extend as needed
292
+ for condition_key, condition_value in self.conditions.items():
293
+ if condition_key in tool_args:
294
+ arg_value = tool_args[condition_key]
295
+
296
+ # Simple equality check
297
+ if isinstance(condition_value, dict):
298
+ if 'max' in condition_value and arg_value > condition_value['max']:
299
+ return False
300
+ if 'min' in condition_value and arg_value < condition_value['min']:
301
+ return False
302
+ elif arg_value != condition_value:
303
+ return False
304
+
305
+ return True
@@ -0,0 +1,24 @@
1
+ """
2
+ Pre-built agent patterns for common use cases.
3
+ """
4
+
5
+ from .content_agents import ContentAnalyzerAgent, ContentGeneratorAgent, ContentValidatorAgent
6
+ from .data_agents import DataProcessorAgent, DataValidatorAgent, DataTransformerAgent
7
+ from .business_agents import BusinessRuleAgent, WorkflowAgent, DecisionAgent
8
+
9
+ __all__ = [
10
+ # Content patterns
11
+ "ContentAnalyzerAgent",
12
+ "ContentGeneratorAgent",
13
+ "ContentValidatorAgent",
14
+
15
+ # Data patterns
16
+ "DataProcessorAgent",
17
+ "DataValidatorAgent",
18
+ "DataTransformerAgent",
19
+
20
+ # Business patterns
21
+ "BusinessRuleAgent",
22
+ "WorkflowAgent",
23
+ "DecisionAgent",
24
+ ]