Extends `server/bot/botActivityHandler.js` (TeamsActivityHandler subclass) with new activity handlers — message reactions, invoke actions, card submit handling, member events. Use when user says 'handle activity', 'respond to card submit', 'add bot event handler', or modifies files in `server/bot/`. Do NOT use for dialog logic (OAuthPrompt, WaterfallDialog) — use the bot-dialog skill instead.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Extends `server/bot/botActivityHandler.js` (TeamsActivityHandler subclass) with new activity handlers — message reactions, invoke actions, card submit handling, member events. Use when user says 'handle activity', 'respond to card submit', 'add bot event handler', or modifies files in `server/bot/`. Do NOT use for dialog logic (OAuthPrompt, WaterfallDialog) — use the bot-dialog skill instead.
bot-activity-handler
Critical
Every handler registered in the constructor must call await next() as its final statement — omitting it silently swallows all subsequent middleware.
Card submit actions arrive as message activities, not invoke activities. Check the msteams.type field within context.activity.value inside onMessage, not onInvokeActivity.
After sending an Adaptive Card, call updateActionSubmitData() to inject activityId into every Action.Submit so the bot can later call context.updateActivity() to replace the card.
Never import from botbuilder-dialogs in this file — that belongs in server/dialogs/.
Instructions
Identify the target handler type. Determine which Bot Framework lifecycle hook applies:
Incoming text/card-submit → this.onMessage
Member joins/leaves → this.onMembersAdded / this.onMembersRemoved
Token response → this.onTokenResponseEvent
Verify the hook name exists in BotActivityHandler constructor in server/bot/botActivityHandler.js before proceeding.
Add the handler inside the constructor of BotActivityHandler in server/bot/botActivityHandler.js. Follow this exact skeleton:
Verify await next() is the last line before the closing }.
For card submit actions, add a branch inside the existing this.onMessage handler. Card action type is found in context.activity.value as the msteams.type field. Pattern:
Card submit never fires: The card's Action.Submit is missing "data": { "msteams": { "type": "yourActionName" } }. Check cards/your_card.json and ensure that field is present.
context.updateActivity throws Activity not found: activityId was not injected into the card before it was sent. Verify updateActionSubmitData() is called after context.sendActivity and before context.updateActivity.
Handler body runs but await next() missing → downstream middleware broken: Add await next() as the last line inside every this.onXxx callback.
TypeError: Cannot read properties of undefined (reading 'type') when reading the msteams type: Use optional chaining: context.activity.value?.msteams?.type.
Reaction events not received: RSC permission ChannelMessage.Read.Group must be declared in appManifest/manifest.json under authorization.permissions.resourceSpecific. Verify with cat appManifest/manifest.json | grep -A5 resourceSpecific.