agentic-django 0.1.0__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.
Files changed (29) hide show
  1. agentic_django-0.1.0/LICENSE +21 -0
  2. agentic_django-0.1.0/PKG-INFO +306 -0
  3. agentic_django-0.1.0/README.md +250 -0
  4. agentic_django-0.1.0/pyproject.toml +94 -0
  5. agentic_django-0.1.0/src/agentic_django/__init__.py +0 -0
  6. agentic_django-0.1.0/src/agentic_django/admin.py +75 -0
  7. agentic_django-0.1.0/src/agentic_django/apps.py +14 -0
  8. agentic_django-0.1.0/src/agentic_django/conf.py +218 -0
  9. agentic_django-0.1.0/src/agentic_django/management/__init__.py +1 -0
  10. agentic_django-0.1.0/src/agentic_django/management/commands/__init__.py +1 -0
  11. agentic_django-0.1.0/src/agentic_django/management/commands/agentic_django_cleanup.py +145 -0
  12. agentic_django-0.1.0/src/agentic_django/management/commands/agentic_django_recover_runs.py +24 -0
  13. agentic_django-0.1.0/src/agentic_django/migrations/0001_initial.py +198 -0
  14. agentic_django-0.1.0/src/agentic_django/migrations/__init__.py +0 -0
  15. agentic_django-0.1.0/src/agentic_django/models.py +151 -0
  16. agentic_django-0.1.0/src/agentic_django/py.typed +1 -0
  17. agentic_django-0.1.0/src/agentic_django/registry.py +25 -0
  18. agentic_django-0.1.0/src/agentic_django/serializers.py +103 -0
  19. agentic_django-0.1.0/src/agentic_django/services.py +408 -0
  20. agentic_django-0.1.0/src/agentic_django/sessions.py +121 -0
  21. agentic_django-0.1.0/src/agentic_django/signals.py +9 -0
  22. agentic_django-0.1.0/src/agentic_django/static/agentic_django/agentic_django.css +90 -0
  23. agentic_django-0.1.0/src/agentic_django/tasks.py +10 -0
  24. agentic_django-0.1.0/src/agentic_django/templates/agentic_django/partials/conversation.html +11 -0
  25. agentic_django-0.1.0/src/agentic_django/templates/agentic_django/partials/run_fragment.html +39 -0
  26. agentic_django-0.1.0/src/agentic_django/templatetags/__init__.py +0 -0
  27. agentic_django-0.1.0/src/agentic_django/templatetags/agentic_django_tags.py +35 -0
  28. agentic_django-0.1.0/src/agentic_django/urls.py +27 -0
  29. agentic_django-0.1.0/src/agentic_django/views.py +244 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Agentic Django contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,306 @@
1
+ Metadata-Version: 2.1
2
+ Name: agentic-django
3
+ Version: 0.1.0
4
+ Summary: Django integration for building agentic apps with the OpenAI Agents SDK
5
+ Author-Email: "B.T. Franklin" <brandon.franklin@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Agentic Django contributors
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Classifier: Programming Language :: Python :: 3
29
+ Classifier: Programming Language :: Python :: 3 :: Only
30
+ Classifier: Programming Language :: Python :: 3.12
31
+ Classifier: Programming Language :: Python :: 3.13
32
+ Classifier: Programming Language :: Python :: 3.14
33
+ Classifier: Framework :: Django
34
+ Classifier: Typing :: Typed
35
+ Classifier: License :: OSI Approved :: MIT License
36
+ Classifier: Operating System :: OS Independent
37
+ Classifier: Intended Audience :: Developers
38
+ Classifier: Topic :: Internet :: WWW/HTTP
39
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
40
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
41
+ Project-URL: Homepage, https://github.com/btfranklin/agentic-django
42
+ Project-URL: Issues, https://github.com/btfranklin/agentic-django/issues
43
+ Project-URL: Changelog, https://github.com/btfranklin/agentic-django/releases
44
+ Project-URL: Repository, https://github.com/btfranklin/agentic-django.git
45
+ Requires-Python: >=3.12
46
+ Requires-Dist: Django<7,>=6
47
+ Requires-Dist: django-tasks>=0.11.0
48
+ Requires-Dist: openai-agents>=0.6.5
49
+ Requires-Dist: pydantic>=2.11.0
50
+ Provides-Extra: rq
51
+ Requires-Dist: django-tasks[rq]>=0.11.0; extra == "rq"
52
+ Requires-Dist: redis>=5.0.0; extra == "rq"
53
+ Provides-Extra: postgres
54
+ Requires-Dist: psycopg[binary]>=3.2.0; extra == "postgres"
55
+ Description-Content-Type: text/markdown
56
+
57
+ # Agentic Django
58
+
59
+ Agentic Django is a reusable Django 6 app that wraps the OpenAI Agents SDK with
60
+ Django-friendly primitives (sessions, runs, and background tasks). The example
61
+ project lives in the sibling `agentic-django-example` repo.
62
+
63
+ ## Requirements
64
+
65
+ - Python 3.12+
66
+ - Django 6.x
67
+
68
+ ## Why use it
69
+
70
+ Building agentic workflows in Django usually means stitching together the OpenAI
71
+ Agents SDK, persistence, and async execution on your own. This project gives you
72
+ a consistent, Django-native way to:
73
+
74
+ - kick off multi-step agent runs from views or services
75
+ - persist conversation history and run status in your database
76
+ - check progress later from any UI or API client
77
+ - keep runs private to each authenticated user
78
+ - reuse the same primitives across multiple apps or projects
79
+
80
+ ## Benefits
81
+
82
+ - Django-first integration with models, admin, templates, and URL patterns
83
+ - simple async model using Django 6 tasks (no Celery required)
84
+ - stable polling UX for HTMX or REST clients
85
+ - per-user ownership baked into queries and views
86
+ - flexible registry so each project can provide its own agents
87
+
88
+ ## How it helps
89
+
90
+ If you have a workflow that can take minutes, branch into tools, or write to
91
+ session memory, you can run it as a background task and poll for status just
92
+ like any other Django async job. You do not need to keep a request open or build
93
+ custom state tracking.
94
+
95
+ ## Usage examples
96
+
97
+ Create a run from a view and enqueue it for background execution:
98
+
99
+ ```python
100
+ from agentic_django.models import AgentRun, AgentSession
101
+ from agentic_django.services import enqueue_agent_run
102
+
103
+ def submit_run(request):
104
+ session, _ = AgentSession.objects.get_or_create(
105
+ owner=request.user,
106
+ session_key=request.POST["session_key"],
107
+ )
108
+ run = AgentRun.objects.create(
109
+ session=session,
110
+ owner=request.user,
111
+ agent_key="demo",
112
+ input_payload=request.POST["input"],
113
+ )
114
+ enqueue_agent_run(str(run.id))
115
+ ```
116
+
117
+ Check run status later from a UI or API client:
118
+
119
+ ```python
120
+ from django.shortcuts import get_object_or_404
121
+ from agentic_django.models import AgentRun
122
+
123
+ def run_status(request, run_id):
124
+ run = get_object_or_404(AgentRun, id=run_id, owner=request.user)
125
+ return {
126
+ "status": run.status,
127
+ "final_output": run.final_output,
128
+ }
129
+ ```
130
+
131
+ ## HTMX
132
+
133
+ HTMX polling + coordinated updates:
134
+
135
+ ```html
136
+ <div
137
+ id="run-container-{{ run.id }}"
138
+ data-status="{{ run.status }}"
139
+ hx-get="{% url 'agents:run-fragment' run.id %}"
140
+ hx-trigger="load delay:1s, every 2s"
141
+ hx-target="#run-container-{{ run.id }}"
142
+ hx-swap="outerHTML"
143
+ hx-on::afterSwap="if (this.dataset.status === 'completed' || this.dataset.status === 'failed') { this.removeAttribute('hx-get'); this.removeAttribute('hx-trigger'); }"
144
+ >
145
+ {% load agentic_django_tags %}
146
+ {% agent_run_fragment run %}
147
+ </div>
148
+ ```
149
+
150
+ Coordinate panels with `HX-Trigger` so you only update when there is run activity:
151
+
152
+ ```python
153
+ # views.py
154
+ response = render(request, "agentic_django/partials/run_fragment.html", {"run": run})
155
+ response["HX-Trigger"] = "run-update"
156
+ return response
157
+ ```
158
+
159
+ ```html
160
+ <div id="conversation-panel"
161
+ hx-get="{% url 'agents:session-items' session.session_key %}"
162
+ hx-trigger="run-update from:body"
163
+ hx-target="#conversation-contents"
164
+ hx-swap="innerHTML">
165
+ ...
166
+ </div>
167
+ ```
168
+
169
+ Template override note: if you create `templates/agentic_django/...` in your project, Django will use those files instead of the package templates with the same path. This is useful for customization, but it can hide edits made in the package templates.
170
+
171
+ ## Styling (optional)
172
+
173
+ The package ships a minimal stylesheet for the default fragments. Include it in your base template:
174
+
175
+ ```html
176
+ {% load static %}
177
+ <link rel="stylesheet" href="{% static 'agentic_django/agentic_django.css' %}">
178
+ ```
179
+
180
+ ## Configuration
181
+
182
+ Add the app and configure the agent registry in `settings.py`:
183
+
184
+ ```python
185
+ INSTALLED_APPS = [
186
+ # ...
187
+ "agentic_django.apps.AgenticDjangoConfig",
188
+ ]
189
+
190
+ AGENTIC_DJANGO_AGENT_REGISTRY = "my_project.agent_registry.get_agent_registry"
191
+ AGENTIC_DJANGO_DEFAULT_AGENT_KEY = "default"
192
+ AGENTIC_DJANGO_DEFAULT_RUN_OPTIONS = {"max_turns": 6}
193
+ AGENTIC_DJANGO_CONCURRENCY_LIMIT = None # auto: CPU count
194
+
195
+ # django-tasks backend selection (Immediate by default, RQ in production)
196
+ TASKS = {
197
+ "default": {
198
+ "BACKEND": "django_tasks.backends.immediate.ImmediateBackend",
199
+ }
200
+ }
201
+
202
+ RQ_QUEUES = {
203
+ "default": {
204
+ "URL": "redis://localhost:6379/0",
205
+ }
206
+ }
207
+
208
+ # Switch to RQ-backed tasks in production
209
+ TASKS["default"]["BACKEND"] = "django_tasks.backends.rq.RQBackend"
210
+
211
+ # Optional: enable event streaming persistence
212
+ AGENTIC_DJANGO_ENABLE_EVENTS = True
213
+
214
+ # Optional: basic abuse protection for run creation
215
+ AGENTIC_DJANGO_RATE_LIMIT = "20/m"
216
+ AGENTIC_DJANGO_MAX_INPUT_BYTES = 20_000
217
+ AGENTIC_DJANGO_MAX_INPUT_ITEMS = 20
218
+
219
+ # Optional: override startup recovery (default: requeue)
220
+ AGENTIC_DJANGO_STARTUP_RECOVERY = "fail"
221
+
222
+ # Optional: cleanup policy for old records
223
+ AGENTIC_DJANGO_CLEANUP_POLICY = {
224
+ "events_days": 7,
225
+ "runs_days": 30,
226
+ "runs_statuses": ["completed", "failed"],
227
+ "sessions_days": 90,
228
+ "sessions_require_empty": True,
229
+ "batch_size": 500,
230
+ }
231
+ ```
232
+
233
+ ## Optional dependencies
234
+
235
+ - RQ-backed tasks: `pdm install -G rq`
236
+ - Postgres driver: `pdm install -G postgres`
237
+
238
+ ## Event streaming (optional)
239
+
240
+ When `AGENTIC_DJANGO_ENABLE_EVENTS = True`, each agent run persists semantic events
241
+ (tool calls, tool outputs, message items). Poll for events with:
242
+
243
+ ```
244
+ GET /runs/<uuid:run_id>/events/?after=<sequence>&limit=<n>
245
+ ```
246
+
247
+ You can also subscribe to the Django signal `agent_run_event` to push UI updates
248
+ after each event is stored.
249
+
250
+ Provide a registry that returns agent factories:
251
+
252
+ ```python
253
+ from agents import Agent
254
+ from my_project.models import MyModelProvider
255
+
256
+ def get_agent_registry():
257
+ def build_default():
258
+ return Agent(
259
+ name="Support Agent",
260
+ instructions="Help the user with account issues.",
261
+ model=MyModelProvider(),
262
+ )
263
+
264
+ return {"default": build_default}
265
+ ```
266
+
267
+ ## Operations
268
+
269
+ Prune old data with the cleanup command (uses `AGENTIC_DJANGO_CLEANUP_POLICY` by default):
270
+
271
+ ```bash
272
+ python manage.py agentic_django_cleanup --dry-run
273
+ python manage.py agentic_django_cleanup --events-days 14 --runs-days 60
274
+ ```
275
+
276
+ Recover runs stuck in `running` after a restart:
277
+
278
+ ```bash
279
+ python manage.py agentic_django_recover_runs --mode=fail
280
+ python manage.py agentic_django_recover_runs --mode=requeue
281
+ ```
282
+
283
+ Startup recovery runs on the first run dispatch/execution in each process, so it does
284
+ not touch the database during app initialization.
285
+
286
+ ## Security notes
287
+
288
+ - Enable Django 6’s Content Security Policy support where feasible, and open
289
+ `connect-src` only to the endpoints your UI needs (for polling or tooling).
290
+ - Keep agent tool registries scoped; do not expose powerful tools to untrusted
291
+ user input without additional validation or allowlists.
292
+
293
+ ## Example project
294
+
295
+ The sample project lives in the sibling `agentic-django-example` repo. See its
296
+ README for setup, Docker, and run instructions.
297
+
298
+ ## Tests
299
+
300
+ ```bash
301
+ pdm run test
302
+ ```
303
+
304
+ ## License
305
+
306
+ MIT. See `LICENSE`.
@@ -0,0 +1,250 @@
1
+ # Agentic Django
2
+
3
+ Agentic Django is a reusable Django 6 app that wraps the OpenAI Agents SDK with
4
+ Django-friendly primitives (sessions, runs, and background tasks). The example
5
+ project lives in the sibling `agentic-django-example` repo.
6
+
7
+ ## Requirements
8
+
9
+ - Python 3.12+
10
+ - Django 6.x
11
+
12
+ ## Why use it
13
+
14
+ Building agentic workflows in Django usually means stitching together the OpenAI
15
+ Agents SDK, persistence, and async execution on your own. This project gives you
16
+ a consistent, Django-native way to:
17
+
18
+ - kick off multi-step agent runs from views or services
19
+ - persist conversation history and run status in your database
20
+ - check progress later from any UI or API client
21
+ - keep runs private to each authenticated user
22
+ - reuse the same primitives across multiple apps or projects
23
+
24
+ ## Benefits
25
+
26
+ - Django-first integration with models, admin, templates, and URL patterns
27
+ - simple async model using Django 6 tasks (no Celery required)
28
+ - stable polling UX for HTMX or REST clients
29
+ - per-user ownership baked into queries and views
30
+ - flexible registry so each project can provide its own agents
31
+
32
+ ## How it helps
33
+
34
+ If you have a workflow that can take minutes, branch into tools, or write to
35
+ session memory, you can run it as a background task and poll for status just
36
+ like any other Django async job. You do not need to keep a request open or build
37
+ custom state tracking.
38
+
39
+ ## Usage examples
40
+
41
+ Create a run from a view and enqueue it for background execution:
42
+
43
+ ```python
44
+ from agentic_django.models import AgentRun, AgentSession
45
+ from agentic_django.services import enqueue_agent_run
46
+
47
+ def submit_run(request):
48
+ session, _ = AgentSession.objects.get_or_create(
49
+ owner=request.user,
50
+ session_key=request.POST["session_key"],
51
+ )
52
+ run = AgentRun.objects.create(
53
+ session=session,
54
+ owner=request.user,
55
+ agent_key="demo",
56
+ input_payload=request.POST["input"],
57
+ )
58
+ enqueue_agent_run(str(run.id))
59
+ ```
60
+
61
+ Check run status later from a UI or API client:
62
+
63
+ ```python
64
+ from django.shortcuts import get_object_or_404
65
+ from agentic_django.models import AgentRun
66
+
67
+ def run_status(request, run_id):
68
+ run = get_object_or_404(AgentRun, id=run_id, owner=request.user)
69
+ return {
70
+ "status": run.status,
71
+ "final_output": run.final_output,
72
+ }
73
+ ```
74
+
75
+ ## HTMX
76
+
77
+ HTMX polling + coordinated updates:
78
+
79
+ ```html
80
+ <div
81
+ id="run-container-{{ run.id }}"
82
+ data-status="{{ run.status }}"
83
+ hx-get="{% url 'agents:run-fragment' run.id %}"
84
+ hx-trigger="load delay:1s, every 2s"
85
+ hx-target="#run-container-{{ run.id }}"
86
+ hx-swap="outerHTML"
87
+ hx-on::afterSwap="if (this.dataset.status === 'completed' || this.dataset.status === 'failed') { this.removeAttribute('hx-get'); this.removeAttribute('hx-trigger'); }"
88
+ >
89
+ {% load agentic_django_tags %}
90
+ {% agent_run_fragment run %}
91
+ </div>
92
+ ```
93
+
94
+ Coordinate panels with `HX-Trigger` so you only update when there is run activity:
95
+
96
+ ```python
97
+ # views.py
98
+ response = render(request, "agentic_django/partials/run_fragment.html", {"run": run})
99
+ response["HX-Trigger"] = "run-update"
100
+ return response
101
+ ```
102
+
103
+ ```html
104
+ <div id="conversation-panel"
105
+ hx-get="{% url 'agents:session-items' session.session_key %}"
106
+ hx-trigger="run-update from:body"
107
+ hx-target="#conversation-contents"
108
+ hx-swap="innerHTML">
109
+ ...
110
+ </div>
111
+ ```
112
+
113
+ Template override note: if you create `templates/agentic_django/...` in your project, Django will use those files instead of the package templates with the same path. This is useful for customization, but it can hide edits made in the package templates.
114
+
115
+ ## Styling (optional)
116
+
117
+ The package ships a minimal stylesheet for the default fragments. Include it in your base template:
118
+
119
+ ```html
120
+ {% load static %}
121
+ <link rel="stylesheet" href="{% static 'agentic_django/agentic_django.css' %}">
122
+ ```
123
+
124
+ ## Configuration
125
+
126
+ Add the app and configure the agent registry in `settings.py`:
127
+
128
+ ```python
129
+ INSTALLED_APPS = [
130
+ # ...
131
+ "agentic_django.apps.AgenticDjangoConfig",
132
+ ]
133
+
134
+ AGENTIC_DJANGO_AGENT_REGISTRY = "my_project.agent_registry.get_agent_registry"
135
+ AGENTIC_DJANGO_DEFAULT_AGENT_KEY = "default"
136
+ AGENTIC_DJANGO_DEFAULT_RUN_OPTIONS = {"max_turns": 6}
137
+ AGENTIC_DJANGO_CONCURRENCY_LIMIT = None # auto: CPU count
138
+
139
+ # django-tasks backend selection (Immediate by default, RQ in production)
140
+ TASKS = {
141
+ "default": {
142
+ "BACKEND": "django_tasks.backends.immediate.ImmediateBackend",
143
+ }
144
+ }
145
+
146
+ RQ_QUEUES = {
147
+ "default": {
148
+ "URL": "redis://localhost:6379/0",
149
+ }
150
+ }
151
+
152
+ # Switch to RQ-backed tasks in production
153
+ TASKS["default"]["BACKEND"] = "django_tasks.backends.rq.RQBackend"
154
+
155
+ # Optional: enable event streaming persistence
156
+ AGENTIC_DJANGO_ENABLE_EVENTS = True
157
+
158
+ # Optional: basic abuse protection for run creation
159
+ AGENTIC_DJANGO_RATE_LIMIT = "20/m"
160
+ AGENTIC_DJANGO_MAX_INPUT_BYTES = 20_000
161
+ AGENTIC_DJANGO_MAX_INPUT_ITEMS = 20
162
+
163
+ # Optional: override startup recovery (default: requeue)
164
+ AGENTIC_DJANGO_STARTUP_RECOVERY = "fail"
165
+
166
+ # Optional: cleanup policy for old records
167
+ AGENTIC_DJANGO_CLEANUP_POLICY = {
168
+ "events_days": 7,
169
+ "runs_days": 30,
170
+ "runs_statuses": ["completed", "failed"],
171
+ "sessions_days": 90,
172
+ "sessions_require_empty": True,
173
+ "batch_size": 500,
174
+ }
175
+ ```
176
+
177
+ ## Optional dependencies
178
+
179
+ - RQ-backed tasks: `pdm install -G rq`
180
+ - Postgres driver: `pdm install -G postgres`
181
+
182
+ ## Event streaming (optional)
183
+
184
+ When `AGENTIC_DJANGO_ENABLE_EVENTS = True`, each agent run persists semantic events
185
+ (tool calls, tool outputs, message items). Poll for events with:
186
+
187
+ ```
188
+ GET /runs/<uuid:run_id>/events/?after=<sequence>&limit=<n>
189
+ ```
190
+
191
+ You can also subscribe to the Django signal `agent_run_event` to push UI updates
192
+ after each event is stored.
193
+
194
+ Provide a registry that returns agent factories:
195
+
196
+ ```python
197
+ from agents import Agent
198
+ from my_project.models import MyModelProvider
199
+
200
+ def get_agent_registry():
201
+ def build_default():
202
+ return Agent(
203
+ name="Support Agent",
204
+ instructions="Help the user with account issues.",
205
+ model=MyModelProvider(),
206
+ )
207
+
208
+ return {"default": build_default}
209
+ ```
210
+
211
+ ## Operations
212
+
213
+ Prune old data with the cleanup command (uses `AGENTIC_DJANGO_CLEANUP_POLICY` by default):
214
+
215
+ ```bash
216
+ python manage.py agentic_django_cleanup --dry-run
217
+ python manage.py agentic_django_cleanup --events-days 14 --runs-days 60
218
+ ```
219
+
220
+ Recover runs stuck in `running` after a restart:
221
+
222
+ ```bash
223
+ python manage.py agentic_django_recover_runs --mode=fail
224
+ python manage.py agentic_django_recover_runs --mode=requeue
225
+ ```
226
+
227
+ Startup recovery runs on the first run dispatch/execution in each process, so it does
228
+ not touch the database during app initialization.
229
+
230
+ ## Security notes
231
+
232
+ - Enable Django 6’s Content Security Policy support where feasible, and open
233
+ `connect-src` only to the endpoints your UI needs (for polling or tooling).
234
+ - Keep agent tool registries scoped; do not expose powerful tools to untrusted
235
+ user input without additional validation or allowlists.
236
+
237
+ ## Example project
238
+
239
+ The sample project lives in the sibling `agentic-django-example` repo. See its
240
+ README for setup, Docker, and run instructions.
241
+
242
+ ## Tests
243
+
244
+ ```bash
245
+ pdm run test
246
+ ```
247
+
248
+ ## License
249
+
250
+ MIT. See `LICENSE`.
@@ -0,0 +1,94 @@
1
+ [project]
2
+ name = "agentic-django"
3
+ version = "0.1.0"
4
+ description = "Django integration for building agentic apps with the OpenAI Agents SDK"
5
+ authors = [
6
+ { name = "B.T. Franklin", email = "brandon.franklin@gmail.com" },
7
+ ]
8
+ dependencies = [
9
+ "Django>=6,<7",
10
+ "django-tasks>=0.11.0",
11
+ "openai-agents>=0.6.5",
12
+ "pydantic>=2.11.0",
13
+ ]
14
+ requires-python = ">=3.12"
15
+ readme = "README.md"
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3 :: Only",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Programming Language :: Python :: 3.13",
21
+ "Programming Language :: Python :: 3.14",
22
+ "Framework :: Django",
23
+ "Typing :: Typed",
24
+ "License :: OSI Approved :: MIT License",
25
+ "Operating System :: OS Independent",
26
+ "Intended Audience :: Developers",
27
+ "Topic :: Internet :: WWW/HTTP",
28
+ "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
29
+ "Topic :: Software Development :: Libraries :: Python Modules",
30
+ ]
31
+
32
+ [project.license]
33
+ file = "LICENSE"
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/btfranklin/agentic-django"
37
+ Issues = "https://github.com/btfranklin/agentic-django/issues"
38
+ Changelog = "https://github.com/btfranklin/agentic-django/releases"
39
+ Repository = "https://github.com/btfranklin/agentic-django.git"
40
+
41
+ [project.optional-dependencies]
42
+ rq = [
43
+ "django-tasks[rq]>=0.11.0",
44
+ "redis>=5.0.0",
45
+ ]
46
+ postgres = [
47
+ "psycopg[binary]>=3.2.0",
48
+ ]
49
+
50
+ [build-system]
51
+ requires = [
52
+ "pdm-backend",
53
+ ]
54
+ build-backend = "pdm.backend"
55
+
56
+ [tool.pdm]
57
+ distribution = true
58
+
59
+ [tool.pdm.build]
60
+ package-dir = "src"
61
+ includes = [
62
+ "src/agentic_django/**",
63
+ ]
64
+ excludes = [
65
+ "tests/**",
66
+ ]
67
+
68
+ [tool.pdm.scripts]
69
+ test = "pytest"
70
+ lint = "ruff check src tests"
71
+
72
+ [tool.pytest.ini_options]
73
+ DJANGO_SETTINGS_MODULE = "tests.settings"
74
+ django_find_project = false
75
+ pythonpath = [
76
+ ".",
77
+ ]
78
+ python_files = [
79
+ "test_*.py",
80
+ ]
81
+
82
+ [tool.ruff.lint]
83
+ select = [
84
+ "E",
85
+ "F",
86
+ "W",
87
+ ]
88
+
89
+ [dependency-groups]
90
+ dev = [
91
+ "pytest>=9.0.2",
92
+ "pytest-django>=4.11.1",
93
+ "ruff>=0.14.11",
94
+ ]
File without changes