Skip to content

Commit bb536f0

Browse files
committed
Add graph visualization queries to approval workflow samples
Add get_graph_ascii() and get_graph_mermaid() queries to both human_in_the_loop workflow samples, demonstrating how to expose graph execution progress via Temporal queries. These queries return: - ASCII art diagram with progress indicators (✓/▶/○) - Mermaid flowchart with colored nodes by status
1 parent c95ddac commit bb536f0

2 files changed

Lines changed: 59 additions & 5 deletions

File tree

langgraph_plugin/human_in_the_loop/approval_graph_interrupt/workflow.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class ApprovalWorkflow:
4747
def __init__(self) -> None:
4848
self._approval_response: dict[str, Any] | None = None
4949
self._interrupt_value: dict[str, Any] | None = None
50+
self._app: Any = None # Store runner for visualization queries
5051

5152
@workflow.signal
5253
def provide_approval(self, response: dict[str, Any]) -> None:
@@ -76,6 +77,32 @@ def get_status(self) -> str:
7677
else:
7778
return "approved" if self._approval_response.get("approved") else "rejected"
7879

80+
@workflow.query
81+
def get_graph_ascii(self) -> str:
82+
"""Query to get ASCII art visualization of graph execution progress.
83+
84+
Returns an ASCII diagram showing which nodes have completed,
85+
which is currently executing/interrupted, and which are pending.
86+
"""
87+
if self._app is None:
88+
return "Graph not yet initialized"
89+
return self._app.get_graph_ascii()
90+
91+
@workflow.query
92+
def get_graph_mermaid(self) -> str:
93+
"""Query to get Mermaid diagram of graph execution progress.
94+
95+
Returns a Mermaid flowchart with nodes colored by status:
96+
- Green: completed nodes
97+
- Yellow: current/interrupted node
98+
- Gray: pending nodes
99+
100+
Can be rendered in GitHub, Notion, or any Mermaid-compatible viewer.
101+
"""
102+
if self._app is None:
103+
return "Graph not yet initialized"
104+
return self._app.get_graph_mermaid()
105+
79106
@workflow.run
80107
async def run(
81108
self,
@@ -92,7 +119,7 @@ async def run(
92119
Returns:
93120
The final state containing result and executed status.
94121
"""
95-
app = lg_compile("approval_workflow")
122+
self._app = lg_compile("approval_workflow")
96123

97124
# Handle both dataclass and dict input (Temporal deserializes to dict)
98125
if isinstance(request, dict):
@@ -112,7 +139,7 @@ async def run(
112139
}
113140

114141
# First invocation - should hit interrupt at request_approval node
115-
result = await app.ainvoke(initial_state)
142+
result = await self._app.ainvoke(initial_state)
116143

117144
# Check for interrupt
118145
if "__interrupt__" in result:
@@ -153,6 +180,6 @@ async def run(
153180
)
154181

155182
# Resume with the approval response
156-
result = await app.ainvoke(Command(resume=self._approval_response))
183+
result = await self._app.ainvoke(Command(resume=self._approval_response))
157184

158185
return result

langgraph_plugin/human_in_the_loop/approval_wait_condition/workflow.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class ApprovalWorkflow:
3939
def __init__(self) -> None:
4040
self._approval_response: dict[str, Any] | None = None
4141
self._pending_approval: dict[str, Any] | None = None
42+
self._app: Any = None # Store runner for visualization queries
4243

4344
@workflow.signal
4445
def provide_approval(self, response: dict[str, Any]) -> None:
@@ -68,6 +69,32 @@ def get_status(self) -> str:
6869
else:
6970
return "approved" if self._approval_response.get("approved") else "rejected"
7071

72+
@workflow.query
73+
def get_graph_ascii(self) -> str:
74+
"""Query to get ASCII art visualization of graph execution progress.
75+
76+
Returns an ASCII diagram showing which nodes have completed,
77+
which is currently executing/interrupted, and which are pending.
78+
"""
79+
if self._app is None:
80+
return "Graph not yet initialized"
81+
return self._app.get_graph_ascii()
82+
83+
@workflow.query
84+
def get_graph_mermaid(self) -> str:
85+
"""Query to get Mermaid diagram of graph execution progress.
86+
87+
Returns a Mermaid flowchart with nodes colored by status:
88+
- Green: completed nodes
89+
- Yellow: current/interrupted node
90+
- Gray: pending nodes
91+
92+
Can be rendered in GitHub, Notion, or any Mermaid-compatible viewer.
93+
"""
94+
if self._app is None:
95+
return "Graph not yet initialized"
96+
return self._app.get_graph_mermaid()
97+
7198
@workflow.run
7299
async def run(self, request: ApprovalRequest) -> dict[str, Any]:
73100
"""Run the approval workflow.
@@ -78,7 +105,7 @@ async def run(self, request: ApprovalRequest) -> dict[str, Any]:
78105
Returns:
79106
The final state containing result and executed status.
80107
"""
81-
app = lg_compile("approval_workflow")
108+
self._app = lg_compile("approval_workflow")
82109

83110
# Handle both dataclass and dict input (Temporal deserializes to dict)
84111
if isinstance(request, dict):
@@ -98,6 +125,6 @@ async def run(self, request: ApprovalRequest) -> dict[str, Any]:
98125
}
99126

100127
# Run the graph - the request_approval node will wait for signal internally
101-
result = await app.ainvoke(initial_state)
128+
result = await self._app.ainvoke(initial_state)
102129

103130
return result

0 commit comments

Comments
 (0)