Skip to content

turnContext.sendActivity does not return reply.id (messageResponse) for channel messages - problem when passing ID to external API #1561

Open
@domix1996

Description

I'm working on a Microsoft Teams bot (based on the Bot Framework) that, when I send a message (e.g. an adaptive card) to a channel, should return a message identifier (reply.id) - referred to in my code as messageResponse. I then pass this identifier to an external API that I use for search (search task) in my application - so the user can navigate to specific posts (tasks) in the Teams feed.

What am I trying to accomplish?

Sending messages to the channel:

I use the turnContext.sendActivity method inside adapter.continueConversationAsync to send a message to a specific channel. In a local environment (e.g. emulator, local server), the method returns an object containing an id property (e.g. { id: "1234567890", ... }), which I treat as messageResponse.

Forward messageResponse to the frontend:

Once the message is sent, the response (containing reply.id) goes to the React application. I then pass this id (placed in the object I send as messageResponse) to the external API. I use this API in the "search task" Tab, where I retrieve an array of posts (tasks) from the feed, allowing the user to navigate to a specific post on channel.

Problem:

In the local environment, everything works correctly - the sendActivity method returns an object with an id property. However, when deployed to the development environment (Azure), the response does not contain reply.id (that is, messageResponse is empty or does not exist). As a result:

I cannot pass the id to the external API. The search module (search task) does not have access to the full array of posts with the correct message id, making it impossible to redirect the user to a specific post in the feed.

Code snippets: Server (Typescript rest - Bot) - sending messages proactively:

server.post(
	'/api/sendProactiveTextMessage',
	restify.plugins.queryParser(),
	restify.plugins.bodyParser(), // Add more parsers if needed
	async (req, res) => {
		const pageSize = 100
		let continuationToken: string | undefined = undefined
		const messageResponses = []
		const channelId = req.body.teamsData.channelId
		const groupId = req.body.teamsData.groupId

		if (!groupId || !channelId) {
			res.status(400)
			return res.json({
				success: false,
				error: 'Brak groupId lub channelId',
			})
		}

		do {
			const pagedData = await notificationApp.notification.getPagedInstallations(pageSize, continuationToken)
			const installations = pagedData.data
			continuationToken = pagedData.continuationToken
			const now = new Date()

			for (const target of installations) {
				if (target.type === 'Channel') {
					cardData = AdaptiveCards.declare<CardData>(notificationTemplate).render({
						// <--- private data!! --->
					})

					try {
						const conversationReference = target.conversationReference

						let messageId: string | undefined

						await adapter.continueConversationAsync(
							config.botId,
							conversationReference,
							async (turnContext: TurnContext) => {
								const replyActivity = MessageFactory.attachment(CardFactory.adaptiveCard(cardData))
								const reply = await turnContext.sendActivity(replyActivity)

								messageId = reply?.id
							}
						)

						res.json({
							success: true,
							text: messageId,
						})
					} catch (error) {
						console.error('Błąd:', error)
						messageResponses.push({
							success: false,
							error: error.message,
						})
					}
				}
			}
		} while (continuationToken)
		res.json({
			success: true,
			messageResponses: messageResponses,
		})
	}
)

Fragments React (getting to /api/sendProactiveTextMessage):

const response = await fetch(`https://${process.env.REACT_APP_BOT_DOMAIN}/api/sendProactiveTextMessage`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(flaskDataWithTeams),
  redirect: 'follow',
});
const data = await response.json();
console.log('API answer:', data);

if (!data.messageResponses || data.messageResponses.length === 0) {
  throw new Error('The API response does not contain messageResponses.');
}

// messageResponses is later used to search and redirect to posts

Summary:

  • Purpose: To get the message identifier (reply.id, or messageResponse) when a message is sent to a channel, in order to pass it to an external API. I use this API to query the full array of posts (tasks) and enable navigation to a specific post in the Teams channel.

  • Problem: In the development/production environment (Azure) turnContext.sendActivity does not return reply.id for messages sent to the channel, even though locally it works fine.

  • Question: does anyone know the reason for this behavior? Is this a known limitation for channel messages? What approach do you recommend to get the id of the message in the production environment to pass to the downstream API?

I would appreciate any tips or suggestions on this problem. Thank you for your help!

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions