DocsPlatform
Writing a backend adapter
Backend adapters translate provider events into Assistant messages and lifecycle state. That is all they do. Framework rendering, composer policy and DOM state are somebody else's job.
ExternalStore contract
Implement load, new, edit, reload, resume, cancel, delete, import and loadExternalState around your provider. Each callback receives an AbortSignal and returns provider data, never framework elements.
const assistant = createExternalStoreAssistant({
adapter: {
load: async ({ signal }) => provider.loadThread(threadId, { signal }),
new: async ({ messages, signal }) => provider.start(messages, { signal }),
resume: async ({ messages, signal }) => provider.resume(messages, { signal }),
},
});Stream events
Normalise provider deltas to cumulative text, tool-call lifecycle, usage and finish/error events. Preserve provider metadata under message metadata; keep transient transport IDs out of the user-visible content.
Ownership boundaries
The adapter owns transport and persistence. The Assistant runtime owns message history and scope state. Headless adapters own subscriptions and SSR-safe props. Styled components own only tokens, DOM semantics and interaction wiring.