// Copyright (c) Microsoft. All rights reserved. namespace Microsoft.Agents.AI.DurableTask; /// /// Builder for configuring durable agents. /// public sealed class DurableAgentsOptions { // Agent names are case-insensitive private readonly Dictionary> _agentFactories = new(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _agentTimeToLive = new(StringComparer.OrdinalIgnoreCase); internal DurableAgentsOptions() { } /// /// Gets or sets the default time-to-live (TTL) for agent entities. /// /// /// If an agent entity is idle for this duration, it will be automatically deleted. /// Defaults to 14 days. Set to to disable TTL for agents without explicit TTL configuration. /// public TimeSpan? DefaultTimeToLive { get; set; } = TimeSpan.FromDays(14); /// /// Gets or sets the minimum delay for scheduling TTL deletion signals. Defaults to 5 minutes. /// /// /// This property is primarily useful for testing (where shorter delays are needed) or for /// shorter-lived agents in workflows that need more rapid cleanup. The maximum allowed value is 5 minutes. /// Reducing the minimum deletion delay below 5 minutes can be useful for testing or for ensuring rapid cleanup of short-lived agent sessions. /// However, this can also increase the load on the system and should be used with caution. /// /// Thrown when the value exceeds 5 minutes. public TimeSpan MinimumTimeToLiveSignalDelay { get; set { const int MaximumDelayMinutes = 5; if (value > TimeSpan.FromMinutes(MaximumDelayMinutes)) { throw new ArgumentOutOfRangeException( nameof(value), value, $"The minimum time-to-live signal delay cannot exceed {MaximumDelayMinutes} minutes."); } field = value; } } = TimeSpan.FromMinutes(5); /// /// Adds an AI agent factory to the options. /// /// The name of the agent. /// The factory function to create the agent. /// Optional time-to-live for this agent's entities. If not specified, uses . /// The options instance. /// Thrown when or is null. public DurableAgentsOptions AddAIAgentFactory(string name, Func factory, TimeSpan? timeToLive = null) { ArgumentNullException.ThrowIfNull(name); ArgumentNullException.ThrowIfNull(factory); this._agentFactories.Add(name, factory); if (timeToLive.HasValue) { this._agentTimeToLive[name] = timeToLive; } return this; } /// /// Adds a list of AI agents to the options. /// /// The list of agents to add. /// The options instance. /// Thrown when is null. public DurableAgentsOptions AddAIAgents(params IEnumerable agents) { ArgumentNullException.ThrowIfNull(agents); foreach (AIAgent agent in agents) { this.AddAIAgent(agent); } return this; } /// /// Adds an AI agent to the options. /// /// The agent to add. /// Optional time-to-live for this agent's entities. If not specified, uses . /// The options instance. /// Thrown when is null. /// /// Thrown when is null or whitespace or when an agent with the same name has already been registered. /// public DurableAgentsOptions AddAIAgent(AIAgent agent, TimeSpan? timeToLive = null) { ArgumentNullException.ThrowIfNull(agent); if (string.IsNullOrWhiteSpace(agent.Name)) { throw new ArgumentException($"{nameof(agent.Name)} must not be null or whitespace.", nameof(agent)); } if (this._agentFactories.ContainsKey(agent.Name)) { throw new ArgumentException($"An agent with name '{agent.Name}' has already been registered.", nameof(agent)); } this._agentFactories.Add(agent.Name, sp => agent); if (timeToLive.HasValue) { this._agentTimeToLive[agent.Name] = timeToLive; } return this; } /// /// Gets the agents that have been added to this builder. /// /// A read-only collection of agents. internal IReadOnlyDictionary> GetAgentFactories() { return this._agentFactories.AsReadOnly(); } /// /// Gets the time-to-live for a specific agent, or the default TTL if not specified. /// /// The name of the agent. /// The time-to-live for the agent, or the default TTL if not specified. internal TimeSpan? GetTimeToLive(string agentName) { return this._agentTimeToLive.TryGetValue(agentName, out TimeSpan? ttl) ? ttl : this.DefaultTimeToLive; } /// /// Determines whether an agent with the specified name is registered. /// /// The name of the agent to locate. Cannot be null. /// true if an agent with the specified name is registered; otherwise, false. internal bool ContainsAgent(string agentName) { ArgumentNullException.ThrowIfNull(agentName); return this._agentFactories.ContainsKey(agentName); } }