重要
本部分中的代码示例基于 Bot Framework SDK 版本 4.6 和更高版本。 如果要查找早期版本的文档,请参阅文档的旧版 SDK 文件夹中的 机器人 - v3 SDK 部分。
为 Microsoft Teams 构建会话机器人时,你可以处理对话事件。 对于发生在机器人活动范围内的对话事件,Teams 会向机器人发送通知。 可以在代码中捕获这些事件,并执行以下操作:
- 将机器人添加到团队时触发欢迎消息。
- 添加或删除新团队成员时触发欢迎消息。
- 创建、重命名或删除频道时触发通知。
- 当用户为机器人消息点赞时触发通知。
- 在安装过程中,从用户输入 (选择) 确定机器人的默认通道。
以下视频演示了聊天机器人如何通过流畅的智能交互来提高客户参与度:
对话更新事件
可以使用聊天更新事件来提供更好的通知和有效的机器人作。
重要
- 你可以随时添加新事件,机器人将开始接收这些事件。
- 必须设计机器人才能接收意外事件。
- 如果你使用的是 Bot Framework SDK,则机器人会自动对你选择不处理的任何事件响应
200 - OK
。
- 当Azure 通信服务 (ACS) 客户端加入或离开 Teams 会议时,不会触发任何对话更新事件。
在以下任一情况下,机器人都会收到 conversationUpdate
事件:
- 将机器人添加到对话时。
- 在会话中添加或删除了其他成员。
- 对话元数据已发生更改。
当机器人收到关于其所属团队的成员身份更新信息时,conversationUpdate
事件就会发送到机器人。 在首次为个人对话添加机器人时,机器人也会收到更新。
下表显示了包含更多详细信息的 Teams 对话更新事件的列表:
采取的操作 |
EventType |
调用的方法 |
说明 |
范围 |
已创建频道 |
channelCreated |
OnTeamsChannelCreatedAsync |
已创建频道。 |
团队 |
已重命名频道 |
channelRenamed |
OnTeamsChannelRenamedAsync |
已重命名频道。 |
团队 |
已删除频道 |
channelDeleted |
OnTeamsChannelDeletedAsync |
已删除频道。 |
团队 |
已还原频道 |
channelRestored |
OnTeamsChannelRestoredAsync |
已还原频道。 |
团队 |
已添加成员。 |
membersAdded |
OnTeamsMembersAddedAsync |
已添加成员。 |
全部 |
已删除成员 |
membersRemoved |
OnTeamsMembersRemovedAsync |
已删除成员。 |
全部 |
已重命名团队 |
teamRenamed |
OnTeamsTeamRenamedAsync |
已重命名团队。 |
团队 |
已删除团队 |
teamDeleted |
OnTeamsTeamDeletedAsync |
已删除团队。 |
团队 |
已存档团队 |
teamArchived |
OnTeamsTeamArchivedAsync |
团队已存档。 |
团队 |
未存档团队 |
teamUnarchived |
OnTeamsTeamUnarchivedAsync |
团队未存档。 |
团队 |
已还原团队 |
teamRestored |
OnTeamsTeamRestoredAsync |
已还原团队 |
团队 |
已创建频道
每当在安装了机器人的团队中创建新通道时,事件 channelCreated
将发送到机器人。
以下代码显示了通道创建事件的示例:
protected override async Task OnTeamsChannelCreatedAsync(ChannelInfo channelInfo, TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var heroCard = new HeroCard(text: $"{channelInfo.Name} is the Channel created");
// Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken);
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
this.onTeamsChannelCreatedEvent(async (channelInfo: ChannelInfo, teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
const card = CardFactory.heroCard('Channel Created', `${channelInfo.name} is the Channel created`);
const message = MessageFactory.attachment(card);
// Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message);
await next();
});
}
}
{
"type": "conversationUpdate",
"timestamp": "2017-02-23T19:34:07.478Z",
"localTimestamp": "2017-02-23T12:34:07.478-07:00",
"id": "f:dd6ec311",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1wR7IdIRIoerMIWbewMi75JA3scaMuxvFon9eRQW2Nix5loMDo0362st2IaRVRirPZBv1WdXT8TIFWWmlQCizZQ"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"recipient": {
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterBot"
},
"channelData": {
"channel": {
"id": "19:6d97d816470f481dbcda38244b98689a@thread.skype",
"name": "FunDiscussions"
},
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"eventType": "channelCreated",
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
}
}
async def on_teams_channel_created(
self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext
):
# Sends a message activity to the sender of the incoming activity.
return await turn_context.send_activity(
MessageFactory.text(
f"The new channel is {channel_info.name}. The channel id is {channel_info.id}"
)
)
已重命名频道
channelRenamed
每当在安装了机器人的团队中重命名通道时,事件将发送到机器人。
以下代码显示了通道重命名事件的示例:
protected override async Task OnTeamsChannelRenamedAsync(ChannelInfo channelInfo, TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var heroCard = new HeroCard(text: $"{channelInfo.Name} is the new Channel name");
// Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken);
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
this.onTeamsChannelRenamedEvent(async (channelInfo: ChannelInfo, teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
const card = CardFactory.heroCard('Channel Renamed', `${channelInfo.name} is the new Channel name`);
const message = MessageFactory.attachment(card);
// Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message);
await next();
});
}
{
"type": "conversationUpdate",
"timestamp": "2017-02-23T19:34:07.478Z",
"localTimestamp": "2017-02-23T12:34:07.478-07:00",
"id": "f:dd6ec311",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1wR7IdIRIoerMIWbewMi75JA3scaMuxvFon9eRQW2Nix5loMDo0362st2IaRVRirPZBv1WdXT8TIFWWmlQCizZQ"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"recipient": {
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterBot"
},
"channelData": {
"channel": {
"id": "19:6d97d816470f481dbcda38244b98689a@thread.skype",
"name": "PhotographyUpdates"
},
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"eventType": "channelRenamed",
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
}
}
async def on_teams_channel_renamed(
self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext
):
return await turn_context.send_activity(
MessageFactory.text(f"The new channel name is {channel_info.name}")
)
已删除频道
channelDeleted
每当在安装了机器人的团队中删除频道时,该事件将发送到机器人。
以下代码显示了通道删除事件的示例:
protected override async Task OnTeamsChannelDeletedAsync(ChannelInfo channelInfo, TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var heroCard = new HeroCard(text: $"{channelInfo.Name} is the Channel deleted");
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken);
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
this.onTeamsChannelDeletedEvent(async (channelInfo: ChannelInfo, teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
const card = CardFactory.heroCard('Channel Deleted', `${channelInfo.name} is the Channel deleted`);
const message = MessageFactory.attachment(card);
// Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message);
await next();
});
}
}
{
"type": "conversationUpdate",
"timestamp": "2017-02-23T19:34:07.478Z",
"localTimestamp": "2017-02-23T12:34:07.478-07:00",
"id": "f:dd6ec311",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1wR7IdIRIoerMIWbewMi75JA3scaMuxvFon9eRQW2Nix5loMDo0362st2IaRVRirPZBv1WdXT8TIFWWmlQCizZQ"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"recipient": {
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterBot"
},
"channelData": {
"channel": {
"id": "19:6d97d816470f481dbcda38244b98689a@thread.skype",
"name": "PhotographyUpdates"
},
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"eventType": "channelDeleted",
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
}
}
async def on_teams_channel_deleted(
self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext
):
# Sends a message activity to the sender of the incoming activity.
return await turn_context.send_activity(
MessageFactory.text(f"The deleted channel is {channel_info.name}")
)
已还原频道
channelRestored
每当在已安装机器人的团队中还原以前删除的频道时,事件将发送到机器人。
以下代码显示了通道还原事件的示例:
protected override async Task OnTeamsChannelRestoredAsync(ChannelInfo channelInfo, TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var heroCard = new HeroCard(text: $"{channelInfo.Name} is the Channel restored.");
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken);
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
this.onTeamsChannelRestoredEvent(async (channelInfo: ChannelInfo, teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
const card = CardFactory.heroCard('Channel Restored', `${channelInfo.name} is the Channel restored`);
const message = MessageFactory.attachment(card);
// Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message);
await next();
});
}
}
{
"type": "conversationUpdate",
"timestamp": "2017-02-23T19:34:07.478Z",
"localTimestamp": "2017-02-23T12:34:07.478-07:00",
"id": "f:dd6ec311",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1wR7IdIRIoerMIWbewMi75JA3scaMuxvFon9eRQW2Nix5loMDo0362st2IaRVRirPZBv1WdXT8TIFWWmlQCizZQ"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"recipient": {
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterBot"
},
"channelData": {
"channel": {
"id": "19:6d97d816470f481dbcda38244b98689a@thread.skype",
"name": "FunDiscussions"
},
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"eventType": "channelRestored",
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
}
}
async def on_teams_channel_restored(
self, channel_info: ChannelInfo, team_info: TeamInfo, turn_context: TurnContext
):
# Sends a message activity to the sender of the incoming activity.
return await turn_context.send_activity(
MessageFactory.text(
f"The restored channel is {channel_info.name}. The channel id is {channel_info.id}"
)
)
已添加成员。
在以下方案中,将成员添加的事件发送到机器人:
当机器人本身安装并添加到对话时
在团队上下文中,活动的 conversation.id 设置为 id
用户在应用安装期间选择的通道或安装机器人的通道的 。
将用户添加到安装了机器人的对话时
在事件有效负载中收到的用户 ID 对于机器人是唯一的,可以缓存以供将来使用,例如直接向用户发送消息。
从团队上下文发送事件时,成员添加的活动 eventType
设置为 teamMemberAdded
。 若要确定添加的新成员是机器人本身还是用户,检查 Activity
的 对象turnContext
。
MembersAdded
如果列表包含的对象,其中id
与 对象的字段Recipient
相同id
,则添加的成员是机器人,否则它是用户。 机器人的 id
的格式为 28:<MicrosoftAppId>
。
以下代码显示了团队成员添加事件的示例:
protected override async Task OnTeamsMembersAddedAsync(IList<TeamsChannelAccount> teamsMembersAdded , TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
foreach (TeamsChannelAccount member in teamsMembersAdded)
{
if (member.Id == turnContext.Activity.Recipient.Id)
{
// Send a message to introduce the bot to the team.
var heroCard = new HeroCard(text: $"The {member.Name} bot has joined {teamInfo.Name}");
// Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken);
}
else
{
var heroCard = new HeroCard(text: $"{member.Name} joined {teamInfo.Name}");
// Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken);
}
}
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
this.onTeamsMembersAddedEvent(async (membersAdded: ChannelAccount[], teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
let newMembers: string = '';
console.log(JSON.stringify(membersAdded));
membersAdded.forEach((account) => {
newMembers += account.id + ' ';
});
const name = !teamInfo ? 'not in team' : teamInfo.name;
const card = CardFactory.heroCard('Account Added', `${newMembers} joined ${name}.`);
const message = MessageFactory.attachment(card);
// Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message);
await next();
});
}
}
机器人添加到团队时机器人接收的消息。
注意
在此有效负载中, conversation.id
和 channelData.settings.selectedChannel.id
是用户在应用安装期间选择的通道的 ID,或者从中触发安装。
{
"type": "conversationUpdate",
"membersAdded": [
{
"id": "28:608cacfd-1cea-40c9-b678-4b93e69bb72b"
}
],
"timestamp": "2021-12-07T22:34:56.534Z",
"id": "f:0b9079f4-d4d3-3d8e-b883-798298053c7e",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer/",
"from": {
"id": "29:1ljv6N86roXr5pjPrCJVIz6xHh5QxjI....",
"aadObjectId": "eddfa9d4-346e-4cce-a18f-fa6261ad776b"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"tenantId": "b28fdbfd-2b78-4f93-b0f8-8881793f0f8f",
"id": "19:0b7f32667e064dd9b25d7969801541f4@thread.tacv2",
"name": "2021 Test Channel"
},
"recipient": {
"id": "28:608cacfd-1cea-40c9-b678-4b93e69bb72b",
"name": "Test Bot"
},
"channelData": {
"settings": {
"selectedChannel": {
"id": "19:0b7f32667e064dd9b25d7969801541f4@thread.tacv2"
}
},
"team": {
"aadGroupId": "f3ec8cd2-e704-4344-8c47-9a3a21d683c0",
"name": "TestTeam2022",
"id": "19:zFLSDFWsesfzcmKArqKJ-65aOXJz@sgf462H2wz41@thread.tacv2"
},
"eventType": "teamMemberAdded",
"tenant": {
"id": "b28fdbfd-2b78-4f93-b0f8-8881793f0f8f"
}
}
}
机器人添加到一对一聊天时机器人收到的消息。
{
"membersAdded": [{
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0"
},
{
"id": "29:<userID>",
"aadObjectId": "***"
}
],
"type": "conversationUpdate",
"timestamp": "2019-04-23T10:17:44.349Z",
"id": "f:5f85c2ad",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:<USERID>",
"aadObjectId": "***"
},
"conversation": {
"conversationType": "personal",
"id": "***"
},
"recipient": {
"id": "28:<BOT ID>",
"name": "<BOT NAME>"
},
"channelData": {
"tenant": {
"id": "<TENANT ID>"
}
}
}
async def on_teams_members_added(
self, teams_members_added: [TeamsChannelAccount], turn_context: TurnContext
):
for member in teams_members_added:
.. # Sends a message activity to the sender of the incoming activity.
await turn_context.send_activity(
MessageFactory.text(f"Welcome your new team member {member.id}")
)
return
已删除成员
在以下情况下,成员删除事件将发送到机器人:
- 当机器人本身被卸载并从对话中删除时。
- 从安装机器人的对话中删除用户时。
从团队上下文发送事件时,成员删除的活动 eventType
设置为 teamMemberRemoved
。 若要确定删除的新成员是机器人本身还是用户,请检查 turnContext
的 Activity
对象。
MembersRemoved
如果列表包含的对象,其中id
与 对象的字段Recipient
相同id
,则添加的成员是机器人,否则它是用户。 机器人的 ID 的格式为 28:<MicrosoftAppId>
。
注意
从租户中永久删除用户时,将触发 membersRemoved conversationUpdate
事件。
以下代码显示了团队成员已删除事件的示例:
protected override async Task OnTeamsMembersRemovedAsync(IList<ChannelAccount> membersRemoved, TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
foreach (TeamsChannelAccount member in membersRemoved)
{
if (member.Id == turnContext.Activity.Recipient.Id)
{
// The bot was removed.
// You should clear any cached data you have for this team.
}
else
{
var heroCard = new HeroCard(text: $"{member.Name} was removed from {teamInfo.Name}");
// Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken);
}
}
}
SDK 参考
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
this.onTeamsMembersRemovedEvent(async (membersRemoved: ChannelAccount[], teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
let removedMembers: string = '';
console.log(JSON.stringify(membersRemoved));
membersRemoved.forEach((account) => {
removedMembers += account.id + ' ';
});
const name = !teamInfo ? 'not in team' : teamInfo.name;
const card = CardFactory.heroCard('Account Removed', `${removedMembers} removed from ${teamInfo.name}.`);
const message = MessageFactory.attachment(card);
// Sends a message activity to the sender of the incoming activity.
await turnContext.sendActivity(message);
await next();
});
}
}
以下有效负载示例中的 channelData
对象基于将成员添加到团队而不是群组聊天,或发起新的一对一对话:
{
"membersRemoved": [
{
"id": "29:1_LCi5Up14pAy65yZuaJzG1uIT7ujYhjjSTsUNqjORsZHjLHKiQIBJa4cX2XsAsRoaY7va2w6ZymA9-1VtSY_g"
}
],
"type": "conversationUpdate",
"timestamp": "2017-02-23T19:37:06.96Z",
"localTimestamp": "2017-02-23T12:37:06.96-07:00",
"id": "f:d8a6a4aa",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1I9Is_Sx0OIy2rQ7Xz1lcaPKlO9eqmBRTBuW6XzkFtcjqxTjPaCMij8BVMdBcL9L_RwWNJyAHFQb0TRzXgyQvA"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"recipient":
{
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterBot"
},
"channelData": {
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"eventType": "teamMemberRemoved",
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
}
}
async def on_teams_members_removed(
self, teams_members_removed: [TeamsChannelAccount], turn_context: TurnContext
):
for member in teams_members_removed:
..# Sends a message activity to the sender of the incoming activity.
await turn_context.send_activity(
MessageFactory.text(f"Say goodbye to {member.id}")
)
return
已重命名团队
重命名团队时通知机器人。 它在 channelData
对象中接收类型为 eventType.teamRenamed
的 conversationUpdate
事件。
以下代码显示了团队重命名事件的示例:
protected override async Task OnTeamsTeamRenamedAsync(TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var heroCard = new HeroCard(text: $"{teamInfo.Name} is the new Team name");
// Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken);
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
// Bot is notified when the team is renamed.
this.onTeamsTeamRenamedEvent(async (teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
const card = CardFactory.heroCard('Team Renamed', `${teamInfo.name} is the new Team name`);
const message = MessageFactory.attachment(card);
// Sends an activity to the sender of the incoming activity.
await turnContext.sendActivity(message);
await next();
});
}
}
{
"type": "conversationUpdate",
"timestamp": "2017-02-23T19:35:56.825Z",
"localTimestamp": "2017-02-23T12:35:56.825-07:00",
"id": "f:1406033e",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1I9Is_Sx0O-Iy2rQ7Xz1lcaPKlO9eqmBRTBuW6XzkFtcjqxTjPaCMij8BVMdBcL9L_RwWNJyAHFQb0TRzXgyQvA"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"recipient": {
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterLocal"
},
"channelData": {
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype",
"name": "New Team Name"
},
"eventType": "teamRenamed",
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
}
}
# Bot is notified when the team is renamed.
async def on_teams_team_renamed(
self, team_info: TeamInfo, turn_context: TurnContext
):
# Sends an activity to the sender of the incoming activity.
return await turn_context.send_activity(
MessageFactory.text(f"The new team name is {team_info.name}")
)
已删除团队
删除团队时,机器人会收到通知。 它在 channelData
对象中接收类型为 eventType.teamDeleted
的 conversationUpdate
事件。
以下代码显示了团队删除事件的示例:
protected override async Task OnTeamsTeamDeletedAsync(TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
// Handle delete event.
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
// Invoked when a Team Deleted event activity is received from the connector. Team Deleted corresponds to the user deleting a team.
this.onTeamsTeamDeletedEvent(async (teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
// Handle delete event.
await next();
});
}
}
{
"type": "conversationUpdate",
"timestamp": "2017-02-23T19:35:56.825Z",
"localTimestamp": "2017-02-23T12:35:56.825-07:00",
"id": "f:1406033e",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1I9Is_Sx0O-Iy2rQ7Xz1lcaPKlO9eqmBRTBuW6XzkFtcjqxTjPaCMij8BVMdBcL9L_RwWNJyAHFQb0TRzXgyQvA"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"recipient": {
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterLocal"
},
"channelData": {
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype",
"name": "Team Name"
},
"eventType": "teamDeleted",
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
}
}
# Invoked when a Team Deleted event activity is received from the connector. Team Deleted corresponds to the user deleting a team.
async def on_teams_team_deleted(
self, team_info: TeamInfo, turn_context: TurnContext
):
# Handle delete event.
)
已还原团队
当团队在删除后还原时,机器人会收到通知。 它在 channelData
对象中接收类型为 eventType.teamrestored
的 conversationUpdate
事件。
以下代码显示了团队还原事件的示例:
protected override async Task OnTeamsTeamrestoredAsync(TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var heroCard = new HeroCard(text: $"{teamInfo.Name} is the team name");
// Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken);
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
// Invoked when a Team Restored event activity is received from the connector. Team Restored corresponds to the user restoring a team.
this.onTeamsTeamrestoredEvent(async (teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
const card = CardFactory.heroCard('Team restored', `${teamInfo.name} is the team name`);
const message = MessageFactory.attachment(card);
// Sends an activity to the sender of the incoming activity.
await turnContext.sendActivity(message);
await next();
});
}
}
{
"type": "conversationUpdate",
"timestamp": "2017-02-23T19:35:56.825Z",
"localTimestamp": "2017-02-23T12:35:56.825-07:00",
"id": "f:1406033e",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1I9Is_Sx0O-Iy2rQ7Xz1lcaPKlO9eqmBRTBuW6XzkFtcjqxTjPaCMij8BVMdBcL9L_RwWNJyAHFQb0TRzXgyQvA"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"recipient": {
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterLocal"
},
"channelData": {
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype",
"name": "Team Name"
},
"eventType": "teamrestored",
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
}
}
# Invoked when a Team Restored event activity is received from the connector. Team Restored corresponds to the user restoring a team.
async def on_teams_team_restored(
self, team_info: TeamInfo, turn_context: TurnContext
):
# Sends an activity to the sender of the incoming activity.
return await turn_context.send_activity(
MessageFactory.text(f"The team name is {team_info.name}")
)
已存档团队
安装和存档团队时,机器人会收到通知。 它在 channelData
对象中接收类型为 eventType.teamarchived
的 conversationUpdate
事件。
以下代码显示团队存档事件的示例:
protected override async Task OnTeamsTeamArchivedAsync(TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var heroCard = new HeroCard(text: $"{teamInfo.Name} is the team name");
// Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken);
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
// Invoked when a Team Archived event activity is received from the connector. Team Archived.
this.onTeamsTeamArchivedEvent(async (teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
const card = CardFactory.heroCard('Team archived', `${teamInfo.name} is the team name`);
const message = MessageFactory.attachment(card);
// Sends an activity to the sender of the incoming activity.
await turnContext.sendActivity(message);
await next();
});
}
}
{
"type": "conversationUpdate",
"timestamp": "2017-02-23T19:35:56.825Z",
"localTimestamp": "2017-02-23T12:35:56.825-07:00",
"id": "f:1406033e",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1I9Is_Sx0O-Iy2rQ7Xz1lcaPKlO9eqmBRTBuW6XzkFtcjqxTjPaCMij8BVMdBcL9L_RwWNJyAHFQb0TRzXgyQvA"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"recipient": {
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterLocal"
},
"channelData": {
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype",
"name": "Team Name"
},
"eventType": "teamArchived",
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
}
}
# Invoked when a Team Archived event activity is received from the connector. Team Archived correspond to the user archiving a team.
async def on_teams_team_archived(
self, team_info: TeamInfo, turn_context: TurnContext
):
# Sends an activity to the sender of the incoming activity.
return await turn_context.send_activity(
MessageFactory.text(f"The team name is {team_info.name}")
)
未存档团队
安装和取消存档团队时,机器人会收到通知。 它在 channelData
对象中接收类型为 eventType.teamUnarchived
的 conversationUpdate
事件。
以下代码显示了团队未存档事件的示例:
protected override async Task OnTeamsTeamUnarchivedAsync(TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var heroCard = new HeroCard(text: $"{teamInfo.Name} is the team name");
// Sends an activity to the sender of the incoming activity.
await turnContext.SendActivityAsync(MessageFactory.Attachment(heroCard.ToAttachment()), cancellationToken);
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
// Invoked when a Team Unarchived event activity is received from the connector. Team.
this.onTeamsTeamUnarchivedEvent(async (teamInfo: TeamInfo, turnContext: TurnContext, next: () => Promise<void>): Promise<void> => {
const card = CardFactory.heroCard('Team archived', `${teamInfo.name} is the team name`);
const message = MessageFactory.attachment(card);
// Sends an activity to the sender of the incoming activity.
await turnContext.sendActivity(message);
await next();
});
}
}
{
"type": "conversationUpdate",
"timestamp": "2017-02-23T19:35:56.825Z",
"localTimestamp": "2017-02-23T12:35:56.825-07:00",
"id": "f:1406033e",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1I9Is_Sx0O-Iy2rQ7Xz1lcaPKlO9eqmBRTBuW6XzkFtcjqxTjPaCMij8BVMdBcL9L_RwWNJyAHFQb0TRzXgyQvA"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"recipient": {
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterLocal"
},
"channelData": {
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype",
"name": "Team Name"
},
"eventType": "teamUnarchived",
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
}
}
# Invoked when a Team Unarchived event activity is received from the connector. Team Unarchived correspond to the user unarchiving a team.
async def on_teams_team_unarchived(
self, team_info: TeamInfo, turn_context: TurnContext
):
# Sends an activity to the sender of the incoming activity.
return await turn_context.send_activity(
MessageFactory.text(f"The team name is {team_info.name}")
)
现在,你已处理会话更新事件,可以了解对消息的不同反应所发生的消息反应事件。
消息回应事件
messageReaction
当用户添加或删除对机器人发送的消息的反应时,将发送事件。
replyToId
包含消息的 ID,Type
是文本格式的回应类型。 回应类型包括生气、爱心、大笑、喜欢、悲伤和惊讶。 此事件不包含原始消息的内容。 如果对于机器人而言处理对消息的回应很重要,则在发送消息时必须存储这些消息。 下表提供了有关事件类型和有效负载对象的详细信息:
EventType |
有效负载对象 |
说明 |
范围 |
messageReaction |
reactionsAdded |
添加到机器人消息的回应。 |
所有 |
messageReaction |
reactionsRemoved |
从机器人消息中删除的回应。 |
全部 |
添加到机器人消息的回应
以下代码显示对机器人消息的回应示例:
protected override async Task OnReactionsAddedAsync(IList<MessageReaction> messageReactions, ITurnContext<IMessageReactionActivity> turnContext, CancellationToken cancellationToken)
{
foreach (var reaction in messageReactions)
{
var newReaction = $"You reacted with '{reaction.Type}' to the following message: '{turnContext.Activity.ReplyToId}'";
var replyActivity = MessageFactory.Text(newReaction);
// Sends an activity to the sender of the incoming activity.
var resourceResponse = await turnContext.SendActivityAsync(replyActivity, cancellationToken);
}
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
// Override this in a derived class to provide logic for when reactions to a previous activity.
this.onReactionsAdded(async (context, next) => {
const reactionsAdded = context.activity.reactionsAdded;
if (reactionsAdded && reactionsAdded.length > 0) {
for (let i = 0; i < reactionsAdded.length; i++) {
const reaction = reactionsAdded[i];
const newReaction = `You reacted with '${reaction.type}' to the following message: '${context.activity.replyToId}'`;
// Sends an activity to the sender of the incoming activity.
const resourceResponse = context.sendActivity(newReaction);
// Save information about the sent message and its ID (resourceResponse.id).
}
}
});
}
}
{
"reactionsAdded": [
{
"type": "like"
}
],
"type": "messageReaction",
"timestamp": "2017-10-16T18:45:41.943Z",
"id": "f:9f78d1f3",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1I9Is_Sx0O-Iy2rQ7Xz1lcaPKlO9eqmBRTBuW6XzkFtcjqxTjPaCMij8BVMdBcL9L_RwWNJyAHFQb0TRzXgyQvA",
"aadObjectId": "c33aafc4-646d-4543-9d4c-abd28e4d2110"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:3629591d4b774aa08cb0887902eee7c1@thread.skype"
},
"recipient": {
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterLocal"
},
"channelData": {
"channel": {
"id": "19:3629591d4b774aa08cb0887902eee7c1@thread.skype"
},
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
},
"replyToId": "1575667808184",
"legacy": {
"replyToId": "1:19uJ8TZA1cZcms7-2HLOW3pWRF4nSWEoVnRqc0DPa_kY"
}
}
# Override this in a derived class to provide logic for when reactions to a previous activity are added to the conversation.
async def on_reactions_added(
self, message_reactions: List[MessageReaction], turn_context: TurnContext
):
for reaction in message_reactions:
activity = await self._log.find(turn_context.activity.reply_to_id)
if not activity:
# Sends an activity to the sender of the incoming activity.
await self._send_message_and_log_activity_id(
turn_context,
f"Activity {turn_context.activity.reply_to_id} not found in log",
)
else:
# Sends an activity to the sender of the incoming activity.
await self._send_message_and_log_activity_id(
turn_context,
f"You added '{reaction.type}' regarding '{activity.text}'",
)
return
从机器人消息中删除的回应
以下代码显示从机器人消息中删除的回应示例:
protected override async Task OnReactionsRemovedAsync(IList<MessageReaction> messageReactions, ITurnContext<IMessageReactionActivity> turnContext, CancellationToken cancellationToken)
{
foreach (var reaction in messageReactions)
{
var newReaction = $"You removed the reaction '{reaction.Type}' from the following message: '{turnContext.Activity.ReplyToId}'";
var replyActivity = MessageFactory.Text(newReaction);
// Sends an activity to the sender of the incoming activity.
var resourceResponse = await turnContext.SendActivityAsync(replyActivity, cancellationToken);
}
}
export class MyBot extends TeamsActivityHandler {
constructor() {
super();
// Override this in a derived class to provide logic for when reactions to a previous activity.
this.onReactionsRemoved(async(context,next)=>{
const reactionsRemoved = context.activity.reactionsRemoved;
if (reactionsRemoved && reactionsRemoved.length > 0) {
for (let i = 0; i < reactionsRemoved.length; i++) {
const reaction = reactionsRemoved[i];
const newReaction = `You removed the reaction '${reaction.type}' from the message: '${context.activity.replyToId}'`;
// Sends an activity to the sender of the incoming activity.
const resourceResponse = context.sendActivity(newReaction);
// Save information about the sent message and its ID (resourceResponse.id).
}
}
});
}
}
{
"reactionsRemoved": [
{
"type": "like"
}
],
"type": "messageReaction",
"timestamp": "2017-10-16T18:45:41.943Z",
"id": "f:9f78d1f3",
"channelId": "msteams",
"serviceUrl": "https://smba.trafficmanager.net/amer-client-ss.msg/",
"from": {
"id": "29:1I9Is_Sx0O-Iy2rQ7Xz1lcaPKlO9eqmBRTBuW6XzkFtcjqxTjPaCMij8BVMdBcL9L_RwWNJyAHFQb0TRzXgyQvA",
"aadObjectId": "c33aafc4-646d-4543-9d4c-abd28e4d2110"
},
"conversation": {
"isGroup": true,
"conversationType": "channel",
"id": "19:3629591d4b774aa08cb0887902eee7c1@thread.skype"
},
"recipient": {
"id": "28:f5d48856-5b42-41a0-8c3a-c5f944b679b0",
"name": "SongsuggesterLocal"
},
"channelData": {
"channel": {
"id": "19:3629591d4b774aa08cb0887902eee7c1@thread.skype"
},
"team": {
"id": "19:efa9296d959346209fea44151c742e73@thread.skype"
},
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
},
"replyToId": "1575667808184",
"legacy": {
"replyToId": "1:19uJ8TZA1cZcms7-2HLOW3pWRF4nSWEoVnRqc0DPa_kY"
}
}
# Override this in a derived class to provide logic specific to removed activities.
async def on_reactions_removed(
self, message_reactions: List[MessageReaction], turn_context: TurnContext
):
for reaction in message_reactions:
activity = await self._log.find(turn_context.activity.reply_to_id)
if not activity:
# Sends an activity to the sender of the incoming activity.
await self._send_message_and_log_activity_id(
turn_context,
f"Activity {turn_context.activity.reply_to_id} not found in log",
)
else:
# Sends an activity to the sender of the incoming activity.
await self._send_message_and_log_activity_id(
turn_context,
f"You removed '{reaction.type}' regarding '{activity.text}'",
)
return
安装更新事件
将机器人安装到对话线程时,机器人会收到 installationUpdate
事件。 从线程中卸载机器人也会触发该事件。 安装机器人时,事件中的“操作”字段将设置为“添加”;卸载机器人时,“操作”字段将设置为“删除”。
注意
升级应用程序时,机器人仅接收事件 installationUpdate
以在清单中添加或删除机器人。 对于所有其他情况, installationUpdate
不会触发该事件。 如果添加机器人,则“操作”字段将设置为“添加-升级”;如果删除机器人,则“操作”字段将设置为“删除-升级”。
安装更新事件
使用该 installationUpdate
事件在安装时从机器人发送介绍性消息。 此事件可帮助你满足隐私和数据保留要求。 你还可以在卸载机器人时清理和删除用户或线程数据。
与 conversationUpdate
将机器人添加到团队时发送的事件类似,事件的 conversation.id installationUpdate
设置为用户在应用安装期间选择的通道的 ID,或安装所在的通道的 ID。 ID 表示用户希望机器人作的通道,在发送欢迎消息时机器人必须使用该通道。 对于显式需要常规通道的 ID 的方案,可以从 中channelData
获取它team.id
。
在此示例中,conversation.id
conversationUpdate
和 installationUpdate
活动的 设置为 Daves Demo 团队中响应通道的 ID。
注意
所选频道 ID 仅在将应用安装到团队时发送的添加事件上installationUpdate
设置。
protected override async Task OnInstallationUpdateActivityAsync(ITurnContext<IInstallationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var activity = turnContext.Activity;
if (string.Equals(activity.Action, "Add", StringComparison.InvariantCultureIgnoreCase))
{
// TO:DO Installation workflow.
}
else
{
// TO:DO Uninstallation workflow.
}
return;
}
作为捕获事件的替代方法,你还可以将专用处理程序用于添加或删除场景。
protected override async Task OnInstallationUpdateAddAsync(ITurnContext<IInstallationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
// TO:DO Installation workflow return;
}
async onInstallationUpdateActivity(context: TurnContext) {
var activity = context.activity.action;
if(activity == "Add") {
// Sends an activity to the sender of the incoming activity to add.
await context.sendActivity(MessageFactory.text("Added"));
}
else {
// Sends an activity to the sender of the incoming activity to uninstalled.
await context.sendActivity(MessageFactory.text("Uninstalled"));
}
}
{
{
"type": "installationUpdate",
"id": "f:816eb23d-bfa1-afa3-dfeb-d2aa338e9541",
"timestamp": "2021-11-09T04:47:30.91Z",
"serviceUrl": "https://smba.trafficmanager.net/amer/",
"channelId": "msteams",
"from": {
"id": "29:1ljv6N86roXr5pjPrCJVIz6xHh5QxjI....",
"aadObjectId": "eddfa9d4-346e-4cce-a18f-fa6261ad776b"
},
"recipient": {
"id": "28:608cacfd-1cea-40c9-b678-4b93e69bb72b",
"name": "Test Bot"
},
"locale": "en-US",
"entities": [
{
"type": "clientInfo",
"locale": "en-US"
}
],
"conversation": {
"isGroup": true,
"id": "19:0b7f32667e064dd9b25d7969801541f4@thread.tacv2",
"name": "2021 Test Channel",
"conversationType": "channel",
"tenantId": "b28fdbfd-2b78-4f93-b0f8-8881793f0f8f"
},
"channelData": {
"settings": {
"selectedChannel": {
"id": "19:0b7f32667e064dd9b25d7969801541f4@thread.tacv2"
}
},
"channel": {
"id": "19:0b7f32667e064dd9b25d7969801541f4@thread.tacv2"
},
"team": {
"aadGroupId": "da849743-4259-475f-ae7a-4f4b0fb49943",
"name": "TestTeam2022",
"id": "19:zFLSDFWsesfzcmKArqKJ-65aOXJz@sgf462H2wz41@thread.tacv2"
},
"tenant": {
"id": "b28fdbfd-2b78-4f93-b0f8-8881793f0f8f"
},
"source": {
"name": "message"
}
},
"action": "add"
}
# Override this in a derived class to provide logic specific to InstallationUpdate activities.
async def on_installation_update(self, turn_context: TurnContext):
if turn_context.activity.action == "add":
# Sends an activity to the sender of the incoming activity to add.
await turn_context.send_activity(MessageFactory.text("Added"))
else:
# Sends an activity to the sender of the incoming activity to uninstalled.
await turn_context.send_activity(MessageFactory.text("Uninstalled"))
使用机器人卸载个人应用的行为
卸载应用时,也会卸载机器人。 当用户向应用发送消息时,他们将收到 403 响应代码。 对于由机器人发布的新消息,机器人将收到 403 响应代码。 现在,个人范围内机器人的卸载后行为与团队和群组聊天范围内的行为相一致。 卸载应用后,无法发送或接收消息。
安装和卸载事件的事件处理
使用安装和卸载事件时,在某些情况下,机器人在从 Teams 接收意外事件时会提供异常,这种情况在以下情况下会发生:
- 你没有使用 Microsoft Bot Framework SDK 来构建机器人,因此机器人在收到意外事件时会出现异常。
- 你使用 Microsoft Bot Framework SDK 来构建机器人,并选择通过覆盖基本事件句柄来更改默认事件行为。
请务必知道,将来随时可以添加新事件,并且机器人会开始接收它们。 因此,必须针对接收意外事件的可能性进行设计。 如果使用 Bot Framework SDK,机器人会自动响应 200 - OK,以处理未选择处理的任何事件。
处理对话事件中的错误
当机器人在处理不同的事件或活动时遇到错误时,不要将没有有意义的上下文的消息发送到对话,如以下屏幕截图所示:
在开发阶段,在对话中发送有意义的消息总是很有帮助,这些消息提供有关特定错误的其他详细信息,以便更好地进行调试。 但是,在生产环境中,必须将错误或事件记录到 Azure 应用程序 Insights。 有关详细信息,请参阅 将遥测数据添加到机器人。
代码示例
示例名称 |
说明 |
.NET |
Node.js |
Python |
清单 |
对话机器人 |
此应用演示机器人对话事件,支持自适应卡片、已读回执和消息更新事件。 它包括对辅助功能的沉浸式阅读器支持。 |
View |
View |
View |
View |
后续步骤
另请参阅