django-agent-studio 0.2.7__tar.gz → 0.3.2__tar.gz
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_agent_studio-0.2.7 → django_agent_studio-0.3.2}/PKG-INFO +4 -1
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/README.md +3 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/agents/dynamic.py +2 -3
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/api/serializers.py +157 -1
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/api/urls.py +45 -10
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/api/views.py +492 -20
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/django_agent_studio.egg-info/PKG-INFO +4 -1
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/django_agent_studio.egg-info/SOURCES.txt +8 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/pyproject.toml +1 -1
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/static/agent-frontend/chat-widget.css +286 -0
- django_agent_studio-0.3.2/static/agent-frontend/chat-widget.js +591 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/templates/django_agent_studio/agent_list.html +12 -5
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/templates/django_agent_studio/builder.html +2 -2
- django_agent_studio-0.3.2/templates/django_agent_studio/collaborators.html +418 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/templates/django_agent_studio/home.html +60 -13
- django_agent_studio-0.3.2/templates/django_agent_studio/system_create.html +148 -0
- django_agent_studio-0.3.2/templates/django_agent_studio/system_list.html +104 -0
- django_agent_studio-0.3.2/templates/django_agent_studio/system_test.html +133 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/templates/django_agent_studio/test.html +9 -4
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/urls.py +9 -2
- django_agent_studio-0.3.2/views.py +454 -0
- django_agent_studio-0.2.7/static/agent-frontend/chat-widget.js +0 -481
- django_agent_studio-0.2.7/views.py +0 -100
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/LICENSE +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/__init__.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/agents/__init__.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/agents/builder.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/api/__init__.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/api/permissions.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/apps.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/django_agent_studio.egg-info/dependency_links.txt +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/django_agent_studio.egg-info/requires.txt +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/django_agent_studio.egg-info/top_level.txt +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/management/__init__.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/management/commands/__init__.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/migrations/0001_initial.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/migrations/__init__.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/models/__init__.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/models/permissions.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/services/__init__.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/services/permissions.py +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/setup.cfg +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/static/agent-frontend/chat-widget-markdown.js +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/static/django_agent_studio/js/builder.js +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/static/django_agent_studio/js/builder.js.map +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/static/django_agent_studio/js/style.css +0 -0
- {django_agent_studio-0.2.7 → django_agent_studio-0.3.2}/templates/django_agent_studio/base.html +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-agent-studio
|
|
3
|
-
Version: 0.2
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: Visual agent builder and management studio for Django - build custom GPTs with a two-pane interface
|
|
5
5
|
Author: Chris Barry
|
|
6
6
|
License: Business Source License 1.1
|
|
@@ -126,6 +126,9 @@ A visual agent builder and management interface for Django applications. Create,
|
|
|
126
126
|
|
|
127
127
|
| Version | Date | Changes |
|
|
128
128
|
|---------|------|---------|
|
|
129
|
+
| **0.3.2** | 2026-01-30 | **Multi-User Access Control** - Collaborator management UI, user search autocomplete, supports both email and username-based User models, system creation from homepage, permission inheritance display |
|
|
130
|
+
| **0.3.1** | 2026-01-30 | **Bug Fixes** - Fixed duplicate message emit in dynamic agents, fixed escapejs encoding in templates, added 800px max-width constraint to system test view |
|
|
131
|
+
| **0.3.0** | 2026-01-29 | **System Listing & Navigation** - Browse and test multi-agent systems from homepage, fixed URL routing for My Systems/My Agents links, system creation now supports optional entry agent |
|
|
129
132
|
| **0.2.0** | 2026-01-28 | **Multi-Agent Systems** - System management UI, shared memory configuration, memory privacy controls, builder tools for managing agent systems |
|
|
130
133
|
| **0.1.9** | 2026-01-27 | Spec documents migration, improved builder agent |
|
|
131
134
|
| **0.1.0** | 2026-01-25 | Initial release with builder interface, dynamic tools, knowledge management |
|
|
@@ -6,6 +6,9 @@ A visual agent builder and management interface for Django applications. Create,
|
|
|
6
6
|
|
|
7
7
|
| Version | Date | Changes |
|
|
8
8
|
|---------|------|---------|
|
|
9
|
+
| **0.3.2** | 2026-01-30 | **Multi-User Access Control** - Collaborator management UI, user search autocomplete, supports both email and username-based User models, system creation from homepage, permission inheritance display |
|
|
10
|
+
| **0.3.1** | 2026-01-30 | **Bug Fixes** - Fixed duplicate message emit in dynamic agents, fixed escapejs encoding in templates, added 800px max-width constraint to system test view |
|
|
11
|
+
| **0.3.0** | 2026-01-29 | **System Listing & Navigation** - Browse and test multi-agent systems from homepage, fixed URL routing for My Systems/My Agents links, system creation now supports optional entry agent |
|
|
9
12
|
| **0.2.0** | 2026-01-28 | **Multi-Agent Systems** - System management UI, shared memory configuration, memory privacy controls, builder tools for managing agent systems |
|
|
10
13
|
| **0.1.9** | 2026-01-27 | Spec documents migration, improved builder agent |
|
|
11
14
|
| **0.1.0** | 2026-01-25 | Initial release with builder interface, dynamic tools, knowledge management |
|
|
@@ -266,9 +266,8 @@ class DynamicAgentRuntime(AgentRuntime):
|
|
|
266
266
|
**model_settings,
|
|
267
267
|
)
|
|
268
268
|
|
|
269
|
-
#
|
|
270
|
-
|
|
271
|
-
await ctx.emit(EventType.ASSISTANT_MESSAGE, {"content": result.final_content})
|
|
269
|
+
# Note: run_agentic_loop already emits ASSISTANT_MESSAGE events,
|
|
270
|
+
# so we don't emit here to avoid duplicate messages in the UI.
|
|
272
271
|
|
|
273
272
|
return RunResult(
|
|
274
273
|
final_output={"response": result.final_content},
|
|
@@ -17,6 +17,10 @@ from django_agent_runtime.models import (
|
|
|
17
17
|
AgentSystemMember,
|
|
18
18
|
AgentSystemVersion,
|
|
19
19
|
AgentSystemSnapshot,
|
|
20
|
+
# Collaborator models
|
|
21
|
+
CollaboratorRole,
|
|
22
|
+
AgentCollaborator,
|
|
23
|
+
SystemCollaborator,
|
|
20
24
|
)
|
|
21
25
|
|
|
22
26
|
|
|
@@ -570,12 +574,29 @@ class AgentSystemCreateSerializer(serializers.Serializer):
|
|
|
570
574
|
slug = serializers.SlugField(max_length=100)
|
|
571
575
|
name = serializers.CharField(max_length=255)
|
|
572
576
|
description = serializers.CharField(required=False, default="")
|
|
573
|
-
|
|
577
|
+
# Accept both entry_agent_id and entry_agent for flexibility
|
|
578
|
+
entry_agent_id = serializers.UUIDField(
|
|
579
|
+
required=False,
|
|
580
|
+
help_text="ID of the entry point agent",
|
|
581
|
+
)
|
|
582
|
+
entry_agent = serializers.UUIDField(
|
|
583
|
+
required=False,
|
|
584
|
+
help_text="ID of the entry point agent (alias for entry_agent_id)",
|
|
585
|
+
)
|
|
574
586
|
auto_discover = serializers.BooleanField(
|
|
575
587
|
default=True,
|
|
576
588
|
help_text="Automatically discover and add all reachable sub-agents",
|
|
577
589
|
)
|
|
578
590
|
|
|
591
|
+
def validate(self, data):
|
|
592
|
+
"""Normalize entry_agent to entry_agent_id."""
|
|
593
|
+
# Accept either entry_agent or entry_agent_id
|
|
594
|
+
if 'entry_agent' in data and data['entry_agent']:
|
|
595
|
+
data['entry_agent_id'] = data.pop('entry_agent')
|
|
596
|
+
elif 'entry_agent' in data:
|
|
597
|
+
data.pop('entry_agent')
|
|
598
|
+
return data
|
|
599
|
+
|
|
579
600
|
|
|
580
601
|
class AddMemberSerializer(serializers.Serializer):
|
|
581
602
|
"""Serializer for adding a member to a system."""
|
|
@@ -604,3 +625,138 @@ class PublishVersionSerializer(serializers.Serializer):
|
|
|
604
625
|
default=False,
|
|
605
626
|
help_text="Whether to make this the active version immediately",
|
|
606
627
|
)
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
# =============================================================================
|
|
631
|
+
# Collaborator Serializers for Multi-User Access Control
|
|
632
|
+
# =============================================================================
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
class AgentCollaboratorSerializer(serializers.ModelSerializer):
|
|
636
|
+
"""Serializer for AgentCollaborator."""
|
|
637
|
+
|
|
638
|
+
user_email = serializers.SerializerMethodField()
|
|
639
|
+
user_name = serializers.SerializerMethodField()
|
|
640
|
+
added_by_email = serializers.SerializerMethodField()
|
|
641
|
+
role_display = serializers.CharField(source='get_role_display', read_only=True)
|
|
642
|
+
can_view = serializers.BooleanField(read_only=True)
|
|
643
|
+
can_edit = serializers.BooleanField(read_only=True)
|
|
644
|
+
can_admin = serializers.BooleanField(read_only=True)
|
|
645
|
+
|
|
646
|
+
class Meta:
|
|
647
|
+
model = AgentCollaborator
|
|
648
|
+
fields = [
|
|
649
|
+
"id",
|
|
650
|
+
"agent",
|
|
651
|
+
"user",
|
|
652
|
+
"user_email",
|
|
653
|
+
"user_name",
|
|
654
|
+
"role",
|
|
655
|
+
"role_display",
|
|
656
|
+
"can_view",
|
|
657
|
+
"can_edit",
|
|
658
|
+
"can_admin",
|
|
659
|
+
"added_by",
|
|
660
|
+
"added_by_email",
|
|
661
|
+
"added_at",
|
|
662
|
+
"updated_at",
|
|
663
|
+
]
|
|
664
|
+
read_only_fields = ["id", "added_by", "added_at", "updated_at"]
|
|
665
|
+
|
|
666
|
+
def get_user_email(self, obj):
|
|
667
|
+
"""Return email or username as identifier."""
|
|
668
|
+
if obj.user:
|
|
669
|
+
return obj.user.email or getattr(obj.user, 'username', None) or str(obj.user)
|
|
670
|
+
return None
|
|
671
|
+
|
|
672
|
+
def get_user_name(self, obj):
|
|
673
|
+
"""Return full name, or fall back to email/username."""
|
|
674
|
+
if obj.user:
|
|
675
|
+
if hasattr(obj.user, 'get_full_name'):
|
|
676
|
+
name = obj.user.get_full_name()
|
|
677
|
+
if name:
|
|
678
|
+
return name
|
|
679
|
+
return obj.user.email or getattr(obj.user, 'username', None) or str(obj.user)
|
|
680
|
+
return None
|
|
681
|
+
|
|
682
|
+
def get_added_by_email(self, obj):
|
|
683
|
+
"""Return added_by email or username."""
|
|
684
|
+
if obj.added_by:
|
|
685
|
+
return obj.added_by.email or getattr(obj.added_by, 'username', None) or str(obj.added_by)
|
|
686
|
+
return None
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
class SystemCollaboratorSerializer(serializers.ModelSerializer):
|
|
690
|
+
"""Serializer for SystemCollaborator."""
|
|
691
|
+
|
|
692
|
+
user_email = serializers.SerializerMethodField()
|
|
693
|
+
user_name = serializers.SerializerMethodField()
|
|
694
|
+
added_by_email = serializers.SerializerMethodField()
|
|
695
|
+
role_display = serializers.CharField(source='get_role_display', read_only=True)
|
|
696
|
+
can_view = serializers.BooleanField(read_only=True)
|
|
697
|
+
can_edit = serializers.BooleanField(read_only=True)
|
|
698
|
+
can_admin = serializers.BooleanField(read_only=True)
|
|
699
|
+
|
|
700
|
+
class Meta:
|
|
701
|
+
model = SystemCollaborator
|
|
702
|
+
fields = [
|
|
703
|
+
"id",
|
|
704
|
+
"system",
|
|
705
|
+
"user",
|
|
706
|
+
"user_email",
|
|
707
|
+
"user_name",
|
|
708
|
+
"role",
|
|
709
|
+
"role_display",
|
|
710
|
+
"can_view",
|
|
711
|
+
"can_edit",
|
|
712
|
+
"can_admin",
|
|
713
|
+
"added_by",
|
|
714
|
+
"added_by_email",
|
|
715
|
+
"added_at",
|
|
716
|
+
"updated_at",
|
|
717
|
+
]
|
|
718
|
+
read_only_fields = ["id", "added_by", "added_at", "updated_at"]
|
|
719
|
+
|
|
720
|
+
def get_user_email(self, obj):
|
|
721
|
+
"""Return email or username as identifier."""
|
|
722
|
+
if obj.user:
|
|
723
|
+
return obj.user.email or getattr(obj.user, 'username', None) or str(obj.user)
|
|
724
|
+
return None
|
|
725
|
+
|
|
726
|
+
def get_user_name(self, obj):
|
|
727
|
+
"""Return full name, or fall back to email/username."""
|
|
728
|
+
if obj.user:
|
|
729
|
+
if hasattr(obj.user, 'get_full_name'):
|
|
730
|
+
name = obj.user.get_full_name()
|
|
731
|
+
if name:
|
|
732
|
+
return name
|
|
733
|
+
return obj.user.email or getattr(obj.user, 'username', None) or str(obj.user)
|
|
734
|
+
return None
|
|
735
|
+
|
|
736
|
+
def get_added_by_email(self, obj):
|
|
737
|
+
"""Return added_by email or username."""
|
|
738
|
+
if obj.added_by:
|
|
739
|
+
return obj.added_by.email or getattr(obj.added_by, 'username', None) or str(obj.added_by)
|
|
740
|
+
return None
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
class AddCollaboratorSerializer(serializers.Serializer):
|
|
744
|
+
"""Serializer for adding a collaborator by email or username."""
|
|
745
|
+
|
|
746
|
+
email = serializers.CharField(
|
|
747
|
+
help_text="Email or username of the user to add as collaborator"
|
|
748
|
+
)
|
|
749
|
+
role = serializers.ChoiceField(
|
|
750
|
+
choices=CollaboratorRole.choices,
|
|
751
|
+
default=CollaboratorRole.VIEWER,
|
|
752
|
+
help_text="Role to grant: viewer, editor, or admin",
|
|
753
|
+
)
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
class UpdateCollaboratorRoleSerializer(serializers.Serializer):
|
|
757
|
+
"""Serializer for updating a collaborator's role."""
|
|
758
|
+
|
|
759
|
+
role = serializers.ChoiceField(
|
|
760
|
+
choices=CollaboratorRole.choices,
|
|
761
|
+
help_text="New role: viewer, editor, or admin",
|
|
762
|
+
)
|
|
@@ -8,8 +8,8 @@ from django_agent_studio.api import views
|
|
|
8
8
|
|
|
9
9
|
urlpatterns = [
|
|
10
10
|
# Agent definition CRUD
|
|
11
|
-
path("agents/", views.AgentDefinitionListCreateView.as_view(), name="
|
|
12
|
-
path("agents/<uuid:pk>/", views.AgentDefinitionDetailView.as_view(), name="
|
|
11
|
+
path("agents/", views.AgentDefinitionListCreateView.as_view(), name="api_agent_list"),
|
|
12
|
+
path("agents/<uuid:pk>/", views.AgentDefinitionDetailView.as_view(), name="api_agent_detail"),
|
|
13
13
|
|
|
14
14
|
# Agent versions
|
|
15
15
|
path(
|
|
@@ -194,46 +194,46 @@ urlpatterns = [
|
|
|
194
194
|
path(
|
|
195
195
|
"systems/",
|
|
196
196
|
views.AgentSystemListCreateView.as_view(),
|
|
197
|
-
name="
|
|
197
|
+
name="api_system_list",
|
|
198
198
|
),
|
|
199
199
|
path(
|
|
200
200
|
"systems/<uuid:pk>/",
|
|
201
201
|
views.AgentSystemDetailView.as_view(),
|
|
202
|
-
name="
|
|
202
|
+
name="api_system_detail",
|
|
203
203
|
),
|
|
204
204
|
|
|
205
205
|
# System members
|
|
206
206
|
path(
|
|
207
207
|
"systems/<uuid:system_id>/members/",
|
|
208
208
|
views.AgentSystemMemberListCreateView.as_view(),
|
|
209
|
-
name="
|
|
209
|
+
name="api_system_member_list",
|
|
210
210
|
),
|
|
211
211
|
path(
|
|
212
212
|
"systems/<uuid:system_id>/members/<uuid:pk>/",
|
|
213
213
|
views.AgentSystemMemberDetailView.as_view(),
|
|
214
|
-
name="
|
|
214
|
+
name="api_system_member_detail",
|
|
215
215
|
),
|
|
216
216
|
|
|
217
217
|
# System versions
|
|
218
218
|
path(
|
|
219
219
|
"systems/<uuid:system_id>/versions/",
|
|
220
220
|
views.AgentSystemVersionListView.as_view(),
|
|
221
|
-
name="
|
|
221
|
+
name="api_system_version_list",
|
|
222
222
|
),
|
|
223
223
|
path(
|
|
224
224
|
"systems/<uuid:system_id>/publish/",
|
|
225
225
|
views.AgentSystemPublishView.as_view(),
|
|
226
|
-
name="
|
|
226
|
+
name="api_system_publish",
|
|
227
227
|
),
|
|
228
228
|
path(
|
|
229
229
|
"systems/<uuid:system_id>/versions/<uuid:version_id>/deploy/",
|
|
230
230
|
views.AgentSystemDeployView.as_view(),
|
|
231
|
-
name="
|
|
231
|
+
name="api_system_deploy",
|
|
232
232
|
),
|
|
233
233
|
path(
|
|
234
234
|
"systems/<uuid:system_id>/versions/<uuid:version_id>/export/",
|
|
235
235
|
views.AgentSystemExportView.as_view(),
|
|
236
|
-
name="
|
|
236
|
+
name="api_system_export",
|
|
237
237
|
),
|
|
238
238
|
|
|
239
239
|
# Discover agents from entry point
|
|
@@ -300,4 +300,39 @@ urlpatterns = [
|
|
|
300
300
|
views.AgentSpecDocumentView.as_view(),
|
|
301
301
|
name="agent_spec_document",
|
|
302
302
|
),
|
|
303
|
+
|
|
304
|
+
# ==========================================================================
|
|
305
|
+
# Collaborator Management Endpoints
|
|
306
|
+
# ==========================================================================
|
|
307
|
+
|
|
308
|
+
# Agent collaborators
|
|
309
|
+
path(
|
|
310
|
+
"agents/<uuid:agent_id>/collaborators/",
|
|
311
|
+
views.AgentCollaboratorListCreateView.as_view(),
|
|
312
|
+
name="agent_collaborator_list",
|
|
313
|
+
),
|
|
314
|
+
path(
|
|
315
|
+
"agents/<uuid:agent_id>/collaborators/<uuid:pk>/",
|
|
316
|
+
views.AgentCollaboratorDetailView.as_view(),
|
|
317
|
+
name="agent_collaborator_detail",
|
|
318
|
+
),
|
|
319
|
+
|
|
320
|
+
# System collaborators
|
|
321
|
+
path(
|
|
322
|
+
"systems/<uuid:system_id>/collaborators/",
|
|
323
|
+
views.SystemCollaboratorListCreateView.as_view(),
|
|
324
|
+
name="system_collaborator_list",
|
|
325
|
+
),
|
|
326
|
+
path(
|
|
327
|
+
"systems/<uuid:system_id>/collaborators/<uuid:pk>/",
|
|
328
|
+
views.SystemCollaboratorDetailView.as_view(),
|
|
329
|
+
name="system_collaborator_detail",
|
|
330
|
+
),
|
|
331
|
+
|
|
332
|
+
# User search for collaborator autocomplete
|
|
333
|
+
path(
|
|
334
|
+
"users/search/",
|
|
335
|
+
views.UserSearchView.as_view(),
|
|
336
|
+
name="user_search",
|
|
337
|
+
),
|
|
303
338
|
]
|