Skip to content

Repository files navigation

django-agents

An agent runtime for Django, with an optional Wagtail integration. Define agents in code, configure models and credentials in the database, and drop a streaming chat widget into any Django, Django-admin, or Wagtail page.

  • litellm under the hood — talk to OpenAI, Anthropic, Google, Mistral, Ollama, or any OpenAI-compatible endpoint.
  • Streaming over SSE — no Channels, no ASGI requirement, no WebSockets.
  • Tools are just methods — decorate a method with @tool and the JSON schema is generated from its type hints and docstring.
  • Secrets stay on the server — API keys are encrypted at rest and write-only through every admin surface.

Screenshots: placeholder — add chat widget / admin screenshots here.

Install

pip install django-agents          # add ".[wagtail]" for the Wagtail integration

Add the app and mount the URLs:

# settings.py
INSTALLED_APPS = [
    # ...
    "django_agents",
]

DJANGO_AGENTS = {
    "DEFAULT_MODEL": "anthropic/claude-sonnet-4-5",
}
# urls.py
urlpatterns = [
    # ...
    path("agents/", include("django_agents.urls")),
]
python manage.py migrate

Quickstart

1. Register an agent in any installed app's agents.py (autodiscovered):

from django_agents.base import Agent, register, tool


@register
class WeatherAgent(Agent):
    slug = "weather"
    name = "Weather assistant"
    system_prompt = "You help with the weather."

    @tool
    def forecast(self, city: str) -> str:
        """Return the forecast for a city.

        :param city: The city to look up.
        """
        return f"It's sunny in {city}."

python manage.py startagent WeatherAgent --app myapp scaffolds this for you.

2. Add a credential. In the Django admin, add a Provider credential with your API key and mark it default. (Keys are encrypted at rest and never returned by the API.)

3. Embed the widget in a template:

{% load agent_tags %}
<head>{% agent_chat_assets %}</head>
<body>{% agent_chat "weather" %}</body>

Or link to the built-in standalone page at /agents/chat/weather/.

60-second demo (sandbox)

cd sandbox
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver
# visit /django-admin/ → add a Provider credential (mark default)
# visit /agents/chat/assistant/ and chat

Set WAGTAIL=1 before runserver to explore the Wagtail integration instead.

Settings reference

All settings live under a single DJANGO_AGENTS dict.

Key Default Meaning
DEFAULT_MODEL None litellm model string used when an agent doesn't set model (e.g. "anthropic/claude-sonnet-4-5").
BACKEND "django_agents.runtime.LiteLLMBackend" Dotted path to the runtime backend. Swap for FakeBackend in tests.
MAX_TOOL_ROUNDS 10 Max tool-execution rounds per run before the run is stopped.
REQUEST_TIMEOUT 60.0 Seconds before a single backend call is aborted, so a hung provider can't wedge a worker indefinitely.
ENCRYPTION_KEY None Overrides SECRET_KEY-derived encryption for stored credentials. Set this to rotate SECRET_KEY without invalidating keys.
REQUIRE_AUTH True Require an authenticated user on every endpoint. Disable only for public demo agents (and understand the risks).
RATE_LIMIT {"PER_MINUTE": 20, "PER_DAY": 200} Per-user message budget for the chat endpoint. Set a window to None to disable it.
RATE_LIMITER "django_agents.ratelimit.CacheRateLimiter" Dotted path to the rate limiter class. Needs a shared cache backend (Redis/Memcached) in multi-process deployments — see Deployment notes.
MAX_CONCURRENT_RUNS 3 Per-user cap on simultaneously in-flight runs, across all of a user's threads. None/0 disables it.
TRACE "auto" Build run traces: "auto" (on iff django_agents.observability is installed), True, or False.
TRACE_CONTENT "full" "full" stores prompts/outputs; "metadata" stores only char counts.
TRACE_SAMPLE 1.0 Fraction of runs (0–1) to build a trace for; unsampled runs still get a row.
OBSERVABILITY_PERMISSION None Dotted path to a callable(user) -> bool gating the run browser; default is a staff check.
OTEL False Emit OpenTelemetry spans (needs opentelemetry-api and OTEL_HOOK).
OTEL_HOOK "django_agents.observability.otel.span_factory" Dotted path to the OTel span factory.
JUDGE_MODEL None Default model for llm_judge eval checks.

The last seven keys are used only by the optional django_agents.observability app (tracing, a run browser, OpenTelemetry export, and evals). See the docs.

Deployment notes

Streaming uses Server-Sent Events, which need a worker that does not buffer the response. It works under runserver and gunicorn's sync worker for modest concurrency. Any reverse proxy in front must have response buffering disabled — the X-Accel-Buffering: no header covers nginx; other proxies need their own configuration.

Rate limiting

The default RATE_LIMIT (20/min, 200/day per user) is enforced by counting messages in CACHES["default"]. That count is only accurate when the cache is shared across worker processes — Redis or Memcached. On Django's default per-process LocMemCache, each worker keeps its own counter, so the effective limit becomes configured limit × worker count. A system check (django_agents.W001) warns about this whenever DEBUG = False and no shared cache is configured — point CACHES["default"] at Redis/Memcached in any deployment running more than one worker process.

Development

uv venv --python 3.12
uv pip install -e ".[dev,wagtail]"
pytest                                             # plain Django
DJANGO_SETTINGS_MODULE=tests.settings_wagtail pytest  # with Wagtail

See sandbox/README.md for running the demo project.

About

Agentic AI agents for django and wagtail

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages