QuickstartLast updated on
Last updated on
Give an agent the Paradoc tools and have it fill a real form
In this quickstart, an agent fills a pet addendum to a lease from one message and saves it as a PDF. The form comes from the Paradoc public registry, so you do not write a form first.
You need Node.js 22.13 or newer, a project with "type": "module" in its package.json, and an OpenAI API key in OPENAI_API_KEY. To use a different model, change the model line. Any model that can call tools works.
Install and write the agent
Pick your framework. Each tab is a complete program.
npm install @paradoc/ai-sdk ai @ai-sdk/openai zodimport { writeFile } from "node:fs/promises"
import { openai } from "@ai-sdk/openai"
import { paradocTools } from "@paradoc/ai-sdk"
import { generateText, isStepCount } from "ai"
const result = await generateText({
model: openai("gpt-4o"),
tools: paradocTools({ defaultRegistryUrl: "https://public.paradoc.dev" }),
stopWhen: isStepCount(10),
system: [
"You fill documents with the Paradoc tools.",
"Leave registry_url out: the tools use the configured registry.",
"Call get_artifact first and follow its agent instructions.",
"Pass the data from the last fill result to render.",
"The app gives the user the PDF. Do not write links to it.",
].join("\n"),
prompt:
"Fill the pet-addendum form. My dog Rex weighs 30 lbs and is vaccinated. " +
"I am Jane Doe, the tenant. The landlord is Acme Properties LLC. " +
"Then render it as a PDF.",
})
for (const step of result.steps) {
for (const call of step.toolCalls) console.log("tool:", call.toolName)
}
console.log(result.text)
const pdf = result.steps
.flatMap((step) => step.toolResults)
.find((r) => r.toolName === "render" && r.output.mime_type === "application/pdf")
if (pdf?.toolName === "render" && pdf.output.content) {
await writeFile("pet-addendum.pdf", Buffer.from(pdf.output.content, "base64"))
}generateText stops after one step unless you set stopWhen. Without it, the agent calls one tool and stops.
The system prompt tells the model four things:
- Leave
registry_urlout.defaultRegistryUrlis only a fallback. If the model writes a URL of its own, the tools use it. - Read the agent instructions.
get_artifactreturns instructions that the form's author wrote for agents: the order to ask questions in, how to check values, and which layer to render. - Pass the draft to
render.fillreturns the draft indata.renderwithoutdatarenders an empty form. - The app delivers the PDF. The model sees only a short copy of each tool result. Your code gets the full result.
Run it
npx tsx agent.tsThe agent calls three tools, then answers:
tool: get_artifact
tool: fill
tool: render
The Pet Addendum form has been filled with the following details:
- Pet Name: Rex
- Species: Dog
- Weight: 30 lbs
- Vaccinated: Yes
- Tenant: Jane Doe
- Landlord: Acme Properties LLC
The form has been rendered as a PDF, ready for signature.The model writes its own answer, so the text changes from run to run. Sometimes the model calls a tool twice: when a value is in the wrong shape, the tool returns an error that says why, and the model tries again.
Open the PDF
pet-addendum.pdf is in the current folder, with the values filled in. It is not signed. Paradoc can seal it for signing.
What happened
get_artifactloaded thepet-addendumform fromhttps://public.paradoc.dev, with its agent instructions.fillchecked the values against the form and returned a draft. If a value was wrong, such as a species the form does not list,fillreturned an error, and the model could fix it or ask you.renderfilled the form's PDF layer with the draft.
In this quickstart, the message gives every value at once. A real form needs a conversation: the agent asks for what is missing, one question at a time. That is the next guide.
Next
- Build an intake agent: collect a form through a conversation.
- Tool reference: the inputs and outputs of each tool.