@djangocfg/widget-agent
What an agent needs to see an app and act on it, plus the viewers that put an API, a request, a log or an environment on screen.
Two halves with different weights:
- Instrumentation —
page-snapshotcaptures the page as a compact tree an LLM can read;browser-bridgetakes the refs from that snapshot and lets the model point at, focus or scroll to a live element;page-copilotwires both to a chat and gates what may act on the page. No viewer, no heavy dependency, and where all 31 test suites are. - Viewers — surfaces for developer data.
openapialone carries a sampler, an HTTP client and a store.
Install
pnpm add @djangocfg/widget-agent
Peers: react 19, react-dom 19, @djangocfg/ui-core, lucide-react,
zustand.
Import a subpath
| Subpath | What it is |
|---|---|
./page-snapshot | capture the page as a CST, with redaction and a ref registry |
./browser-bridge | resolve a ref to an element; highlight, focus, scroll |
./page-copilot | wrap a chat adapter so every turn carries the page, and gate the actions it proposes |
./openapi | OpenapiViewer, lazy — a schema browser with a request playground |
./request-viewer | one HTTP exchange, headers and bodies |
./api-ref-table | endpoints as a table |
./log-viewer | virtualised log stream, lazy |
./log-viewer/full | the same, eager |
./env-table | environment variables, with the values masked |
import { PageSnapshotProvider } from '@djangocfg/widget-agent/page-snapshot';
import { HighlightOverlay } from '@djangocfg/widget-agent/browser-bridge';
The round trip
capture page-snapshot assigns @e1, @e2, … to interactive nodes and keeps a
ref → element registry
↓ snapshot travels with the request
model may answer with a directive: point at @e4
↓ directive arrives on the client
bridge resolve @e4 → element, draw the spotlight, optionally focus
Read-only by default. A point directive highlights, focuses or scrolls.
It never types, clicks or changes the user's data.
fill and click do change it, so they arrive as a PROPOSAL: a data part
with kind: 'ui-action' that renders as a card with Approve and Skip, and
reaches the page only on Approve. The ref is re-resolved at that moment — the
page moves between the agent proposing and the user reading — and every
outcome (approved, rejected, stale, not-visible, expired) is reported
back exactly once, because an agent with no answer re-proposes.
The two modules stay independent: browser-bridge depends on a structural
RefResolver interface, not on the capture engine, so either can be used alone.
Mounting the copilot
Three hooks, and no change to the chat — it gets no new prop, no capability and no import.
const copilot = usePageCopilot(adapter); // page rides every turn
const queue = useProposals( // the gate
snapshot.sentSnapshot?.refs ?? null, // the SENT registry
copilot.reportResult,
);
const renderers = {
data: createActionRenderer({ queue, fallback: DataRenderer }),
};
Two things that are silent when wrong:
- The resolver must be
sentSnapshot.refs, never the newest capture. CST refs are positional, so a later capture renumbers them and@e1resolves to a different element than the one the agent named. fallbackis not optional in practice. The registry dispatches onpart.type, so one renderer owns EVERY data part; registering ours without delegating blanks every media block the chat already draws.
Widgets/Agent/PageCopilot Live is this wiring, running.
The split runs through the dependencies too
@djangocfg/widget-code and @djangocfg/widget-data are reached from the
viewers only — nine files, all under openapi/ and request-viewer/, for
syntax highlighting, markdown and a JSON tree. Nothing in page-snapshot or
browser-bridge touches them, which is what makes the instrumentation half
usable in a page that renders no viewer at all.
Redaction is part of capture, not a step after it
A snapshot leaves the user's browser. page-snapshot/redaction runs during the
walk — patterns, heuristics and a Luhn check for card numbers — and has its own
audit suite. A value that reaches the serialiser unredacted has already left.
Testing
pnpm --filter @djangocfg/widget-agent check-types test
22 suites: the capture walk, budget, scoping and folding; CST serialisation; the ref registry and locator; staleness hashing; every redaction layer; the React provider and chip; and the overlay's ref resolution.