django-admin-agent 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.
Files changed (39) hide show
  1. django_admin_agent/__init__.py +19 -0
  2. django_admin_agent/admin/__init__.py +0 -0
  3. django_admin_agent/admin/build_route_map.py +50 -0
  4. django_admin_agent/admin/build_sidebar_context.py +44 -0
  5. django_admin_agent/admin/sidebar_admin_site.py +26 -0
  6. django_admin_agent/conf.py +43 -0
  7. django_admin_agent/py.typed +0 -0
  8. django_admin_agent/static/django_admin_agent/admin_agent.js +50 -0
  9. django_admin_agent/static/django_admin_agent/admin_tools.js +482 -0
  10. django_admin_agent/static/django_admin_agent/ag-ui-web-component.bundle.js +319 -0
  11. django_admin_agent/static/django_admin_agent/unfold_shim.js +57 -0
  12. django_admin_agent/templates/django_admin_agent/sidebar.html +9 -0
  13. django_admin_agent/templatetags/__init__.py +0 -0
  14. django_admin_agent/templatetags/django_admin_agent.py +24 -0
  15. django_admin_agent/tools/__init__.py +0 -0
  16. django_admin_agent/tools/introspect/__init__.py +0 -0
  17. django_admin_agent/tools/introspect/get_settings_summary.py +70 -0
  18. django_admin_agent/tools/introspect/inspect_modeladmin.py +83 -0
  19. django_admin_agent/tools/introspect/list_admin_models.py +44 -0
  20. django_admin_agent/tools/introspect/list_installed_apps.py +23 -0
  21. django_admin_agent/tools/introspect/list_models.py +35 -0
  22. django_admin_agent/tools/introspect/list_signals.py +71 -0
  23. django_admin_agent/tools/introspect/list_urls.py +39 -0
  24. django_admin_agent/tools/introspect/register.py +25 -0
  25. django_admin_agent/tools/register.py +26 -0
  26. django_admin_agent/tools/shell/__init__.py +0 -0
  27. django_admin_agent/tools/shell/count_model.py +24 -0
  28. django_admin_agent/tools/shell/get_model_instance.py +31 -0
  29. django_admin_agent/tools/shell/inspect_model_schema.py +56 -0
  30. django_admin_agent/tools/shell/query_model.py +49 -0
  31. django_admin_agent/tools/shell/register.py +19 -0
  32. django_admin_agent/tools/types/__init__.py +0 -0
  33. django_admin_agent/tools/utils.py +33 -0
  34. django_admin_agent/urls.py +38 -0
  35. django_admin_agent/version.py +5 -0
  36. django_admin_agent-0.1.0.dist-info/METADATA +142 -0
  37. django_admin_agent-0.1.0.dist-info/RECORD +39 -0
  38. django_admin_agent-0.1.0.dist-info/WHEEL +4 -0
  39. django_admin_agent-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,19 @@
1
+ """An always-present chat-agent sidebar in the Django admin."""
2
+
3
+ from django_admin_agent.tools.introspect.register import register_introspect_tools
4
+ from django_admin_agent.tools.register import (
5
+ build_default_registry,
6
+ register_admin_tools,
7
+ )
8
+ from django_admin_agent.tools.shell.register import register_shell_tools
9
+ from django_admin_agent.urls import get_urls
10
+ from django_admin_agent.version import __version__
11
+
12
+ __all__ = [
13
+ "__version__",
14
+ "build_default_registry",
15
+ "get_urls",
16
+ "register_admin_tools",
17
+ "register_introspect_tools",
18
+ "register_shell_tools",
19
+ ]
File without changes
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from django.contrib import admin
6
+ from django.urls import NoReverseMatch, reverse
7
+
8
+
9
+ def build_route_map() -> list[dict[str, Any]]:
10
+ """Build the agent's navigable-route manifest from the admin registry.
11
+
12
+ One changelist route (and one add route, when available) per registered
13
+ model, shaped for the Web Component's ``routeMap`` — ``{id, path, title,
14
+ group}``. The agent calls ``list_routes`` to discover destinations and
15
+ ``navigate_to_route`` to jump to one, instead of guessing admin URLs.
16
+ """
17
+ routes: list[dict[str, Any]] = []
18
+ for model_cls in admin.site._registry:
19
+ meta = model_cls._meta
20
+ changelist = _admin_url(meta, "changelist")
21
+ if changelist is not None:
22
+ routes.append(
23
+ {
24
+ "id": f"{meta.app_label}.{meta.model_name}.changelist",
25
+ "path": changelist,
26
+ "title": str(meta.verbose_name_plural),
27
+ "group": meta.app_label,
28
+ },
29
+ )
30
+ add = _admin_url(meta, "add")
31
+ if add is not None:
32
+ routes.append(
33
+ {
34
+ "id": f"{meta.app_label}.{meta.model_name}.add",
35
+ "path": add,
36
+ "title": f"Add {meta.verbose_name}",
37
+ "group": meta.app_label,
38
+ },
39
+ )
40
+ return routes
41
+
42
+
43
+ def _admin_url(meta: Any, action: str) -> str | None:
44
+ try:
45
+ return reverse(f"admin:{meta.app_label}_{meta.model_name}_{action}")
46
+ except NoReverseMatch:
47
+ return None
48
+
49
+
50
+ __all__ = ["build_route_map"]
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from django.templatetags.static import static
6
+ from django.urls import NoReverseMatch, reverse
7
+
8
+ from django_admin_agent.admin.build_route_map import build_route_map
9
+ from django_admin_agent.conf import get_settings
10
+
11
+ _BUNDLE_PATH = "django_admin_agent/admin_agent.js"
12
+
13
+
14
+ def build_sidebar_context() -> dict[str, Any]:
15
+ """Build the context the sidebar template needs.
16
+
17
+ Reverses the AG-UI endpoint URL, resolves the bootstrap module's static
18
+ URL, reads the title / auto-confirm flag from settings, and resolves the
19
+ admin index URL so the frontend ``nav.*`` tools can build changelist /
20
+ changeform URLs without reversing named routes in the browser. Shared by
21
+ the ``{% django_admin_agent_sidebar %}`` template tag and the
22
+ :class:`~django_admin_agent.admin.sidebar_admin_site.SidebarAdminSite`
23
+ ``each_context`` hook.
24
+ """
25
+ config = get_settings()
26
+ return {
27
+ "endpoint": reverse(config.endpoint_url_name),
28
+ "title": config.title,
29
+ "auto_confirm": config.auto_confirm,
30
+ "bootstrap_url": static(_BUNDLE_PATH),
31
+ "admin_base_url": _admin_base_url(),
32
+ "route_map": build_route_map(),
33
+ }
34
+
35
+
36
+ def _admin_base_url() -> str:
37
+ """Resolve the admin index URL (e.g. ``/admin/``), or ``/`` if unmounted."""
38
+ try:
39
+ return reverse("admin:index")
40
+ except NoReverseMatch:
41
+ return "/"
42
+
43
+
44
+ __all__ = ["build_sidebar_context"]
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from django.contrib.admin import AdminSite
6
+ from django.http import HttpRequest
7
+
8
+ from django_admin_agent.admin.build_sidebar_context import build_sidebar_context
9
+
10
+
11
+ class SidebarAdminSite(AdminSite):
12
+ """A drop-in ``AdminSite`` that exposes the sidebar config to every page.
13
+
14
+ Adds ``django_admin_agent`` (the sidebar context) to ``each_context`` so
15
+ a base template can render the chat without the template tag. Using the
16
+ ``{% django_admin_agent_sidebar %}`` tag in ``admin/base_site.html`` is
17
+ the more common path and does not require swapping the admin site.
18
+ """
19
+
20
+ def each_context(self, request: HttpRequest) -> dict[str, Any]:
21
+ context = super().each_context(request)
22
+ context["django_admin_agent"] = build_sidebar_context()
23
+ return context
24
+
25
+
26
+ __all__ = ["SidebarAdminSite"]
@@ -0,0 +1,43 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any
5
+
6
+ from django.conf import settings
7
+
8
+ _SETTING_NAME = "DJANGO_ADMIN_AGENT"
9
+
10
+
11
+ @dataclass(frozen=True)
12
+ class AdminAgentSettings:
13
+ """Snapshot of the user-configurable ``DJANGO_ADMIN_AGENT`` settings.
14
+
15
+ Built fresh on every read so test overrides take effect immediately.
16
+ The agent model itself is configured separately via ``django-ag-ui``'s
17
+ ``DJANGO_AG_UI["MODEL"]``.
18
+ """
19
+
20
+ title: str
21
+ """Header text shown on the sidebar chat panel."""
22
+
23
+ auto_confirm: bool
24
+ """When ``True``, destructive UI tools run without a confirmation modal.
25
+ Passed to the Web Component as ``autoConfirm``."""
26
+
27
+ endpoint_url_name: str
28
+ """URL name to reverse for the AG-UI endpoint. Mount it with
29
+ :func:`django_admin_agent.get_urls` (which names it
30
+ ``django_admin_agent_endpoint``)."""
31
+
32
+
33
+ def get_settings() -> AdminAgentSettings:
34
+ """Read the active ``DJANGO_ADMIN_AGENT`` settings dict."""
35
+ raw: dict[str, Any] = getattr(settings, _SETTING_NAME, {}) or {}
36
+ return AdminAgentSettings(
37
+ title=raw.get("TITLE", "Admin Copilot"),
38
+ auto_confirm=bool(raw.get("AUTO_CONFIRM", False)),
39
+ endpoint_url_name=raw.get("ENDPOINT_URL_NAME", "django_admin_agent_endpoint"),
40
+ )
41
+
42
+
43
+ __all__ = ["AdminAgentSettings", "get_settings"]
File without changes
@@ -0,0 +1,50 @@
1
+ // Bootstrap for the Django-admin chat sidebar. Loaded as an ES module from
2
+ // the same static directory as the vendored web-component bundle, so it can
3
+ // import the component by relative path.
4
+ //
5
+ // Responsibilities:
6
+ // - register the <ag-ui-chat> custom element
7
+ // - attach the CSRF header so the AG-UI endpoint accepts POSTs under the
8
+ // logged-in admin session
9
+ // - read the auto-confirm flag from the element's data attribute
10
+ // - register the admin-aware frontend tools (DOM driving) — see
11
+ // ./admin_tools.js
12
+ import { defineAgUiChat } from "./ag-ui-web-component.bundle.js";
13
+ import { registerAdminTools } from "./admin_tools.js";
14
+
15
+ function readCsrfToken() {
16
+ const match = document.cookie.match(/(?:^|;\s*)csrftoken=([^;]+)/);
17
+ return match ? decodeURIComponent(match[1]) : "";
18
+ }
19
+
20
+ // The navigable route manifest the server embedded (admin changelists/add
21
+ // pages), driving the component's list_routes / navigate_to_route tools.
22
+ function readRouteMap() {
23
+ const node = document.getElementById("django-admin-agent-routes");
24
+ if (node === null) {
25
+ return [];
26
+ }
27
+ try {
28
+ return JSON.parse(node.textContent);
29
+ } catch {
30
+ return [];
31
+ }
32
+ }
33
+
34
+ function bootstrap() {
35
+ defineAgUiChat();
36
+ const el = document.querySelector("ag-ui-chat#django-admin-agent");
37
+ if (el === null) {
38
+ return;
39
+ }
40
+ el.headers = { "X-CSRFToken": readCsrfToken() };
41
+ el.autoConfirm = el.getAttribute("data-auto-confirm") === "true";
42
+ el.routeMap = readRouteMap();
43
+ registerAdminTools(el);
44
+ }
45
+
46
+ if (document.readyState === "loading") {
47
+ document.addEventListener("DOMContentLoaded", bootstrap);
48
+ } else {
49
+ bootstrap();
50
+ }