Skip to content

Commit 005e2b3

Browse files
Merge pull request #421 from MicrosoftDocs/main
DocsUpdates
2 parents 57d1a00 + 2c8260f commit 005e2b3

File tree

7 files changed

+613
-3
lines changed

7 files changed

+613
-3
lines changed

semantic-kernel/concepts/plugins/adding-openapi-plugins.md

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ The base URL will be `https://api-host.com`.
538538

539539
In some instances, the server URL specified in the OpenAPI document or the server from which the document was loaded may not be suitable for use cases involving the OpenAPI plugin.
540540

541-
The Semantic Kernel allows you to override the server URL by providing a custom base URL when adding the OpenAPI plugin to the kernel:
541+
Semantic Kernel allows you to override the server URL by providing a custom base URL when adding the OpenAPI plugin to the kernel:
542542
```csharp
543543
await kernel.ImportPluginFromOpenApiAsync(
544544
pluginName: "lights",
@@ -593,6 +593,117 @@ await kernel.ImportPluginFromOpenApiAsync(
593593
});
594594
```
595595

596+
For more complex authentication scenarios that require dynamic access to the details of the authentication schemas supported by an API, you can use document
597+
and operation metadata to obtain this information. For more details, see [Document and operation metadata](./adding-openapi-plugins.md#document-and-operation-metadata).
598+
599+
## Response content reading customization
600+
601+
Semantic Kernel has a built-in mechanism for reading the content of HTTP responses from OpenAPI plugins and converting them to the appropriate .NET data types.
602+
For example, an image response can be read as a byte array, while a JSON or XML response can be read as a string.
603+
604+
However, there may be cases when the built-in mechanism is insufficient for your needs. For instance, when the response is a large JSON object or image that needs
605+
to be read as a stream in order to be supplied as input to another API. In such cases, reading the response content as a string or byte array and then converting
606+
it back to a stream can be inefficient and may lead to performance issues. To address this, Semantic Kernel allows for response content reading customization
607+
by providing a custom content reader:
608+
609+
```csharp
610+
private static async Task<object?> ReadHttpResponseContentAsync(HttpResponseContentReaderContext context, CancellationToken cancellationToken)
611+
{
612+
// Read JSON content as a stream instead of as a string, which is the default behavior.
613+
if (context.Response.Content.Headers.ContentType?.MediaType == "application/json")
614+
{
615+
return await context.Response.Content.ReadAsStreamAsync(cancellationToken);
616+
}
617+
618+
// HTTP request and response properties can be used to determine how to read the content.
619+
if (context.Request.Headers.Contains("x-stream"))
620+
{
621+
return await context.Response.Content.ReadAsStreamAsync(cancellationToken);
622+
}
623+
624+
// Return null to indicate that any other HTTP content not handled above should be read by the default reader.
625+
return null;
626+
}
627+
628+
await kernel.ImportPluginFromOpenApiAsync(
629+
pluginName: "lights",
630+
uri: new Uri("https://example.com/v1/swagger.json"),
631+
executionParameters: new OpenApiFunctionExecutionParameters()
632+
{
633+
HttpResponseContentReader = ReadHttpResponseContentAsync
634+
});
635+
```
636+
637+
In this example, the `ReadHttpResponseContentAsync` method reads the HTTP response content as a stream when the content type is `application/json` or when the request
638+
contains a custom header `x-stream`. The method returns `null` for any other content types, indicating that the default content reader should be used.
639+
640+
## Document and operation metadata
641+
642+
Semantic Kernel extracts OpenAPI document and operation metadata, including API information, security schemas, operation ID, description, parameter metadata and many more.
643+
It provides access to this information through the `KernelFunction.Metadata.AdditionalParameters` property. This metadata can be useful in scenarios where additional
644+
information about the API or operation is required, such as for authentication purposes:
645+
646+
```csharp
647+
static async Task AuthenticateRequestAsyncCallbackAsync(HttpRequestMessage request, CancellationToken cancellationToken = default)
648+
{
649+
// Get the function context
650+
if (request.Options.TryGetValue(OpenApiKernelFunctionContext.KernelFunctionContextKey, out OpenApiKernelFunctionContext? functionContext))
651+
{
652+
// Get the operation metadata
653+
if (functionContext!.Function!.Metadata.AdditionalProperties["operation"] is RestApiOperation operation)
654+
{
655+
// Handle API key-based authentication
656+
IEnumerable<KeyValuePair<RestApiSecurityScheme, IList<string>>> apiKeySchemes = operation.SecurityRequirements.Select(requirement => requirement.FirstOrDefault(schema => schema.Key.SecuritySchemeType == "apiKey"));
657+
if (apiKeySchemes.Any())
658+
{
659+
(RestApiSecurityScheme scheme, IList<string> scopes) = apiKeySchemes.First();
660+
661+
// Get the API key for the scheme and scopes from your app identity provider
662+
var apiKey = await this.identityPropvider.GetApiKeyAsync(scheme, scopes);
663+
664+
// Add the API key to the request headers
665+
if (scheme.In == RestApiParameterLocation.Header)
666+
{
667+
request.Headers.Add(scheme.Name, apiKey);
668+
}
669+
else if (scheme.In == RestApiParameterLocation.Query)
670+
{
671+
request.RequestUri = new Uri($"{request.RequestUri}?{scheme.Name}={apiKey}");
672+
}
673+
else
674+
{
675+
throw new NotSupportedException($"API key location '{scheme.In}' is not supported.");
676+
}
677+
}
678+
679+
// Handle other authentication types like Basic, Bearer, OAuth2, etc. For more information, see https://swagger.io/docs/specification/v3_0/authentication/
680+
}
681+
}
682+
}
683+
684+
// Import the transformed OpenAPI plugin specification
685+
var plugin = kernel.ImportPluginFromOpenApi(
686+
pluginName: "lights",
687+
uri: new Uri("https://example.com/v1/swagger.json"),
688+
new OpenApiFunctionExecutionParameters()
689+
{
690+
AuthCallback = AuthenticateRequestAsyncCallbackAsync
691+
});
692+
693+
await kernel.InvokePromptAsync("Test");
694+
```
695+
696+
In this example, the `AuthenticateRequestAsyncCallbackAsync` method reads the operation metadata from the function context and extracts the security requirements for the operation
697+
to determine the authentication scheme. It then retrieves the API key, for the scheme and scopes, from the app identity provider and adds it to the request headers or query parameters.
698+
699+
The following table lists the metadata available in the `KernelFunction.Metadata.AdditionalParameters` dictionary:
700+
701+
| Key | Type | Description |
702+
|------------|--------------------------------------|---------------------------------|
703+
| info | `RestApiInfo` | API information, including title, description, and version. |
704+
| operation | `RestApiOperation` | API operation details, such as id, description, path, method, etc. |
705+
| security | IList<`RestApiSecurityRequirement`> | API security requirements - type, name, in, etc. |
706+
596707
::: zone-end
597708

598709

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
- name: Prompt Engineering with Semantic Kernel
22
href: index.md
3+
- name: YAML Schema Reference for Prompts
4+
href: yaml-schema.md
35
- name: Semantic Kernel Prompt Templates
46
href: prompt-template-syntax.md
57
- name: Handlebars Prompt Templates
68
href: handlebars-prompt-templates.md
79
- name: Liquid Prompt Templates
810
href: liquid-prompt-templates.md
11+
- name: Protecting against Prompt Injection Attacks
12+
href: prompt-injection-attacks.md

semantic-kernel/concepts/prompts/handlebars-prompt-templates.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,4 +243,5 @@ More coming soon.
243243
## Next steps
244244

245245
> [!div class="nextstepaction"]
246-
> [Liquid Prompt Templates](./liquid-prompt-templates.md)
246+
> [Liquid Prompt Templates](./liquid-prompt-templates.md)
247+
> [Protecting against Prompt Injection Attacks](./prompt-injection-attacks.md)

semantic-kernel/concepts/prompts/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,7 @@ Prompt engineering is a dynamic and evolving field, and skilled prompt engineers
6464

6565
> [!div class="nextstepaction"]
6666
> [Semantic Kernel Prompt Templates](./prompt-template-syntax.md)
67+
> [YAML Schema Reference for Prompts](./yaml-schema.md)
6768
> [Handlebars Prompt Templates](./handlebars-prompt-templates.md)
6869
> [Liquid Prompt Templates](./liquid-prompt-templates.md)
70+
> [Protecting against Prompt Injection Attacks](./prompt-injection-attacks.md)

0 commit comments

Comments
 (0)