Skip to content

ant_ai.workflow.visualize

build_workflow_graph

build_workflow_graph(
    workflow: Workflow,
    *,
    engine: str = "dot",
    rankdir: str = "LR",
) -> Digraph

Build and return a graphviz.Digraph for workflow.

The returned object renders inline in Jupyter notebooks and can be passed to :func:render_workflow for file export.

Parameters:

Name Type Description Default
workflow Workflow

The workflow to visualise.

required
engine str

Graphviz layout engine ("dot", "neato", "fdp"…).

'dot'
rankdir str

Layout direction — "LR" (left-to-right, default) or "TB" (left-to-right).

'LR'

Raises:

Type Description
ImportError

if the graphviz package is not installed. Install with pip install ant-ai[viz].

Source code in src/ant_ai/workflow/visualize.py
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def build_workflow_graph(
    workflow: Workflow,
    *,
    engine: str = "dot",
    rankdir: str = "LR",
) -> Digraph:
    """
    Build and return a ``graphviz.Digraph`` for *workflow*.

    The returned object renders inline in Jupyter notebooks and can be passed
    to :func:`render_workflow` for file export.

    Args:
        workflow: The workflow to visualise.
        engine: Graphviz layout engine (``"dot"``, ``"neato"``, ``"fdp"``…).
        rankdir: Layout direction — ``"LR"`` (left-to-right, default) or ``"TB"``
            (left-to-right).

    Raises:
        ImportError: if the ``graphviz`` package is not installed.
            Install with ``pip install ant-ai[viz]``.
    """
    try:
        import graphviz
    except ImportError as exc:  # pragma: no cover
        raise ImportError(
            "Workflow visualisation requires the graphviz package. "
            "Install it with:  pip install ant-ai[viz]"
        ) from exc

    g = graphviz.Digraph(engine=engine)
    g.attr(rankdir=rankdir, fontname="Helvetica", fontsize="12")
    g.attr("node", fontname="Helvetica", fontsize="12")
    g.attr("edge", fontname="Helvetica", fontsize="10")

    # START / END — ellipse
    for special in (START, END):
        g.node(
            _gv_id(special),
            label=special,
            shape="ellipse",
            style="filled",
            fillcolor=_FILL_SPECIAL,
        )

    # Regular nodes — rectangle
    for name in workflow.nodes:
        g.node(
            _gv_id(name),
            label=name,
            shape="rectangle",
            style="filled,rounded",
            fillcolor=_FILL_NODE,
        )

    # Static edges
    for src, dst in workflow.edges.items():
        g.edge(_gv_id(src), _gv_id(dst))

    # Conditional edges — diamond + AST-extracted destinations
    for src, router in workflow.conditional_edges.items():
        diamond_id = f"__router_{_gv_id(src)}__"
        g.node(
            diamond_id,
            label=getattr(router, "__name__", repr(router)),
            shape="diamond",
            style="filled",
            fillcolor=_FILL_ROUTER,
        )
        g.edge(_gv_id(src), diamond_id)
        for dst in _router_destinations(router):
            g.edge(diamond_id, _gv_id(dst), style="dashed")

    return g

build_workflow_mermaid

build_workflow_mermaid(
    workflow: Workflow, *, rankdir: str = "LR"
) -> str

Build a Mermaid flowchart definition for workflow.

Unlike :func:build_workflow_graph, this has no dependency on the graphviz package or CLI — Mermaid does its own auto-layout, and the result is plain text that renders natively in GitHub, GitLab, MkDocs Material, and the Mermaid Live Editor.

Parameters:

Name Type Description Default
workflow Workflow

The workflow to visualise.

required
rankdir str

Layout direction — "LR" (left-to-right, default) or "TB" (top-to-bottom). Passed through to Mermaid's flowchart direction.

'LR'

Returns:

Type Description
str

A Mermaid flowchart definition as a string.

Source code in src/ant_ai/workflow/visualize.py
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
def build_workflow_mermaid(
    workflow: Workflow,
    *,
    rankdir: str = "LR",
) -> str:
    """
    Build a Mermaid ``flowchart`` definition for *workflow*.

    Unlike :func:`build_workflow_graph`, this has no dependency on the
    ``graphviz`` package or CLI — Mermaid does its own auto-layout, and the
    result is plain text that renders natively in GitHub, GitLab, MkDocs
    Material, and the Mermaid Live Editor.

    Args:
        workflow: The workflow to visualise.
        rankdir: Layout direction — ``"LR"`` (left-to-right, default) or
            ``"TB"`` (top-to-bottom). Passed through to Mermaid's
            ``flowchart`` direction.

    Returns:
        A Mermaid ``flowchart`` definition as a string.
    """
    lines = [f"flowchart {rankdir}"]

    # START / END — stadium shape
    for special in (START, END):
        lines.append(f'    {_mmd_id(special)}(["{special}"])')

    # Regular nodes — rectangle
    for name in workflow.nodes:
        lines.append(f'    {_mmd_id(name)}["{name}"]')

    # Static edges
    for src, dst in workflow.edges.items():
        lines.append(f"    {_mmd_id(src)} --> {_mmd_id(dst)}")

    # Conditional edges — diamond + AST-extracted destinations
    for src, router in workflow.conditional_edges.items():
        diamond_id = f"r_{_gv_id(src)}"
        router_label = getattr(router, "__name__", repr(router))
        lines.append(f'    {diamond_id}{{"{router_label}"}}')
        lines.append(f"    {_mmd_id(src)} --> {diamond_id}")
        for dst in _router_destinations(router):
            lines.append(f"    {diamond_id} -.-> {_mmd_id(dst)}")

    return "\n".join(lines)

render_workflow

render_workflow(
    workflow: Workflow,
    path: str | Path,
    format: RenderFormat = "png",
    *,
    engine: str = "dot",
    rankdir: str = "LR",
) -> Path

Render workflow to a file.

Parameters:

Name Type Description Default
workflow Workflow

The workflow to visualise.

required
path str | Path

Output path. The file extension is set automatically based on format (any existing extension is replaced).

required
format RenderFormat

"png", "jpg", "pdf", "svg", "latex", or "mermaid". The "latex" format produces a self-contained .tex file that can be compiled with pdflatex. The "mermaid" format produces a .mmd file with a Mermaid flowchart definition — no graphviz dependency required.

'png'
engine str

Graphviz layout engine. Ignored for "mermaid".

'dot'
rankdir str

Layout direction — "LR" (left-to-right, default) or "TB".

'LR'

Returns:

Type Description
Path

class:~pathlib.Path of the rendered file.

Raises:

Type Description
ImportError

if the graphviz package is not installed and format requires it (i.e. not "latex" or "mermaid").

ValueError

if format is not one of the supported values.

Source code in src/ant_ai/workflow/visualize.py
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
def render_workflow(
    workflow: Workflow,
    path: str | Path,
    format: RenderFormat = "png",
    *,
    engine: str = "dot",
    rankdir: str = "LR",
) -> Path:
    """
    Render *workflow* to a file.

    Args:
        workflow: The workflow to visualise.
        path: Output path. The file extension is set automatically based on
            *format* (any existing extension is replaced).
        format: ``"png"``, ``"jpg"``, ``"pdf"``, ``"svg"``, ``"latex"``, or
            ``"mermaid"``. The ``"latex"`` format produces a self-contained
            ``.tex`` file that can be compiled with ``pdflatex``. The
            ``"mermaid"`` format produces a ``.mmd`` file with a Mermaid
            ``flowchart`` definition — no ``graphviz`` dependency required.
        engine: Graphviz layout engine. Ignored for ``"mermaid"``.
        rankdir: Layout direction — ``"LR"`` (left-to-right, default) or ``"TB"``.

    Returns:
        :class:`~pathlib.Path` of the rendered file.

    Raises:
        ImportError: if the ``graphviz`` package is not installed and
            *format* requires it (i.e. not ``"latex"`` or ``"mermaid"``).
        ValueError: if *format* is not one of the supported values.
    """
    if format not in _FORMATS:
        raise ValueError(f"format must be one of {_FORMATS!r}, got {format!r}")

    out = Path(path)

    if format == "mermaid":
        mmd = build_workflow_mermaid(workflow, rankdir=rankdir)
        dest = out.with_suffix(".mmd")
        dest.write_text(mmd, encoding="utf-8")
        return dest

    if format == "latex":
        tex = _build_tikz(workflow, engine=engine)
        dest = out.with_suffix(".tex")
        dest.write_text(tex, encoding="utf-8")
        return dest

    g: Digraph = build_workflow_graph(workflow, engine=engine, rankdir=rankdir)
    gv_format: Literal["jpeg", "png", "pdf", "svg"] = (
        "jpeg" if format == "jpg" else format
    )
    rendered = g.render(
        filename=str(out.with_suffix("")),
        format=gv_format,
        cleanup=True,
    )
    return Path(rendered)