Depending on the use case or query, the API might present the user with a form to fill out rather than asking a set of questions and expecting the user to type in the answers. For example, if the user wants to plan a trip, the API would present a form to fill out asking their preferences like the destination, the dates, the type of accommodation, etc. rather than asking users to type in the answers.

C1 supports a variety of input types out of the box and we are constantly adding more. The following input fields are currently supported:

  • Text input
  • Number input
  • Date input
  • Dropdown
  • Checkbox
  • Radio buttons
  • Textarea
  • Slider
  • Switches

The generation, validation and submission of the form is automatically handled by Thesys SDK and no additional code is required to handle this. To guide the generation of the form, you can use the system prompt to instruct the API to generate forms with certain fields or specific kind of input options.

Manual form generation

Sometimes, you might want to generate a form with a specific set of fields or input options. For example, if you want to generate a form for a trip planning application, you can use the following system prompt:

You are a helpful travel planner assistant.
When user wants to plan a trip, you should generate a form with the following fields:
- Destination: A text input field for the destination of the trip.
- Date: A date input field for the dates of the trip.
- Type of accommodation: A dropdown with the following options: Hotel, Apartment, Hostel, etc.
- Number of people: A number input field for the number of people in the trip.
- Budget: A range slider with the following options: $0 - $1000.
- Travel preferences: A dropdown with the following options: Beach, Mountains, City, etc.

Automatic form generation

In most cases, you don’t need to manually specify a prompt for the form. A better approach is to pass in the tool call for the action you want the agent to perform and let C1 automtically render the form based on the JSON schema of the tool call input parameters.

For example if you want to create a AI Jira copilot, rather than manually specifying the form fields, you can pass in the tool call specification for creating a Jira issue and let C1 automatically render the form based on the JSON schema of the tool call input parameters.

src/api/route.ts
const tools = [
  {
    name: "create_jira_issue",
    description: "Create a Jira issue",
    parameters: {
      type: "object",
      properties: {
        title: {
          type: "string",
          description: "The title of the Jira issue"
        },
        priority: {
          type: "enum",
          enum: ["Low", "Medium", "High"],
          description: "The priority of the Jira issue"
        },
        description: {
          type: "string",
          description: "Multiline description of the Jira issue"
        }
      }
      required: ["title", "priority", "description"]
    }
  }
]
const response = client.chat.completions.create({
  ...
  messages: [
    {
      role: "system",
      content: "You are a helpful Jira copilot. You help users create, update and delete Jira issues."
    },
    {
      role: "user",
      content: "Create a Jira issue with the title 'New Feature'"
    }
  ],
  tools: tools,
  ...
})

In this case, C1 will automatically render a form with the fields required to create a Jira issue and even automatically prefill the title since that was already provided in the user query.

Handling form submissions

Form submissions can be handled in the same way as general interactivity is handled. When the user fills out the form and clicks on the submit button, the onAction callback will be called with the form data. In this case, Thesys SDK will automatically fill the llmFriendlyMessage with the form data and the action such that the appropriate tool call is made to the backend.

Note: If you are building a chatbot, this is already handled for you in the <C1Chat> component.

Persisting form data

Sometime, you might want to persist the form data in the Generative UI application so that when the user refreshes the page, the form data is not lost. Field data is automatically kept in sync with the user’s input within the context of the same ‘response’ object.

Whenever the user updates the form, the updateMessage callback will be called with the updated form data merged with the rest of the response object. Simply pass in a function to the updateMessage prop that can be used to persist the entire reponse and form persistence should be handled automatically.

src/app/page.tsx
<C1Chat
  updateMessage={(message) => {
    // Persist the message to the database
  }}
/>

If you implement persistence for the generated response and update it via this callback, when the user refreshes the page the entire application state will be restored including the form data.