← Back to Plugins
Channels

Adaptive Cards

VikrantSingh01 By VikrantSingh01 👁 36 views ▲ 0 votes

Adaptive Cards plugin for OpenClaw โ€” native structured UI on iOS, Android, Teams, and web

GitHub

Install

openclaw plugins install @vikrantsingh01/openclaw-adaptive-cards

Configuration Example

{
  "body": [
    { "type": "TextBlock", "text": "Project Status", "weight": "Bolder" },
    { "type": "FactSet", "facts": [
      { "title": "Deploy API", "value": "Done" },
      { "title": "Write tests", "value": "In Progress" }
    ]}
  ],
  "actions": [
    { "type": "Action.Submit", "title": "Mark Complete", "data": { "task": "tests" } }
  ]
}

README

# openclaw-adaptive-cards

Adaptive Cards plugin for [OpenClaw](https://openclaw.ai) โ€” gives the AI an `adaptive_card` tool to respond with native [Adaptive Cards](https://adaptivecards.io/) (v1.5) instead of plain text.

Cards render natively on:
- **iOS** โ€” SwiftUI via [Teams-AdaptiveCards-Mobile](https://github.com/microsoft/Teams-AdaptiveCards-Mobile)
- **Android** โ€” Jetpack Compose via Teams-AdaptiveCards-Mobile
- **Teams** โ€” Bot Framework attachment (native AC rendering)
- **Web** โ€” [adaptivecards.io](https://www.npmjs.com/package/adaptivecards) JavaScript SDK

Channels that don't support cards (Telegram, Slack, IRC) see auto-generated fallback text.

## Install

```bash
openclaw plugins install @vikrantsingh01/openclaw-adaptive-cards
```

## Architecture

### High-Level Flow

```
Agent LLM
  โ”‚  decides structured content is appropriate
  โ–ผ
adaptive_card tool executes (this plugin)
  โ”‚  assembles AdaptiveCard v1.5 JSON
  โ”‚  generates fallback text
  โ”‚  embeds both in HTML comment markers
  โ–ผ
Gateway passes text through unmodified
  โ”‚  no schema changes, no hooks, no middleware
  โ”‚  cards piggyback on existing ReplyPayload.text
  โ–ผ
Client receives tool result text
  โ”‚
  โ”œโ”€โ–บ iOS / Android โ”€โ”€ regex-extract JSON โ”€โ”€ Teams-AdaptiveCards-Mobile SDK โ”€โ”€ native SwiftUI / Compose view
  โ”œโ”€โ–บ MS Teams โ”€โ”€โ”€โ”€โ”€โ”€โ”€ regex-extract JSON โ”€โ”€ Bot Framework Attachment โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ native Teams card
  โ”œโ”€โ–บ Web UI โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ regex-extract JSON โ”€โ”€ adaptivecards.io JS SDK โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ rendered in browser
  โ””โ”€โ–บ Telegram / Slack / IRC โ”€โ”€ markers invisible (HTML comments) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ shows fallback text only
```

### Marker Wire Format

The tool result text contains three sections:

```
Project Status: Deploy API (done), Write tests (in progress).     โ† FALLBACK TEXT (always visible)

<!--adaptive-card-->{"type":"AdaptiveCard","version":"1.5",...}<!--/adaptive-card-->     โ† CARD JSON
<!--adaptive-card-data-->{"projectId":"abc123"}<!--/adaptive-card-data-->                โ† TEMPLATE DATA (optional)
```

| Section | Purpose |
|---|---|
| **Fallback text** | Auto-generated or agent-provided. Visible on all channels. Non-card channels only see this. |
| **Card JSON** | Full AdaptiveCard v1.5 envelope. Clients regex between `<!--adaptive-card-->` markers. Gateway never touches this. |
| **Template data** | Optional. Enables client-side `${expression}` expansion. Separated from card body for clean data binding. |

### Plugin Layers

```
src/index.ts (260 lines)
  โ”‚
  โ”œโ”€โ”€ AI Tool Layer (lines 22-115)
  โ”‚     Register adaptive_card tool via plugin SDK
  โ”‚     Params: body, actions, fallback_text, template_data
  โ”‚     Assembles AdaptiveCard JSON + marker embedding
  โ”‚
  โ”œโ”€โ”€ Transport Layer (lines 94-113)
  โ”‚     In-band marker embedding in tool result text
  โ”‚     Fallback text โ†’ blank line โ†’ card markers โ†’ template data markers
  โ”‚     Returns structured data in details field for typed access
  โ”‚
  โ”œโ”€โ”€ Fallback Generation (lines 179-260)
  โ”‚     Recursive tree walker: card body โ†’ plain text
  โ”‚     TextBlock, RichTextBlock, FactSet, ColumnSet, Container,
  โ”‚     Image, Table, Input.* all handled
  โ”‚
  โ””โ”€โ”€ Test Command (lines 119-171)
        /acard test โ€” canned card for QA
        /acard {json} โ€” custom card JSON
```

### Design Decisions

| Decision | Why |
|---|---|
| **HTML comment markers** | Travel inside existing tool result text. No gateway schema changes, no new API surfaces. Gateway sanitization only truncates โ€” never strips comments. |
| **Stateless plugin** | No config, no database, no state. Registers a tool and a command โ€” zero operational overhead. |
| **Client-side parsing** | Each client independently decides whether to parse markers. Clients adopt at their own pace with no coordination. |
| **AC v1.5 (not v1.6)** | Highest version with full support across Teams-AdaptiveCards-Mobile, Bot Framework, and JS SDK. |
| **Auto-fallback generation** | Reduces agent prompt complexity. Recursive extractor handles all common elements so agent focuses on card authoring. |
| **Template data separation** | Enables client-side binding without server roundtrips. Card body uses `${expression}` syntax; data travels in a separate marker. |

## How It Works

The plugin registers an `adaptive_card` tool that the AI agent calls when structured content is appropriate (status dashboards, option selections, forms, data tables).

The tool embeds Adaptive Card JSON between HTML comment markers in the tool result text. Mobile apps extract the JSON between markers and render natively. Non-card channels show only the fallback text (markers are invisible HTML comments). The gateway is completely unaware of cards.

## Usage

### AI Tool

The agent calls the `adaptive_card` tool automatically when structured content benefits from visual layout:

```json
{
  "body": [
    { "type": "TextBlock", "text": "Project Status", "weight": "Bolder" },
    { "type": "FactSet", "facts": [
      { "title": "Deploy API", "value": "Done" },
      { "title": "Write tests", "value": "In Progress" }
    ]}
  ],
  "actions": [
    { "type": "Action.Submit", "title": "Mark Complete", "data": { "task": "tests" } }
  ]
}
```

### Tool Parameters

| Parameter | Type | Required | Description |
|---|---|---|---|
| `body` | `unknown[]` | Yes | Array of AC v1.5 body elements (TextBlock, FactSet, ColumnSet, Table, Input.*, etc.) |
| `actions` | `unknown[]` | No | Array of card actions (Action.Submit, Action.OpenUrl, Action.ShowCard) |
| `fallback_text` | `string` | No | Plain text for non-card channels. Auto-generated if omitted. |
| `template_data` | `unknown` | No | Data context for client-side `${expression}` expansion. |

### Test Command

```
/acard test          โ€” Send a test card to verify rendering
/acard {"type":...}  โ€” Send custom card JSON
```

## Supported Elements

### Body Elements

| Element | Fallback Text | Notes |
|---|---|---|
| TextBlock | `.text` | Bold/subtle preserved in fallback |
| RichTextBlock | `.inlines[]` TextRun concatenation | Handles both string and TextRun inlines |
| FactSet | `title: value` per fact | One line per fact |
| ColumnSet | Recurse into `.columns[].items` | Flattened in fallback |
| Container | Recurse into `.items` | Flattened in fallback |
| Image | `[Image: altText]` | Only if `altText` provided |
| Table | Recurse cells, join with `\|` | Row-by-row extraction |
| Input.* | `.label` or `[placeholder]` | Input.Text, Input.Number, Input.Date, etc. |

### Actions

| Action | Supported |
|---|---|
| Action.Submit | Yes โ€” triggers callback with `data` payload |
| Action.OpenUrl | Yes โ€” opens URL in browser |
| Action.ShowCard | Yes โ€” nested card (rendering depends on client) |

## Configuration

No configuration needed โ€” the plugin is stateless.

## Origin

This plugin was extracted from [openclaw/openclaw#33486](https://github.com/openclaw/openclaw/pull/33486) (*Extensions: add adaptive-cards extension for native GenUI*) at the maintainers' request to be published as a standalone third-party plugin.

## Related

- [Adaptive Cards v1.5 Schema Explorer](https://adaptivecards.io/explorer/)
- [Teams-AdaptiveCards-Mobile](https://github.com/microsoft/Teams-AdaptiveCards-Mobile) โ€” MIT-licensed native renderers for iOS (SwiftUI) and Android (Jetpack Compose)
- [adaptivecards npm package](https://www.npmjs.com/package/adaptivecards) โ€” JavaScript SDK for web rendering

## License

MIT
channels

Comments

Sign in to leave a comment

Loading comments...