Skip to content
This repository was archived by the owner on Jun 30, 2022. It is now read-only.

Commit 0c723d0

Browse files
committed
2 parents 11efb39 + be8c030 commit 0c723d0

File tree

7 files changed

+80
-57
lines changed

7 files changed

+80
-57
lines changed

lib/csharp/microsoft.bot.builder.skills/Microsoft.Bot.Builder.Skills.Tests/Mocks/MockSkillTransport.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using System;
22
using System.Threading.Tasks;
3+
using Microsoft.Bot.Builder.Skills.Auth;
4+
using Microsoft.Bot.Builder.Skills.Models.Manifest;
35
using Microsoft.Bot.Schema;
46

57
namespace Microsoft.Bot.Builder.Skills.Tests.Mocks
@@ -8,7 +10,7 @@ public class MockSkillTransport : ISkillTransport
810
{
911
private Activity _activityForwarded;
1012

11-
public Task CancelRemoteDialogsAsync(ITurnContext turnContext)
13+
public Task CancelRemoteDialogsAsync(SkillManifest skillManifest, IServiceClientCredentials serviceClientCredentials, ITurnContext turnContext)
1214
{
1315
return Task.CompletedTask;
1416
}
@@ -17,7 +19,7 @@ public void Disconnect()
1719
{
1820
}
1921

20-
public Task<bool> ForwardToSkillAsync(ITurnContext dialogContext, Activity activity, Action<Activity> tokenRequestHandler = null)
22+
public Task<bool> ForwardToSkillAsync(SkillManifest skillManifest, IServiceClientCredentials serviceClientCredentials, ITurnContext dialogContext, Activity activity, Action<Activity> tokenRequestHandler = null)
2123
{
2224
_activityForwarded = activity;
2325

lib/csharp/microsoft.bot.builder.skills/Microsoft.Bot.Builder.Skills.Tests/SkillDialogInvocationTests.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System;
2-
using System.Threading.Tasks;
1+
using System.Threading.Tasks;
32
using Microsoft.Bot.Builder.Skills.Auth;
43
using Microsoft.Bot.Builder.Skills.Models.Manifest;
54
using Microsoft.Bot.Builder.Skills.Tests.Mocks;

lib/csharp/microsoft.bot.builder.skills/Microsoft.Bot.Builder.Skills/ISkillTransport.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
using System;
22
using System.Threading.Tasks;
3+
using Microsoft.Bot.Builder.Skills.Auth;
4+
using Microsoft.Bot.Builder.Skills.Models.Manifest;
35
using Microsoft.Bot.Schema;
46

57
namespace Microsoft.Bot.Builder.Skills
68
{
79
public interface ISkillTransport
810
{
9-
Task<bool> ForwardToSkillAsync(ITurnContext dialogContext, Activity activity, Action<Activity> tokenRequestHandler = null);
11+
Task<bool> ForwardToSkillAsync(SkillManifest skillManifest, IServiceClientCredentials serviceClientCredentials, ITurnContext dialogContext, Activity activity, Action<Activity> tokenRequestHandler = null);
1012

11-
Task CancelRemoteDialogsAsync(ITurnContext turnContext);
13+
Task CancelRemoteDialogsAsync(SkillManifest skillManifest, IServiceClientCredentials serviceClientCredentials, ITurnContext turnContext);
1214

1315
void Disconnect();
1416
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Microsoft.Bot.Builder.Skills
2+
{
3+
public class SkillConstants
4+
{
5+
public const string SkillStart = "start";
6+
public const string SkillContinue = "continue";
7+
public const string SkillDone = "done";
8+
}
9+
}

lib/csharp/microsoft.bot.builder.skills/Microsoft.Bot.Builder.Skills/SkillDialog.cs

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public SkillDialog(
5252
_serviceClientCredentials = serviceClientCredentials ?? throw new ArgumentNullException(nameof(serviceClientCredentials));
5353
_telemetryClient = telemetryClient ?? throw new ArgumentNullException(nameof(telemetryClient));
5454
_userState = userState;
55-
_skillTransport = skillTransport ?? new SkillWebSocketTransport(_skillManifest, _serviceClientCredentials, telemetryClient);
55+
_skillTransport = skillTransport ?? new SkillWebSocketTransport(telemetryClient);
5656

5757
if (authDialog != null)
5858
{
@@ -69,7 +69,7 @@ public override async Task EndDialogAsync(ITurnContext turnContext, DialogInstan
6969
// to cancel all dialogs on the skill side
7070
if (_skillTransport != null)
7171
{
72-
await _skillTransport.CancelRemoteDialogsAsync(turnContext);
72+
await _skillTransport.CancelRemoteDialogsAsync(_skillManifest, _serviceClientCredentials, turnContext);
7373
}
7474
}
7575

@@ -91,55 +91,65 @@ public override async Task EndDialogAsync(ITurnContext turnContext, DialogInstan
9191
var accessor = _userState.CreateProperty<SkillContext>(nameof(SkillContext));
9292
var skillContext = await accessor.GetAsync(innerDc.Context, () => new SkillContext());
9393

94-
/* In instances where the caller is able to identify/specify the action we process the Action specific slots
95-
In other scenarios (aggregated skill dispatch) we evaluate all possible slots against context and pass across
96-
enabling the Skill to perform it's own action identification. */
94+
var dialogOptions = options != null ? options as SkillDialogOption : null;
95+
var actionName = dialogOptions?.Action;
9796

98-
var actionName = options != null ? options as string : null;
99-
if (actionName != null)
97+
var activity = innerDc.Context.Activity;
98+
99+
// only set SemanticAction if it's not populated
100+
if (activity.SemanticAction == null)
100101
{
101-
// Find the specified within the selected Skill for slot filling evaluation
102-
var action = _skillManifest.Actions.SingleOrDefault(a => a.Id == actionName);
103-
if (action != null)
102+
var semanticAction = new SemanticAction
104103
{
105-
// If the action doesn't define any Slots or SkillContext is empty then we skip slot evaluation
106-
if (action.Definition.Slots != null && skillContext.Count > 0)
104+
Id = actionName,
105+
Entities = new Dictionary<string, Entity>(),
106+
};
107+
108+
if (!string.IsNullOrWhiteSpace(actionName))
109+
{
110+
// only set the semantic state if action is not empty
111+
semanticAction.State = SkillConstants.SkillStart;
112+
113+
// Find the specified action within the selected Skill for slot filling evaluation
114+
var action = _skillManifest.Actions.SingleOrDefault(a => a.Id == actionName);
115+
if (action != null)
107116
{
108-
// Match Slots to Skill Context
109-
slots = await MatchSkillContextToSlots(innerDc, action.Definition.Slots, skillContext);
117+
// If the action doesn't define any Slots or SkillContext is empty then we skip slot evaluation
118+
if (action.Definition.Slots != null && skillContext.Count > 0)
119+
{
120+
// Match Slots to Skill Context
121+
slots = await MatchSkillContextToSlots(innerDc, action.Definition.Slots, skillContext);
122+
}
123+
}
124+
else
125+
{
126+
throw new ArgumentException($"Passed Action ({actionName}) could not be found within the {_skillManifest.Id} skill manifest action definition.");
110127
}
111128
}
112129
else
113130
{
114-
throw new ArgumentException($"Passed Action ({actionName}) could not be found within the {_skillManifest.Id} skill manifest action definition.");
131+
// The caller hasn't got the capability of identifying the action as well as the Skill so we enumerate
132+
// actions and slot data to pass what we have
133+
134+
// Retrieve a distinct list of all slots, some actions may use the same slot so we use distinct to ensure we only get 1 instance.
135+
var skillSlots = _skillManifest.Actions.SelectMany(s => s.Definition.Slots).Distinct(new SlotEqualityComparer());
136+
if (skillSlots != null)
137+
{
138+
// Match Slots to Skill Context
139+
slots = await MatchSkillContextToSlots(innerDc, skillSlots.ToList(), skillContext);
140+
}
115141
}
116-
}
117-
else
118-
{
119-
// The caller hasn't got the capability of identifying the action as well as the Skill so we enumerate
120-
// actions and slot data to pass what we have
121142

122-
// Retrieve a distinct list of all slots, some actions may use the same slot so we use distinct to ensure we only get 1 instance.
123-
var skillSlots = _skillManifest.Actions.SelectMany(s => s.Definition.Slots).Distinct(new SlotEqualityComparer());
124-
if (skillSlots != null)
143+
foreach (var slot in slots)
125144
{
126-
// Match Slots to Skill Context
127-
slots = await MatchSkillContextToSlots(innerDc, skillSlots.ToList(), skillContext);
145+
semanticAction.Entities.Add(slot.Key, new Entity { Properties = slot.Value });
128146
}
147+
148+
activity.SemanticAction = semanticAction;
129149
}
130150

131151
await innerDc.Context.SendActivityAsync(new Activity(type: ActivityTypes.Trace, text: $"-->Handing off to the {_skillManifest.Name} skill."));
132152

133-
var activity = innerDc.Context.Activity;
134-
var semanticAction = new SemanticAction { Entities = new Dictionary<string, Entity>() };
135-
136-
foreach (var slot in slots)
137-
{
138-
semanticAction.Entities.Add(slot.Key, new Entity { Properties = slot.Value });
139-
}
140-
141-
activity.SemanticAction = semanticAction;
142-
143153
return await ForwardToSkillAsync(innerDc, activity);
144154
}
145155

@@ -215,7 +225,7 @@ private async Task<DialogTurnResult> ForwardToSkillAsync(DialogContext innerDc,
215225
{
216226
try
217227
{
218-
var endOfConversation = await _skillTransport.ForwardToSkillAsync(innerDc.Context, activity, GetTokenRequestCallback(innerDc));
228+
var endOfConversation = await _skillTransport.ForwardToSkillAsync(_skillManifest, _serviceClientCredentials, innerDc.Context, activity, GetTokenRequestCallback(innerDc));
219229

220230
if (endOfConversation)
221231
{
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Microsoft.Bot.Builder.Skills
2+
{
3+
public class SkillDialogOption
4+
{
5+
public string Action { get; set; }
6+
}
7+
}

lib/csharp/microsoft.bot.builder.skills/Microsoft.Bot.Builder.Skills/SkillWebSocketTransport.cs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,51 +18,45 @@ namespace Microsoft.Bot.Builder.Skills
1818
public class SkillWebSocketTransport : ISkillTransport
1919
{
2020
private IStreamingTransportClient _streamingTransportClient;
21-
private readonly SkillManifest _skillManifest;
22-
private readonly IServiceClientCredentials _serviceClientCredentials;
2321
private readonly IBotTelemetryClient _botTelemetryClient;
2422
private bool endOfConversation = false;
2523

2624
public SkillWebSocketTransport(
27-
SkillManifest skillManifest,
28-
IServiceClientCredentials serviceCLientCredentials,
2925
IBotTelemetryClient botTelemetryClient,
3026
IStreamingTransportClient streamingTransportClient = null)
3127
{
32-
_skillManifest = skillManifest ?? throw new ArgumentNullException(nameof(skillManifest));
33-
_serviceClientCredentials = serviceCLientCredentials ?? throw new ArgumentNullException(nameof(serviceCLientCredentials));
3428
_botTelemetryClient = botTelemetryClient;
3529
_streamingTransportClient = streamingTransportClient;
3630
}
3731

38-
public async Task<bool> ForwardToSkillAsync(ITurnContext turnContext, Activity activity, Action<Activity> tokenRequestHandler = null)
32+
public async Task<bool> ForwardToSkillAsync(SkillManifest skillManifest, IServiceClientCredentials serviceClientCredentials, ITurnContext turnContext, Activity activity, Action<Activity> tokenRequestHandler = null)
3933
{
4034
if (_streamingTransportClient == null)
4135
{
4236
// acquire AAD token
43-
MicrosoftAppCredentials.TrustServiceUrl(_skillManifest.Endpoint.AbsoluteUri);
44-
var token = await _serviceClientCredentials.GetTokenAsync();
37+
MicrosoftAppCredentials.TrustServiceUrl(skillManifest.Endpoint.AbsoluteUri);
38+
var token = await serviceClientCredentials.GetTokenAsync();
4539

4640
// put AAD token in the header
4741
var headers = new Dictionary<string, string>();
4842
headers.Add("Authorization", $"Bearer {token}");
4943

5044
// establish websocket connection
5145
_streamingTransportClient = new WebSocketClient(
52-
EnsureWebSocketUrl(_skillManifest.Endpoint.ToString()),
46+
EnsureWebSocketUrl(skillManifest.Endpoint.ToString()),
5347
new SkillCallingRequestHandler(
5448
turnContext,
5549
_botTelemetryClient,
5650
GetTokenCallback(turnContext, tokenRequestHandler),
5751
GetHandoffActivityCallback()),
5852
headers);
59-
60-
await _streamingTransportClient.ConnectAsync();
6153
}
6254

55+
await _streamingTransportClient.ConnectAsync();
56+
6357
// set recipient to the skill
6458
var recipientId = activity.Recipient.Id;
65-
activity.Recipient.Id = _skillManifest.MSAappId;
59+
activity.Recipient.Id = skillManifest.MSAappId;
6660

6761
// Serialize the activity and POST to the Skill endpoint
6862
var body = new StringContent(JsonConvert.SerializeObject(activity, SerializationSettings.BotSchemaSerializationSettings), Encoding.UTF8, SerializationSettings.ApplicationJson);
@@ -76,14 +70,14 @@ public async Task<bool> ForwardToSkillAsync(ITurnContext turnContext, Activity a
7670
return endOfConversation;
7771
}
7872

79-
public async Task CancelRemoteDialogsAsync(ITurnContext turnContext)
73+
public async Task CancelRemoteDialogsAsync(SkillManifest skillManifest, IServiceClientCredentials appCredentials, ITurnContext turnContext)
8074
{
8175
var cancelRemoteDialogEvent = turnContext.Activity.CreateReply();
8276

8377
cancelRemoteDialogEvent.Type = ActivityTypes.Event;
8478
cancelRemoteDialogEvent.Name = SkillEvents.CancelAllSkillDialogsEventName;
8579

86-
await ForwardToSkillAsync(turnContext, cancelRemoteDialogEvent);
80+
await ForwardToSkillAsync(skillManifest, appCredentials, turnContext, cancelRemoteDialogEvent);
8781
}
8882

8983
public void Disconnect()

0 commit comments

Comments
 (0)