API reference¶
Autodoc of the public surface re-exported from django_ag_ui. Everything below
is importable directly, e.g. from django_ag_ui import ToolRegistry.
Registry¶
ToolRegistry ¶
An ordered, named collection of server-side tools.
State lives on the instance: a DjangoAGUIView holds one registry;
tests build a fresh registry per scenario. The registry derives a
JSON Schema for each tool at registration (including the
x-destructive / x-category extensions) and can dispatch sync
or async callables.
register ¶
Register spec and return its binding.
Raises:
| Type | Description |
|---|---|
ValueError
|
when |
call ¶
Dispatch a sync call to the registered tool.
Refuses coroutine functions to avoid silently returning an
un-awaited coroutine. Use :meth:acall for async tools.
acall
async
¶
Dispatch an async call; transparently awaits sync callables.
tool ¶
tool(
registry: ToolRegistry,
*,
name: str | None = None,
description: str | None = None,
destructive: bool = False,
category: ToolCategory = ToolCategory.OTHER,
confirm: str | None = None,
summary: str | None = None,
) -> Callable[[F], F]
Register the decorated callable on registry as a tool.
The tool's name defaults to the function name; its description
defaults to the first paragraph of the function's docstring. Both
can be overridden via the keyword arguments. confirm supplies a
human-readable confirmation prompt for a destructive tool (surfaced as
x-confirm); summary a short display label (surfaced as
x-summary).
build_input_schema ¶
build_input_schema(
fn: Callable[..., Any],
*,
destructive: bool = False,
category: ToolCategory = ToolCategory.OTHER,
confirm: str | None = None,
summary: str | None = None,
) -> dict[str, Any]
Derive a JSON Schema object from fn's parameters.
Supports the primitive types used by the built-in tool surface:
str, int, float, bool, list[T], dict[str, Any],
and X | None unions. Anything richer falls back to an empty
schema fragment (no type constraint), which is still wire-valid JSON
Schema.
The destructive flag is stamped at the schema root as
x-destructive; category as x-category; confirm (when
given) as x-confirm. AG-UI passes these extensions through
verbatim, and frontends read x-destructive / x-confirm to gate
execution behind a confirmation step.
ToolSpec
dataclass
¶
Canonical declaration of a server-side tool.
A ToolSpec bundles the callable with the metadata the registry
needs to expose it to a Pydantic-AI agent and to a frontend: a
stable name, a human-facing description, a destructive risk
flag, and a coarse category.
name
instance-attribute
¶
Stable identifier exposed to the agent. Must be unique within a
:class:~django_ag_ui.registry.tool_registry.ToolRegistry.
fn
instance-attribute
¶
The Python callable that implements the tool. Must have typed parameters; the registry derives a JSON Schema from the signature.
description
instance-attribute
¶
User-facing summary shown to the agent. The first line is what most clients display.
destructive
class-attribute
instance-attribute
¶
If True, calling this tool may mutate state. The registry
stamps x-destructive: true into the tool's JSON Schema so
frontends can gate it behind a confirmation step.
category
class-attribute
instance-attribute
¶
Coarse capability grouping. Surfaced as x-category in the
JSON Schema.
confirm
class-attribute
instance-attribute
¶
Optional human-readable confirmation prompt for a destructive tool
(e.g. "Activate this project?"). Stamped as x-confirm so the frontend
can show it instead of a generic "Run
summary
class-attribute
instance-attribute
¶
Optional short label for the tool (e.g. "Query orders"). Stamped as
x-summary so the frontend shows it on the tool-call card instead of the
raw tool name.
ToolBinding
dataclass
¶
A registered tool plus the JSON Schema derived from its signature.
The schema is computed once at registration (including the
x-destructive / x-category extensions) and carried alongside
the spec so tool listings don't re-introspect on every request.
ToolCategory ¶
Bases: str, Enum
Coarse grouping for a tool, surfaced to the agent and the UI.
Categories are advisory metadata: they let a frontend group tools,
let a system prompt reason about capability classes, and let a
project apply category-wide policy. They do not by themselves
gate execution — that is the destructive flag's job.
Skills¶
SkillRegistry ¶
An ordered, named collection of :class:SkillSpecs.
State lives on the instance (like :class:~django_ag_ui.registry.tool_registry.ToolRegistry).
:meth:payload produces the JSON-serialisable catalog the frontend consumes
(camelCase keys, optional fields omitted when default).
register ¶
Register spec; raise ValueError if the name is taken.
add ¶
add(
name: str,
title: str,
prompt: str,
*,
description: str | None = None,
send_immediately: bool = False,
chip: bool = False,
) -> SkillSpec
Construct a :class:SkillSpec and register it (convenience).
payload ¶
The client catalog: a list of skill dicts with camelCase keys.
SkillSpec
dataclass
¶
A pre-defined prompt offered to the user (a "skill").
Serialised into the client catalog the frontend surfaces as chips and/or
the /-command palette. Skills are data, not callables — the prompt
is a static string (it may contain {placeholder}s the client fills from
its skill context before sending).
description
class-attribute
instance-attribute
¶
Optional secondary line shown in the palette.
send_immediately
class-attribute
instance-attribute
¶
Send on pick instead of pre-filling the input. Surfaced as
sendImmediately.
chip
class-attribute
instance-attribute
¶
Also surface as a chip (the palette shows all skills regardless).
SkillsView ¶
A read-only endpoint returning a :class:SkillRegistry's client catalog.
A callable instance (like :class:~django_ag_ui.agent.agui_view.DjangoAGUIView)
so it can hold the registry and a project can mount several. GET returns
the JSON skill list the frontend fetches via data-skills-url.
Skill prompts can encode internal workflows — worth gating. The view
carries the same authentication seam as DjangoAGUIView
(require_authenticated / get_user, sync or async hooks), so one
policy can cover the agent endpoint and its catalogs. Defaults stay open
for backwards compatibility — lock the catalog down whenever the agent
endpoint is locked down.
Agent and view¶
DjangoAGUIView ¶
An async Django view that serves an AG-UI endpoint.
Bridges a Django HttpRequest to Pydantic-AI's AGUIAdapter without
Starlette: it parses the posted RunAgentInput, builds a Pydantic-AI
Agent from the server-side tool registry, and returns a
StreamingHttpResponse of AG-UI events (Server-Sent Events). Frontend
tools declared in the request are merged by the adapter automatically.
The view is a callable instance, so configuration lives on self and a
project can mount several with independent registries. model,
instructions, and audit_logger fall back to the DJANGO_AG_UI
settings when not passed explicitly (tests inject a TestModel).
Authentication is the host's responsibility. Tools (and the drf-mcp
bridge) act as request.user; if your middleware hasn't authenticated the
request, that is AnonymousUser — a data-exposure footgun. Pass
require_authenticated=True to fail closed (401 for unauthenticated
requests), and/or a get_user(request) hook to establish the user (e.g.
from a token) before tools run. get_user may be sync or async; a
sync hook runs off the event loop, so a plain ORM token → User lookup
(Token.objects.select_related("user").get(key=...).user) is fully
supported. A hook that raises propagates as an unhandled error (500) —
return AnonymousUser (or None) for a clean 401 instead.
CSRF: the view defaults to csrf_exempt=True because AG-UI clients
typically authenticate via headers (Bearer / API key), where CSRF does not
apply. If your deployment authenticates with session cookies, pass
csrf_exempt=False and send the CSRF token from the client — tools act
as request.user, so a cookie-auth endpoint without CSRF protection
lets any third-party page drive the agent as the logged-in user
(mitigated, not eliminated, by Django's default SameSite=Lax cookie).
ToolsView ¶
A read-only endpoint returning the agent's server-tool catalog (GET, JSON).
A callable instance (like :class:~django_ag_ui.agent.agui_view.DjangoAGUIView)
holding the same :class:~django_ag_ui.registry.tool_registry.ToolRegistry
the view uses. GET returns the :func:build_tool_catalog list the web
component fetches via data-tools-url to label tool-call cards for
server-side tools (whose schema never reaches the browser).
The catalog names every server tool the agent can wield — an inventory
worth gating. The view carries the same authentication seam as
DjangoAGUIView (require_authenticated / get_user, sync or
async hooks), so one policy can cover the agent endpoint and its
catalogs. Defaults stay open for backwards compatibility — lock the
catalog down whenever the agent endpoint is locked down.
get_urls ¶
get_urls(
view: DjangoAGUIView,
prefix: str = "agent/",
*,
skills: SkillRegistry | None = None,
tools: ToolRegistry | None = None,
) -> list[URLPattern]
Return URL patterns mounting view at <prefix> (POST, SSE).
When skills is given, also mounts a read-only skills catalog at
<prefix>skills/ (GET, JSON) for the web component's data-skills-url.
When tools (the same :class:ToolRegistry the view uses) is given, also
mounts a read-only tool catalog at <prefix>tools/ (GET, JSON) for the
component's data-tools-url — friendly card labels for server-side tools.
Include the result from your project's root URLconf::
urlpatterns = [
...,
path("", include(get_urls(DjangoAGUIView(registry), tools=registry))),
]
build_agent ¶
Build a Pydantic-AI Agent from a registry and an :class:AgentConfig.
Each registry tool is registered as a plain Pydantic-AI tool. When
config.audit_logger is set, every tool call is timed and recorded; the
wrapper preserves the original signature so Pydantic-AI's schema generation
is unaffected. Frontend tools declared in the AG-UI RunAgentInput are
merged automatically by the adapter and are not registered here.
model_settings / retries tune the model; toolsets and
capabilities compose external Pydantic-AI toolsets/capabilities (e.g. an
MCP-client toolset) alongside the registry tools, so the agent can reach
beyond the registered set.
AgentConfig
dataclass
¶
Resolved construction parameters for a Pydantic-AI Agent.
Bundles everything :func:~django_ag_ui.agent.agent_factory.build_agent
needs so the call site passes one record instead of a long keyword list.
The view resolves these from explicit overrides and the DJANGO_AG_UI
settings; toolsets and capabilities arrive already resolved to
instances (not dotted paths).
instructions
class-attribute
instance-attribute
¶
System/instructions prompt for the agent.
audit_logger
class-attribute
instance-attribute
¶
Wraps every server-side tool call for timing + success/failure
records. None means no auditing (a no-op logger).
model_settings
class-attribute
instance-attribute
¶
Pydantic-AI ModelSettings (temperature, max_tokens, …).
retries
class-attribute
instance-attribute
¶
Default tool/output retry budget.
toolsets
class-attribute
instance-attribute
¶
Extra Pydantic-AI toolsets composed alongside the registry tools.
capabilities
class-attribute
instance-attribute
¶
Pydantic-AI capabilities passed to the Agent.
AgentFactoryFn ¶
Bases: Protocol
The escape-hatch signature for DJANGO_AG_UI['AGENT_FACTORY'].
A dotted path to a callable matching this shape fully replaces the
built-in :func:~django_ag_ui.agent.agent_factory.build_agent, giving a
project complete control over Pydantic-AI Agent construction (custom
model providers, output types, toolsets, instrumentation, …). It receives
the per-request server-side tool registry and the resolved settings.
DEFAULT_SYSTEM_PROMPT
module-attribute
¶
DEFAULT_SYSTEM_PROMPT = "You are an assistant embedded in a web application. You can call tools to read data and to drive the user interface on the user's behalf. Prefer the most specific tool available. For a destructive action, call the tool directly with the right arguments — the interface shows the user an explicit confirmation before it runs, so do NOT ask for confirmation in text or wait for the user to say yes. Briefly state what you are doing. When the user refers to something by name, use a listing or search tool's arguments to find it and then act on the result — don't stop after the lookup. Treat 'open', 'go to', or 'show me' as a request to navigate. Always finish your turn with a short reply or a completed action — never an empty turn. Keep replies concise."
Configuration¶
AppSettings
dataclass
¶
Snapshot of the user-configurable DJANGO_AG_UI settings.
Built fresh on every read so test overrides take effect immediately
(Django's settings object is the cache, not this dataclass).
model
instance-attribute
¶
The Pydantic-AI model: a "provider:name" string (e.g.
"anthropic:claude-sonnet-4.6") or a pre-built Model instance.
Optional here; the agent factory raises a clear error if it is unset
when an agent is actually built.
api_key
instance-attribute
¶
API key handed to the provider when MODEL is a "provider:name"
string, so the key comes from settings rather than the environment.
Ignored when PROVIDER is set or MODEL is already a Model.
provider
instance-attribute
¶
Optional Pydantic-AI Provider instance (or dotted path to one) used
to build the model — for a custom base_url / client. When set, MODEL
is just the model name's "provider:name" string and API_KEY is
ignored (the provider carries its own credentials).
auto_confirm
instance-attribute
¶
When True, destructive tools do not require client-side
confirmation. Surfaced to the frontend so it can skip the modal.
audit_logger
instance-attribute
¶
Dotted path to an AuditLogger implementation. None means
use the package default (a no-op logger).
system_prompt
instance-attribute
¶
Optional override for the agent's system prompt.
model_settings
instance-attribute
¶
Pydantic-AI ModelSettings (e.g. {"temperature": 0.2,
"max_tokens": 1024}) passed straight to the Agent. None leaves
the model defaults untouched.
retries
instance-attribute
¶
Default tool/output retry budget passed to the Agent. None uses
Pydantic-AI's default.
agent_factory
instance-attribute
¶
Dotted path to a callable (registry, settings) -> Agent that fully
replaces the built-in factory — the escape hatch for arbitrary Pydantic-AI
configuration. None uses the built-in
:func:~django_ag_ui.agent.agent_factory.build_agent.
toolsets
instance-attribute
¶
Dotted paths to extra Pydantic-AI toolsets (or zero-arg callables
returning one) merged into the agent's catalog — e.g. an MCP-client
toolset or the drf-mcp bridge. Empty by default.
capabilities
instance-attribute
¶
Dotted paths to Pydantic-AI capabilities (or zero-arg callables
returning one) passed to the Agent. Empty by default.
conversation_store
instance-attribute
¶
Dotted path to a ConversationStore for server-side persistence.
None keeps the server stateless (the default NullConversationStore).
drf_mcp_server
instance-attribute
¶
Dotted path to a drf-mcp-server MCPServer instance whose tools
are exposed to the agent in-process (requires the [drf-mcp] extra).
None disables the bridge.
get_settings ¶
Read the active DJANGO_AG_UI settings dict into an AppSettings.
Policy and audit¶
needs_confirmation ¶
Return whether binding should prompt for confirmation.
A tool needs confirmation when it is destructive and the project has
not opted into autopilot (auto_confirm=False). The actual modal
is rendered client-side; this helper is the canonical server-side
statement of the rule, used to annotate tool listings and to keep the
confirmation policy in one place.
AuditLogger ¶
Bases: Protocol
Sink for tool-invocation records.
Implementations are free to drop, sample, or forward events. The
package ships a no-op default (NullAuditLogger) and a
logging-backed implementation (LoggingAuditLogger); projects
supply their own by setting DJANGO_AG_UI["AUDIT_LOGGER"] to a
dotted path.
AuditEvent
dataclass
¶
A single tool invocation as seen by the audit logger.
Arguments are stored as a string (typically JSON-encoded) to keep audit records cheap to serialize and to discourage retention of sensitive raw values.
NullAuditLogger ¶
Discards every event. The default when no audit logger is configured.
LoggingAuditLogger ¶
Writes audit events to the Python logging framework.
Successful invocations log at INFO; failures log at WARNING
with the error message included.
resolve_audit_logger ¶
Instantiate the audit logger referenced by a dotted path.
None yields a NullAuditLogger. The path must point to a class
importable with no arguments; consumers that need a parameterised
logger should construct the instance themselves and pass it to the
view directly.
Conversation persistence¶
ConversationStore ¶
Bases: Protocol
Pluggable server-side persistence for AG-UI conversations.
Resolved from DJANGO_AG_UI["CONVERSATION_STORE"]. The package ships a
no-op default (NullConversationStore — the server stays stateless) and a
session-backed implementation; projects supply their own (a DB model, Redis,
…) by pointing the setting at a dotted path. All methods are async so an
implementation can use the async ORM or a network backend.
Conversation
dataclass
¶
A persisted conversation, keyed by thread_id.
messages are AG-UI Message objects (the wire shape the client
speaks), so a store round-trips them verbatim. owner_id scopes the
conversation to a user for authorization.
NullConversationStore ¶
The default store: no-op, keeping the server stateless.
load always returns None and save / delete do nothing, so
the conversation lives entirely in the client's posted history (today's
behaviour). The view treats this store as "persistence off".
DjangoSessionConversationStore ¶
Conversation persistence in the Django session (no migration).
Conversations are namespaced by thread_id within the logged-in user's
session, so scoping to the user is implicit and durability spans that
user's browser session. The batteries-included server-side store; for
cross-device or audited persistence, supply a model-backed store instead.
ModelConversationStore ¶
Bases: ABC
Abstract base for a model-backed (or any sync) ConversationStore.
Provides the async wrapping and per-request owner scoping; a subclass implements the three synchronous row operations against its own Django model (cross-device, auditable persistence). Kept model-agnostic on purpose — the package ships no concrete model so it forces no migration; consumers define the model, its fields, and the owner relationship.
Example::
class MyStore(ModelConversationStore):
def _fetch(self, thread_id, owner_id):
row = MyConversation.objects.filter(
thread_id=thread_id, owner_id=owner_id,
).first()
return None if row is None else Conversation(...)
def _store(self, conversation, owner_id): ...
def _remove(self, thread_id, owner_id): ...
resolve_conversation_store ¶
Instantiate the conversation store referenced by a dotted path.
None yields a NullConversationStore (persistence off). The path must
point to a class importable with no arguments; a store needing constructor
arguments should be wired by the consumer.
Internal helpers¶
These are not part of the public re-export surface but are referenced from the guides.
resolve_dotted_instances ¶
Resolve dotted paths into instances, for TOOLSETS / CAPABILITIES.
Each path resolves to either an instance (used as-is) or a zero-arg
callable / class returning one (invoked). The results are passed to
:func:~django_ag_ui.agent.agent_factory.build_agent to compose external
Pydantic-AI toolsets and capabilities alongside the registry tools.
build_model ¶
Build a Pydantic-AI model from a "provider:name" string + explicit key.
Delegates the provider: prefix → Model-class resolution to Pydantic-AI's
own :func:infer_model, supplying a provider_factory that injects the
credentials instead of letting Pydantic-AI read them from the environment:
provider(aProviderinstance, or a dotted path to one) takes precedence — used as-is, so it can carry a custombase_url/ client.- otherwise
api_keyis passed to the prefix's defaultProviderclass (resolved via :func:infer_provider_class).
Because the prefix map lives in Pydantic-AI, every provider it knows works
automatically (anthropic, openai, openai-responses, google,
groq, bedrock, …) — there is no hand-maintained table to drift out
of date.
A bare model name Pydantic-AI can map to a provider (e.g. claude-… →
anthropic) is accepted too; only when the provider can't be resolved at all
is an error raised.
Raises:
| Type | Description |
|---|---|
ImproperlyConfigured
|
when the model's provider can't be resolved — an
unknown / uninferable prefix, or the matching provider extra not
installed. Set |
build_tool_catalog ¶
The agent's server-tool catalog for the frontend to label tool-call cards.
Server-side tools (the @tool registry, and drf-mcp tools when
DJANGO_AG_UI['DRF_MCP_SERVER'] is set) execute server-side, so their
JSON Schema never reaches the browser — the web component can't read an
x-summary off it. This catalog is the channel for those labels: the
component fetches it via data-tools-url and maps tool name → label.
Each entry is {"name", "summary", "description"?}. summary is always
present, resolved from the single source of truth with a fallback chain:
- registry tools →
@tool(summary=…)→ a prettified name; - drf-mcp tools →
display_name→title→ a prettified name.
description (a longer blurb for tooltips) is included when available
(ToolSpec.description / drf-mcp display_description → description).
Registry tools win on name collisions.
DrfMcpToolset ¶
Bases: ExternalToolset[Any]
Exposes a drf-mcp MCPServer's tools as a Pydantic-AI toolset.
Built per request so the acting user is the current AG-UI user. Tool schemas and execution both route through drf-mcp's own handlers, so the advertised parameters, serializer validation, and permissions match the HTTP transport exactly.
exclude_names carries the @tool registry's names: on a collision
the registry tool wins (the same rule build_tool_catalog applies) and
the drf-mcp twin is skipped — otherwise pydantic-ai raises UserError
for the duplicate name at run time.
get_tools
async
¶
Load tool defs from drf-mcp's tools/list once, then defer to base.
Loading runs in a thread (sync_to_async) because the sync
handle_tools_list may evaluate per-user listing permissions against
the DB, which Django forbids on the async event loop.