// Copyright (c) Microsoft. All rights reserved. using System; using Microsoft.Shared.Diagnostics; namespace Microsoft.Agents.AI.Workflows.Execution; /// /// Represents a unique key used to identify an update within a specific scope. /// /// An is composed of a and a key, similar /// to . The difference is in how equality is determined: Unlike ScopeKey, /// two UpdateKeys that differ only by their ScopeId's ExecutorId are considered different, because /// updates coming from different executors need to be tracked separately, until they are marged (if /// appropriate) and published during a step transition. /// /// internal sealed class UpdateKey(ScopeId scopeId, string key) { public ScopeId ScopeId { get; } = Throw.IfNull(scopeId); public string Key { get; } = Throw.IfNullOrEmpty(key); public UpdateKey(string executorId, string? scopeName, string key) : this(new ScopeId(Throw.IfNullOrEmpty(executorId), scopeName), key) { } public override string ToString() => $"{this.ScopeId}/{this.Key}"; public bool IsMatchingScope(ScopeId scopeId, bool strict = false) => this.ScopeId == scopeId && (!strict || this.ScopeId.ExecutorId == scopeId.ExecutorId); public override bool Equals(object? obj) { if (obj is UpdateKey other) { // Unlike ScopeId, UpdateKey is equal only if both the Executor and ScopeName are the same return this.IsMatchingScope(other.ScopeId, strict: true) && this.Key == other.Key; } return false; } public override int GetHashCode() => HashCode.Combine(this.ScopeId.ExecutorId, this.ScopeId.ScopeName, this.Key); }