// Copyright (c) Microsoft. All rights reserved.
// Routing decision flow for a single edge.
// Example: the B→D edge from a workflow like below:
//
// [A] ──► [B] ──► [C] ──► [E] (B→D has condition: x => x.NeedsReview)
// │ ▲
// └──► [D] ──────┘
//
// (condition: x => x.NeedsReview, _sourceOutputType: typeof(Order))
//
// RouteMessage(envelope) envelope.Message = "{\"NeedsReview\":true, ...}"
// │
// ▼
// Has condition? ──── No ────► Enqueue to sink's queue
// │
// Yes (B→D has one)
// │
// ▼
// Deserialize message JSON string → Order object using _sourceOutputType
// │
// ▼
// Evaluate _condition(order) order => order.NeedsReview
// │
// ┌──┴──┐
// true false
// │ │
// ▼ └──► Skip (log and return, D will not run)
// Enqueue to
// D's queue
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using Microsoft.Extensions.Logging;
namespace Microsoft.Agents.AI.DurableTask.Workflows.EdgeRouters;
///
/// Routes messages from a source executor to a single target executor with optional condition evaluation.
///
///
///
/// Created by during construction — one instance per (source, sink) edge.
/// When an edge has a condition (e.g., order => order.Total > 1000), the router deserialises
/// the serialised JSON message back to the source executor's output type so the condition delegate
/// can evaluate it against strongly-typed properties. If the condition returns false, the
/// message is not forwarded and the target executor will not run for this edge.
///
///
/// For sources with multiple successors, individual instances
/// are wrapped in a so a single RouteMessage call
/// fans the same message out to all targets, each evaluating its own condition independently.
///
///
internal sealed class DurableDirectEdgeRouter : IDurableEdgeRouter
{
private readonly string _sourceId;
private readonly string _sinkId;
private readonly Func