Skip to content

.Net: Update AgentDefinition to match the latest schema changes #10735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions dotnet/src/Agents/Abstractions/Agents.Abstractions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<AssemblyName>Microsoft.SemanticKernel.Agents.Abstractions</AssemblyName>
<RootNamespace>Microsoft.SemanticKernel.Agents</RootNamespace>
<TargetFrameworks>net8.0;netstandard2.0</TargetFrameworks>
<NoWarn>$(NoWarn);SKEXP0110;SKEXP0001</NoWarn>
<EnablePackageValidation>false</EnablePackageValidation>
<VersionSuffix>rc</VersionSuffix>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public sealed class AgentDefinition
/// <summary>
/// Gets or sets the metadata associated with the agent.
/// </summary>
public IDictionary<string, object?>? Metadata { get; set; }
public AgentMetadata? Metadata { get; set; }

/// <summary>
/// Gets or sets the model used by the agent.
Expand Down
46 changes: 46 additions & 0 deletions dotnet/src/Agents/Abstractions/Definition/AgentMetadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;

namespace Microsoft.SemanticKernel.Agents;

/// <summary>
/// Defines agent metadata.
/// </summary>
[ExcludeFromCodeCoverage]
[Experimental("SKEXP0110")]
public sealed class AgentMetadata
{
/// <summary>
/// Gets or sets the collection of authors associated with the agent.
/// </summary>
public IList<string>? Authors { get; set; }

/// <summary>
/// Gets or sets the collection of tags associated with the agent.
/// </summary>
public IList<string>? Tags { get; set; }

/// <summary>
/// Extra properties that may be included in the serialized agent metadata.
/// </summary>
/// <remarks>
/// Used to store agent specific metadata.
/// </remarks>
[JsonExtensionData]
public IDictionary<string, object?> ExtensionData
{
get => this._extensionData ??= new Dictionary<string, object?>();
set
{
Verify.NotNull(value);
this._extensionData = value;
}
}

#region private
private IDictionary<string, object?>? _extensionData;
#endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public sealed class AzureAIAgentFactory : KernelAgentFactory
/// <summary>
/// The type of the Azure AI agent.
/// </summary>
public const string AzureAIAgentType = "azureai_agent";
public const string AzureAIAgentType = "foundry_agent";

/// <summary>
/// Initializes a new instance of the <see cref="AzureAIAgentFactory"/> class.
Expand Down
110 changes: 110 additions & 0 deletions dotnet/src/Agents/UnitTests/Yaml/AgentDefinitionYamlTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.SemanticKernel.Agents;
using Xunit;

namespace SemanticKernel.Agents.UnitTests.Yaml;

/// <summary>
/// Unit tests for <see cref="AgentDefinitionYaml"/>.
/// </summary>
public class AgentDefinitionYamlTests
{
/// <summary>
/// Verify can create an instance of <see cref="AgentDefinition"/> from YAML text.
/// </summary>
[Fact]
public void VerifyAgentDefinitionFromYaml()
{
// Arrange
var text =
"""
version: 1.0.0
type: chat_completion_agent
name: My Agent
description: Description of My Agent
instructions: Instructions for how My Agent works
metadata:
authors:
- Bob
- Ted
- Alice
tags:
- red
- green
- blue
created: 2025-02-21
model:
id: gpt-4o-mini
options:
temperature: 0.4
function_choice_behavior:
type: auto
configuration:
type: azureai
inputs:
- name: input1
description: input1 description
- name: input2
description: input2 description
outputs:
- description: output1 description
template:
format: liquid
parser: semantic-kernel
tools:
- name: tool1
type: code_interpreter
- name: tool2
type: file_search
""";

// Act
var agentDefinition = AgentDefinitionYaml.FromYaml(text);

// Assert
Assert.NotNull(agentDefinition);
}

/// <summary>
/// Verify can create an instance of <see cref="AgentDefinition"/> from YAML text.
/// </summary>
[Fact]
public void VerifyAgentDefinitionMetadataPropertiesFromYaml()
{
// Arrange
var text =
"""
version: 1.0.0
type: chat_completion_agent
name: My Agent
description: Description of My Agent
instructions: Instructions for how My Agent works
metadata:
authors:
- Bob
- Ted
- Alice
tags:
- red
- green
- blue
created: 2025-02-21
""";

// Act
var agentDefinition = AgentDefinitionYaml.FromYaml(text);

// Assert
Assert.NotNull(agentDefinition);
Assert.Equal("1.0.0", agentDefinition.Version);
Assert.Equal("chat_completion_agent", agentDefinition.Type);
Assert.Equal("My Agent", agentDefinition.Name);
Assert.Equal("Description of My Agent", agentDefinition.Description);
Assert.Equal("Instructions for how My Agent works", agentDefinition.Instructions);
Assert.NotNull(agentDefinition.Metadata);
Assert.Equal(3, agentDefinition.Metadata.Authors?.Count);
Assert.Equal(3, agentDefinition.Metadata.Tags?.Count);
Assert.Equal("2025-02-21", agentDefinition.Metadata.ExtensionData["created"]);
}
}
14 changes: 7 additions & 7 deletions dotnet/src/Agents/UnitTests/Yaml/AzureAIKernelAgentYamlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public async Task VerifyRequestIncludesToolAsync(string type)
// Arrange
var text =
$"""
type: azureai_agent
type: foundry_agent
name: AzureAIAgent
description: AzureAIAgent Description
instructions: AzureAIAgent Instructions
Expand Down Expand Up @@ -99,7 +99,7 @@ public async Task VerifyRequestIncludesAzureFunctionAsync()
// Arrange
var text =
"""
type: azureai_agent
type: foundry_agent
name: AzureAIAgent
description: AzureAIAgent Description
instructions: AzureAIAgent Instructions
Expand Down Expand Up @@ -147,7 +147,7 @@ public async Task VerifyRequestIncludesFunctionAsync()
// Arrange
var text =
"""
type: azureai_agent
type: foundry_agent
name: AzureAIAgent
description: AzureAIAgent Description
instructions: AzureAIAgent Instructions
Expand Down Expand Up @@ -189,7 +189,7 @@ public async Task VerifyRequestIncludesBingGroundingAsync()
// Arrange
var text =
"""
type: azureai_agent
type: foundry_agent
name: AzureAIAgent
description: AzureAIAgent Description
instructions: AzureAIAgent Instructions
Expand Down Expand Up @@ -224,7 +224,7 @@ public async Task VerifyRequestIncludesMicrosoftFabricAsync()
// Arrange
var text =
"""
type: azureai_agent
type: foundry_agent
name: AzureAIAgent
description: AzureAIAgent Description
instructions: AzureAIAgent Instructions
Expand Down Expand Up @@ -259,7 +259,7 @@ public async Task VerifyRequestIncludesOpenAPIAsync()
// Arrange
var text =
"""
type: azureai_agent
type: foundry_agent
name: AzureAIAgent
description: AzureAIAgent Description
instructions: AzureAIAgent Instructions
Expand Down Expand Up @@ -309,7 +309,7 @@ public async Task VerifyRequestIncludesSharepointGroundingAsync()
// Arrange
var text =
"""
type: azureai_agent
type: foundry_agent
name: AzureAIAgent
description: AzureAIAgent Description
instructions: AzureAIAgent Instructions
Expand Down
51 changes: 1 addition & 50 deletions dotnet/src/Agents/UnitTests/Yaml/KernelAgentYamlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,55 +63,6 @@ public void Dispose()
this._httpClient.Dispose();
}

/// <summary>
/// Verify can create an instance of <see cref="AgentDefinition"/> from YAML text.
/// </summary>
[Fact]
public void VerifyAgentDefinitionFromYaml()
{
// Arrange
var text =
"""
version: 1.0.0
type: chat_completion_agent
name: ChatCompletionAgent
description: ChatCompletionAgent Description
instructions: ChatCompletionAgent Instructions
metadata:
author: Microsoft
created: 2025-02-21
model:
id: gpt-4o-mini
options:
temperature: 0.4
function_choice_behavior:
type: auto
configuration:
type: azureai
inputs:
- name: input1
description: input1 description
- name: input2
description: input2 description
outputs:
- description: output1 description
template:
format: liquid
parser: semantic-kernel
tools:
- name: tool1
type: code_interpreter
- name: tool2
type: file_search
""";

// Act
var agentDefinition = AgentDefinitionYaml.FromYaml(text);

// Assert
Assert.NotNull(agentDefinition);
}

/// <summary>
/// Verify can create an instance of <see cref="KernelAgent"/> using <see cref="ChatCompletionAgentFactory"/>
/// </summary>
Expand Down Expand Up @@ -189,7 +140,7 @@ public async Task VerifyCanCreateAzureAIAgentAsync()
// Arrange
var text =
"""
type: azureai_agent
type: foundry_agent
name: AzureAIAgent
description: AzureAIAgent Description
instructions: AzureAIAgent Instructions
Expand Down
1 change: 1 addition & 0 deletions dotnet/src/Agents/Yaml/AgentDefinitionYaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public static AgentDefinition FromYaml(string text)
.WithTypeConverter(new PromptExecutionSettingsTypeConverter())
.WithTypeConverter(new ModelConfigurationTypeConverter())
.WithTypeConverter(new AgentToolDefinitionTypeConverter())
.WithTypeConverter(new AgentMetadataTypeConverter())
.Build();

return deserializer.Deserialize<AgentDefinition>(text);
Expand Down
70 changes: 70 additions & 0 deletions dotnet/src/Agents/Yaml/AgentMetadataTypeConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.Collections.Generic;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

namespace Microsoft.SemanticKernel.Agents;

/// <summary>
/// Type converter custom deserialization for <see cref="AgentToolDefinition"/> from YAML.
/// </summary>
/// <remarks>
/// Required to correctly deserialize the <see cref="AgentToolDefinition.Configuration"/> from YAML.
/// </remarks>
internal sealed class AgentToolDefinitionTypeConverter : IYamlTypeConverter
{
/// <inheritdoc/>
public bool Accepts(Type type)
{
return type == typeof(AgentToolDefinition);
}

/// <inheritdoc/>
public object? ReadYaml(IParser parser, Type type)
{
s_deserializer ??= new DeserializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.IgnoreUnmatchedProperties() // Required to ignore the 'type' property used as type discrimination. Otherwise, the "Property 'type' not found on type '{type.FullName}'" exception is thrown.
.Build();

parser.MoveNext(); // Move to the first property

var agentToolDefinition = new AgentToolDefinition();
while (parser.Current is not MappingEnd)
{
var propertyName = parser.Consume<Scalar>().Value;
switch (propertyName)
{
case "type":
agentToolDefinition.Type = s_deserializer.Deserialize<string>(parser);
break;
case "name":
agentToolDefinition.Name = s_deserializer.Deserialize<string>(parser);
break;
case "description":
agentToolDefinition.Description = s_deserializer.Deserialize<string>(parser);
break;
default:
(agentToolDefinition.Configuration ??= new Dictionary<string, object?>()).Add(propertyName, s_deserializer.Deserialize<object>(parser));
break;
}
}
parser.MoveNext(); // Move past the MappingEnd event
return agentToolDefinition;
}

/// <inheritdoc/>
public void WriteYaml(IEmitter emitter, object? value, Type type)
{
throw new NotImplementedException();
}

/// <summary>
/// The YamlDotNet deserializer instance.
/// </summary>
private static IDeserializer? s_deserializer;
}
Loading
Loading