Implements proactive messaging to a Teams conversation using the Redis conversation-reference pattern in `server/api/msgController.js`. Covers storing `convref:{conversationId}` keys in Redis via `ioredis`, retrieving them, and calling `sendProactiveMessage()` via `BotFrameworkAdapter.continueConversation`. Use when user says 'send proactive message', 'notify channel', 'push message to Teams', or modifies `server/api/msgController.js`. Do NOT use for reactive bot replies (those belong in `server/bot/botActivityHandler.js`).
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.
Implements proactive messaging to a Teams conversation using the Redis conversation-reference pattern in `server/api/msgController.js`. Covers storing `convref:{conversationId}` keys in Redis via `ioredis`, retrieving them, and calling `sendProactiveMessage()` via `BotFrameworkAdapter.continueConversation`. Use when user says 'send proactive message', 'notify channel', 'push message to Teams', or modifies `server/api/msgController.js`. Do NOT use for reactive bot replies (those belong in `server/bot/botActivityHandler.js`).
Proactive Message
Critical
The bot MUST have already received a message from the target conversation before a proactive message can be sent. convref:{conversationId} is written to Redis in server/bot/botActivityHandler.js inside this.onMessage — if this key is missing, the lookup returns null and you get a 404.
Never skip MicrosoftAppCredentials.trustServiceUrl(conversationReference.serviceUrl) on auth-error retries — without it the next attempt will also fail.
Redis key format is always convref:{conversationId} (e.g. convref:19:0c93975aae904b7db892891da3065c33@thread.v2).
Instructions
Store the conversation reference on every incoming message in server/bot/botActivityHandler.js inside this.onMessage:
Verify: run redis-cli get 'convref:<id>' on dragonfly.mailbaby.net:6379 and confirm JSON is stored.
Define sendProactiveMessage in server/api/msgController.js using BotFrameworkAdapter.continueConversation with retry logic (mirrors the existing pattern):
Verify: POST /api/message is already registered in server/api/index.js — do not add another route.
Test end-to-end:
curl -X POST http://localhost:3978/api/message \
-H 'Content-Type: application/json' \
-d '{"message": "Hello from proactive!"}'# Expected: {"message":"sent"}# If 404: the bot hasn't received a message in that channel yet — send any message to the bot first.
Examples
User says: "Add a proactive endpoint that pings the int-dev-private channel when a deploy completes."
Actions taken:
Confirm the conversation reference is stored by sending a test message in the channel and verifying the Redis key exists.
In server/api/msgController.js, set targetConversationId to the int-dev-private channel's conversation ID.
POST /api/message with { "message": "Deploy complete ✅" } → bot posts in channel.
Result: Channel receives the message without any user @mention trigger.
Common Issues
404 no conversation reference found: The bot has not yet received a message in that conversation. Send any message to the bot in the target channel first, then retry.
401 / authorization has been denied: MicrosoftAppId or MicrosoftAppPassword in .env is wrong, or the service URL is not trusted. The retry loop calls MicrosoftAppCredentials.trustServiceUrl(conversationReference.serviceUrl) automatically — if it persists, verify the Azure Bot registration credentials.
ECONNRESET / socket hang up: Transient network error. The sendProactiveMessage retry loop (max 2 attempts, 1 s delay) handles this automatically. If it persists, check connectivity to botframework.com.
Redis ECONNREFUSED: Confirm the Redis host dragonfly.mailbaby.net:6379 is reachable: redis-cli -h dragonfly.mailbaby.net -p 6379 ping should return PONG.
Cannot read properties of null (reading 'serviceUrl'): JSON.parse(stored) returned a malformed reference. Delete the key with redis-cli del 'convref:<id>' and let the bot re-store it on the next incoming message.