fix(core): resolve mermaid node id collisions when special chars are used (#32857)

### Description

* Replace the Mermaid graph node label escaping logic
(`_escape_node_label`) with `_to_safe_id`, which converts a string into
a unique, Mermaid-compatible node id. Ensures nodes with special
characters always render correctly.

**Before**
* Invalid characters (e.g. `开`) replaced with `_`. Causes collisions
between nodes with names that are the same length and contain all
non-safe characters:
```python
_escape_node_label("开") # '_'
_escape_node_label("始") # '_'  same as above, but different character passed in. not a unique mapping.
```

**After**
```python
_to_safe_id("开") # \5f00
_to_safe_id("始") # \59cb  unique!
```

### Tests
* Rename `test_graph_mermaid_escape_node_label()` to
`test_graph_mermaid_to_safe_id()` and update function logic to use
`_to_safe_id`
* Add `test_graph_mermaid_special_chars()`

### Issue

Fixes langchain-ai/langgraph#6036
This commit is contained in:
Caspar Broekhuizen
2025-09-11 14:15:17 -07:00
committed by GitHub
parent 9cc85387d1
commit 15d558ff16
4 changed files with 335 additions and 284 deletions

View File

@@ -6,6 +6,7 @@ import asyncio
import base64
import random
import re
import string
import time
from dataclasses import asdict
from pathlib import Path
@@ -148,7 +149,7 @@ def draw_mermaid(
+ "</em></small>"
)
node_label = format_dict.get(key, format_dict[default_class_label]).format(
_escape_node_label(key), label
_to_safe_id(key), label
)
return f"{indent}{node_label}\n"
@@ -211,8 +212,7 @@ def draw_mermaid(
edge_label = " -.-> " if edge.conditional else " --> "
mermaid_graph += (
f"\t{_escape_node_label(source)}{edge_label}"
f"{_escape_node_label(target)};\n"
f"\t{_to_safe_id(source)}{edge_label}{_to_safe_id(target)};\n"
)
# Recursively add nested subgraphs
@@ -256,9 +256,18 @@ def draw_mermaid(
return mermaid_graph
def _escape_node_label(node_label: str) -> str:
"""Escapes the node label for Mermaid syntax."""
return re.sub(r"[^a-zA-Z-_0-9]", "_", node_label)
def _to_safe_id(label: str) -> str:
"""Convert a string into a Mermaid-compatible node id.
Keep [a-zA-Z0-9_-] characters unchanged.
Map every other character -> backslash + lowercase hex codepoint.
Result is guaranteed to be unique and Mermaid-compatible,
so nodes with special characters always render correctly.
"""
allowed = string.ascii_letters + string.digits + "_-"
out = [ch if ch in allowed else "\\" + format(ord(ch), "x") for ch in label]
return "".join(out)
def _generate_mermaid_graph_styles(node_colors: NodeStyles) -> str:

View File

@@ -12,16 +12,16 @@
parent_2(parent_2)
__end__([<p>__end__</p>]):::last
__start__ --> parent_1;
child_child_2 --> parent_2;
parent_1 --> child_child_1_grandchild_1;
child\3achild_2 --> parent_2;
parent_1 --> child\3achild_1\3agrandchild_1;
parent_2 --> __end__;
subgraph child
child_child_2(child_2)
child_child_1_grandchild_2 --> child_child_2;
child\3achild_2(child_2)
child\3achild_1\3agrandchild_2 --> child\3achild_2;
subgraph child_1
child_child_1_grandchild_1(grandchild_1)
child_child_1_grandchild_2(grandchild_2<hr/><small><em>__interrupt = before</em></small>)
child_child_1_grandchild_1 --> child_child_1_grandchild_2;
child\3achild_1\3agrandchild_1(grandchild_1)
child\3achild_1\3agrandchild_2(grandchild_2<hr/><small><em>__interrupt = before</em></small>)
child\3achild_1\3agrandchild_1 --> child\3achild_1\3agrandchild_2;
end
end
classDef default fill:#f2f0ff,line-height:1.2
@@ -34,13 +34,13 @@
'''
graph TD;
PromptInput --> PromptTemplate_1;
Parallel_llm1_llm2_Input --> FakeListLLM_1;
FakeListLLM_1 --> Parallel_llm1_llm2_Output;
Parallel_llm1_llm2_Input --> FakeListLLM_2;
FakeListLLM_2 --> Parallel_llm1_llm2_Output;
PromptTemplate_1 --> Parallel_llm1_llm2_Input;
Parallel\3cllm1\2cllm2\3eInput --> FakeListLLM_1;
FakeListLLM_1 --> Parallel\3cllm1\2cllm2\3eOutput;
Parallel\3cllm1\2cllm2\3eInput --> FakeListLLM_2;
FakeListLLM_2 --> Parallel\3cllm1\2cllm2\3eOutput;
PromptTemplate_1 --> Parallel\3cllm1\2cllm2\3eInput;
PromptTemplate_2 --> PromptTemplateOutput;
Parallel_llm1_llm2_Output --> PromptTemplate_2;
Parallel\3cllm1\2cllm2\3eOutput --> PromptTemplate_2;
'''
# ---
@@ -65,6 +65,27 @@
'''
# ---
# name: test_graph_mermaid_special_chars[mermaid]
'''
---
config:
flowchart:
curve: linear
---
graph TD;
__start__([<p>__start__</p>]):::first
\5f00\59cb(开始)
\7ed3\675f(结束)
__end__([<p>__end__</p>]):::last
__start__ --> \5f00\59cb;
\5f00\59cb --> \7ed3\675f;
\7ed3\675f --> __end__;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
classDef last fill:#bfb6fc
'''
# ---
# name: test_graph_sequence[ascii]
'''
+-------------+
@@ -1902,15 +1923,15 @@
graph TD;
PromptInput --> PromptTemplate;
PromptTemplate --> FakeListLLM;
Parallel_as_list_as_str_Input --> CommaSeparatedListOutputParser;
CommaSeparatedListOutputParser --> Parallel_as_list_as_str_Output;
Parallel\3cas_list\2cas_str\3eInput --> CommaSeparatedListOutputParser;
CommaSeparatedListOutputParser --> Parallel\3cas_list\2cas_str\3eOutput;
conditional_str_parser_input --> StrOutputParser;
StrOutputParser --> conditional_str_parser_output;
conditional_str_parser_input --> XMLOutputParser;
XMLOutputParser --> conditional_str_parser_output;
Parallel_as_list_as_str_Input --> conditional_str_parser_input;
conditional_str_parser_output --> Parallel_as_list_as_str_Output;
FakeListLLM --> Parallel_as_list_as_str_Input;
Parallel\3cas_list\2cas_str\3eInput --> conditional_str_parser_input;
conditional_str_parser_output --> Parallel\3cas_list\2cas_str\3eOutput;
FakeListLLM --> Parallel\3cas_list\2cas_str\3eInput;
'''
# ---
@@ -1925,8 +1946,8 @@
PromptInput([PromptInput]):::first
PromptTemplate(PromptTemplate)
FakeListLLM(FakeListLLM)
Parallel_as_list_as_str_Input(Parallel<as_list,as_str>Input)
Parallel_as_list_as_str_Output([Parallel<as_list,as_str>Output]):::last
Parallel\3cas_list\2cas_str\3eInput(Parallel<as_list,as_str>Input)
Parallel\3cas_list\2cas_str\3eOutput([Parallel<as_list,as_str>Output]):::last
CommaSeparatedListOutputParser(CommaSeparatedListOutputParser)
conditional_str_parser_input(conditional_str_parser_input)
conditional_str_parser_output(conditional_str_parser_output)
@@ -1934,15 +1955,15 @@
XMLOutputParser(XMLOutputParser)
PromptInput --> PromptTemplate;
PromptTemplate --> FakeListLLM;
Parallel_as_list_as_str_Input --> CommaSeparatedListOutputParser;
CommaSeparatedListOutputParser --> Parallel_as_list_as_str_Output;
Parallel\3cas_list\2cas_str\3eInput --> CommaSeparatedListOutputParser;
CommaSeparatedListOutputParser --> Parallel\3cas_list\2cas_str\3eOutput;
conditional_str_parser_input --> StrOutputParser;
StrOutputParser --> conditional_str_parser_output;
conditional_str_parser_input --> XMLOutputParser;
XMLOutputParser --> conditional_str_parser_output;
Parallel_as_list_as_str_Input --> conditional_str_parser_input;
conditional_str_parser_output --> Parallel_as_list_as_str_Output;
FakeListLLM --> Parallel_as_list_as_str_Input;
Parallel\3cas_list\2cas_str\3eInput --> conditional_str_parser_input;
conditional_str_parser_output --> Parallel\3cas_list\2cas_str\3eOutput;
FakeListLLM --> Parallel\3cas_list\2cas_str\3eInput;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
classDef last fill:#bfb6fc
@@ -2000,20 +2021,20 @@
outer_2(outer_2)
__end__([<p>__end__</p>]):::last
__start__ --> outer_1;
inner_1_inner_2 --> outer_2;
inner_2_inner_2 --> outer_2;
outer_1 --> inner_1_inner_1;
outer_1 --> inner_2_inner_1;
inner_1\3ainner_2 --> outer_2;
inner_2\3ainner_2 --> outer_2;
outer_1 --> inner_1\3ainner_1;
outer_1 --> inner_2\3ainner_1;
outer_2 --> __end__;
subgraph inner_1
inner_1_inner_1(inner_1)
inner_1_inner_2(inner_2<hr/><small><em>__interrupt = before</em></small>)
inner_1_inner_1 --> inner_1_inner_2;
inner_1\3ainner_1(inner_1)
inner_1\3ainner_2(inner_2<hr/><small><em>__interrupt = before</em></small>)
inner_1\3ainner_1 --> inner_1\3ainner_2;
end
subgraph inner_2
inner_2_inner_1(inner_1)
inner_2_inner_2(inner_2)
inner_2_inner_1 --> inner_2_inner_2;
inner_2\3ainner_1(inner_1)
inner_2\3ainner_2(inner_2)
inner_2\3ainner_1 --> inner_2\3ainner_2;
end
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
@@ -2031,10 +2052,10 @@
graph TD;
__start__([<p>__start__</p>]):::first
__end__([<p>__end__</p>]):::last
__start__ --> sub_meow;
sub_meow --> __end__;
__start__ --> sub\3ameow;
sub\3ameow --> __end__;
subgraph sub
sub_meow(meow)
sub\3ameow(meow)
end
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
@@ -2117,19 +2138,19 @@
parent_2(parent_2)
__end__([<p>__end__</p>]):::last
__start__ --> parent_1;
child_child_2 --> parent_2;
parent_1 --> child_child_1_grandchild_1;
child\3achild_2 --> parent_2;
parent_1 --> child\3achild_1\3agrandchild_1;
parent_2 --> __end__;
subgraph child
child_child_2(child_2)
child_child_1_grandchild_2 --> child_child_2;
child\3achild_2(child_2)
child\3achild_1\3agrandchild_2 --> child\3achild_2;
subgraph child_1
child_child_1_grandchild_1(grandchild_1)
child_child_1_grandchild_2(grandchild_2<hr/><small><em>__interrupt = before</em></small>)
child_child_1_grandchild_1_greatgrandchild --> child_child_1_grandchild_2;
child\3achild_1\3agrandchild_1(grandchild_1)
child\3achild_1\3agrandchild_2(grandchild_2<hr/><small><em>__interrupt = before</em></small>)
child\3achild_1\3agrandchild_1\3agreatgrandchild --> child\3achild_1\3agrandchild_2;
subgraph grandchild_1
child_child_1_grandchild_1_greatgrandchild(greatgrandchild)
child_child_1_grandchild_1 --> child_child_1_grandchild_1_greatgrandchild;
child\3achild_1\3agrandchild_1\3agreatgrandchild(greatgrandchild)
child\3achild_1\3agrandchild_1 --> child\3achild_1\3agrandchild_1\3agreatgrandchild;
end
end
end

View File

@@ -15,8 +15,8 @@ from langchain_core.runnables import RunnableConfig
from langchain_core.runnables.base import Runnable
from langchain_core.runnables.graph import Edge, Graph, MermaidDrawMethod, Node
from langchain_core.runnables.graph_mermaid import (
_escape_node_label,
_render_mermaid_using_api,
_to_safe_id,
draw_mermaid_png,
)
from langchain_core.utils.pydantic import PYDANTIC_VERSION
@@ -521,12 +521,12 @@ def test_runnable_get_graph_with_invalid_output_type() -> None:
runnable.get_graph()
def test_graph_mermaid_escape_node_label() -> None:
def test_graph_mermaid_to_safe_id() -> None:
"""Test that node labels are correctly preprocessed for draw_mermaid."""
assert _escape_node_label("foo") == "foo"
assert _escape_node_label("foo-bar") == "foo-bar"
assert _escape_node_label("foo_1") == "foo_1"
assert _escape_node_label("#foo*&!") == "_foo___"
assert _to_safe_id("foo") == "foo"
assert _to_safe_id("foo-bar") == "foo-bar"
assert _to_safe_id("foo_1") == "foo_1"
assert _to_safe_id("#foo*&!") == "\\23foo\\2a\\26\\21"
def test_graph_mermaid_duplicate_nodes(snapshot: SnapshotAssertion) -> None:
@@ -653,3 +653,24 @@ def test_graph_draw_mermaid_png_base_url() -> None:
args, kwargs = mock_get.call_args
url = args[0] # First argument to request.get is the URL
assert url.startswith(custom_url)
def test_graph_mermaid_special_chars(snapshot: SnapshotAssertion) -> None:
graph = Graph(
nodes={
"__start__": Node(
id="__start__", name="__start__", data=BaseModel, metadata=None
),
"开始": Node(id="开始", name="开始", data=BaseModel, metadata=None),
"结束": Node(id="结束", name="结束", data=BaseModel, metadata=None),
"__end__": Node(
id="__end__", name="__end__", data=BaseModel, metadata=None
),
},
edges=[
Edge(source="__start__", target="开始", data=None, conditional=False),
Edge(source="开始", target="结束", data=None, conditional=False),
Edge(source="结束", target="__end__", data=None, conditional=False),
],
)
assert graph.draw_mermaid() == snapshot(name="mermaid")

View File

@@ -28,11 +28,11 @@
graph TD;
__start__([<p>__start__</p>]):::first
model_request(model_request)
NoopOne_before_model(NoopOne.before_model)
NoopOne\2ebefore_model(NoopOne.before_model)
__end__([<p>__end__</p>]):::last
NoopOne_before_model -.-> __end__;
NoopOne_before_model -.-> model_request;
__start__ --> NoopOne_before_model;
NoopOne\2ebefore_model -.-> __end__;
NoopOne\2ebefore_model -.-> model_request;
__start__ --> NoopOne\2ebefore_model;
model_request --> __end__;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
@@ -50,15 +50,15 @@
graph TD;
__start__([<p>__start__</p>]):::first
model_request(model_request)
NoopTen_before_model(NoopTen.before_model)
NoopTen_after_model(NoopTen.after_model)
NoopTen\2ebefore_model(NoopTen.before_model)
NoopTen\2eafter_model(NoopTen.after_model)
__end__([<p>__end__</p>]):::last
NoopTen_after_model -.-> NoopTen_before_model;
NoopTen_after_model -.-> __end__;
NoopTen_before_model -.-> __end__;
NoopTen_before_model -.-> model_request;
__start__ --> NoopTen_before_model;
model_request --> NoopTen_after_model;
NoopTen\2eafter_model -.-> NoopTen\2ebefore_model;
NoopTen\2eafter_model -.-> __end__;
NoopTen\2ebefore_model -.-> __end__;
NoopTen\2ebefore_model -.-> model_request;
__start__ --> NoopTen\2ebefore_model;
model_request --> NoopTen\2eafter_model;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
classDef last fill:#bfb6fc
@@ -75,23 +75,23 @@
graph TD;
__start__([<p>__start__</p>]):::first
model_request(model_request)
NoopTen_before_model(NoopTen.before_model)
NoopTen_after_model(NoopTen.after_model)
NoopEleven_before_model(NoopEleven.before_model)
NoopEleven_after_model(NoopEleven.after_model)
NoopTen\2ebefore_model(NoopTen.before_model)
NoopTen\2eafter_model(NoopTen.after_model)
NoopEleven\2ebefore_model(NoopEleven.before_model)
NoopEleven\2eafter_model(NoopEleven.after_model)
__end__([<p>__end__</p>]):::last
NoopEleven_after_model -.-> NoopTen_after_model;
NoopEleven_after_model -.-> NoopTen_before_model;
NoopEleven_after_model -.-> __end__;
NoopEleven_before_model -.-> NoopTen_before_model;
NoopEleven_before_model -.-> __end__;
NoopEleven_before_model -.-> model_request;
NoopTen_after_model -.-> NoopTen_before_model;
NoopTen_after_model -.-> __end__;
NoopTen_before_model -.-> NoopEleven_before_model;
NoopTen_before_model -.-> __end__;
__start__ --> NoopTen_before_model;
model_request --> NoopEleven_after_model;
NoopEleven\2eafter_model -.-> NoopTen\2eafter_model;
NoopEleven\2eafter_model -.-> NoopTen\2ebefore_model;
NoopEleven\2eafter_model -.-> __end__;
NoopEleven\2ebefore_model -.-> NoopTen\2ebefore_model;
NoopEleven\2ebefore_model -.-> __end__;
NoopEleven\2ebefore_model -.-> model_request;
NoopTen\2eafter_model -.-> NoopTen\2ebefore_model;
NoopTen\2eafter_model -.-> __end__;
NoopTen\2ebefore_model -.-> NoopEleven\2ebefore_model;
NoopTen\2ebefore_model -.-> __end__;
__start__ --> NoopTen\2ebefore_model;
model_request --> NoopEleven\2eafter_model;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
classDef last fill:#bfb6fc
@@ -108,15 +108,15 @@
graph TD;
__start__([<p>__start__</p>]):::first
model_request(model_request)
NoopOne_before_model(NoopOne.before_model)
NoopTwo_before_model(NoopTwo.before_model)
NoopOne\2ebefore_model(NoopOne.before_model)
NoopTwo\2ebefore_model(NoopTwo.before_model)
__end__([<p>__end__</p>]):::last
NoopOne_before_model -.-> NoopTwo_before_model;
NoopOne_before_model -.-> __end__;
NoopTwo_before_model -.-> NoopOne_before_model;
NoopTwo_before_model -.-> __end__;
NoopTwo_before_model -.-> model_request;
__start__ --> NoopOne_before_model;
NoopOne\2ebefore_model -.-> NoopTwo\2ebefore_model;
NoopOne\2ebefore_model -.-> __end__;
NoopTwo\2ebefore_model -.-> NoopOne\2ebefore_model;
NoopTwo\2ebefore_model -.-> __end__;
NoopTwo\2ebefore_model -.-> model_request;
__start__ --> NoopOne\2ebefore_model;
model_request --> __end__;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
@@ -134,19 +134,19 @@
graph TD;
__start__([<p>__start__</p>]):::first
model_request(model_request)
NoopOne_before_model(NoopOne.before_model)
NoopTwo_before_model(NoopTwo.before_model)
NoopThree_before_model(NoopThree.before_model)
NoopOne\2ebefore_model(NoopOne.before_model)
NoopTwo\2ebefore_model(NoopTwo.before_model)
NoopThree\2ebefore_model(NoopThree.before_model)
__end__([<p>__end__</p>]):::last
NoopOne_before_model -.-> NoopTwo_before_model;
NoopOne_before_model -.-> __end__;
NoopThree_before_model -.-> NoopOne_before_model;
NoopThree_before_model -.-> __end__;
NoopThree_before_model -.-> model_request;
NoopTwo_before_model -.-> NoopOne_before_model;
NoopTwo_before_model -.-> NoopThree_before_model;
NoopTwo_before_model -.-> __end__;
__start__ --> NoopOne_before_model;
NoopOne\2ebefore_model -.-> NoopTwo\2ebefore_model;
NoopOne\2ebefore_model -.-> __end__;
NoopThree\2ebefore_model -.-> NoopOne\2ebefore_model;
NoopThree\2ebefore_model -.-> __end__;
NoopThree\2ebefore_model -.-> model_request;
NoopTwo\2ebefore_model -.-> NoopOne\2ebefore_model;
NoopTwo\2ebefore_model -.-> NoopThree\2ebefore_model;
NoopTwo\2ebefore_model -.-> __end__;
__start__ --> NoopOne\2ebefore_model;
model_request --> __end__;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
@@ -164,12 +164,12 @@
graph TD;
__start__([<p>__start__</p>]):::first
model_request(model_request)
NoopFour_after_model(NoopFour.after_model)
NoopFour\2eafter_model(NoopFour.after_model)
__end__([<p>__end__</p>]):::last
NoopFour_after_model -.-> __end__;
NoopFour_after_model -.-> model_request;
NoopFour\2eafter_model -.-> __end__;
NoopFour\2eafter_model -.-> model_request;
__start__ --> model_request;
model_request --> NoopFour_after_model;
model_request --> NoopFour\2eafter_model;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
classDef last fill:#bfb6fc
@@ -186,16 +186,16 @@
graph TD;
__start__([<p>__start__</p>]):::first
model_request(model_request)
NoopFour_after_model(NoopFour.after_model)
NoopFive_after_model(NoopFive.after_model)
NoopFour\2eafter_model(NoopFour.after_model)
NoopFive\2eafter_model(NoopFive.after_model)
__end__([<p>__end__</p>]):::last
NoopFive_after_model -.-> NoopFour_after_model;
NoopFive_after_model -.-> __end__;
NoopFive_after_model -.-> model_request;
NoopFour_after_model -.-> __end__;
NoopFour_after_model -.-> model_request;
NoopFive\2eafter_model -.-> NoopFour\2eafter_model;
NoopFive\2eafter_model -.-> __end__;
NoopFive\2eafter_model -.-> model_request;
NoopFour\2eafter_model -.-> __end__;
NoopFour\2eafter_model -.-> model_request;
__start__ --> model_request;
model_request --> NoopFive_after_model;
model_request --> NoopFive\2eafter_model;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
classDef last fill:#bfb6fc
@@ -212,20 +212,20 @@
graph TD;
__start__([<p>__start__</p>]):::first
model_request(model_request)
NoopFour_after_model(NoopFour.after_model)
NoopFive_after_model(NoopFive.after_model)
NoopSix_after_model(NoopSix.after_model)
NoopFour\2eafter_model(NoopFour.after_model)
NoopFive\2eafter_model(NoopFive.after_model)
NoopSix\2eafter_model(NoopSix.after_model)
__end__([<p>__end__</p>]):::last
NoopFive_after_model -.-> NoopFour_after_model;
NoopFive_after_model -.-> __end__;
NoopFive_after_model -.-> model_request;
NoopFour_after_model -.-> __end__;
NoopFour_after_model -.-> model_request;
NoopSix_after_model -.-> NoopFive_after_model;
NoopSix_after_model -.-> __end__;
NoopSix_after_model -.-> model_request;
NoopFive\2eafter_model -.-> NoopFour\2eafter_model;
NoopFive\2eafter_model -.-> __end__;
NoopFive\2eafter_model -.-> model_request;
NoopFour\2eafter_model -.-> __end__;
NoopFour\2eafter_model -.-> model_request;
NoopSix\2eafter_model -.-> NoopFive\2eafter_model;
NoopSix\2eafter_model -.-> __end__;
NoopSix\2eafter_model -.-> model_request;
__start__ --> model_request;
model_request --> NoopSix_after_model;
model_request --> NoopSix\2eafter_model;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
classDef last fill:#bfb6fc
@@ -242,15 +242,15 @@
graph TD;
__start__([<p>__start__</p>]):::first
model_request(model_request)
NoopSeven_before_model(NoopSeven.before_model)
NoopSeven_after_model(NoopSeven.after_model)
NoopSeven\2ebefore_model(NoopSeven.before_model)
NoopSeven\2eafter_model(NoopSeven.after_model)
__end__([<p>__end__</p>]):::last
NoopSeven_after_model -.-> NoopSeven_before_model;
NoopSeven_after_model -.-> __end__;
NoopSeven_before_model -.-> __end__;
NoopSeven_before_model -.-> model_request;
__start__ --> NoopSeven_before_model;
model_request --> NoopSeven_after_model;
NoopSeven\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopSeven\2eafter_model -.-> __end__;
NoopSeven\2ebefore_model -.-> __end__;
NoopSeven\2ebefore_model -.-> model_request;
__start__ --> NoopSeven\2ebefore_model;
model_request --> NoopSeven\2eafter_model;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
classDef last fill:#bfb6fc
@@ -267,23 +267,23 @@
graph TD;
__start__([<p>__start__</p>]):::first
model_request(model_request)
NoopSeven_before_model(NoopSeven.before_model)
NoopSeven_after_model(NoopSeven.after_model)
NoopEight_before_model(NoopEight.before_model)
NoopEight_after_model(NoopEight.after_model)
NoopSeven\2ebefore_model(NoopSeven.before_model)
NoopSeven\2eafter_model(NoopSeven.after_model)
NoopEight\2ebefore_model(NoopEight.before_model)
NoopEight\2eafter_model(NoopEight.after_model)
__end__([<p>__end__</p>]):::last
NoopEight_after_model -.-> NoopSeven_after_model;
NoopEight_after_model -.-> NoopSeven_before_model;
NoopEight_after_model -.-> __end__;
NoopEight_before_model -.-> NoopSeven_before_model;
NoopEight_before_model -.-> __end__;
NoopEight_before_model -.-> model_request;
NoopSeven_after_model -.-> NoopSeven_before_model;
NoopSeven_after_model -.-> __end__;
NoopSeven_before_model -.-> NoopEight_before_model;
NoopSeven_before_model -.-> __end__;
__start__ --> NoopSeven_before_model;
model_request --> NoopEight_after_model;
NoopEight\2eafter_model -.-> NoopSeven\2eafter_model;
NoopEight\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopEight\2eafter_model -.-> __end__;
NoopEight\2ebefore_model -.-> NoopSeven\2ebefore_model;
NoopEight\2ebefore_model -.-> __end__;
NoopEight\2ebefore_model -.-> model_request;
NoopSeven\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopSeven\2eafter_model -.-> __end__;
NoopSeven\2ebefore_model -.-> NoopEight\2ebefore_model;
NoopSeven\2ebefore_model -.-> __end__;
__start__ --> NoopSeven\2ebefore_model;
model_request --> NoopEight\2eafter_model;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
classDef last fill:#bfb6fc
@@ -300,31 +300,31 @@
graph TD;
__start__([<p>__start__</p>]):::first
model_request(model_request)
NoopSeven_before_model(NoopSeven.before_model)
NoopSeven_after_model(NoopSeven.after_model)
NoopEight_before_model(NoopEight.before_model)
NoopEight_after_model(NoopEight.after_model)
NoopNine_before_model(NoopNine.before_model)
NoopNine_after_model(NoopNine.after_model)
NoopSeven\2ebefore_model(NoopSeven.before_model)
NoopSeven\2eafter_model(NoopSeven.after_model)
NoopEight\2ebefore_model(NoopEight.before_model)
NoopEight\2eafter_model(NoopEight.after_model)
NoopNine\2ebefore_model(NoopNine.before_model)
NoopNine\2eafter_model(NoopNine.after_model)
__end__([<p>__end__</p>]):::last
NoopEight_after_model -.-> NoopSeven_after_model;
NoopEight_after_model -.-> NoopSeven_before_model;
NoopEight_after_model -.-> __end__;
NoopEight_before_model -.-> NoopNine_before_model;
NoopEight_before_model -.-> NoopSeven_before_model;
NoopEight_before_model -.-> __end__;
NoopNine_after_model -.-> NoopEight_after_model;
NoopNine_after_model -.-> NoopSeven_before_model;
NoopNine_after_model -.-> __end__;
NoopNine_before_model -.-> NoopSeven_before_model;
NoopNine_before_model -.-> __end__;
NoopNine_before_model -.-> model_request;
NoopSeven_after_model -.-> NoopSeven_before_model;
NoopSeven_after_model -.-> __end__;
NoopSeven_before_model -.-> NoopEight_before_model;
NoopSeven_before_model -.-> __end__;
__start__ --> NoopSeven_before_model;
model_request --> NoopNine_after_model;
NoopEight\2eafter_model -.-> NoopSeven\2eafter_model;
NoopEight\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopEight\2eafter_model -.-> __end__;
NoopEight\2ebefore_model -.-> NoopNine\2ebefore_model;
NoopEight\2ebefore_model -.-> NoopSeven\2ebefore_model;
NoopEight\2ebefore_model -.-> __end__;
NoopNine\2eafter_model -.-> NoopEight\2eafter_model;
NoopNine\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopNine\2eafter_model -.-> __end__;
NoopNine\2ebefore_model -.-> NoopSeven\2ebefore_model;
NoopNine\2ebefore_model -.-> __end__;
NoopNine\2ebefore_model -.-> model_request;
NoopSeven\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopSeven\2eafter_model -.-> __end__;
NoopSeven\2ebefore_model -.-> NoopEight\2ebefore_model;
NoopSeven\2ebefore_model -.-> __end__;
__start__ --> NoopSeven\2ebefore_model;
model_request --> NoopNine\2eafter_model;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
classDef last fill:#bfb6fc
@@ -342,28 +342,28 @@
__start__([<p>__start__</p>]):::first
model_request(model_request)
tools(tools)
NoopSeven_before_model(NoopSeven.before_model)
NoopSeven_after_model(NoopSeven.after_model)
NoopEight_before_model(NoopEight.before_model)
NoopEight_after_model(NoopEight.after_model)
NoopSeven\2ebefore_model(NoopSeven.before_model)
NoopSeven\2eafter_model(NoopSeven.after_model)
NoopEight\2ebefore_model(NoopEight.before_model)
NoopEight\2eafter_model(NoopEight.after_model)
__end__([<p>__end__</p>]):::last
NoopEight_after_model -.-> NoopSeven_after_model;
NoopEight_after_model -.-> NoopSeven_before_model;
NoopEight_after_model -.-> __end__;
NoopEight_after_model -.-> tools;
NoopEight_before_model -.-> NoopSeven_before_model;
NoopEight_before_model -.-> __end__;
NoopEight_before_model -.-> model_request;
NoopEight_before_model -.-> tools;
NoopSeven_after_model -.-> NoopSeven_before_model;
NoopSeven_after_model -.-> __end__;
NoopSeven_after_model -.-> tools;
NoopSeven_before_model -.-> NoopEight_before_model;
NoopSeven_before_model -.-> __end__;
NoopSeven_before_model -.-> tools;
__start__ --> NoopSeven_before_model;
model_request --> NoopEight_after_model;
tools -.-> NoopSeven_before_model;
NoopEight\2eafter_model -.-> NoopSeven\2eafter_model;
NoopEight\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopEight\2eafter_model -.-> __end__;
NoopEight\2eafter_model -.-> tools;
NoopEight\2ebefore_model -.-> NoopSeven\2ebefore_model;
NoopEight\2ebefore_model -.-> __end__;
NoopEight\2ebefore_model -.-> model_request;
NoopEight\2ebefore_model -.-> tools;
NoopSeven\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopSeven\2eafter_model -.-> __end__;
NoopSeven\2eafter_model -.-> tools;
NoopSeven\2ebefore_model -.-> NoopEight\2ebefore_model;
NoopSeven\2ebefore_model -.-> __end__;
NoopSeven\2ebefore_model -.-> tools;
__start__ --> NoopSeven\2ebefore_model;
model_request --> NoopEight\2eafter_model;
tools -.-> NoopSeven\2ebefore_model;
tools -.-> __end__;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
@@ -382,28 +382,28 @@
__start__([<p>__start__</p>]):::first
model_request(model_request)
tools(tools)
NoopSeven_before_model(NoopSeven.before_model)
NoopSeven_after_model(NoopSeven.after_model)
NoopEight_before_model(NoopEight.before_model)
NoopEight_after_model(NoopEight.after_model)
NoopSeven\2ebefore_model(NoopSeven.before_model)
NoopSeven\2eafter_model(NoopSeven.after_model)
NoopEight\2ebefore_model(NoopEight.before_model)
NoopEight\2eafter_model(NoopEight.after_model)
__end__([<p>__end__</p>]):::last
NoopEight_after_model -.-> NoopSeven_after_model;
NoopEight_after_model -.-> NoopSeven_before_model;
NoopEight_after_model -.-> __end__;
NoopEight_after_model -.-> tools;
NoopEight_before_model -.-> NoopSeven_before_model;
NoopEight_before_model -.-> __end__;
NoopEight_before_model -.-> model_request;
NoopEight_before_model -.-> tools;
NoopSeven_after_model -.-> NoopSeven_before_model;
NoopSeven_after_model -.-> __end__;
NoopSeven_after_model -.-> tools;
NoopSeven_before_model -.-> NoopEight_before_model;
NoopSeven_before_model -.-> __end__;
NoopSeven_before_model -.-> tools;
__start__ --> NoopSeven_before_model;
model_request --> NoopEight_after_model;
tools -.-> NoopSeven_before_model;
NoopEight\2eafter_model -.-> NoopSeven\2eafter_model;
NoopEight\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopEight\2eafter_model -.-> __end__;
NoopEight\2eafter_model -.-> tools;
NoopEight\2ebefore_model -.-> NoopSeven\2ebefore_model;
NoopEight\2ebefore_model -.-> __end__;
NoopEight\2ebefore_model -.-> model_request;
NoopEight\2ebefore_model -.-> tools;
NoopSeven\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopSeven\2eafter_model -.-> __end__;
NoopSeven\2eafter_model -.-> tools;
NoopSeven\2ebefore_model -.-> NoopEight\2ebefore_model;
NoopSeven\2ebefore_model -.-> __end__;
NoopSeven\2ebefore_model -.-> tools;
__start__ --> NoopSeven\2ebefore_model;
model_request --> NoopEight\2eafter_model;
tools -.-> NoopSeven\2ebefore_model;
tools -.-> __end__;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
@@ -422,28 +422,28 @@
__start__([<p>__start__</p>]):::first
model_request(model_request)
tools(tools)
NoopSeven_before_model(NoopSeven.before_model)
NoopSeven_after_model(NoopSeven.after_model)
NoopEight_before_model(NoopEight.before_model)
NoopEight_after_model(NoopEight.after_model)
NoopSeven\2ebefore_model(NoopSeven.before_model)
NoopSeven\2eafter_model(NoopSeven.after_model)
NoopEight\2ebefore_model(NoopEight.before_model)
NoopEight\2eafter_model(NoopEight.after_model)
__end__([<p>__end__</p>]):::last
NoopEight_after_model -.-> NoopSeven_after_model;
NoopEight_after_model -.-> NoopSeven_before_model;
NoopEight_after_model -.-> __end__;
NoopEight_after_model -.-> tools;
NoopEight_before_model -.-> NoopSeven_before_model;
NoopEight_before_model -.-> __end__;
NoopEight_before_model -.-> model_request;
NoopEight_before_model -.-> tools;
NoopSeven_after_model -.-> NoopSeven_before_model;
NoopSeven_after_model -.-> __end__;
NoopSeven_after_model -.-> tools;
NoopSeven_before_model -.-> NoopEight_before_model;
NoopSeven_before_model -.-> __end__;
NoopSeven_before_model -.-> tools;
__start__ --> NoopSeven_before_model;
model_request --> NoopEight_after_model;
tools -.-> NoopSeven_before_model;
NoopEight\2eafter_model -.-> NoopSeven\2eafter_model;
NoopEight\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopEight\2eafter_model -.-> __end__;
NoopEight\2eafter_model -.-> tools;
NoopEight\2ebefore_model -.-> NoopSeven\2ebefore_model;
NoopEight\2ebefore_model -.-> __end__;
NoopEight\2ebefore_model -.-> model_request;
NoopEight\2ebefore_model -.-> tools;
NoopSeven\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopSeven\2eafter_model -.-> __end__;
NoopSeven\2eafter_model -.-> tools;
NoopSeven\2ebefore_model -.-> NoopEight\2ebefore_model;
NoopSeven\2ebefore_model -.-> __end__;
NoopSeven\2ebefore_model -.-> tools;
__start__ --> NoopSeven\2ebefore_model;
model_request --> NoopEight\2eafter_model;
tools -.-> NoopSeven\2ebefore_model;
tools -.-> __end__;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
@@ -462,28 +462,28 @@
__start__([<p>__start__</p>]):::first
model_request(model_request)
tools(tools)
NoopSeven_before_model(NoopSeven.before_model)
NoopSeven_after_model(NoopSeven.after_model)
NoopEight_before_model(NoopEight.before_model)
NoopEight_after_model(NoopEight.after_model)
NoopSeven\2ebefore_model(NoopSeven.before_model)
NoopSeven\2eafter_model(NoopSeven.after_model)
NoopEight\2ebefore_model(NoopEight.before_model)
NoopEight\2eafter_model(NoopEight.after_model)
__end__([<p>__end__</p>]):::last
NoopEight_after_model -.-> NoopSeven_after_model;
NoopEight_after_model -.-> NoopSeven_before_model;
NoopEight_after_model -.-> __end__;
NoopEight_after_model -.-> tools;
NoopEight_before_model -.-> NoopSeven_before_model;
NoopEight_before_model -.-> __end__;
NoopEight_before_model -.-> model_request;
NoopEight_before_model -.-> tools;
NoopSeven_after_model -.-> NoopSeven_before_model;
NoopSeven_after_model -.-> __end__;
NoopSeven_after_model -.-> tools;
NoopSeven_before_model -.-> NoopEight_before_model;
NoopSeven_before_model -.-> __end__;
NoopSeven_before_model -.-> tools;
__start__ --> NoopSeven_before_model;
model_request --> NoopEight_after_model;
tools -.-> NoopSeven_before_model;
NoopEight\2eafter_model -.-> NoopSeven\2eafter_model;
NoopEight\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopEight\2eafter_model -.-> __end__;
NoopEight\2eafter_model -.-> tools;
NoopEight\2ebefore_model -.-> NoopSeven\2ebefore_model;
NoopEight\2ebefore_model -.-> __end__;
NoopEight\2ebefore_model -.-> model_request;
NoopEight\2ebefore_model -.-> tools;
NoopSeven\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopSeven\2eafter_model -.-> __end__;
NoopSeven\2eafter_model -.-> tools;
NoopSeven\2ebefore_model -.-> NoopEight\2ebefore_model;
NoopSeven\2ebefore_model -.-> __end__;
NoopSeven\2ebefore_model -.-> tools;
__start__ --> NoopSeven\2ebefore_model;
model_request --> NoopEight\2eafter_model;
tools -.-> NoopSeven\2ebefore_model;
tools -.-> __end__;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0
@@ -502,28 +502,28 @@
__start__([<p>__start__</p>]):::first
model_request(model_request)
tools(tools)
NoopSeven_before_model(NoopSeven.before_model)
NoopSeven_after_model(NoopSeven.after_model)
NoopEight_before_model(NoopEight.before_model)
NoopEight_after_model(NoopEight.after_model)
NoopSeven\2ebefore_model(NoopSeven.before_model)
NoopSeven\2eafter_model(NoopSeven.after_model)
NoopEight\2ebefore_model(NoopEight.before_model)
NoopEight\2eafter_model(NoopEight.after_model)
__end__([<p>__end__</p>]):::last
NoopEight_after_model -.-> NoopSeven_after_model;
NoopEight_after_model -.-> NoopSeven_before_model;
NoopEight_after_model -.-> __end__;
NoopEight_after_model -.-> tools;
NoopEight_before_model -.-> NoopSeven_before_model;
NoopEight_before_model -.-> __end__;
NoopEight_before_model -.-> model_request;
NoopEight_before_model -.-> tools;
NoopSeven_after_model -.-> NoopSeven_before_model;
NoopSeven_after_model -.-> __end__;
NoopSeven_after_model -.-> tools;
NoopSeven_before_model -.-> NoopEight_before_model;
NoopSeven_before_model -.-> __end__;
NoopSeven_before_model -.-> tools;
__start__ --> NoopSeven_before_model;
model_request --> NoopEight_after_model;
tools -.-> NoopSeven_before_model;
NoopEight\2eafter_model -.-> NoopSeven\2eafter_model;
NoopEight\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopEight\2eafter_model -.-> __end__;
NoopEight\2eafter_model -.-> tools;
NoopEight\2ebefore_model -.-> NoopSeven\2ebefore_model;
NoopEight\2ebefore_model -.-> __end__;
NoopEight\2ebefore_model -.-> model_request;
NoopEight\2ebefore_model -.-> tools;
NoopSeven\2eafter_model -.-> NoopSeven\2ebefore_model;
NoopSeven\2eafter_model -.-> __end__;
NoopSeven\2eafter_model -.-> tools;
NoopSeven\2ebefore_model -.-> NoopEight\2ebefore_model;
NoopSeven\2ebefore_model -.-> __end__;
NoopSeven\2ebefore_model -.-> tools;
__start__ --> NoopSeven\2ebefore_model;
model_request --> NoopEight\2eafter_model;
tools -.-> NoopSeven\2ebefore_model;
tools -.-> __end__;
classDef default fill:#f2f0ff,line-height:1.2
classDef first fill-opacity:0