diff --git a/src/Agents/AIContextProviderFactory.cs b/src/Agents/AIContextProviderFactory.cs
deleted file mode 100644
index c70de44..0000000
--- a/src/Agents/AIContextProviderFactory.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using Microsoft.Agents.AI;
-using static Microsoft.Agents.AI.ChatClientAgentOptions;
-
-namespace Devlooped.Agents.AI;
-
-///
-/// An implementation of an factory as a class that can provide
-/// the functionality to and integrates
-/// more easily into a service collection.
-///
-///
-/// The is a key extensibility point in Microsoft.Agents.AI, allowing
-/// augmentation of instructions, messages and tools before agent execution is performed.
-///
-public abstract class AIContextProviderFactory
-{
- ///
- /// Provides the implementation of ,
- /// which is invoked whenever agent threads are created or rehydrated.
- ///
- /// The context to potentially hydrate state from.
- /// The context provider that will enhance interactions with an agent.
- public abstract AIContextProvider CreateProvider(AIContextProviderFactoryContext context);
-}
diff --git a/src/Agents/AgentExtensions.cs b/src/Agents/AgentExtensions.cs
deleted file mode 100644
index 997dc59..0000000
--- a/src/Agents/AgentExtensions.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.ComponentModel;
-using System.Runtime.CompilerServices;
-using Microsoft.Agents.AI;
-using Microsoft.Extensions.AI;
-
-namespace Devlooped.Agents.AI;
-
-///
-/// Miscenalleous extension methods for agents.
-///
-[EditorBrowsable(EditorBrowsableState.Never)]
-public static class AgentExtensions
-{
- /// Ensures the returned contains the as an additional property.
- /// Change priority to -10 and make EditorBrowsable.Never when https://github.com/microsoft/agent-framework/issues/1574 is fixed.
- [OverloadResolutionPriority(10)]
- public static ChatResponse AsChatResponse(this AgentRunResponse response)
- {
- var chatResponse = AgentRunResponseExtensions.AsChatResponse(response);
-
- chatResponse.AdditionalProperties ??= [];
- chatResponse.AdditionalProperties[nameof(response.AgentId)] = response.AgentId;
-
- return chatResponse;
- }
-
- extension(AIAgent agent)
- {
- /// Gets the emoji associated with the agent, if any.
- public string? Emoji => agent is not IHasAdditionalProperties additional
- ? null
- : additional.AdditionalProperties is null
- ? null
- : additional.AdditionalProperties.TryGetValue("Emoji", out var value) ? value as string : null;
- }
-}
\ No newline at end of file
diff --git a/src/Agents/AgentMarkdownExtensions.cs b/src/Agents/AgentMarkdownExtensions.cs
deleted file mode 100644
index 6780c7a..0000000
--- a/src/Agents/AgentMarkdownExtensions.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using System.ComponentModel;
-using System.Text;
-using Microsoft.Extensions.Configuration;
-using NetEscapades.Configuration.Yaml;
-
-namespace Devlooped.Agents.AI;
-
-[EditorBrowsable(EditorBrowsableState.Never)]
-public static class AgentMarkdownExtensions
-{
- ///
- /// Adds an instructions markdown file with optional YAML front-matter to the configuration sources.
- ///
- public static IConfigurationBuilder AddAgentMarkdown(this IConfigurationBuilder builder, string path, bool optional = false, bool reloadOnChange = false)
- => builder.Add(source =>
- {
- source.Path = path;
- source.Optional = optional;
- source.ReloadOnChange = reloadOnChange;
- source.ResolveFileProvider();
- });
-
- ///
- /// Adds an instructions markdown stream with optional YAML front-matter to the configuration sources.
- ///
- public static IConfigurationBuilder AddAgentMarkdown(this IConfigurationBuilder builder, Stream stream)
- => Throw.IfNull(builder).Add((InstructionsStreamConfigurationSource source) => source.Stream = stream);
-
- static class InstructionsParser
- {
- public static Dictionary Parse(Stream stream)
- {
- using var reader = new StreamReader(stream);
- var frontMatter = new StringBuilder();
- var line = reader.ReadLine();
- // First line must be the front-matter according to spec.
- if (line == "---")
- {
- while ((line = reader.ReadLine()) != "---" && !reader.EndOfStream)
- frontMatter.AppendLine(line);
- }
-
- if (frontMatter.Length > 0 && line != "---")
- throw new FormatException("Instructions markdown front-matter is not properly closed with '---'.");
-
- var instructions = reader.ReadToEnd().Trim();
- var data = new YamlConfigurationStreamParser().Parse(new MemoryStream(Encoding.UTF8.GetBytes(frontMatter.ToString())));
- if (!data.TryGetValue("id", out var value) || Convert.ToString(value) is not { Length: > 1 } id)
- throw new FormatException("Instructions markdown file must contain YAML front-matter with an 'id' key that specifies the section identifier.");
-
- data.Remove("id");
- // id should use the config delimiter rather than dot (which is a typical mistake when coming from TOML)
- id = id.Replace(".", ConfigurationPath.KeyDelimiter);
- var result = new Dictionary(StringComparer.OrdinalIgnoreCase);
- foreach (var entry in data)
- result[$"{id}{ConfigurationPath.KeyDelimiter}{entry.Key}"] = entry.Value;
-
- result[$"{id}{ConfigurationPath.KeyDelimiter}instructions"] = instructions;
- return result;
- }
- }
-
- class InstructionsStreamConfigurationSource : StreamConfigurationSource
- {
- public override IConfigurationProvider Build(IConfigurationBuilder builder) => new InstructionsStreamConfigurationProvider(this);
- }
-
- class InstructionsStreamConfigurationProvider(InstructionsStreamConfigurationSource source) : StreamConfigurationProvider(source)
- {
- public override void Load(Stream stream) => Data = InstructionsParser.Parse(stream);
- }
-
- class InstructionsConfigurationSource : FileConfigurationSource
- {
- public override IConfigurationProvider Build(IConfigurationBuilder builder)
- {
- EnsureDefaults(builder);
- return new InstructionsConfigurationProvider(this);
- }
- }
-
- class InstructionsConfigurationProvider(FileConfigurationSource source) : FileConfigurationProvider(source)
- {
- public override void Load(Stream stream) => Data = InstructionsParser.Parse(stream);
- }
-}
diff --git a/src/Agents/Agents.csproj b/src/Agents/Agents.csproj
deleted file mode 100644
index 3fb6b4d..0000000
--- a/src/Agents/Agents.csproj
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
- net8.0;net9.0;net10.0
- Preview
- Devlooped.Agents.AI
- $(AssemblyName)
- $(AssemblyName)
- Extensions for Microsoft.Agents.AI
-
- OSMFEULA.txt
- true
- true
- true
-
-
- $(NoWarn);CS0436;SYSLIB1100;SYSLIB1101;MEAI001
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Agents/ChatMessageStoreFactory.cs b/src/Agents/ChatMessageStoreFactory.cs
deleted file mode 100644
index 0bf6cb8..0000000
--- a/src/Agents/ChatMessageStoreFactory.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using Microsoft.Agents.AI;
-using static Microsoft.Agents.AI.ChatClientAgentOptions;
-
-namespace Devlooped.Agents.AI;
-
-///
-/// An implementation of a factory as a class that can provide
-/// the functionality to and integrates
-/// more easily into a service collection.
-///
-///
-/// The is a key extensibility point in Microsoft.Agents.AI, allowing
-/// storage and retrieval of chat messages.
-///
-public abstract class ChatMessageStoreFactory
-{
- ///
- /// Provides the implementation of
- /// to provide message persistence.
- ///
- /// The context to potentially hydrate state from.
- /// The message store that will handle chat messages.
- public abstract ChatMessageStore CreateStore(ChatMessageStoreFactoryContext context);
-}
diff --git a/src/Agents/CompositeAIContextProvider.cs b/src/Agents/CompositeAIContextProvider.cs
deleted file mode 100644
index be42e3c..0000000
--- a/src/Agents/CompositeAIContextProvider.cs
+++ /dev/null
@@ -1,99 +0,0 @@
-using Microsoft.Agents.AI;
-using Microsoft.Extensions.AI;
-
-namespace Devlooped.Agents.AI;
-
-///
-/// Concatenates multiple instances into a single one.
-///
-class CompositeAIContextProvider : AIContextProvider
-{
- readonly IList providers;
- readonly AIContext? staticContext;
-
- public CompositeAIContextProvider(IList providers)
- {
- this.providers = providers;
-
- // Special case for single provider of static contexts
- if (providers.Count == 1 && providers[0] is StaticAIContextProvider staticProvider)
- {
- staticContext = staticProvider.Context;
- return;
- }
-
- // Special case where all providers are static
- if (providers.All(x => x is StaticAIContextProvider))
- {
- // Concatenate instructions from all contexts
- staticContext = new();
- var instructions = new List();
- var messages = new List();
- var tools = new List();
-
- foreach (var provider in providers.Cast())
- {
- var ctx = provider.Context;
-
- if (!string.IsNullOrEmpty(ctx.Instructions))
- instructions.Add(ctx.Instructions);
-
- if (ctx.Messages != null)
- messages.AddRange(ctx.Messages);
-
- if (ctx.Tools != null)
- tools.AddRange(ctx.Tools);
- }
-
- // Same separator used by M.A.AI for instructions appending from AIContext
- if (instructions.Count > 0)
- staticContext.Instructions = string.Join('\n', instructions);
-
- if (messages.Count > 0)
- staticContext.Messages = messages;
-
- if (tools.Count > 0)
- staticContext.Tools = tools;
- }
- }
-
- public override async ValueTask InvokingAsync(InvokingContext invoking, CancellationToken cancellationToken = default)
- {
- if (staticContext is not null)
- return staticContext;
-
- if (providers.Count == 1)
- return await providers[0].InvokingAsync(invoking, cancellationToken);
-
- var context = new AIContext();
- var instructions = new List();
- var messages = new List();
- var tools = new List();
-
- foreach (var provider in providers)
- {
- var ctx = await provider.InvokingAsync(invoking, cancellationToken);
-
- if (!string.IsNullOrEmpty(ctx.Instructions))
- instructions.Add(ctx.Instructions);
-
- if (ctx.Messages != null)
- messages.AddRange(ctx.Messages);
-
- if (ctx.Tools != null)
- tools.AddRange(ctx.Tools);
- }
-
- // Same separator used by M.A.AI for instructions appending from AIContext
- if (instructions.Count > 0)
- context.Instructions = string.Join('\n', instructions);
-
- if (messages.Count > 0)
- context.Messages = messages;
-
- if (tools.Count > 0)
- context.Tools = tools;
-
- return context;
- }
-}
\ No newline at end of file
diff --git a/src/Agents/ConfigurableAIAgent.cs b/src/Agents/ConfigurableAIAgent.cs
deleted file mode 100644
index 4fffe3a..0000000
--- a/src/Agents/ConfigurableAIAgent.cs
+++ /dev/null
@@ -1,276 +0,0 @@
-using System.ComponentModel;
-using System.Diagnostics;
-using System.Text.Json;
-using Devlooped.Extensions.AI;
-using Devlooped.Extensions.AI.OpenAI;
-using Microsoft.Agents.AI;
-using Microsoft.Extensions.AI;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-using xAI;
-
-namespace Devlooped.Agents.AI;
-
-///
-/// A configuration-driven which monitors configuration changes and
-/// re-applies them to the inner agent automatically.
-///
-public sealed partial class ConfigurableAIAgent : AIAgent, IHasAdditionalProperties, IDisposable
-{
- readonly IServiceProvider services;
- readonly IConfiguration configuration;
- readonly string section;
- readonly string name;
- readonly ILogger logger;
- readonly Action? configure;
- IDisposable reloadToken;
- ChatClientAgent agent;
- ChatClientAgentOptions options;
- IChatClient chat;
- AIAgentMetadata metadata;
-
- public ConfigurableAIAgent(IServiceProvider services, string section, string name, Action? configure)
- {
- if (section.Contains('.'))
- throw new ArgumentException("Section separator must be ':', not '.'");
-
- this.services = Throw.IfNull(services);
- this.configuration = services.GetRequiredService();
- this.logger = services.GetRequiredService>();
- this.section = Throw.IfNullOrEmpty(section);
- this.name = Throw.IfNullOrEmpty(name);
- this.configure = configure;
-
- (agent, options, chat, metadata) = Configure(configuration.GetRequiredSection(section));
- reloadToken = configuration.GetReloadToken().RegisterChangeCallback(OnReload, state: null);
- }
-
- /// Disposes the client and stops monitoring configuration changes.
- public void Dispose() => reloadToken?.Dispose();
-
- ///
- public override object? GetService(Type serviceType, object? serviceKey = null) => serviceType switch
- {
- Type t when t == typeof(ChatClientAgentOptions) => options,
- Type t when t == typeof(IChatClient) => chat,
- Type t when typeof(AIAgentMetadata).IsAssignableFrom(t) => metadata,
- _ => agent.GetService(serviceType, serviceKey)
- };
-
- ///
- public AdditionalPropertiesDictionary? AdditionalProperties { get; set; }
-
- ///
- public override string Id => agent.Id;
- ///
- public override string? Description => agent.Description;
- ///
- public override string DisplayName => agent.DisplayName;
- ///
- public override string? Name => name;
- ///
- public override AgentThread DeserializeThread(JsonElement serializedThread, JsonSerializerOptions? jsonSerializerOptions = null)
- => agent.DeserializeThread(serializedThread, jsonSerializerOptions);
- ///
- public override AgentThread GetNewThread() => agent.GetNewThread();
- ///
- public override Task RunAsync(IEnumerable messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
- => agent.RunAsync(messages, thread, options, cancellationToken);
- ///
- public override IAsyncEnumerable RunStreamingAsync(IEnumerable messages, AgentThread? thread = null, AgentRunOptions? options = null, CancellationToken cancellationToken = default)
- => agent.RunStreamingAsync(messages, thread, options, cancellationToken);
-
- ///
- /// Configured agent options.
- ///
- public ChatClientAgentOptions Options => options;
-
- (ChatClientAgent, ChatClientAgentOptions, IChatClient, AIAgentMetadata) Configure(IConfigurationSection configSection)
- {
- var options = configSection.Get();
- options?.Name ??= name;
- options?.Description = options?.Description?.Dedent();
- options?.Instructions = options?.Instructions?.Dedent();
-
- var properties = configSection.Get();
- if (properties is not null)
- {
- properties?.Remove(nameof(AgentClientOptions.Name));
- properties?.Remove(nameof(AgentClientOptions.Description));
- properties?.Remove(nameof(AgentClientOptions.Instructions));
- properties?.Remove(nameof(AgentClientOptions.Client));
- properties?.Remove(nameof(AgentClientOptions.Model));
- properties?.Remove(nameof(AgentClientOptions.Use));
- properties?.Remove(nameof(AgentClientOptions.Tools));
-
- AdditionalProperties = properties;
- }
-
- // If there was a custom id, we must validate it didn't change since that's not supported.
- if (configuration[$"{section}:name"] is { } newname && newname != name)
- throw new InvalidOperationException($"The name of a configured agent cannot be changed at runtime. Expected '{name}' but was '{newname}'.");
-
- var client = services.GetKeyedService(options?.Client
- ?? throw new InvalidOperationException($"A client must be specified for agent '{name}' in configuration section '{section}'."))
- ?? services.GetKeyedService(new ServiceKey(options!.Client))
- ?? throw new InvalidOperationException($"Specified chat client '{options!.Client}' for agent '{name}' is not registered.");
-
- var provider = client.GetService()?.ProviderName;
- ChatOptions? chat = provider == "xai"
- ? configSection.GetSection("options").Get()
- : configSection.GetSection("options").Get();
-
- if (chat is not null)
- options.ChatOptions = chat;
- else if (options.Model is not null)
- (options.ChatOptions ??= new()).ModelId = options.Model;
-
- configure?.Invoke(name, options);
-
- if (options.AIContextProviderFactory is null)
- {
- var contextFactory = services.GetKeyedService(name) ??
- services.GetService();
-
- if (contextFactory is not null)
- {
- if (options.Use?.Count > 0 || options.Tools?.Count > 0)
- throw new InvalidOperationException($"Invalid simultaneous use of keyed service {nameof(AIContextProviderFactory)} and '{section}:use/tools' in configuration.");
-
- options.AIContextProviderFactory = contextFactory.CreateProvider;
- }
- else
- {
- var contexts = new List();
- if (services.GetKeyedService(name) is { } contextProvider)
- contexts.Add(contextProvider);
-
- foreach (var use in options.Use ?? [])
- {
- if (services.GetKeyedService(use) is { } staticContext)
- {
- contexts.Add(new StaticAIContextProvider(staticContext));
- continue;
- }
- else if (services.GetKeyedService(use) is { } dynamicContext)
- {
- contexts.Add(dynamicContext);
- continue;
- }
-
- // Else, look for a config section.
- if (configuration.GetSection("ai:context:" + use) is { } ctxSection &&
- ctxSection.Get() is { } ctxConfig)
- {
- var configured = new AIContext();
- if (ctxConfig.Instructions is not null)
- configured.Instructions = ctxConfig.Instructions.Dedent();
- if (ctxConfig.Messages is { Count: > 1 } messages)
- configured.Messages = messages;
-
- if (ctxConfig.Tools is not null)
- {
- foreach (var toolName in ctxConfig.Tools)
- {
- var tool = services.GetKeyedService(toolName) ??
- services.GetKeyedService(toolName) ??
- throw new InvalidOperationException($"Specified tool '{toolName}' for AI context '{ctxSection.Path}:tools' is not registered as a keyed {nameof(AITool)} or {nameof(AIFunction)}, and is required by agent section '{configSection.Path}'.");
-
- configured.Tools ??= [];
- configured.Tools.Add(tool);
- }
- }
-
- contexts.Add(new StaticAIContextProvider(configured));
- continue;
- }
-
- throw new InvalidOperationException($"Specified AI context '{use}' for agent '{name}' is not registered as either {nameof(AIContent)} or configuration section 'ai:context:{use}'.");
- }
-
- foreach (var toolName in options.Tools ?? [])
- {
- var tool = services.GetKeyedService(toolName) ??
- services.GetKeyedService(toolName) ??
- throw new InvalidOperationException($"Specified tool '{toolName}' for agent '{section}' is not registered as a keyed {nameof(AITool)}, {nameof(AIFunction)} or MCP server tools.");
-
- contexts.Add(new StaticAIContextProvider(new AIContext { Tools = [tool] }));
- }
-
- options.AIContextProviderFactory = _ => new CompositeAIContextProvider(contexts);
- }
- }
- else if (options.Use?.Count > 0)
- {
- throw new InvalidOperationException($"Invalid simultaneous use of {nameof(ChatClientAgentOptions)}.{nameof(ChatClientAgentOptions.AIContextProviderFactory)} and '{section}:use' in configuration.");
- }
-
- if (options.ChatMessageStoreFactory is null)
- {
- var storeFactory = services.GetKeyedService(name) ??
- services.GetService();
-
- if (storeFactory is not null)
- options.ChatMessageStoreFactory = storeFactory.CreateStore;
- }
-
- LogConfigured(name);
-
- var agent = new ChatClientAgent(client, options, services.GetRequiredService(), services);
- var metadata = agent.GetService() ?? new AIAgentMetadata(provider);
-
- return (agent, options, client, new ConfigurableAIAgentMetadata(name, section, metadata.ProviderName));
- }
-
- void OnReload(object? state)
- {
- var configSection = configuration.GetRequiredSection(section);
- reloadToken?.Dispose();
- chat?.Dispose();
- (agent, options, chat, metadata) = Configure(configSection);
- reloadToken = configuration.GetReloadToken().RegisterChangeCallback(OnReload, state: null);
- }
-
- [LoggerMessage(LogLevel.Information, "AIAgent '{Id}' configured.")]
- private partial void LogConfigured(string id);
-
- internal class AgentClientOptions : ChatClientAgentOptions
- {
- public string? Client { get; set; }
- public string? Model { get; set; }
- public IList? Use { get; set; }
- public IList? Tools { get; set; }
- }
-}
-
-/// Metadata for a .
-
-[DebuggerDisplay("Name = {Name}, Section = {ConfigurationSection}, ProviderName = {ProviderName}")]
-public class ConfigurableAIAgentMetadata(string name, string configurationSection, string? providerName) : AIAgentMetadata(providerName)
-{
- /// Name of the agent.
- public string Name => name;
- /// Configuration section where the agent is defined.
- public string ConfigurationSection = configurationSection;
-}
-
-class AIContextConfiguration
-{
- public string? Instructions { get; set; }
-
- public IList? Messages =>
- MessageConfigurations?.Select(config =>
- config.System is not null ? new ChatMessage(ChatRole.System, config.System) :
- config.User is not null ? new ChatMessage(ChatRole.User, config.User) :
- config.Assistant is not null ? new ChatMessage(ChatRole.Assistant, config.Assistant) :
- null).Where(x => x is not null).Cast().ToList();
-
- public IList? Tools { get; set; }
-
- [EditorBrowsable(EditorBrowsableState.Never)]
- [ConfigurationKeyName("Messages")]
- public MessageConfiguration[]? MessageConfigurations { get; set; }
-}
-
-record MessageConfiguration(string? System = default, string? User = default, string? Assistant = default);
diff --git a/src/Agents/ConfigurableAgentsExtensions.cs b/src/Agents/ConfigurableAgentsExtensions.cs
deleted file mode 100644
index c46e110..0000000
--- a/src/Agents/ConfigurableAgentsExtensions.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-using System.ComponentModel;
-using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
-using System.Text.Json;
-using Devlooped.Agents.AI;
-using Devlooped.Extensions.AI;
-using Microsoft.Agents.AI;
-using Microsoft.Agents.AI.Hosting;
-using Microsoft.Extensions.AI;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using Microsoft.Extensions.Hosting;
-using ModelContextProtocol.Server;
-
-namespace Microsoft.Extensions.DependencyInjection;
-
-///
-/// Adds configuration-driven agents to an application host.
-///
-[EditorBrowsable(EditorBrowsableState.Never)]
-public static class ConfigurableAgentsExtensions
-{
- /// Adds instances to the service collection backing .
- /// The tool type.
- /// The builder instance.
- /// The serializer options governing tool parameter marshalling.
- /// The builder provided in .
- /// is .
- ///
- /// This method discovers all instance and static methods (public and non-public) on the specified
- /// type, where the methods are attributed as , and adds an
- /// instance for each. For instance methods, an instance will be constructed for each invocation of the tool.
- ///
- public static IAIAgentsBuilder WithTools<[DynamicallyAccessedMembers(
- DynamicallyAccessedMemberTypes.PublicMethods |
- DynamicallyAccessedMemberTypes.NonPublicMethods |
- DynamicallyAccessedMemberTypes.PublicConstructors)] TToolType>(
- this IAIAgentsBuilder builder,
- JsonSerializerOptions? serializerOptions = null,
- ServiceLifetime lifetime = ServiceLifetime.Singleton)
- {
- Throw.IfNull(builder);
-
- // Preserve existing registration if any, such as when using Devlooped.Extensions.DependencyInjection
- // via [Service] attribute or by convention.
- builder.Services.TryAdd(ServiceDescriptor.Describe(typeof(TToolType), typeof(TToolType), lifetime));
-
- serializerOptions ??= ToolJsonOptions.Default;
-
- foreach (var toolMethod in typeof(TToolType).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance))
- {
- if (toolMethod.GetCustomAttribute() is { } toolAttribute)
- {
- var function = toolMethod.IsStatic
- ? AIFunctionFactory.Create(toolMethod, null,
- toolAttribute.Name ?? ToolJsonOptions.Default.PropertyNamingPolicy!.ConvertName(toolMethod.Name),
- serializerOptions: serializerOptions)
- : AIFunctionFactory.Create(toolMethod, args => args.Services?.GetRequiredService(typeof(TToolType)) ??
- throw new InvalidOperationException("Could not determine target instance for tool."),
- new AIFunctionFactoryOptions
- {
- Name = toolAttribute.Name ?? ToolJsonOptions.Default.PropertyNamingPolicy!.ConvertName(toolMethod.Name),
- SerializerOptions = serializerOptions
- });
-
- builder.Services.TryAdd(ServiceDescriptor.DescribeKeyed(
- typeof(AIFunction), function.Name,
- (_, _) => function, lifetime));
- }
- }
-
- return builder;
- }
-
- ///
- /// Adds AI agents to the host application builder based on configuration.
- ///
- /// The host application builder.
- /// Optional action to configure the pipeline for each agent.
- /// Optional action to configure options for each agent.
- /// The configuration prefix for agents, defaults to "ai:agents".
- /// The host application builder with AI agents added.
- public static IAIAgentsBuilder AddAIAgents(this IHostApplicationBuilder builder, Action? configurePipeline = default, Action? configureOptions = default, string prefix = "ai:agents")
- {
- builder.AddChatClients();
-
- foreach (var entry in builder.Configuration.AsEnumerable().Where(x =>
- x.Key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) &&
- x.Key.EndsWith("client", StringComparison.OrdinalIgnoreCase)))
- {
- var section = string.Join(':', entry.Key.Split(':')[..^1]);
- // key == name (unlike chat clients, the AddAIAgent expects the key to be the name).
- var name = builder.Configuration[$"{section}:name"] ?? section[(prefix.Length + 1)..];
-
- var options = builder.Configuration.GetRequiredSection(section).Get();
- // We need logging set up for the configurable client to log changes
- builder.Services.AddLogging();
-
- builder.AddAIAgent(name, (sp, key) =>
- {
- var agent = new ConfigurableAIAgent(sp, section, key, configureOptions);
-
- if (configurePipeline is not null)
- {
- var builder = agent.AsBuilder();
- configurePipeline(key, builder);
- return builder.Build(sp);
- }
-
- return agent;
- });
-
- // Also register for case-insensitive lookup, but without duplicating the entry in
- // the AgentCatalog, since that will always resolve from above.
- builder.Services.TryAdd(ServiceDescriptor.KeyedSingleton(new ServiceKey(name), (sp, key)
- => sp.GetRequiredKeyedService(name)));
- }
-
- return new DefaultAIAgentsBuilder(builder);
- }
-
- /// Gets an AI agent by name (case-insensitive) from the service provider.
- public static AIAgent? GetIAAgent(this IServiceProvider services, string name)
- => services.GetKeyedService(name) ?? services.GetKeyedService(new ServiceKey(name));
-}
\ No newline at end of file
diff --git a/src/Agents/Extensions/.editorconfig b/src/Agents/Extensions/.editorconfig
deleted file mode 100644
index f93cc99..0000000
--- a/src/Agents/Extensions/.editorconfig
+++ /dev/null
@@ -1,2 +0,0 @@
-[*.cs]
-generated_code = true
\ No newline at end of file
diff --git a/src/Agents/Extensions/Dedent.cs b/src/Agents/Extensions/Dedent.cs
deleted file mode 100644
index 920f671..0000000
--- a/src/Agents/Extensions/Dedent.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-//
-#region License
-// MIT License
-//
-// Copyright (c) Daniel Cazzulino
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-#endregion
-
-#nullable enable
-using System.Text;
-using System.Text.RegularExpressions;
-
-namespace System
-{
- ///
- /// String extension methods for text processing.
- ///
- static partial class StringExtensions
- {
- ///
- /// Remove leading whitespace from each line of a multi-line string that is common
- /// to all non-empty lines. This is equivalent to Python's textwrap.dedent().
- ///
- /// The text to dedent.
- /// The dedented text.
- ///
- ///
- /// var text = """
- /// Line 1
- /// Line 2
- /// Line 3
- /// """;
- /// var dedented = text.Dedent();
- /// // Result:
- /// // Line 1
- /// // Line 2
- /// // Line 3
- ///
- ///
- public static string Dedent(this string text)
- {
- if (string.IsNullOrEmpty(text))
- return text;
-
- // Detect the line ending style used in the input
- var lineEnding = Environment.NewLine;
- if (text.Contains("\r\n"))
- lineEnding = "\r\n";
- else if (text.Contains('\r'))
- lineEnding = "\r";
- else if (text.Contains('\n'))
- lineEnding = "\n";
-
- // Split using regex to properly handle different line endings
- var lines = NewLineExpr().Split(text);
-
- // Remove leading and trailing empty lines
- int start = 0;
- int end = lines.Length - 1;
-
- while (start < lines.Length && string.IsNullOrWhiteSpace(lines[start]))
- start++;
-
- while (end >= 0 && string.IsNullOrWhiteSpace(lines[end]))
- end--;
-
- if (start > end)
- return string.Empty;
-
- // Find the minimum indentation (ignoring empty lines)
- int minIndent = int.MaxValue;
- for (int i = start; i <= end; i++)
- {
- var line = lines[i];
- if (!string.IsNullOrWhiteSpace(line))
- {
- int indent = 0;
- while (indent < line.Length && char.IsWhiteSpace(line[indent]))
- indent++;
-
- minIndent = Math.Min(minIndent, indent);
- }
- }
-
- if (minIndent == int.MaxValue || minIndent == 0)
- minIndent = 0;
-
- // Remove the common indentation from all lines
- var result = new StringBuilder();
- for (int i = start; i <= end; i++)
- {
- var line = lines[i];
- if (string.IsNullOrWhiteSpace(line))
- {
- if (i < end) // Don't add newline for last empty line
- result.Append(lineEnding);
- }
- else
- {
- var dedentedLine = line.Length > minIndent ? line[minIndent..] : string.Empty;
- result.Append(dedentedLine);
- if (i < end)
- result.Append(lineEnding);
- }
- }
-
- return result.ToString();
- }
-
- [GeneratedRegex(@"\r\n|\r|\n")]
- private static partial Regex NewLineExpr();
- }
-}
\ No newline at end of file
diff --git a/src/Agents/Extensions/Resources.cs b/src/Agents/Extensions/Resources.cs
deleted file mode 100644
index d8f32c8..0000000
--- a/src/Agents/Extensions/Resources.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-using System.Globalization;
-
-namespace NetEscapades.Configuration.Yaml
-{
- internal static class Resources
- {
- ///
- /// A duplicate key '{0}' was found.
- ///
- internal static string FormatError_KeyIsDuplicated(object p0)
- {
- return string.Format(CultureInfo.CurrentCulture, "A duplicate key '{0}' was found.", p0);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Agents/Extensions/Throw.cs b/src/Agents/Extensions/Throw.cs
deleted file mode 100644
index eea3e12..0000000
--- a/src/Agents/Extensions/Throw.cs
+++ /dev/null
@@ -1,992 +0,0 @@
-//
-#region License
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// Adapted from https://github.com/dotnet/extensions/blob/main/src/Shared/Throw/Throw.cs
-#endregion
-
-#nullable enable
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.CompilerServices;
-
-#pragma warning disable CA1716
-namespace System;
-#pragma warning restore CA1716
-
-///
-/// Defines static methods used to throw exceptions.
-///
-///
-/// The main purpose is to reduce code size, improve performance, and standardize exception
-/// messages.
-///
-[SuppressMessage("Minor Code Smell", "S4136:Method overloads should be grouped together", Justification = "Doesn't work with the region layout")]
-[SuppressMessage("Minor Code Smell", "S2333:Partial is gratuitous in this context", Justification = "Some projects add additional partial parts.")]
-[SuppressMessage("Design", "CA1716", Justification = "Not part of an API")]
-
-#if !SHARED_PROJECT
-[ExcludeFromCodeCoverage]
-#endif
-
-static partial class Throw
-{
- #region For Object
-
- ///
- /// Throws an if the specified argument is .
- ///
- /// Argument type to be checked for .
- /// Object to be checked for .
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [return: NotNull]
- public static T IfNull([NotNull] T argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument is null)
- {
- ArgumentNullException(paramName);
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified argument is ,
- /// or if the specified member is .
- ///
- /// Argument type to be checked for .
- /// Member type to be checked for .
- /// Argument to be checked for .
- /// Object member to be checked for .
- /// The name of the parameter being checked.
- /// The name of the member.
- /// The original value of .
- ///
- ///
- /// Throws.IfNullOrMemberNull(myObject, myObject?.MyProperty)
- ///
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [return: NotNull]
- public static TMember IfNullOrMemberNull(
- [NotNull] TParameter argument,
- [NotNull] TMember member,
- [CallerArgumentExpression(nameof(argument))] string paramName = "",
- [CallerArgumentExpression(nameof(member))] string memberName = "")
- {
- if (argument is null)
- {
- ArgumentNullException(paramName);
- }
-
- if (member is null)
- {
- ArgumentException(paramName, $"Member {memberName} of {paramName} is null");
- }
-
- return member;
- }
-
- ///
- /// Throws an if the specified member is .
- ///
- /// Argument type.
- /// Member type to be checked for .
- /// Argument to which member belongs.
- /// Object member to be checked for .
- /// The name of the parameter being checked.
- /// The name of the member.
- /// The original value of .
- ///
- ///
- /// Throws.IfMemberNull(myObject, myObject.MyProperty)
- ///
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [return: NotNull]
- [SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Analyzer isn't seeing the reference to 'argument' in the attribute")]
- public static TMember IfMemberNull(
- TParameter argument,
- [NotNull] TMember member,
- [CallerArgumentExpression(nameof(argument))] string paramName = "",
- [CallerArgumentExpression(nameof(member))] string memberName = "")
- where TParameter : notnull
- {
- if (member is null)
- {
- ArgumentException(paramName, $"Member {memberName} of {paramName} is null");
- }
-
- return member;
- }
-
- #endregion
-
- #region For String
-
- ///
- /// Throws either an or an
- /// if the specified string is or whitespace respectively.
- ///
- /// String to be checked for or whitespace.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [return: NotNull]
- public static string IfNullOrWhitespace([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
-#if !NETCOREAPP3_1_OR_GREATER
- if (argument == null)
- {
- ArgumentNullException(paramName);
- }
-#endif
-
- if (string.IsNullOrWhiteSpace(argument))
- {
- if (argument == null)
- {
- ArgumentNullException(paramName);
- }
- else
- {
- ArgumentException(paramName, "Argument is whitespace");
- }
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the string is ,
- /// or if it is empty.
- ///
- /// String to be checked for or empty.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [return: NotNull]
- public static string IfNullOrEmpty([NotNull] string? argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
-#if !NETCOREAPP3_1_OR_GREATER
- if (argument == null)
- {
- ArgumentNullException(paramName);
- }
-#endif
-
- if (string.IsNullOrEmpty(argument))
- {
- if (argument == null)
- {
- ArgumentNullException(paramName);
- }
- else
- {
- ArgumentException(paramName, "Argument is an empty string");
- }
- }
-
- return argument;
- }
-
- #endregion
-
- #region For Buffer
-
- ///
- /// Throws an if the argument's buffer size is less than the required buffer size.
- ///
- /// The actual buffer size.
- /// The required buffer size.
- /// The name of the parameter to be checked.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void IfBufferTooSmall(int bufferSize, int requiredSize, string paramName = "")
- {
- if (bufferSize < requiredSize)
- {
- ArgumentException(paramName, $"Buffer too small, needed a size of {requiredSize} but got {bufferSize}");
- }
- }
-
- #endregion
-
- #region For Enums
-
- ///
- /// Throws an if the enum value is not valid.
- ///
- /// The argument to evaluate.
- /// The name of the parameter being checked.
- /// The type of the enumeration.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static T IfOutOfRange(T argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- where T : struct, Enum
- {
-#if NET5_0_OR_GREATER
- if (!Enum.IsDefined(argument))
-#else
- if (!Enum.IsDefined(typeof(T), argument))
-#endif
- {
- ArgumentOutOfRangeException(paramName, $"{argument} is an invalid value for enum type {typeof(T)}");
- }
-
- return argument;
- }
-
- #endregion
-
- #region For Collections
-
- ///
- /// Throws an if the collection is ,
- /// or if it is empty.
- ///
- /// The collection to evaluate.
- /// The name of the parameter being checked.
- /// The type of objects in the collection.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- [return: NotNull]
-
- // The method has actually 100% coverage, but due to a bug in the code coverage tool,
- // a lower number is reported. Therefore, we temporarily exclude this method
- // from the coverage measurements. Once the bug in the code coverage tool is fixed,
- // the exclusion attribute can be removed.
- [ExcludeFromCodeCoverage]
- public static IEnumerable IfNullOrEmpty([NotNull] IEnumerable? argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument == null)
- {
- ArgumentNullException(paramName);
- }
- else
- {
- switch (argument)
- {
- case ICollection collection:
- if (collection.Count == 0)
- {
- ArgumentException(paramName, "Collection is empty");
- }
-
- break;
- case IReadOnlyCollection readOnlyCollection:
- if (readOnlyCollection.Count == 0)
- {
- ArgumentException(paramName, "Collection is empty");
- }
-
- break;
- default:
- using (IEnumerator enumerator = argument.GetEnumerator())
- {
- if (!enumerator.MoveNext())
- {
- ArgumentException(paramName, "Collection is empty");
- }
- }
-
- break;
- }
- }
-
- return argument;
- }
-
- #endregion
-
- #region Exceptions
-
- ///
- /// Throws an .
- ///
- /// The name of the parameter that caused the exception.
-#if !NET6_0_OR_GREATER
- [MethodImpl(MethodImplOptions.NoInlining)]
-#endif
- [DoesNotReturn]
- public static void ArgumentNullException(string paramName)
- => throw new ArgumentNullException(paramName);
-
- ///
- /// Throws an .
- ///
- /// The name of the parameter that caused the exception.
- /// A message that describes the error.
-#if !NET6_0_OR_GREATER
- [MethodImpl(MethodImplOptions.NoInlining)]
-#endif
- [DoesNotReturn]
- public static void ArgumentNullException(string paramName, string? message)
- => throw new ArgumentNullException(paramName, message);
-
- ///
- /// Throws an .
- ///
- /// The name of the parameter that caused the exception.
-#if !NET6_0_OR_GREATER
- [MethodImpl(MethodImplOptions.NoInlining)]
-#endif
- [DoesNotReturn]
- public static void ArgumentOutOfRangeException(string paramName)
- => throw new ArgumentOutOfRangeException(paramName);
-
- ///
- /// Throws an .
- ///
- /// The name of the parameter that caused the exception.
- /// A message that describes the error.
-#if !NET6_0_OR_GREATER
- [MethodImpl(MethodImplOptions.NoInlining)]
-#endif
- [DoesNotReturn]
- public static void ArgumentOutOfRangeException(string paramName, string? message)
- => throw new ArgumentOutOfRangeException(paramName, message);
-
- ///
- /// Throws an .
- ///
- /// The name of the parameter that caused the exception.
- /// The value of the argument that caused this exception.
- /// A message that describes the error.
-#if !NET6_0_OR_GREATER
- [MethodImpl(MethodImplOptions.NoInlining)]
-#endif
- [DoesNotReturn]
- public static void ArgumentOutOfRangeException(string paramName, object? actualValue, string? message)
- => throw new ArgumentOutOfRangeException(paramName, actualValue, message);
-
- ///
- /// Throws an .
- ///
- /// The name of the parameter that caused the exception.
- /// A message that describes the error.
-#if !NET6_0_OR_GREATER
- [MethodImpl(MethodImplOptions.NoInlining)]
-#endif
- [DoesNotReturn]
- public static void ArgumentException(string paramName, string? message)
- => throw new ArgumentException(message, paramName);
-
- ///
- /// Throws an .
- ///
- /// The name of the parameter that caused the exception.
- /// A message that describes the error.
- /// The exception that is the cause of the current exception.
- ///
- /// If the is not a , the current exception is raised in a catch
- /// block that handles the inner exception.
- ///
-#if !NET6_0_OR_GREATER
- [MethodImpl(MethodImplOptions.NoInlining)]
-#endif
- [DoesNotReturn]
- public static void ArgumentException(string paramName, string? message, Exception? innerException)
- => throw new ArgumentException(message, paramName, innerException);
-
- ///
- /// Throws an .
- ///
- /// A message that describes the error.
-#if !NET6_0_OR_GREATER
- [MethodImpl(MethodImplOptions.NoInlining)]
-#endif
- [DoesNotReturn]
- public static void InvalidOperationException(string message)
- => throw new InvalidOperationException(message);
-
- ///
- /// Throws an .
- ///
- /// A message that describes the error.
- /// The exception that is the cause of the current exception.
-#if !NET6_0_OR_GREATER
- [MethodImpl(MethodImplOptions.NoInlining)]
-#endif
- [DoesNotReturn]
- public static void InvalidOperationException(string message, Exception? innerException)
- => throw new InvalidOperationException(message, innerException);
-
- #endregion
-
- #region For Integer
-
- ///
- /// Throws an if the specified number is less than min.
- ///
- /// Number to be expected being less than min.
- /// The number that must be less than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IfLessThan(int argument, int min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument < min)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument less than minimum value {min}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is greater than max.
- ///
- /// Number to be expected being greater than max.
- /// The number that must be greater than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IfGreaterThan(int argument, int max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument > max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument greater than maximum value {max}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is less or equal than min.
- ///
- /// Number to be expected being less or equal than min.
- /// The number that must be less or equal than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IfLessThanOrEqual(int argument, int min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument <= min)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument less or equal than minimum value {min}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is greater or equal than max.
- ///
- /// Number to be expected being greater or equal than max.
- /// The number that must be greater or equal than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IfGreaterThanOrEqual(int argument, int max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument >= max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument greater or equal than maximum value {max}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is not in the specified range.
- ///
- /// Number to be expected being greater or equal than max.
- /// The lower bound of the allowed range of argument values.
- /// The upper bound of the allowed range of argument values.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IfOutOfRange(int argument, int min, int max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument < min || argument > max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument not in the range [{min}..{max}]");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is equal to 0.
- ///
- /// Number to be expected being not equal to zero.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IfZero(int argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument == 0)
- {
- ArgumentOutOfRangeException(paramName, "Argument is zero");
- }
-
- return argument;
- }
-
- #endregion
-
- #region For Unsigned Integer
-
- ///
- /// Throws an if the specified number is less than min.
- ///
- /// Number to be expected being less than min.
- /// The number that must be less than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint IfLessThan(uint argument, uint min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument < min)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument less than minimum value {min}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is greater than max.
- ///
- /// Number to be expected being greater than max.
- /// The number that must be greater than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint IfGreaterThan(uint argument, uint max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument > max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument greater than maximum value {max}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is less or equal than min.
- ///
- /// Number to be expected being less or equal than min.
- /// The number that must be less or equal than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint IfLessThanOrEqual(uint argument, uint min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument <= min)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument less or equal than minimum value {min}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is greater or equal than max.
- ///
- /// Number to be expected being greater or equal than max.
- /// The number that must be greater or equal than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint IfGreaterThanOrEqual(uint argument, uint max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument >= max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument greater or equal than maximum value {max}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is not in the specified range.
- ///
- /// Number to be expected being greater or equal than max.
- /// The lower bound of the allowed range of argument values.
- /// The upper bound of the allowed range of argument values.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint IfOutOfRange(uint argument, uint min, uint max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument < min || argument > max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument not in the range [{min}..{max}]");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is equal to 0.
- ///
- /// Number to be expected being not equal to zero.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static uint IfZero(uint argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument == 0U)
- {
- ArgumentOutOfRangeException(paramName, "Argument is zero");
- }
-
- return argument;
- }
-
- #endregion
-
- #region For Long
-
- ///
- /// Throws an if the specified number is less than min.
- ///
- /// Number to be expected being less than min.
- /// The number that must be less than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long IfLessThan(long argument, long min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument < min)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument less than minimum value {min}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is greater than max.
- ///
- /// Number to be expected being greater than max.
- /// The number that must be greater than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long IfGreaterThan(long argument, long max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument > max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument greater than maximum value {max}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is less or equal than min.
- ///
- /// Number to be expected being less or equal than min.
- /// The number that must be less or equal than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long IfLessThanOrEqual(long argument, long min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument <= min)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument less or equal than minimum value {min}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is greater or equal than max.
- ///
- /// Number to be expected being greater or equal than max.
- /// The number that must be greater or equal than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long IfGreaterThanOrEqual(long argument, long max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument >= max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument greater or equal than maximum value {max}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is not in the specified range.
- ///
- /// Number to be expected being greater or equal than max.
- /// The lower bound of the allowed range of argument values.
- /// The upper bound of the allowed range of argument values.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long IfOutOfRange(long argument, long min, long max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument < min || argument > max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument not in the range [{min}..{max}]");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is equal to 0.
- ///
- /// Number to be expected being not equal to zero.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long IfZero(long argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument == 0L)
- {
- ArgumentOutOfRangeException(paramName, "Argument is zero");
- }
-
- return argument;
- }
-
- #endregion
-
- #region For Unsigned Long
-
- ///
- /// Throws an if the specified number is less than min.
- ///
- /// Number to be expected being less than min.
- /// The number that must be less than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong IfLessThan(ulong argument, ulong min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument < min)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument less than minimum value {min}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is greater than max.
- ///
- /// Number to be expected being greater than max.
- /// The number that must be greater than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong IfGreaterThan(ulong argument, ulong max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument > max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument greater than maximum value {max}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is less or equal than min.
- ///
- /// Number to be expected being less or equal than min.
- /// The number that must be less or equal than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong IfLessThanOrEqual(ulong argument, ulong min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument <= min)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument less or equal than minimum value {min}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is greater or equal than max.
- ///
- /// Number to be expected being greater or equal than max.
- /// The number that must be greater or equal than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong IfGreaterThanOrEqual(ulong argument, ulong max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument >= max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument greater or equal than maximum value {max}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is not in the specified range.
- ///
- /// Number to be expected being greater or equal than max.
- /// The lower bound of the allowed range of argument values.
- /// The upper bound of the allowed range of argument values.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong IfOutOfRange(ulong argument, ulong min, ulong max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument < min || argument > max)
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument not in the range [{min}..{max}]");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is equal to 0.
- ///
- /// Number to be expected being not equal to zero.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ulong IfZero(ulong argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- if (argument == 0UL)
- {
- ArgumentOutOfRangeException(paramName, "Argument is zero");
- }
-
- return argument;
- }
-
- #endregion
-
- #region For Double
-
- ///
- /// Throws an if the specified number is less than min.
- ///
- /// Number to be expected being less than min.
- /// The number that must be less than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double IfLessThan(double argument, double min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- // strange conditional needed in order to handle NaN values correctly
-#pragma warning disable S1940 // Boolean checks should not be inverted
- if (!(argument >= min))
-#pragma warning restore S1940 // Boolean checks should not be inverted
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument less than minimum value {min}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is greater than max.
- ///
- /// Number to be expected being greater than max.
- /// The number that must be greater than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double IfGreaterThan(double argument, double max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- // strange conditional needed in order to handle NaN values correctly
-#pragma warning disable S1940 // Boolean checks should not be inverted
- if (!(argument <= max))
-#pragma warning restore S1940 // Boolean checks should not be inverted
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument greater than maximum value {max}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is less or equal than min.
- ///
- /// Number to be expected being less or equal than min.
- /// The number that must be less or equal than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double IfLessThanOrEqual(double argument, double min, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- // strange conditional needed in order to handle NaN values correctly
-#pragma warning disable S1940 // Boolean checks should not be inverted
- if (!(argument > min))
-#pragma warning restore S1940 // Boolean checks should not be inverted
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument less or equal than minimum value {min}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is greater or equal than max.
- ///
- /// Number to be expected being greater or equal than max.
- /// The number that must be greater or equal than the argument.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double IfGreaterThanOrEqual(double argument, double max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- // strange conditional needed in order to handle NaN values correctly
-#pragma warning disable S1940 // Boolean checks should not be inverted
- if (!(argument < max))
-#pragma warning restore S1940 // Boolean checks should not be inverted
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument greater or equal than maximum value {max}");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is not in the specified range.
- ///
- /// Number to be expected being greater or equal than max.
- /// The lower bound of the allowed range of argument values.
- /// The upper bound of the allowed range of argument values.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double IfOutOfRange(double argument, double min, double max, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
- // strange conditional needed in order to handle NaN values correctly
- if (!(min <= argument && argument <= max))
- {
- ArgumentOutOfRangeException(paramName, argument, $"Argument not in the range [{min}..{max}]");
- }
-
- return argument;
- }
-
- ///
- /// Throws an if the specified number is equal to 0.
- ///
- /// Number to be expected being not equal to zero.
- /// The name of the parameter being checked.
- /// The original value of .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double IfZero(double argument, [CallerArgumentExpression(nameof(argument))] string paramName = "")
- {
-#pragma warning disable S1244 // Floating point numbers should not be tested for equality
- if (argument == 0.0)
-#pragma warning restore S1244 // Floating point numbers should not be tested for equality
- {
- ArgumentOutOfRangeException(paramName, "Argument is zero");
- }
-
- return argument;
- }
-
- #endregion
-}
diff --git a/src/Agents/Extensions/YamlConfigurationStreamParser.cs b/src/Agents/Extensions/YamlConfigurationStreamParser.cs
deleted file mode 100644
index 38d262a..0000000
--- a/src/Agents/Extensions/YamlConfigurationStreamParser.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using Microsoft.Extensions.Configuration;
-using YamlDotNet.RepresentationModel;
-
-namespace NetEscapades.Configuration.Yaml
-{
- internal class YamlConfigurationStreamParser
- {
- private readonly IDictionary _data = new SortedDictionary(StringComparer.OrdinalIgnoreCase);
- private readonly Stack _context = new Stack();
- private string _currentPath;
-
- public IDictionary Parse(Stream input)
- {
- _data.Clear();
- _context.Clear();
-
- // https://dotnetfiddle.net/rrR2Bb
- var yaml = new YamlStream();
- yaml.Load(new StreamReader(input, detectEncodingFromByteOrderMarks: true));
-
- if (yaml.Documents.Any())
- {
- var mapping = (YamlMappingNode)yaml.Documents[0].RootNode;
-
- // The document node is a mapping node
- VisitYamlMappingNode(mapping);
- }
-
- return _data;
- }
-
- private void VisitYamlNodePair(KeyValuePair yamlNodePair)
- {
- var context = ((YamlScalarNode)yamlNodePair.Key).Value;
- VisitYamlNode(context, yamlNodePair.Value);
- }
-
- private void VisitYamlNode(string context, YamlNode node)
- {
- if (node is YamlScalarNode scalarNode)
- {
- VisitYamlScalarNode(context, scalarNode);
- }
- if (node is YamlMappingNode mappingNode)
- {
- VisitYamlMappingNode(context, mappingNode);
- }
- if (node is YamlSequenceNode sequenceNode)
- {
- VisitYamlSequenceNode(context, sequenceNode);
- }
- }
-
- private void VisitYamlScalarNode(string context, YamlScalarNode yamlValue)
- {
- //a node with a single 1-1 mapping
- EnterContext(context);
- var currentKey = _currentPath;
-
- if (_data.ContainsKey(currentKey))
- {
- throw new FormatException(Resources.FormatError_KeyIsDuplicated(currentKey));
- }
-
- _data[currentKey] = IsNullValue(yamlValue) ? null : yamlValue.Value;
- ExitContext();
- }
-
- private void VisitYamlMappingNode(YamlMappingNode node)
- {
- foreach (var yamlNodePair in node.Children)
- {
- VisitYamlNodePair(yamlNodePair);
- }
- }
-
- private void VisitYamlMappingNode(string context, YamlMappingNode yamlValue)
- {
- //a node with an associated sub-document
- EnterContext(context);
-
- VisitYamlMappingNode(yamlValue);
-
- ExitContext();
- }
-
- private void VisitYamlSequenceNode(string context, YamlSequenceNode yamlValue)
- {
- //a node with an associated list
- EnterContext(context);
-
- VisitYamlSequenceNode(yamlValue);
-
- ExitContext();
- }
-
- private void VisitYamlSequenceNode(YamlSequenceNode node)
- {
- for (int i = 0; i < node.Children.Count; i++)
- {
- VisitYamlNode(i.ToString(), node.Children[i]);
- }
- }
-
- private void EnterContext(string context)
- {
- _context.Push(context);
- _currentPath = ConfigurationPath.Combine(_context.Reverse());
- }
-
- private void ExitContext()
- {
- _context.Pop();
- _currentPath = ConfigurationPath.Combine(_context.Reverse());
- }
-
- private bool IsNullValue(YamlScalarNode yamlValue)
- {
- return yamlValue.Style == YamlDotNet.Core.ScalarStyle.Plain
- && (
- yamlValue.Value == "~"
- || yamlValue.Value == "null"
- || yamlValue.Value == "Null"
- || yamlValue.Value == "NULL"
- );
- }
- }
-}
diff --git a/src/Agents/IAIAgentsBuilder.cs b/src/Agents/IAIAgentsBuilder.cs
deleted file mode 100644
index c44d02c..0000000
--- a/src/Agents/IAIAgentsBuilder.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Diagnostics.Metrics;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-
-namespace Devlooped.Agents.AI;
-
-/// Provides a mechanism to configure AI agents.
-public interface IAIAgentsBuilder : IHostApplicationBuilder
-{
-}
-
-class DefaultAIAgentsBuilder(IHostApplicationBuilder builder) : IAIAgentsBuilder
-{
- public IDictionary