Skip to content
Draft
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
8 changes: 8 additions & 0 deletions src/Kiota.Builder/Configuration/GenerationConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,14 @@ public PluginAuthConfiguration? PluginAuthInformation
{
get; set;
}

/// <summary>
/// When true, should allow generation of adaptive cards
/// </summary>
public bool? ShouldGenerateAdaptiveCards
{
get; set;
}
}
#pragma warning restore CA1056
#pragma warning restore CA2227
1 change: 1 addition & 0 deletions src/Kiota.Builder/Kiota.Builder.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<NoWarn>$(NoWarn);CS8785;NU5048;NU5104;CA1724;CA1055;CA1848;CA1308;CA1822</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AdaptiveCards" Version="3.1.0" />
<PackageReference Include="AsyncKeyedLock" Version="7.1.6" />
<PackageReference Include="DotNet.Glob" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.4" />
Expand Down
63 changes: 63 additions & 0 deletions src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AdaptiveCards;
using Microsoft.OpenApi.Models;

namespace Kiota.Builder.Plugins
{
public class AdaptiveCardGenerator
{
public AdaptiveCardGenerator()
{
}

public AdaptiveCard GenerateAdaptiveCard(OpenApiOperation operation)
{
ArgumentNullException.ThrowIfNull(operation);

var responses = operation.Responses;
var response = responses["200"];

Check failure on line 23 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Dereference of a possibly null reference.

Check failure on line 23 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Dereference of a possibly null reference.

Check failure on line 23 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (ubuntu-latest)

Dereference of a possibly null reference.

Check failure on line 23 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check failure on line 23 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check failure on line 23 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (macos-latest)

Dereference of a possibly null reference.

Check failure on line 23 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (windows-latest)

Dereference of a possibly null reference.

Check failure on line 23 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test_and_generate_binaries (osx-arm64, macOS-latest)

Dereference of a possibly null reference.
ArgumentNullException.ThrowIfNull(response);

var schema = response.Content["application/json"].Schema;

Check failure on line 26 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Dereference of a possibly null reference.

Check failure on line 26 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Dereference of a possibly null reference.

Check failure on line 26 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (ubuntu-latest)

Dereference of a possibly null reference.

Check failure on line 26 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check failure on line 26 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.

Check failure on line 26 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (macos-latest)

Dereference of a possibly null reference.

Check failure on line 26 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (windows-latest)

Dereference of a possibly null reference.

Check failure on line 26 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test_and_generate_binaries (osx-arm64, macOS-latest)

Dereference of a possibly null reference.
ArgumentNullException.ThrowIfNull(schema);

var properties = schema.Properties;
ArgumentNullException.ThrowIfNull(properties);

AdaptiveCard card = new AdaptiveCard(new AdaptiveSchemaVersion(1, 5));

foreach (var property in properties)
{

if (property.Value.Type == "string" && property.Value.Format == "uri")

Check failure on line 37 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 37 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 37 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 37 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (ubuntu-latest)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 37 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 37 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 37 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (macos-latest)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 37 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (windows-latest)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 37 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test_and_generate_binaries (osx-arm64, macOS-latest)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'
{
card.Body.Add(new AdaptiveImage()
{
Url = new Uri($"${{{property.Key}}}"),
Size = AdaptiveImageSize.Large,
});
}
else if (property.Value.Type == "array")

Check failure on line 45 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 45 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 45 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / Analyze (csharp)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 45 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (ubuntu-latest)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 45 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 45 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / build

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 45 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (macos-latest)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 45 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test-release (windows-latest)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'

Check failure on line 45 in src/Kiota.Builder/Plugins/AdaptiveCardGenerator.cs

View workflow job for this annotation

GitHub Actions / test_and_generate_binaries (osx-arm64, macOS-latest)

Operator '==' cannot be applied to operands of type 'JsonSchemaType?' and 'string'
{
card.Body.Add(new AdaptiveTextBlock()
{
Text = $"${{{property.Key}.join(', ')}}",
});
}
else
{
card.Body.Add(new AdaptiveTextBlock()
{
Text = $"${{{property.Key}, {property.Key}, 'N/A'}}",
});
}
}
return card;
}
}
}
35 changes: 26 additions & 9 deletions src/Kiota.Builder/Plugins/PluginsGenerationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Emit;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
Expand Down Expand Up @@ -417,7 +418,7 @@ private OpenApiDocument GetDocumentWithTrimmedComponentsAndResponses(OpenApiDocu

private PluginManifestDocument GetManifestDocument(string openApiDocumentPath)
{
var (runtimes, functions, conversationStarters) = GetRuntimesFunctionsAndConversationStartersFromTree(OAIDocument, Configuration.PluginAuthInformation, TreeNode, openApiDocumentPath, Logger);
var (runtimes, functions, conversationStarters) = GetRuntimesFunctionsAndConversationStartersFromTree(OAIDocument, Configuration, TreeNode, openApiDocumentPath, Logger);
var descriptionForHuman = OAIDocument.Info?.Description is string d && !string.IsNullOrEmpty(d) ? d : $"Description for {OAIDocument.Info?.Title}";
var manifestInfo = ExtractInfoFromDocument(OAIDocument.Info);
var pluginManifestDocument = new PluginManifestDocument
Expand Down Expand Up @@ -499,13 +500,14 @@ private sealed record OpenApiManifestInfo(
string? PrivacyUrl = null,
string ContactEmail = DefaultContactEmail);

private static (OpenApiRuntime[], Function[], ConversationStarter[]) GetRuntimesFunctionsAndConversationStartersFromTree(OpenApiDocument document, PluginAuthConfiguration? authInformation, OpenApiUrlTreeNode currentNode,
private static (OpenApiRuntime[], Function[], ConversationStarter[]) GetRuntimesFunctionsAndConversationStartersFromTree(OpenApiDocument document, GenerationConfiguration configuration, OpenApiUrlTreeNode currentNode,
string openApiDocumentPath, ILogger<KiotaBuilder> logger)
{
var runtimes = new List<OpenApiRuntime>();
var functions = new List<Function>();
var conversationStarters = new List<ConversationStarter>();
var configAuth = authInformation?.ToPluginManifestAuth();
var configAuth = configuration.PluginAuthInformation?.ToPluginManifestAuth();
bool shouldGenerateAdaptiveCards = configuration.ShouldGenerateAdaptiveCards ?? false;
if (currentNode.PathItems.TryGetValue(Constants.DefaultOpenApiLabel, out var pathItem) && pathItem.Operations is not null)
{
foreach (var operation in pathItem.Operations.Values.Where(static x => !string.IsNullOrEmpty(x.OperationId)))
Expand Down Expand Up @@ -536,15 +538,17 @@ private static (OpenApiRuntime[], Function[], ConversationStarter[]) GetRuntimes

var summary = operation.Summary.CleanupXMLString();
var description = operation.Description.CleanupXMLString();

functions.Add(new Function
var function = new Function
{
Name = operation.OperationId!,
Description = !string.IsNullOrEmpty(description) ? description : summary,
States = GetStatesFromOperation(operation),
Capabilities = GetFunctionCapabilitiesFromOperation(operation),
Capabilities = GetFunctionCapabilitiesFromOperation(operation, shouldGenerateAdaptiveCards),
};


functions.Add(function);

});
conversationStarters.Add(new ConversationStarter
{
Text = !string.IsNullOrEmpty(summary) ? summary : description
Expand All @@ -555,7 +559,7 @@ private static (OpenApiRuntime[], Function[], ConversationStarter[]) GetRuntimes

foreach (var node in currentNode.Children)
{
var (childRuntimes, childFunctions, childConversationStarters) = GetRuntimesFunctionsAndConversationStartersFromTree(document, authInformation, node.Value, openApiDocumentPath, logger);
var (childRuntimes, childFunctions, childConversationStarters) = GetRuntimesFunctionsAndConversationStartersFromTree(document, configuration, node.Value, openApiDocumentPath, logger);
runtimes.AddRange(childRuntimes);
functions.AddRange(childFunctions);
conversationStarters.AddRange(childConversationStarters);
Expand Down Expand Up @@ -652,7 +656,7 @@ rExtRaw is T rExt &&
return null;
}

private static FunctionCapabilities? GetFunctionCapabilitiesFromOperation(OpenApiOperation openApiOperation)
private static FunctionCapabilities? GetFunctionCapabilitiesFromOperation(OpenApiOperation openApiOperation, bool shouldGenerateAdaptiveCards = false)
{
var capabilities = GetFunctionCapabilitiesFromCapabilitiesExtension(openApiOperation, OpenApiAiCapabilitiesExtension.Name);
if (capabilities != null)
Expand All @@ -668,6 +672,19 @@ rExtRaw is T rExt &&
ResponseSemantics = responseSemantics
};
}

if (shouldGenerateAdaptiveCards)
{
var generator = new AdaptiveCardGenerator();
var card = generator.GenerateAdaptiveCard(openApiOperation);
return new FunctionCapabilities
{
ResponseSemantics = new ResponseSemantics
{
StaticTemplate = JsonDocument.Parse(card.ToJson()).RootElement
}
};
}
return null;
}

Expand Down
65 changes: 65 additions & 0 deletions tests/Kiota.Builder.Tests/Plugins/AdaptiveCardGeneratorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using AdaptiveCards;
using Kiota.Builder.Plugins;
using Microsoft.OpenApi.Models;
using Xunit;

namespace Kiota.Builder.Tests.Plugins
{
public sealed class AdaptiveCardGeneratorTests
{
[Fact]
public void GenerateAdaptiveCardFromOperation()
{
var sample = new OpenApiOperation
{
Responses = new OpenApiResponses
{
["200"] = new OpenApiResponse
{
Description = "OK",
Content = new Dictionary<string, OpenApiMediaType>
{
["application/json"] = new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Type = "object",
Properties = new Dictionary<string, OpenApiSchema>
{
["name"] = new OpenApiSchema
{
Type = "string"
},
["age"] = new OpenApiSchema
{
Type = "number"
}
}
}
}
}
}
}
};
var expectedCard = new AdaptiveCard(new AdaptiveSchemaVersion(1, 5));
expectedCard.Body.Add(new AdaptiveTextBlock()
{
Text = "${name, name, 'N/A'}",
});
expectedCard.Body.Add(new AdaptiveTextBlock()
{
Text = "${age, age, 'N/A'}",
});

var generator = new AdaptiveCardGenerator();
var actualCard = generator.GenerateAdaptiveCard(sample);
Assert.Equal(expectedCard.Body.Count, actualCard.Body.Count);
}
}
}
Loading
Loading