Adds workflow name to workflow graph (#278)

* feat: add workflow class name to WorkflowGraph representation

Add a required `name` field to the WorkflowGraph model that contains
the workflow class name. This provides better identification of workflows
when viewing their graph representation or JSON output.
This commit is contained in:
Adrian Lyjak
2026-01-14 01:19:24 -05:00
committed by GitHub
parent 192437fc47
commit 40be1c7f6f
6 changed files with 30 additions and 5 deletions
+6
View File
@@ -0,0 +1,6 @@
---
"llama-index-workflows": patch
"llama-index-utils-workflow": patch
---
add workflow class name to WorkflowGraph representation
@@ -339,7 +339,7 @@ def _extract_single_agent_structure(agent: BaseWorkflowAgent) -> WorkflowGraph:
# Add edge from agent to tool
edges.append(WorkflowGraphEdge(source="agent", target=tool_id))
return WorkflowGraph(nodes=nodes, edges=edges)
return WorkflowGraph(name=agent.name, nodes=nodes, edges=edges)
def _process_tools_and_handoffs(
@@ -428,7 +428,7 @@ def _extract_agent_workflow_structure(
agent_nodes = [n for n in nodes if n.node_type == "workflow_agent"]
edges.append(WorkflowGraphEdge(source=agent_nodes[-1].id, target="output"))
return WorkflowGraph(nodes=nodes, edges=edges)
return WorkflowGraph(name=type(agent_workflow).__name__, nodes=nodes, edges=edges)
def _extract_execution_graph(
@@ -248,8 +248,11 @@ def get_workflow_representation(workflow: Workflow) -> WorkflowGraph:
)
)
workflow_name = type(workflow).__name__
workflow_description = inspect.getdoc(workflow)
return WorkflowGraph(nodes=nodes, edges=edges, description=workflow_description)
return WorkflowGraph(
name=workflow_name, nodes=nodes, edges=edges, description=workflow_description
)
__all__ = ["get_workflow_representation"]
@@ -139,6 +139,7 @@ class WorkflowGraphEdge(BaseModel):
class WorkflowGraph(BaseModel):
"""Complete workflow graph structure containing all nodes and edges."""
name: str = Field(description="Name of the workflow class")
nodes: list[WorkflowGraphNode] = Field(
description="All nodes in the workflow graph"
)
@@ -233,6 +234,7 @@ class WorkflowGraph(BaseModel):
)
return WorkflowGraph(
name=self.name,
nodes=remaining_nodes,
edges=new_edges,
description=self.description,
@@ -21,6 +21,7 @@ from .conftest import DummyWorkflow # type: ignore[import]
@pytest.fixture()
def ground_truth_repr() -> WorkflowGraph:
return WorkflowGraph(
name="DummyWorkflow",
nodes=[
WorkflowStepNode(
id="end_step",
@@ -96,6 +97,7 @@ def test_truncated_label() -> None:
def test_graph_serialization() -> None:
"""Test that WorkflowGraphNodeEdges serializes correctly to JSON."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[
WorkflowStepNode(id="test", label="test"),
WorkflowEventNode(
@@ -451,6 +453,7 @@ def test_resource_node_serialization_roundtrip() -> None:
def test_graph_with_all_node_types_serialization() -> None:
"""Test full graph serialization/deserialization with all node types."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[
WorkflowStepNode(id="step1", label="Step 1"),
WorkflowEventNode(
@@ -509,6 +512,7 @@ def test_graph_with_all_node_types_serialization() -> None:
def test_graph_deserialization_from_raw_json() -> None:
"""Test that graph can be deserialized from raw JSON dict."""
raw_data = {
"name": "TestWorkflow",
"nodes": [
{"id": "step1", "label": "Step 1", "node_type": "step"},
{
@@ -544,6 +548,7 @@ def test_graph_deserialization_from_raw_json() -> None:
def test_filter_by_node_type_removes_nodes() -> None:
"""Test that filter_by_node_type removes specified node types."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[
WorkflowStepNode(id="step1", label="Step 1"),
WorkflowEventNode(
@@ -572,6 +577,7 @@ def test_filter_by_node_type_removes_nodes() -> None:
def test_filter_by_node_type_resolves_edges() -> None:
"""Test that edges through filtered nodes are resolved."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[
WorkflowStepNode(id="step1", label="Step 1"),
WorkflowEventNode(
@@ -599,6 +605,7 @@ def test_filter_by_node_type_resolves_edges() -> None:
def test_filter_by_node_type_chain_of_filtered_nodes() -> None:
"""Test filtering handles chains of filtered nodes."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[
WorkflowStepNode(id="step1", label="Step 1"),
WorkflowEventNode(
@@ -635,6 +642,7 @@ def test_filter_by_node_type_chain_of_filtered_nodes() -> None:
def test_filter_by_node_type_multiple_types() -> None:
"""Test filtering multiple node types at once."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[
WorkflowStepNode(id="step1", label="Step 1"),
WorkflowEventNode(
@@ -667,6 +675,7 @@ def test_filter_by_node_type_multiple_types() -> None:
def test_filter_by_node_type_preserves_direct_edges() -> None:
"""Test that direct edges between remaining nodes are preserved."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[
WorkflowStepNode(id="step1", label="Step 1"),
WorkflowStepNode(id="step2", label="Step 2"),
@@ -694,6 +703,7 @@ def test_filter_by_node_type_preserves_direct_edges() -> None:
def test_filter_by_node_type_uses_filtered_node_label() -> None:
"""Test that the first filtered node's label becomes the new edge label."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[
WorkflowStepNode(id="step1", label="Step 1"),
WorkflowEventNode(
@@ -720,6 +730,7 @@ def test_filter_by_node_type_uses_filtered_node_label() -> None:
def test_filter_by_node_type_preserves_direct_edge_labels() -> None:
"""Test that labels on direct edges are preserved."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[
WorkflowStepNode(id="step1", label="Step 1"),
WorkflowResourceNode(id="resource1", label="Resource"),
@@ -746,6 +757,7 @@ def test_filter_by_node_type_preserves_direct_edge_labels() -> None:
def test_filter_by_node_type_no_matching_types() -> None:
"""Test filtering with types that don't exist in graph."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[
WorkflowStepNode(id="step1", label="Step 1"),
WorkflowStepNode(id="step2", label="Step 2"),
@@ -763,6 +775,7 @@ def test_filter_by_node_type_no_matching_types() -> None:
def test_filter_by_node_type_preserves_description() -> None:
"""Test that the workflow description is preserved."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[WorkflowStepNode(id="step1", label="Step 1")],
edges=[],
description="My workflow description",
@@ -776,6 +789,7 @@ def test_filter_by_node_type_preserves_description() -> None:
def test_filter_by_node_type_deduplicates_edges() -> None:
"""Test that duplicate edges are not created."""
graph = WorkflowGraph(
name="TestWorkflow",
nodes=[
WorkflowStepNode(id="step1", label="Step 1"),
WorkflowEventNode(
Generated
+2 -2
View File
@@ -1644,7 +1644,7 @@ wheels = [
[[package]]
name = "llama-index-utils-workflow"
version = "0.6.0"
version = "0.7.0"
source = { editable = "packages/llama-index-utils-workflow" }
dependencies = [
{ name = "llama-index-core" },
@@ -1677,7 +1677,7 @@ dev = [
[[package]]
name = "llama-index-workflows"
version = "2.11.7"
version = "2.12.0"
source = { editable = "packages/llama-index-workflows" }
dependencies = [
{ name = "eval-type-backport", marker = "python_full_version < '3.10'" },