django-cfg 1.1.82__py3-none-any.whl → 1.2.1__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 +450 -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 +91 -19
- 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.1.dist-info}/METADATA +83 -86
- django_cfg-1.2.1.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.1.dist-info}/WHEEL +0 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.1.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.1.82.dist-info → django_cfg-1.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,360 @@
|
|
1
|
+
"""
|
2
|
+
Registry admin interfaces with Unfold optimization.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from django.contrib import admin, messages
|
6
|
+
from django.utils.html import format_html
|
7
|
+
from django.urls import reverse
|
8
|
+
from django.utils.safestring import mark_safe
|
9
|
+
from django.db import models
|
10
|
+
from django.db.models import Count, Avg, Sum, Q
|
11
|
+
from django.utils import timezone
|
12
|
+
from django.db.models.fields.json import JSONField
|
13
|
+
from datetime import timedelta
|
14
|
+
from django_json_widget.widgets import JSONEditorWidget
|
15
|
+
from unfold.admin import ModelAdmin, TabularInline
|
16
|
+
from unfold.decorators import display, action
|
17
|
+
from unfold.enums import ActionVariant
|
18
|
+
from unfold.contrib.filters.admin import AutocompleteSelectFilter, AutocompleteSelectMultipleFilter
|
19
|
+
from unfold.contrib.forms.widgets import WysiwygWidget
|
20
|
+
|
21
|
+
from ..models.registry import AgentDefinition, AgentTemplate
|
22
|
+
from ..models.execution import AgentExecution
|
23
|
+
|
24
|
+
|
25
|
+
class AgentExecutionInline(TabularInline):
|
26
|
+
"""Inline for agent executions with Unfold styling."""
|
27
|
+
|
28
|
+
model = AgentExecution
|
29
|
+
verbose_name = "Agent Execution"
|
30
|
+
verbose_name_plural = "🚀 Recent Executions (Read-only)"
|
31
|
+
extra = 0
|
32
|
+
max_num = 5 # Show only last 5 executions
|
33
|
+
can_delete = False
|
34
|
+
show_change_link = True
|
35
|
+
|
36
|
+
def has_add_permission(self, request, obj=None):
|
37
|
+
return False
|
38
|
+
|
39
|
+
def has_change_permission(self, request, obj=None):
|
40
|
+
return False
|
41
|
+
|
42
|
+
def has_delete_permission(self, request, obj=None):
|
43
|
+
return False
|
44
|
+
|
45
|
+
fields = [
|
46
|
+
'user', 'status_badge_inline', 'execution_time_display',
|
47
|
+
'tokens_used', 'cost_display_inline', 'created_at'
|
48
|
+
]
|
49
|
+
readonly_fields = [
|
50
|
+
'user', 'status_badge_inline', 'execution_time_display',
|
51
|
+
'tokens_used', 'cost_display_inline', 'created_at'
|
52
|
+
]
|
53
|
+
|
54
|
+
# Unfold specific options
|
55
|
+
hide_title = False
|
56
|
+
classes = ['collapse']
|
57
|
+
|
58
|
+
@display(description="Status")
|
59
|
+
def status_badge_inline(self, obj):
|
60
|
+
"""Status badge for inline display."""
|
61
|
+
colors = {
|
62
|
+
'pending': 'bg-yellow-100 text-yellow-800',
|
63
|
+
'running': 'bg-blue-100 text-blue-800',
|
64
|
+
'completed': 'bg-green-100 text-green-800',
|
65
|
+
'failed': 'bg-red-100 text-red-800',
|
66
|
+
'cancelled': 'bg-gray-100 text-gray-800'
|
67
|
+
}
|
68
|
+
color_class = colors.get(obj.status, 'bg-gray-100 text-gray-800')
|
69
|
+
return format_html(
|
70
|
+
'<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium {}">{}</span>',
|
71
|
+
color_class, obj.get_status_display()
|
72
|
+
)
|
73
|
+
|
74
|
+
@display(description="Execution Time")
|
75
|
+
def execution_time_display(self, obj):
|
76
|
+
"""Execution time display for inline."""
|
77
|
+
if obj.execution_time:
|
78
|
+
return f"{obj.execution_time:.2f}s"
|
79
|
+
return "-"
|
80
|
+
|
81
|
+
@display(description="Cost")
|
82
|
+
def cost_display_inline(self, obj):
|
83
|
+
"""Cost display for inline."""
|
84
|
+
if obj.cost:
|
85
|
+
return f"${obj.cost:.4f}"
|
86
|
+
return "-"
|
87
|
+
|
88
|
+
def get_queryset(self, request):
|
89
|
+
"""Optimize queryset for inline display."""
|
90
|
+
return super().get_queryset(request).select_related('user').order_by('-created_at')
|
91
|
+
|
92
|
+
|
93
|
+
@admin.register(AgentDefinition)
|
94
|
+
class AgentDefinitionAdmin(ModelAdmin):
|
95
|
+
"""Admin interface for AgentDefinition with Unfold styling."""
|
96
|
+
|
97
|
+
list_display = [
|
98
|
+
'name_display', 'display_name', 'category_badge', 'status_badges',
|
99
|
+
'usage_stats', 'performance_indicator', 'created_by', 'created_at'
|
100
|
+
]
|
101
|
+
ordering = ['-created_at']
|
102
|
+
inlines = [AgentExecutionInline]
|
103
|
+
list_filter = [
|
104
|
+
'is_active', 'is_public', 'category', 'enable_caching', 'created_at',
|
105
|
+
('created_by', AutocompleteSelectFilter)
|
106
|
+
]
|
107
|
+
search_fields = ['name', 'display_name', 'description', 'instructions']
|
108
|
+
autocomplete_fields = ['created_by', 'allowed_users', 'allowed_groups']
|
109
|
+
readonly_fields = [
|
110
|
+
'usage_count', 'last_used_at', 'created_at', 'updated_at',
|
111
|
+
'performance_metrics', 'recent_executions_summary'
|
112
|
+
]
|
113
|
+
|
114
|
+
# Unfold form field overrides
|
115
|
+
formfield_overrides = {
|
116
|
+
models.TextField: {"widget": WysiwygWidget},
|
117
|
+
JSONField: {"widget": JSONEditorWidget},
|
118
|
+
}
|
119
|
+
|
120
|
+
fieldsets = (
|
121
|
+
("🤖 Basic Information", {
|
122
|
+
'fields': ('name', 'display_name', 'description', 'category', 'tags'),
|
123
|
+
'classes': ('tab',)
|
124
|
+
}),
|
125
|
+
("⚙️ Configuration", {
|
126
|
+
'fields': ('instructions', 'deps_type', 'output_type', 'model'),
|
127
|
+
'classes': ('tab',)
|
128
|
+
}),
|
129
|
+
("🔧 Execution Settings", {
|
130
|
+
'fields': ('timeout', 'max_retries', 'enable_caching'),
|
131
|
+
'classes': ('tab',)
|
132
|
+
}),
|
133
|
+
("🛠️ Tools & Advanced", {
|
134
|
+
'fields': ('tools_config',),
|
135
|
+
'classes': ('tab', 'collapse')
|
136
|
+
}),
|
137
|
+
("🔐 Access Control", {
|
138
|
+
'fields': ('is_active', 'is_public', 'allowed_users', 'allowed_groups'),
|
139
|
+
'classes': ('tab',)
|
140
|
+
}),
|
141
|
+
("📊 Statistics", {
|
142
|
+
'fields': ('usage_count', 'last_used_at', 'performance_metrics', 'recent_executions_summary'),
|
143
|
+
'classes': ('tab', 'collapse')
|
144
|
+
}),
|
145
|
+
("📝 Metadata", {
|
146
|
+
'fields': ('version', 'created_by', 'created_at', 'updated_at'),
|
147
|
+
'classes': ('tab', 'collapse')
|
148
|
+
}),
|
149
|
+
)
|
150
|
+
|
151
|
+
# Unfold actions
|
152
|
+
actions = ['activate_agents', 'deactivate_agents', 'make_public', 'make_private']
|
153
|
+
|
154
|
+
@display(description="Agent Name")
|
155
|
+
def name_display(self, obj):
|
156
|
+
"""Enhanced name display with icon."""
|
157
|
+
return format_html(
|
158
|
+
'<div class="flex items-center space-x-2">'
|
159
|
+
'<span class="text-blue-600 font-medium">{}</span>'
|
160
|
+
'</div>',
|
161
|
+
obj.name
|
162
|
+
)
|
163
|
+
|
164
|
+
@display(description="Category")
|
165
|
+
def category_badge(self, obj):
|
166
|
+
"""Category with badge styling."""
|
167
|
+
if not obj.category:
|
168
|
+
return "-"
|
169
|
+
return format_html(
|
170
|
+
'<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-purple-100 text-purple-800">{}</span>',
|
171
|
+
obj.category
|
172
|
+
)
|
173
|
+
|
174
|
+
@display(description="Status")
|
175
|
+
def status_badges(self, obj):
|
176
|
+
"""Combined status badges."""
|
177
|
+
badges = []
|
178
|
+
|
179
|
+
if obj.is_active:
|
180
|
+
badges.append('<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800">Active</span>')
|
181
|
+
else:
|
182
|
+
badges.append('<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-red-100 text-red-800">Inactive</span>')
|
183
|
+
|
184
|
+
if obj.is_public:
|
185
|
+
badges.append('<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800">Public</span>')
|
186
|
+
else:
|
187
|
+
badges.append('<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-gray-100 text-gray-800">Private</span>')
|
188
|
+
|
189
|
+
if obj.enable_caching:
|
190
|
+
badges.append('<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">Cached</span>')
|
191
|
+
|
192
|
+
return format_html('<div class="space-y-1">{}</div>', ''.join(badges))
|
193
|
+
|
194
|
+
@display(description="Usage Stats")
|
195
|
+
def usage_stats(self, obj):
|
196
|
+
"""Usage statistics display."""
|
197
|
+
return format_html(
|
198
|
+
'<div class="text-sm">'
|
199
|
+
'<div class="font-medium text-gray-900">{} executions</div>'
|
200
|
+
'<div class="text-gray-500">{}</div>'
|
201
|
+
'</div>',
|
202
|
+
obj.usage_count,
|
203
|
+
f"Last used: {obj.last_used_at.strftime('%m/%d %H:%M')}" if obj.last_used_at else "Never used"
|
204
|
+
)
|
205
|
+
|
206
|
+
@display(description="Performance")
|
207
|
+
def performance_indicator(self, obj):
|
208
|
+
"""Performance indicator based on recent executions."""
|
209
|
+
# This would need to be calculated from related executions
|
210
|
+
return format_html(
|
211
|
+
'<div class="flex items-center space-x-1">'
|
212
|
+
'<div class="w-2 h-2 bg-green-400 rounded-full"></div>'
|
213
|
+
'<span class="text-xs text-gray-600">Good</span>'
|
214
|
+
'</div>'
|
215
|
+
)
|
216
|
+
|
217
|
+
@display(description="Performance Metrics")
|
218
|
+
def performance_metrics(self, obj):
|
219
|
+
"""Detailed performance metrics."""
|
220
|
+
# This would calculate from related AgentExecution objects
|
221
|
+
return format_html(
|
222
|
+
'<div class="space-y-2">'
|
223
|
+
'<div>Avg Execution Time: <span class="font-mono">-</span></div>'
|
224
|
+
'<div>Success Rate: <span class="font-mono">-</span></div>'
|
225
|
+
'<div>Avg Cost: <span class="font-mono">-</span></div>'
|
226
|
+
'</div>'
|
227
|
+
)
|
228
|
+
|
229
|
+
@display(description="Recent Executions")
|
230
|
+
def recent_executions_summary(self, obj):
|
231
|
+
"""Summary of recent executions."""
|
232
|
+
return format_html(
|
233
|
+
'<div class="text-sm text-gray-600">'
|
234
|
+
'See inline executions below for recent activity'
|
235
|
+
'</div>'
|
236
|
+
)
|
237
|
+
|
238
|
+
@action(description="Activate selected agents", icon="play_arrow", variant=ActionVariant.SUCCESS)
|
239
|
+
def activate_agents(self, request, queryset):
|
240
|
+
"""Activate selected agents."""
|
241
|
+
updated = queryset.update(is_active=True)
|
242
|
+
messages.success(request, f"Activated {updated} agents.")
|
243
|
+
|
244
|
+
@action(description="Deactivate selected agents", icon="pause", variant=ActionVariant.WARNING)
|
245
|
+
def deactivate_agents(self, request, queryset):
|
246
|
+
"""Deactivate selected agents."""
|
247
|
+
updated = queryset.update(is_active=False)
|
248
|
+
messages.warning(request, f"Deactivated {updated} agents.")
|
249
|
+
|
250
|
+
@action(description="Make public", icon="public", variant=ActionVariant.INFO)
|
251
|
+
def make_public(self, request, queryset):
|
252
|
+
"""Make selected agents public."""
|
253
|
+
updated = queryset.update(is_public=True)
|
254
|
+
messages.info(request, f"Made {updated} agents public.")
|
255
|
+
|
256
|
+
@action(description="Make private", icon="lock", variant=ActionVariant.DEFAULT)
|
257
|
+
def make_private(self, request, queryset):
|
258
|
+
"""Make selected agents private."""
|
259
|
+
updated = queryset.update(is_public=False)
|
260
|
+
messages.info(request, f"Made {updated} agents private.")
|
261
|
+
|
262
|
+
def get_queryset(self, request):
|
263
|
+
"""Optimize queryset."""
|
264
|
+
return super().get_queryset(request).select_related('created_by').prefetch_related('allowed_users', 'allowed_groups')
|
265
|
+
|
266
|
+
def save_model(self, request, obj, form, change):
|
267
|
+
"""Set created_by on new objects."""
|
268
|
+
if not change:
|
269
|
+
obj.created_by = request.user
|
270
|
+
super().save_model(request, obj, form, change)
|
271
|
+
|
272
|
+
|
273
|
+
@admin.register(AgentTemplate)
|
274
|
+
class AgentTemplateAdmin(ModelAdmin):
|
275
|
+
"""Admin interface for AgentTemplate with Unfold styling."""
|
276
|
+
|
277
|
+
list_display = ['name_display', 'category_badge', 'status_badge', 'use_cases_preview', 'created_by', 'created_at']
|
278
|
+
ordering = ['-created_at']
|
279
|
+
list_filter = [
|
280
|
+
'category', 'is_active', 'created_at',
|
281
|
+
('created_by', AutocompleteSelectFilter)
|
282
|
+
]
|
283
|
+
search_fields = ['name', 'description', 'use_cases']
|
284
|
+
autocomplete_fields = ['created_by']
|
285
|
+
readonly_fields = ['created_at', 'updated_at']
|
286
|
+
|
287
|
+
# Unfold form field overrides
|
288
|
+
formfield_overrides = {
|
289
|
+
models.TextField: {"widget": WysiwygWidget},
|
290
|
+
JSONField: {"widget": JSONEditorWidget},
|
291
|
+
}
|
292
|
+
|
293
|
+
fieldsets = (
|
294
|
+
("📋 Template Information", {
|
295
|
+
'fields': ('name', 'description', 'category', 'use_cases'),
|
296
|
+
'classes': ('tab',)
|
297
|
+
}),
|
298
|
+
("⚙️ Template Configuration", {
|
299
|
+
'fields': ('template_config', 'default_instructions', 'recommended_model'),
|
300
|
+
'classes': ('tab',)
|
301
|
+
}),
|
302
|
+
("🔧 Settings", {
|
303
|
+
'fields': ('is_active', 'created_by', 'created_at', 'updated_at'),
|
304
|
+
'classes': ('tab',)
|
305
|
+
}),
|
306
|
+
)
|
307
|
+
|
308
|
+
actions = ['activate_templates', 'deactivate_templates']
|
309
|
+
|
310
|
+
@display(description="Template Name")
|
311
|
+
def name_display(self, obj):
|
312
|
+
"""Enhanced name display."""
|
313
|
+
return format_html(
|
314
|
+
'<div class="flex items-center space-x-2">'
|
315
|
+
'<span class="text-purple-600 font-medium">{}</span>'
|
316
|
+
'</div>',
|
317
|
+
obj.name
|
318
|
+
)
|
319
|
+
|
320
|
+
@display(description="Category")
|
321
|
+
def category_badge(self, obj):
|
322
|
+
"""Category badge."""
|
323
|
+
if not obj.category:
|
324
|
+
return "-"
|
325
|
+
return format_html(
|
326
|
+
'<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800">{}</span>',
|
327
|
+
obj.category
|
328
|
+
)
|
329
|
+
|
330
|
+
@display(description="Status", boolean=True)
|
331
|
+
def status_badge(self, obj):
|
332
|
+
"""Status badge."""
|
333
|
+
return obj.is_active
|
334
|
+
|
335
|
+
@display(description="Use Cases")
|
336
|
+
def use_cases_preview(self, obj):
|
337
|
+
"""Preview of use cases."""
|
338
|
+
if not obj.use_cases:
|
339
|
+
return "-"
|
340
|
+
preview = obj.use_cases[:100] + "..." if len(obj.use_cases) > 100 else obj.use_cases
|
341
|
+
return format_html(
|
342
|
+
'<div class="text-sm text-gray-600 max-w-xs truncate">{}</div>',
|
343
|
+
preview
|
344
|
+
)
|
345
|
+
|
346
|
+
@action(description="Activate templates", icon="play_arrow", variant=ActionVariant.SUCCESS)
|
347
|
+
def activate_templates(self, request, queryset):
|
348
|
+
"""Activate selected templates."""
|
349
|
+
updated = queryset.update(is_active=True)
|
350
|
+
messages.success(request, f"Activated {updated} templates.")
|
351
|
+
|
352
|
+
@action(description="Deactivate templates", icon="pause", variant=ActionVariant.WARNING)
|
353
|
+
def deactivate_templates(self, request, queryset):
|
354
|
+
"""Deactivate selected templates."""
|
355
|
+
updated = queryset.update(is_active=False)
|
356
|
+
messages.warning(request, f"Deactivated {updated} templates.")
|
357
|
+
|
358
|
+
def get_queryset(self, request):
|
359
|
+
"""Optimize queryset."""
|
360
|
+
return super().get_queryset(request).select_related('created_by')
|