Skip to main content
A form collector lets an AGO agent fill a form by talking to the user. You define the form’s fields once. The SDK gives the agent a function to record values as the conversation goes, keeps a live store you can render, and tells the agent which required fields are still missing so it knows what to ask next. You define the fields in one place. From that single schema the SDK derives:
  • an observable store holding the collected values and whether the form was submitted — its completeness (missing, complete) is computed on read with deriveFormStatus, never stored
  • an update_<name> function the agent calls to record values (it can call it many times, with any subset of fields)
  • a context entry sent with every message so the agent always knows the current values and what’s left
  • an optional submit_<name> function that sends the completed form

Create a Collector

The name becomes the function names (update_order, submit_order), so it must contain only letters, numbers, underscores, or hyphens, and be at most 40 characters.

Define the form in the backend

Instead of writing the schema in your page, you can store it once in AGO and fetch it by name. The form then has a single source of truth: change a field in the admin interface and every page picks it up on next load, with no redeploy. Create the definition in the admin interface (its name, description, schema, and submit target), then reference it by name:
Any option you pass overrides the stored one — useful for a browser-only submit handler, which can’t be stored on the server:
A runnable widget version (the schema lives in the backend, the page only references it by name) is in the SDK repository under examples/simple-html/credit-form-backend.html.

React

useFormCollector registers the collector on mount, removes it on unmount, and returns the live state.
Keep the schema and submit object stable across renders (declare them outside the component or memoize them) so an inline handler isn’t captured stale. To use a backend-defined form instead, pass only its name — the hook fetches the definition and exposes loading while it does:

State

The store holds only the canonical state: Completeness is derived from the values, not stored. Compute it with deriveFormStatus(schema, values) — or, in React, read it straight off order.state, which already includes it:

Restoring state after a reload

When a visitor reloads the page and you reopen their previous conversation, the collector rebuilds itself from the values the agent already recorded. Loading a conversation replays its update_<name> and submit_<name> calls onto the store, so the collected values and the submitted flag come back exactly as they were (and missing/complete derive from them), and the visitor doesn’t have to start over. This happens on its own once the collector is installed (with install or useFormCollector): loading a conversation restores any matching form. Loading a conversation that never used the form leaves it at its initial values. If you build the conversation loading yourself, call order.hydrate(toolCalls) with the tool calls of the loaded messages to restore the state manually.

Submitting

Choose how the completed form is sent with the submit option.
The browser sends the values to a URL you control, using the page’s existing session. Use this when the endpoint is your own API and needs no server-only secret.
submit_<name> only submits once every required field is present. If fields are still missing it returns them instead, so the agent asks for the rest before trying again. You can also submit from your own UI by calling order.submit().

Submission history

Every form submitted through the server ({ via: "backend" }) is kept in a history you can review in the admin interface. Open Form Collectors and click Form Submissions to see, for each submission:
  • the date and time it was sent
  • the form it belongs to
  • whether it completed or failed
  • the user who submitted it
  • a preview of the submitted values
Click a row to open its detail page, with the full submitted data and the failure reason if it failed. Filter the list by form, status, or date range. Submissions handled entirely in the browser ({ via: "client" }) never reach the server, so they don’t appear here.

Complete Example

A contact-intake form in plain JavaScript. The agent collects the prospect’s details through the conversation, the summary updates live, and the form submits once it’s complete.
A runnable version (a self-contained HTML page) lives in the SDK repository under examples/simple-html/contact-form.html.