forked from microsoft/semantic-kernel
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
.Net: Handlebars planner complex types (microsoft#3502)
### Motivation and Context <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> Support for complex types in Handlebars Planner ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> Native Plugin with Complex Types ![image](https://github.com/microsoft/semantic-kernel/assets/125500434/01c9d5a0-b98b-4d88-ae5a-f38425a2d1ba) Remote Plugin with Complex Types ![image](https://github.com/microsoft/semantic-kernel/assets/125500434/ebd3afb7-1c49-483a-b4ea-6f41783837bf) ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone 😄
- Loading branch information
1 parent
5623544
commit cbf31ee
Showing
19 changed files
with
1,278 additions
and
452 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
...et/samples/KernelSyntaxExamples/Plugins/DictionaryPlugin/ComplexParamsDictionaryPlugin.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.ComponentModel; | ||
using System.Globalization; | ||
using System.Linq; | ||
using System.Security.Cryptography; | ||
using System.Text.Json; | ||
using Microsoft.SemanticKernel; | ||
|
||
namespace Plugins.DictionaryPlugin; | ||
|
||
/// <summary> | ||
/// Plugin example with two Local functions, where one function gets a random word and the other returns a definition for a given word. | ||
/// </summary> | ||
public sealed class ComplexParamsDictionaryPlugin | ||
{ | ||
public const string PluginName = nameof(ComplexParamsDictionaryPlugin); | ||
|
||
private readonly List<DictionaryEntry> _dictionary = new() | ||
{ | ||
new DictionaryEntry("apple", "a round fruit with red, green, or yellow skin and a white flesh"), | ||
new DictionaryEntry("book", "a set of printed or written pages bound together along one edge"), | ||
new DictionaryEntry("cat", "a small furry animal with whiskers and a long tail that is often kept as a pet"), | ||
new DictionaryEntry("dog", "a domesticated animal with four legs, a tail, and a keen sense of smell that is often used for hunting or companionship"), | ||
new DictionaryEntry("elephant", "a large gray mammal with a long trunk, tusks, and ears that lives in Africa and Asia") | ||
}; | ||
|
||
[SKFunction, SKName("GetRandomEntry"), System.ComponentModel.Description("Gets a random word from a dictionary of common words and their definitions.")] | ||
public DictionaryEntry GetRandomEntry() | ||
{ | ||
// Get random number | ||
var index = RandomNumberGenerator.GetInt32(0, this._dictionary.Count - 1); | ||
|
||
// Return the word at the random index | ||
return this._dictionary[index]; | ||
} | ||
|
||
[SKFunction, SKName("GetWord"), System.ComponentModel.Description("Gets the word for a given dictionary entry.")] | ||
public string GetWord([System.ComponentModel.Description("Word to get definition for.")] DictionaryEntry entry) | ||
{ | ||
// Return the definition or a default message | ||
return this._dictionary.FirstOrDefault(e => e.Word == entry.Word)?.Word ?? "Entry not found"; | ||
} | ||
|
||
[SKFunction, SKName("GetDefinition"), System.ComponentModel.Description("Gets the definition for a given word.")] | ||
public string GetDefinition([System.ComponentModel.Description("Word to get definition for.")] string word) | ||
{ | ||
// Return the definition or a default message | ||
return this._dictionary.FirstOrDefault(e => e.Word == word)?.Definition ?? "Word not found"; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// In order to use custom types, <see cref="TypeConverter"/> should be specified, | ||
/// that will convert object instance to string representation. | ||
/// </summary> | ||
/// <remarks> | ||
/// <see cref="TypeConverter"/> is used to represent complex object as meaningful string, so | ||
/// it can be passed to AI for further processing using semantic functions. | ||
/// It's possible to choose any format (e.g. XML, JSON, YAML) to represent your object. | ||
/// </remarks> | ||
[TypeConverter(typeof(DictionaryEntryConverter))] | ||
public sealed class DictionaryEntry | ||
{ | ||
public string Word { get; set; } = string.Empty; | ||
public string Definition { get; set; } = string.Empty; | ||
|
||
public DictionaryEntry(string word, string definition) | ||
{ | ||
this.Word = word; | ||
this.Definition = definition; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Implementation of <see cref="TypeConverter"/> for <see cref="DictionaryEntry"/>. | ||
/// In this example, object instance is serialized with <see cref="JsonSerializer"/> from System.Text.Json, | ||
/// but it's possible to convert object to string using any other serialization logic. | ||
/// </summary> | ||
#pragma warning disable CA1812 // instantiated by Kernel | ||
public sealed class DictionaryEntryConverter : TypeConverter | ||
#pragma warning restore CA1812 | ||
{ | ||
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) => true; | ||
|
||
/// <summary> | ||
/// This method is used to convert object from string to actual type. This will allow to pass object to | ||
/// Local function which requires it. | ||
/// </summary> | ||
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) | ||
{ | ||
return JsonSerializer.Deserialize<DictionaryEntry>((string)value); | ||
} | ||
|
||
/// <summary> | ||
/// This method is used to convert actual type to string representation, so it can be passed to AI | ||
/// for further processing. | ||
/// </summary> | ||
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) | ||
{ | ||
return JsonSerializer.Serialize(value); | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
dotnet/samples/KernelSyntaxExamples/Plugins/DictionaryPlugin/StringParamsDictionaryPlugin.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Security.Cryptography; | ||
using Microsoft.SemanticKernel; | ||
|
||
namespace Plugins.DictionaryPlugin; | ||
|
||
/// <summary> | ||
/// Plugin example with two native functions, where one function gets a random word and the other returns a definition for a given word. | ||
/// </summary> | ||
public sealed class StringParamsDictionaryPlugin | ||
{ | ||
public const string PluginName = nameof(StringParamsDictionaryPlugin); | ||
|
||
private readonly Dictionary<string, string> _dictionary = new() | ||
{ | ||
{"apple", "a round fruit with red, green, or yellow skin and a white flesh"}, | ||
{"book", "a set of printed or written pages bound together along one edge"}, | ||
{"cat", "a small furry animal with whiskers and a long tail that is often kept as a pet"}, | ||
{"dog", "a domesticated animal with four legs, a tail, and a keen sense of smell that is often used for hunting or companionship"}, | ||
{"elephant", "a large gray mammal with a long trunk, tusks, and ears that lives in Africa and Asia"} | ||
}; | ||
|
||
[SKFunction, SKName("GetRandomWord"), System.ComponentModel.Description("Gets a random word from a dictionary of common words and their definitions.")] | ||
public string GetRandomWord() | ||
{ | ||
// Get random number | ||
var index = RandomNumberGenerator.GetInt32(0, this._dictionary.Count - 1); | ||
|
||
// Return the word at the random index | ||
return this._dictionary.ElementAt(index).Key; | ||
} | ||
|
||
[SKFunction, SKName("GetDefinition"), System.ComponentModel.Description("Gets the definition for a given word.")] | ||
public string GetDefinition([System.ComponentModel.Description("Word to get definition for.")] string word) | ||
{ | ||
return this._dictionary.TryGetValue(word, out var definition) | ||
? definition | ||
: "Word not found"; | ||
} | ||
} |
Oops, something went wrong.