Skip to content
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Microsoft.Extensions.AI.Abstractions Release History

## 10.1.1 (NOT YET RELEASED)

- Added `InputCachedTokenCount` and `ReasoningTokenCount` to `UsageDetails`.
- Added constructors to `HostedCodeInterpreterTool`, `HostedFileSearchTool`, `HostedImageGeneratorTool`, `HostedMcpServerTool`,
and `HostedWebSearchTool` that accept a dictionary for `AdditionalProperties`.

## 10.1.0

- Fixed package references for net10.0 asset.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1918,9 +1918,17 @@
{
"Member": "Microsoft.Extensions.AI.HostedCodeInterpreterTool.HostedCodeInterpreterTool();",
"Stage": "Stable"
},
{
"Member": "Microsoft.Extensions.AI.HostedCodeInterpreterTool.HostedCodeInterpreterTool(System.Collections.Generic.IReadOnlyDictionary<string, object?>? additionalProperties);",
"Stage": "Stable"
}
],
"Properties": [
{
"Member": "override System.Collections.Generic.IReadOnlyDictionary<string, object?> Microsoft.Extensions.AI.HostedCodeInterpreterTool.AdditionalProperties { get; }",
"Stage": "Stable"
},
{
"Member": "System.Collections.Generic.IList<Microsoft.Extensions.AI.AIContent>? Microsoft.Extensions.AI.HostedCodeInterpreterTool.Inputs { get; set; }",
"Stage": "Stable"
Expand All @@ -1938,9 +1946,17 @@
{
"Member": "Microsoft.Extensions.AI.HostedFileSearchTool.HostedFileSearchTool();",
"Stage": "Stable"
},
{
"Member": "Microsoft.Extensions.AI.HostedFileSearchTool.HostedFileSearchTool(System.Collections.Generic.IReadOnlyDictionary<string, object?>? additionalProperties);",
"Stage": "Stable"
}
],
"Properties": [
{
"Member": "override System.Collections.Generic.IReadOnlyDictionary<string, object?> Microsoft.Extensions.AI.HostedFileSearchTool.AdditionalProperties { get; }",
"Stage": "Stable"
},
{
"Member": "System.Collections.Generic.IList<Microsoft.Extensions.AI.AIContent>? Microsoft.Extensions.AI.HostedFileSearchTool.Inputs { get; set; }",
"Stage": "Stable"
Expand All @@ -1962,9 +1978,17 @@
{
"Member": "Microsoft.Extensions.AI.HostedWebSearchTool.HostedWebSearchTool();",
"Stage": "Stable"
},
{
"Member": "Microsoft.Extensions.AI.HostedWebSearchTool.HostedWebSearchTool(System.Collections.Generic.IReadOnlyDictionary<string, object?>? additionalProperties);",
"Stage": "Stable"
}
],
"Properties": [
{
"Member": "override System.Collections.Generic.IReadOnlyDictionary<string, object?> Microsoft.Extensions.AI.HostedWebSearchTool.AdditionalProperties { get; }",
"Stage": "Stable"
},
{
"Member": "override string Microsoft.Extensions.AI.HostedWebSearchTool.Name { get; }",
"Stage": "Stable"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,27 @@ namespace Microsoft.Extensions.AI;
/// </remarks>
public class HostedCodeInterpreterTool : AITool
{
/// <summary>Any additional properties associated with the tool.</summary>
private IReadOnlyDictionary<string, object?>? _additionalProperties;

/// <summary>Initializes a new instance of the <see cref="HostedCodeInterpreterTool"/> class.</summary>
public HostedCodeInterpreterTool()
{
}

/// <summary>Initializes a new instance of the <see cref="HostedCodeInterpreterTool"/> class.</summary>
/// <param name="additionalProperties">Any additional properties associated with the tool.</param>
public HostedCodeInterpreterTool(IReadOnlyDictionary<string, object?>? additionalProperties)
{
_additionalProperties = additionalProperties;
}

/// <inheritdoc />
public override string Name => "code_interpreter";

/// <inheritdoc />
public override IReadOnlyDictionary<string, object?> AdditionalProperties => _additionalProperties ?? base.AdditionalProperties;

/// <summary>Gets or sets a collection of <see cref="AIContent"/> to be used as input to the code interpreter tool.</summary>
/// <remarks>
/// Services support different varied kinds of inputs. Most support the IDs of files that are hosted by the service,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,27 @@ namespace Microsoft.Extensions.AI;
/// </remarks>
public class HostedFileSearchTool : AITool
{
/// <summary>Any additional properties associated with the tool.</summary>
private IReadOnlyDictionary<string, object?>? _additionalProperties;

/// <summary>Initializes a new instance of the <see cref="HostedFileSearchTool"/> class.</summary>
public HostedFileSearchTool()
{
}

/// <summary>Initializes a new instance of the <see cref="HostedFileSearchTool"/> class.</summary>
/// <param name="additionalProperties">Any additional properties associated with the tool.</param>
public HostedFileSearchTool(IReadOnlyDictionary<string, object?>? additionalProperties)
{
_additionalProperties = additionalProperties;
}

/// <inheritdoc />
public override string Name => "file_search";

/// <inheritdoc />
public override IReadOnlyDictionary<string, object?> AdditionalProperties => _additionalProperties ?? base.AdditionalProperties;

/// <summary>Gets or sets a collection of <see cref="AIContent"/> to be used as input to the file search tool.</summary>
/// <remarks>
/// If no explicit inputs are provided, the service determines what inputs should be searched. Different services
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.Extensions.AI;
Expand All @@ -13,13 +14,29 @@ namespace Microsoft.Extensions.AI;
[Experimental("MEAI001")]
public class HostedImageGenerationTool : AITool
{
/// <summary>Any additional properties associated with the tool.</summary>
private IReadOnlyDictionary<string, object?>? _additionalProperties;

/// <summary>
/// Initializes a new instance of the <see cref="HostedImageGenerationTool"/> class with the specified options.
/// </summary>
public HostedImageGenerationTool()
{
}

/// <summary>Initializes a new instance of the <see cref="HostedImageGenerationTool"/> class.</summary>
/// <param name="additionalProperties">Any additional properties associated with the tool.</param>
public HostedImageGenerationTool(IReadOnlyDictionary<string, object?>? additionalProperties)
{
_additionalProperties = additionalProperties;
}

/// <inheritdoc />
public override string Name => "image_generation";

/// <inheritdoc />
public override IReadOnlyDictionary<string, object?> AdditionalProperties => _additionalProperties ?? base.AdditionalProperties;

/// <summary>
/// Gets or sets the options used to configure image generation.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ namespace Microsoft.Extensions.AI;
[Experimental("MEAI001")]
public class HostedMcpServerTool : AITool
{
/// <summary>Any additional properties associated with the tool.</summary>
private IReadOnlyDictionary<string, object?>? _additionalProperties;

/// <summary>
/// Initializes a new instance of the <see cref="HostedMcpServerTool"/> class.
/// </summary>
Expand All @@ -27,6 +30,20 @@ public HostedMcpServerTool(string serverName, string serverAddress)
ServerAddress = Throw.IfNullOrWhitespace(serverAddress);
}

/// <summary>
/// Initializes a new instance of the <see cref="HostedMcpServerTool"/> class.
/// </summary>
/// <param name="serverName">The name of the remote MCP server.</param>
/// <param name="serverAddress">The address of the remote MCP server. This may be a URL, or in the case of a service providing built-in MCP servers with known names, it can be such a name.</param>
/// <param name="additionalProperties">Any additional properties associated with the tool.</param>
/// <exception cref="ArgumentNullException"><paramref name="serverName"/> or <paramref name="serverAddress"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException"><paramref name="serverName"/> or <paramref name="serverAddress"/> is empty or composed entirely of whitespace.</exception>
public HostedMcpServerTool(string serverName, string serverAddress, IReadOnlyDictionary<string, object?>? additionalProperties)
: this(serverName, serverAddress)
{
_additionalProperties = additionalProperties;
}

/// <summary>
/// Initializes a new instance of the <see cref="HostedMcpServerTool"/> class.
/// </summary>
Expand All @@ -40,6 +57,21 @@ public HostedMcpServerTool(string serverName, Uri serverUrl)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="HostedMcpServerTool"/> class.
/// </summary>
/// <param name="serverName">The name of the remote MCP server.</param>
/// <param name="serverUrl">The URL of the remote MCP server.</param>
/// <param name="additionalProperties">Any additional properties associated with the tool.</param>
/// <exception cref="ArgumentNullException"><paramref name="serverName"/> or <paramref name="serverUrl"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException"><paramref name="serverName"/> is empty or composed entirely of whitespace.</exception>
/// <exception cref="ArgumentException"><paramref name="serverUrl"/> is not an absolute URL.</exception>
public HostedMcpServerTool(string serverName, Uri serverUrl, IReadOnlyDictionary<string, object?>? additionalProperties)
: this(serverName, ValidateUrl(serverUrl))
{
_additionalProperties = additionalProperties;
}

private static string ValidateUrl(Uri serverUrl)
{
_ = Throw.IfNull(serverUrl);
Expand All @@ -55,6 +87,9 @@ private static string ValidateUrl(Uri serverUrl)
/// <inheritdoc />
public override string Name => "mcp";

/// <inheritdoc />
public override IReadOnlyDictionary<string, object?> AdditionalProperties => _additionalProperties ?? base.AdditionalProperties;

/// <summary>
/// Gets the name of the remote MCP server that is used to identify it.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;

namespace Microsoft.Extensions.AI;

/// <summary>Represents a hosted tool that can be specified to an AI service to enable it to perform web searches.</summary>
Expand All @@ -10,11 +12,24 @@ namespace Microsoft.Extensions.AI;
/// </remarks>
public class HostedWebSearchTool : AITool
{
/// <summary>Any additional properties associated with the tool.</summary>
private IReadOnlyDictionary<string, object?>? _additionalProperties;

/// <summary>Initializes a new instance of the <see cref="HostedWebSearchTool"/> class.</summary>
public HostedWebSearchTool()
{
}

/// <summary>Initializes a new instance of the <see cref="HostedWebSearchTool"/> class.</summary>
/// <param name="additionalProperties">Any additional properties associated with the tool.</param>
public HostedWebSearchTool(IReadOnlyDictionary<string, object?>? additionalProperties)
{
_additionalProperties = additionalProperties;
}

/// <inheritdoc />
public override string Name => "web_search";

/// <inheritdoc />
public override IReadOnlyDictionary<string, object?> AdditionalProperties => _additionalProperties ?? base.AdditionalProperties;
}
7 changes: 7 additions & 0 deletions src/Libraries/Microsoft.Extensions.AI.OpenAI/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Microsoft.Extensions.AI.OpenAI Release History

## 10.1.1-preview.1.? (NOT YET RELEASED)

- Updated to accommodate the additions in `Microsoft.Extensions.AI.Abstractions`.
- Updated the OpenAI Responses and Chat Completion `IChatClient`s to populate `UsageDetails`'s `InputCachedTokenCount` and `ReasoningTokenCount`.
- Updated handling of `HostedWebSearchTool`, `HostedFileSearchTool`, and `HostedImageGenerationTool` to pull OpenAI-specific
options from `AdditionalProperties`.

## 10.1.0-preview.1.25608.1

- Fixed package references for net10.0 asset.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,10 @@ internal static FunctionToolDefinition ToOpenAIAssistantsFunctionToolDefinition(
break;

case HostedFileSearchTool fileSearchTool:
_ = toolsOverride.Add(ToolDefinition.CreateFileSearch(fileSearchTool.MaximumResultCount));
var fst = ToolDefinition.CreateFileSearch(fileSearchTool.MaximumResultCount);
fst.RankingOptions = fileSearchTool.GetProperty<FileSearchRankingOptions>(nameof(FileSearchToolDefinition.RankingOptions));
_ = toolsOverride.Add(fst);

if (fileSearchTool.Inputs is { Count: > 0 } fileSearchInputs)
{
foreach (var input in fileSearchInputs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ internal static void PatchModelIfNotSet(ref JsonPatch patch, string? modelId)
}
}

/// <summary>Gets the typed property of the specified name from the tool's <see cref="AITool.AdditionalProperties"/>.</summary>
internal static T? GetProperty<T>(this AITool tool, string name) =>
tool.AdditionalProperties?.TryGetValue(name, out object? value) is true && value is T tValue ? tValue : default;

/// <summary>Used to create the JSON payload for an OpenAI tool description.</summary>
internal sealed class ToolJson
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,25 +544,17 @@ void IDisposable.Dispose()
return ToResponseTool(aiFunction, options);

case HostedWebSearchTool webSearchTool:
WebSearchToolLocation? location = null;
if (webSearchTool.AdditionalProperties.TryGetValue(nameof(WebSearchToolLocation), out object? objLocation))
{
location = objLocation as WebSearchToolLocation;
}

WebSearchToolContextSize? size = null;
if (webSearchTool.AdditionalProperties.TryGetValue(nameof(WebSearchToolContextSize), out object? objSize) &&
objSize is WebSearchToolContextSize)
{
size = (WebSearchToolContextSize)objSize;
}

return ResponseTool.CreateWebSearchTool(location, size);
return ResponseTool.CreateWebSearchTool(
webSearchTool.GetProperty<WebSearchToolLocation?>(nameof(WebSearchTool.UserLocation)),
webSearchTool.GetProperty<WebSearchToolContextSize?>(nameof(WebSearchTool.SearchContextSize)),
webSearchTool.GetProperty<WebSearchToolFilters?>(nameof(WebSearchTool.Filters)));

case HostedFileSearchTool fileSearchTool:
return ResponseTool.CreateFileSearchTool(
fileSearchTool.Inputs?.OfType<HostedVectorStoreContent>().Select(c => c.VectorStoreId) ?? [],
fileSearchTool.MaximumResultCount);
fileSearchTool.MaximumResultCount,
fileSearchTool.GetProperty<FileSearchToolRankingOptions?>(nameof(FileSearchTool.RankingOptions)),
fileSearchTool.GetProperty<BinaryData?>(nameof(FileSearchTool.Filters)));

case HostedImageGenerationTool imageGenerationTool:
return ToImageResponseTool(imageGenerationTool);
Expand Down Expand Up @@ -642,36 +634,31 @@ internal static FunctionTool ToResponseTool(AIFunctionDeclaration aiFunction, Ch

internal static ImageGenerationTool ToImageResponseTool(HostedImageGenerationTool imageGenerationTool)
{
ImageGenerationTool result = new();
ImageGenerationOptions? imageGenerationOptions = imageGenerationTool.Options;

// Model: Image generation model
result.Model = imageGenerationOptions?.ModelId;

// Size: Image dimensions (e.g., 1024x1024, 1024x1536)
if (imageGenerationOptions?.ImageSize is not null)
{
result.Size = new ImageGenerationToolSize(
imageGenerationOptions.ImageSize.Value.Width,
imageGenerationOptions.ImageSize.Value.Height);
}
ImageGenerationOptions? options = imageGenerationTool.Options;

// OutputFileFormat: File output format
if (imageGenerationOptions?.MediaType is not null)
return new()
{
result.OutputFileFormat = imageGenerationOptions.MediaType switch
{
"image/png" => ImageGenerationToolOutputFileFormat.Png,
"image/jpeg" => ImageGenerationToolOutputFileFormat.Jpeg,
"image/webp" => ImageGenerationToolOutputFileFormat.Webp,
_ => null,
};
}

// PartialImageCount: Whether to return partial images during generation
result.PartialImageCount ??= imageGenerationOptions?.StreamingCount;

return result;
Background = imageGenerationTool.GetProperty<ImageGenerationToolBackground?>(nameof(ImageGenerationTool.Background)),
InputFidelity = imageGenerationTool.GetProperty<ImageGenerationToolInputFidelity?>(nameof(ImageGenerationTool.InputFidelity)),
InputImageMask = imageGenerationTool.GetProperty<ImageGenerationToolInputImageMask?>(nameof(ImageGenerationTool.InputImageMask)),
Model = options?.ModelId,
ModerationLevel = imageGenerationTool.GetProperty<ImageGenerationToolModerationLevel?>(nameof(ImageGenerationTool.ModerationLevel)),
OutputCompressionFactor = imageGenerationTool.GetProperty<int?>(nameof(ImageGenerationTool.OutputCompressionFactor)),
OutputFileFormat = options?.MediaType is not null ?
options.MediaType switch
{
"image/png" => ImageGenerationToolOutputFileFormat.Png,
"image/jpeg" => ImageGenerationToolOutputFileFormat.Jpeg,
"image/webp" => ImageGenerationToolOutputFileFormat.Webp,
_ => null,
} :
null,
PartialImageCount = options?.StreamingCount,
Quality = imageGenerationTool.GetProperty<ImageGenerationToolQuality?>(nameof(ImageGenerationTool.Quality)),
Size = options?.ImageSize is not null ?
new ImageGenerationToolSize(options.ImageSize.Value.Width, options.ImageSize.Value.Height) :
null
};
}

/// <summary>Creates a <see cref="ChatRole"/> from a <see cref="MessageRole"/>.</summary>
Expand Down
4 changes: 4 additions & 0 deletions src/Libraries/Microsoft.Extensions.AI/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Microsoft.Extensions.AI Release History

## 10.1.1 (NOT YET RELEASED)

- Updated to accommodate the additions in `Microsoft.Extensions.AI.Abstractions`.

## 10.1.0

- Fixed package references for net10.0 asset.
Expand Down
Loading
Loading