A képességek segítségével kiterjeszthet egy másik robotot.
A képesség olyan robot, amely egy másik robot számára képes feladatokat végrehajtani.
A jegyzék egy képesség felületét írja le. Azok a fejlesztők, akik nem férnek hozzá a képesség forráskódjába, használhatják a jegyzékben szereplő információkat a képességfelhasználó tervezéséhez.
A szakértelem jogcímérvényesítéssel kezelheti, hogy mely robotok vagy felhasználók férhetnek hozzá.
Ez a cikk bemutatja, hogyan valósíthat meg olyan készséget, amely tükrözi a felhasználó bemenetét.
Bizonyos típusú készségfelhasználók nem tudnak bizonyos típusú képességrobotokat használni.
Az alábbi táblázat ismerteti, hogy mely kombinációk támogatottak.
Több-bérlős képesség
Egybérlős képesség
Felhasználó által hozzárendelt felügyelt identitástudás
Több-bérlős fogyasztó
Támogatott
Nem támogatott
Nem támogatott
Egybérlős fogyasztó
Nem támogatott
Támogatott, ha mindkét alkalmazás ugyanahhoz a bérlőhöz tartozik
Támogatott, ha mindkét alkalmazás ugyanahhoz a bérlőhöz tartozik
Felhasználó által hozzárendelt felügyelt identitásfelhasználó
Nem támogatott
Támogatott, ha mindkét alkalmazás ugyanahhoz a bérlőhöz tartozik
Támogatott, ha mindkét alkalmazás ugyanahhoz a bérlőhöz tartozik
Feljegyzés
A Bot Framework JavaScript, C# és Python SDK-k továbbra is támogatottak lesznek, a Java SDK-t azonban 2023 novemberében végső hosszú távú támogatással kivonják.
A Java SDK-val létrehozott meglévő robotok továbbra is működni fognak.
Az új robotépítéshez fontolja meg a Microsoft Copilot Studio használatát, és olvassa el a megfelelő copilot-megoldás kiválasztását.
Azure-előfizetés (a képesség üzembe helyezéséhez). Ha még nincs előfizetése, hozzon létre egy ingyenes fiókot, mielőtt hozzákezd.
A C#, JavaScript, Java vagy Python nyelven készült egyszerű robot-robot mintapéldány másolata.
Feljegyzés
A 4.11-es verziótól kezdve nincs szükség alkalmazásazonosítóra és jelszóra egy képesség helyi teszteléséhez a Bot Framework Emulatorban. A képesség Azure-beli üzembe helyezéséhez továbbra is Azure-előfizetésre van szükség.
A minta ismertetése
Az egyszerű robot-robot minta két robothoz tartozó projekteket tartalmaz:
Az echo skill robot, amely megvalósítja a képességet.
Az egyszerű gyökérrobot, amely implementál egy gyökérrobotot, amely felhasználja a képességet.
Ez a cikk a képességre összpontosít, amely magában foglalja a támogatási logikát a robotban és az adapterben.
Az egyszerű gyökérrobottal kapcsolatos információkért tekintse meg, hogyan implementálhat készségfelhasználót.
Források
Az üzembe helyezett robotok esetében a robotok között történő hitelesítéshez minden résztvevő robotnak érvényes identitásadatokra van szüksége.
Az Emulator használatával azonban helyileg tesztelheti a több-bérlős készségeket és készségeket, alkalmazásazonosító és jelszó nélkül.
Szükség esetén adja hozzá a képesség identitásadatait a konfigurációs fájlhoz. Ha a képesség- vagy képességfelhasználó identitásadatokat ad meg, mindkettőnek meg kell lennie.
Az engedélyezett hívótömbök korlátozhatják , hogy mely képességfelhasználók férhetnek hozzá a képességhez.
Ha bármilyen készségfelhasználó hívásait szeretné fogadni, adjon hozzá egy "*" elemet.
Feljegyzés
Ha helyileg, robotidentitás-adatok nélkül teszteli a készségeit, sem a készségfelhasználó nem futtatja a kódot a jogcímek érvényesítéséhez.
Igény szerint adja hozzá a képesség identitásadatait a appsettings.json fájlhoz.
{
"MicrosoftAppType": "",
"MicrosoftAppId": "",
"MicrosoftAppPassword": "",
"MicrosoftAppTenantId": "",
// This is a comma separate list with the App IDs that will have access to the skill.
// This setting is used in AllowedCallersClaimsValidator.
// Examples:
// [ "*" ] allows all callers.
// [ "AppId1", "AppId2" ] only allows access to parent bots with "AppId1" and "AppId2".
"AllowedCallers": [ "*" ]
}
echo-skill-bot/.env
Ha szükséges, adja hozzá a képesség identitásadatait az .env fájlhoz.
Szükség esetén adja hozzá a képesség alkalmazásazonosítóját és jelszavát az application.properties fájlhoz.
MicrosoftAppId=
MicrosoftAppPassword=
server.port=39783
# This is a comma separate list with the App IDs that will have access to the skill.
# This setting is used in AllowedCallersClaimsValidator.
# Examples:
# * allows all callers.
# AppId1,AppId2 only allows access to parent bots with "AppId1" and "AppId2".
AllowedCallers=*
Szükség esetén adja hozzá a képesség alkalmazásazonosítóját és jelszavát a config.py fájlhoz.
config.py
APP_ID = os.environ.get("MicrosoftAppId", "")
APP_PASSWORD = os.environ.get("MicrosoftAppPassword", "")
APP_TYPE = os.environ.get("MicrosoftAppType", "MultiTenant")
APP_TENANTID = os.environ.get("MicrosoftAppTenantId", "")
# Callers to only those specified, '*' allows any caller.
Tevékenységkezelő logika
Bemeneti paraméterek elfogadása
A képességfelhasználó adatokat küldhet a képességnek. Az ilyen információk elfogadásának egyik módja az, ha a bejövő üzenetek értéktulajdonságán keresztül fogadják el őket. Egy másik módszer az események kezelése és a tevékenységek meghívása.
A példában szereplő képesség nem fogadja el a bemeneti paramétereket.
Beszélgetés folytatása vagy befejezése
Amikor a képesség egy tevékenységet küld, a képességfelhasználónak tovább kell küldenie a tevékenységet a felhasználónak.
A képesség befejeződésekor azonban el kell küldenie egy endOfConversation tevékenységet, ellenkező esetben a képességfelhasználó továbbra is továbbítja a felhasználói tevékenységeket a képességnek.
Ha szeretné, a tevékenység értéktulajdonságával adjon meg egy visszatérési értéket, és a tevékenység kódtulajdonságávaljelezze, hogy miért fejeződik be a képesség.
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
if (turnContext.Activity.Text.Contains("end") || turnContext.Activity.Text.Contains("stop"))
{
// Send End of conversation at the end.
var messageText = $"ending conversation from the skill...";
await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput), cancellationToken);
var endOfConversation = Activity.CreateEndOfConversationActivity();
endOfConversation.Code = EndOfConversationCodes.CompletedSuccessfully;
await turnContext.SendActivityAsync(endOfConversation, cancellationToken);
}
else
{
var messageText = $"Echo: {turnContext.Activity.Text}";
await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.IgnoringInput), cancellationToken);
messageText = "Say \"end\" or \"stop\" and I'll end the conversation and back to the parent.";
await turnContext.SendActivityAsync(MessageFactory.Text(messageText, messageText, InputHints.ExpectingInput), cancellationToken);
}
}
echo-skill-bot/bot.js
this.onMessage(async (context, next) => {
switch (context.activity.text.toLowerCase()) {
case 'end':
case 'stop':
await context.sendActivity({
type: ActivityTypes.EndOfConversation,
code: EndOfConversationCodes.CompletedSuccessfully
});
break;
default:
await context.sendActivity(`Echo (JS) : '${ context.activity.text }'`);
await context.sendActivity('Say "end" or "stop" and I\'ll end the conversation and back to the parent.');
}
// By calling next() you ensure that the next BotHandler is run.
await next();
});
echoSkillBot\EchoBot.java
protected CompletableFuture<Void> onMessageActivity(TurnContext turnContext) {
if (
turnContext.getActivity().getText().contains("end") || turnContext.getActivity().getText().contains("stop")
) {
String messageText = "ending conversation from the skill...";
return turnContext.sendActivity(MessageFactory.text(messageText, messageText, InputHints.IGNORING_INPUT))
.thenApply(result -> {
Activity endOfConversation = Activity.createEndOfConversationActivity();
endOfConversation.setCode(EndOfConversationCodes.COMPLETED_SUCCESSFULLY);
return turnContext.sendActivity(endOfConversation);
})
.thenApply(finalResult -> null);
} else {
String messageText = String.format("Echo: %s", turnContext.getActivity().getText());
return turnContext.sendActivity(MessageFactory.text(messageText, messageText, InputHints.IGNORING_INPUT))
.thenApply(result -> {
String nextMessageText =
"Say \"end\" or \"stop\" and I'll end the conversation and back to the parent.";
return turnContext.sendActivity(
MessageFactory.text(nextMessageText, nextMessageText, InputHints.EXPECTING_INPUT)
);
})
.thenApply(result -> null);
}
}
echo-skill-bot/bots/echo_bot.py
async def on_message_activity(self, turn_context: TurnContext):
if "end" in turn_context.activity.text or "stop" in turn_context.activity.text:
# Send End of conversation at the end.
await turn_context.send_activity(
MessageFactory.text("Ending conversation from the skill...")
)
end_of_conversation = Activity(type=ActivityTypes.end_of_conversation)
end_of_conversation.code = EndOfConversationCodes.completed_successfully
await turn_context.send_activity(end_of_conversation)
else:
await turn_context.send_activity(
MessageFactory.text(f"Echo (python): {turn_context.activity.text}")
)
await turn_context.send_activity(
MessageFactory.text(
f'Say "end" or "stop" and I\'ll end the conversation and back to the parent.'
)
)
A képesség megszakítása
Többfordulós készségek esetén a készségfelhasználó tevékenységeit is elfogadná endOfConversation , hogy a fogyasztó megszakíthassa az aktuális beszélgetést.
Ennek a képességnek a logikája nem változik átfordulásról fordulóra. Ha olyan készséget valósít meg, amely beszélgetési erőforrásokat foglal le, adjon hozzá erőforrás-törlési kódot a beszélgetés vége kezelőhöz.
protected override Task OnEndOfConversationActivityAsync(ITurnContext<IEndOfConversationActivity> turnContext, CancellationToken cancellationToken)
{
// This will be called if the root bot is ending the conversation. Sending additional messages should be
// avoided as the conversation may have been deleted.
// Perform cleanup of resources if needed.
return Task.CompletedTask;
}
echo-skill-bot/bot.js
Ezzel a onUnrecognizedActivityType módszerrel adhat hozzá egy beszélgetés végi logikát. A kezelőben ellenőrizze, hogy a felismeretlen tevékenység type egyenlő-e endOfConversation.
this.onEndOfConversation(async (context, next) => {
// This will be called if the root bot is ending the conversation. Sending additional messages should be
// avoided as the conversation may have been deleted.
// Perform cleanup of resources if needed.
// By calling next() you ensure that the next BotHandler is run.
await next();
});
echoSkillBot\EchoBot.java
protected CompletableFuture<Void> onEndOfConversationActivity(TurnContext turnContext) {
// This will be called if the root bot is ending the conversation. Sending
// additional messages should be
// avoided as the conversation may have been deleted.
// Perform cleanup of resources if needed.
return CompletableFuture.completedFuture(null);
}
echo-skill-bot/bots/echo_bot.py
async def on_end_of_conversation_activity(self, turn_context: TurnContext):
# This will be called if the root bot is ending the conversation. Sending additional messages should be
# avoided as the conversation may have been deleted.
# Perform cleanup of resources if needed.
pass
Jogcím-érvényesítő
Ez a minta egy engedélyezett hívólistát használ a jogcímek érvényesítéséhez. A képesség konfigurációs fájlja határozza meg a listát. Az érvényesítő objektum ezután felolvassa a listát.
A hitelesítési konfigurációhoz hozzá kell adnia egy jogcím-érvényesítőt . A jogcímek kiértékelése a hitelesítési fejléc után történik. Az érvényesítési kódnak hibát vagy kivételt kell küldenie a kérés elutasításához. Az egyébként hitelesített kérések elutasításának számos oka lehet. Példa:
A képesség egy fizetős szolgáltatás része. Az adatbázisban nem szereplő felhasználónak nem szabad hozzáféréssel rendelkeznie.
A képesség védett. Csak bizonyos készségfelhasználók hívhatják meg a képességet.
Fontos
Ha nem ad meg jogcím-érvényesítőt, a robot hibaüzenetet vagy kivételt fog generálni, amikor egy tevékenységet kap a készségfelhasználótól.
Az SDK egy olyan osztályt AllowedCallersClaimsValidator biztosít, amely alkalmazásszintű engedélyezést ad hozzá azoknak az alkalmazásoknak az egyszerű azonosítói alapján, amelyek meghívhatják a készséget. Ha a lista csillagot (*) tartalmaz, akkor minden hívó engedélyezett. A jogcím-érvényesítő Startup.cs van konfigurálva.
Az SDK egy olyan osztályt allowedCallersClaimsValidator biztosít, amely alkalmazásszintű engedélyezést ad hozzá azoknak az alkalmazásoknak az egyszerű azonosítói alapján, amelyek meghívhatják a készséget. Ha a lista csillagot (*) tartalmaz, akkor minden hívó engedélyezett. A jogcím-érvényesítő index.js van konfigurálva.
Az SDK egy olyan osztályt AllowedCallersClaimsValidator biztosít, amely alkalmazásszintű engedélyezést ad hozzá azoknak az alkalmazásoknak az egyszerű azonosítói alapján, amelyek meghívhatják a készséget. Ha a lista csillagot (*) tartalmaz, akkor minden hívó engedélyezett. A jogcím-érvényesítő Application.java van konfigurálva.
Adjon meg egy jogcímérvényesítési módszert, amely hibát jelez a bejövő kérések elutasításához.
class AllowedCallersClaimsValidator:
config_key = "ALLOWED_CALLERS"
def __init__(self, config: DefaultConfig):
if not config:
raise TypeError(
"AllowedCallersClaimsValidator: config object cannot be None."
)
# ALLOWED_CALLERS is the setting in config.py file
# that consists of the list of parent bot ids that are allowed to access the skill
# to add a new parent bot simply go to the AllowedCallers and add
# the parent bot's microsoft app id to the list
caller_list = getattr(config, self.config_key)
if caller_list is None:
raise TypeError(f'"{self.config_key}" not found in configuration.')
self._allowed_callers = frozenset(caller_list)
@property
def claims_validator(self) -> Callable[[List[Dict]], Awaitable]:
async def allow_callers_claims_validator(claims: Dict[str, object]):
# if allowed_callers is None we allow all calls
if "*" not in self._allowed_callers and SkillValidation.is_skill_claim(
claims
):
# Check that the appId claim in the skill request is in the list of skills configured for this bot.
app_id = JwtTokenValidation.get_app_id_from_claims(claims)
if app_id not in self._allowed_callers:
raise PermissionError(
f'Received a request from a bot with an app ID of "{app_id}".'
f" To enable requests from this caller, add the app ID to your configuration file."
)
return
return allow_callers_claims_validator
Képességadapter
Hiba esetén a képesség adapterének törölnie kell a készség beszélgetési állapotát, és egy tevékenységet is el kell küldenie endOfConversation a készségfelhasználónak. Annak jelzésére, hogy a képesség hiba miatt véget ért, használja a tevékenység kódtulajdonságát .
private async Task HandleTurnError(ITurnContext turnContext, Exception exception)
{
// Log any leaked exception from the application.
_logger.LogError(exception, $"[OnTurnError] unhandled error : {exception.Message}");
await SendErrorMessageAsync(turnContext, exception);
await SendEoCToParentAsync(turnContext, exception);
}
private async Task SendErrorMessageAsync(ITurnContext turnContext, Exception exception)
{
try
{
// Send a message to the user.
var errorMessageText = "The skill encountered an error or bug.";
var errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.IgnoringInput);
await turnContext.SendActivityAsync(errorMessage);
errorMessageText = "To continue to run this bot, please fix the bot source code.";
errorMessage = MessageFactory.Text(errorMessageText, errorMessageText, InputHints.ExpectingInput);
await turnContext.SendActivityAsync(errorMessage);
// Send a trace activity, which will be displayed in the Bot Framework Emulator.
// Note: we return the entire exception in the value property to help the developer;
// this should not be done in production.
await turnContext.TraceActivityAsync("OnTurnError Trace", exception.ToString(), "https://www.botframework.com/schemas/error", "TurnError");
}
catch (Exception ex)
{
_logger.LogError(ex, $"Exception caught in SendErrorMessageAsync : {ex}");
}
}
private async Task SendEoCToParentAsync(ITurnContext turnContext, Exception exception)
{
try
{
// Send an EndOfConversation activity to the skill caller with the error to end the conversation,
// and let the caller decide what to do.
var endOfConversation = Activity.CreateEndOfConversationActivity();
endOfConversation.Code = "SkillError";
endOfConversation.Text = exception.Message;
await turnContext.SendActivityAsync(endOfConversation);
}
catch (Exception ex)
{
_logger.LogError(ex, $"Exception caught in SendEoCToParentAsync : {ex}");
}
}
echo-skill-bot/index.js
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to the console log, instead of to app insights.
// NOTE: In a production environment, you should consider logging this to Azure
// application insights.
console.error(`\n [onTurnError] unhandled error: ${ error }`);
await sendErrorMessage(context, error);
await sendEoCToParent(context, error);
};
async function sendErrorMessage(context, error) {
try {
// Send a message to the user.
let onTurnErrorMessage = 'The skill encountered an error or bug.';
await context.sendActivity(onTurnErrorMessage, onTurnErrorMessage, InputHints.ExpectingInput);
onTurnErrorMessage = 'To continue to run this bot, please fix the bot source code.';
await context.sendActivity(onTurnErrorMessage, onTurnErrorMessage, InputHints.ExpectingInput);
// Send a trace activity, which will be displayed in the Bot Framework Emulator.
// Note: we return the entire exception in the value property to help the developer;
// this should not be done in production.
await context.sendTraceActivity('OnTurnError Trace', error.toString(), 'https://www.botframework.com/schemas/error', 'TurnError');
} catch (err) {
console.error(`\n [onTurnError] Exception caught in sendErrorMessage: ${ err }`);
}
}
async function sendEoCToParent(context, error) {
try {
// Send an EndOfConversation activity to the skill caller with the error to end the conversation,
// and let the caller decide what to do.
const endOfConversation = {
type: ActivityTypes.EndOfConversation,
code: 'SkillError',
text: error.toString()
};
await context.sendActivity(endOfConversation);
} catch (err) {
console.error(`\n [onTurnError] Exception caught in sendEoCToParent: ${ err }`);
}
}
echoSkillBot\SkillAdapterWithErrorHandler.java
public SkillAdapterWithErrorHandler(
Configuration configuration,
AuthenticationConfiguration authenticationConfiguration
) {
super(configuration, authenticationConfiguration);
setOnTurnError(new SkillAdapterErrorHandler());
}
private class SkillAdapterErrorHandler implements OnTurnErrorHandler {
@Override
public CompletableFuture<Void> invoke(TurnContext turnContext, Throwable exception) {
return sendErrorMessage(turnContext, exception).thenAccept(result -> {
sendEoCToParent(turnContext, exception);
});
}
private CompletableFuture<Void> sendErrorMessage(TurnContext turnContext, Throwable exception) {
try {
// Send a message to the user.
String errorMessageText = "The skill encountered an error or bug.";
Activity errorMessage =
MessageFactory.text(errorMessageText, errorMessageText, InputHints.IGNORING_INPUT);
return turnContext.sendActivity(errorMessage).thenAccept(result -> {
String secondLineMessageText = "To continue to run this bot, please fix the bot source code.";
Activity secondErrorMessage =
MessageFactory.text(secondLineMessageText, secondLineMessageText, InputHints.EXPECTING_INPUT);
turnContext.sendActivity(secondErrorMessage)
.thenApply(
sendResult -> {
// Send a trace activity, which will be displayed in the Bot Framework Emulator.
// Note: we return the entire exception in the value property to help the
// developer;
// this should not be done in production.
return TurnContext.traceActivity(
turnContext,
String.format("OnTurnError Trace %s", exception.toString())
);
}
);
});
} catch (Exception ex) {
return Async.completeExceptionally(ex);
}
}
private CompletableFuture<Void> sendEoCToParent(TurnContext turnContext, Throwable exception) {
try {
// Send an EndOfConversation activity to the skill caller with the error to end
// the conversation,
// and let the caller decide what to do.
Activity endOfConversation = Activity.createEndOfConversationActivity();
endOfConversation.setCode(EndOfConversationCodes.SKILL_ERROR);
endOfConversation.setText(exception.getMessage());
return turnContext.sendActivity(endOfConversation).thenApply(result -> null);
} catch (Exception ex) {
return Async.completeExceptionally(ex);
}
}
}
echo-skill-bot/adapter_with_error_handler.py
# This check writes out errors to console log
# NOTE: In production environment, you should consider logging this to Azure
# application insights.
print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr)
traceback.print_exc()
await self._send_error_message(turn_context, error)
await self._send_eoc_to_parent(turn_context, error)
async def _send_error_message(self, turn_context: TurnContext, error: Exception):
try:
# Send a message to the user.
error_message_text = "The skill encountered an error or bug."
error_message = MessageFactory.text(
error_message_text, error_message_text, InputHints.ignoring_input
)
await turn_context.send_activity(error_message)
error_message_text = (
"To continue to run this bot, please fix the bot source code."
)
error_message = MessageFactory.text(
error_message_text, error_message_text, InputHints.ignoring_input
)
await turn_context.send_activity(error_message)
# Send a trace activity, which will be displayed in Bot Framework Emulator.
await turn_context.send_trace_activity(
label="TurnError",
name="on_turn_error Trace",
value=f"{error}",
value_type="https://www.botframework.com/schemas/error",
)
except Exception as exception:
print(
f"\n Exception caught on _send_error_message : {exception}",
file=sys.stderr,
)
traceback.print_exc()
async def _send_eoc_to_parent(self, turn_context: TurnContext, error: Exception):
try:
# Send an EndOfConversation activity to the skill caller with the error to end the conversation,
# and let the caller decide what to do.
end_of_conversation = Activity(type=ActivityTypes.end_of_conversation)
end_of_conversation.code = "SkillError"
end_of_conversation.text = str(error)
await turn_context.send_activity(end_of_conversation)
except Exception as exception:
print(
f"\n Exception caught on _send_eoc_to_parent : {exception}",
file=sys.stderr,
)
traceback.print_exc()
Szolgáltatásregisztráció
A Bot Framework-adapter egy hitelesítési konfigurációs objektummal (az adapter létrehozásakor van beállítva) ellenőrzi a hitelesítési fejlécet a bejövő kéréseken.
Ez a minta jogcímérvényesítést ad hozzá a hitelesítési konfigurációhoz, és az előző szakaszban ismertetett hibakezelővel rendelkező képességadaptert használja.
options.SerializerSettings.MaxDepth = HttpHelper.BotMessageSerializerSettings.MaxDepth;
});
// Register AuthConfiguration to enable custom claim validation.
services.AddSingleton(sp =>
{
var allowedCallers = new List<string>(sp.GetService<IConfiguration>().GetSection("AllowedCallers").Get<string[]>());
var claimsValidator = new AllowedCallersClaimsValidator(allowedCallers);
// If TenantId is specified in config, add the tenant as a valid JWT token issuer for Bot to Skill conversation.
// The token issuer for MSI and single tenant scenarios will be the tenant where the bot is registered.
var validTokenIssuers = new List<string>();
var tenantId = sp.GetService<IConfiguration>().GetSection(MicrosoftAppCredentials.MicrosoftAppTenantIdKey)?.Value;
if (!string.IsNullOrWhiteSpace(tenantId))
{
// For SingleTenant/MSI auth, the JWT tokens will be issued from the bot's home tenant.
// Therefore, these issuers need to be added to the list of valid token issuers for authenticating activity requests.
validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV1, tenantId));
validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV2, tenantId));
validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV1, tenantId));
validTokenIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV2, tenantId));
}
return new AuthenticationConfiguration
{
ClaimsValidator = claimsValidator,
ValidTokenIssuers = validTokenIssuers
};
});
// Create the Bot Framework Authentication to be used with the Bot Adapter.
services.AddSingleton<BotFrameworkAuthentication, ConfigurationBotFrameworkAuthentication>();
echo-skill-bot/index.js
const allowedCallers = (process.env.AllowedCallers || '').split(',').filter((val) => val) || [];
const claimsValidators = allowedCallersClaimsValidator(allowedCallers);
// If the MicrosoftAppTenantId is specified in the environment config, add the tenant as a valid JWT token issuer for Bot to Skill conversation.
// The token issuer for MSI and single tenant scenarios will be the tenant where the bot is registered.
let validTokenIssuers = [];
const { MicrosoftAppTenantId } = process.env;
if (MicrosoftAppTenantId) {
// For SingleTenant/MSI auth, the JWT tokens will be issued from the bot's home tenant.
// Therefore, these issuers need to be added to the list of valid token issuers for authenticating activity requests.
validTokenIssuers = [
`${ AuthenticationConstants.ValidTokenIssuerUrlTemplateV1 }${ MicrosoftAppTenantId }/`,
`${ AuthenticationConstants.ValidTokenIssuerUrlTemplateV2 }${ MicrosoftAppTenantId }/v2.0/`,
`${ AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV1 }${ MicrosoftAppTenantId }/`,
`${ AuthenticationConstants.ValidGovernmentTokenIssuerUrlTemplateV2 }${ MicrosoftAppTenantId }/v2.0/`
];
}
// Define our authentication configuration.
const authConfig = new AuthenticationConfiguration([], claimsValidators, validTokenIssuers);
const credentialsFactory = new ConfigurationServiceClientCredentialFactory({
MicrosoftAppId: process.env.MicrosoftAppId,
MicrosoftAppPassword: process.env.MicrosoftAppPassword,
MicrosoftAppType: process.env.MicrosoftAppType,
MicrosoftAppTenantId: process.env.MicrosoftAppTenantId
});
const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(process.env, credentialsFactory, authConfig);
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about how bots work.
const adapter = new CloudAdapter(botFrameworkAuthentication);
echoSkillBot\Application.java
@Override
public AuthenticationConfiguration getAuthenticationConfiguration(Configuration configuration) {
AuthenticationConfiguration authenticationConfiguration = new AuthenticationConfiguration();
authenticationConfiguration.setClaimsValidator(
new AllowedCallersClaimsValidator(Arrays.asList(configuration.getProperties(configKey)))
);
return authenticationConfiguration;
}
echo-skill-bot/app.py
CLAIMS_VALIDATOR = AllowedCallersClaimsValidator(CONFIG)
AUTH_CONFIG = AuthenticationConfiguration(
claims_validator=CLAIMS_VALIDATOR.claims_validator
)
# Create adapter.
# See https://aka.ms/about-bot-adapter to learn more about how bots work.
SETTINGS = ConfigurationBotFrameworkAuthentication(
CONFIG,
auth_configuration=AUTH_CONFIG,
)
ADAPTER = AdapterWithErrorHandler(SETTINGS)
Készségjegyzék
A képességjegyzék egy JSON-fájl, amely leírja a képesség által elvégezhető tevékenységeket, azok bemeneti és kimeneti paramétereit, valamint a képesség végpontjait.
A jegyzék tartalmazza azokat az információkat, amelyekre szüksége van a képesség eléréséhez egy másik robottól.
A legújabb sémaverzió a 2.1-es verzió.
{
"$schema": "https://schemas.botframework.com/schemas/skills/skill-manifest-2.0.0.json",
"$id": "EchoSkillBot",
"name": "Echo Skill bot",
"version": "1.0",
"description": "This is a sample echo skill",
"publisherName": "Microsoft",
"privacyUrl": "https://echoskillbot.contoso.com/privacy.html",
"copyright": "Copyright (c) Microsoft Corporation. All rights reserved.",
"license": "",
"iconUrl": "https://echoskillbot.contoso.com/icon.png",
"tags": [
"sample",
"echo"
],
"endpoints": [
{
"name": "default",
"protocol": "BotFrameworkV3",
"description": "Default endpoint for the skill",
"endpointUrl": "http://echoskillbot.contoso.com/api/messages",
"msAppId": "00000000-0000-0000-0000-000000000000"
}
]
}
A képességjegyzék-séma egy JSON-fájl, amely leírja a képességjegyzék sémáját. Az aktuális sémaverzió a 2.1.0.
A képesség tesztelése
Ezen a ponton tesztelheti a képességet az Emulátorban, mintha normál robot lenne. Ahhoz azonban, hogy készségként tesztelje, egy készségfelhasználót kell implementálnia.
Futtassa helyileg az Echo skill robotot a gépen. Ha útmutatásra van szüksége, tekintse meg a README C#, JavaScript, Java vagy Python mintafájlt.
Az Emulator használatával tesztelje a robotot. Amikor "end" vagy "stop" üzenetet küld a képességnek, az a válaszüzenet mellett egy endOfConversation tevékenységet is küld. A képesség elküldi a endOfConversation tevékenységet, jelezve, hogy a képesség befejeződött.
További információ a hibakeresésről
Mivel a készségek és a készségfelhasználók közötti forgalom hitelesítése megtörtént, az ilyen robotok hibakereséséhez további lépések is szükségesek.
A készségfelhasználónak és az általa használt összes készségnek közvetlenül vagy közvetve futnia kell.
Ha a robotok helyileg futnak, és bármelyik robot rendelkezik alkalmazásazonosítóval és jelszóval, akkor minden robotnak érvényes azonosítókkal és jelszóval kell rendelkeznie.
Ellenkező esetben ugyanúgy hibakeresést végezhet egy képességfelhasználón vagy képességen, mint más robotok. További információ: Robot hibakeresése és hibakeresés a Bot Framework Emulator használatával.