# For Agent Developers

<details>

<summary>Prerequisite</summary>

The following section assumes you have the UI (web application) ready to render A2UI component.

See  [for-ui-developers](https://gdplabs.gitbook.io/glchat/sdk-a2ui/getting-started/for-ui-developers "mention") for details.

</details>

{% hint style="info" %}
Here are some references from A2UI documentation:

* [Brief Introduction for Agent as the Server-Side](https://a2ui.org/agents/)
* [Agent Development Guide](https://a2ui.org/guides/agent-development/)
  {% endhint %}

This section contains sample of Agent response that contains A2UI. Please note that A2UI is only *a part* of the whole JSON response. Therefore, Agent and UI must agree on the JSON structure.

The JSON structure in this page uses AIP standard. If you use other standard, please adjust accordingly.

## Sample Agent Response

Modify the agent implementation to return the response in this JSON format (streaming is optional):

{% code lineNumbers="true" expandable="true" %}

```json
{
  "status": "success",
  "task_state": "completed",
  "content": "Showing A2UI sample: hello",
  "event_type": "final_response",
  "final": true,
  "metadata": {
    "kind": "final_response",
    "status": "finished",
    "event_type": "final_response",
    "a2ui_content": [
      {
        "surfaceUpdate": {
          "surfaceId": "main",
          "components": [
            {
              "id": "root",
              "component": {
                "Card": {
                  "child": "content"
                }
              }
            },
            {
              "id": "content",
              "component": {
                "Column": {
                  "children": {
                    "explicitList": [
                      "header",
                      "description",
                      "command-list",
                      "divider",
                      "footer"
                    ]
                  },
                  "distribution": "start",
                  "alignment": "stretch"
                }
              }
            },
            {
              "id": "header",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "Hello! 👋"
                  },
                  "usageHint": "h2"
                }
              }
            },
            {
              "id": "description",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "Welcome to A2UI! Try these commands:"
                  },
                  "usageHint": "body"
                }
              }
            },
            {
              "id": "command-list",
              "component": {
                "List": {
                  "children": {
                    "template": {
                      "componentId": "command-item",
                      "dataBinding": "/commands"
                    }
                  },
                  "direction": "vertical",
                  "alignment": "start"
                }
              }
            },
            {
              "id": "command-item",
              "component": {
                "Text": {
                  "text": {
                    "path": "command"
                  },
                  "usageHint": "body"
                }
              }
            },
            {
              "id": "divider",
              "component": {
                "Divider": {
                  "axis": "horizontal"
                }
              }
            },
            {
              "id": "footer",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "Type any keyword above to see the demo!"
                  },
                  "usageHint": "caption"
                }
              }
            }
          ]
        }
      },
      {
        "dataModelUpdate": {
          "surfaceId": "main",
          "path": "/commands",
          "contents": [
            {
              "key": "0",
              "valueMap": [
                {
                  "key": "command",
                  "valueString": "• 'hello' - Simple greeting card"
                }
              ]
            },
            {
              "key": "1",
              "valueMap": [
                {
                  "key": "command",
                  "valueString": "• 'hitl' - Human-in-the-loop approval workflow"
                }
              ]
            }
          ]
        }
      },
      {
        "beginRendering": {
          "surfaceId": "main",
          "root": "root"
        }
      }
    ]
  }
}
```

{% endcode %}

The above JSON will make the UI render the following component:

<figure><img src="https://1470748636-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDY50EL4OmcrPvtoecg4h%2Fuploads%2FC7aGQNLgThWgFNHkZPcD%2Fimage.png?alt=media&#x26;token=9535a985-0477-4dec-af9c-9f85b72ce7d1" alt=""><figcaption></figcaption></figure>

To learn more about the JSON structure of A2UI component, see <https://a2ui.org/concepts/components/>.

## Sample Agent Response with Action

The following is JSON with **action**:

{% code lineNumbers="true" expandable="true" %}

```json
{
  "status": "success",
  "task_state": "completed",
  "content": "Showing A2UI sample: hitl",
  "event_type": "final_response",
  "final": true,
  "metadata": {
    "kind": "final_response",
    "status": "finished",
    "event_type": "final_response",
    "a2ui_content": [
      {
        "surfaceUpdate": {
          "surfaceId": "header",
          "components": [
            {
              "id": "root",
              "component": {
                "Row": {
                  "children": {
                    "explicitList": ["title", "icon"]
                  },
                  "distribution": "start",
                  "alignment": "center"
                }
              }
            },
            {
              "id": "title",
              "component": {
                "Text": {
                  "text": {
                    "path": "/header/title"
                  },
                  "usageHint": "h2"
                }
              }
            },
            {
              "id": "icon",
              "component": {
                "Text": {
                  "text": {
                    "path": "/header/icon"
                  },
                  "usageHint": "h2"
                }
              }
            }
          ]
        }
      },
      {
        "dataModelUpdate": {
          "surfaceId": "header",
          "contents": [
            {
              "key": "header",
              "valueMap": [
                {
                  "key": "title",
                  "valueString": "Approval Required"
                },
                {
                  "key": "icon",
                  "valueString": "⚠️"
                }
              ]
            }
          ]
        }
      },
      {
        "beginRendering": {
          "surfaceId": "header",
          "root": "root"
        }
      },
      {
        "surfaceUpdate": {
          "surfaceId": "hitl",
          "components": [
            {
              "id": "root",
              "component": {
                "Column": {
                  "children": {
                    "explicitList": ["action-card"]
                  },
                  "distribution": "start",
                  "alignment": "stretch"
                }
              }
            },
            {
              "id": "hitl-header",
              "component": {
                "Row": {
                  "children": {
                    "explicitList": ["header-icon", "header-text"]
                  },
                  "distribution": "start",
                  "alignment": "center"
                }
              }
            },
            {
              "id": "header-icon",
              "component": {
                "Text": {
                  "text": {
                    "path": "/hitl/icon"
                  },
                  "usageHint": "h2"
                }
              }
            },
            {
              "id": "header-text",
              "component": {
                "Text": {
                  "text": {
                    "path": "/hitl/title"
                  },
                  "usageHint": "h2"
                }
              }
            },
            {
              "id": "action-card",
              "component": {
                "Card": {
                  "child": "action-content"
                }
              }
            },
            {
              "id": "action-content",
              "component": {
                "Column": {
                  "children": {
                    "explicitList": ["action-label-row", "action-buttons"]
                  },
                  "distribution": "start",
                  "alignment": "stretch"
                }
              }
            },
            {
              "id": "action-label-row",
              "component": {
                "Row": {
                  "children": {
                    "explicitList": ["action-label", "hitl-timeout"]
                  },
                  "distribution": "start",
                  "alignment": "center"
                }
              }
            },
            {
              "id": "action-label",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "Please review and take action:"
                  },
                  "usageHint": "body"
                }
              }
            },
            {
              "id": "hitl-timeout",
              "component": {
                "Timeout": {
                  "targetTimeUtc": {
                    "path": "/hitl/expiresAt"
                  },
                  "usageHint": "caption"
                }
              }
            },
            {
              "id": "action-buttons",
              "component": {
                "Row": {
                  "children": {
                    "explicitList": ["approve-btn", "reject-btn", "skip-btn"]
                  },
                  "distribution": "start",
                  "alignment": "start"
                }
              }
            },
            {
              "id": "approve-btn",
              "component": {
                "Button": {
                  "child": "approve-text",
                  "action": {
                    "name": "hitl_decision",
                    "context": [
                      {
                        "key": "decision",
                        "value": {
                          "literalString": "approved"
                        }
                      },
                      {
                        "key": "requestId",
                        "value": {
                          "path": "/hitl/requestId"
                        }
                      }
                    ]
                  },
                  "primary": true
                }
              }
            },
            {
              "id": "approve-text",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "✓ Approve"
                  },
                  "usageHint": "body"
                }
              }
            },
            {
              "id": "reject-btn",
              "component": {
                "Button": {
                  "child": "reject-text",
                  "action": {
                    "name": "hitl_decision",
                    "context": [
                      {
                        "key": "decision",
                        "value": {
                          "literalString": "rejected"
                        }
                      },
                      {
                        "key": "requestId",
                        "value": {
                          "path": "/hitl/requestId"
                        }
                      }
                    ]
                  },
                  "primary": false,
                  "destructive": true
                }
              }
            },
            {
              "id": "reject-text",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "✗ Reject"
                  },
                  "usageHint": "body"
                }
              }
            },
            {
              "id": "skip-btn",
              "component": {
                "Button": {
                  "child": "skip-text",
                  "action": {
                    "name": "hitl_decision",
                    "context": [
                      {
                        "key": "decision",
                        "value": {
                          "literalString": "skipped"
                        }
                      },
                      {
                        "key": "requestId",
                        "value": {
                          "path": "/hitl/requestId"
                        }
                      }
                    ]
                  },
                  "primary": false
                }
              }
            },
            {
              "id": "skip-text",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "Skip"
                  },
                  "usageHint": "body"
                }
              }
            }
          ]
        }
      },
      {
        "dataModelUpdate": {
          "surfaceId": "hitl",
          "contents": [
            {
              "key": "hitl",
              "valueMap": [
                {
                  "key": "requestId",
                  "valueString": "REQ-2024-00847"
                },
                {
                  "key": "expiresAt",
                  "valueString": "2026-03-11T12:00:00Z"
                }
              ]
            }
          ]
        }
      },
      {
        "beginRendering": {
          "surfaceId": "hitl",
          "root": "root"
        }
      }
    ]
  }
}

```

{% endcode %}

The above JSON will make the UI render the following component:

<figure><img src="https://1470748636-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDY50EL4OmcrPvtoecg4h%2Fuploads%2FppXOPMEWU5sKRNpBs3xC%2Fimage.png?alt=media&#x26;token=13cc4927-e160-475b-944e-c84f21d4e426" alt=""><figcaption></figcaption></figure>

## Sample Agent Response with Delete Surface

The following is JSON that will display 2 separate surface:

{% code lineNumbers="true" expandable="true" %}

```json
{
  "status": "success",
  "task_state": "completed",
  "content": "Showing A2UI sample: hello",
  "event_type": "final_response",
  "final": true,
  "metadata": {
    "kind": "final_response",
    "status": "finished",
    "event_type": "final_response",
    "a2ui_content": [
      {
        "surfaceUpdate": {
          "surfaceId": "main",
          "components": [
            {
              "id": "main-root",
              "component": {
                "Card": {
                  "child": "main-content"
                }
              }
            },
            {
              "id": "main-content",
              "component": {
                "Column": {
                  "children": [
                    "main-header",
                    "main-body"
                  ],
                  "distribution": "start",
                  "alignment": "stretch"
                }
              }
            },
            {
              "id": "main-header",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "Main Surface"
                  },
                  "usageHint": "h3"
                }
              }
            },
            {
              "id": "main-body",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "This surface will remain after the temporary one is deleted."
                  },
                  "usageHint": "body"
                }
              }
            }
          ]
        }
      },
      {
        "beginRendering": {
          "surfaceId": "main",
          "root": "main-root"
        }
      },
      {
        "surfaceUpdate": {
          "surfaceId": "temporary",
          "components": [
            {
              "id": "temp-root",
              "component": {
                "Card": {
                  "child": "temp-content"
                }
              }
            },
            {
              "id": "temp-content",
              "component": {
                "Column": {
                  "children": [
                    "temp-header",
                    "temp-body",
                    "temp-countdown"
                  ],
                  "distribution": "start",
                  "alignment": "stretch"
                }
              }
            },
            {
              "id": "temp-header",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "⏱️ Temporary Surface"
                  },
                  "usageHint": "h3"
                }
              }
            },
            {
              "id": "temp-body",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "This surface will be automatically deleted in 3 seconds..."
                  },
                  "usageHint": "body"
                }
              }
            },
            {
              "id": "temp-countdown",
              "component": {
                "Text": {
                  "text": {
                    "literalString": "Watch it disappear! 👀"
                  },
                  "usageHint": "caption"
                }
              }
            }
          ]
        }
      },
      {
        "beginRendering": {
          "surfaceId": "temporary",
          "root": "temp-root"
        }
      }
    ]
  }
}
```

{% endcode %}

<figure><img src="https://1470748636-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDY50EL4OmcrPvtoecg4h%2Fuploads%2FwNymRhD9sXpb8340AWer%2Fimage.png?alt=media&#x26;token=27df7b3a-606b-43d4-891d-0606360f0cb5" alt=""><figcaption></figcaption></figure>

The following is JSON that will **delete existing rendered surface**:

{% code lineNumbers="true" expandable="true" %}

```json
{
  "status": "success",
  "task_state": "completed",
  "content": "Showing A2UI sample: hello",
  "event_type": "final_response",
  "final": true,
  "metadata": {
    "kind": "final_response",
    "status": "finished",
    "event_type": "final_response",
    "a2ui_content": [
      {
        "deleteSurface": {
          "surfaceId": "temporary"
        }
      }
    ]
  }
}
```

{% endcode %}

<figure><img src="https://1470748636-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FDY50EL4OmcrPvtoecg4h%2Fuploads%2FyTxZ9aSwDT69Pz8NOQbQ%2Fimage.png?alt=media&#x26;token=bb114d00-adbc-4ced-96d0-4977c180689f" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
See the component screenshot and compare it with the JSON to get the idea on how to construct A2UI-compliant JSON.
{% endhint %}

## Handle User Interaction

Every time user interact with action component (e.g. clicks a button), agent receives a `userAction` payload from client and should act accordingly. Therefore, agent needs to implement a handler that receives and processes the `userAction` .

`userAction` object has the following structure ([ref](https://a2ui.org/specification/v0.8-a2ui/#52-the-useraction-message)):

```typescript
interface UserActionRequest {
  name: string; //The name of the action, taken directly from the `action.name` property of the component
  surfaceId: string; //The id of the surface where the event originated
  sourceComponentId: string; //The id of the component that triggered the event
  timestamp: string; //An ISO 8601 timestamp of when the event occurred
  context: Record<string, unknown>; //A JSON object containing the key-value pairs from the component's `action.context`, after resolving all values
}
```

Event Flow Example:

1. Let's use our [HITL message above](#sample-agent-response-with-action) as an example. For simplicity, we'll focus on a single button component.

```json
{
  "surfaceUpdate": {
    "surfaceId": "main", // surfaceId
    "components": [
          {
            "id": "approve-btn", // sourceComponentId
            "component": {
                "Button": {
                    "child": "approve-text",
                    "action": {
                        "name": "hitl_decision", // name
                        "context": { // context
                            "decision": {
                                "literalString": "approved"
                            },
                            "requestId": {
                                "path": "/hitl/requestId"
                            }
                        }
                    },
                    "primary": true
                }
            }
        },
    ],
  },
}
```

2. When user clicks the button, agent will receive:

```json
"userAction": {
    "name": "hitl_decision",
    "surfaceId": "main",
    "sourceComponentId": "approve-btn",
    "context": {
        "decision": "approved",
        "requestId": "REQ-2024-00847" // resolved from the dataModelUpdate object
    },
    "timestamp": "2026-03-05T03:30:54.822Z"
}
```

3. The agent's handler receives and process the `userAction` and responds accordingly. If the UI needs to change, agent sends new `surfaceUpdate` and/or `dataModelUpdate` messages over the existing SSE stream.
