Puck AI 0.9 lets you build custom AI agents, supports user field types in design mode, adds localization, and includes several other API improvements.
See the AI overview for more information on Puck AI.
In this post, we’ll go over everything new in Puck AI 0.9 and how you can start using it:
You can also find in-depth documentation in our AI docs.
The new usePuckAi hook lets you build your own UI for Puck AI. Use it to hold a conversation, request a single change to the current page, or integrate Puck AI with your own agent.
import { usePuckAi } from "@puckeditor/plugin-ai";
function AiChat() {
const { chat } = usePuckAi();
const [input, setInput] = useState("");
const messages = chat.messages.map((message) =>
message.parts.map((part, i) =>
part.type === "text" ? <p key={i}>{part.text}</p> : null
)
);
return (
<div>
{messages}
<form
onSubmit={(e) => {
e.preventDefault();
chat.sendMessage(input);
setInput("");
}}
>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button>Send</button>
</form>
</div>
);
}The hook can be used anywhere the Internal Puck API is available. See the custom agents guide for more details.
It’s now possible to stream AI changes from your own server-sided agent.
The headless server-side generate now exposes each AI Part through onPart. These parts can be sent to the client and applied to the editor using usePuckAi().applyPart:
// server side
await generate({
prompt: "Create a page about dogs",
config,
pageData,
onPart: (part) => {
// send part to browser, or save it for later
},
});Apply each part when the editor receives it:
const { applyPart } = usePuckAi();
// get the parts from the server
// const parts = ...
for await (const part of parts) {
await applyPart(part);
}By default, headless generations run for one iteration. Set maxIterations to allow more iterations and configure onPart to process requests from the agent.
generate can now iterate during page generation to review its work and make further changes.
To enable this, set maxIterations in the options object and respond to data-client-request parts with onPart:
await generate({
prompt: "Create a page about dogs",
config,
maxIterations: 10,
onPart: (part, respond) => {
if (part.type === "data-client-request") {
if (data.action === "getPageData") {
// Provide the latest page data via respond(pageData)
}
// handle other actions
}
},
});See the onPart documentation for more details on handling data-client-request parts.
Puck AI now supports user field types in both assembly mode and design mode, letting you define their schema once and use them when assembling pages or designing new components.
To use user field types in assembly mode, define them with the fieldTypes prop when creating your AI plugin:
const aiPlugin = createAiPlugin({
fieldTypes: {
cta: {
description: "Renders a branded call-to-action button",
schema: {
type: "object",
properties: {
label: { type: "string" },
href: { type: "string" },
variant: { type: "string" },
},
},
},
},
});Combine user field types with field transforms to let Puck AI include your components in the new components it designs:
const aiPlugin = createAiPlugin({
fieldTypes: {
cta: {
description: "Renders a branded call-to-action button",
schema: {
type: "object",
properties: {
label: { type: "string" },
href: { type: "string" },
variant: { type: "string" },
},
},
},
},
});
const fieldTransforms = {
cta: ({ value }) => (
<Button href={value.href} variant={value.variant}>
{value.label}
</Button>
),
};See AI configuration for more details.
The AI plugin introduces a new label prop and new keys for Puck’s dictionary prop, letting you replace every string shown in the UI:
const aiPlugin = createAiPlugin({ label: "IA" });
<Puck
plugins={[aiPlugin]}
dictionary={{
"plugin-ai-prompt-placeholder": "¿Qué quieres construir?",
"plugin-ai-chat-msg-thinking": "Pensando...",
}}
config={config}
data={data}
/>;See the localization guide for more details, and the AI plugin dictionary reference for the full list of strings.
Assembly mode now uses openai/gpt-5.6-luna by default, matching design mode. Set ai.model to use a different model.
puckHandler option: ai.maxIterationspuckHandler now accepts ai.maxIterations, which limits how many times the AI can iterate on a request:
puckHandler(request, {
ai: {
maxIterations: 10,
},
});Users can now paste files, including screenshots, straight into the chat input. Pasted files follow your chat.attachments settings.
Setting ai.mode to "design" now enables design mode for every request without also setting designMode.allowed:
puckHandler(request, {
ai: {
mode: "design",
},
});Use designMode.allowed only when users need to toggle design mode in the plugin interface.
puckHandler and generate now await onFinishpuckHandler and generate now wait for async onFinish callbacks. generate rejects if its callback fails, while puckHandler logs the failure.
usePuckAi() for custom AI interfacesgenerate() requestsai.mode force design mode without designMode.allowedopenai/gpt-5.6-luna as the default assembly modelonFinish callbacksproviderApiKey is set without a modeldefaultProps@puckeditor/ai-types and @puckeditor/cloud-client@puckeditor/cloud-clientHeaders instances returned from prepareRequestRun the following command to install the latest Puck AI packages:
npm install @puckeditor/cloud-client@latest @puckeditor/plugin-ai@latestNo stable Puck AI APIs were removed or deprecated in this release.
Puck AI is available now. Sign up.