Skip to content

Commit 689ae13

Browse files
jozkeeCopilot
andauthored
Stabilize ImageGeneration content types and HostedImageGenerationTool (#7476)
* Stabilize ImageGeneration content types and HostedImageGenerationTool Remove [Experimental] from ImageGenerationToolCallContent, ImageGenerationToolResultContent, and HostedImageGenerationTool so IChatClient consumers can use them without MEAI001 suppression. - Uncomment [JsonDerivedType] on AIContent, ToolCallContent, and ToolResultContent for the two content types - Remove corresponding AddAIContentTypeChain runtime workarounds and [JsonSerializable] entries from AIJsonUtilities.Defaults - Update API baseline (Experimental -> Stable) - Add targeted #pragma for ImageGenerationOptions in HostedImageGenerationToolTests (still experimental) - Add Stabilization.Tests project that builds without MEAI001 to verify no experimental leakage Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Stabilize ImageGenerationOptions and ImageGenerationResponseFormat Remove [Experimental] from ImageGenerationOptions and ImageGenerationResponseFormat, update API baselines, and remove the #pragma workaround in HostedImageGenerationToolTests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove unused ImageGenerationResponseFormat.Hosted enum member Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR feedback: fix XML docs and add ProjectUnderTest Fix misleading XML docs on ImageGenerationToolResultContent that described it as a tool call rather than a tool result. Add ProjectUnderTest attribute to Stabilization.Tests project references. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add API compat suppression for removed ImageGenerationResponseFormat.Hosted The member was experimental but still present in the 10.4.0 baseline binary. Suppress CP0002 for all target frameworks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add Hosted enum value back as experimental and add image generation integration test - Restore ImageGenerationResponseFormat.Hosted with [Experimental] attribute - Add UseImageGeneration_ProducesImageContent integration test for Responses API image generation tool Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Remove CompatibilitySuppressions.xml for Hosted enum value The CP0002 suppressions are no longer needed since Hosted was restored. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add ImageGenerationResponseFormat.Hosted test and api baseline back --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent bc2258f commit 689ae13

12 files changed

Lines changed: 128 additions & 57 deletions

File tree

src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/AIContent.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ namespace Microsoft.Extensions.AI;
2626
[JsonDerivedType(typeof(ToolApprovalResponseContent), typeDiscriminator: "toolApprovalResponse")]
2727
[JsonDerivedType(typeof(McpServerToolCallContent), typeDiscriminator: "mcpServerToolCall")]
2828
[JsonDerivedType(typeof(McpServerToolResultContent), typeDiscriminator: "mcpServerToolResult")]
29+
[JsonDerivedType(typeof(ImageGenerationToolCallContent), typeDiscriminator: "imageGenerationToolCall")]
30+
[JsonDerivedType(typeof(ImageGenerationToolResultContent), typeDiscriminator: "imageGenerationToolResult")]
2931

3032
// These should be added in once they're no longer [Experimental]. If they're included while still
3133
// experimental, any JsonSerializerContext that includes AIContent will incur errors about using
@@ -34,8 +36,6 @@ namespace Microsoft.Extensions.AI;
3436
// as well as the [JsonSerializable] attributes for them on the JsonContext should be removed.
3537
// [JsonDerivedType(typeof(CodeInterpreterToolCallContent), typeDiscriminator: "codeInterpreterToolCall")]
3638
// [JsonDerivedType(typeof(CodeInterpreterToolResultContent), typeDiscriminator: "codeInterpreterToolResult")]
37-
// [JsonDerivedType(typeof(ImageGenerationToolCallContent), typeDiscriminator: "imageGenerationToolCall")]
38-
// [JsonDerivedType(typeof(ImageGenerationToolResultContent), typeDiscriminator: "imageGenerationToolResult")]
3939
// [JsonDerivedType(typeof(WebSearchToolCallContent), typeDiscriminator: "webSearchToolCall")]
4040
// [JsonDerivedType(typeof(WebSearchToolResultContent), typeDiscriminator: "webSearchToolResult")]
4141

src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ImageGenerationToolCallContent.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.Diagnostics.CodeAnalysis;
5-
using Microsoft.Shared.DiagnosticIds;
6-
74
namespace Microsoft.Extensions.AI;
85

96
/// <summary>
107
/// Represents the invocation of an image generation tool call by a hosted service.
118
/// </summary>
12-
[Experimental(DiagnosticIds.Experiments.AIImageGeneration, UrlFormat = DiagnosticIds.UrlFormat)]
139
public sealed class ImageGenerationToolCallContent : ToolCallContent
1410
{
1511
/// <summary>

src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ImageGenerationToolResultContent.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,16 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections.Generic;
5-
using System.Diagnostics.CodeAnalysis;
6-
using Microsoft.Shared.DiagnosticIds;
75

86
namespace Microsoft.Extensions.AI;
97

108
/// <summary>
11-
/// Represents an image generation tool call invocation by a hosted service.
9+
/// Represents the result of an image generation tool invocation by a hosted service.
1210
/// </summary>
1311
/// <remarks>
14-
/// This content type represents when a hosted AI service invokes an image generation tool.
15-
/// It is informational only and represents the call itself, not the result.
12+
/// This content type is used to represent the result of an image generation tool invocation by a hosted service.
13+
/// It is informational only.
1614
/// </remarks>
17-
[Experimental(DiagnosticIds.Experiments.AIImageGeneration, UrlFormat = DiagnosticIds.UrlFormat)]
1815
public sealed class ImageGenerationToolResultContent : ToolResultContent
1916
{
2017
/// <summary>

src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolCallContent.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace Microsoft.Extensions.AI;
1212
/// </summary>
1313
[JsonDerivedType(typeof(FunctionCallContent), "functionCall")]
1414
[JsonDerivedType(typeof(McpServerToolCallContent), "mcpServerToolCall")]
15+
[JsonDerivedType(typeof(ImageGenerationToolCallContent), "imageGenerationToolCall")]
1516

1617
// Same as in AIContent.
1718
// These should be added in once they're no longer [Experimental]. If they're included while still
@@ -20,7 +21,6 @@ namespace Microsoft.Extensions.AI;
2021
// these lines should be uncommented and the corresponding lines in AIJsonUtilities.CreateDefaultOptions
2122
// as well as the [JsonSerializable] attributes for them on the JsonContext should be removed.
2223
// [JsonDerivedType(typeof(CodeInterpreterToolCallContent), "codeInterpreterToolCall")]
23-
// [JsonDerivedType(typeof(ImageGenerationToolCallContent), "imageGenerationToolCall")]
2424
// [JsonDerivedType(typeof(WebSearchToolCallContent), "webSearchToolCall")]
2525
public class ToolCallContent : AIContent
2626
{

src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolResultContent.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace Microsoft.Extensions.AI;
1212
/// </summary>
1313
[JsonDerivedType(typeof(FunctionResultContent), "functionResult")]
1414
[JsonDerivedType(typeof(McpServerToolResultContent), "mcpServerToolResult")]
15+
[JsonDerivedType(typeof(ImageGenerationToolResultContent), "imageGenerationToolResult")]
1516

1617
// Same as in AIContent.
1718
// These should be added in once they're no longer [Experimental]. If they're included while still
@@ -20,7 +21,6 @@ namespace Microsoft.Extensions.AI;
2021
// these lines should be uncommented and the corresponding lines in AIJsonUtilities.CreateDefaultOptions
2122
// as well as the [JsonSerializable] attributes for them on the JsonContext should be removed.
2223
// [JsonDerivedType(typeof(CodeInterpreterToolResultContent), "codeInterpreterToolResult")]
23-
// [JsonDerivedType(typeof(ImageGenerationToolResultContent), "imageGenerationToolResult")]
2424
// [JsonDerivedType(typeof(WebSearchToolResultContent), "webSearchToolResult")]
2525
public class ToolResultContent : AIContent
2626
{

src/Libraries/Microsoft.Extensions.AI.Abstractions/Image/ImageGenerationOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
namespace Microsoft.Extensions.AI;
1111

1212
/// <summary>Represents the options for an image generation request.</summary>
13-
[Experimental(DiagnosticIds.Experiments.AIImageGeneration, UrlFormat = DiagnosticIds.UrlFormat)]
1413
public class ImageGenerationOptions
1514
{
1615
/// <summary>Initializes a new instance of the <see cref="ImageGenerationOptions"/> class.</summary>
@@ -101,7 +100,6 @@ protected ImageGenerationOptions(ImageGenerationOptions? other)
101100
/// <remarks>
102101
/// Not all implementations support all response formats and this value might be ignored by the implementation if not supported.
103102
/// </remarks>
104-
[Experimental(DiagnosticIds.Experiments.AIImageGeneration, UrlFormat = DiagnosticIds.UrlFormat)]
105103
public enum ImageGenerationResponseFormat
106104
{
107105
/// <summary>
@@ -117,5 +115,7 @@ public enum ImageGenerationResponseFormat
117115
/// <summary>
118116
/// The generated image is returned as a hosted resource identifier, which can be used to retrieve the image later.
119117
/// </summary>
118+
[Experimental(DiagnosticIds.Experiments.AIImageGeneration, UrlFormat = DiagnosticIds.UrlFormat)]
120119
Hosted,
120+
121121
}

src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
{
2-
"Name": "Microsoft.Extensions.AI.Abstractions, Version=10.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
1+
{
2+
"Name": "Microsoft.Extensions.AI.Abstractions, Version=10.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35",
33
"Types": [
44
{
55
"Type": "sealed class Microsoft.Extensions.AI.AdditionalPropertiesDictionary : Microsoft.Extensions.AI.AdditionalPropertiesDictionary<object?>",
@@ -2521,29 +2521,29 @@
25212521
},
25222522
{
25232523
"Type": "class Microsoft.Extensions.AI.HostedImageGenerationTool : Microsoft.Extensions.AI.AITool",
2524-
"Stage": "Experimental",
2524+
"Stage": "Stable",
25252525
"Methods": [
25262526
{
25272527
"Member": "Microsoft.Extensions.AI.HostedImageGenerationTool.HostedImageGenerationTool();",
2528-
"Stage": "Experimental"
2528+
"Stage": "Stable"
25292529
},
25302530
{
25312531
"Member": "Microsoft.Extensions.AI.HostedImageGenerationTool.HostedImageGenerationTool(System.Collections.Generic.IReadOnlyDictionary<string, object?>? additionalProperties);",
2532-
"Stage": "Experimental"
2532+
"Stage": "Stable"
25332533
}
25342534
],
25352535
"Properties": [
25362536
{
25372537
"Member": "override System.Collections.Generic.IReadOnlyDictionary<string, object?> Microsoft.Extensions.AI.HostedImageGenerationTool.AdditionalProperties { get; }",
2538-
"Stage": "Experimental"
2538+
"Stage": "Stable"
25392539
},
25402540
{
25412541
"Member": "override string Microsoft.Extensions.AI.HostedImageGenerationTool.Name { get; }",
2542-
"Stage": "Experimental"
2542+
"Stage": "Stable"
25432543
},
25442544
{
25452545
"Member": "Microsoft.Extensions.AI.ImageGenerationOptions? Microsoft.Extensions.AI.HostedImageGenerationTool.Options { get; set; }",
2546-
"Stage": "Experimental"
2546+
"Stage": "Stable"
25472547
}
25482548
]
25492549
},
@@ -2853,53 +2853,53 @@
28532853
},
28542854
{
28552855
"Type": "class Microsoft.Extensions.AI.ImageGenerationOptions",
2856-
"Stage": "Experimental",
2856+
"Stage": "Stable",
28572857
"Methods": [
28582858
{
28592859
"Member": "Microsoft.Extensions.AI.ImageGenerationOptions.ImageGenerationOptions();",
2860-
"Stage": "Experimental"
2860+
"Stage": "Stable"
28612861
},
28622862
{
28632863
"Member": "Microsoft.Extensions.AI.ImageGenerationOptions.ImageGenerationOptions(Microsoft.Extensions.AI.ImageGenerationOptions? other);",
2864-
"Stage": "Experimental"
2864+
"Stage": "Stable"
28652865
},
28662866
{
28672867
"Member": "virtual Microsoft.Extensions.AI.ImageGenerationOptions Microsoft.Extensions.AI.ImageGenerationOptions.Clone();",
2868-
"Stage": "Experimental"
2868+
"Stage": "Stable"
28692869
}
28702870
],
28712871
"Properties": [
28722872
{
28732873
"Member": "Microsoft.Extensions.AI.AdditionalPropertiesDictionary? Microsoft.Extensions.AI.ImageGenerationOptions.AdditionalProperties { get; set; }",
2874-
"Stage": "Experimental"
2874+
"Stage": "Stable"
28752875
},
28762876
{
28772877
"Member": "int? Microsoft.Extensions.AI.ImageGenerationOptions.Count { get; set; }",
2878-
"Stage": "Experimental"
2878+
"Stage": "Stable"
28792879
},
28802880
{
28812881
"Member": "System.Drawing.Size? Microsoft.Extensions.AI.ImageGenerationOptions.ImageSize { get; set; }",
2882-
"Stage": "Experimental"
2882+
"Stage": "Stable"
28832883
},
28842884
{
28852885
"Member": "string? Microsoft.Extensions.AI.ImageGenerationOptions.MediaType { get; set; }",
2886-
"Stage": "Experimental"
2886+
"Stage": "Stable"
28872887
},
28882888
{
28892889
"Member": "string? Microsoft.Extensions.AI.ImageGenerationOptions.ModelId { get; set; }",
2890-
"Stage": "Experimental"
2890+
"Stage": "Stable"
28912891
},
28922892
{
28932893
"Member": "System.Func<Microsoft.Extensions.AI.IImageGenerator, object?>? Microsoft.Extensions.AI.ImageGenerationOptions.RawRepresentationFactory { get; set; }",
2894-
"Stage": "Experimental"
2894+
"Stage": "Stable"
28952895
},
28962896
{
28972897
"Member": "Microsoft.Extensions.AI.ImageGenerationResponseFormat? Microsoft.Extensions.AI.ImageGenerationOptions.ResponseFormat { get; set; }",
2898-
"Stage": "Experimental"
2898+
"Stage": "Stable"
28992899
},
29002900
{
29012901
"Member": "int? Microsoft.Extensions.AI.ImageGenerationOptions.StreamingCount { get; set; }",
2902-
"Stage": "Experimental"
2902+
"Stage": "Stable"
29032903
}
29042904
]
29052905
},
@@ -2961,17 +2961,17 @@
29612961
},
29622962
{
29632963
"Type": "enum Microsoft.Extensions.AI.ImageGenerationResponseFormat",
2964-
"Stage": "Experimental",
2964+
"Stage": "Stable",
29652965
"Methods": [
29662966
{
29672967
"Member": "Microsoft.Extensions.AI.ImageGenerationResponseFormat.ImageGenerationResponseFormat();",
2968-
"Stage": "Experimental"
2968+
"Stage": "Stable"
29692969
}
29702970
],
29712971
"Fields": [
29722972
{
29732973
"Member": "const Microsoft.Extensions.AI.ImageGenerationResponseFormat Microsoft.Extensions.AI.ImageGenerationResponseFormat.Data",
2974-
"Stage": "Experimental",
2974+
"Stage": "Stable",
29752975
"Value": "1"
29762976
},
29772977
{
@@ -2981,34 +2981,34 @@
29812981
},
29822982
{
29832983
"Member": "const Microsoft.Extensions.AI.ImageGenerationResponseFormat Microsoft.Extensions.AI.ImageGenerationResponseFormat.Uri",
2984-
"Stage": "Experimental",
2984+
"Stage": "Stable",
29852985
"Value": "0"
29862986
}
29872987
]
29882988
},
29892989
{
29902990
"Type": "sealed class Microsoft.Extensions.AI.ImageGenerationToolCallContent : Microsoft.Extensions.AI.ToolCallContent",
2991-
"Stage": "Experimental",
2991+
"Stage": "Stable",
29922992
"Methods": [
29932993
{
29942994
"Member": "Microsoft.Extensions.AI.ImageGenerationToolCallContent.ImageGenerationToolCallContent(string callId);",
2995-
"Stage": "Experimental"
2995+
"Stage": "Stable"
29962996
}
29972997
]
29982998
},
29992999
{
30003000
"Type": "sealed class Microsoft.Extensions.AI.ImageGenerationToolResultContent : Microsoft.Extensions.AI.ToolResultContent",
3001-
"Stage": "Experimental",
3001+
"Stage": "Stable",
30023002
"Methods": [
30033003
{
30043004
"Member": "Microsoft.Extensions.AI.ImageGenerationToolResultContent.ImageGenerationToolResultContent(string callId);",
3005-
"Stage": "Experimental"
3005+
"Stage": "Stable"
30063006
}
30073007
],
30083008
"Properties": [
30093009
{
30103010
"Member": "System.Collections.Generic.IList<Microsoft.Extensions.AI.AIContent>? Microsoft.Extensions.AI.ImageGenerationToolResultContent.Outputs { get; set; }",
3011-
"Stage": "Experimental"
3011+
"Stage": "Stable"
30123012
}
30133013
]
30143014
},
@@ -4843,4 +4843,4 @@
48434843
]
48444844
}
48454845
]
4846-
}
4846+
}

src/Libraries/Microsoft.Extensions.AI.Abstractions/Tools/HostedImageGenerationTool.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections.Generic;
5-
using System.Diagnostics.CodeAnalysis;
6-
using Microsoft.Shared.DiagnosticIds;
75

86
namespace Microsoft.Extensions.AI;
97

@@ -12,7 +10,6 @@ namespace Microsoft.Extensions.AI;
1210
/// This tool does not itself implement image generation. It is a marker that can be used to inform a service
1311
/// that the service is allowed to perform image generation if the service is capable of doing so.
1412
/// </remarks>
15-
[Experimental(DiagnosticIds.Experiments.AIImageGeneration, UrlFormat = DiagnosticIds.UrlFormat)]
1613
public class HostedImageGenerationTool : AITool
1714
{
1815
/// <summary>Any additional properties associated with the tool.</summary>

src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Defaults.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ private static JsonSerializerOptions CreateDefaultOptions()
5353
// Once they're no longer [Experimental] and added as [JsonDerivedType] on AIContent, these lines should be removed.
5454
AddAIContentTypeChain(options, typeof(CodeInterpreterToolCallContent), typeDiscriminatorId: "codeInterpreterToolCall", checkBuiltIn: false);
5555
AddAIContentTypeChain(options, typeof(CodeInterpreterToolResultContent), typeDiscriminatorId: "codeInterpreterToolResult", checkBuiltIn: false);
56-
AddAIContentTypeChain(options, typeof(ImageGenerationToolCallContent), typeDiscriminatorId: "imageGenerationToolCall", checkBuiltIn: false);
57-
AddAIContentTypeChain(options, typeof(ImageGenerationToolResultContent), typeDiscriminatorId: "imageGenerationToolResult", checkBuiltIn: false);
5856
AddAIContentTypeChain(options, typeof(WebSearchToolCallContent), typeDiscriminatorId: "webSearchToolCall", checkBuiltIn: false);
5957
AddAIContentTypeChain(options, typeof(WebSearchToolResultContent), typeDiscriminatorId: "webSearchToolResult", checkBuiltIn: false);
6058

@@ -123,8 +121,6 @@ private static JsonSerializerOptions CreateDefaultOptions()
123121
// and are included via [JsonDerivedType] on AIContent.
124122
[JsonSerializable(typeof(CodeInterpreterToolCallContent))]
125123
[JsonSerializable(typeof(CodeInterpreterToolResultContent))]
126-
[JsonSerializable(typeof(ImageGenerationToolCallContent))]
127-
[JsonSerializable(typeof(ImageGenerationToolResultContent))]
128124
[JsonSerializable(typeof(WebSearchToolCallContent))]
129125
[JsonSerializable(typeof(WebSearchToolResultContent))]
130126
[JsonSerializable(typeof(ResponseContinuationToken))]

src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIImageGenerator.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,6 @@ private OpenAI.Images.ImageGenerationOptions ToOpenAIImageGenerationOptions(Imag
179179
{
180180
ImageGenerationResponseFormat.Uri => GeneratedImageFormat.Uri,
181181
ImageGenerationResponseFormat.Data => GeneratedImageFormat.Bytes,
182-
183-
// ImageGenerationResponseFormat.Hosted not supported by ImageGenerator, however other OpenAI API support file IDs.
184182
_ => (GeneratedImageFormat?)null
185183
};
186184

@@ -214,8 +212,6 @@ private ImageEditOptions ToOpenAIImageEditOptions(ImageGenerationOptions? option
214212
{
215213
ImageGenerationResponseFormat.Uri => GeneratedImageFormat.Uri,
216214
ImageGenerationResponseFormat.Data => GeneratedImageFormat.Bytes,
217-
218-
// ImageGenerationResponseFormat.Hosted not supported by ImageGenerator, however other OpenAI API support file IDs.
219215
_ => (GeneratedImageFormat?)null
220216
};
221217

0 commit comments

Comments
 (0)