django-auto-agent 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.
- django_auto_agent-0.1.0/LICENSE +21 -0
- django_auto_agent-0.1.0/MANIFEST.in +6 -0
- django_auto_agent-0.1.0/PKG-INFO +156 -0
- django_auto_agent-0.1.0/README.md +110 -0
- django_auto_agent-0.1.0/ai_agent/Dockerfile +12 -0
- django_auto_agent-0.1.0/ai_agent/__init__.py +9 -0
- django_auto_agent-0.1.0/ai_agent/admin/__init__.py +9 -0
- django_auto_agent-0.1.0/ai_agent/admin/_helpers.py +68 -0
- django_auto_agent-0.1.0/ai_agent/admin/_query.py +1256 -0
- django_auto_agent-0.1.0/ai_agent/admin/memories.py +167 -0
- django_auto_agent-0.1.0/ai_agent/admin/messages.py +40 -0
- django_auto_agent-0.1.0/ai_agent/admin/prompts.py +154 -0
- django_auto_agent-0.1.0/ai_agent/admin/threads.py +129 -0
- django_auto_agent-0.1.0/ai_agent/apps.py +14 -0
- django_auto_agent-0.1.0/ai_agent/auth.py +130 -0
- django_auto_agent-0.1.0/ai_agent/compaction.py +102 -0
- django_auto_agent-0.1.0/ai_agent/conf.py +494 -0
- django_auto_agent-0.1.0/ai_agent/context.py +212 -0
- django_auto_agent-0.1.0/ai_agent/discovery.py +239 -0
- django_auto_agent-0.1.0/ai_agent/evals/__init__.py +1 -0
- django_auto_agent-0.1.0/ai_agent/evals/cases.py +97 -0
- django_auto_agent-0.1.0/ai_agent/evals/fixtures.py +61 -0
- django_auto_agent-0.1.0/ai_agent/evals/harness.py +253 -0
- django_auto_agent-0.1.0/ai_agent/evals/report.py +71 -0
- django_auto_agent-0.1.0/ai_agent/evals/runtime.py +44 -0
- django_auto_agent-0.1.0/ai_agent/evals/scoring.py +375 -0
- django_auto_agent-0.1.0/ai_agent/executor.py +140 -0
- django_auto_agent-0.1.0/ai_agent/expose.py +63 -0
- django_auto_agent-0.1.0/ai_agent/graph.py +797 -0
- django_auto_agent-0.1.0/ai_agent/http_auth.py +114 -0
- django_auto_agent-0.1.0/ai_agent/limits.py +128 -0
- django_auto_agent-0.1.0/ai_agent/management/__init__.py +1 -0
- django_auto_agent-0.1.0/ai_agent/management/commands/__init__.py +1 -0
- django_auto_agent-0.1.0/ai_agent/management/commands/eval_agent.py +75 -0
- django_auto_agent-0.1.0/ai_agent/management/commands/optimize_agent_prompts.py +83 -0
- django_auto_agent-0.1.0/ai_agent/management/commands/reconcile_agent_memory.py +64 -0
- django_auto_agent-0.1.0/ai_agent/management/commands/seed_memory_optimizer_fixture.py +260 -0
- django_auto_agent-0.1.0/ai_agent/memory/__init__.py +11 -0
- django_auto_agent-0.1.0/ai_agent/memory/curator.py +416 -0
- django_auto_agent-0.1.0/ai_agent/memory/managers.py +311 -0
- django_auto_agent-0.1.0/ai_agent/memory/middleware.py +434 -0
- django_auto_agent-0.1.0/ai_agent/memory/namespaces.py +114 -0
- django_auto_agent-0.1.0/ai_agent/memory/optimizer_fixture.py +319 -0
- django_auto_agent-0.1.0/ai_agent/memory/prompt_optimize.py +1122 -0
- django_auto_agent-0.1.0/ai_agent/memory/reconcile.py +573 -0
- django_auto_agent-0.1.0/ai_agent/memory/schemas.py +80 -0
- django_auto_agent-0.1.0/ai_agent/memory/spec.py +61 -0
- django_auto_agent-0.1.0/ai_agent/memory/store.py +107 -0
- django_auto_agent-0.1.0/ai_agent/memory/supervisor_schemas.py +67 -0
- django_auto_agent-0.1.0/ai_agent/memory/tools.py +589 -0
- django_auto_agent-0.1.0/ai_agent/memory/user_memories.py +139 -0
- django_auto_agent-0.1.0/ai_agent/messages.py +24 -0
- django_auto_agent-0.1.0/ai_agent/migrations/0001_initial.py +53 -0
- django_auto_agent-0.1.0/ai_agent/migrations/0002_agentmessage.py +62 -0
- django_auto_agent-0.1.0/ai_agent/migrations/0003_agentprompt.py +31 -0
- django_auto_agent-0.1.0/ai_agent/migrations/__init__.py +1 -0
- django_auto_agent-0.1.0/ai_agent/models.py +71 -0
- django_auto_agent-0.1.0/ai_agent/runtime.py +192 -0
- django_auto_agent-0.1.0/ai_agent/safety.py +179 -0
- django_auto_agent-0.1.0/ai_agent/schema.py +376 -0
- django_auto_agent-0.1.0/ai_agent/serializers.py +26 -0
- django_auto_agent-0.1.0/ai_agent/studio.py +61 -0
- django_auto_agent-0.1.0/ai_agent/templates/admin/ai_agent/confirm_delete.html +28 -0
- django_auto_agent-0.1.0/ai_agent/templates/admin/ai_agent/memory_list.html +159 -0
- django_auto_agent-0.1.0/ai_agent/templates/admin/ai_agent/memory_user.html +213 -0
- django_auto_agent-0.1.0/ai_agent/templates/admin/ai_agent/prompt_detail.html +89 -0
- django_auto_agent-0.1.0/ai_agent/templates/admin/ai_agent/prompt_list.html +188 -0
- django_auto_agent-0.1.0/ai_agent/templates/admin/ai_agent/thread_detail.html +108 -0
- django_auto_agent-0.1.0/ai_agent/templates/admin/ai_agent/thread_list.html +141 -0
- django_auto_agent-0.1.0/ai_agent/tools.py +130 -0
- django_auto_agent-0.1.0/ai_agent/transcript.py +177 -0
- django_auto_agent-0.1.0/ai_agent/urls.py +18 -0
- django_auto_agent-0.1.0/ai_agent/views.py +178 -0
- django_auto_agent-0.1.0/django_auto_agent.egg-info/PKG-INFO +156 -0
- django_auto_agent-0.1.0/django_auto_agent.egg-info/SOURCES.txt +78 -0
- django_auto_agent-0.1.0/django_auto_agent.egg-info/dependency_links.txt +1 -0
- django_auto_agent-0.1.0/django_auto_agent.egg-info/requires.txt +17 -0
- django_auto_agent-0.1.0/django_auto_agent.egg-info/top_level.txt +1 -0
- django_auto_agent-0.1.0/pyproject.toml +70 -0
- django_auto_agent-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alireza fz
|
|
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,156 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-auto-agent
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Django reusable app: DRF-to-LangGraph agent bridge with long-term memory.
|
|
5
|
+
Author: Alireza fz
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/alirezafz/django-auto-agent
|
|
8
|
+
Project-URL: Repository, https://github.com/alirezafz/django-auto-agent
|
|
9
|
+
Project-URL: Issues, https://github.com/alirezafz/django-auto-agent/issues
|
|
10
|
+
Keywords: django,djangorestframework,langgraph,agent,copilotkit
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Web Environment
|
|
13
|
+
Classifier: Framework :: Django
|
|
14
|
+
Classifier: Framework :: Django :: 4.2
|
|
15
|
+
Classifier: Framework :: Django :: 5.0
|
|
16
|
+
Classifier: Framework :: Django :: 5.1
|
|
17
|
+
Classifier: Framework :: Django :: 5.2
|
|
18
|
+
Classifier: Intended Audience :: Developers
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: Django>=4.2
|
|
30
|
+
Requires-Dist: djangorestframework
|
|
31
|
+
Requires-Dist: drf-spectacular
|
|
32
|
+
Requires-Dist: fastapi
|
|
33
|
+
Requires-Dist: langchain>=1.0.0
|
|
34
|
+
Requires-Dist: langchain-openai>=1.0.0
|
|
35
|
+
Requires-Dist: langgraph>=1.0.0
|
|
36
|
+
Requires-Dist: langgraph-checkpoint-postgres>=2.0.0
|
|
37
|
+
Requires-Dist: langgraph-sdk>=0.1.61
|
|
38
|
+
Requires-Dist: langmem>=0.0.29
|
|
39
|
+
Requires-Dist: psycopg[binary]>=3.1.0
|
|
40
|
+
Requires-Dist: psycopg-pool>=3.2.0
|
|
41
|
+
Requires-Dist: copilotkit>=0.1.96
|
|
42
|
+
Provides-Extra: redis
|
|
43
|
+
Requires-Dist: redis>=5.0.0; extra == "redis"
|
|
44
|
+
Requires-Dist: langgraph-checkpoint-redis; extra == "redis"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
# django-auto-agent
|
|
48
|
+
|
|
49
|
+
Django reusable app that turns opted-in DRF endpoints into a LangGraph supervisor, with optional long-term memory, admin views, and evals.
|
|
50
|
+
|
|
51
|
+
Import name: `ai_agent`.
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install django-auto-agent
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Redis-backed memory store (optional):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install "django-auto-agent[redis]"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
From a clone of this repository:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install -e .
|
|
69
|
+
pip install -e ".[redis]"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Host wiring
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
INSTALLED_APPS = [
|
|
76
|
+
# ...
|
|
77
|
+
"ai_agent",
|
|
78
|
+
"catalog", # your domain app
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
AI_AGENT = {
|
|
82
|
+
"SUPERVISOR_MODEL": "openai:gpt-4.1-mini",
|
|
83
|
+
"SUBAGENT_MODEL": "openai:gpt-4.1-nano",
|
|
84
|
+
"AUTHENTICATE_TOKEN": "myproject.auth.authenticate_access_token",
|
|
85
|
+
"PLATFORM_NAME": "Acme",
|
|
86
|
+
"PLATFORM_DOMAINS": ("catalog", "billing"),
|
|
87
|
+
"EVAL_MODULE": "catalog.evals",
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`AUTHENTICATE_TOKEN` is required. It must be a callable (or dotted path to one) that accepts a bearer token and returns a user object with `.pk`.
|
|
92
|
+
|
|
93
|
+
Optional evals — point `EVAL_MODULE` at a host module that defines:
|
|
94
|
+
|
|
95
|
+
- `seed_eval_world() -> EvalWorld` (users plus `prompt_vars` for case prompts)
|
|
96
|
+
- `snapshot_world(world, kind) -> dict` (optional; used by mutation cases)
|
|
97
|
+
- `CASES: list[EvalCase]` (or partitioned `ROUTING_CASES` / `TOOL_CASES` / `MUTATION_CASES` / `E2E_CASES`)
|
|
98
|
+
|
|
99
|
+
The library always includes safety routing cases (off-policy greeting, jailbreaks). Domain tool and mutation cases come from the host module. See `dummy/evals.py` in this repo.
|
|
100
|
+
|
|
101
|
+
`HTTP_TRUSTED_PROXY_COUNT` (default `0`) controls whether the CopilotKit HTTP throttle reads `X-Forwarded-For`. Leave it at `0` unless the app sits behind that many trusted reverse proxies; otherwise clients can rotate a spoofed header and bypass the limit.
|
|
102
|
+
|
|
103
|
+
Include the chat/memory HTTP API:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
urlpatterns = [
|
|
107
|
+
path("api/agent/", include("ai_agent.urls")),
|
|
108
|
+
]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Opt a host app into the agent by setting flags on its `AppConfig`:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
class CatalogConfig(AppConfig):
|
|
115
|
+
name = "catalog"
|
|
116
|
+
agent_expose = True
|
|
117
|
+
agent_description = "List and create catalog items for the authenticated user."
|
|
118
|
+
agent_exclude = ("internal_webhook",)
|
|
119
|
+
agent_memory_profile = "catalog.memory_schemas.CatalogProfile"
|
|
120
|
+
agent_memory_collections = (
|
|
121
|
+
"ai_agent.memory.schemas.SemanticFact",
|
|
122
|
+
"catalog.memory_schemas.CatalogAccount",
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Mark individual views even when the app is off:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from ai_agent.expose import agent_expose, agent_exclude
|
|
130
|
+
|
|
131
|
+
@agent_expose
|
|
132
|
+
def public_note(request):
|
|
133
|
+
...
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## LangGraph Agent Server
|
|
137
|
+
|
|
138
|
+
This package is not a host Docker image. Install `django-auto-agent` **and** your Django project into the Agent Server image, then point `langgraph.json` at the library entrypoints (see the example `langgraph.json` in this repo):
|
|
139
|
+
|
|
140
|
+
- graphs: `ai_agent.studio:graph`, `ai_agent.studio:memory`
|
|
141
|
+
- auth: `ai_agent.auth:auth`
|
|
142
|
+
- HTTP app: `ai_agent.studio:app`
|
|
143
|
+
|
|
144
|
+
Set `DJANGO_SETTINGS_MODULE` (or `AI_AGENT_STUDIO_DJANGO_SETTINGS`) to **your** settings module before starting Studio.
|
|
145
|
+
|
|
146
|
+
The example `langgraph.json` uses `cors.allow_origins: ["*"]`. Auth is Bearer-token based (not cookies), so CSRF exposure is limited; restrict origins in production.
|
|
147
|
+
|
|
148
|
+
## Tests
|
|
149
|
+
|
|
150
|
+
From this repo:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
python manage.py test ai_agent
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The `dummy` and `notes` apps plus `tests/settings.py` are a sample host. They are not installed with the wheel.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# django-auto-agent
|
|
2
|
+
|
|
3
|
+
Django reusable app that turns opted-in DRF endpoints into a LangGraph supervisor, with optional long-term memory, admin views, and evals.
|
|
4
|
+
|
|
5
|
+
Import name: `ai_agent`.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install django-auto-agent
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Redis-backed memory store (optional):
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install "django-auto-agent[redis]"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
From a clone of this repository:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install -e .
|
|
23
|
+
pip install -e ".[redis]"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Host wiring
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
INSTALLED_APPS = [
|
|
30
|
+
# ...
|
|
31
|
+
"ai_agent",
|
|
32
|
+
"catalog", # your domain app
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
AI_AGENT = {
|
|
36
|
+
"SUPERVISOR_MODEL": "openai:gpt-4.1-mini",
|
|
37
|
+
"SUBAGENT_MODEL": "openai:gpt-4.1-nano",
|
|
38
|
+
"AUTHENTICATE_TOKEN": "myproject.auth.authenticate_access_token",
|
|
39
|
+
"PLATFORM_NAME": "Acme",
|
|
40
|
+
"PLATFORM_DOMAINS": ("catalog", "billing"),
|
|
41
|
+
"EVAL_MODULE": "catalog.evals",
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`AUTHENTICATE_TOKEN` is required. It must be a callable (or dotted path to one) that accepts a bearer token and returns a user object with `.pk`.
|
|
46
|
+
|
|
47
|
+
Optional evals — point `EVAL_MODULE` at a host module that defines:
|
|
48
|
+
|
|
49
|
+
- `seed_eval_world() -> EvalWorld` (users plus `prompt_vars` for case prompts)
|
|
50
|
+
- `snapshot_world(world, kind) -> dict` (optional; used by mutation cases)
|
|
51
|
+
- `CASES: list[EvalCase]` (or partitioned `ROUTING_CASES` / `TOOL_CASES` / `MUTATION_CASES` / `E2E_CASES`)
|
|
52
|
+
|
|
53
|
+
The library always includes safety routing cases (off-policy greeting, jailbreaks). Domain tool and mutation cases come from the host module. See `dummy/evals.py` in this repo.
|
|
54
|
+
|
|
55
|
+
`HTTP_TRUSTED_PROXY_COUNT` (default `0`) controls whether the CopilotKit HTTP throttle reads `X-Forwarded-For`. Leave it at `0` unless the app sits behind that many trusted reverse proxies; otherwise clients can rotate a spoofed header and bypass the limit.
|
|
56
|
+
|
|
57
|
+
Include the chat/memory HTTP API:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
urlpatterns = [
|
|
61
|
+
path("api/agent/", include("ai_agent.urls")),
|
|
62
|
+
]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Opt a host app into the agent by setting flags on its `AppConfig`:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
class CatalogConfig(AppConfig):
|
|
69
|
+
name = "catalog"
|
|
70
|
+
agent_expose = True
|
|
71
|
+
agent_description = "List and create catalog items for the authenticated user."
|
|
72
|
+
agent_exclude = ("internal_webhook",)
|
|
73
|
+
agent_memory_profile = "catalog.memory_schemas.CatalogProfile"
|
|
74
|
+
agent_memory_collections = (
|
|
75
|
+
"ai_agent.memory.schemas.SemanticFact",
|
|
76
|
+
"catalog.memory_schemas.CatalogAccount",
|
|
77
|
+
)
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Mark individual views even when the app is off:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from ai_agent.expose import agent_expose, agent_exclude
|
|
84
|
+
|
|
85
|
+
@agent_expose
|
|
86
|
+
def public_note(request):
|
|
87
|
+
...
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## LangGraph Agent Server
|
|
91
|
+
|
|
92
|
+
This package is not a host Docker image. Install `django-auto-agent` **and** your Django project into the Agent Server image, then point `langgraph.json` at the library entrypoints (see the example `langgraph.json` in this repo):
|
|
93
|
+
|
|
94
|
+
- graphs: `ai_agent.studio:graph`, `ai_agent.studio:memory`
|
|
95
|
+
- auth: `ai_agent.auth:auth`
|
|
96
|
+
- HTTP app: `ai_agent.studio:app`
|
|
97
|
+
|
|
98
|
+
Set `DJANGO_SETTINGS_MODULE` (or `AI_AGENT_STUDIO_DJANGO_SETTINGS`) to **your** settings module before starting Studio.
|
|
99
|
+
|
|
100
|
+
The example `langgraph.json` uses `cors.allow_origins: ["*"]`. Auth is Bearer-token based (not cookies), so CSRF exposure is limited; restrict origins in production.
|
|
101
|
+
|
|
102
|
+
## Tests
|
|
103
|
+
|
|
104
|
+
From this repo:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
python manage.py test ai_agent
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The `dummy` and `notes` apps plus `tests/settings.py` are a sample host. They are not installed with the wheel.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Example only. django-auto-agent is a pip library, not a host image.
|
|
2
|
+
#
|
|
3
|
+
# Build the LangGraph Agent Server from YOUR Django project:
|
|
4
|
+
# 1. pip install django-auto-agent
|
|
5
|
+
# 2. COPY your Django project into the image
|
|
6
|
+
# 3. Set DJANGO_SETTINGS_MODULE to your settings
|
|
7
|
+
# 4. Point langgraph.json at ai_agent.studio and ai_agent.auth
|
|
8
|
+
#
|
|
9
|
+
# See README.md and the example langgraph.json in this repository.
|
|
10
|
+
|
|
11
|
+
FROM langchain/langgraph-api:3.11-bookworm
|
|
12
|
+
RUN echo "Install django-auto-agent and your Django host project; do not copy a product tree into this library."
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Opt-in DRF-to-LangGraph agent bridge.
|
|
2
|
+
|
|
3
|
+
Extractable surface: expose, discovery, schema, executor, tools, graph, context.
|
|
4
|
+
Product wiring (chat view, Django settings) stays in this app.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from ai_agent.expose import agent_exclude, agent_expose
|
|
8
|
+
|
|
9
|
+
__all__ = ["agent_expose", "agent_exclude"]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Shared presentation helpers for AI agent admin views."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from django.core.paginator import EmptyPage, Paginator
|
|
6
|
+
from django.urls import NoReverseMatch, reverse
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def user_display_name(user) -> str:
|
|
10
|
+
"""Prefer first/last name, then ``get_username()``."""
|
|
11
|
+
if user is None:
|
|
12
|
+
return ""
|
|
13
|
+
name = " ".join(
|
|
14
|
+
part
|
|
15
|
+
for part in (getattr(user, "first_name", None), getattr(user, "last_name", None))
|
|
16
|
+
if part
|
|
17
|
+
)
|
|
18
|
+
if name:
|
|
19
|
+
return name
|
|
20
|
+
getter = getattr(user, "get_username", None)
|
|
21
|
+
if callable(getter):
|
|
22
|
+
return str(getter() or "").strip()
|
|
23
|
+
return ""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def user_change_url(user) -> str:
|
|
27
|
+
"""Django admin change URL for the configured user model."""
|
|
28
|
+
if user is None:
|
|
29
|
+
return ""
|
|
30
|
+
opts = user._meta
|
|
31
|
+
try:
|
|
32
|
+
return reverse(
|
|
33
|
+
f"admin:{opts.app_label}_{opts.model_name}_change",
|
|
34
|
+
args=[user.pk],
|
|
35
|
+
)
|
|
36
|
+
except NoReverseMatch:
|
|
37
|
+
return ""
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def paginate(request, items, total: int, *, per_page: int = 25):
|
|
41
|
+
"""Build a Django page from an already-sliced list plus a known total."""
|
|
42
|
+
paginator = Paginator(range(total), per_page)
|
|
43
|
+
page_number = request.GET.get("p") or 1
|
|
44
|
+
try:
|
|
45
|
+
page = paginator.page(page_number)
|
|
46
|
+
except EmptyPage:
|
|
47
|
+
page = paginator.page(paginator.num_pages or 1)
|
|
48
|
+
page.object_list = items
|
|
49
|
+
return page, paginator
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def page_offset(request, *, per_page: int = 25) -> int:
|
|
53
|
+
try:
|
|
54
|
+
page_number = int(request.GET.get("p") or 1)
|
|
55
|
+
except (TypeError, ValueError):
|
|
56
|
+
page_number = 1
|
|
57
|
+
if page_number < 1:
|
|
58
|
+
page_number = 1
|
|
59
|
+
return (page_number - 1) * per_page
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def safe_next(raw: str, fallback: str) -> str:
|
|
63
|
+
"""Allow only a relative query string on the same admin path."""
|
|
64
|
+
value = (raw or "").strip()
|
|
65
|
+
path, _, _ = fallback.partition("?")
|
|
66
|
+
if value.startswith("?") and "://" not in value and "\n" not in value:
|
|
67
|
+
return path + value
|
|
68
|
+
return fallback
|