Files
vercel__chat/examples
Aamir Jawaid 4f5d20029f Add modal support for Teams (#325)
* feat(teams): add dialog (task module) support

Teams dialogs require modal content to be returned inline in the HTTP
response when a task/fetch invoke fires. This adds:

- `actionType: "modal"` on buttons to emit msteams task/fetch hint
- `onOpenModal` hook on WebhookOptions for inline modal interception
- dialog.open/dialog.submit handlers in Teams adapter with Promise.race
- Modal-to-AdaptiveCard converter (modals.ts)
- Bridge adapter sends empty body (not "{}") for dialog close responses

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(teams): use @microsoft/teams.cards builders for Adaptive Cards

Replace hand-rolled plain JSON objects and local type definitions with
typed builder classes from @microsoft/teams.cards. This gives compile-time
type safety and eliminates the local AdaptiveCard/AdaptiveCardElement/
AdaptiveCardAction interfaces.

Also fix ephemeral modal button missing actionType="modal", which
prevented the dialog from opening on Teams.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(teams): preserve contextId in modal update/push responses

Pass the original contextId through to re-rendered modals so subsequent
submissions can still retrieve the stored thread/message/channel context.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor: address review feedback across dialog support

- Clean up timeout timer in handleDialogOpen to prevent resource leak
- Also race on actionPromise so errors surface instead of silently timing out
- Extract buildContinueResponse helper to deduplicate update/push cases
- Use typed TextInputOptions/ChoiceSetInputOptions instead of Record<string, unknown>
- Make processSlashCommand options parameter explicit (WebhookOptions | undefined)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(chat): await storeModalContext before opening modal

The state write was fire-and-forget, so a fast dialog.submit could
arrive before the context was persisted, causing retrieveModalContext
to return empty. Also adds changeset for the new public API surface.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(chat): add missing disabled prop to ButtonProps JSX interface

The ButtonElement and ButtonOptions already supported disabled, but the
JSX ButtonProps interface was missing it, causing <Button disabled> to
silently drop the prop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address PR review feedback for dialog support

- Add unit tests for modals.ts (16 tests) and modal button actionType in cards.test.ts
- Make dialog open timeout configurable via dialogOpenTimeoutMs in TeamsAdapterConfig
- Fix ModalSubmitHandler type to accept Promise<void> returns, remove @ts-expect-error from example
- Delete stored modal context after retrieval to prevent state adapter leaks

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: lint fixes and add X-User-Agent header to Teams adapter

- Fix import ordering, formatting, and non-null assertions in modals.test.ts
- Sort interface members in TeamsAdapterConfig
- Add X-User-Agent: Vercel.ChatSDK header to Teams SDK App client

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:09:25 +10:00
..