Skip to content

Conversation

@joslat
Copy link
Contributor

@joslat joslat commented Oct 16, 2025

Motivation and Context

1. Why is this change required?

The workflow visualization system currently lacks support for adding labels or annotations to edges. This limitation makes it impossible to document edge purpose, data flow, or business logic directly in workflow visualizations, forcing developers to rely on external documentation or code comments.

2. What problem does it solve?

This PR solves several critical documentation and communication challenges:

  • Self-documenting workflows: Edge labels make workflow logic understandable without examining code
  • Conditional edge clarity: Multiple conditional edges can now be distinguished (e.g., "High Quality ≥90" vs "Low Quality <70" instead of generic "conditional")
  • Data flow documentation: Labels can show what data transformations occur at each stage
  • Stakeholder communication: Diagrams become understandable to non-technical audiences
  • Professional diagrams: Visualizations are ready for documentation and presentations

Example:
Generated Mermaid code:

flowchart TD
  split_data_executor["split_data_executor (Start)"];
  map_executor_0["map_executor_0"];
  map_executor_1["map_executor_1"];
  map_executor_2["map_executor_2"];
  shuffle_executor["shuffle_executor"];
  reduce_executor_0["reduce_executor_0"];
  reduce_executor_1["reduce_executor_1"];
  reduce_executor_2["reduce_executor_2"];
  reduce_executor_3["reduce_executor_3"];
  completion_executor["completion_executor"];

  fan_in::shuffle_executor::AAF0D85A((fan-in))
  fan_in::completion_executor::1E85EEB6((fan-in))
  map_executor_0 --> fan_in::shuffle_executor::AAF0D85A;
  map_executor_1 --> fan_in::shuffle_executor::AAF0D85A;
  map_executor_2 --> fan_in::shuffle_executor::AAF0D85A;
  fan_in::shuffle_executor::AAF0D85A --> shuffle_executor;
  reduce_executor_0 --> fan_in::completion_executor::1E85EEB6;
  reduce_executor_1 --> fan_in::completion_executor::1E85EEB6;
  reduce_executor_2 --> fan_in::completion_executor::1E85EEB6;
  reduce_executor_3 --> fan_in::completion_executor::1E85EEB6;
  fan_in::completion_executor::1E85EEB6 --> completion_executor;
  split_data_executor -->|Splitting| map_executor_0;
  split_data_executor -->|Splitting| map_executor_1;
  split_data_executor -->|Splitting| map_executor_2;
  shuffle_executor -->|Shuffling| reduce_executor_0;
  shuffle_executor -->|Shuffling| reduce_executor_1;
  shuffle_executor -->|Shuffling| reduce_executor_2;
  shuffle_executor -->|Shuffling| reduce_executor_3;

Rendered Mermaid:
image

3. What scenario does it contribute to?

Quality-based Routing:

var workflow = new WorkflowBuilder(qualityCheck) 
.AddEdge(qualityCheck, approval, condition: r => r.Score >= 90, label: "High Quality ≥90") 
.AddEdge(qualityCheck, review, condition: r => r.Score >= 70 && r.Score < 90, label: "Good Quality 70-89") .AddEdge(qualityCheck, rejection, condition: r => r.Score < 70, label: "Low Quality <70") .Build();

Data Transformation Pipeline:

var workflow = new WorkflowBuilder(inputParser) 
.AddEdge(inputParser, validator, label: "Raw JSON") 
.AddEdge(validator, transformer, label: "Validated data")
 .AddEdge(transformer, enricher, label: "Normalized schema") 
.AddEdge(enricher, output, label: "Enriched with metadata") 
.Build();

4. Related Issues

Fixes:

Addresses the need for edge annotations in workflow visualizations to improve documentation and diagram clarity.

Description

This PR adds comprehensive support for custom labels on workflow edges and fixes critical rendering issues in both DOT (Graphviz) and Mermaid visualization formats.

Core Changes

1. Extended Edge Data Structures

  • Added Label property to DirectEdgeData, FanOutEdgeData, and FanInEdgeData
  • Maintained backward compatibility with nullable string? type

2. Enhanced WorkflowBuilder API
Extended all AddEdge methods with optional label parameter:

// Regular edge public WorkflowBuilder AddEdge(ExecutorIsh source, ExecutorIsh sink, string? label = null)
// Conditional edge public WorkflowBuilder AddEdge<T>(ExecutorIsh source, ExecutorIsh sink, Func<T?, bool> condition, string? label = null)
// Fan-out edge public WorkflowBuilder AddFanOutEdge(ExecutorIsh source, string? label, params ExecutorIsh[] sinks)
// Fan-in edge public WorkflowBuilder AddFanInEdge(ExecutorIsh target, string? label, params ExecutorIsh[] sources)

All label parameters are optional to maintain backward compatibility.

3. Fixed Visualization Rendering

DOT (Graphviz) Format Fixes:

  • ✅ Fixed: Conditional edges with custom labels now properly render with style=dashed
  • ✅ Fixed: Edge attributes are correctly formatted
  • ✅ Added: Proper label escaping for DOT syntax
  • ✅ Improved: Clean attribute building logic with clear separation of concerns

Mermaid Format Fixes:

  • ✅ Fixed: Implemented proper Mermaid syntax for labeled edges
  • ✅ Fixed: Conditional edges default to "conditional" label if no custom label provided
  • ✅ Improved: Consistent label rendering across all edge types

4. Refactored Label Logic

  • Separated concerns: ComputeNormalEdges returns raw label data
  • Visualization layers apply format-specific defaults independently
  • DOT: Shows custom labels only, applies style=dashed for conditional edges
  • Mermaid: Shows custom labels or defaults to "conditional" for conditional edges

Benefits

Self-documenting workflows - Purpose is clear from diagrams
Better conditional clarity - Each condition has meaningful context
Data flow visibility - Documents transformations at each stage
Professional diagrams - Ready for stakeholders and documentation
Industry standard - Uses standard "label" terminology from DOT/Mermaid
Backward compatible - No breaking changes, all labels are optional
Proper rendering - Fixed DOT and Mermaid syntax issues

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • [] Is this a breaking change? No - All changes are backward compatible. The label parameter is optional in all methods, and existing code without labels continues to work unchanged.

…d mermaid, adds rendering of labels in edges
Copilot AI review requested due to automatic review settings October 16, 2025 00:26
@markwallace-microsoft markwallace-microsoft added .NET workflows Related to Workflows in agent-framework labels Oct 16, 2025
@joslat joslat changed the title adds support for labels in edges, fixes rendering of labels in dot a… .NET: adds support for labels in edges, fixes rendering of labels in dot a… Oct 16, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Adds edge label support across workflow data structures, builder APIs, and visualization (DOT/Mermaid), and updates tests/samples accordingly.

  • Adds Label to DirectEdgeData, FanOutEdgeData, FanInEdgeData and threads it through WorkflowBuilder.
  • Updates visualization: DOT escapes labels and applies dashed style for conditional edges; Mermaid renders labeled edges.
  • Refactors tests and samples to new builder signatures; adds sample usage of labels.

Reviewed Changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
dotnet/src/Microsoft.Agents.AI.Workflows/WorkflowBuilder.cs Extends AddEdge/AddFanOutEdge/AddFanInEdge with label support and propagates to edge data.
dotnet/src/Microsoft.Agents.AI.Workflows/Visualization/WorkflowVisualizer.cs Emits labels for DOT and Mermaid; adds DOT label escaping; refactors ComputeNormalEdges to include labels.
dotnet/src/Microsoft.Agents.AI.Workflows/FanOutEdgeData.cs Adds Label property and ctor parameter.
dotnet/src/Microsoft.Agents.AI.Workflows/FanInEdgeData.cs Adds Label property and ctor parameter.
dotnet/src/Microsoft.Agents.AI.Workflows/DirectEdgeData.cs Adds Label property and ctor parameter.
dotnet/src/Microsoft.Agents.AI.Workflows/SwitchBuilder.cs Updates fan-out calls to include label parameter.
dotnet/src/Microsoft.Agents.AI.Workflows/AgentWorkflowBuilder.cs Updates fan-out calls to include label parameter.
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/WorkflowVisualizerTests.cs Adapts tests to new AddFanOutEdge/AddFanInEdge signatures.
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/RepresentationTests.cs Updates FanInEdgeData construction to include label.
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/JsonSerializationTests.cs Updates FanInEdgeData test data to include label.
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/InProcessStateTests.cs Updates fan-out call to include label parameter.
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/EdgeRunnerTests.cs Constructs FanInEdgeData with a custom label.
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/EdgeMapSmokeTests.cs Updates FanInEdgeData construction to include label.
dotnet/samples/GettingStarted/Workflows/_Foundational/01_ExecutorsAndEdges/Program.cs Demonstrates labeled direct edge in sample.
dotnet/samples/GettingStarted/Workflows/SharedStates/Program.cs Updates fan-out/fan-in calls to include label parameter.
dotnet/samples/GettingStarted/Workflows/Concurrent/MapReduce/Program.cs Demonstrates labels on fan-out/fan-in edges.
dotnet/samples/GettingStarted/Workflows/Concurrent/Concurrent/Program.cs Demonstrates labels on fan-out/fan-in edges.
dotnet/samples/GettingStarted/Workflows/Agents/WorkflowAsAnAgent/WorkflowHelper.cs Updates fan-out/fan-in calls to include label parameter.

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@joslat
Copy link
Contributor Author

joslat commented Oct 19, 2025

Hi @lokitoth & @alliscode, any opinion & feedback on this?

/// <summary>
/// An optional label for the edge.
/// </summary>
public string? Label { get; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Minor] This should probably be on EdgeData, rather than the specific EdgeDatas.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I move it? I was unsure if you wanted to keep EdgeData pure, but I agree to the suggestion. happy to move this to EdgeData...
Do I proceed? :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's unify them


// Combine attributes
var attrString = attributes.Count > 0 ? $" [{string.Join(", ", attributes)}]" : "";
lines.Add($"{indent}\"{MapId(src)}\" -> \"{MapId(target)}\"{attrString};");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the ids need to be put through EscapeDotXYZ()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, but I thought it would be nice in case we find text in chinese, korean or using other special characters, to scape them for compatibility.

Can remove those escape functions though in aras to simplicity, becoming responsibility of the user then.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep it consistent, but I do not have a strong opinion as to which of the two.

@alliscode alliscode requested a review from lokitoth October 22, 2025 14:55
@joslat
Copy link
Contributor Author

joslat commented Oct 29, 2025

@lokitoth what do you say about my replies? what should we do to proceed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

.NET workflows Related to Workflows in agent-framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants