Skip to content

Commit

Permalink
.NET Agents - Fix enum handling of function parameters (#10513)
Browse files Browse the repository at this point in the history
### Motivation and Context

`OpenAIAssistant` and `AzureAIAgent` fail when describing a function
with an enum parameter.

### Description
<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->

Remove custom logic and reconcile processing with
`JsonSchemaFunctionParameters` and `KernelJsonSchema` that is now
available.

### 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
crickman authored Feb 13, 2025
1 parent 784f13e commit 50a46c3
Show file tree
Hide file tree
Showing 24 changed files with 451 additions and 568 deletions.
3 changes: 0 additions & 3 deletions dotnet/samples/Concepts/Concepts.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,6 @@
<EmbeddedResource Include="Resources\*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="Resources\Agents\*">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Remove="Resources\Plugins\EventPlugin\openapiV1.json" />
Expand Down
9 changes: 0 additions & 9 deletions dotnet/samples/Concepts/Resources/Agents/ParrotAgent.yaml

This file was deleted.

7 changes: 0 additions & 7 deletions dotnet/samples/Concepts/Resources/Agents/ToolAgent.yaml

This file was deleted.

217 changes: 0 additions & 217 deletions dotnet/samples/Concepts/Resources/Agents/travelinfo.txt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,78 +1,20 @@
// Copyright (c) Microsoft. All rights reserved.
using System.ComponentModel;
using Azure.AI.Projects;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.AzureAI;
using Microsoft.SemanticKernel.ChatCompletion;
using Resources;
using Agent = Azure.AI.Projects.Agent;

namespace GettingStarted.AzureAgents;

/// <summary>
/// This example demonstrates similarity between using <see cref="AzureAIAgent"/>
/// and <see cref="ChatCompletionAgent"/> (see: Step 2).
/// and other agent types.
/// </summary>
public class Step01_AzureAIAgent(ITestOutputHelper output) : BaseAgentsTest(output)
{
private const string HostName = "Host";
private const string HostInstructions = "Answer questions about the menu.";

[Fact]
public async Task UseSingleAssistantAgentAsync()
{
// Define the agent
AzureAIClientProvider clientProvider = this.GetAzureProvider();
AgentsClient client = clientProvider.Client.GetAgentsClient();

Agent definition = await client.CreateAgentAsync(
TestConfiguration.AzureAI.ChatModelId,
HostName,
null,
HostInstructions);
AzureAIAgent agent = new(definition, clientProvider)
{
Kernel = new Kernel(),
};

// Initialize plugin and add to the agent's Kernel (same as direct Kernel usage).
KernelPlugin plugin = KernelPluginFactory.CreateFromType<MenuPlugin>();
agent.Kernel.Plugins.Add(plugin);

// Create a thread for the agent conversation.
AgentThread thread = await client.CreateThreadAsync(metadata: AssistantSampleMetadata);

// Respond to user input
try
{
await InvokeAgentAsync("Hello");
await InvokeAgentAsync("What is the special soup and its price?");
await InvokeAgentAsync("What is the special drink and its price?");
await InvokeAgentAsync("Thank you");
}
finally
{
await client.DeleteThreadAsync(thread.Id);
await client.DeleteAgentAsync(agent.Id);
}

// Local function to invoke agent and display the conversation messages.
async Task InvokeAgentAsync(string input)
{
ChatMessageContent message = new(AuthorRole.User, input);
await agent.AddChatMessageAsync(thread.Id, message);
this.WriteAgentChatMessage(message);

await foreach (ChatMessageContent response in agent.InvokeAsync(thread.Id))
{
this.WriteAgentChatMessage(response);
}
}
}

[Fact]
public async Task UseTemplateForAssistantAgentAsync()
public async Task UseTemplateForAzureAgentAsync()
{
// Define the agent
string generateStoryYaml = EmbeddedResource.Read("GenerateStory.yaml");
Expand Down Expand Up @@ -102,11 +44,11 @@ public async Task UseTemplateForAssistantAgentAsync()

// Invoke the agent with the override arguments.
await InvokeAgentAsync(
new()
{
{ "topic", "Cat" },
{ "length", "3" },
});
new()
{
{ "topic", "Cat" },
{ "length", "3" },
});
}
finally
{
Expand All @@ -123,22 +65,4 @@ async Task InvokeAgentAsync(KernelArguments? arguments = null)
}
}
}

private sealed class MenuPlugin
{
[KernelFunction, Description("Provides a list of specials from the menu.")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "Too smart")]
public string GetSpecials() =>
"""
Special Soup: Clam Chowder
Special Salad: Cobb Salad
Special Drink: Chai Tea
""";

[KernelFunction, Description("Provides the price of the requested menu item.")]
public string GetItemPrice(
[Description("The name of the menu item.")]
string menuItem) =>
"$9.99";
}
}
Loading

0 comments on commit 50a46c3

Please sign in to comment.