django-cfg 1.1.82__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.
- django_cfg/__init__.py +20 -448
- django_cfg/apps/accounts/README.md +3 -3
- django_cfg/apps/accounts/admin/__init__.py +0 -2
- django_cfg/apps/accounts/admin/activity.py +2 -9
- django_cfg/apps/accounts/admin/filters.py +0 -42
- django_cfg/apps/accounts/admin/inlines.py +8 -8
- django_cfg/apps/accounts/admin/otp.py +5 -5
- django_cfg/apps/accounts/admin/registration_source.py +1 -8
- django_cfg/apps/accounts/admin/user.py +12 -20
- django_cfg/apps/accounts/managers/user_manager.py +2 -129
- django_cfg/apps/accounts/migrations/0006_remove_twilioresponse_otp_secret_and_more.py +46 -0
- django_cfg/apps/accounts/models.py +3 -123
- django_cfg/apps/accounts/serializers/otp.py +40 -44
- django_cfg/apps/accounts/serializers/profile.py +0 -2
- django_cfg/apps/accounts/services/otp_service.py +98 -186
- django_cfg/apps/accounts/signals.py +25 -15
- django_cfg/apps/accounts/utils/auth_email_service.py +84 -0
- django_cfg/apps/accounts/views/otp.py +35 -36
- django_cfg/apps/agents/README.md +129 -0
- django_cfg/apps/agents/__init__.py +68 -0
- django_cfg/apps/agents/admin/__init__.py +17 -0
- django_cfg/apps/agents/admin/execution_admin.py +460 -0
- django_cfg/apps/agents/admin/registry_admin.py +360 -0
- django_cfg/apps/agents/admin/toolsets_admin.py +482 -0
- django_cfg/apps/agents/apps.py +29 -0
- django_cfg/apps/agents/core/__init__.py +20 -0
- django_cfg/apps/agents/core/agent.py +281 -0
- django_cfg/apps/agents/core/dependencies.py +154 -0
- django_cfg/apps/agents/core/exceptions.py +66 -0
- django_cfg/apps/agents/core/models.py +106 -0
- django_cfg/apps/agents/core/orchestrator.py +391 -0
- django_cfg/apps/agents/examples/__init__.py +3 -0
- django_cfg/apps/agents/examples/simple_example.py +161 -0
- django_cfg/apps/agents/integration/__init__.py +14 -0
- django_cfg/apps/agents/integration/middleware.py +80 -0
- django_cfg/apps/agents/integration/registry.py +345 -0
- django_cfg/apps/agents/integration/signals.py +50 -0
- django_cfg/apps/agents/management/__init__.py +3 -0
- django_cfg/apps/agents/management/commands/__init__.py +3 -0
- django_cfg/apps/agents/management/commands/create_agent.py +365 -0
- django_cfg/apps/agents/management/commands/orchestrator_status.py +191 -0
- django_cfg/apps/agents/managers/__init__.py +23 -0
- django_cfg/apps/agents/managers/execution.py +236 -0
- django_cfg/apps/agents/managers/registry.py +254 -0
- django_cfg/apps/agents/managers/toolsets.py +496 -0
- django_cfg/apps/agents/migrations/0001_initial.py +286 -0
- django_cfg/apps/agents/migrations/__init__.py +5 -0
- django_cfg/apps/agents/models/__init__.py +15 -0
- django_cfg/apps/agents/models/execution.py +215 -0
- django_cfg/apps/agents/models/registry.py +220 -0
- django_cfg/apps/agents/models/toolsets.py +305 -0
- django_cfg/apps/agents/patterns/__init__.py +24 -0
- django_cfg/apps/agents/patterns/content_agents.py +234 -0
- django_cfg/apps/agents/toolsets/__init__.py +15 -0
- django_cfg/apps/agents/toolsets/cache_toolset.py +285 -0
- django_cfg/apps/agents/toolsets/django_toolset.py +220 -0
- django_cfg/apps/agents/toolsets/file_toolset.py +324 -0
- django_cfg/apps/agents/toolsets/orm_toolset.py +319 -0
- django_cfg/apps/agents/urls.py +46 -0
- django_cfg/apps/knowbase/README.md +150 -0
- django_cfg/apps/knowbase/__init__.py +27 -0
- django_cfg/apps/knowbase/admin/__init__.py +23 -0
- django_cfg/apps/knowbase/admin/archive_admin.py +857 -0
- django_cfg/apps/knowbase/admin/chat_admin.py +386 -0
- django_cfg/apps/knowbase/admin/document_admin.py +650 -0
- django_cfg/apps/knowbase/admin/external_data_admin.py +685 -0
- django_cfg/apps/knowbase/apps.py +81 -0
- django_cfg/apps/knowbase/config/README.md +176 -0
- django_cfg/apps/knowbase/config/__init__.py +51 -0
- django_cfg/apps/knowbase/config/constance_fields.py +186 -0
- django_cfg/apps/knowbase/config/constance_settings.py +200 -0
- django_cfg/apps/knowbase/config/settings.py +444 -0
- django_cfg/apps/knowbase/examples/__init__.py +3 -0
- django_cfg/apps/knowbase/examples/external_data_usage.py +191 -0
- django_cfg/apps/knowbase/management/__init__.py +0 -0
- django_cfg/apps/knowbase/management/commands/__init__.py +0 -0
- django_cfg/apps/knowbase/management/commands/knowbase_stats.py +158 -0
- django_cfg/apps/knowbase/management/commands/setup_knowbase.py +59 -0
- django_cfg/apps/knowbase/managers/__init__.py +22 -0
- django_cfg/apps/knowbase/managers/archive.py +426 -0
- django_cfg/apps/knowbase/managers/base.py +32 -0
- django_cfg/apps/knowbase/managers/chat.py +141 -0
- django_cfg/apps/knowbase/managers/document.py +203 -0
- django_cfg/apps/knowbase/managers/external_data.py +471 -0
- django_cfg/apps/knowbase/migrations/0001_initial.py +427 -0
- django_cfg/apps/knowbase/migrations/0002_archiveitem_archiveitemchunk_documentarchive_and_more.py +434 -0
- django_cfg/apps/knowbase/migrations/__init__.py +5 -0
- django_cfg/apps/knowbase/mixins/__init__.py +15 -0
- django_cfg/apps/knowbase/mixins/config.py +108 -0
- django_cfg/apps/knowbase/mixins/creator.py +81 -0
- django_cfg/apps/knowbase/mixins/examples/vehicle_model_example.py +199 -0
- django_cfg/apps/knowbase/mixins/external_data_mixin.py +813 -0
- django_cfg/apps/knowbase/mixins/service.py +362 -0
- django_cfg/apps/knowbase/models/__init__.py +41 -0
- django_cfg/apps/knowbase/models/archive.py +599 -0
- django_cfg/apps/knowbase/models/base.py +58 -0
- django_cfg/apps/knowbase/models/chat.py +157 -0
- django_cfg/apps/knowbase/models/document.py +267 -0
- django_cfg/apps/knowbase/models/external_data.py +376 -0
- django_cfg/apps/knowbase/serializers/__init__.py +68 -0
- django_cfg/apps/knowbase/serializers/archive_serializers.py +386 -0
- django_cfg/apps/knowbase/serializers/chat_serializers.py +137 -0
- django_cfg/apps/knowbase/serializers/document_serializers.py +94 -0
- django_cfg/apps/knowbase/serializers/external_data_serializers.py +256 -0
- django_cfg/apps/knowbase/serializers/public_serializers.py +74 -0
- django_cfg/apps/knowbase/services/__init__.py +40 -0
- django_cfg/apps/knowbase/services/archive/__init__.py +42 -0
- django_cfg/apps/knowbase/services/archive/archive_service.py +541 -0
- django_cfg/apps/knowbase/services/archive/chunking_service.py +791 -0
- django_cfg/apps/knowbase/services/archive/exceptions.py +52 -0
- django_cfg/apps/knowbase/services/archive/extraction_service.py +508 -0
- django_cfg/apps/knowbase/services/archive/vectorization_service.py +362 -0
- django_cfg/apps/knowbase/services/base.py +53 -0
- django_cfg/apps/knowbase/services/chat_service.py +239 -0
- django_cfg/apps/knowbase/services/document_service.py +144 -0
- django_cfg/apps/knowbase/services/embedding/__init__.py +43 -0
- django_cfg/apps/knowbase/services/embedding/async_processor.py +244 -0
- django_cfg/apps/knowbase/services/embedding/batch_processor.py +250 -0
- django_cfg/apps/knowbase/services/embedding/batch_result.py +61 -0
- django_cfg/apps/knowbase/services/embedding/models.py +229 -0
- django_cfg/apps/knowbase/services/embedding/processors.py +148 -0
- django_cfg/apps/knowbase/services/embedding/utils.py +176 -0
- django_cfg/apps/knowbase/services/prompt_builder.py +191 -0
- django_cfg/apps/knowbase/services/search_service.py +293 -0
- django_cfg/apps/knowbase/signals/__init__.py +21 -0
- django_cfg/apps/knowbase/signals/archive_signals.py +211 -0
- django_cfg/apps/knowbase/signals/chat_signals.py +37 -0
- django_cfg/apps/knowbase/signals/document_signals.py +143 -0
- django_cfg/apps/knowbase/signals/external_data_signals.py +157 -0
- django_cfg/apps/knowbase/tasks/__init__.py +39 -0
- django_cfg/apps/knowbase/tasks/archive_tasks.py +316 -0
- django_cfg/apps/knowbase/tasks/document_processing.py +341 -0
- django_cfg/apps/knowbase/tasks/external_data_tasks.py +341 -0
- django_cfg/apps/knowbase/tasks/maintenance.py +195 -0
- django_cfg/apps/knowbase/urls.py +43 -0
- django_cfg/apps/knowbase/utils/__init__.py +12 -0
- django_cfg/apps/knowbase/utils/chunk_settings.py +261 -0
- django_cfg/apps/knowbase/utils/text_processing.py +375 -0
- django_cfg/apps/knowbase/utils/validation.py +99 -0
- django_cfg/apps/knowbase/views/__init__.py +28 -0
- django_cfg/apps/knowbase/views/archive_views.py +469 -0
- django_cfg/apps/knowbase/views/base.py +49 -0
- django_cfg/apps/knowbase/views/chat_views.py +181 -0
- django_cfg/apps/knowbase/views/document_views.py +183 -0
- django_cfg/apps/knowbase/views/public_views.py +129 -0
- django_cfg/apps/leads/admin.py +70 -0
- django_cfg/apps/newsletter/admin.py +234 -0
- django_cfg/apps/newsletter/admin_filters.py +124 -0
- django_cfg/apps/support/admin.py +196 -0
- django_cfg/apps/support/admin_filters.py +71 -0
- django_cfg/apps/support/templates/support/chat/ticket_chat.html +1 -1
- django_cfg/apps/urls.py +5 -4
- django_cfg/cli/README.md +1 -1
- django_cfg/cli/commands/create_project.py +2 -2
- django_cfg/cli/commands/info.py +1 -1
- django_cfg/config.py +44 -0
- django_cfg/core/config.py +29 -82
- django_cfg/core/environment.py +1 -1
- django_cfg/core/generation.py +19 -107
- django_cfg/{integration.py → core/integration.py} +18 -16
- django_cfg/core/validation.py +1 -1
- django_cfg/management/__init__.py +1 -1
- django_cfg/management/commands/__init__.py +1 -1
- django_cfg/management/commands/auto_generate.py +482 -0
- django_cfg/management/commands/migrator.py +19 -101
- django_cfg/management/commands/test_email.py +1 -1
- django_cfg/middleware/README.md +0 -158
- django_cfg/middleware/__init__.py +0 -2
- django_cfg/middleware/user_activity.py +3 -3
- django_cfg/models/api.py +145 -0
- django_cfg/models/base.py +287 -0
- django_cfg/models/cache.py +4 -4
- django_cfg/models/constance.py +25 -88
- django_cfg/models/database.py +9 -9
- django_cfg/models/drf.py +3 -36
- django_cfg/models/email.py +163 -0
- django_cfg/models/environment.py +276 -0
- django_cfg/models/limits.py +1 -1
- django_cfg/models/logging.py +366 -0
- django_cfg/models/revolution.py +41 -2
- django_cfg/models/security.py +125 -0
- django_cfg/models/services.py +1 -1
- django_cfg/modules/__init__.py +2 -56
- django_cfg/modules/base.py +78 -52
- django_cfg/modules/django_currency/service.py +2 -2
- django_cfg/modules/django_email.py +2 -2
- django_cfg/modules/django_health.py +267 -0
- django_cfg/modules/django_llm/llm/client.py +79 -17
- django_cfg/modules/django_llm/translator/translator.py +2 -2
- django_cfg/modules/django_logger.py +2 -2
- django_cfg/modules/django_ngrok.py +2 -2
- django_cfg/modules/django_tasks.py +68 -3
- django_cfg/modules/django_telegram.py +3 -3
- django_cfg/modules/django_twilio/sendgrid_service.py +2 -2
- django_cfg/modules/django_twilio/service.py +2 -2
- django_cfg/modules/django_twilio/simple_service.py +2 -2
- django_cfg/modules/django_twilio/twilio_service.py +2 -2
- django_cfg/modules/django_unfold/__init__.py +69 -0
- django_cfg/modules/{unfold → django_unfold}/callbacks.py +23 -22
- django_cfg/modules/django_unfold/dashboard.py +278 -0
- django_cfg/modules/django_unfold/icons/README.md +145 -0
- django_cfg/modules/django_unfold/icons/__init__.py +12 -0
- django_cfg/modules/django_unfold/icons/constants.py +2851 -0
- django_cfg/modules/django_unfold/icons/generate_icons.py +486 -0
- django_cfg/modules/django_unfold/models/__init__.py +42 -0
- django_cfg/modules/django_unfold/models/config.py +601 -0
- django_cfg/modules/django_unfold/models/dashboard.py +206 -0
- django_cfg/modules/django_unfold/models/dropdown.py +40 -0
- django_cfg/modules/django_unfold/models/navigation.py +73 -0
- django_cfg/modules/django_unfold/models/tabs.py +25 -0
- django_cfg/modules/{unfold → django_unfold}/system_monitor.py +2 -2
- django_cfg/modules/django_unfold/utils.py +140 -0
- django_cfg/registry/__init__.py +23 -0
- django_cfg/registry/core.py +61 -0
- django_cfg/registry/exceptions.py +11 -0
- django_cfg/registry/modules.py +12 -0
- django_cfg/registry/services.py +26 -0
- django_cfg/registry/third_party.py +52 -0
- django_cfg/routing/__init__.py +19 -0
- django_cfg/routing/callbacks.py +198 -0
- django_cfg/routing/routers.py +48 -0
- django_cfg/templates/admin/layouts/dashboard_with_tabs.html +8 -9
- django_cfg/templatetags/__init__.py +0 -0
- django_cfg/templatetags/django_cfg.py +33 -0
- django_cfg/urls.py +33 -0
- django_cfg/utils/path_resolution.py +1 -1
- django_cfg/utils/smart_defaults.py +7 -61
- django_cfg/utils/toolkit.py +663 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/METADATA +83 -86
- django_cfg-1.2.0.dist-info/RECORD +441 -0
- django_cfg/archive/django_sample.zip +0 -0
- django_cfg/models/unfold.py +0 -271
- django_cfg/modules/unfold/__init__.py +0 -29
- django_cfg/modules/unfold/dashboard.py +0 -318
- django_cfg/pyproject.toml +0 -370
- django_cfg/routers.py +0 -83
- django_cfg-1.1.82.dist-info/RECORD +0 -278
- /django_cfg/{exceptions.py → core/exceptions.py} +0 -0
- /django_cfg/modules/{unfold → django_unfold}/models.py +0 -0
- /django_cfg/modules/{unfold → django_unfold}/tailwind.py +0 -0
- /django_cfg/{version_check.py → utils/version_check.py} +0 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/WHEEL +0 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.0.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.1.82.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
|
+
]
|