Repository: microsoft/kiota (csharp)

Issue:
Update the x-ai-adaptive-card extension schema to the latest supported one
### Is your feature request related to a problem? Please describe the problem.

_No response_

### Client library/SDK language

None

### Describe the solution you'd like

Map to the latest schema from the API Plugin manifest: https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/api-plugin-manifest-2.3#response-semantics-object

### Additional context

_No response_

Pull request:
## Plan to add new properties to OpenApiAiAdaptiveCardExtension

Based on analysis of the code, I need to implement the following minimal changes to support the new CardResponseSemanticProperties interface:

- [x] Analyze existing code structure and patterns
- [x] Add SubTitle property to OpenApiAiAdaptiveCardExtension class
- [x] Add ThumbnailUrl property to OpenApiAiAdaptiveCardExtension class  
- [x] Add InformationProtectionLabel property to OpenApiAiAdaptiveCardExtension class
- [x] Update Parse method to handle new properties in JSON parsing
- [x] Update Write method to serialize new properties
- [x] Update AdaptiveCardInfo record to include new properties
- [x] Update AdaptiveCardMapper to pass new properties
- [x] Update unit tests to cover new properties in parsing and serialization
- [x] Update plugin generation tests if needed
- [x] Verify all changes work correctly
- [x] Add changelog entry
- [x] Update changelog entry to reference issue #6934

The new properties to add are:
- `subTitle?: string;` ✅ Added as `Subtitle`
- `thumbnailUrl?: string;` ✅ Added as `ThumbnailUrl` 
- `informationProtectionLabel?: string;` ✅ Added as `InformationProtectionLabel`

Note: `title` and `url` properties already exist in the current implementation.

## Changes Made:
- ✅ Added three new optional string properties to OpenApiAiAdaptiveCardExtension class
- ✅ Updated Parse method to handle these properties from JSON with appropriate snake_case naming (`subtitle`, `thumbnail_url`, `information_protection_label`)
- ✅ Updated Write method to serialize these properties with correct naming conventions
- ✅ Updated AdaptiveCardInfo record to include the new properties as optional parameters
- ✅ Updated AdaptiveCardMapper to pass the new properties to the record
- ✅ Added comprehensive test coverage for parsing and serialization with all properties
- ✅ Verified syntax and naming conventions are correct using test compilation
- ✅ Ensured backward compatibility with existing functionality
- ✅ Added changelog entry documenting the new feature
- ✅ Updated changelog entry to reference issue #6934

## Summary:
All requirements have been successfully implemented with minimal changes that maintain backward compatibility. The new properties are optional and follow the existing patterns in the codebase for naming conventions, parsing, and serialization. A changelog entry has been added to document this new feature and references the related issue #6934.

<!-- START COPILOT CODING AGENT SUFFIX -->



<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a5d4394ad1..ccc36670f5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
+- Added support for new properties in `OpenApiAiAdaptiveCardExtension`: `subtitle`, `thumbnailUrl`, and `informationProtectionLabel` to align with the updated `CardResponseSemanticProperties` interface. [#6934](https://github.com/microsoft/kiota/issues/6934)
+
 ### Changed
 
 - Fixed a bug where Java code generation fails due to creation of an invalid object property name derived from the '@' symbol. [#6688](https://github.com/microsoft/kiota/issues/6688)
diff --git a/src/Kiota.Builder/OpenApiExtensions/OpenApiAiAdaptiveCardExtension.cs b/src/Kiota.Builder/OpenApiExtensions/OpenApiAiAdaptiveCardExtension.cs
index 22a8707226..2bc0d3b65d 100644
--- a/src/Kiota.Builder/OpenApiExtensions/OpenApiAiAdaptiveCardExtension.cs
+++ b/src/Kiota.Builder/OpenApiExtensions/OpenApiAiAdaptiveCardExtension.cs
@@ -23,11 +23,25 @@ public string? Title
         get; set;
     }
 
+    public string? Subtitle
+    {
+        get; set;
+    }
+
 #pragma warning disable CA1056 // URI-like properties should not be strings
 
     public string? Url
+    {
+        get; set;
+    }
+
+    public string? ThumbnailUrl
+    {
+        get; set;
+    }
 #pragma warning restore CA1056 // URI-like properties should not be strings
 
+    public string? InformationProtectionLabel
     {
         get; set;
     }
@@ -54,6 +68,18 @@ public static OpenApiAiAdaptiveCardExtension Parse(JsonNode source)
         {
             extension.Url = urlStrValue;
         }
+        if (rawObject.TryGetPropertyValue(nameof(Subtitle).ToFirstCharacterLowerCase(), out var subtitle) && subtitle is JsonValue subtitleValue && subtitleValue.GetValueKind() is JsonValueKind.String && subtitleValue.TryGetValue<string>(out var subtitleStrValue))
+        {
+            extension.Subtitle = subtitleStrValue;
+        }
+        if (rawObject.TryGetPropertyValue(nameof(ThumbnailUrl).ToFirstCharacterLowerCase().ToSnakeCase(), out var thumbnailUrl) && thumbnailUrl is JsonValue thumbnailUrlValue && thumbnailUrlValue.GetValueKind() is JsonValueKind.String && thumbnailUrlValue.TryGetValue<string>(out var thumbnailUrlStrValue))
+        {
+            extension.ThumbnailUrl = thumbnailUrlStrValue;
+        }
+        if (rawObject.TryGetPropertyValue(nameof(InformationProtectionLabel).ToFirstCharacterLowerCase().ToSnakeCase(), out var informationProtectionLabel) && informationProtectionLabel is JsonValue informationProtectionLabelValue && informationProtectionLabelValue.GetValueKind() is JsonValueKind.String && informationProtectionLabelValue.TryGetValue<string>(out var informationProtectionLabelStrValue))
+        {
+            extension.InformationProtectionLabel = informationProtectionLabelStrValue;
+        }
         // We are supporting empty extension to avoid creating the template when emitting from typespec scenario
         if (string.IsNullOrEmpty(extension.DataPath) || string.IsNullOrEmpty(extension.File) || string.IsNullOrEmpty(extension.Title))
             return emptyExtension;
@@ -77,6 +103,21 @@ public void Write(IOpenApiWriter writer, OpenApiSpecVersion specVersion)
                 writer.WritePropertyName(nameof(Url).ToFirstCharacterLowerCase());
                 writer.WriteValue(Url);
             }
+            if (!string.IsNullOrEmpty(Subtitle))
+            {
+                writer.WritePropertyName(nameof(Subtitle).ToFirstCharacterLowerCase());
+                writer.WriteValue(Subtitle);
+            }
+            if (!string.IsNullOrEmpty(ThumbnailUrl))
+            {
+                writer.WritePropertyName(nameof(ThumbnailUrl).ToFirstCharacterLowerCase().ToSnakeCase());
+                writer.WriteValue(ThumbnailUrl);
+            }
+            if (!string.IsNullOrEmpty(InformationProtectionLabel))
+            {
+                writer.WritePropertyName(nameof(InformationProtectionLabel).ToFirstCharacterLowerCase().ToSnakeCase());
+                writer.WriteValue(InformationProtectionLabel);
+            }
         }
         writer.WriteEndObject();
     }
diff --git a/src/kiota/Rpc/AdaptiveCardInfo.cs b/src/kiota/Rpc/AdaptiveCardInfo.cs
index 6444059717..b3699f9e60 100644
--- a/src/kiota/Rpc/AdaptiveCardInfo.cs
+++ b/src/kiota/Rpc/AdaptiveCardInfo.cs
@@ -1,4 +1,4 @@
 ﻿namespace kiota.Rpc
 {
-    public record AdaptiveCardInfo(string dataPath, string file, string title, string? url = null);
+    public record AdaptiveCardInfo(string dataPath, string file, string title, string? url = null, string? subtitle = null, string? thumbnailUrl = null, string? informationProtectionLabel = null);
 }
diff --git a/src/kiota/Rpc/AdaptiveCardMapper.cs b/src/kiota/Rpc/AdaptiveCardMapper.cs
index 805812ff6c..293a7aac41 100644
--- a/src/kiota/Rpc/AdaptiveCardMapper.cs
+++ b/src/kiota/Rpc/AdaptiveCardMapper.cs
@@ -12,7 +12,7 @@ internal class AdaptiveCardMapper
             {
                 if (adaptiveCard.DataPath is not null && adaptiveCard.File is not null && adaptiveCard.Title is not null)
                 {
-                    return new AdaptiveCardInfo(adaptiveCard.DataPath, adaptiveCard.File, adaptiveCard.Title, adaptiveCard.Url);
+                    return new AdaptiveCardInfo(adaptiveCard.DataPath, adaptiveCard.File, adaptiveCard.Title, adaptiveCard.Url, adaptiveCard.Subtitle, adaptiveCard.ThumbnailUrl, adaptiveCard.InformationProtectionLabel);
                 }
             }
             return null;


Test patch:
diff --git a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiAdaptiveCardExtensionTests.cs b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiAdaptiveCardExtensionTests.cs
index accbd82f42..7dae21710c 100644
--- a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiAdaptiveCardExtensionTests.cs
+++ b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiAiAdaptiveCardExtensionTests.cs
@@ -39,6 +39,37 @@ public void Parses()
         Assert.Equal("path_to_file", value.File);
         Assert.Equal("title", value.Title);
         Assert.Equal("https://example.com", value.Url);
+        Assert.Null(value.Subtitle);
+        Assert.Null(value.ThumbnailUrl);
+        Assert.Null(value.InformationProtectionLabel);
+    }
+
+    [Fact]
+    public void ParsesWithAllProperties()
+    {
+        var oaiValueRepresentation =
+        """
+        {
+            "data_path": "$.items",
+            "file": "path_to_file",
+            "title": "title",
+            "url": "https://example.com",
+            "subtitle": "subtitle text",
+            "thumbnail_url": "https://example.com/thumbnail.jpg",
+            "information_protection_label": "confidential"
+        }
+        """;
+        using var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(oaiValueRepresentation));
+        var oaiValue = JsonNode.Parse(stream);
+        var value = OpenApiAiAdaptiveCardExtension.Parse(oaiValue);
+        Assert.NotNull(value);
+        Assert.Equal("$.items", value.DataPath);
+        Assert.Equal("path_to_file", value.File);
+        Assert.Equal("title", value.Title);
+        Assert.Equal("https://example.com", value.Url);
+        Assert.Equal("subtitle text", value.Subtitle);
+        Assert.Equal("https://example.com/thumbnail.jpg", value.ThumbnailUrl);
+        Assert.Equal("confidential", value.InformationProtectionLabel);
     }
     private readonly string TempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
     [Fact]
@@ -138,4 +169,25 @@ public void Serializes()
         var result = sWriter.ToString();
         Assert.Equal("{\"data_path\":\"$.items\",\"file\":\"path_to_file\",\"title\":\"title\",\"url\":\"https://example.com\"}", result);
     }
+
+    [Fact]
+    public void SerializesWithAllProperties()
+    {
+        var value = new OpenApiAiAdaptiveCardExtension
+        {
+            DataPath = "$.items",
+            File = "path_to_file",
+            Title = "title",
+            Url = "https://example.com",
+            Subtitle = "subtitle text",
+            ThumbnailUrl = "https://example.com/thumbnail.jpg",
+            InformationProtectionLabel = "confidential"
+        };
+        using var sWriter = new StringWriter();
+        OpenApiJsonWriter writer = new(sWriter, new OpenApiJsonWriterSettings { Terse = true });
+
+        value.Write(writer, OpenApiSpecVersion.OpenApi3_0);
+        var result = sWriter.ToString();
+        Assert.Equal("{\"data_path\":\"$.items\",\"file\":\"path_to_file\",\"title\":\"title\",\"url\":\"https://example.com\",\"subtitle\":\"subtitle text\",\"thumbnail_url\":\"https://example.com/thumbnail.jpg\",\"information_protection_label\":\"confidential\"}", result);
+    }
 }