// 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);
}
}