chore: import upstream snapshot with attribution
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.PowerFx;
|
||||
using Microsoft.PowerFx.Types;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="BoolExpression"/>.
|
||||
/// </summary>
|
||||
internal static class BoolExpressionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Evaluates the given <see cref="BoolExpression"/> using the provided <see cref="RecalcEngine"/>.
|
||||
/// </summary>
|
||||
/// <param name="expression">Expression to evaluate.</param>
|
||||
/// <param name="engine">Recalc engine to use for evaluation.</param>
|
||||
/// <returns>The evaluated boolean value, or null if the expression is null or cannot be evaluated.</returns>
|
||||
internal static bool? Eval(this BoolExpression? expression, RecalcEngine? engine)
|
||||
{
|
||||
if (expression is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expression.IsLiteral)
|
||||
{
|
||||
return expression.LiteralValue;
|
||||
}
|
||||
|
||||
if (engine is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expression.IsExpression)
|
||||
{
|
||||
return engine.Eval(expression.ExpressionText!).AsBoolean();
|
||||
}
|
||||
else if (expression.IsVariableReference)
|
||||
{
|
||||
var formulaValue = engine.Eval(expression.VariableReference!.VariableName);
|
||||
if (formulaValue is BooleanValue booleanValue)
|
||||
{
|
||||
return booleanValue.Value;
|
||||
}
|
||||
|
||||
if (formulaValue is StringValue stringValue && bool.TryParse(stringValue.Value, out bool result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="CodeInterpreterTool"/>.
|
||||
/// </summary>
|
||||
internal static class CodeInterpreterToolExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a <see cref="HostedCodeInterpreterTool"/> from a <see cref="CodeInterpreterTool"/>.
|
||||
/// </summary>
|
||||
/// <param name="tool">Instance of <see cref="CodeInterpreterTool"/></param>
|
||||
internal static HostedCodeInterpreterTool AsCodeInterpreterTool(this CodeInterpreterTool tool)
|
||||
{
|
||||
Throw.IfNull(tool);
|
||||
|
||||
return new HostedCodeInterpreterTool();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="FileSearchTool"/>.
|
||||
/// </summary>
|
||||
internal static class FileSearchToolExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a <see cref="HostedFileSearchTool"/> from a <see cref="FileSearchTool"/>.
|
||||
/// </summary>
|
||||
/// <param name="tool">Instance of <see cref="FileSearchTool"/></param>
|
||||
internal static HostedFileSearchTool CreateFileSearchTool(this FileSearchTool tool)
|
||||
{
|
||||
Throw.IfNull(tool);
|
||||
|
||||
return new HostedFileSearchTool()
|
||||
{
|
||||
MaximumResultCount = (int?)tool.MaximumResultCount?.LiteralValue,
|
||||
Inputs = tool.VectorStoreIds?.LiteralValue.Select(id => (AIContent)new HostedVectorStoreContent(id)).ToList(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="InvokeClientTaskAction"/>.
|
||||
/// </summary>
|
||||
internal static class FunctionToolExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a <see cref="AIFunctionDeclaration"/> from a <see cref="InvokeClientTaskAction"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If a matching function already exists in the provided list, it will be returned.
|
||||
/// Otherwise, a new function declaration will be created.
|
||||
/// </remarks>
|
||||
/// <param name="tool">Instance of <see cref="InvokeClientTaskAction"/></param>
|
||||
/// <param name="functions">Instance of <see cref="IList{AIFunction}"/></param>
|
||||
internal static AITool CreateOrGetAITool(this InvokeClientTaskAction tool, IList<AIFunction>? functions)
|
||||
{
|
||||
Throw.IfNull(tool);
|
||||
Throw.IfNull(tool.Name);
|
||||
|
||||
// use the tool from the provided list if it exists
|
||||
if (functions is not null)
|
||||
{
|
||||
var function = functions.FirstOrDefault(f => tool.Matches(f));
|
||||
|
||||
if (function is not null)
|
||||
{
|
||||
return function;
|
||||
}
|
||||
}
|
||||
|
||||
return AIFunctionFactory.CreateDeclaration(
|
||||
name: tool.Name,
|
||||
description: tool.Description,
|
||||
jsonSchema: tool.ClientActionInputSchema?.GetSchema() ?? s_defaultSchema);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a <see cref="InvokeClientTaskAction"/> matches an <see cref="AITool"/>.
|
||||
/// </summary>
|
||||
/// <param name="tool">Instance of <see cref="InvokeClientTaskAction"/></param>
|
||||
/// <param name="aiFunc">Instance of <see cref="AIFunction"/></param>
|
||||
internal static bool Matches(this InvokeClientTaskAction tool, AIFunction aiFunc)
|
||||
{
|
||||
Throw.IfNull(tool);
|
||||
Throw.IfNull(aiFunc);
|
||||
|
||||
return tool.Name == aiFunc.Name;
|
||||
}
|
||||
|
||||
private static readonly JsonElement s_defaultSchema = JsonDocument.Parse("{\"type\":\"object\",\"properties\":{},\"additionalProperties\":false}").RootElement;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Globalization;
|
||||
using Microsoft.PowerFx;
|
||||
using Microsoft.PowerFx.Types;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IntExpression"/>.
|
||||
/// </summary>
|
||||
internal static class IntExpressionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Evaluates the given <see cref="IntExpression"/> using the provided <see cref="RecalcEngine"/>.
|
||||
/// </summary>
|
||||
/// <param name="expression">Expression to evaluate.</param>
|
||||
/// <param name="engine">Recalc engine to use for evaluation.</param>
|
||||
/// <returns>The evaluated integer value, or null if the expression is null or cannot be evaluated.</returns>
|
||||
internal static long? Eval(this IntExpression? expression, RecalcEngine? engine)
|
||||
{
|
||||
if (expression is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expression.IsLiteral)
|
||||
{
|
||||
return expression.LiteralValue;
|
||||
}
|
||||
|
||||
if (engine is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expression.IsExpression)
|
||||
{
|
||||
return (long)engine.Eval(expression.ExpressionText!).AsDouble();
|
||||
}
|
||||
else if (expression.IsVariableReference)
|
||||
{
|
||||
var formulaValue = engine.Eval(expression.VariableReference!.VariableName);
|
||||
if (formulaValue is NumberValue numberValue)
|
||||
{
|
||||
return (long)numberValue.Value;
|
||||
}
|
||||
|
||||
if (formulaValue is StringValue stringValue && int.TryParse(stringValue.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="McpServerToolApprovalMode"/>.
|
||||
/// </summary>
|
||||
internal static class McpServerToolApprovalModeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a <see cref="McpServerToolApprovalMode"/> to a <see cref="HostedMcpServerToolApprovalMode"/>.
|
||||
/// </summary>
|
||||
/// <param name="mode">Instance of <see cref="McpServerToolApprovalMode"/></param>
|
||||
internal static HostedMcpServerToolApprovalMode AsHostedMcpServerToolApprovalMode(this McpServerToolApprovalMode mode)
|
||||
{
|
||||
return mode switch
|
||||
{
|
||||
McpServerToolNeverRequireApprovalMode => HostedMcpServerToolApprovalMode.NeverRequire,
|
||||
McpServerToolAlwaysRequireApprovalMode => HostedMcpServerToolApprovalMode.AlwaysRequire,
|
||||
McpServerToolRequireSpecificApprovalMode specificMode =>
|
||||
HostedMcpServerToolApprovalMode.RequireSpecific(
|
||||
specificMode?.AlwaysRequireApprovalToolNames?.LiteralValue ?? [],
|
||||
specificMode?.NeverRequireApprovalToolNames?.LiteralValue ?? []
|
||||
),
|
||||
_ => HostedMcpServerToolApprovalMode.AlwaysRequire,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="McpServerTool"/>.
|
||||
/// </summary>
|
||||
internal static class McpServerToolExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a <see cref="HostedMcpServerTool"/> from a <see cref="McpServerTool"/>.
|
||||
/// </summary>
|
||||
/// <param name="tool">Instance of <see cref="McpServerTool"/></param>
|
||||
internal static HostedMcpServerTool CreateHostedMcpTool(this McpServerTool tool)
|
||||
{
|
||||
Throw.IfNull(tool);
|
||||
Throw.IfNull(tool.ServerName?.LiteralValue);
|
||||
Throw.IfNull(tool.Connection);
|
||||
|
||||
var connection = tool.Connection as AnonymousConnection ?? throw new ArgumentException("Only AnonymousConnection is supported for MCP Server Tool connections.", nameof(tool));
|
||||
var serverUrl = connection.Endpoint?.LiteralValue;
|
||||
Throw.IfNullOrEmpty(serverUrl, nameof(connection.Endpoint));
|
||||
|
||||
return new HostedMcpServerTool(tool.ServerName.LiteralValue, serverUrl)
|
||||
{
|
||||
ServerDescription = tool.ServerDescription?.LiteralValue,
|
||||
AllowedTools = tool.AllowedTools?.LiteralValue,
|
||||
ApprovalMode = tool.ApprovalMode?.AsHostedMcpServerToolApprovalMode(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="ModelOptions"/>.
|
||||
/// </summary>
|
||||
internal static class ModelOptionsExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the 'chatToolMode' property from a <see cref="ModelOptions"/> to a <see cref="ChatToolMode"/>.
|
||||
/// </summary>
|
||||
/// <param name="modelOptions">Instance of <see cref="ModelOptions"/></param>
|
||||
internal static ChatToolMode? AsChatToolMode(this ModelOptions modelOptions)
|
||||
{
|
||||
Throw.IfNull(modelOptions);
|
||||
|
||||
var mode = modelOptions.ExtensionData?.GetPropertyOrNull<StringDataValue>(InitializablePropertyPath.Create("chatToolMode"))?.Value;
|
||||
if (mode is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return mode switch
|
||||
{
|
||||
"auto" => ChatToolMode.Auto,
|
||||
"none" => ChatToolMode.None,
|
||||
"require_any" => ChatToolMode.RequireAny,
|
||||
_ => ChatToolMode.RequireSpecific(mode),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the 'additional_properties' property from a <see cref="ModelOptions"/>.
|
||||
/// </summary>
|
||||
/// <param name="modelOptions">Instance of <see cref="ModelOptions"/></param>
|
||||
/// <param name="excludedProperties">List of properties which should not be included in additional properties.</param>
|
||||
internal static AdditionalPropertiesDictionary? GetAdditionalProperties(this ModelOptions modelOptions, string[] excludedProperties)
|
||||
{
|
||||
Throw.IfNull(modelOptions);
|
||||
|
||||
var options = modelOptions.ExtensionData;
|
||||
if (options is null || options.Properties.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var additionalProperties = options.Properties
|
||||
.Where(kvp => !excludedProperties.Contains(kvp.Key))
|
||||
.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToObject());
|
||||
|
||||
if (additionalProperties is null || additionalProperties.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new AdditionalPropertiesDictionary(additionalProperties);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Globalization;
|
||||
using Microsoft.PowerFx;
|
||||
using Microsoft.PowerFx.Types;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="NumberExpression"/>.
|
||||
/// </summary>
|
||||
internal static class NumberExpressionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Evaluates the given <see cref="NumberExpression"/> using the provided <see cref="RecalcEngine"/>.
|
||||
/// </summary>
|
||||
/// <param name="expression">Expression to evaluate.</param>
|
||||
/// <param name="engine">Recalc engine to use for evaluation.</param>
|
||||
/// <returns>The evaluated number value, or null if the expression is null or cannot be evaluated.</returns>
|
||||
internal static double? Eval(this NumberExpression? expression, RecalcEngine? engine)
|
||||
{
|
||||
if (expression is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expression.IsLiteral)
|
||||
{
|
||||
return expression.LiteralValue;
|
||||
}
|
||||
|
||||
if (engine is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expression.IsExpression)
|
||||
{
|
||||
return engine.Eval(expression.ExpressionText!).AsDouble();
|
||||
}
|
||||
else if (expression.IsVariableReference)
|
||||
{
|
||||
var formulaValue = engine.Eval(expression.VariableReference!.VariableName);
|
||||
if (formulaValue is NumberValue numberValue)
|
||||
{
|
||||
return numberValue.Value;
|
||||
}
|
||||
|
||||
if (formulaValue is StringValue stringValue && double.TryParse(stringValue.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.PowerFx;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="GptComponentMetadata"/>.
|
||||
/// </summary>
|
||||
public static class PromptAgentExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the 'options' property from a <see cref="GptComponentMetadata"/> as a <see cref="ChatOptions"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="promptAgent">Instance of <see cref="GptComponentMetadata"/></param>
|
||||
/// <param name="engine">Instance of <see cref="RecalcEngine"/></param>
|
||||
/// <param name="functions">Instance of <see cref="IList{AIFunction}"/></param>
|
||||
public static ChatOptions? GetChatOptions(this GptComponentMetadata promptAgent, RecalcEngine? engine, IList<AIFunction>? functions)
|
||||
{
|
||||
Throw.IfNull(promptAgent);
|
||||
|
||||
var outputSchema = promptAgent.OutputType;
|
||||
var modelOptions = promptAgent.Model?.Options;
|
||||
|
||||
var tools = promptAgent.GetAITools(functions);
|
||||
|
||||
if (modelOptions is null && tools is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ChatOptions()
|
||||
{
|
||||
Instructions = promptAgent.Instructions?.ToTemplateString(),
|
||||
Temperature = (float?)modelOptions?.Temperature?.Eval(engine),
|
||||
MaxOutputTokens = (int?)modelOptions?.MaxOutputTokens?.Eval(engine),
|
||||
TopP = (float?)modelOptions?.TopP?.Eval(engine),
|
||||
TopK = (int?)modelOptions?.TopK?.Eval(engine),
|
||||
FrequencyPenalty = (float?)modelOptions?.FrequencyPenalty?.Eval(engine),
|
||||
PresencePenalty = (float?)modelOptions?.PresencePenalty?.Eval(engine),
|
||||
Seed = modelOptions?.Seed?.Eval(engine),
|
||||
ResponseFormat = outputSchema?.AsChatResponseFormat(),
|
||||
ModelId = promptAgent.Model?.ModelNameHint,
|
||||
StopSequences = modelOptions?.StopSequences,
|
||||
AllowMultipleToolCalls = modelOptions?.AllowMultipleToolCalls?.Eval(engine),
|
||||
ToolMode = modelOptions?.AsChatToolMode(),
|
||||
Tools = tools,
|
||||
AdditionalProperties = modelOptions?.GetAdditionalProperties(s_chatOptionProperties),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the 'tools' property from a <see cref="GptComponentMetadata"/>.
|
||||
/// </summary>
|
||||
/// <param name="promptAgent">Instance of <see cref="GptComponentMetadata"/></param>
|
||||
/// <param name="functions">Instance of <see cref="IList{AIFunction}"/></param>
|
||||
internal static List<AITool>? GetAITools(this GptComponentMetadata promptAgent, IList<AIFunction>? functions)
|
||||
{
|
||||
return promptAgent.Tools.Select(tool =>
|
||||
{
|
||||
return tool switch
|
||||
{
|
||||
CodeInterpreterTool => ((CodeInterpreterTool)tool).AsCodeInterpreterTool(),
|
||||
InvokeClientTaskAction => ((InvokeClientTaskAction)tool).CreateOrGetAITool(functions),
|
||||
McpServerTool => ((McpServerTool)tool).CreateHostedMcpTool(),
|
||||
FileSearchTool => ((FileSearchTool)tool).CreateFileSearchTool(),
|
||||
WebSearchTool => ((WebSearchTool)tool).CreateWebSearchTool(),
|
||||
_ => throw new NotSupportedException($"Unable to create tool definition because of unsupported tool type: {tool.Kind}, supported tool types are: {string.Join(",", s_validToolKinds)}"),
|
||||
};
|
||||
}).ToList() ?? [];
|
||||
}
|
||||
|
||||
#region private
|
||||
private const string CodeInterpreterKind = "codeInterpreter";
|
||||
private const string FileSearchKind = "fileSearch";
|
||||
private const string FunctionKind = "function";
|
||||
private const string WebSearchKind = "webSearch";
|
||||
private const string McpKind = "mcp";
|
||||
|
||||
private static readonly string[] s_validToolKinds =
|
||||
[
|
||||
CodeInterpreterKind,
|
||||
FileSearchKind,
|
||||
FunctionKind,
|
||||
WebSearchKind,
|
||||
McpKind
|
||||
];
|
||||
|
||||
private static readonly string[] s_chatOptionProperties =
|
||||
[
|
||||
"allowMultipleToolCalls",
|
||||
"conversationId",
|
||||
"chatToolMode",
|
||||
"frequencyPenalty",
|
||||
"additionalInstructions",
|
||||
"maxOutputTokens",
|
||||
"modelId",
|
||||
"presencePenalty",
|
||||
"responseFormat",
|
||||
"seed",
|
||||
"stopSequences",
|
||||
"temperature",
|
||||
"topK",
|
||||
"topP",
|
||||
"toolMode",
|
||||
"tools",
|
||||
];
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="PropertyInfo"/>.
|
||||
/// </summary>
|
||||
public static class PropertyInfoExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a <see cref="Dictionary{TKey, TValue}"/> of <see cref="string"/> and <see cref="object"/>
|
||||
/// from an <see cref="IReadOnlyDictionary{TKey, TValue}"/> of <see cref="string"/> and <see cref="PropertyInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="properties">A read-only dictionary of property names and their corresponding <see cref="PropertyInfo"/> objects.</param>
|
||||
public static Dictionary<string, object> AsObjectDictionary(this IReadOnlyDictionary<string, PropertyInfo> properties)
|
||||
{
|
||||
var result = new Dictionary<string, object>();
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
result[property.Key] = BuildPropertySchema(property.Value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#region private
|
||||
private static Dictionary<string, object> BuildPropertySchema(PropertyInfo propertyInfo)
|
||||
{
|
||||
var propertySchema = new Dictionary<string, object>();
|
||||
|
||||
// Map the DataType to JSON schema type and add type-specific properties
|
||||
switch (propertyInfo.Type)
|
||||
{
|
||||
case StringDataType:
|
||||
propertySchema["type"] = "string";
|
||||
break;
|
||||
case NumberDataType:
|
||||
propertySchema["type"] = "number";
|
||||
break;
|
||||
case BooleanDataType:
|
||||
propertySchema["type"] = "boolean";
|
||||
break;
|
||||
case DateTimeDataType:
|
||||
propertySchema["type"] = "string";
|
||||
propertySchema["format"] = "date-time";
|
||||
break;
|
||||
case DateDataType:
|
||||
propertySchema["type"] = "string";
|
||||
propertySchema["format"] = "date";
|
||||
break;
|
||||
case TimeDataType:
|
||||
propertySchema["type"] = "string";
|
||||
propertySchema["format"] = "time";
|
||||
break;
|
||||
case RecordDataType nestedRecordType:
|
||||
#pragma warning disable IL2026, IL3050
|
||||
// For nested records, recursively build the schema
|
||||
var nestedSchema = nestedRecordType.GetSchema();
|
||||
var nestedJson = JsonSerializer.Serialize(nestedSchema, ElementSerializer.CreateOptions());
|
||||
var nestedDict = JsonSerializer.Deserialize<Dictionary<string, object>>(nestedJson, ElementSerializer.CreateOptions());
|
||||
#pragma warning restore IL2026, IL3050
|
||||
if (nestedDict != null)
|
||||
{
|
||||
return nestedDict;
|
||||
}
|
||||
propertySchema["type"] = "object";
|
||||
break;
|
||||
case TableDataType tableType:
|
||||
propertySchema["type"] = "array";
|
||||
// TableDataType has Properties like RecordDataType
|
||||
propertySchema["items"] = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = "object",
|
||||
["properties"] = AsObjectDictionary(tableType.Properties),
|
||||
["additionalProperties"] = false
|
||||
};
|
||||
break;
|
||||
default:
|
||||
propertySchema["type"] = "string";
|
||||
break;
|
||||
}
|
||||
|
||||
// Add description if available
|
||||
if (!string.IsNullOrEmpty(propertyInfo.Description))
|
||||
{
|
||||
propertySchema["description"] = propertyInfo.Description;
|
||||
}
|
||||
|
||||
return propertySchema;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="RecordDataType"/>.
|
||||
/// </summary>
|
||||
public static class RecordDataTypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a <see cref="ChatResponseFormat"/> from a <see cref="RecordDataType"/>.
|
||||
/// </summary>
|
||||
/// <param name="recordDataType">Instance of <see cref="RecordDataType"/></param>
|
||||
internal static ChatResponseFormat? AsChatResponseFormat(this RecordDataType recordDataType)
|
||||
{
|
||||
Throw.IfNull(recordDataType);
|
||||
|
||||
if (recordDataType.Properties.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: Consider adding schemaName and schemaDescription parameters to this method.
|
||||
return ChatResponseFormat.ForJsonSchema(
|
||||
schema: recordDataType.GetSchema(),
|
||||
schemaName: recordDataType.GetSchemaName(),
|
||||
schemaDescription: recordDataType.GetSchemaDescription());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="RecordDataType"/> to a <see cref="JsonElement"/>.
|
||||
/// </summary>
|
||||
/// <param name="recordDataType">Instance of <see cref="RecordDataType"/></param>
|
||||
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
|
||||
#pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
|
||||
public static JsonElement GetSchema(this RecordDataType recordDataType)
|
||||
{
|
||||
Throw.IfNull(recordDataType);
|
||||
|
||||
var schemaObject = new Dictionary<string, object>
|
||||
{
|
||||
["type"] = "object",
|
||||
["properties"] = recordDataType.Properties.AsObjectDictionary(),
|
||||
["additionalProperties"] = false
|
||||
};
|
||||
|
||||
var json = JsonSerializer.Serialize(schemaObject, ElementSerializer.CreateOptions());
|
||||
return JsonSerializer.Deserialize<JsonElement>(json);
|
||||
}
|
||||
#pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
|
||||
#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the 'schemaName' property from a <see cref="RecordDataType"/>.
|
||||
/// </summary>
|
||||
private static string? GetSchemaName(this RecordDataType recordDataType)
|
||||
{
|
||||
Throw.IfNull(recordDataType);
|
||||
|
||||
return recordDataType.ExtensionData?.GetPropertyOrNull<StringDataValue>(InitializablePropertyPath.Create("schemaName"))?.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the 'schemaDescription' property from a <see cref="RecordDataType"/>.
|
||||
/// </summary>
|
||||
private static string? GetSchemaDescription(this RecordDataType recordDataType)
|
||||
{
|
||||
Throw.IfNull(recordDataType);
|
||||
|
||||
return recordDataType.ExtensionData?.GetPropertyOrNull<StringDataValue>(InitializablePropertyPath.Create("schemaDescription"))?.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="RecordDataValue"/>.
|
||||
/// </summary>
|
||||
public static class RecordDataValueExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a 'number' property from a <see cref="RecordDataValue"/>
|
||||
/// </summary>
|
||||
/// <param name="recordData">Instance of <see cref="RecordDataValue"/></param>
|
||||
/// <param name="propertyPath">Path of the property to retrieve</param>
|
||||
public static decimal? GetNumber(this RecordDataValue recordData, string propertyPath)
|
||||
{
|
||||
Throw.IfNull(recordData);
|
||||
|
||||
var numberValue = recordData.GetPropertyOrNull<NumberDataValue>(InitializablePropertyPath.Create(propertyPath));
|
||||
return numberValue?.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a nullable boolean value from the specified property path within the given record data.
|
||||
/// </summary>
|
||||
/// <param name="recordData">Instance of <see cref="RecordDataValue"/></param>
|
||||
/// <param name="propertyPath">Path of the property to retrieve</param>
|
||||
public static bool? GetBoolean(this RecordDataValue recordData, string propertyPath)
|
||||
{
|
||||
Throw.IfNull(recordData);
|
||||
|
||||
var booleanValue = recordData.GetPropertyOrNull<BooleanDataValue>(InitializablePropertyPath.Create(propertyPath));
|
||||
return booleanValue?.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a <see cref="RecordDataValue"/> to a <see cref="IReadOnlyDictionary{TKey, TValue}"/>.
|
||||
/// </summary>
|
||||
/// <param name="recordData">Instance of <see cref="RecordDataValue"/></param>
|
||||
public static IReadOnlyDictionary<string, string> ToDictionary(this RecordDataValue recordData)
|
||||
{
|
||||
Throw.IfNull(recordData);
|
||||
|
||||
return recordData.Properties.ToDictionary(
|
||||
kvp => kvp.Key,
|
||||
kvp => kvp.Value?.ToString() ?? string.Empty
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the 'schema' property from a <see cref="RecordDataValue"/>.
|
||||
/// </summary>
|
||||
/// <param name="recordData">Instance of <see cref="RecordDataValue"/></param>
|
||||
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
|
||||
#pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
|
||||
public static JsonElement? GetSchema(this RecordDataValue recordData)
|
||||
{
|
||||
Throw.IfNull(recordData);
|
||||
|
||||
try
|
||||
{
|
||||
var schemaStr = recordData.GetPropertyOrNull<StringDataValue>(InitializablePropertyPath.Create("json_schema.schema"));
|
||||
if (schemaStr?.Value is not null)
|
||||
{
|
||||
return JsonSerializer.Deserialize<JsonElement>(schemaStr.Value);
|
||||
}
|
||||
}
|
||||
catch (InvalidCastException)
|
||||
{
|
||||
// Ignore and try next
|
||||
}
|
||||
|
||||
var responseFormRec = recordData.GetPropertyOrNull<RecordDataValue>(InitializablePropertyPath.Create("json_schema.schema"));
|
||||
if (responseFormRec is not null)
|
||||
{
|
||||
var json = JsonSerializer.Serialize(responseFormRec, ElementSerializer.CreateOptions());
|
||||
return JsonSerializer.Deserialize<JsonElement>(json);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#pragma warning restore IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
|
||||
#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
|
||||
|
||||
internal static object? ToObject(this DataValue? value)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return value switch
|
||||
{
|
||||
StringDataValue s => s.Value,
|
||||
NumberDataValue n => n.Value,
|
||||
BooleanDataValue b => b.Value,
|
||||
TableDataValue t => t.Values.Select(v => v.ToObject()).ToList(),
|
||||
RecordDataValue r => r.Properties.ToDictionary(kvp => kvp.Key, kvp => kvp.Value?.ToObject()),
|
||||
_ => throw new NotSupportedException($"Unsupported DataValue type: {value.GetType().FullName}"),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.PowerFx;
|
||||
using Microsoft.PowerFx.Types;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="StringExpression"/>.
|
||||
/// </summary>
|
||||
public static class StringExpressionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Evaluates the given <see cref="StringExpression"/> using the provided <see cref="RecalcEngine"/>.
|
||||
/// </summary>
|
||||
/// <param name="expression">Expression to evaluate.</param>
|
||||
/// <param name="engine">Recalc engine to use for evaluation.</param>
|
||||
/// <returns>The evaluated string value, or null if the expression is null or cannot be evaluated.</returns>
|
||||
public static string? Eval(this StringExpression? expression, RecalcEngine? engine)
|
||||
{
|
||||
if (expression is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expression.IsLiteral)
|
||||
{
|
||||
return expression.LiteralValue?.ToString();
|
||||
}
|
||||
|
||||
if (engine is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (expression.IsExpression)
|
||||
{
|
||||
return engine.Eval(expression.ExpressionText!).ToString();
|
||||
}
|
||||
else if (expression.IsVariableReference)
|
||||
{
|
||||
var stringValue = engine.Eval(expression.VariableReference!.VariableName) as StringValue;
|
||||
return stringValue?.Value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="WebSearchTool"/>.
|
||||
/// </summary>
|
||||
internal static class WebSearchToolExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a <see cref="HostedWebSearchTool"/> from a <see cref="WebSearchTool"/>.
|
||||
/// </summary>
|
||||
/// <param name="tool">Instance of <see cref="WebSearchTool"/></param>
|
||||
internal static HostedWebSearchTool CreateWebSearchTool(this WebSearchTool tool)
|
||||
{
|
||||
Throw.IfNull(tool);
|
||||
|
||||
return new HostedWebSearchTool();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Shared.Diagnostics;
|
||||
|
||||
namespace Microsoft.Agents.AI;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="PromptAgentFactory"/> to support YAML based agent definitions.
|
||||
/// </summary>
|
||||
public static class YamlAgentFactoryExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a <see cref="AIAgent"/> from the given agent YAML.
|
||||
/// </summary>
|
||||
/// <param name="agentFactory"><see cref="PromptAgentFactory"/> which will be used to create the agent.</param>
|
||||
/// <param name="agentYaml">Text string containing the YAML representation of an <see cref="AIAgent" />.</param>
|
||||
/// <param name="cancellationToken">Optional cancellation token</param>
|
||||
[RequiresDynamicCode("Calls YamlDotNet.Serialization.DeserializerBuilder.DeserializerBuilder()")]
|
||||
public static Task<AIAgent> CreateFromYamlAsync(this PromptAgentFactory agentFactory, string agentYaml, CancellationToken cancellationToken = default)
|
||||
{
|
||||
Throw.IfNull(agentFactory);
|
||||
Throw.IfNullOrEmpty(agentYaml);
|
||||
|
||||
var agentDefinition = AgentBotElementYaml.FromYaml(agentYaml);
|
||||
|
||||
return agentFactory.CreateAsync(
|
||||
agentDefinition,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user