django-agent-studio 0.1.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_agent_studio/__init__.py +12 -0
- django_agent_studio/api/__init__.py +4 -0
- django_agent_studio/api/permissions.py +160 -0
- django_agent_studio/api/serializers.py +606 -0
- django_agent_studio/api/urls.py +245 -0
- django_agent_studio/api/views.py +1548 -0
- django_agent_studio/apps.py +24 -0
- django_agent_studio/management/__init__.py +2 -0
- django_agent_studio/management/commands/__init__.py +2 -0
- django_agent_studio/static/agent-frontend/chat-widget-markdown.js +110 -0
- django_agent_studio/static/agent-frontend/chat-widget.css +1401 -0
- django_agent_studio/static/agent-frontend/chat-widget.js +319 -0
- django_agent_studio/templates/django_agent_studio/agent_list.html +101 -0
- django_agent_studio/templates/django_agent_studio/base.html +137 -0
- django_agent_studio/templates/django_agent_studio/builder.html +1443 -0
- django_agent_studio/templates/django_agent_studio/home.html +97 -0
- django_agent_studio/templates/django_agent_studio/test.html +126 -0
- django_agent_studio/urls.py +25 -0
- django_agent_studio/views.py +100 -0
- django_agent_studio-0.1.0.dist-info/METADATA +416 -0
- django_agent_studio-0.1.0.dist-info/RECORD +23 -0
- django_agent_studio-0.1.0.dist-info/WHEEL +5 -0
- django_agent_studio-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Django Agent Studio - Visual agent builder and management interface.
|
|
3
|
+
|
|
4
|
+
A Django app that provides a two-pane interface for building and testing
|
|
5
|
+
custom GPT-like agents. Uses agent-frontend for the chat interfaces and
|
|
6
|
+
integrates with django_agent_runtime for agent execution.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__version__ = "0.1.0"
|
|
10
|
+
|
|
11
|
+
default_app_config = "django_agent_studio.apps.DjangoAgentStudioConfig"
|
|
12
|
+
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DRF Permission classes for Dynamic Tool access control.
|
|
3
|
+
|
|
4
|
+
These permissions integrate with the DynamicToolPermissionService
|
|
5
|
+
to enforce access levels on API endpoints.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from rest_framework import permissions
|
|
9
|
+
from rest_framework.request import Request
|
|
10
|
+
from rest_framework.views import APIView
|
|
11
|
+
|
|
12
|
+
from django_agent_studio.services.permissions import get_permission_service
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class BaseDynamicToolPermission(permissions.BasePermission):
|
|
16
|
+
"""
|
|
17
|
+
Base class for dynamic tool permissions.
|
|
18
|
+
|
|
19
|
+
Subclasses should set `required_level` to the minimum access level needed.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
required_level: str = None
|
|
23
|
+
message = "You do not have permission to perform this action."
|
|
24
|
+
|
|
25
|
+
def has_permission(self, request: Request, view: APIView) -> bool:
|
|
26
|
+
if not request.user or not request.user.is_authenticated:
|
|
27
|
+
return False
|
|
28
|
+
|
|
29
|
+
# Get agent from view kwargs if available
|
|
30
|
+
agent = self._get_agent(request, view)
|
|
31
|
+
|
|
32
|
+
service = get_permission_service()
|
|
33
|
+
return service.has_level(request.user, self.required_level, agent)
|
|
34
|
+
|
|
35
|
+
def _get_agent(self, request: Request, view: APIView):
|
|
36
|
+
"""Try to get the agent from the view."""
|
|
37
|
+
from django_agent_runtime.models import AgentDefinition
|
|
38
|
+
|
|
39
|
+
agent_id = view.kwargs.get('agent_id') or view.kwargs.get('pk')
|
|
40
|
+
if agent_id:
|
|
41
|
+
try:
|
|
42
|
+
return AgentDefinition.objects.get(id=agent_id)
|
|
43
|
+
except AgentDefinition.DoesNotExist:
|
|
44
|
+
return None
|
|
45
|
+
return None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class CanViewDynamicTools(BaseDynamicToolPermission):
|
|
49
|
+
"""Permission to view discovered functions and tools."""
|
|
50
|
+
|
|
51
|
+
required_level = 'viewer'
|
|
52
|
+
message = "You need at least Viewer access to view dynamic tools."
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class CanScanProject(BaseDynamicToolPermission):
|
|
56
|
+
"""Permission to scan project for functions."""
|
|
57
|
+
|
|
58
|
+
required_level = 'scanner'
|
|
59
|
+
message = "You need at least Scanner access to scan the project."
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class CanRequestTool(BaseDynamicToolPermission):
|
|
63
|
+
"""Permission to request tool creation (with approval)."""
|
|
64
|
+
|
|
65
|
+
required_level = 'requester'
|
|
66
|
+
message = "You need at least Requester access to request tool creation."
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class CanCreateTool(BaseDynamicToolPermission):
|
|
70
|
+
"""Permission to create tools directly without approval."""
|
|
71
|
+
|
|
72
|
+
required_level = 'creator'
|
|
73
|
+
message = "You need Creator access to create tools directly."
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class CanApproveTool(BaseDynamicToolPermission):
|
|
77
|
+
"""Permission to approve/reject tool requests."""
|
|
78
|
+
|
|
79
|
+
required_level = 'admin'
|
|
80
|
+
message = "You need Admin access to approve tool requests."
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class CanManagePermissions(BaseDynamicToolPermission):
|
|
84
|
+
"""Permission to manage other users' access levels."""
|
|
85
|
+
|
|
86
|
+
required_level = 'admin'
|
|
87
|
+
message = "You need Admin access to manage permissions."
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class DynamicToolObjectPermission(permissions.BasePermission):
|
|
91
|
+
"""
|
|
92
|
+
Object-level permission for dynamic tools.
|
|
93
|
+
|
|
94
|
+
Checks if user can modify/delete a specific tool.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
def has_object_permission(self, request: Request, view: APIView, obj) -> bool:
|
|
98
|
+
if not request.user or not request.user.is_authenticated:
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
service = get_permission_service()
|
|
102
|
+
|
|
103
|
+
# Read operations need viewer access
|
|
104
|
+
if request.method in permissions.SAFE_METHODS:
|
|
105
|
+
return service.can_view(request.user, obj.agent)
|
|
106
|
+
|
|
107
|
+
# Delete needs admin
|
|
108
|
+
if request.method == 'DELETE':
|
|
109
|
+
return service.can_delete_tool(request.user, obj)
|
|
110
|
+
|
|
111
|
+
# Modify needs creator
|
|
112
|
+
return service.can_modify_tool(request.user, obj)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class IsOwnerOrHasDynamicToolAccess(permissions.BasePermission):
|
|
116
|
+
"""
|
|
117
|
+
Combined permission: owner of agent OR has dynamic tool access.
|
|
118
|
+
|
|
119
|
+
This allows the existing owner-based access to work alongside
|
|
120
|
+
the new permission system.
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
required_level: str = 'viewer'
|
|
124
|
+
|
|
125
|
+
def has_permission(self, request: Request, view: APIView) -> bool:
|
|
126
|
+
if not request.user or not request.user.is_authenticated:
|
|
127
|
+
return False
|
|
128
|
+
|
|
129
|
+
# Superusers always have access
|
|
130
|
+
if request.user.is_superuser:
|
|
131
|
+
return True
|
|
132
|
+
|
|
133
|
+
# Check if user owns the agent
|
|
134
|
+
from django_agent_runtime.models import AgentDefinition
|
|
135
|
+
|
|
136
|
+
agent_id = view.kwargs.get('agent_id') or view.kwargs.get('pk')
|
|
137
|
+
if agent_id:
|
|
138
|
+
try:
|
|
139
|
+
agent = AgentDefinition.objects.get(id=agent_id)
|
|
140
|
+
if agent.owner == request.user:
|
|
141
|
+
return True
|
|
142
|
+
except AgentDefinition.DoesNotExist:
|
|
143
|
+
pass
|
|
144
|
+
|
|
145
|
+
# Fall back to permission service
|
|
146
|
+
service = get_permission_service()
|
|
147
|
+
agent = self._get_agent(request, view)
|
|
148
|
+
return service.has_level(request.user, self.required_level, agent)
|
|
149
|
+
|
|
150
|
+
def _get_agent(self, request: Request, view: APIView):
|
|
151
|
+
from django_agent_runtime.models import AgentDefinition
|
|
152
|
+
|
|
153
|
+
agent_id = view.kwargs.get('agent_id') or view.kwargs.get('pk')
|
|
154
|
+
if agent_id:
|
|
155
|
+
try:
|
|
156
|
+
return AgentDefinition.objects.get(id=agent_id)
|
|
157
|
+
except AgentDefinition.DoesNotExist:
|
|
158
|
+
return None
|
|
159
|
+
return None
|
|
160
|
+
|