> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ravenna.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Forms

> Submit Ravenna request type forms directly in Microsoft Teams as interactive Adaptive Cards.

Ravenna forms render in Microsoft Teams as interactive Adaptive Cards. Users can submit a request type form to update a ticket without leaving Teams.

## Mental model

Form rendering is owned by `TeamsOutboundRenderer`. When the Agent emits a message of type `form` (request type or workflow), the renderer dispatches to the appropriate card builder:

* `request_type_form` → an "Open form" dialog card (`buildRequestTypeOpenDialogCard`) whose button opens the Ravenna web form as a Teams task module (deep-linked to `/teams/forms/...`). The web form renders the fields and resolves the dynamic options.
* `workflow_form` → an inline workflow trigger form card (`buildWorkflowTriggerFormCard`) with the trigger's input declarations.

Both card types follow the same submission contract: a single `Action.Submit` button posts `activity.value` back to the bot with an `actionType` discriminator (`form_submit`, `workflow_form_submit`, or `form_dismiss`), and the form-submission handler routes accordingly.

***

## Submission flow

1. The user clicks **Submit** on the Adaptive Card.
2. Teams sends a `message` activity with no text but an `activity.value` payload containing the form state and `actionType`.
3. `processFormSubmission` routes by `actionType`:
   * `form_submit` → `convertFlatFormStateToTicketFields` converts the flat Teams form state into Ravenna ticket fields; `FormService.submitForm` applies the fields and publishes the ticket.
   * `workflow_form_submit` → the `RunWorkflow` function triggers the configured workflow with the submitted inputs.
   * `form_dismiss` → the card is replaced with a dismissed-state confirmation.
4. The card is replaced with a confirmation card showing the submitted values and a deep link back to the ticket.

***

## Approval forms

Approval requests use the same submission plumbing but a dedicated `approvalCard` builder:

* The card surfaces the ticket context and **Approve** / **Decline** buttons.
* Declining reveals an optional reason input before final submission.
* Submission posts `activity.value.actionType = 'approval_approve' | 'approval_decline'` plus the decline reason; the handler updates the approval round via `ApprovalService`.

Approval cards are sent as DMs to each approver when they are added to a round, so they fire without an existing channel conversation.

***

## Field resolution

For request-type forms, dynamic options are resolved inside the embedded Ravenna web form rather than baked into the card server-side:

* **Workspace members**: for assignee / requester / approver fields, the web form resolves the eligible member set so the dropdown is populated.
* **Applications**: for application-typed fields, the web form resolves the configured application options.

Resolving inside the web form lets the form support parent/child field dependencies and keeps option data out of the posted card.

***

## Constraints and gotchas

* Adaptive Card form fields are limited to the input types Teams supports. Ravenna field types that don't have a 1:1 mapping degrade to the closest supported input.
* Once submitted, the card is replaced. There's no in-place edit of the submitted card. Users must edit the ticket directly to change values after submission.
* The `actionType` discriminator on `activity.value` is required for the form-submission router. Custom cards added later must follow the same convention.
* **Conversational form-fill via the Agent is still being validated on Teams.** The Agent may escalate without rendering the configured request-type form in some flows. Use the explicit form-card flow above as the reliable path until this is finalized.
