Description
WorkflowViz.to_mermaid() can turn distinct executor IDs into the same Mermaid node ID. For example, a workflow with step-a followed by step_a executes both steps, but its exported diagram declares step_a twice and draws a self-edge. The same problem affects Unicode IDs, digit-prefix normalization, nested workflow namespaces, and generated fan-in nodes.
Steps to reproduce
from agent_framework import Executor, WorkflowBuilder, WorkflowContext, WorkflowViz, handler
class Step(Executor):
@handler
async def handle(self, message: str, ctx: WorkflowContext[str]) -> None:
await ctx.send_message(message)
first = Step(id="step-a")
second = Step(id="step_a")
workflow = WorkflowBuilder(start_executor=first).add_edge(first, second).build()
print(WorkflowViz(workflow).to_mermaid())
Current output:
flowchart TD
step_a["step-a (Start)"];
step_a["step_a"];
step_a --> step_a;
Loading
Expected behavior
Distinct workflow entities retain distinct diagram IDs, with edges pointing to the original source and target. Labels and ordinary, non-colliding diagrams remain unchanged.
Actual behavior
The identifier sanitizer is not one-to-one, and executor, namespace, and generated fan-in IDs are allocated separately. Mermaid 12.1.0 parses the example as one vertex and one self-edge. Parsing succeeds, so a syntax check alone does not catch the incorrect topology.
Environment
- Official main b9d24c8fb484c8330abe8bb9e7500ca3c3bbf46c, core 1.20.0.
- Windows, Python 3.12.14 and 3.14.3; Node 24.21.0 for the independent Mermaid parser check.
- Reproduction uses local workflow objects and no model or external service. The Mermaid check inspects the parser's graph database; it does not render SVG or test a browser UI.
I am preparing a fix that allocates stable IDs across one export while preserving the existing labels and non-colliding output.
Description
WorkflowViz.to_mermaid() can turn distinct executor IDs into the same Mermaid node ID. For example, a workflow with step-a followed by step_a executes both steps, but its exported diagram declares step_a twice and draws a self-edge. The same problem affects Unicode IDs, digit-prefix normalization, nested workflow namespaces, and generated fan-in nodes.
Steps to reproduce
Current output:
Expected behavior
Distinct workflow entities retain distinct diagram IDs, with edges pointing to the original source and target. Labels and ordinary, non-colliding diagrams remain unchanged.
Actual behavior
The identifier sanitizer is not one-to-one, and executor, namespace, and generated fan-in IDs are allocated separately. Mermaid 12.1.0 parses the example as one vertex and one self-edge. Parsing succeeds, so a syntax check alone does not catch the incorrect topology.
Environment
I am preparing a fix that allocates stable IDs across one export while preserving the existing labels and non-colliding output.